注册 登录
编程论坛 汇编论坛

PE文件学习笔记 - 更新中

onepc 发布于 2009-10-15 09:36, 1267 次点击
建议先去看雪的加壳与脱壳版块的置顶贴里先看下那些大大翻译的相关PE文章,用stud_pe工具辅助学习PE
http://bbs.
的第二楼
程序代码:
IMAGE_DOS_SIGNATURE equ 5A4Dh  ;这个是DOS签名 MZ
IMAGE_OS2_SIGNATURE equ 454Eh
IMAGE_OS2_SIGNATURE_LE equ 454Ch
IMAGE_VXD_SIGNATURE equ 454Ch
IMAGE_NT_SIGNATURE equ 4550h   ;NT下的PE头


;DOS MZ header 的结构是 IMAGE_DOS_HEADER
IMAGE_DOS_HEADER STRUCT
  e_magic           WORD      ?     ;IMAGE_DOS_SIGNATURE  5a4dh mz
  e_cblp            WORD      ?
  e_cp              WORD      ?
  e_crlc            WORD      ?
  e_cparhdr         WORD      ?
  e_minalloc        WORD      ?
  e_maxalloc        WORD      ?
  e_ss              WORD      ?
  e_sp              WORD      ?
  e_csum            WORD      ?
  e_ip              WORD      ?
  e_cs              WORD      ?
  e_lfarlc          WORD      ?
  e_ovno            WORD      ?
  e_res             WORD   4 dup(?)
  e_oemid           WORD      ?
  e_oeminfo         WORD      ?
  e_res2            WORD  10 dup(?)
  e_lfanew          DWORD      ?    ;此DWORD存放的值是PE HEAD对文件的偏移值。即是说从文件开头移到它指定长度的值之后就是PE头的开始。
IMAGE_DOS_HEADER ENDS
e_magic==IMAGE_DOS_SIGNATURE ;这个word型的值是MZ 一般检验一个PE文件都是先验证这个字是否是mz然后再检验PE签名

;一般编程时 先CreateFile打开一个文件,再用CreateFileMapping 建立内存映射文件对象
;调用MapViewOfFile函数把整个文件的一个区域或者整个文件映射到内存中。得到指向映射到内存的第一个字节的指针lpMemory
 mov edi, lpMemory  ;这里把lpMemory的地址传给edi 这时edi的值就是e_magic这里的第一个字节的位置
 assume edi:ptr IMAGE_DOS_HEADER  ;把edi指向一个dos头的结构。这时就可以用[edi].e_magic 来判断是否等于MZ的值了。
 .if [edi].e_magic==IMAGE_DOS_SIGNATURE ;判断

   add edi, [edi].e_lfanew  ;这里表示edi的值加上[edi].e_lfanew结构成员中的值。这时edi的值就PE头的位置
   assume edi:ptr IMAGE_NT_HEADERS ;就可以用assume指向这个nthead了。
   .if [edi].Signature==IMAGE_NT_SIGNATURE ;判断是否是PE这个值。



;PE header 是一个 IMAGE_NT_HEADERS 结构
IMAGE_NT_HEADERS32 STRUCT
  Signature       DWORD ?
  FileHeader      IMAGE_FILE_HEADER <>
  OptionalHeader  IMAGE_OPTIONAL_HEADER32 <>
IMAGE_NT_HEADERS32 ENDS

;stPeHead IMAGE_NT_HEADERS32 <?>
;stPeHead.Signature  dword型 值为 50h,45h,00h,00h (PE\0\0) 若e_magic的值是mz,这个值又是pe的话则证明是一个PE文件


只有本站会员才能查看附件,请 登录


[ 本帖最后由 onepc 于 2009-10-15 09:45 编辑 ]
3 回复
#2
onepc2009-10-16 09:46
程序代码:
;边理解PE结构边自己写查看的程序
;看别人的程序,还是要自己动手写一下才深刻一点的。
;简单的查看。未完成
;by onepc 153785587
.386
.model flat,stdcall
option casemap:none
 
include windows.inc
include user32.inc
include kernel32.inc
;include gdi32.inc  ;图形
 
includelib user32.lib
includelib kernel32.lib
;includelib gde32.lib
 
include comdlg32.inc
includelib comdlg32.lib
 
include macro.asm  ;ctxt("")
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IDD_TEST_DIALOG    equ             102
IDR_MAINFRAME       equ            128
IDD_DIALOG1       equ              129
IDC_BUTTON1      equ               1000
IDC_BUTTON2    equ                 1001
IDC_EDIT1     equ                  1003
IDC_EDIT7    equ                   1004
IDC_EDIT2   equ                    1005
IDC_EDIT3    equ                   1006
IDC_EDIT4      equ                 1007
IDC_EDIT5     equ                  1008
IDC_EDIT6     equ                  1009
IDC_BUTTON3    equ                 1010
IDC_LIST2     equ                  1012
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
IMAGE_DOS_SIGNATURE equ 5A4Dh  ;MZ
IMAGE_NT_SIGNATURE equ 4550h   ;PE
 
 
 
