当前位置: 首页 > news >正文

第2章 三个小工具的编写(2)

2.3 PEComp的实现

PEComp是PE文件比较器。功能是按照PE文件格式的数据结构按字段对两个指定的PE文件进行比对,以获取两个PE文件结构中的不相同的信息。在实际应用中,我们可以通过对比病毒感染前后PE文件在相关字段上发生的变化来判断病毒的感染方式,从而确定清理病毒的方法。

2.3.1 编程思路

PEComp的功能是在通用框架pe.asm的基础上,实现两个PE文件的对比,并通过图形界面将不同之处形象地表示出来。编码的大致思路如下:

步骤1 打开要比较的两个文件,分别进行文件的内存映射,获取内存起始地址。

步骤2 线性搜索,根据文件头部内容确定该文件是否为PE文件,不是则退出。

步骤3 将esi指向要操作的第一个文件的相关字段处,将edi指向第二个要操作的文件的相同字段处,同时获取该位置的指定个数的字节到内存,比较并显示,如果不同,则显示时使用红色背景以示区别。

下面开始具体的设计过程,首先根据构思的最终显示效果定义资源文件。

2.3.2 定义资源文件

将2.1.2节中的资源文件pe.rc复制到pecomp.rc,并在pecomp.rc文件中增加一个对话框,该对话框中包括用户选择的参与对比的两个PE文件文本框ID_TEXT1和ID_TEXT2、两个浏览按钮、一个显示结果用的表格IDC_MODULETABLE和一个执行按钮,增加的对话框脚本定义如下所示:

  RESULT_MODULE DIALOG 76,10,630,480STYLE DS_MODALFRAME | WS_POPUP |WS_VISIBLE | WS_CAPTION |WS_SYSMENUCAPTION "PE文件对比结果"FONT 9,"宋体"BEGINLTEXT "您选定的第一个文件为:",ID_STATIC,10,13,200,15EDITTEXT ID_TEXT1,130,13,440,15PUSHBUTTON "浏览...",IDC_BROWSE1,570,13,50,14LTEXT "您选定的第二个文件为:",ID_STATIC1,10,35,200,15EDITTEXT ID_TEXT2,130,35,440,15PUSHBUTTON "浏览...",IDC_BROWSE2,570,35,50,14CONTROL  "",  IDC_MODULETABLE,  "SysListView32",13  |  WS_CHILD  |  WS_VISIBLE  |WS_BORDER | WS_TABSTOP, 10,60,610,390AUTOCHECKBOX "只显示不同的值" IDC_THESAME,10,460,100,14PUSHBUTTON "执行...(&R)",IDC_OK,570,460,50,14END

2.3.3 PEComp编码

复制pe.asm到PEComp.asm,并从代码中的窗口回调函数的菜单项响应部分开始编码,增加内容有以下4个部分。

1.菜单项响应代码

在主窗口的回调函数中,定义对鼠标点击菜单项“文件”|“打开”所引发的消息处理程序,添加如下代码:

.elseif eax==IDM_OPEN    ;打开PE文件对比对话框invoke DialogBoxParam,hInstance,RESULT_MODULE,hWnd,\offset _resultProcMain,0invoke InvalidateRect,hWnd,NULL,TRUEinvoke UpdateWindow,hWnd

当用户选择了“打开”菜单选项时,会弹出资源文件里定义的对话框RESULT_MODULE。通过定义该对话框的回调函数,可以处理对话框控件发出的消息。该对话框的回调函数是_resultProcMain,其代码如代码清单2-4所示。

代码清单2-4 PE文件比较器的窗口回调函数_resultProcMain实现(chapter2\pecomp.asm)

   ;-----------------------; 弹出PE对比窗口回调函数;-----------------------
_resultProcMain    proc  uses ebx edi esihProcessModuleDlg:HWND,wMsg,wParam,lParam 5 mov eax,wMsg.if eax==WM_CLOSEinvoke EndDialog,hProcessModuleDlg,NULL.elseif eax==WM_INITDIALOGinvoke GetDlgItem,hProcessModuleDlg,IDC_MODULETABLEmov hProcessModuleTable,eaxinvoke GetDlgItem,hProcessModuleDlg,ID_TEXT1mov hText1,eaxinvoke GetDlgItem,hProcessModuleDlg,ID_TEXT2mov hText2,eax;定义表格外观invoke SendMessage,hProcessModuleTable,LVM_SETEXTENDEDLISTVIEWSTYLE,\0,LVS_EX_GRIDLINES or LVS_EX_FULLROWSELECTinvoke ShowWindow,hProcessModuleTable,SW_SHOW;清空表格内容invoke _clearResultView.elseif eax==WM_NOTIFYmov eax,lParammov ebx,lParam;更改各控件状态mov eax,[eax+NMHDR.hwndFrom].if eax==hProcessModuleTablemov ebx,lParam.if [ebx+NMHDR.code]==NM_CUSTOMDRAW   ;绘画时mov ebx,lParamassume ebx:ptr NMLVCUSTOMDRAW.if [ebx].nmcd.dwDrawStage==CDDS_PREPAINTinvoke SetWindowLong,hProcessModuleDlg,DWL_MSGRESULT,\CDRF_NOTIFYITEMDRAWmov eax,TRUE.elseif [ebx].nmcd.dwDrawStage==CDDS_ITEMPREPAINT;当每一单元格内容被重新绘制前,判断;两列的值是否一致invoke _GetListViewItem,hProcessModuleTable,\[ebx].nmcd.dwItemSpec,1,addr bufTemp1invoke _GetListViewItem,hProcessModuleTable,\[ebx].nmcd.dwItemSpec,2,addr bufTemp2invoke lstrlen,addr bufTemp1invoke _MemCmp,addr bufTemp1,addr bufTemp2,eax;如果一致,则将文本的背景色设置为浅红色,否则为黑色.if eax==1mov [ebx].clrTextBk,0a0a0ffh.elsemov [ebx].clrTextBk,0ffffffh.endifinvoke SetWindowLong,hProcessModuleDlg,DWL_MSGRESULT,\CDRF_DODEFAULTmov eax,TRUE.endif.elseif [ebx+NMHDR.code]==NM_CLICKassume ebx:ptr NMLISTVIEW.endif.endif.elseif eax==WM_COMMANDmov eax,wParam.if ax==IDC_OK   ;执行对比invoke _openFile.elseif ax==IDC_BROWSE1invoke _OpenFile1     ;用户选择第一个文件.elseif ax==IDC_BROWSE2invoke _OpenFile2     ;用户选择第二个文件.endif.elsemov eax,FALSEret.endifmov eax,TRUEret_resultProcMain     endp

PE文件比较器窗口回调函数中最主要的代码集中在第31~58行。由窗口回调函数注册的监听器一旦发现由表格控件引发了绘画消息,则判断该绘画是否为表格项重画(第38行)。如果是,则获取要重画的项目当前所在行的第1列和第2列的值。这两个值来自于两个不同PE文件的同一个字段,通过判断二者是否相等来决定重画时使用的背景色。如果不相等,则将重画时的背景色设置为0a0a0ffh(浅红色),否则设置为0ffffffh(黑色)。

如上所示,当用户选择了两个要参与对比的PE文件以后,点击执行对比按钮,系统会调用函数_openFile。

2. _openFile函数

_openFile函数的功能是把两个PE文件数据结构中的相关字段的值取出,分别放到表格的第1列和第2列,判断两个值是否相等的代码在回调函数_resultProcMain中已经给出。

与前面的思路一样,程序还是使用了内存映射函数来操作参与对比的两个PE文件,所不同的是这里需要定义两个指针。一个指针指向第一个文件的内存映射函数的起始位置,另一个指针指向第二个文件的内存映射函数的起始位置。假设该工作已经完成,接下来就是把两个PE文件按照第3章里描述的所有字段的值取出来显示到表格中,完成该功能的代码如代码清单2-5所示。

 ;到此为止,两个内存文件的指针已经获取到了;@lpMemory和@lpMemory1分别指向两个文件头;下面是从这个文件头开始,先找出各数据结构的字段值,然后进行比较;调整esi,edi指向DOS头mov esi,@lpMemoryassume esi:ptr IMAGE_DOS_HEADERmov edi,@lpMemory1assume edi:ptr IMAGE_DOS_HEADERinvoke _Header1;调整esi,dei指针指向PE文件头add esi,[esi].e_lfanewassume esi:ptr IMAGE_NT_HEADERSadd edi,[edi].e_lfanewassume edi:ptr IMAGE_NT_HEADERSinvoke _Header2movzx ecx,word ptr [esi+6]movzx eax,word ptr [edi+6].if eax>ecxmov ecx,eax.endif;调整esi,edi指针指向节表add esi,sizeof IMAGE_NT_HEADERSadd edi,sizeof IMAGE_NT_HEADERSmov eax,1.repeatinvoke _Header3dec ecxinc eax.break .if ecx==0add esi,sizeof IMAGE_SECTION_HEADERadd edi,sizeof IMAGE_SECTION_HEADER.until FALSE

代码清单2-5 _openFile函数实现的部分代码

由于编码比较长,这里只以结构IMAGE_DOS_HEADER中的字段e_lpanew为例介绍程序设计的流程:将esi和edi分别赋值到两个PE文件的IMAGE_DOS_HEADER后,调用函数_Header1,处理数据结构DOS头的相关字段(第5~10行)。

3._Header1函数

_Header1函数完成了DOS头部分的字段比较,此部分的详细代码如代码清单2-6所示。

代码清单2-6 DOS头部分的字段比较函数_Header1(chapter2\pecomp.asm)

;--------------------------------------------
; IMAGE_DOS_HEADER头信息
;-------------------------------------------
_Header1 procpushadinvoke _addLine,addr szRec1,esi,edi,2add esi,2add edi,2invoke _addLine,addr szRec2,esi,edi,2add esi,2add edi,2invoke _addLine,addr szRec3,esi,edi,2add esi,2add edi,2invoke _addLine,addr szRec4,esi,edi,2add esi,2add edi,2invoke _addLine,addr szRec5,esi,edi,2add esi,2add edi,2invoke _addLine,addr szRec6,esi,edi,2add esi,2add edi,2invoke _addLine,addr szRec7,esi,edi,2add esi,2add edi,2invoke _addLine,addr szRec8,esi,edi,2add esi,2add edi,2invoke _addLine,addr szRec9,esi,edi,2add esi,2add edi,2invoke _addLine,addr szRec10,esi,edi,2add esi,2add edi,2invoke _addLine,addr szRec11,esi,edi,2add esi,2add edi,2invoke _addLine,addr szRec12,esi,edi,2add esi,2add edi,2invoke _addLine,addr szRec13,esi,edi,2add esi,2add edi,2invoke _addLine,addr szRec14,esi,edi,2add esi,2add edi,2invoke _addLine,addr szRec15,esi,edi,8add esi,8add edi,8invoke _addLine,addr szRec16,esi,edi,2add esi,2add edi,2invoke _addLine,addr szRec17,esi,edi,2add esi,2add edi,2invoke _addLine,addr szRec18,esi,edi,20add esi,20add edi,20invoke _addLine,addr szRec19,esi,edi,4popadret
_Header1 endp

DOS头结构中字段e_lpanew的处理在第59~61行。首先,将esi和edi指向该字段所在内存位置;然后,调用_addLine函数将两个PE文件对应字段的值加入到表格中。

invoke _addLine,para1,para2,para3,para4

_addLine的参数描述如下:

para1:字段名称字符串所在地址。

para2:PE文件1该字段值所在内存地址。

para3:PE文件2该字段值所在内存地址。

para4:该字段的长度(即字节数)。

4. _addLine函数

该函数完成了在表格中增加一行的操作,具体定义如代码清单2-7所示。

代码清单2-7 在表格中增加一行的函数_addLine( chapter2\pecomp.asm)

