erbi_lucifer吧 关注:407贴子:3,325
  • 14回复贴,共1

【win32 ASM】File format parsing (part 7)

只看楼主收藏回复


part 6度娘吞了……


1楼2013-05-02 09:28回复
    【文件格式解析(六)】ICO/CUR文件格式




    ICO/CUR:
    ico是Icon file的缩写,是Windows的图标文件格式的一种,可以存储单个图案、多尺寸、多色板的图标文件。
    cur是cursor的缩写。文件的格式是静态光标文件,它的格式与图标文件*.ico的格式是一致的。cur文件其实和icon等文件是一样的,就是文件头的一个标志不同。


    本楼含有高级字体2楼2013-05-02 09:30
    回复

      (一)文件组成
      (1)6字节的文件头:
      1. 保留的字节 2字节
      2. 资源类型(数值有两种:01为图标,02为光标) 2字节
      3. 图象个数 2字节
      (2)16字节的图像信息块(连续的多块,数量就是文件头的图像个数):
      1. 图标宽度 1字节
      2. 图标高度 1字节
      3. 颜色计数(02=单色, 00≥256色) 1字节
      4. 未用 1字节
      5. 保留的 4字节
      6. 图象数据块的长度 4字节
      7. 图象数据块相对于文件头部的偏移量 4字节
      (3)40字节的BMP信息头
      1. BMP 信息头结构长度 4字节
      2. 图像宽度 4字节
      3. 图像高度(XOR图高度+AND图高度) 4字节
      4. 位面板数 2字节
      5. 每象素所占位数 2字节
      6. 象素数据的压缩类型 4字节
      7. 图象数据的长度 4字节
      8. 未用 16字节
      (4)图像数据


      本楼含有高级字体3楼2013-05-02 09:30
      回复

        (二)构建结构体

        根据文件结构我们可以构建下面三个结构体,然后读取文件即可获取文件的信息。
        IcoHead struct
        reserved dw ?;
        itype dw ?;
        imagenum dw ?;
        IcoHead ends
        (6字节的文件头)
        ImgInfo struct
        iwidth db ?
        height db ?
        count db ?
        inone db ?
        reserved dd ?
        imglenghtdd ?
        ioffset dd ?
        ImgInfo ends
        (16字节的图像信息)
        BMPHead struct
        headlength dd ?
        iwidth dd ?
        height dd ?
        biPlanes dw ?
        biSizeImage dw ?
        biCompression dd ?
        imglenght dd ?
        inone db 16 dup(?)
        BMPHead ends
        (40字节的bmp位图头信息)


        本楼含有高级字体4楼2013-05-02 09:31
        回复

          (三)读取文件信息
          接下来以图标文件“1.ico”(文件见附件)为例子读取它的结构信息。
          (1)图片“1.ico”的文件头结构:
          首先我们读取前6字节的信息(图片中选择的那部分),并存入结构体IcoHead中。

          “1.ico”的文件头结构:
          从图片中我们可以看到
          前两个字节(保留字段)是用0填充的。
          第三四字节的数据是“01 00”,即该文件是图像类型是“01”,是ICO图标。
          第五六字节的数据是“05 00”,即该文件的图像个数是5个(图标文件一般包含多张图片)。也就是说接下来的图像信息我们需要循环5次进行全部读取。
          故读取结果为:


          本楼含有高级字体5楼2013-05-02 09:32
          回复

            (2)图像信息头
            首个图像信息头的结构信息,我们将其读取后存入ImgInfo结构中,并显示。

            我们可以看到这第一个图像信息块:
            1. 字节1:数值是“80”,也就是说图标宽度是“80H”,即128像素。
            2. 字节2:数值是“80”,也就是说图标高度是“80H”,即128像素(一般图标的宽高是相等的)。
            3. 字节3:数值是“00”,也就是说颜色计数是0,这表示这是大于256色的图像。
            4. 字节4:数值是“00”,未用结构。
            5. 字节5-8:数值是“01 00 20 00”,保留的字段。
            6. 字节9-12:数值是“28 08 01 00”,表示数据块的长度,值为67624。
            7. 字节13-16:数值是“56 00 00 00”,表示这个图象信息所表示的图像数据块相对于文件头部的偏移量,值为86。
            故读取结果为:


            6楼2013-05-02 09:33
            回复

              同理,“1.ico”文件中5个图像的信息头如下:

              即:
              00000006h: 8080 00 00 01 00 20 00 28 08 01 00 56 00 00 00 ;.... .(...V...
              00000016h: 4040 00 00 01 00 20 00 28 42 00 00 7E 08 01 00 ;@@.... .(B..~...
              00000026h: 3030 00 00 01 00 20 00 A8 25 00 00 A6 4A 01 00 ;00.... .?....
              00000036h: 2020 00 00 01 00 20 00 A8 10 00 00 4E 70 01 00 ; .... .?..Np..
              00000046h: 1010 00 00 01 00 20 00 68 04 00 00 F6 80 01 00 ;...... .h...鰛..
              我们可以看到,该文件中的5中图片是一张比一张小的。
              宽(高)分别为:128 pix ,64 pix ,48 pix ,32 pix ,16 pix
              颜色记数相同,保存的数据块偏移量越来越大。


              7楼2013-05-02 09:34
              回复

                全部读取到的图像信息为:
                --------------------1张图片信息--------------------
                图标宽度:128
                图标高度:128
                颜色计数:0
                未用:00
                保留字段:00200001
                图象数据块长度:67624
                图象数据块相对于文件头部的偏移量:86
                --------------------2张图片信息--------------------
                图标宽度:64
                图标高度:64
                颜色计数:0
                未用:00
                保留字段:00200001
                图象数据块长度:16936
                图象数据块相对于文件头部的偏移量:67710
                --------------------3张图片信息--------------------
                图标宽度:48
                图标高度:48
                颜色计数:0
                未用:00
                保留字段:00200001
                图象数据块长度:9640
                图象数据块相对于文件头部的偏移量:84646
                --------------------4张图片信息--------------------
                图标宽度:32
                图标高度:32
                颜色计数:0
                未用:00
                保留字段:00200001
                图象数据块长度:4264
                图象数据块相对于文件头部的偏移量:94286
                --------------------5张图片信息--------------------
                图标宽度:16
                图标高度:16
                颜色计数:0
                未用:00
                保留字段:00200001
                图象数据块长度:1128
                图象数据块相对于文件头部的偏移量:98550


                9楼2013-05-02 11:56
                回复

                  (3)bmp位图头信息
                  40个字节的bmp位图信息块,我们读取这些信息后存入BMPHead结构中。

                  我们可以看到:
                  1. 1-4字节:数值是“28 0000 00”,故读取到的信息头结构长度为40(28H)。
                  2. 5-8字节:数值是“80 0000 00”,故读取到的bmp图像的宽为128(80H)。
                  3. 9-12字节:数值是“00 0100 00”,故读取到的bmp图像的高为256(100H)。
                  4. 13-14字节:数值是“01 00”,故读取到的位面板数为:1。
                  5. 15-16字节:数值是“20 00”,故读取到的每像素所占位数为32(20H)。
                  6. 17-20字节:数值是“00 0000 00”,故读取到的像素数据的压缩类型:0(0表示未压缩)。
                  7. 21-24字节:数值是“00 0001 00”,故读取到的图象数据的长度:65536(10000H)
                  读取结果为:


                  10楼2013-05-02 11:57
                  回复

                    .386
                    .model flat, stdcall
                    option casemap :none
                    include windows.inc
                    include user32.inc
                    include kernel32.inc
                    include masm32.inc
                    include gdi32.inc
                    include Shlwapi.inc
                    includelib gdi32.lib
                    includelib user32.lib
                    includelib kernel32.lib
                    includelib masm32.lib
                    includelib Shlwapi.lib
                    include macro.asm .data
                    lpMsg db "请带参数运行:icoH d:/1.ico",13,10,0
                    lpMsg_fileerr db 13,10,"文件打开失败。",13,10,0
                    repeatnum dw 0 .data?
                    IcoHead struct
                    reserved dw ?;
                    itype dw ?;
                    imagenum dw ?;
                    IcoHead ends
                    ImgInfo struct
                    iwidth db ?
                    height db ?
                    count db ?
                    inone db ?
                    reserved dd ?
                    imglenght dd ?
                    ioffset dd ?
                    ImgInfo ends
                    BMPHead struct
                    headlength dd ?
                    iwidth dd ?
                    height dd ?
                    biPlanes dw ?
                    biSizeImage dw ?
                    biCompression dd ?
                    imglenght dd ?
                    inone db 16 dup(?)
                    BMPHead ends
                    icoH IcoHead <>
                    imgI ImgInfo <>
                    bmpH BMPHead <>
                    buffer db MAX_PATH dup(?)
                    dwRead dd ?;读取的字节数
                    CommandLine LPSTR ?
                    LpArg LPSTR ?
                    hFile dd ?
                    info db MAX_PATH dup(?)
                    .CODE


                    12楼2013-05-02 11:58
                    回复

                      START:
                      ;获取参数
                      call GetCommandLine
                      mov CommandLine,eax
                      ;提取参数
                      push CommandLine
                      call PathGetArgs
                      mov LpArg,eax
                      mov esi,eax
                      lodsb ;[esi]-->al
                      cmp al,0
                      je noArgs
                      cmp al,34 ;双引号
                      jne @F
                      push LpArg
                      call PathUnquoteSpaces ;去双引号
                      mov LpArg,eax
                      @@:
                      push type icoH
                      push offset icoH
                      call RtlZeroMemory
                      ;打开文件
                      push NULL
                      push FILE_ATTRIBUTE_NORMAL
                      push OPEN_EXISTING
                      push NULL
                      push FILE_SHARE_READ
                      push GENERIC_READ
                      push LpArg
                      call CreateFile
                      cmp eax,INVALID_HANDLE_VALUE
                      je openerror
                      ;读取icoH
                      mov hFile, eax
                      push NULL
                      push offset dwRead
                      push sizeof icoH
                      push offset icoH
                      push hFile
                      call ReadFile
                      ;读取失败跳转
                      cmp dwRead,sizeof icoH
                      jne colseend
                      mov edi,offset icoH
                      jmp ShowFileHead
                      ;循环读取imgI结构
                      goon:
                      push sizeof imgI
                      push offset imgI
                      call RtlZeroMemory
                      push NULL
                      push offset dwRead
                      push sizeof imgI
                      push offset imgI
                      push hFile
                      call ReadFile
                      cmp dwRead,sizeof imgI
                      jne colseend
                      ;显示信息
                      jmp ShowImageInfo
                      ingoon:;显示信息结束后跳转到这里
                      dec icoH.imagenum
                      cmp icoH.imagenum,0
                      jg goon
                      push sizeof bmpH
                      push offset bmpH
                      call RtlZeroMemory
                      ;读取bmpH结构
                      push NULL
                      push offset dwRead
                      push sizeof bmpH
                      push offset bmpH
                      push hFile
                      call ReadFile
                      cmp dwRead,sizeof bmpH
                      jne colseend
                      ;显示信息
                      jmp ShowBMPHead
                      colseend:
                      ;关闭文件
                      push hFile
                      call CloseHandle
                      jmp endexit
                      noArgs:
                      ;没有运行参数
                      push offset lpMsg
                      call StdOut
                      jmp endexit
                      openerror:
                      ;打开失败
                      push offset lpMsg_fileerr
                      call StdOut
                      jmp endexit
                      endexit:
                      ;暂停,退出
                      push sizeof buffer
                      push offset buffer
                      call StdIn
                      push 0
                      call ExitProcess


                      13楼2013-05-02 11:59
                      回复

                        ShowFileHead:
                        ;输出icoH结构的信息
                        push offset CTXT(13,10,"----------------------文件头----------------------",13,10)
                        push offset info
                        call wsprintf
                        push offset info
                        call StdOut
                        xor eax,eax
                        mov ax,WORD ptr icoH.reserved;
                        push eax
                        push offset CTXT("保留字段:%02X",13,10)
                        push offset info
                        call wsprintf
                        push offset info
                        call StdOut
                        xor eax,eax
                        mov ax,WORD ptr icoH.itype
                        push eax
                        push offset CTXT("图片类型(01为图标,02为光标):%02X",13,10)
                        push offset info
                        call wsprintf
                        push offset info
                        call StdOut
                        xor eax,eax
                        mov ax,WORD ptr icoH.imagenum
                        push eax
                        push offset CTXT("图片数量:%d",13,10)
                        push offset info
                        call wsprintf
                        push offset info
                        call StdOut
                        jmp goon


                        14楼2013-05-02 11:59
                        回复

                          ShowImageInfo:
                          ;输出imgI结构的信息
                          inc repeatnum
                          xor eax,eax
                          mov ax,WORD ptr repeatnum
                          push eax
                          push offset CTXT(13,10,"--------------------%d张图片信息--------------------",13,10)
                          push offset info
                          call wsprintf
                          push offset info
                          call StdOut
                          xor eax,eax
                          mov al,BYTE ptr imgI.iwidth
                          push eax
                          push offset CTXT("图标宽度:%d",13,10)
                          push offset info
                          call wsprintf
                          push offset info
                          call StdOut
                          xor eax,eax
                          mov al,BYTE ptr imgI.height
                          push eax
                          push offset CTXT("图标高度:%d",13,10)
                          push offset info
                          call wsprintf
                          push offset info
                          call StdOut
                          xor eax,eax
                          mov al,BYTE ptr imgI.count
                          push eax
                          push offset CTXT("颜色计数:%d",13,10)
                          push offset info
                          call wsprintf
                          push offset info
                          call StdOut
                          xor eax,eax
                          mov al,BYTE ptr imgI.inone
                          push eax
                          push offset CTXT("未用:%02X",13,10)
                          push offset info
                          call wsprintf
                          push offset info
                          call StdOut
                          push imgI.reserved
                          push offset CTXT("保留字段:%08X",13,10)
                          push offset info
                          call wsprintf
                          push offset info
                          call StdOut
                          push imgI.imglenght
                          push offset CTXT("图象数据块长度:%ld",13,10)
                          push offset info
                          call wsprintf
                          push offset info
                          call StdOut
                          push imgI.ioffset
                          push offset CTXT("图象数据块相对于文件头部的偏移量:%ld",13,10)
                          push offset info
                          call wsprintf
                          push offset info
                          call StdOut
                          jmp ingoon


                          15楼2013-05-02 11:59
                          回复

                            ShowBMPHead:
                            ;输出bmpH结构的信息
                            push offset CTXT(13,10,"---------------------BMP信息头---------------------",13,10)
                            push offset info
                            call wsprintf
                            push offset info
                            call StdOut
                            push bmpH.headlength
                            push offset CTXT("信息头结构长度:%ld",13,10)
                            push offset info
                            call wsprintf
                            push offset info
                            call StdOut
                            push bmpH.iwidth
                            push offset CTXT("图像宽度:%ld",13,10)
                            push offset info
                            call wsprintf
                            push offset info
                            call StdOut
                            push bmpH.height
                            push offset CTXT("图像高度:%ld",13,10)
                            push offset info
                            call wsprintf
                            push offset info
                            call StdOut
                            xor eax,eax
                            mov ax,WORD ptr bmpH.biPlanes
                            push eax
                            push offset CTXT("位面板数:%d",13,10)
                            push offset info
                            call wsprintf
                            push offset info
                            call StdOut
                            xor eax,eax
                            mov ax,WORD ptr bmpH.biSizeImage
                            push eax
                            push offset CTXT("每像素所占位数:%d",13,10)
                            push offset info
                            call wsprintf
                            push offset info
                            call StdOut
                            push bmpH.biCompression
                            push offset CTXT("像素数据的压缩类型:%ld",13,10)
                            push offset info
                            call wsprintf
                            push offset info
                            call StdOut
                            push bmpH.imglenght
                            push offset CTXT("图象数据的长度:%ld",13,10)
                            push offset info
                            call wsprintf
                            push offset info
                            call StdOut
                            jmp colseend
                            end START


                            16楼2013-05-02 11:59
                            回复

                              (2)显示信息需要注意的地方。
                              使用invoke可以很方便的调用wsprintf来格式化字符串,但是我们使用压栈的方式调用的时候就要注意了。
                              压入栈的值是双字(4个字节)的,DW,DB之类的值直接push的话,结果显示出来的是错误的值,所以需要转为DD。
                              于是我们可以使用这个方法:先把eax清空,如果是DW型的数值,那么放入ax中再把eax 压入堆栈,如果是DB型的数值,那么放入al,再把eax压入堆栈。
                              DW:
                              xor eax,eax
                              mov ax,WORD ptr icoH.reserved;
                              push eax
                              push offset CTXT("保留字段:%02X",13,10)
                              push offset info
                              call wsprintf
                              DB:
                              xor eax,eax
                              mov al,BYTE ptr imgI.inone
                              push eax
                              push offset CTXT("未用:%02X",13,10)
                              push offset info
                              call wsprintf


                              17楼2013-05-02 12:00
                              回复