.data
szFilter    db    'Text Files(*.exe)',0,'*.exe',0,'Dll Files(*.dll)',0,'*.dll',0,0
 
szFmatTxt db '%08X',0
.data?
hInstance dd ?  ;模块句柄
hMain dd ?      ;对话框句柄
 
hFile dd ?   ;CreateFile 返回文件句柄
hMapFile dd ? ;CreateFileMapping 返回内存映射文件句柄
lPMemory dd ? ;MapViewOfFile 返回文件映射到内存的第一个字节的指针
 
 
 
 
szPath db MAX_PATH dup(?)  ;文件路径缓冲区
 
szTemBuffer db MAX_PATH dup (?)
 
 
 
 
.code
 
 
 
 
 
;***********************打开文件***********************
_OpenFile proc  
          local @stFile:OPENFILENAME
          invoke RtlZeroMemory,addr @stFile,sizeof @stFile  ;填零
          mov @stFile.lStructSize,sizeof @stFile
          push hMain
          pop @stFile.hwndOwner
          ;mov @stFile.hwndOwner,hMin
          mov @stFile.lpstrFilter,offset szFilter
          mov @stFile.lpstrFile,offset szPath
          mov @stFile.nMaxFile,MAX_PATH
          mov @stFile.Flags,OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST
          invoke GetOpenFileName,addr @stFile
          .if eax      ;getopenfilename打开成功的话返回非0值
                ;invoke    MessageBox,NULL,addr szPath,addr szPath,MB_OK
                invoke SetDlgItemText,hMain,IDC_EDIT7,addr szPath
                invoke GetDlgItem,hMain,IDC_BUTTON1
                invoke EnableWindow,eax,TRUE
                invoke GetDlgItem,hMain,IDC_BUTTON2
                invoke EnableWindow,eax,TRUE
             ;.else
             ;  invoke MessageBox,NULL,CTXT("aa"),CTXT("aa"),0
          .endif
    ret
_OpenFile endp
;***********************打开文件***********************
 
 
;***********************映射文件***********************
_CreateFileMap proc
   invoke CreateFile,addr szPath,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL
     .if eax==INVALID_HANDLE_VALUE
         invoke MessageBox,NULL,CTXT("打开文件出错!"),CTXT("Erorr"),NULL
         ret
     .endif  
   mov hFile,eax  
   invoke CreateFileMapping,hFile,NULL,PAGE_READONLY,0,0,NULL
      .if !eax
         invoke CloseHandle,hFile
         invoke MessageBox,NULL,CTXT("映射文件出错!"),CTXT("Erorr"),NULL
         
         ret
      .endif
   mov hMapFile,eax
   invoke MapViewOfFile,hMapFile,FILE_MAP_READ,NULL,NULL,NULL
      .if !eax
         invoke CloseHandle,hMapFile
         invoke CloseHandle,hFile      
         invoke MessageBox,NULL,CTXT("映射到内存出错!"),CTXT("Erorr"),NULL
         ret
      .endif
   mov lPMemory,eax
  ret
_CreateFileMap endp
;***********************映射文件***********************
 
 
 
 
;***********************PE CHECK***********************
_PeInfo proc uses esi edi ebx
  mov esi,lPMemory
  assume esi:ptr IMAGE_DOS_HEADER
   .if [esi].e_magic==IMAGE_DOS_SIGNATURE
       add esi,[esi].e_lfanew
         assume esi:ptr IMAGE_NT_HEADERS
           .if [esi].Signature==IMAGE_NT_SIGNATURE  
               ;invoke MessageBox,NULL,CTXT("是一个PE文件!"),CTXT("OK"),NULL
               
                ; call _ShowPeInfo
                ;**************************************************************************
                   movzx eax,[esi].FileHeader.NumberOfSections
                   invoke SetDlgItemInt,hMain,IDC_EDIT6,eax,FALSE
                    
                   mov eax,[esi].OptionalHeader.ImageBase
                   invoke wsprintf,addr szTemBuffer,addr szFmatTxt,eax
                   invoke SetDlgItemText,hMain,IDC_EDIT1,addr szTemBuffer
                   ;invoke SetDlgItemInt,hMain,IDC_EDIT1,eax,FALSE
                    
                   mov eax,[esi].OptionalHeader.AddressOfEntryPoint
                   ;invoke SetDlgItemInt,hMain,IDC_EDIT2,eax,FALSE
                   invoke wsprintf,addr szTemBuffer,addr szFmatTxt,eax
                   invoke SetDlgItemText,hMain,IDC_EDIT2,addr szTemBuffer
                    
                   mov eax,[esi].OptionalHeader.FileAlignment
                   ;invoke SetDlgItemInt,hMain,IDC_EDIT3,eax,FALSE
                   invoke wsprintf,addr szTemBuffer,addr szFmatTxt,eax
                   invoke SetDlgItemText,hMain,IDC_EDIT3,addr szTemBuffer
                   mov eax,[esi].OptionalHeader.SectionAlignment
                   ;invoke SetDlgItemInt,hMain,IDC_EDIT4,eax,FALSE
                   invoke wsprintf,addr szTemBuffer,addr szFmatTxt,eax
                   invoke SetDlgItemText,hMain,IDC_EDIT4,addr szTemBuffer
                    
                   mov eax,[esi].OptionalHeader.SizeOfImage
                   ;invoke SetDlgItemInt,hMain,IDC_EDIT4,eax,FALSE
                   invoke wsprintf,addr szTemBuffer,addr szFmatTxt,eax
                   invoke SetDlgItemText,hMain,IDC_EDIT5,addr szTemBuffer
                 ;**************************************************************************
                ; ret
                .else
                invoke MessageBox,NULL,CTXT("不是有效PE文件"),CTXT("ERROR"),0   
                    ;call @F
            .endif  
       .else
        invoke MessageBox,NULL,CTXT("不是有效PE文件"),CTXT("ERROR"),0   
          ;call @F
   .endif
   @@:   invoke UnmapViewOfFile,lPMemory
         invoke CloseHandle,hMapFile
         invoke CloseHandle,hFile  
   
  ret