;--------------------------------------------
; 在表格中增加一行
; _lpSZ为第一行要显示的字段名
; _lpSP1为第一个文件该字段的位置
; _lpSP2为第二个文件该字段的位置
; _Size为该字段的字节长度
;--------------------------------------------
_addLine proc _lpSZ,_lpSP1,_lpSP2,_Sizepushadinvoke _ListViewSetItem,hProcessModuleTable,dwCount,-1,\_lpSZ                ;在表格中新增加一行mov dwCount,eaxxor ebx,ebxinvoke _ListViewSetItem,hProcessModuleTable,dwCount,ebx,\_lpSZ                        ;显示字段名invoke RtlZeroMemory,addr szBuffer,50invoke MemCopy,_lpSP1,addr bufTemp2,_Sizeinvoke _Byte2Hex,_Size;将指定字段按照十六进制显示,格式:一个字节+一个空格invoke lstrcat,addr szBuffer,addr bufTemp1inc ebxinvoke _ListViewSetItem,hProcessModuleTable,dwCount,ebx,\addr szBuffer ;第一个文件中的值invoke RtlZeroMemory,addr szBuffer,50invoke MemCopy,_lpSP2,addr bufTemp2,_Sizeinvoke _Byte2Hex,_Sizeinvoke lstrcat,addr szBuffer,addr bufTemp1inc ebxinvoke _ListViewSetItem,hProcessModuleTable,dwCount,ebx,\addr szBuffer ;第二个文件中的值popadret
_addLine   endp

显示字段值的同时,会在消息处理函数中调用字节比对函数_MemCmp以确定值是否相同,如果不相同则将表格行的背景色设置为红色以示区别。其他字段的处理方式与字段IMAGE_DOS_HEADER. e_lpanew的处理方式类似,不再一一陈述。

2.3.4 运行PEComp

编译资源文件PEComp.rc,编译链接PEComp.asm生成最终的PEComp.exe程序;将随书文件中目录chapter2下的两个测试用文件peinfoNor.bin和peinfoVir.bin重命名,其扩展名都改为exe,然后运行PEComp.exe程序。

依次选择菜单“文件”→“打开”,弹出PE对比对话框窗口,在对话框中选择并打开刚才重命名的两个EXE文件,然后进行对比,运行效果如图2-5所示。

                                                                图2-5 PEComp运行效果

注意 请不要运行以上两个文件,因为peinfoVir.exe是个病毒文件。测试完以后请将扩展名改回原来的“bin”。

通过对比可以看出,在两个PE文件的文件头部结构中,字段不相同的部分来自最后一个节的描述。可以初步断定,该病毒程序是通过修改正常程序的最后一个节的相关字段的值来实现病毒代码携带的。


笔记:

peComp.rc文件:

#include <resource.h>#define ICO_MAIN  1000
#define DLG_MAIN  1000
#define IDC_INFO  1001
#define IDM_MAIN  2000
#define IDM_OPEN  2001
#define IDM_EXIT  2002#define IDM_1    4000
#define IDM_2    4001
#define IDM_3    4002
#define IDM_4    4003#define RESULT_MODULE 5000
#define ID_TEXT1  5001
#define ID_TEXT2  5002
#define IDC_MODULETABLE 5003
#define IDC_OK 5004
#define ID_STATIC 5005
#define ID_STATIC1 5006
#define IDC_BROWSE1 5007
#define IDC_BROWSE2 5008
#define IDC_THESAME 5009ICO_MAIN  ICON  "main.ico"DLG_MAIN DIALOG 50,50,544,399
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "PEComp by Scott"
MENU IDM_MAIN
FONT 9,"宋体"
BEGINCONTROL "",IDC_INFO,"RichEdit20A",196 | ES_WANTRETURN | WS_CHILD | ES_READONLY| WS_VISIBLE |WS_BORDER | WS_VSCROLL | WS_TABSTOP,0,0,540,396
ENDRESULT_MODULE DIALOG 76,10,630,480
STYLE DS_MODALFRAME | WS_POPUP |WS_VISIBLE | WS_CAPTION |WS_SYSMENU
CAPTION "PE文件对比结果"
FONT 9,"宋体"
BEGINLTEXT "您选定的第一个文件为:",ID_STATIC,10,13,200,15EDITTEXT ID_TEXT1,130,13,440,15PUSHBUTTON "浏览...",IDC_BROWSE1,570,13,50,14LTEXT "您选定的第二个文件为:",ID_STATIC1,10,35,200,15EDITTEXT ID_TEXT2,130,35,440,15PUSHBUTTON "浏览...",IDC_BROWSE2,570,35,50,14CONTROL "", IDC_MODULETABLE, "SysListView32",13 | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 10,60,610,390  AUTOCHECKBOX "只显示不同的值" IDC_THESAME,10,460,100,14PUSHBUTTON "执行...(&R)",IDC_OK,570,460,50,14
ENDIDM_MAIN menu discardable
BEGINPOPUP "文件(&F)"BEGINmenuitem "打开PE对比对话框",IDM_OPENmenuitem "---",IDM_1menuitem "---",IDM_2menuitem "---",IDM_3 CHECKEDmenuitem separatormenuitem "退出(&x)",IDM_EXITENDPOPUP "编辑(&E)"BEGINmenuitem separatorENDPOPUP "格式(&O)"BEGINmenuitem separatorENDPOPUP "查看(&V)"BEGINmenuitem "源文件",IDM_1menuitem "窗口透明度",IDM_2menuitem separatormenuitem "大小",IDM_3menuitem "宽度",IDM_4ENDPOPUP "帮助(&H)"BEGINmenuitem separatorENDEND

peComp.asm文件:

;peComp.asm   通用程序框架
;使用 nmake 或下列命令进行编译和链接:
;ml -c -coff peComp.asm
;rc -r peComp.rc
;link -subsystem:windows peComp.obj peComp.res
.386
.model flat, stdcall 
option casemap:none include		c:/masm32/include/windows.inc 
include 	c:/masm32/include/user32.inc 
include 	c:/masm32/include/kernel32.inc 
include 	c:/masm32/include/comdlg32.inc 
include 	c:/masm32/include/gdi32.inc 
include 	c:/masm32/include/comctl32.inc 
include 	c:/masm32/include/comdlg32.inc 
include 	c:/masm32/include/advapi32.inc 
include 	c:/masm32/include/shell32.inc 
include 	c:/masm32/include/masm32.inc 
include 	c:/masm32/include/netapi32.inc 
include 	c:/masm32/include/winmm.inc 
include 	c:/masm32/include/ws2_32.inc 
include 	c:/masm32/include/psapi.inc 
include 	c:/masm32/include/mpr.inc 			;WNetCancelConnection2
include 	c:/masm32/include/iphlpapi.inc 		;SendARPincludelib 	c:/masm32/lib/user32.lib 
includelib 	c:/masm32/lib/kernel32.lib 
includelib 	c:/masm32/lib/comdlg32.lib 
includelib 	c:/masm32/lib/comdlg32.lib 
includelib 	c:/masm32/lib/gdi32.lib 
includelib 	c:/masm32/lib/comctl32.lib 
includelib 	c:/masm32/lib/comdlg32.lib 
includelib 	c:/masm32/lib/advapi32.lib 
includelib 	c:/masm32/lib/shell32.lib 
includelib 	c:/masm32/lib/masm32.lib 
includelib 	c:/masm32/lib/netapi32.lib 
includelib 	c:/masm32/lib/winmm.lib 
includelib 	c:/masm32/lib/ws2_32.lib 
includelib 	c:/masm32/lib/psapi.lib 
includelib 	c:/masm32/lib/mpr.lib 			
includelib 	c:/masm32/lib/iphlpapi.libICO_MAIN	equ 1000 
DLG_MAIN 	equ 1000
IDC_INFO	equ 1001 
IDM_MAIN 	equ 2000
IDM_OPEN 	equ 2001 
IDM_EXIT 	equ 2002 
IDM_1		equ 4000
IDM_2 		equ 4001 
IDM_3 		equ 4002 
RESULT_MODULE   equ 5000
ID_TEXT1        equ 5001
ID_TEXT2        equ 5002
IDC_MODULETABLE equ 5003
IDC_OK          equ 5004
ID_STATIC       equ 5005
ID_STATIC1      equ 5006
IDC_BROWSE1     equ 5007
IDC_BROWSE2     equ 5008
IDC_THESAME     equ 5009.data 
hInstance 	dword ?
hRichEdit 	dword ?
hWinMain	dword ?
hWinEdit	dword ?
dwCount 	dword ?
dwColorRed 	dword ?
hText1 		dword ?
hText2 		dword ?
hFile 		dword ?hProcessModuleTable dword ?szFileName 			byte MAX_PATH dup(?)
szFileNameOpen1		byte MAX_PATH dup(0)
szFileNameOpen2 	byte MAX_PATH dup(0)szResultColName1	byte 'PE数据结构相关字段',0
szResultColName2 	byte '文件1的值(H)',0
szResultColName3 	byte '文件2的值(H)',0
szBuffer 			byte 256 dup(0), 0
bufTemp1 			byte 200 dup(0), 0
bufTemp2 			byte 200 dup(0), 0 
szFilter1 			byte 'Excutable Files',0,'*.exe;*.com',0byte 0.const 
szDllEdit 	byte 'RichEd20.dll', 0
szClassEdit byte 'RichEdit20A', 0
szFont 		byte '宋体', 0
szExtPe 	byte 'PE File',0,'*.exe;*.dll;*.scr;*.fon;*.drv',0byte 'All Files(*.*)',0,'*.*',0,0
szErr 		byte '文件格式错误!',0
szErrFormat byte '这个文件不是PE格式的文件!',0
szSuccess 	byte '恭喜你,程序执行到这里是成功的。',0
szNotFound 	byte '无法查找',0szRec1      byte 'IMAGE_DOS_HEADER.e_magic',0
szRec2      byte 'IMAGE_DOS_HEADER.e_cblp',0
szRec3      byte 'IMAGE_DOS_HEADER.e_cp',0
szRec4      byte 'IMAGE_DOS_HEADER.e_crlc',0
szRec5      byte 'IMAGE_DOS_HEADER.e_cparhdr',0
szRec6      byte 'IMAGE_DOS_HEADER.e_minalloc',0
szRec7      byte 'IMAGE_DOS_HEADER.e_maxalloc',0
szRec8      byte 'IMAGE_DOS_HEADER.e_ss',0
szRec9      byte 'IMAGE_DOS_HEADER.e_sp',0
szRec10     byte 'IMAGE_DOS_HEADER.e_csum',0
szRec11     byte 'IMAGE_DOS_HEADER.e_ip',0
szRec12     byte 'IMAGE_DOS_HEADER.e_cs',0
szRec13     byte 'IMAGE_DOS_HEADER.e_lfarlc',0
szRec14     byte 'IMAGE_DOS_HEADER.e_ovno',0
szRec15     byte 'IMAGE_DOS_HEADER.e_res',0
szRec16     byte 'IMAGE_DOS_HEADER.e_oemid',0
szRec17     byte 'IMAGE_DOS_HEADER.e_oeminfo',0
szRec18     byte 'IMAGE_DOS_HEADER.e_res2',0
szRec19     byte 'IMAGE_DOS_HEADER.e_lfanew',0
szRec20     byte 'IMAGE_NT_HEADERS.Signature',0
szRec21     byte 'IMAGE_FILE_HEADER.Machine',0
szRec22     byte 'IMAGE_FILE_HEADER.NumberOfSections',0
szRec23     byte 'IMAGE_FILE_HEADER.TimeDateStamp',0
szRec24     byte 'IMAGE_FILE_HEADER.PointerToSymbolTable',0
szRec25     byte 'IMAGE_FILE_HEADER.NumberOfSymbols',0
szRec26     byte 'IMAGE_FILE_HEADER.SizeOfOptionalHeader',0
szRec27     byte 'IMAGE_FILE_HEADER.Characteristics',0
szRec28     byte 'IMAGE_OPTIONAL_HEADER32.Magic',0
szRec29     byte 'IMAGE_OPTIONAL_HEADER32.MajorLinkerVersion',0
szRec30     byte 'IMAGE_OPTIONAL_HEADER32.MinorLinkerVersion',0
szRec31     byte 'IMAGE_OPTIONAL_HEADER32.SizeOfCode',0
szRec32     byte 'IMAGE_OPTIONAL_HEADER32.SizeOfInitializedData',0
szRec33     byte 'IMAGE_OPTIONAL_HEADER32.SizeOfUninitializedData',0
szRec34     byte 'IMAGE_OPTIONAL_HEADER32.AddressOfEntryPoint',0
szRec35     byte 'IMAGE_OPTIONAL_HEADER32.BaseOfCode',0
szRec36     byte 'IMAGE_OPTIONAL_HEADER32.BaseOfData',0
szRec37     byte 'IMAGE_OPTIONAL_HEADER32.ImageBase',0
szRec38     byte 'IMAGE_OPTIONAL_HEADER32.SectionAlignment',0
szRec39     byte 'IMAGE_OPTIONAL_HEADER32.FileAlignment',0
szRec40     byte 'IMAGE_OPTIONAL_HEADER32.MajorOperatingSystemVersion',0
szRec41     byte 'IMAGE_OPTIONAL_HEADER32.MinorOperatingSystemVersion',0
szRec42     byte 'IMAGE_OPTIONAL_HEADER32.MajorImageVersion',0
szRec43     byte 'IMAGE_OPTIONAL_HEADER32.MinorImageVersion',0
szRec44     byte 'IMAGE_OPTIONAL_HEADER32.MajorSubsystemVersion',0
szRec45     byte 'IMAGE_OPTIONAL_HEADER32.MinorSubsystemVersion',0
szRec46     byte 'IMAGE_OPTIONAL_HEADER32.Win32VersionValue',0
szRec47     byte 'IMAGE_OPTIONAL_HEADER32.SizeOfImage',0
szRec48     byte 'IMAGE_OPTIONAL_HEADER32.SizeOfHeaders',0
szRec49     byte 'IMAGE_OPTIONAL_HEADER32.CheckSum',0
szRec50     byte 'IMAGE_OPTIONAL_HEADER32.Subsystem',0
szRec51     byte 'IMAGE_OPTIONAL_HEADER32.DllCharacteristics',0
szRec52     byte 'IMAGE_OPTIONAL_HEADER32.SizeOfStackReserve',0
szRec53     byte 'IMAGE_OPTIONAL_HEADER32.SizeOfStackCommit',0
szRec54     byte 'IMAGE_OPTIONAL_HEADER32.SizeOfHeapReserve',0
szRec55     byte 'IMAGE_OPTIONAL_HEADER32.SizeOfHeapCommit',0
szRec56     byte 'IMAGE_OPTIONAL_HEADER32.LoaderFlags',0
szRec57     byte 'IMAGE_OPTIONAL_HEADER32.NumberOfRvaAndSizes',0szRec58     byte 'IMAGE_DATA_DIRECTORY.VirtualAddress(Export)',0
szRec59     byte 'IMAGE_DATA_DIRECTORY.isize(Export)',0
szRec60     byte 'IMAGE_DATA_DIRECTORY.VirtualAddress(Import)',0
szRec61     byte 'IMAGE_DATA_DIRECTORY.isize(Import)',0
szRec62     byte 'IMAGE_DATA_DIRECTORY.VirtualAddress(Resource)',0
szRec63     byte 'IMAGE_DATA_DIRECTORY.isize(Resource)',0
szRec64     byte 'IMAGE_DATA_DIRECTORY.VirtualAddress(Exception)',0
szRec65     byte 'IMAGE_DATA_DIRECTORY.isize(Exception)',0
szRec66     byte 'IMAGE_DATA_DIRECTORY.VirtualAddress(Security)',0
szRec67     byte 'IMAGE_DATA_DIRECTORY.isize(Security)',0
szRec68     byte 'IMAGE_DATA_DIRECTORY.VirtualAddress(BaseReloc)',0
szRec69     byte 'IMAGE_DATA_DIRECTORY.isize(BaseReloc)',0
szRec70     byte 'IMAGE_DATA_DIRECTORY.VirtualAddress(Debug)',0
szRec71     byte 'IMAGE_DATA_DIRECTORY.isize(Debug)',0
szRec72     byte 'IMAGE_DATA_DIRECTORY.VirtualAddress(Architecture)',0
szRec73     byte 'IMAGE_DATA_DIRECTORY.isize(Architecture)',0
szRec74     byte 'IMAGE_DATA_DIRECTORY.VirtualAddress(GlobalPTR)',0
szRec75     byte 'IMAGE_DATA_DIRECTORY.isize(GlobalPTR)',0
szRec76     byte 'IMAGE_DATA_DIRECTORY.VirtualAddress(TLS)',0
szRec77     byte 'IMAGE_DATA_DIRECTORY.isize(TLS)',0
szRec78     byte 'IMAGE_DATA_DIRECTORY.VirtualAddress(Load_Config)',0
szRec79     byte 'IMAGE_DATA_DIRECTORY.isize(Load_Config)',0
szRec80     byte 'IMAGE_DATA_DIRECTORY.VirtualAddress(Bound_Import)',0
szRec81     byte 'IMAGE_DATA_DIRECTORY.isize(Bound_Import)',0
szRec82     byte 'IMAGE_DATA_DIRECTORY.VirtualAddress(IAT)',0
szRec83     byte 'IMAGE_DATA_DIRECTORY.isize(IAT)',0
szRec84     byte 'IMAGE_DATA_DIRECTORY.VirtualAddress(Delay_Import)',0
szRec85     byte 'IMAGE_DATA_DIRECTORY.isize(Delay_Import)',0
szRec86     byte 'IMAGE_DATA_DIRECTORY.VirtualAddress(Com_Descriptor)',0
szRec87     byte 'IMAGE_DATA_DIRECTORY.isize(Com_Descriptor)',0
szRec88     byte 'IMAGE_DATA_DIRECTORY.VirtualAddress(Reserved)',0
szRec89     byte 'IMAGE_DATA_DIRECTORY.isize(Reserved)',0szRec90     byte 'IMAGE_SECTION_HEADER%d.Name1',0
szRec91     byte 'IMAGE_SECTION_HEADER%d.VirtualSize',0
szRec92     byte 'IMAGE_SECTION_HEADER%d.VirtualAddress',0
szRec93     byte 'IMAGE_SECTION_HEADER%d.SizeOfRawData',0
szRec94     byte 'IMAGE_SECTION_HEADER%d.PointerToRawData',0
szRec95     byte 'IMAGE_SECTION_HEADER%d.PointerToRelocations',0
szRec96     byte 'IMAGE_SECTION_HEADER%d.PointerToLinenumbers',0
szRec97     byte 'IMAGE_SECTION_HEADER%d.NumberOfRelocations',0
szRec98     byte 'IMAGE_SECTION_HEADER%d.NumberOfLinenumbers',0
szRec99     byte 'IMAGE_SECTION_HEADER%d.Characteristics',0szOut1      byte '%02x',0
szOut2      byte '%04x',0
lpszHexArr  byte '0123456789ABCDEF',0.data?
stLVC 	LV_COLUMN<?>
stLVI 	LV_ITEM<?>.code
;初始化窗口程序
_init proc local @stCf:CHARFORMAT invoke GetDlgItem, hWinMain, IDC_INFO mov hWinEdit, eax ;为窗口设置图标invoke LoadIcon, hInstance, ICO_MAIN invoke SendMessage, hWinMain, WM_SETICON, ICON_BIG, eax 	;设置编辑控件	invoke SendMessage, hWinEdit, EM_SETTEXTMODE, TM_PLAINTEXT, 0 		invoke RtlZeroMemory, addr @stCf, sizeof @stCf 					;初始化 mov @stCf.cbSize, sizeof @stCf mov @stCf.yHeight, 9*20mov @stCf.dwMask, CFM_FACE or CFM_SIZE or CFM_BOLD invoke lstrcpy, addr @stCf.szFaceName, addr szFont invoke SendMessage, hWinEdit, EM_SETCHARFORMAT, 0, addr @stCf invoke SendMessage, hWinEdit, EM_EXLIMITTEXT, 0, -1 ret 
_init endp ;-------------------------------
;错误Handler
;--------------------------------
_Handler proc _lpExceptionRecord, _lpSEH, \_lpContext, _lpDispathcerContext pushad mov esi, _lpExceptionRecord mov edi, _lpContext assume esi:ptr EXCEPTION_RECORD, edi:ptr CONTEXT mov eax, _lpSEH push [eax+0ch]pop [edi].regEbp push [eax+8]pop [edi].regEip push eax pop [edi].regEsp assume esi:nothing, edi:nothing popad mov eax, ExceptionContinueExecution ret 
_Handler endp ;-------------------------------
; 将内存偏移量RVA转换为文件偏移
;-------------------------------
_RVAToOffset proc _lpFileHead, _dwRVA local @dwReturn pushad mov esi, _lpFileHead assume esi:ptr IMAGE_DOS_HEADER add esi, [esi].e_lfanew assume esi:ptr IMAGE_NT_HEADERS mov edi, _dwRVA mov edx, esi add edx, sizeof IMAGE_NT_HEADERS assume edx:ptr IMAGE_SECTION_HEADERmovzx ecx, [esi].FileHeader.NumberOfSections ;遍历节表.repeat mov eax, [edx].VirtualAddress add eax, [edx].SizeOfRawData		;计算该节结束RVA    相对虚拟地址.if (edi >= [edx].VirtualAddress) && (edi < eax)mov eax, [edx].VirtualAddress sub edi, eax 					;计算RVA在节中的偏移mov eax, [edx].PointerToRawData add eax, edi 					;加上节在文件中的的起始位置jmp @F .endif add edx, sizeof IMAGE_SECTION_HEADER .untilcxz assume edx:nothing assume esi:nothing mov eax, -1 
@@:mov @dwReturn, eax popad mov eax, @dwReturn ret 
_RVAToOffset endp ;------------------------
; 获取RVA所在节的名称
;------------------------
_getRVASectionName proc _lpFileHead, _dwRVA local @dwReturn pushad mov esi, _lpFileHead assume esi:ptr IMAGE_DOS_HEADER add esi, [esi].e_lfanew assume esi:ptr IMAGE_NT_HEADERS mov edi, _dwRVA mov edx, esi add edx, sizeof IMAGE_NT_HEADERS assume edx:ptr IMAGE_SECTION_HEADER movzx ecx, [esi].FileHeader.NumberOfSections ;遍历节表.repeat mov eax, [edx].VirtualAddress add eax,[edx].SizeOfRawData  ;计算该节结束RVA.if (edi>=[edx].VirtualAddress) && (edi < eax)mov eax, edx jmp @F .endif add edx, sizeof IMAGE_SECTION_HEADER .untilcxz assume edx:nothing assume esi:nothing mov eax, offset szNotFound 
@@:mov @dwReturn, eax popad mov eax, @dwReturn ret 
_getRVASectionName endp ;---------------------------------
;在ListView中增加一个列
;输入:_dwColumn = 增加的列编号
;	  _dwWidth = 列的宽度
;	  _lpszHead = 列的标题字符串 
;---------------------------------
_ListViewAddColumn proc uses ebx ecx _hWinView, _dwColumn, _dwWidth, _lpszHead local @stLVC:LV_COLUMN invoke RtlZeroMemory, addr @stLVC, sizeof LV_COLUMN mov @stLVC.imask, LVCF_TEXT or LVCF_WIDTH or LVCF_FMT mov @stLVC.fmt, LVCFMT_LEFT push _lpszHead pop @stLVC.pszText push _dwWidth pop @stLVC.lx push _dwColumn pop @stLVC.iSubItem invoke SendMessage, _hWinView, LVM_INSERTCOLUMN, _dwColumn, addr @stLVC ret 
_ListViewAddColumn endp ;----------------------------------------------------------------------
; 在ListView中新增一行,或修改一行中某个字段的内容
; 输入:_dwItem = 要修改的行的编号
;	   _dwSubItem = 要修改的字段的编号,-1表示插入新的行,>=1表示字段的编号
;-----------------------------------------------------------------------
_ListViewSetItem proc uses ebx ecx _hWinView, _dwItem, _dwSubItem, _lpszText invoke RtlZeroMemory, addr stLVI, sizeof LV_ITEM invoke lstrlen, _lpszText mov stLVI.cchTextMax, eax mov stLVI.imask, LVIF_TEXT push _lpszText pop stLVI.pszText push _dwItem pop stLVI.iItem push _dwSubItem pop stLVI.iSubItem .if _dwSubItem == -1 mov stLVI.iSubItem, 0 invoke SendMessage, _hWinView, LVM_INSERTITEM, NULL, addr stLVI .else invoke SendMessage, _hWinView, LVM_SETITEM, NULL, addr stLVI .endif ret 
_ListViewSetItem endp ;----------------------
; 清除ListView中的内容
; 删除所有的行和所有的列
;----------------------
_ListViewClear proc uses ebx ecx _hWinView invoke SendMessage, _hWinView, LVM_DELETEALLITEMS, 0, 0.while TRUE invoke SendMessage, _hWinView, LVM_DELETECOLUMN, 0, 0.break .if !eax .endw ret 
_ListViewClear endp ;---------------------
; 返回指定行列的值
; 结果在szBuffer中
;---------------------
_GetListViewItem proc _hWinView:DWORD, _dwLine:DWORD, _dwCol:DWORD, _lpszText local @stLVI:LV_ITEM invoke RtlZeroMemory, addr @stLVI, sizeof LV_ITEM invoke RtlZeroMemory, _lpszText, 512 mov @stLVI.cchTextMax, 512mov @stLVI.imask, LVIF_TEXT push _lpszText pop @stLVI.pszText push _dwCol pop @stLVI.iSubItem invoke SendMessage, _hWinView, LVM_GETITEMTEXT, _dwLine, addr @stLVI ret 
_GetListViewItem endp ;---------------------
; 初始化结果表格
;---------------------
_clearResultView proc uses ebx ecx invoke _ListViewClear, hProcessModuleTable ;添加表头mov ebx, 1 mov eax, 200 lea ecx, szResultColName1 invoke _ListViewAddColumn, hProcessModuleTable, ebx, eax, ecx mov ebx, 2 mov eax, 400 lea ecx, szResultColName2 invoke _ListViewAddColumn, hProcessModuleTable, ebx, eax, ecx mov ebx, 3 mov eax, 400 lea ecx, szResultColName3 invoke _ListViewAddColumn, hProcessModuleTable, ebx, eax, ecx mov dwCount, 0 ret  
_clearResultView endp ;------------------------------------------
; 打开输入文件
;------------------------------------------
_OpenFile1 proc local @stOF:OPENFILENAME 				;openfilenamelocal @stES:EDITSTREAM 					;editstream;如果打开之前还有文件句柄存在,则先关闭再赋值 .if hFile invoke CloseHandle, hFile mov hFile, 0 .endif ;显示“打开文件”对话框invoke RtlZeroMemory, addr @stOF, sizeof @stOF mov @stOF.lStructSize, sizeof @stOF push hWinMainpop @stOF.hwndOwner push hInstance pop @stOF.hInstance mov @stOF.lpstrFilter, offset szFilter1 mov @stOF.lpstrFile, offset szFileNameOpen1 mov @stOF.nMaxFile, MAX_PATHmov @stOF.Flags, OFN_FILEMUSTEXIST or \OFN_HIDEREADONLY or OFN_PATHMUSTEXIST invoke GetOpenFileName, addr @stOF .if eax invoke SetWindowText, hText1, addr szFileNameOpen1 .endif ret 
_OpenFile1 endp ;------------------------------------------
; 打开输入文件
;------------------------------------------
_OpenFile2 proc local @stOF:OPENFILENAME local @stES:EDITSTREAM;如果打开之前还有文件句柄存在,则先关闭再赋值 .if hFile invoke CloseHandle, hFile mov hFile, 0 .endif ;显示“打开文件”对话框invoke RtlZeroMemory, addr @stOF, sizeof @stOF mov @stOF.lStructSize, sizeof @stOF push hWinMain pop @stOF.hwndOwner push hInstance pop @stOF.hInstance mov @stOF.lpstrFilter, offset szFilter1 mov @stOF.lpstrFile, offset szFileNameOpen2 mov @stOF.nMaxFile, MAX_PATH mov @stOF.Flags, OFN_FILEMUSTEXIST or \OFN_HIDEREADONLY or OFN_PATHMUSTEXISTinvoke GetOpenFileName, addr @stOF .if eax invoke SetWindowText, hText2, addr szFileNameOpen2 .endif ret 
_OpenFile2 endp ;-------------------------------------------------
; 将_lpPoint位置处_dwSize个字节转换为16进制的字符串
; bufTemp1处为转换后的字符串
;-------------------------------------------------
_Byte2Hex proc _dwSize local @dwSize:dword pushad mov esi, offset bufTemp2 mov edi, offset bufTemp1 mov @dwSize, 0.repeat mov al, byte ptr [esi] mov bl, al xor edx, edx xor eax, eax mov al, bl mov cx, 16 div cx 				;结果高位在al中,余数在dl中xor bx, bx mov bl, al movzx edi, bx mov bl, byte ptr lpszHexArr[edi]mov eax, @dwSize mov byte ptr bufTemp1[eax], bl inc @dwSize xor bx, bx mov bl, dl movzx edi, bx ;invoke wsprintf,addr szBuffer,addr szOut2,edx;invoke MessageBox,NULL,addr szBuffer,NULL,MB_OKmov bl, byte ptr lpszHexArr[edi]mov eax, @dwSize mov byte ptr bufTemp1[eax], blinc @dwSize mov bl, 20h mov eax, @dwSize mov byte ptr bufTemp1[eax], bl inc @dwSize inc esi dec _dwSize .break .if _dwSize == 0 .until FALSE mov bl, 0 mov eax, @dwSize mov byte ptr bufTemp1[eax],bl popad ret 
_Byte2Hex endp _MemCmp proc _lp1, _lp2, _size local @dwResult:dword pushad mov esi, _lp1 mov edi, _lp2 mov ecx, _size .repeat mov al, byte ptr [esi]mov bl, byte ptr [edi].break .if al != bl inc esi inc edi dec ecx .break .if ecx == 0 .until FALSE .if ecx != 0 mov @dwResult, 1 .else mov @dwResult, 0 .endif popad mov eax, @dwResult ret 
_MemCmp endp ;--------------------------------------------
; 在表格中增加一行
; _lpSZ为第一行要显示的字段名
; _lpSP1为第一个文件该字段的位置
; _lpSP2为第二个文件该字段的位置
; _Size为该字段的字节长度
;--------------------------------------------	
_addLine proc _lpSZ, _lpSP1, _lpSP2, _Size pushad invoke _ListViewSetItem, hProcessModuleTable, dwCount, -1, \_lpSZ 				;在表格中新增加一行mov dwCount, eax xor ebx, ebx invoke _ListViewSetItem, hProcessModuleTable, dwCount, ebx, \_lpSZ 				;显示字段名invoke RtlZeroMemory, addr szBuffer, 50 invoke MemCopy, _lpSP1, addr bufTemp2, _Size invoke _Byte2Hex, _Size ;将指定字段按照十六进制显示,格式:一个字节+一个空格invoke lstrcat, addr szBuffer, addr bufTemp1 inc ebx invoke _ListViewSetItem, hProcessModuleTable, dwCount, ebx, \addr szBuffer 			;第一个文件中的值invoke RtlZeroMemory, addr szBuffer, 50 invoke MemCopy, _lpSP2, addr bufTemp2, _Size invoke _Byte2Hex, _Size invoke lstrcat, addr szBuffer, addr bufTemp1 inc ebx invoke _ListViewSetItem, hProcessModuleTable, dwCount, ebx, \addr szBuffer			;第二个文件中的值popad ret 
_addLine endp ;-----------------------
; IMAGE_DOS_HEADER头信息
;-----------------------
_Header1 proc pushad invoke _addLine, addr szRec1, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec2, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec3, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec4, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec5, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec6, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec7, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec8, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec9, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec10, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec11, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec12, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec13, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec14, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec15, esi, edi, 8add esi, 8 add edi, 8 invoke _addLine, addr szRec16, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec17, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec18, esi, edi, 20 add esi,20add edi,20invoke _addLine,addr szRec19,esi,edi,4popad ret 
_Header1 endp ;-----------------------
; IMAGE_DOS_HEADER头信息
;-----------------------
_Header2 proc pushad invoke _addLine, addr szRec20, esi, edi, 4 add esi, 4 add edi, 4 invoke _addLine, addr szRec21, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec22, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec23, esi, edi, 4 add esi, 4 add edi, 4 invoke _addLine, addr szRec24, esi, edi, 4 add esi, 4 add edi, 4 invoke _addLine, addr szRec25, esi, edi, 4 add esi, 4 add edi, 4 invoke _addLine, addr szRec26, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec27, esi, edi, 2 add esi, 2 add edi, 2invoke _addLine, addr szRec28, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec29, esi, edi, 1 add esi, 1 add edi, 1 invoke _addLine, addr szRec30, esi, edi, 1 add esi, 1 add edi, 1invoke _addLine, addr szRec31, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec32, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec33, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec34, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec35, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec36, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec37, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec38, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec39, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec40, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec41, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec42, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec43, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec44, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec45, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec46, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec47, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec48, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec49, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec50, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec51, esi, edi, 2 add esi, 2 add edi, 2 invoke _addLine, addr szRec52, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec53, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec54, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec55, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec56, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec57, esi, edi, 4 ;IMAGE_DATA_DIRECTORYadd esi, 4 add edi, 4invoke _addLine, addr szRec58, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec59, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec60, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec61, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec62, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec63, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec64, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec65, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec66, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec67, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec68, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec69, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec70, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec71, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec72, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec73, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec74, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec75, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec76, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec77, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec78, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec79, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec80, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec81, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec82, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec83, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec84, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec85, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec86, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec87, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec88, esi, edi, 4 add esi, 4 add edi, 4invoke _addLine, addr szRec89, esi, edi, 4 popad ret 
_Header2 endp ;---------------------------------------
; 节表
; eax=节序号
;---------------------------------------	
_Header3 proc local _dwValue:dword pushad mov _dwValue, eax invoke wsprintf, addr szBuffer, addr szRec90, _dwValue invoke _addLine, addr szBuffer, esi, edi, 8 add esi, 8 add edi, 8invoke wsprintf, addr szBuffer, addr szRec91, _dwValue invoke _addLine, addr szBuffer, esi, edi, 4 add esi, 4 add edi, 4invoke wsprintf, addr szBuffer, addr szRec92, _dwValue invoke _addLine, addr szBuffer, esi, edi, 4 add esi, 4 add edi, 4invoke wsprintf, addr szBuffer, addr szRec93, _dwValue invoke _addLine, addr szBuffer, esi, edi, 4 add esi, 4 add edi, 4invoke wsprintf, addr szBuffer, addr szRec94, _dwValue invoke _addLine, addr szBuffer, esi, edi, 4 add esi, 4 add edi, 4invoke wsprintf, addr szBuffer, addr szRec95, _dwValue invoke _addLine, addr szBuffer, esi, edi, 4 add esi, 4 add edi, 4invoke wsprintf, addr szBuffer, addr szRec96, _dwValue invoke _addLine, addr szBuffer, esi, edi, 4 add esi, 4 add edi, 4invoke wsprintf, addr szBuffer, addr szRec97, _dwValue invoke _addLine, addr szBuffer, esi, edi, 2 add esi, 2 add edi, 2invoke wsprintf, addr szBuffer, addr szRec98, _dwValue invoke _addLine, addr szBuffer, esi, edi, 2 add esi, 2 add edi, 2invoke wsprintf, addr szBuffer, addr szRec99, _dwValue invoke _addLine, addr szBuffer, esi, edi, 4 popad ret 
_Header3 endp ;_goHere;--------------------
; 打开PE文件并处理
;--------------------
_openFile proc local @stOF:OPENFILENAME local @hFile, @dwFileSize, @hMapFile, @lpMemory local @hFile1, @dwFileSize1, @hMapFile1, @lpMemory1 local @bufTemp1[10]:byte local @dwTemp:dword invoke CreateFile, addr szFileNameOpen1, GENERIC_READ, \FILE_SHARE_READ or FILE_SHARE_WRITE, NULL, \OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL .if eax != INVALID_HANDLE_VALUE mov @hFile, eax invoke GetFileSize, eax, NULL mov @dwFileSize, eax .if eax invoke CreateFileMapping, @hFile, \			;内存映射文件NULL, PAGE_READONLY, 0, 0, NULL .if eax mov @hMapFile, eax invoke MapViewOfFile, eax, \FILE_MAP_READ, 0, 0, 0.if eax mov @lpMemory, eax 				;获得文件在内存的映象起始位置assume fs:nothing push ebp push offset _ErrFormat push offset _Handler push fs:[0]mov fs:[0], esp ;检测PE文件是否有效mov esi, @lpMemory assume esi:ptr IMAGE_DOS_HEADER .if [esi].e_magic != IMAGE_DOS_SIGNATURE 	;判断是否有MZ字样jmp _ErrFormat .endif add esi, [esi].e_lfanew 					;调整ESI指针指向PE文件头assume esi:ptr IMAGE_NT_HEADERS .if [esi].Signature != IMAGE_NT_SIGNATURE	;判断是否有PE字样jmp _ErrFormat .endif .endif .endif .endif .endif invoke CreateFile, addr szFileNameOpen2, GENERIC_READ, \FILE_SHARE_READ or FILE_SHARE_WRITE, NULL, \OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL .if eax != INVALID_HANDLE_VALUE mov @hFile1, eax invoke GetFileSize, eax, NULL mov @dwFileSize1, eax .if eax invoke CreateFileMapping, @hFile1, \				;内存映射文件NULL, PAGE_READONLY, 0, 0, NULL .if eax mov @hMapFile1, eax invoke MapViewOfFile, eax, \FILE_MAP_READ, 0, 0, 0.if eax mov @lpMemory1, eax 						;获得文件在内存的映象起始位置assume fs:nothing push ebp push offset _ErrFormat1 push offset _Handler push fs:[0]mov fs:[0], esp ;检测PE文件是否有效mov esi, @lpMemory1 assume esi:ptr IMAGE_DOS_HEADER .if [esi].e_magic != IMAGE_DOS_SIGNATURE 	;判断是否有MZ字样jmp _ErrFormat1 .endif add esi, [esi].e_lfanew 					;调整ESI指针指向PE文件头assume esi:ptr IMAGE_NT_HEADERS.if [esi].Signature != IMAGE_NT_SIGNATURE 	;判断是否有PE字样jmp _ErrFormat1 .endif .endif .endif .endif .endif ;到此为止,两个内存文件的指针已经获取到了。;@lpMemory和@lpMemory1分别指向两个文件头;下面是从这个文件头开始,找出各数据结构的字段值,进行比较。;调整ESI,EDI指向DOS头			mov esi, @lpMemory assume esi:ptr IMAGE_DOS_HEADER mov edi, @lpMemory1 assume edi:ptr IMAGE_DOS_HEADER invoke _Header1 ;调整ESI,EDI指针指向PE文件头add esi, [esi].e_lfanew assume esi:ptr IMAGE_NT_HEADERS add edi, [edi].e_lfanew assume edi:ptr IMAGE_NT_HEADERS invoke _Header2 movzx ecx, word ptr [esi+6]movzx eax, word ptr [edi+6].if eax > ecx mov ecx, eax .endif ;调整ESI,EDI指针指向节表add esi, sizeof IMAGE_NT_HEADERS add edi, sizeof IMAGE_NT_HEADERS mov eax, 1 .repeat invoke _Header3 dec ecx inc eax .break .if ecx == 0 add esi, sizeof IMAGE_SECTION_HEADER add edi, sizeof IMAGE_SECTION_HEADER .until FALSE jmp _ErrorExit 			;正常退出_ErrFormat:invoke MessageBox, hWinMain, offset szErrFormat, NULL, MB_OK _ErrorExit:pop fs:[0]add esp, 0ch invoke UnmapViewOfFile, @lpMemory invoke CloseHandle, @hMapFile invoke CloseHandle, @hFile jmp @F 
_ErrFormat1:invoke MessageBox, hWinMain, offset szErrFormat, NULL, MB_OK 
_ErrorExit1:pop fs:[0]add esp, 0ch invoke UnmapViewOfFile, @lpMemory1 invoke CloseHandle, @hMapFile1 invoke CloseHandle, @hFile1 
@@:ret 
_openFile endp ;-----------------------
; 弹出PE对比窗口回调函数
;----------------------
_resultProcMain proc uses ebx edi esi hProcessModuleDlg:HWND, wMsg, wParam, lParam mov eax, wMsg .if eax == WM_CLOSE invoke EndDialog, hProcessModuleDlg, NULL .elseif eax == WM_INITDIALOG invoke GetDlgItem, hProcessModuleDlg, IDC_MODULETABLE mov hProcessModuleTable, eax invoke GetDlgItem, hProcessModuleDlg, ID_TEXT1 mov hText1, eax invoke GetDlgItem, hProcessModuleDlg, ID_TEXT2 mov hText2, eax ;定义表格外观invoke SendMessage, hProcessModuleTable, LVM_SETEXTENDEDLISTVIEWSTYLE, \0, LVS_EX_GRIDLINES or LVS_EX_FULLROWSELECT invoke ShowWindow, hProcessModuleTable, SW_SHOW ;清空表格内容invoke _clearResultView .elseif eax == WM_NOTIFYmov eax, lParam mov ebx, lParam ;更改各控件状态mov eax, [eax+NMHDR.hwndFrom].if eax == hProcessModuleTable mov ebx, lParam .if [ebx+NMHDR.code] == NM_CUSTOMDRAW 		;绘画时mov ebx, lParam assume ebx:ptr NMLVCUSTOMDRAW .if [ebx].nmcd.dwDrawStage == CDDS_PREPAINT invoke SetWindowLong, hProcessModuleDlg, DWL_MSGRESULT, \CDRF_NOTIFYITEMDRAW mov eax, TRUE .elseif [ebx].nmcd.dwDrawStage == CDDS_ITEMPREPAINT ;当每一单元格内容预画时,判断;两列的值是否一致invoke _GetListViewItem, hProcessModuleTable, \[ebx].nmcd.dwItemSpec, 1, addr bufTemp1 invoke _GetListViewItem, hProcessModuleTable, \[ebx].nmcd.dwItemSpec, 2, addr bufTemp2 invoke lstrlen, addr bufTemp1 invoke _MemCmp, addr bufTemp1, addr bufTemp2, eax ;如果一致,则将文本的背景色设置为浅红色,否则黑色.if eax == 1mov [ebx].clrTextBk, 0a0a0ffh .else mov [ebx].clrTextBk, 0ffffffh.endif invoke SetWindowLong, hProcessModuleDlg, DWL_MSGRESULT, \CDRF_DODEFAULTmov eax, TRUE .endif .elseif [ebx+NMHDR.code] == NM_CLICK assume ebx:ptr NMLISTVIEW.endif .endif .elseif eax == WM_COMMAND mov eax, wParam .if ax == IDC_OK 				;刷新invoke _openFile .elseif ax == IDC_BROWSE1 invoke _OpenFile1 			;用户选择第一个文件.elseif ax == IDC_BROWSE2 invoke _OpenFile2			;用户选择第二个文件.endif .else mov eax, FALSE ret .endif mov eax, TRUE ret 
_resultProcMain endp ;-------------------------------
;窗口程序
;--------------------------------
_ProcDlgMain proc uses ebx edi esi hWnd, wMsg, wParam, lParam mov eax, wMsg .if eax == WM_CLOSE invoke EndDialog, hWnd, NULL .elseif eax == WM_INITDIALOG				;初始化 	push hWnd pop hWinMain call _init .elseif eax == WM_COMMAND 					;菜单mov eax, wParam .if eax == IDM_EXIT						;退出invoke EndDialog, hWnd, NULL .elseif eax == IDM_OPEN 				;打开PE对比对话框 invoke DialogBoxParam, hInstance, RESULT_MODULE, hWnd, \offset _resultProcMain, 0 invoke InvalidateRect, hWnd, NULL, TRUE invoke UpdateWindow, hWnd .elseif eax == IDM_1 .elseif eax == IDM_2 .elseif eax == IDM_3 .endif .elsemov eax, FALSE ret .endif mov eax, TRUE ret 
_ProcDlgMain endp start:invoke InitCommonControls invoke LoadLibrary, offset szDllEdit mov hRichEdit, eax invoke GetModuleHandle, NULL mov hInstance, eax invoke DialogBoxParam, hInstance, \DLG_MAIN, NULL, offset _ProcDlgMain, NULL invoke FreeLibrary, hRichEdit invoke ExitProcess, NULL 
end start 