_PeInfo endp  
;***********************PE CHECK***********************
 
 
;***********************PE SHOW***********************
_ShowPeInfo proc
 
   
 
   ret
_ShowPeInfo endp
;***********************PE SHOW***********************
 
 
 
 
 
 
;;对话框回调过程
_DlgProc proc uses esi edi ebx hDlg,uMsg,wParam,lParam
.if uMsg==WM_INITDIALOG   ;对话框初始化
    push hDlg
    pop hMain
    invoke LoadIcon,hInstance,IDR_MAINFRAME
    invoke    SendMessage,hDlg,WM_SETICON,ICON_BIG,eax
    ;灰化Button
    invoke GetDlgItem,hDlg,IDC_BUTTON1
    invoke EnableWindow,eax,FALSE
    invoke GetDlgItem,hDlg,IDC_BUTTON2
    invoke EnableWindow,eax,FALSE
     
 
     
.elseif uMsg==WM_COMMAND
    mov eax,wParam
    .if ax==IDC_BUTTON1     ;ReadFile
        ;invoke EndDialog,hDlg,TRUE
        call _CreateFileMap
       call _PeInfo
     
    .elseif ax==IDC_BUTTON2   
     
    .elseif ax==IDC_BUTTON3   ;OpenFile
        call _OpenFile
    .endif
     
.elseif uMsg==WM_CLOSE
 
 
     
    invoke EndDialog,hDlg,FALSE
.else
    mov eax,FALSE
    ret
.endif
mov eax,TRUE
ret
_DlgProc endp
;;对话框回调过程
  
 
start:
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke DialogBoxParam,hInstance,IDD_TEST_DIALOG,NULL,addr _DlgProc,NULL
invoke ExitProcess,NULL
 
end start




程序代码:

#include "resource.h"
 
#define IDD_TEST_DIALOG                 102
#define IDR_MAINFRAME                   128
#define IDD_DIALOG1                     129
#define IDC_BUTTON1                     1000
#define IDC_BUTTON2                     1001
#define IDC_EDIT1                       1003
#define IDC_EDIT7                       1004
#define IDC_EDIT2                       1005
#define IDC_EDIT3                       1006
#define IDC_EDIT4                       1007
#define IDC_EDIT5                       1008
#define IDC_EDIT6                       1009
#define IDC_BUTTON3                     1010
#define IDC_LIST2                       1012
IDR_MAINFRAME           ICON    DISCARDABLE     "test.ico"
 
 
IDD_TEST_DIALOG DIALOGEX 0, 0, 230, 177
STYLE DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE |  
    WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_APPWINDOW
CAPTION "32ASM - PE AND 界面"
FONT 9, "宋体"
BEGIN
    PUSHBUTTON      "ReadFile",IDC_BUTTON1,47,146,50,17
    PUSHBUTTON      "ImportTable",IDC_BUTTON2,116,145,54,17
    LTEXT           "ImageBase:",IDC_STATIC,52,15,45,8
    LTEXT           "File Alignment:",IDC_STATIC,32,47,65,8
    LTEXT           "EntryPoint:",IDC_STATIC,48,31,49,8
    LTEXT           "Sections Alignment:",IDC_STATIC,15,64,81,8
    LTEXT           "SizeOfImage:",IDC_STATIC,44,79,65,8
    LTEXT           "Number of sections:",IDC_STATIC,15,94,81,8
    EDITTEXT        IDC_EDIT1,97,12,105,12,ES_AUTOHSCROLL
    EDITTEXT        IDC_EDIT2,97,28,105,12,ES_AUTOHSCROLL
    EDITTEXT        IDC_EDIT3,97,44,105,12,ES_AUTOHSCROLL
    EDITTEXT        IDC_EDIT4,97,61,105,12,ES_AUTOHSCROLL
    EDITTEXT        IDC_EDIT5,97,77,105,12,ES_AUTOHSCROLL
    EDITTEXT        IDC_EDIT6,97,93,105,12,ES_AUTOHSCROLL
    EDITTEXT        IDC_EDIT7,17,121,136,14,ES_AUTOHSCROLL
    PUSHBUTTON      "Open File",IDC_BUTTON3,163,119,47,16
END
 
IDD_DIALOG1 DIALOG DISCARDABLE  0, 0, 227, 156
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "PE"
FONT 10, "System"
BEGIN
END
 
#3
onepc2009-10-16 10:01
程序代码:
PE文件结构收集 保存为asm 用masmplues看


byonepc 153785587
IMAGE_DOS_SIGNATURE equ 5A4Dh  ;这个是DOS签名 MZ
IMAGE_OS2_SIGNATURE equ 454Eh  
IMAGE_OS2_SIGNATURE_LE equ 454Ch  
IMAGE_VXD_SIGNATURE equ 454Ch  
IMAGE_NT_SIGNATURE equ 4550h   ;NT下的PE头  
;DOS MZ header 的结构是 IMAGE_DOS_HEADER  
IMAGE_DOS_HEADER STRUCT
  e_magic           WORD      ?     ;IMAGE_DOS_SIGNATURE  5a4dh mz
  e_cblp            WORD      ?
  e_cp              WORD      ?
  e_crlc            WORD      ?
  e_cparhdr         WORD      ?
  e_minalloc        WORD      ?
  e_maxalloc        WORD      ?
  e_ss              WORD      ?
  e_sp              WORD      ?
  e_csum            WORD      ?
  e_ip              WORD      ?
  e_cs              WORD      ?
  e_lfarlc          WORD      ?
  e_ovno            WORD      ?
  e_res             WORD   4 dup(?)
  e_oemid           WORD      ?
  e_oeminfo         WORD      ?
  e_res2            WORD  10 dup(?)
  e_lfanew          DWORD      ?    ;此DWORD存放的值是PE HEAD对文件的偏移值。即是说从文件开头移到它指定长度的值之后就是PE头的开始。
IMAGE_DOS_HEADER ENDS
e_magic==IMAGE_DOS_SIGNATURE ;这个word型的值是MZ 一般检验一个PE文件都是先验证这个字是否是mz然后再检验PE签名  
 
;一般编程时 先CreateFile打开一个文件,再用CreateFileMapping 建立内存映射文件对象
;调用MapViewOfFile函数把整个文件的一个区域或者整个文件映射到内存中。得到指向映射到内存的第一个字节的指针lpMemory
  mov edi, lpMemory  ;这里把lpMemory的地址传给edi 这时edi的值就是e_magic这里的第一个字节的位置  
  assume edi:ptr IMAGE_DOS_HEADER  ;把edi指向一个dos头的结构。这时就可以用[edi].e_magic 来判断是否等于MZ的值了。
  .if [edi].e_magic==IMAGE_DOS_SIGNATURE ;判断
  add edi, [edi].e_lfanew  ;这里表示edi的值加上[edi].e_lfanew结构成员中的值。这时edi的值就PE头的位置
  assume edi:ptr IMAGE_NT_HEADERS ;就可以用assume指向这个nthead了。
  .if [edi].Signature==IMAGE_NT_SIGNATURE ;判断是否是PE这个值。
 
 
 
;PE header 是一个 IMAGE_NT_HEADERS 结构  [COFF HEADER]
IMAGE_NT_HEADERS32 STRUCT
  Signature       DWORD ?
  FileHeader      IMAGE_FILE_HEADER <>  ;结构中的结构
  OptionalHeader  IMAGE_OPTIONAL_HEADER32 <>
IMAGE_NT_HEADERS32 ENDS
 
;stPeHead IMAGE_NT_HEADERS32 <?>
;stPeHead.Signature  dword型 值为 50h,45h,00h,00h (PE\0\0) 若e_magic的值是mz,这个值又是pe的话则证明是一个PE文件
 
 
;FileHeader 文件头  stud_pe 里显示的是COFF HEADER
IMAGE_FILE_HEADER STRUCT
  Machine               WORD    ? ;这个PE文件运行的所要求CPU ;Intel一般的值是014ch
  NumberOfSections      WORD    ?;文件的节数目。如果我们要在文件中增加或删除一个节,就需要修改这个值。
  TimeDateStamp         DWORD   ?;文件创建日期和时间
  PointerToSymbolTable  DWORD   ?
  NumberOfSymbols       DWORD   ?
  SizeOfOptionalHeader  WORD    ?;指示紧随本结构之后的 OptionalHeader [IMAGE_OPTIONAL_HEADER 可选头]结构大小,必须为有效值。
  Characteristics       WORD    ?;关于文件信息的标记,比如文件是exe还是dll。