Makefile文件:

NAME = pecomp
OBJS = $(NAME).obj
RES  = $(NAME).resLINK_FLAG = /subsystem:windows
ML_FLAG = /c /coff$(NAME).exe: $(OBJS) $(RES)Link $(LINK_FLAG) $(OBJS) $(RES).asm.obj:ml $(ML_FLAG) $<
.rc.res:rc $<clean:del *.objdel *.res

编译:

运行:

打开文件:


2.4 PEInfo的实现

PEInfo是PE文件结构查看器,它将PE中的字节码以形象的描述语言显示出来,塑造一个整体的PE形象。通过编写PEInfo,可以锻炼我们使用数据结构定位特定PE信息的能力。

2.4.1 编程思路

这个小工具开发起来也不难,只是过程复杂了一些而已,其编程思路如下:

步骤1 打开文件,判断是否为PE文件。

判断方法非常简单,首先查看IMAGE_DOS_HEADER. e_magic字段,然后查看IMAGE_NT_HEADER.Signature字段;如果符合PE文件定义,则视为合法PE文件。事实上,操作系统在装载PE文件时,对PE文件的检测远比此方法复杂得多。

步骤2 将指针定位到相关数据结构,获取字段内容并以更人性化的方式显示相关内容。

提示 由于我们还没有正式开始学习PE文件格式,而PEInfo编程中涉及PE头部的大量数据结构,所以该部分代码的阅读最好等学习完第3章以后再进行。