IMAGE_FILE_HEADER ENDS
 
;Machine 已知合法的值
;  IMAGE_FILE_MACHINE_I386 (0x14c)   Intel 80386 处理器或更高
;  0x014d          Intel 80386 处理器或更高
;  0x014e          Intel 80386 处理器或更高
;  0x0160                     R3000 (MIPS⑧)处理器
;  IMAGE_FILE_MACHINE_R3000 (0x162)           R3000 (MIPS)处理器
;  IMAGE_FILE_MACHINE_R4000 (0x166)           R4000 (MIPS)处理器
;  IMAGE_FILE_MACHINE_R10000 (0x168)           R10000 (MIPS)处理器
;  IMAGE_FILE_MACHINE_ALPHA (0x184)           DEC Alpha AXP⑩处理器
;  IMAGE_FILE_MACHINE_POWERPC (0x1F0)           IBM Power PC
 
;Characteristics       WORD  
;数  据  位     Windows.inc中的预定义值         为1时的含义
;0 IMAGE_FILE_RELOCS_STRIPPED               文件中不存在重定位信息
;1 IMAGE_FILE_EXECUTABLE_IMAGE              文件是可执行的
;2 IMAGE_FILE_LINE_NUMS_STRIPPED             不存在行信息
;3 IMAGE_FILE_LOCAL_SYMS_STRIPPED          不存在符号信息
;7 IMAGE_FILE_BYTES_REVERSED_LO            小尾方式
;8 IMAGE_FILE_32BIT_MACHINE               只在32位平台上运行
;数  据  位     Windows.inc中的预定义值      为1时的含义
;9 IMAGE_FILE_DEBUG_STRIPPED              不包含调试信息
;10 IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP      不能从可移动盘(如软盘、光盘)运行
;11 IMAGE_FILE_NET_RUN_FROM_SWAP           不能从网络运行
;12 IMAGE_FILE_SYSTEM                     系统文件(如驱动程序),不能直接运行
;13 IMAGE_FILE_DLL                           这是一个 DLL 文件
;14 IMAGE_FILE_UP_SYSTEM_ONLY             文件不能在多处理器上计算机上运行
;15 IMAGE_FILE_BYTES_REVERSED_HI                大尾方式
;对于普通的可执行PE文件,这个字段的值一般是010fh,而对于DLL文件来说,这个字段的值一般是210eh。
 
;NumberOfSections
;节表是一个结构数组,每个结构包含一个节的信息。因此若有3个节,数组就有3个成员。  
;我们需要NumberOfSections值来了解该数组中到底有几个成员。  
;也许您会想检测结构中的全0成员起到同样效果。Windows确实采用了这种方法。
;为了证明这一点,可以增加NumberOfSections的值,Windows仍然可以正常执行文件。
;据我们的观察,Windows读取NumberOfSections的值然后检查节表里的每个结构,如果找到一个全0结构就结束搜索,
;否则一直处理完NumberOfSections指定数目的结构。
 
 
 
 
;RAV == 相对偏移地址,比如装入的地址是40000 ,某一节的RAV值是1000 ,那么这个节在内存中的位置的地址是 41000h
 
;IMAGE_OPTIONAL_HEADER32 可选头结构
 
IMAGE_OPTIONAL_HEADER32 STRUCT
  Magic                         WORD       ?
  MajorLinkerVersion            BYTE       ?
  MinorLinkerVersion            BYTE       ?
  SizeOfCode                    DWORD      ?;所有含代码的节的总大小
  SizeOfInitializedData         DWORD      ?;所有含已初始化数据的节的总大小
  SizeOfUninitializedData       DWORD      ?;所有含未初始化数据的节的大小
  AddressOfEntryPoint           DWORD      ?;PE装载器准备运行的PE文件的第一个指令的RVA。若您要改变整个执行的流程
  ;可以将该值指定到新的RVA,这样新RVA处的指令首先被执行。
  BaseOfCode                    DWORD      ?;代码的节的起始RVA
  BaseOfData                    DWORD      ?;数据的节的起始RVA
  ImageBase                     DWORD      ?;PE文件的优先装载地址。比如,如果该值是400000h,PE装载器将尝试把文件
  ;装到虚拟地址空间的400000h处。字眼"优先"表示若该地址区域已被其他模块占用,那PE装载器会选用其他空闲地址。
  SectionAlignment              DWORD      ?;内存中节对齐的粒度。例如,如果该值是4096 (1000h),那么每节的起始地址必须是4096的倍数。
  ;若第一节从401000h开始且大小是10个字节,则下一节必定从402000h开始,即使401000h和402000h之间还有很多空间没被使用。
  FileAlignment                 DWORD      ?;文件中节对齐的粒度。例如,如果该值是(200h),那么每节的起始地址必须是512的
  ;倍数。若第一节从文件偏移量200h开始且大小是10个字节,则下一节必定位于偏移量400h: 即使偏移量512和1024之间还有很多空间没被使用定义。
  MajorOperatingSystemVersion   WORD       ?
  MinorOperatingSystemVersion   WORD       ?
  MajorImageVersion             WORD       ?
  MinorImageVersion             WORD       ?
  MajorSubsystemVersion         WORD       ?
  MinorSubsystemVersion         WORD       ?
  Win32VersionValue             DWORD      ?
  SizeOfImage                   DWORD      ?;内存中整个PE映像体的尺寸。它是所有头和节经过节对齐处理后的大小。  
  SizeOfHeaders                 DWORD      ?;所有头+节表的大小,也就等于文件尺寸减去文件中所有节的尺寸。可以以此值作为PE文件第一节的文件偏移量。
  CheckSum                      DWORD      ?
  Subsystem                     WORD       ?
  DllCharacteristics            WORD       ?
  SizeOfStackReserve            DWORD      ?;初始化时的堆栈大小
  SizeOfStackCommit             DWORD      ?;初始化时实际提交的堆栈大小
  SizeOfHeapReserve             DWORD      ?;初始化时保留的堆大小
  SizeOfHeapCommit              DWORD      ?;初始化时实际提交的堆大小
  LoaderFlags                   DWORD      ?
  NumberOfRvaAndSizes           DWORD      ?;下面的数据目录结构的数量 10h ==16
  DataDirectory                 IMAGE_DATA_DIRECTORY IMAGE_NUMBEROF_DIRECTORY_ENTRIES dup(<>)
  ;一IMAGE_DATA_DIRECTORY 结构数组。每个结构给出一个重要数据结构的RVA,比如引入地址表等。
IMAGE_OPTIONAL_HEADER32 ENDS
 
IMAGE_OPTIONAL_HEADER  equ  <IMAGE_OPTIONAL_HEADER32>
 
;ImageBase
;指出文件的优先装入地址。也就是说当文件被执行时,如果可能的话,Windows优先将文件装入到由ImageBase字段指定的地址中,
;只有指定的地址已经被其他模块使用时,文件才被装入到其他地址中。链接器产生可执行文件的时候对应这个地址来生成机器码,
;所以当文件被装入这个地址时不需要进行重定位操作,装入的速度最快
;对于EXE文件来说,由于每个文件总是使用独立的虚拟地址空间,优先装入地址不可能被其他模块占据,
;所以EXE总是能够按照这个地址装入,这也意味着EXE文件不再需要重定位信息。对于DLL文件来说,
;由于多个DLL文件全部使用宿主EXE文件的地址空间,不能保证优先装入地址没有被其他的DLL使用,
;所以DLL文件中必须包含重定位信息以防万一。因此,在IMAGE_FILE_HEADER 结构的Characteristics字段中,
;DLL文件对应的IMAGE_FILE_RELOCS_STRIPPED位总是为0,而EXE文件的这个标志位总是为1。
;在链接的时候,可以通过对link.exe指定/base:address选项来自定义优先装入地址,如果不指定这个选项的话,
;一般EXE文件的默认优先装入地址被定为00400000h,而DLL文件的默认优先装入地址被定为10000000h。
 
 
 
 
;DataDirectory    某种数据块的位置和长度
IMAGE_DATA_DIRECTORY STRUCT
  VirtualAddress    DWORD      ?  ;数据的起始RVA
  isize             DWORD      ?  ;数据块的长度
IMAGE_DATA_DIRECTORY ENDS
;索引   索引值在Windows.inc中的预定义值    对应的数据块
;0          IMAGE_DIRECTORY_ENTRY_EXPORT        导出表
;1          IMAGE_DIRECTORY_ENTRY_IMPORT        导入表
;2          IMAGE_DIRECTORY_ENTRY_RESOURCE      资源
;3          IMAGE_DIRECTORY_ENTRY_EXCEPTION     异常(具体资料不详)
;4          IMAGE_DIRECTORY_ENTRY_SECURITY      安全(具体资料不详)
;5          IMAGE_DIRECTORY_ENTRY_BASERELOC        重定位表
;6          IMAGE_DIRECTORY_ENTRY_DEBUG        调试信息
;7          IMAGE_DIRECTORY_ENTRY_ARCHITECTURE   版权信息
;8          IMAGE_DIRECTORY_ENTRY_GLOBALPTR      具体资料不详
;9          IMAGE_DIRECTORY_ENTRY_TLS            Thread Local Storage
;10         IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG      具体资料不详
;11         IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT     具体资料不详
;12         IMAGE_DIRECTORY_ENTRY_IAT           导入函数地址表
;13         IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT    具体资料不详
;14         IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR   具体资料不详
;15                                                 未使用
 