2.4.2 PEInfo编码

编写PEInfo不需要额外的资源文件,复制一份pe.rc到PEInfo.rc即可,源代码依然来自pe.asm。与pe.asm不同的是,我们需要在PEInfo.asm的窗口回调函数中,为菜单项“文件”|“打开”的消息响应代码加入调用_openFile函数的代码。如下所示:

.elseif eax==IDM_OPEN    ;打开文件call _openFile

下面来看_openFile函数和_getMainInfo函数。

1. _openFile函数

_openFile函数完成了显示PE结构的所有功能,该部分代码如代码清单2-8所示。

代码清单2-8 _openFile函数实现(chapter2\peinfo.asm)

   ;------------------------------; 打开PE文件并处理;------------------------------_openFile proclocal @stOF:OPENFILENAMElocal @hFile,@dwFileSize,@hMapFile,@lpMemoryinvoke RtlZeroMemory,addr @stOF,sizeof @stOFmov @stOF.lStructSize,sizeof @stOFpush hWinMainpop @stOF.hwndOwnermov @stOF.lpstrFilter,offset szExtPemov @stOF.lpstrFile,offset szFileNamemov @stOF.nMaxFile,MAX_PATHmov @stOF.Flags,OFN_PATHMUSTEXIST or OFN_FILEMUSTEXISTinvoke GetOpenFileName,addr @stOF   ;让用户选择打开的文件.if !eaxjmp @F.endifinvoke CreateFile,addr szFileName,GENERIC_READ,\FILE_SHARE_READ or FILE_SHARE_WRITE,NULL,\OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL.if eax!=INVALID_HANDLE_VALUEmov @hFile,eaxinvoke GetFileSize,eax,NULLmov @dwFileSize,eax.if eaxinvoke CreateFileMapping,@hFile,\   ;内存映射文件NULL,PAGE_READONLY,0,0,NULL.if eaxmov @hMapFile,eaxinvoke MapViewOfFile,eax,\FILE_MAP_READ,0,0,0.if eax;获得文件在内存中的映像起始位置mov @lpMemory,eaxassume fs:nothingpush ebppush offset _ErrFormatpush offset _Handlerpush fs:[0]mov fs:[0],esp;检测PE文件是否有效mov esi,@lpMemoryassume esi:ptr IMAGE_DOS_HEADER;判断是否有MZ字样.if [esi].e_magic!=IMAGE_DOS_SIGNATUREjmp _ErrFormat.endif;调整esi指针指向PE文件头add esi,[esi].e_lfanewassume esi:ptr IMAGE_NT_HEADERS;判断是否有PE字样.if [esi].Signature!=IMAGE_NT_SIGNATUREjmp _ErrFormat.endif;到此为止,该文件的验证已经完成。是PE结构文件;接下来分析文件映射到内存中的数据,并显示相关信息invoke _getMainInfo,@lpMemory,esi,@dwFileSize;显示导入表invoke _getImportInfo,@lpMemory,esi,@dwFileSize;显示导出表invoke _getExportInfo,@lpMemory,esi,@dwFileSize;显示重定位信息invoke _getRelocInfo,@lpMemory,esi,@dwFileSize;显示其他信息jmp _ErrorExit_ErrFormat:invoke MessageBox,hWinMain,offset szErrFormat,\NULL,MB_OK_ErrorExit:pop fs:[0]add esp,0chinvoke UnmapViewOfFile,@lpMemory.endifinvoke CloseHandle,@hMapFile.endifinvoke CloseHandle,@hFile.endif.endif@@:ret_openFile endp