;VirtualAddress 实际上是数据结构的相对虚拟地址(RVA)。比如,如果该结构是关于import symbols的,
;该域就包含指向IMAGE_IMPORT_DESCRIPTOR 数组的RVA。  
;isize 含有VirtualAddress所指向数据结构的字节数。
 
 
; 在PE文件中寻找特定的数据时就是从这些IMAGE_DATA_DIRECTORY结构开始的,比如要存取资源,那么必须从
; 第3个IMAGE_DATA_DIRECTORY结构(索引为2)中得到资源数据块的大小和位置;同理,如果要查看PE文件导入了
; 哪些DLL文件的哪些API函数,那就必须首先从第2个IMAGE_DATA_DIRECTORY结构得到导入表的位置和大小。
 
;导入表*****************************************
;data directory数组第二项的VirtualAddress包含导入表地址。导入表实际上是一个 IMAGE_IMPORT_DESCRIPTOR 结构数组。
;导入表由一系列的IMAGE_IMPORT_DESCRIPTOR结构组成,结构的数量取决于程序要使用的DLL文件的数量,
;每个结构对应一个DLL文件,例如,如果一个PE文件从10个不同的DLL文件中引入了函数,那么就存在10个IMAGE_IMPORT_DESCRIPTOR
;结构来描述这些DLL文件,在所有这些结构的最后,由一个内容全为0的IMAGE_IMPORT_DESCRIPTOR结构作为结束。
IMAGE_IMPORT_DESCRIPTOR STRUCT
    union
        Characteristics dd      ?
        OriginalFirstThunk dd   ?
     ends
    TimeDateStamp dd    ?
    ForwarderChain dd   ?
    Name1 dd            ?
    FirstThunk dd       ?
IMAGE_IMPORT_DESCRIPTOR ENDS
 
;结构中的Name1字段(使用Name1作为字段名同样是因为Name一词和MASM的关键字冲突)是一个RVA,
;它指向此结构所对应的DLL文件的名称,这个文件名是一个以NULL结尾的字符串。
 
;OriginalFirstThunk字段和FirstThunk字段的含义现在可以看成是相同的
;它们都指向一个包含一系列IMAGE_THUNK_DATA32结构的数组,数组中的每个IMAGE_THUNK_DATA32结构定义了一个导入函数的信息,
;数组的最后以一个内容为0的IMAGE_THUNK_DATA结构作为结束。
;一个IMAGE_THUNK_DATA32结构实际上就是一个双字,之所以把它定义成结构,是因为它在不同的时刻有不同的含义,结构的定义如下:
IMAGE_THUNK_DATA32 STRUCT
    union u1
        ForwarderString dd  ?
        Function dd         ?
        Ordinal dd          ?
        AddressOfData dd    ?
    ends
IMAGE_THUNK_DATA32 ENDS
 
;一个IMAGE_THUNK_DATA结构如何用来指定一个导入函数呢?当双字(就是指结构!)的最高位为1时,
;表示函数是以序号的方式导入的,这时双字的低位就是函数的序号。读者可以用预定义值IMAGE_ORDINAL_FLAG32(或80000000h)
;来对最高位进行测试,当双字的最高位为0时,表示函数以字符串类型的函数名方式导入,这时双字的值是一个RVA,
;指向一个用来定义导入函数名称的IMAGE_IMPORT_BY_NAME结构,此结构的定义如下:
IMAGE_IMPORT_BY_NAME STRUCT
    Hint dw     ?
    Name1 db    ?
IMAGE_IMPORT_BY_NAME ENDS
;结构中的Hint字段也表示函数的序号,不过这个字段是可选的,有些编译器总是将它设置为0,
;Name1字段定义了导入函数的名称字符串,这是一个以0为结尾的字符串。
 
 
 
;导入地址表(IAT)
;IMAGE_IMPORT_DESCRIPTOR结构中FirstThunk字段指向的数组最后会被替换成导入函数的真正入口地址,
;暂且把这个数组称为导入地址数组。在PE文件中,所有DLL对应的导入地址数组在位置上是被排列在一起的,
;全部这些数组的组合也被称为导入地址表(Import Address Table,或者简称为IAT),
;导入表中第一个IMAGE_IMPORT_DESCRIPTOR结构的FirstThunk字段指向的就是IAT的起始地
 
 
 
 
 
 
 
 
;之后就是节表了。节表后面是各节数据。   
;PE文件装入内存时,文件头到节节之间的数据是原始装入的不会处理的。节数据会按节对齐处理
 