第44~59行代码的功能是检测打开的文件是否符合PE标准。第61~69行的代码的功能是调用不同的函数显示PE的相关信息。例如,PE的主要信息的显示调用了函数_getMainInfo:

invoke _getMainInfo,@lpMemory,esi,@dwFileSize

2._getMainInfo函数

该函数接收三个参数:

        ❑ _lpFile (内存映射文件的起始地址)

        ❑ _lpPeHead (数据结构IMAGE_NT_HEADERS在内存中的起始位置)

        ❑ _dwSize (PE文件大小)

该函数获取PE文件的头部信息并显示, 由于实现很简单,就不再详细分析了,如代码清单2-9所示。

代码清单2-9 获取PE文件主要信息的函数_getMainInfo(chapter2\peinfo.asm)

;----------------------------------------------
; 从内存中获取PE文件的主要信息
;----------------------------------------------
_getMainInfo   proc _lpFile,_lpPeHead,_dwSizelocal @szBuffer[1024]:bytelocal @szSecName[16]:bytepushadmov edi,_lpPeHeadassume edi:ptr IMAGE_NT_HEADERSmovzx ecx,[edi].FileHeader.Machine             ;运行平台movzx edx,[edi].FileHeader.NumberOfSections ;节的数量movzx ebx,[edi].FileHeader.Characteristics   ;节的属性invoke wsprintf,addr @szBuffer,addr szMsg,\addr szFileName,ecx,edx,ebx,\[edi].OptionalHeader.ImageBase,\      ;包含建议装入的地址[edi].OptionalHeader.AddressOfEntryPointinvoke SetWindowText,hWinEdit,addr @szBuffer;添加到编辑框中;显示每个节的主要信息invoke _appendInfo,addr szMsgSecmovzx ecx,[edi].FileHeader.NumberOfSectionsadd edi,sizeof IMAGE_NT_HEADERSassume edi:ptr IMAGE_SECTION_HEADER.repeatpush ecx;获取节的名称,注意:长度为8的名称,并且不以0结尾invoke RtlZeroMemory,addr @szSecName,sizeof @szSecNamepush esipush edimov ecx,8mov esi,edilea edi,@szSecNamecld@@:lodsb.if !al  ;如果名称为0,则显示为空格mov al,' '.endifstosbloop @Bpop edipop esi;获取节的主要信息invoke wsprintf,addr @szBuffer,addr szFmtSec,\addr @szSecName,[edi].Misc.VirtualSize,\[edi].VirtualAddress,[edi].SizeOfRawData,\[edi].PointerToRawData,[edi].Characteristicsinvoke _appendInfo,addr @szBufferadd edi,sizeof IMAGE_SECTION_HEADERpop ecx.untilcxzassume edi:nothingpopadret
_getMainInfo endp

其他信息(如导入表、导出表、资源表等)的显示代码将在后续的章节中详细介绍。

2.4.3 运行PEInfo

编译链接生成PEInfo.exe,然后运行。用该程序打开第1章生成的HelloWorld.exe程序,运行效果见图2-6。

                                                                      图2-6 PEInfo运行效果

至此,三个小工具的开发工作就完成了,在后续的章节中,会陆续使用这些小工具完成对PE格式的分析和学习。


笔记:

peinfo.rc文件

#include <resource.h>#define ICO_MAIN  1000
#define DLG_MAIN  1000
#define IDC_INFO  1001
#define IDM_MAIN  2000
#define IDM_OPEN  2001
#define IDM_EXIT  2002#define IDM_1    4000
#define IDM_2    4001
#define IDM_3    4002
#define IDM_4    4003ICO_MAIN  ICON  "main.ico"DLG_MAIN DIALOG 50,50,544,399
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "PEInfo by Scott"
MENU IDM_MAIN
FONT 9,"宋体"
BEGINCONTROL "",IDC_INFO,"RichEdit20A",196 | ES_WANTRETURN | WS_CHILD | ES_READONLY| WS_VISIBLE |WS_BORDER | WS_VSCROLL | WS_TABSTOP,0,0,540,396
ENDIDM_MAIN menu discardable
BEGINPOPUP "文件(&F)"BEGINmenuitem "打开文件(&O)...",IDM_OPENmenuitem separatormenuitem "退出(&x)",IDM_EXITENDPOPUP "编辑(&E)"BEGINmenuitem separatorENDPOPUP "格式(&O)"BEGINmenuitem separatorENDPOPUP "查看(&V)"BEGINmenuitem "源文件",IDM_1menuitem "窗口透明度",IDM_2menuitem separatormenuitem "大小",IDM_3menuitem "宽度",IDM_4ENDPOPUP "帮助(&H)"BEGINmenuitem separatorENDEND

peinfo.asm文件