;PE文件中所有节的属性都被定义在节表中,节表由一系列的IMAGE_SECTION_HEADER结构排列而成,
;每个结构用来描述一个节,结构的排列顺序和它们描述的节在文件中的排列顺序是一致的。
;全部有效结构的最后以一个空的IMAGE_SECTION_HEADER结构作为结束,所以节表中总的IMAGE_SECTION_HEADER
;结构数量等于节的数量加一。节表总是被存放在紧接在PE文件头的地方,也就是从PE文件头(注意:不是文件本身的头部)
;开始的偏移为00f8h的地方。
;用stud_pe查看文件 pe头开始位置在100处。那么偏移0f8h处就是在 1f8h处。这里就是节表开始位置
 
 
IMAGE_SECTION_HEADER STRUCT
    Name1 db IMAGE_SIZEOF_SHORT_NAME dup(?);事实上本域的名称是"name",只是"name"已被MASM用作关键字,所以我们只能用"Name1"代替。
    ;这儿的节名长不超过8字节。记住节名仅仅是个标记而已,我们选择任何名字甚至空着也行,注意这里不用null结束。命名不是一个ASCIIZ字符串,所以不用null结尾。
    union Misc
        PhysicalAddress dd  ?
        VirtualSize dd      ? ;节区的尺寸;代表节的大小,这是节的数据在没有进行对齐处理前的实际大小。
    ends
    VirtualAddress dd       ?;本节的RVA(相对虚拟地址)。PE装载器将节映射至内存时会读取本值,因此如果域值是1000h,
    ;而PE文件装在地址400000h处,那么本节就被载到401000h。它的数值总是SectionAlignment的值的整数倍
    SizeOfRawData dd        ?;经过文件对齐处理后节尺寸,PE装载器提取本域值了解需映射入内存的节字节数。
    ;(译者注: 假设一个文件的文件对齐尺寸是0x200,如果前面的 VirtualSize域指示本节长度是0x388字节,则本域值为0x400,表示本节是0x400字节长)。
    PointerToRawData dd     ?;这是节基于文件的偏移量,PE装载器通过本域值找到节数据在文件中的位置。
    PointerToRelocations dd ?
    PointerToLinenumbers dd ?
    NumberOfRelocations dw  ?
    NumberOfLinenumbers dw  ?
    Characteristics dd      ?;含标记以指示节属性,比如节是否含有可执行代码、初始化数据、未初始数据,是否可写、可读等。
IMAGE_SECTION_HEADER ENDS
 
;Characteristics    数据位在Windows.inc中的预定义值以及为1时的含义
;5  (IMAGE_SCN_CNT_CODE或00000020h)节中包含代码
;6  (IMAGE_SCN_CNT_INITIALIZED_DATA或00000040h)节中包含已初始化数据
;7  (IMAGE_SCN_CNT_UNINITIALIZED_DATA或00000080h)节中包含未初始化数据
;25 (IMAGE_SCN_MEM_DISCARDABLE或02000000h)节中的数据在进程开始以后将被丢弃,前面举例的包含重定位表的.reloc节就是一个例子  
;26 (IMAGE_SCN_MEM_NOT_CACHED或04000000h)节中的数据不会经过缓存
;27 (IMAGE_SCN_MEM_NOT_PAGED或08000000h)节中的数据不会被交换到磁盘  
;28 (IMAGE_SCN_MEM_SHARED或10000000h)表示节中的数据将被不同的进程所共享,在第11章的钩子例子中的共享数据的节就设置了这个属性标志  
;29 (IMAGE_SCN_MEM_EXECUTE或20000000h)映射到内存后的页面包含可执行属性
;30 (IMAGE_SCN_MEM_READ或40000000h)映射到内存后的页面包含可读属性
;31 (IMAGE_SCN_MEM_WRITE或80000000h)映射到内存后的页面包含可写属性
;代码节的属性一般为60000020h,也就是可执行、可读和“节中包含代码”;
;数据节的属性一般为c0000040h,也就是可读、可写和“包含已初始化数据”;
;而常量节(对应源代码中的.const段)的属性为40000040h,也就是可读和“包含已初始化数据”;
;资源节的属性和常量节的属性一般是相同的。
 
 
;当从PE文件中读取需要的节时,不能以节的名称作为定位标准,
;正确的方法是按照IMAGE_OPTIONAL_HEADER32结构中的数据目录字段定位。
 
;要到节头的地方,只要在指向NT头这里。再把这个位置加上NT头的大小这时这个值就是指向节头的起始位置了。就可以根据
;NT头里的节数目就可以循环读取各节头指示的东东 [节表]
;其实PE文件从开始到节头结尾这里是固定的,只有从节的数据区开始就是不定的。
;所以定位各个地方时,可以用定好的结构,那也可以手写算。^_^!
assume edi:ptr IMAGE_NT_HEADERS
add edi,sizeof IMAGE_NT_HEADERS
assume esi:ptr IMAGE_SECTION_HEADER
 
 


[ 本帖最后由 onepc 于 2009-10-16 10:04 编辑 ]
#4
psdx2009-10-26 18:42
mark,跟班学习一下
1