;peinfo.asm   通用程序框架
;使用 nmake 或下列命令进行编译和链接:
;ml -c -coff peinfo.asm
;rc -r peinfo.rc
;link -subsystem:windows peinfo.obj peinfo.res
.386
.model flat, stdcall 
option casemap:none include		c:/masm32/include/windows.inc 
include 	c:/masm32/include/user32.inc 
includelib 	c:/masm32/lib/user32.lib 
include 	c:/masm32/include/kernel32.inc 
includelib 	c:/masm32/lib/kernel32.lib 
include 	c:/masm32/include/comdlg32.inc 
includelib 	c:/masm32/lib/comdlg32.lib ICO_MAIN	equ 1000 
DLG_MAIN 	equ 1000
IDC_INFO	equ 1001 
IDM_MAIN 	equ 2000
IDM_OPEN 	equ 2001 
IDM_EXIT 	equ 2002 
IDM_1		equ 4000
IDM_2 		equ 4001 
IDM_3 		equ 4002 .data 
hInstance 	dword ?
hRichEdit 	dword ?
hWinMain	dword ?
hWinEdit	dword ?
szFileName 	byte MAX_PATH dup(?).const 
szDllEdit 	byte 'RichEd20.dll', 0
szClassEdit byte 'RichEdit20A', 0
szFont 		byte '宋体', 0
szExtPe 	byte 'PE File',0,'*.exe;*.dll;*.scr;*.fon;*.drv',0byte 'All Files(*.*)',0,'*.*',0,0
szErr 		byte '文件格式错误!',0
szErrFormat byte '这个文件不是PE格式的文件!',0
szSuccess	byte '恭喜你,程序执行到这里是成功的。',0
szNotFound	byte '无法查找',0
szMsg 		byte '文件名:%s',0dh,0ahbyte '-----------------------------------------',0dh,0ah,0dh,0ah,0dh,0ahbyte '运行平台:      0x%04x  (014c:Intel 386   014dh:Intel 486  014eh:Intel 586)',0dh,0ahbyte '节的数量:      %d',0dh,0ahbyte '文件属性:      0x%04x  (大尾-禁止多处理器-DLL-系统文件-禁止网络运行-禁止优盘运行-无调试-32位-小尾-X-X-X-无符号-无行-可执行-无重定位)',0dh,0ahbyte '建议装入基地址:  0x%08x',0dh,0ahbyte '文件执行入口(RVA地址):  0x%04x',0dh,0ah,0dh,0ah,0
szMsgSec 	byte '---------------------------------------------------------------------------------',0dh,0ahbyte '节的属性参考:',0dh,0ahbyte '  00000020h  包含代码',0dh,0ahbyte '  00000040h  包含已经初始化的数据,如.const',0dh,0ahbyte '  00000080h  包含未初始化数据,如 .data?',0dh,0ahbyte '  02000000h  数据在进程开始以后被丢弃,如.reloc',0dh,0ahbyte '  04000000h  节中数据不经过缓存',0dh,0ahbyte '  08000000h  节中数据不会被交换到磁盘',0dh,0ahbyte '  10000000h  数据将被不同进程共享',0dh,0ahbyte '  20000000h  可执行',0dh,0ahbyte '  40000000h  可读',0dh,0ahbyte '  80000000h  可写',0dh,0ahbyte '常见的代码节一般为:60000020h,数据节一般为:c0000040h,常量节一般为:40000040h',0dh,0ahbyte '---------------------------------------------------------------------------------',0dh,0ah,0dh,0ah,0dh,0ahbyte '节的名称  未对齐前真实长度  内存中的偏移(对齐后的) 文件中对齐后的长度 文件中的偏移  节的属性',0dh,0ahbyte '---------------------------------------------------------------------------------------------',0dh,0ah,0
szFmtSec	byte '%s     %08x         %08x              %08x           %08x     %08x',0dh,0ah,0dh,0ah,0dh,0ah,0
szMsg1 		byte 0dh,0ah,0dh,0ah,0dh,0ahbyte '---------------------------------------------------------------------------------------------',0dh,0ahbyte '导入表所处的节:%s',0dh,0ahbyte '---------------------------------------------------------------------------------------------',0dh,0ah,0
szMsgImport byte 0dh,0ah,0dh,0ahbyte '导入库:%s',0dh,0ahbyte '-----------------------------',0dh,0ah,0dh,0ahbyte 'OriginalFirstThunk  %08x',0dh,0ahbyte 'TimeDateStamp       %08x',0dh,0ahbyte 'ForwarderChain      %08x',0dh,0ahbyte 'FirstThunk          %08x',0dh,0ahbyte '-----------------------------',0dh,0ah,0dh,0ah,0
szMsg2 		byte '%08u         %s',0dh,0ah,0
szMsg3		byte '%08u(无函数名,按序号导入)',0dh,0ah,0
szErrNoImport	byte  0dh,0ah,0dh,0ahbyte  '未发现该文件有导入函数',0dh,0ah,0dh,0ah,0szMsgExport byte 0dh,0ah,0dh,0ah,0dh,0ahbyte '---------------------------------------------------------------------------------------------',0dh,0ahbyte '导出表所处的节:%s',0dh,0ahbyte '---------------------------------------------------------------------------------------------',0dh,0ahbyte '原始文件名:%s',0dh,0ahbyte 'nBase               %08x',0dh,0ahbyte 'NumberOfFunctions   %08x',0dh,0ahbyte 'NuberOfNames        %08x',0dh,0ahbyte 'AddressOfFunctions  %08x',0dh,0ahbyte 'AddressOfNames      %08x',0dh,0ahbyte 'AddressOfNameOrd    %08x',0dh,0ahbyte '-------------------------------------',0dh,0ah,0dh,0ahbyte '导出序号    虚拟地址    导出函数名称',0dh,0ahbyte '-------------------------------------',0dh,0ah,0
szMsg4      byte '%08x      %08x      %s',0dh,0ah,0
szExportByOrd 	byte  '(按照序号导出)',0
szErrNoExport 	byte 0dh,0ah,0dh,0ahbyte  '未发现该文件有导出函数',0dh,0ah,0dh,0ah,0
szMsgReloc1 byte 0dh,0ah,'重定位表所处的节:%s',0dh,0ah,0
szMsgReloc2 byte 0dh,0ahbyte '--------------------------------------------------------------------------------------------',0dh,0ahbyte '重定位基地址: %08x',0dh,0ahbyte '重定位项数量: %d',0dh,0ahbyte '--------------------------------------------------------------------------------------------',0dh,0ahbyte '需要重定位的地址列表(ffffffff表示对齐用,不需要重定位)',0dh,0ahbyte '--------------------------------------------------------------------------------------------',0dh,0ah,0
szMsgReloc3 byte '%08x  ',0
szCrLf      byte 0dh,0ah,0
szMsgReloc4 byte 0dh,0ah,'未发现该文件有重定位信息.',0dh,0ah,0.code
;初始化窗口程序
_init proc local @stCf:CHARFORMAT invoke GetDlgItem, hWinMain, IDC_INFO mov hWinEdit, eax ;为窗口设置图标invoke LoadIcon, hInstance, ICO_MAIN invoke SendMessage, hWinMain, WM_SETICON, ICON_BIG, eax 	;设置编辑控件	invoke SendMessage, hWinEdit, EM_SETTEXTMODE, TM_PLAINTEXT, 0 		invoke RtlZeroMemory, addr @stCf, sizeof @stCf 					;初始化 mov @stCf.cbSize, sizeof @stCf mov @stCf.yHeight, 9*20mov @stCf.dwMask, CFM_FACE or CFM_SIZE or CFM_BOLD invoke lstrcpy, addr @stCf.szFaceName, addr szFont invoke SendMessage, hWinEdit, EM_SETCHARFORMAT, 0, addr @stCf invoke SendMessage, hWinEdit, EM_EXLIMITTEXT, 0, -1 ret 
_init endp ;------------------
; 错误Handler
;------------------
_Handler proc _lpExceptionRecord, _lpSEH, \_lpContext, _lpDispathcerContext pushad mov esi, _lpExceptionRecord mov edi, _lpContext assume esi:ptr EXCEPTION_RECORD, edi:ptr CONTEXT mov eax, _lpSEH push [eax+0ch]pop [edi].regEbp push [eax+8]pop [edi].regEip push eax pop [edi].regEsp assume esi:nothing, edi:nothing popad mov eax, ExceptionContinueExecution ret 
_Handler endp ;---------------------------------
; 将内存偏移量RVA转换为文件偏移
; lp_FileHead为文件头的起始地址
; _dwRVA为给定的RVA地址
;---------------------------------
_RVAToOffset proc _lpFileHead, _dwRVA local @dwReturn pushad mov esi, _lpFileHead assume esi:ptr IMAGE_DOS_HEADER add esi, [esi].e_lfanew assume esi:ptr IMAGE_NT_HEADERS mov edi, _dwRVA mov edx, esi add edx, sizeof IMAGE_NT_HEADERS assume edx:ptr IMAGE_SECTION_HEADER movzx ecx, [esi].FileHeader.NumberOfSections ;遍历节表.repeat mov eax, [edx].VirtualAddress ;计算该节结束RVA,不用Misc的主要原因是有些段的Misc值是错误的!add eax, [edx].SizeOfRawData .if (edi >= [edx].VirtualAddress) && (edi < eax)mov eax, [edx].VirtualAddress ;计算RVA在节中的偏移sub edi, eax mov eax, [edx].PointerToRawData ;加上节在文件中的的起始位置add eax, edi jmp @F .endif add edx, sizeof IMAGE_SECTION_HEADER .untilcxz assume edx:nothing assume esi:nothing mov eax, -1 
@@:mov @dwReturn, eax popad mov eax, @dwReturn ret 
_RVAToOffset endp ;-------------------------------------------
; 将距离文件头的文件偏移转换为内存偏移量RVA
; lp_FileHead为文件头的起始地址
; _dwOffset为给定的文件偏移地址
;-------------------------------------------
_OffsetToRVA proc _lpFileHead, _dwOffset local @dwReturn pushad mov esi, _lpFileHead assume esi:ptr IMAGE_DOS_HEADER add esi, [esi].e_lfanew assume esi:ptr IMAGE_NT_HEADERS mov edi, _dwOffset mov edx, esi add edx, sizeof IMAGE_NT_HEADERS assume edx:ptr IMAGE_SECTION_HEADER movzx ecx, [esi].FileHeader.NumberOfSections ;遍历节表.repeat mov eax, [edx].PointerToRawData ;计算该节结束RVA,不用Misc的主要原因是有些段的Misc值是错误的!add eax, [edx].SizeOfRawData .if (edi >= [edx].PointerToRawData) && (edi < eax)mov eax, [edx].PointerToRawData ;计算RVA在节中的偏移sub edi, eax mov eax, [edx].VirtualAddress ;加上节在文件中的的起始位置add eax, edi jmp @F .endif add edx, sizeof IMAGE_SECTION_HEADER .untilcxz assume edx:nothing assume esi:nothing mov eax, -1 
@@:mov @dwReturn, eax popad mov eax, @dwReturn ret 
_OffsetToRVA endp;------------------------
; 获取RVA所在节的名称
;------------------------
_getRVASectionName proc _lpFileHead, _dwRVA local @dwReturn pushad mov esi, _lpFileHead assume esi:ptr IMAGE_DOS_HEADER add esi, [esi].e_lfanew assume esi:ptr IMAGE_NT_HEADERS mov edi, _dwRVA mov edx, esi add edx, sizeof IMAGE_NT_HEADERS assume edx:ptr IMAGE_SECTION_HEADERmovzx ecx, [esi].FileHeader.NumberOfSections ;遍历节表.repeat mov eax, [edx].VirtualAddress add eax, [edx].SizeOfRawData 		;计算该节结束RVA.if (edi >= [edx].VirtualAddress) && (edi < eax)mov eax, edx jmp @F .endif add edx, sizeof IMAGE_SECTION_HEADER .untilcxz assume edx:nothing assume esi:nothing mov eax, offset szNotFound 
@@:mov @dwReturn,eax popad mov eax, @dwReturn ret 
_getRVASectionName endp ;-------------------------------
; 获取指定字符串的API函数的调用地址
; 入口参数:_hModule为动态链接库的基址,_lpApi为API函数名的首址
; 出口参数:eax为函数在虚拟地址空间中的真实地址
;-------------------------------
_getApi proc _hModule, _lpApi local @ret local @dwLen pushad mov @ret, 0 ;计算API字符串的长度,含最后的零mov edi, _lpApi mov ecx, -1 xor al, al cld repnz scasbmov ecx, edi sub ecx, _lpApi mov @dwLen, ecx ;从pe文件头的数据目录获取导出表地址mov esi, _hModule add esi, [esi+3ch]assume esi:ptr IMAGE_NT_HEADERS mov esi, [esi].OptionalHeader.DataDirectory.VirtualAddress add esi, _hModule assume esi:ptr IMAGE_EXPORT_DIRECTORY ;查找符合名称的导出函数名mov ebx, [esi].AddressOfNames add ebx, _hModule xor edx, edx .repeat push esi mov edi, [ebx]add edi, _hModule mov esi, _lpApi mov ecx, @dwLen repz cmpsb .if ZERO?pop esi jmp @F .endif pop esi add ebx, 4 inc edx .until edx >= [esi].NumberOfNames jmp _ret 
@@:;通过API名称索引获取序号索引再获取地址索引	sub ebx, [esi].AddressOfNames  sub ebx, _hModule shr ebx, 1 add ebx, [esi].AddressOfNameOrdinals add ebx, _hModule movzx eax, word ptr [ebx] shl eax, 2 add eax, [esi].AddressOfFunctions add eax, _hModule ;从地址表得到导出函数的地址mov eax, [eax]add eax, _hModule mov @ret, eax _ret:assume esi:nothing popad mov eax, @ret ret 
_getApi endp ;---------------------
; 往文本框中追加文本
;---------------------
_appendInfo proc _lpsz local @stCR:CHARRANGE pushad invoke GetWindowTextLength, hWinEdit mov @stCR.cpMin, eax 		;将插入点移动到最后mov @stCR.cpMax, eax invoke SendMessage, hWinEdit, EM_EXSETSEL, 0, addr @stCR invoke SendMessage, hWinEdit, EM_REPLACESEL, FALSE, _lpsz popad ret 
_appendInfo endp ;--------------------
; 从内存中获取PE文件的主要信息
;--------------------
_getMainInfo proc _lpFile, _lpPeHead, _dwSize local @szBuffer[1024]:byte local @szSecName[16]:byte pushad mov edi, _lpPeHead assume edi:ptr IMAGE_NT_HEADERS movzx ecx, [edi].FileHeader.Machine 				;运行平台movzx edx, [edi].FileHeader.NumberOfSections 		;节的数量movzx ebx, [edi].FileHeader.Characteristics		;节的属性invoke wsprintf, addr @szBuffer, addr szMsg, \addr szFileName, ecx, edx, ebx, \[edi].OptionalHeader.ImageBase, \			;含建议装入的地址[edi].OptionalHeader.AddressOfEntryPoint invoke SetWindowText, hWinEdit, addr @szBuffer		;添加到编辑框中;显示每个节的主要信息invoke _appendInfo, addr szMsgSec movzx ecx, [edi].FileHeader.NumberOfSections add edi, sizeof IMAGE_NT_HEADERS assume edi:ptr IMAGE_SECTION_HEADER .repeat push ecx ;获取节的名称,注意长度为8的名称并不以0结尾invoke RtlZeroMemory, addr @szSecName, sizeof @szSecName push esi push edi mov ecx, 8 mov esi, edi lea edi, @szSecName cld 
@@:lodsb 			;从内存中加载一个字节到 AL 寄存器的指令,同时它会自动更新源指针(通常是 ESI 寄存器)。.if !al 		;如果名称为0,则显示为空格mov al, ' ' .endif stosb loop @B pop edi pop esi ;获取节的主要信息invoke wsprintf, addr @szBuffer, addr szFmtSec,  \addr @szSecName, [edi].Misc.VirtualSize, \[edi].VirtualAddress, [edi].SizeOfRawData, \[edi].PointerToRawData, [edi].Characteristics invoke _appendInfo, addr @szBuffer add edi, sizeof IMAGE_SECTION_HEADER pop ecx .untilcxz assume edi:nothing popad ret 
_getMainInfo endp ;--------------------
; 获取PE文件的导入表
;--------------------
_getImportInfo proc _lpFile, _lpPeHead, _dwSize local @szBuffer[1024]:byte local @szSectionName[16]:byte pushad mov edi, _lpPeHead assume edi:ptr IMAGE_NT_HEADERS mov eax, [edi].OptionalHeader.DataDirectory[8].VirtualAddress .if !eax invoke _appendInfo, addr szErrNoImport jmp _Ret .endif invoke _RVAToOffset, _lpFile, eax add eax, _lpFile mov edi, eax 				;计算引入表所在文件偏移位置assume edi:ptr IMAGE_IMPORT_DESCRIPTOR invoke _getRVASectionName, _lpFile, [edi].OriginalFirstThunk invoke wsprintf, addr @szBuffer, addr szMsg1, eax 	;显示节名invoke _appendInfo, addr @szBuffer .while [edi].OriginalFirstThunk || [edi].TimeDateStamp || \[edi].ForwarderChain || [edi].Name1 || \[edi].FirstThunk invoke _RVAToOffset, _lpFile, [edi].Name1add eax, _lpFile invoke wsprintf, addr @szBuffer, addr szMsgImport, eax, \[edi].OriginalFirstThunk, [edi].TimeDateStamp, \[edi].ForwarderChain, [edi].FirstThunk invoke _appendInfo, addr @szBuffer ;获取IMAGE_THUNK_DATA列表到EBX.if [edi].OriginalFirstThunk mov eax, [edi].OriginalFirstThunk .else mov eax, [edi].FirstThunk .endif invoke _RVAToOffset, _lpFile, eax add eax, _lpFile mov ebx, eax .while dword ptr [ebx];按序号导入.if dword ptr [ebx] & IMAGE_ORDINAL_FLAG32 mov eax, dword ptr [ebx]and eax, 0ffffhinvoke wsprintf, addr @szBuffer, addr szMsg3, eax .else 		;按名称导入invoke _RVAToOffset, _lpFile, dword ptr [ebx]add eax, _lpFile assume eax:ptr IMAGE_IMPORT_BY_NAME movzx ecx, [eax].Hint invoke wsprintf, addr @szBuffer, \addr szMsg2, ecx, addr [eax].Name1 assume eax:nothing .endif invoke _appendInfo, addr @szBuffer add ebx, 4 .endw add edi, sizeof IMAGE_IMPORT_DESCRIPTOR .endw 
_Ret:assume edi:nothing popad ret 
_getImportInfo endp ;--------------------
; 获取PE文件的导出表
;--------------------
_getExportInfo proc _lpFile, _lpPeHead, _dwSize local @szBuffer[1024]:byte local @szSectionName[16]:byte local @lpAddressOfNames, @dwIndex, @lpAddressOfNameOrdinals pushad mov esi, _lpPeHead assume esi:ptr IMAGE_NT_HEADERS mov eax, [esi].OptionalHeader.DataDirectory[0].VirtualAddress .if !eax invoke _appendInfo, addr szErrNoExport jmp _Ret .endif invoke _RVAToOffset, _lpFile, eax add eax, _lpFile mov edi, eax 			;计算导出表所在文件偏移位置assume edi:ptr IMAGE_EXPORT_DIRECTORY invoke _RVAToOffset, _lpFile, [edi].nName add eax, _lpFile mov ecx, eax invoke _getRVASectionName, _lpFile, [edi].nName invoke wsprintf, addr @szBuffer, addr szMsgExport, \eax, ecx, [edi].nBase, [edi].NumberOfFunctions, \[edi].NumberOfNames, [edi].AddressOfFunctions, \[edi].AddressOfNames, [edi].AddressOfNameOrdinals invoke _appendInfo, addr @szBuffer invoke _RVAToOffset, _lpFile, [edi].AddressOfNames add eax, _lpFile mov @lpAddressOfNames, eax invoke _RVAToOffset, _lpFile, [edi].AddressOfNameOrdinals add eax, _lpFile mov @lpAddressOfNameOrdinals, eax invoke _RVAToOffset, _lpFile, [edi].AddressOfFunctions add eax, _lpFile mov esi, eax 			;函数的地址表mov ecx, [edi].NumberOfFunctions mov @dwIndex, 0 
@@:pushad mov eax, @dwIndex push edi mov ecx, [edi].NumberOfNames cld mov edi, @lpAddressOfNameOrdinals repnz scasw .if ZERO?		;找到函数名称sub edi, @lpAddressOfNameOrdinals sub edi, 2 shl edi, 1 add edi, @lpAddressOfNames invoke _RVAToOffset, _lpFile, dword ptr[edi]add eax, _lpFile .else mov eax, offset szExportByOrd .endif pop edi ;序号在ecx中mov ecx, @dwIndex add ecx, [edi].nBase invoke wsprintf, addr @szBuffer, addr szMsg4, \ecx, dword ptr [esi], eax invoke _appendInfo, addr @szBuffer popad add esi, 4 inc @dwIndex loop @B 
_Ret:assume esi:nothing assume edi:nothing popad ret 
_getExportInfo endp ;-----------------------
; 获取PE文件的重定位信息
;-----------------------
_getRelocInfo proc _lpFile, _lpPeHead, _dwSize local @szBuffer[1024]:byte local @szSectionName[16]:byte pushad mov esi, _lpPeHead assume esi:ptr IMAGE_NT_HEADERS mov eax, [esi].OptionalHeader.DataDirectory[8*5].VirtualAddress .if !eax invoke _appendInfo, addr szMsgReloc4 jmp _ret .endif push eax invoke _RVAToOffset, _lpFile, eax add eax, _lpFile mov esi, eax pop eax invoke _getRVASectionName, _lpFile, eax invoke wsprintf, addr @szBuffer, addr szMsgReloc1, eax invoke _appendInfo, addr @szBuffer assume esi:ptr IMAGE_BASE_RELOCATION ;循环处理每个重定位块.while [esi].VirtualAddress cld lodsd 		;eax=[esi].VirtualAddressmov ebx, eax lodsd 		;eax=[esi].SizeofBlocksub eax, sizeof IMAGE_BASE_RELOCATION 		;块总长度-两个ddshr eax, 1									;然后除以2,得到重定位项数量;除以2是因为重定位项是wordpush eax invoke wsprintf, addr @szBuffer, addr szMsgReloc2, ebx, eax invoke _appendInfo, addr @szBuffer pop ecx 									;重定位项数量xor edi, edi .repeat push ecx lodsw mov cx, ax and cx, 0f000h 		;得到高四位.if cx == 03000h		;重定位地址指向的双字的32位都需要休正and ax, 0fffh movzx eax, ax add eax, ebx 		;得到修正以前的偏移,;该偏移加上装入时的基址就是绝对地址.else 					;该重定位项无意义,仅用来作为对齐mov eax, -1 .endif invoke wsprintf, addr @szBuffer, addr szMsgReloc3, eax inc edi .if edi == 8 			;每显示8个项目换行invoke lstrcat, addr @szBuffer, addr szCrLf xor edi, edi .endif invoke _appendInfo, addr @szBuffer pop ecx .untilcxz .if edi invoke _appendInfo, addr szCrLf.endif .endw
_ret:assume esi:nothing popad ret 
_getRelocInfo endp ;--------------------
; 打开PE文件并处理
;--------------------
_openFile proc local @stOF:OPENFILENAME local @hFile, @dwFileSize, @hMapFile, @lpMemory invoke RtlZeroMemory, addr @stOF, sizeof @stOF mov @stOF.lStructSize, sizeof @stOF push hWinMain pop @stOF.hwndOwner mov @stOF.lpstrFilter, offset szExtPe mov @stOF.lpstrFile, offset szFileName mov @stOF.nMaxFile, MAX_PATH mov @stOF.Flags, OFN_PATHMUSTEXIST or OFN_FILEMUSTEXIST invoke GetOpenFileName, addr @stOF 		;让用户选择打开的文件.if !eax jmp @F .endif invoke CreateFile, addr szFileName, GENERIC_READ, \FILE_SHARE_READ or FILE_SHARE_WRITE, NULL, \OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL .if eax != INVALID_HANDLE_VALUE mov @hFile, eax invoke GetFileSize, eax, NULL mov @dwFileSize, eax .if eax invoke CreateFileMapping, @hFile, \			;内存映射文件NULL, PAGE_READONLY, 0, 0, NULL .if eax mov @hMapFile, eax invoke MapViewOfFile, eax, \FILE_MAP_READ, 0, 0, 0.if eax ;获得文件在内存的映象起始位置mov @lpMemory, eax assume fs:nothing push ebp push offset _ErrFormat push offset _Handler push fs:[0]mov fs:[0], esp ;检测PE文件是否有效mov esi, @lpMemory assume esi:ptr IMAGE_DOS_HEADER ;判断是否有MZ字样.if [esi].e_magic != IMAGE_DOS_SIGNATURE jmp _ErrFormat .endif ;调整ESI指针指向PE文件头add esi, [esi].e_lfanew assume esi:ptr IMAGE_NT_HEADERS ;判断是否有PE字样.if [esi].Signature != IMAGE_NT_SIGNATURE jmp _ErrFormat .endif ;到此为止,该文件的验证已经完成。为PE结构文件;接下来分析分件映射到内存中的数据,并显示主要参数invoke _getMainInfo, @lpMemory, esi, @dwFileSize ;显示导入表invoke _getImportInfo, @lpMemory, esi, @dwFileSize ;显示导出表invoke _getExportInfo, @lpMemory, esi, @dwFileSize ;显示重定位信息invoke _getRelocInfo, @lpMemory, esi, @dwFileSizejmp _ErrorExit 
_ErrFormat:invoke MessageBox, hWinMain, offset szErrFormat, \NULL, MB_OK _ErrorExit:pop fs:[0]add esp, 0ch invoke UnmapViewOfFile, @lpMemory .endif invoke CloseHandle, @hMapFile .endif invoke CloseHandle, @hFile .endif .endif 
@@:ret 
_openFile endp ;-------------------------------
;窗口程序
;--------------------------------
_ProcDlgMain proc uses ebx edi esi hWnd, wMsg, wParam, lParam mov eax, wMsg .if eax == WM_CLOSE invoke EndDialog, hWnd, NULL .elseif eax == WM_INITDIALOG				;初始化 	push hWnd pop hWinMain call _init .elseif eax == WM_COMMAND 					;菜单mov eax, wParam .if eax == IDM_EXIT						;退出invoke EndDialog, hWnd, NULL .elseif eax == IDM_OPEN 				;打开文件 call _openFile.elseif eax == IDM_1 invoke MessageBox, NULL, offset szErrFormat, offset szErr, MB_ICONWARNING.elseif eax == IDM_2 invoke MessageBox, NULL, offset szErrFormat, offset szErr, MB_ICONQUESTION.elseif eax == IDM_3 invoke MessageBox, NULL, offset szErrFormat, offset szErr, MB_YESNOCANCEL.endif .elsemov eax, FALSE ret .endif mov eax, TRUE ret 
_ProcDlgMain endp start:invoke LoadLibrary, offset szDllEdit mov hRichEdit, eax invoke GetModuleHandle, NULL mov hInstance, eax invoke DialogBoxParam, hInstance, \DLG_MAIN, NULL, offset _ProcDlgMain, NULL invoke FreeLibrary, hRichEdit invoke ExitProcess, NULL 
end start 

Makefile文件

NAME = peinfo
OBJS = $(NAME).obj
RES  = $(NAME).resLINK_FLAG = /subsystem:windows
ML_FLAG = /c /coff$(NAME).exe: $(OBJS) $(RES)Link $(LINK_FLAG) $(OBJS) $(RES).asm.obj:ml $(ML_FLAG) $<
.rc.res:rc $<clean:del *.objdel *.res

编译:

运行:


2.5 小结

本章主要学习了如何通过汇编语言来编写基于PE操作的三个小工具,在后面对PE文件的分析中会经常使用这三个小工具。后面会讲到如何利用PEInfo遍历PE文件的导入表和导出表,那时还会用到本章的源代码。大家也可以对这些小工具进行扩展或整合,编写属于自己的PE分析工具。

值得一提的是,随编译器分发的可执行程序中有一个基于命令行的PE文件结构分析工具dumpbin.exe,它是公认的最好的PE分析工具之一,如果你喜欢,也可以用它来代替我们的小程序。

http://www.dtcms.com/a/426742.html

相关文章:

  • 【DeepResearch】langgraph自主迭代研究能力的 AI 代理及分析
  • 专题:2025医药行业数智赋能与AI应用全景研究报告|附200+份报告PDF、数据仪表盘汇总下载
  • Alibaba Cloud Linux 3 +Docker 部署 ThinkPHP6 (宝塔环境)-问题篇
  • LeetCode 刷题【93. 复原 IP 地址】
  • Python类和对象----实例属性,类属性(这是我理解类和对象最透彻的一次!!)
  • 文档解析Logics-Parsing
  • 网站设计报价.doc网页端
  • IDEA中Add New Configuration找不到Tomcat
  • 学习笔记092——Windows如何将 jar 包启动设置成系统服务
  • React前端框架有哪些?
  • 文昌市建设局网站无锡工厂网站建设
  • 龙岗网站建设-信科网络深圳房地产论坛家在深圳
  • Ceph 分布式存储学习笔记(三):块存储和对象存储管理
  • Ubuntu22.4安装Samba服务器
  • 服务器安装Java与nginx与nacos
  • Navicat导入Excel至瀚高数据库
  • 网站的制作与调试微网站服务合同
  • JavaScript调试工具有哪些?常见问题与常用调试工具推荐
  • 网站项目建设策划方案超级外链发布
  • 使用 Lens连接阿里云k8s集群
  • UNIX下C语言编程与实践24-UNIX 标准文件编程库:无格式读写函数族(字符、行、块)的使用
  • mysql中的日志
  • Spring Cloud Nacos 配置中心详解:从基础使用到 MyBatis 整合(含多文档配置)
  • 去出海做产品吧,亚马逊爆款产品 属于电子类的消费产品。用全志A733完胜--
  • 设计配色网站租房合同范本下载word
  • 安卓生态进化史:从手机系统到全场景智能
  • 自适应网站开发工具网站优化排名提升
  • 中国建材网:重构建材行业生态的数字力量
  • 【有源码】基于Hadoop+Spark的豆瓣电影数据分析与可视化系统-基于大数据的电影评分趋势分析与可视化系统
  • 模板匹配算法原理