《WindowsPE权威指南》戚利第2章三个小工具的编写.docx

上传人:b****2 文档编号:491061 上传时间:2023-04-29 格式:DOCX 页数:46 大小:143.20KB
下载 相关 举报
《WindowsPE权威指南》戚利第2章三个小工具的编写.docx_第1页
第1页 / 共46页
《WindowsPE权威指南》戚利第2章三个小工具的编写.docx_第2页
第2页 / 共46页
《WindowsPE权威指南》戚利第2章三个小工具的编写.docx_第3页
第3页 / 共46页
《WindowsPE权威指南》戚利第2章三个小工具的编写.docx_第4页
第4页 / 共46页
《WindowsPE权威指南》戚利第2章三个小工具的编写.docx_第5页
第5页 / 共46页
《WindowsPE权威指南》戚利第2章三个小工具的编写.docx_第6页
第6页 / 共46页
《WindowsPE权威指南》戚利第2章三个小工具的编写.docx_第7页
第7页 / 共46页
《WindowsPE权威指南》戚利第2章三个小工具的编写.docx_第8页
第8页 / 共46页
《WindowsPE权威指南》戚利第2章三个小工具的编写.docx_第9页
第9页 / 共46页
《WindowsPE权威指南》戚利第2章三个小工具的编写.docx_第10页
第10页 / 共46页
《WindowsPE权威指南》戚利第2章三个小工具的编写.docx_第11页
第11页 / 共46页
《WindowsPE权威指南》戚利第2章三个小工具的编写.docx_第12页
第12页 / 共46页
《WindowsPE权威指南》戚利第2章三个小工具的编写.docx_第13页
第13页 / 共46页
《WindowsPE权威指南》戚利第2章三个小工具的编写.docx_第14页
第14页 / 共46页
《WindowsPE权威指南》戚利第2章三个小工具的编写.docx_第15页
第15页 / 共46页
《WindowsPE权威指南》戚利第2章三个小工具的编写.docx_第16页
第16页 / 共46页
《WindowsPE权威指南》戚利第2章三个小工具的编写.docx_第17页
第17页 / 共46页
《WindowsPE权威指南》戚利第2章三个小工具的编写.docx_第18页
第18页 / 共46页
《WindowsPE权威指南》戚利第2章三个小工具的编写.docx_第19页
第19页 / 共46页
《WindowsPE权威指南》戚利第2章三个小工具的编写.docx_第20页
第20页 / 共46页
亲,该文档总共46页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

《WindowsPE权威指南》戚利第2章三个小工具的编写.docx

《《WindowsPE权威指南》戚利第2章三个小工具的编写.docx》由会员分享,可在线阅读,更多相关《《WindowsPE权威指南》戚利第2章三个小工具的编写.docx(46页珍藏版)》请在冰点文库上搜索。

《WindowsPE权威指南》戚利第2章三个小工具的编写.docx

《WindowsPE权威指南》戚利第2章三个小工具的编写

《Windows_PE权威指南》(戚利)

第2章三个小工具的编写

俗话说:

“工欲善其事,必先利其器。

”本章将完成与WindowsPE有关的三个小工具的开发。

这三个小工具分别是:

❑PEDump:

PE文件字节码查看器

❑PEComp:

PE文件比较器

❑PEInfo:

PE文件结构查看器

首先让我们从编写最基本的汇编窗口程序开始。

该窗口程序是本章三个小工具编写的基础,也是后续大部分章节中其他程序编写的基础。

2.1构造基本窗口程序

本节我们将构造一个具有基本窗口元素(含标题栏、菜单栏、工作区域)的窗口程序,后续大部分的程序开发都将以这个基本窗口程序作为基础进行扩展。

2.1.1构造窗口界面

要构造的窗口程序具备窗口图形界面的大部分元素,包含窗口、菜单、图标、工作区域等。

通常的做法是:

首先根据程序功能对程序的界面进行构思,然后在纸张上将大致的结构图画出,最后通过资源脚本来定义并实现界面中的每一部分。

当然,读者也可以使用一些辅助的软件如RADAsm中的资源编辑器或者VS中的资源编辑器,根据构思好的界面在所见即所得的资源编辑器图形界面中直接构造程序窗口界面,该程序最终显示的效果如图2-1所示。

图2-1:

基本窗口界面

2.1.2编写相关的资源文件

构造完窗口界面以后,需要依据界面编写对应的资源文件,这有点类似于工程建设里的依照图纸施工。

资源文件一般以“.rc”为扩展名,资源文件编写完成后还必须通过资源编译器对资源文件实施编译以生成资源目标文件。

整个过程分为两个阶段:

❑创建资源文件pe.rc

❑生成资源目标文件pe.res

下面我们分别来介绍这两个阶段的内容。

1.创建资源文件pe.rc

在编写资源文件时,需要定义图形中出现的所有菜单项、对话框、图标等。

资源文件详细编码如代码清单2-1所示。

代码清单2-1:

资源文件详细编码(chapter2\pe.rc)

1#include

2

3#defineICO_MAIN1000

4#defineDLG_MAIN1000

5#defineIDC_INFO1001

6#defineIDM_MAIN2000

7#defineIDM_OPEN2001

8#defineIDM_EXIT2002

9

10#defineIDM_14000

11#defineIDM_24001

12#defineIDM_34002

13#defineIDM_44003

14

15

16ICO_MAINICON"main.ico"

17

18DLG_MAINDIALOG50,50,544,399

19STYLEDS_MODALFRAME|WS_POPUP|WS_VISIBLE|WS_CAPTION|WS_SYSMENU

20CAPTION"PE文件基本信息byqixiaorui"

21MENUIDM_MAIN

22FONT9,"宋体"

23BEGIN

24CONTROL"",IDC_INFO,"RichEdit20A",196|ES_WANTRETURN|WS_CHILD|WS_READONLY

25|WS_VISIBLE|WS_BORDER|WS_VSCROLL|WS_TABSTOP,0,0,540,396

26END

27

28IDM_MAINmenudiscardable

29BEGIN

30POPUP"文件(&F)"

31BEGIN

32menuitem"打开文件(&O)...",IDM_OPEN

33menuitemseparator

34menuitem"退出(&x)",IDM_EXIT

35END

36

37POPUP"查看"

38BEGIN

39menuitem"源文件",IDM_1

40menuitem"窗口透明度",IDM_2

41menuitemseparator

42menuitem"大小",IDM_3

43menuitem"宽度",IDM_4

44END

45

46END

行1~13定义了各元素常量,行16指定了显示在窗口标题栏的图标为main.ico。

需要注意的是,必须保证图标文件与资源文件在同一个目录中,如果指定的图标文件在其他目录,则需要使用绝对路径。

语法如下:

ICO_MAINICON"C:

\source\icon\main.ico"

行18~26定义了对话框DIALOG,该对话框最终显示效果如图2-1所示。

窗口定义中包含了窗口的显示样式、标题栏文字、窗口中包含的菜单IDM_MAIN及窗口字体格式,在窗口工作区域中只包含了一个富文本框控件IDC_INFO(在行24、行25定义)。

行28~46定义了菜单IDM_MAIN。

它包含了两个弹出式下拉菜单,分别是“文件”菜单和“查看”菜单,每个弹出式菜单中又各包含了多个菜单选项。

2.生成资源目标文件pe.res

资源文件是文本文件,由定义资源的一些脚本语句组成。

资源文件可以使用文本编辑软件(如记事本)查看和修改。

资源目标文件是对这些脚本的一种再组织,根据脚本描述将脚本涉及到的所有资源编译到一起,形成二进制字节码,资源目标文件无法通过文本编辑软件查看。

编译资源文件,生成资源目标文件(扩展名为res)。

在命令提示符下输入以下命令(非斜体部分):

D:

\masm32\source\chapter2>rc–rpe.rc

如果执行编译没有错误发生(如资源脚本中定义的相关文件不存在就会产生错误提示),则命令执行后会在当前目录下生成资源目标文件pe.res。

该资源目标文件最终要被链接程序嵌入到PE文件中,形成PE资源表所描述的数据的一部分。

2.1.3通用程序框架的实现

资源目标文件生成以后,接下来的工作就是实现通用程序框架。

主要分为三个阶段:

❑编码源程序pe.asm

❑编译生成目标文件pe.obj

❑链接生成可执行文件pe.exe

下面我们分别介绍各阶段的详细内容。

1.编码源程序pe.asm

首先,打开记事本,输入代码清单2-2所示内容(去掉前面的行号)。

代码清单2-2:

通用程序框架的源程序(chapter2\pe.asm)

1.386

2.modelflat,stdcall

3optioncasemap:

none

4

5includewindows.inc

6includeuser32.inc

7includelibuser32.lib

8includekernel32.inc

9includelibkernel32.lib

10includecomdlg32.inc

11includelibcomdlg32.lib

12

13

14ICO_MAINequ1000

15DLG_MAINequ1000

16IDC_INFOequ1001

17IDM_MAINequ2000

18IDM_OPENequ2001

19IDM_EXITequ2002

20IDM_1equ4000

21IDM_2equ4001

22IDM_3equ4002

23

24.data

25hInstancedd?

;进程实例句柄

26hRichEditdd?

;富文本动态链接库句柄

27hWinMaindd?

;窗口句柄

28hWinEditdd?

;文本控件句柄

29szFileNamedbMAX_PATHdup(?

30

31.const

32szDllEditdb'RichEd20.dll',0

33szClassEditdb'RichEdit20A',0

34szFontdb'宋体',0

35

36

37.code

38

39;----------------

40;初始化窗口程序

41;----------------

42_initproc

43local@stCf:

CHARFORMAT

44

45invokeGetDlgItem,hWinMain,IDC_INFO

46movhWinEdit,eax

47

48;为窗口设置图标

49invokeLoadIcon,hInstance,ICO_MAIN

50invokeSendMessage,hWinMain,WM_SETICON,ICON_BIG,eax

51

52;设置编辑控件

53invokeSendMessage,hWinEdit,EM_SETTEXTMODE,TM_PLAINTEXT,0

54invokeRtlZeroMemory,addr@stCf,sizeof@stCf

55mov@stCf.cbSize,sizeof@stCf

56mov@stCf.yHeight,9*20

57mov@stCf.dwMask,CFM_FACEorCFM_SIZEorCFM_BOLD

58invokelstrcpy,addr@stCf.szFaceName,addrszFont

59invokeSendMessage,hWinEdit,EM_SETCHARFORMAT,0,addr@stCf

60invokeSendMessage,hWinEdit,EM_EXLIMITTEXT,0,-1

61ret

62_initendp

63

64

65;-------------------

66;窗口回调函数

67;-------------------

68_ProcDlgMainprocusesebxediesihWnd,wMsg,wParam,lParam

69moveax,wMsg

70.ifeax==WM_CLOSE

71invokeEndDialog,hWnd,NULL

72.elseifeax==WM_INITDIALOG;初始化

73pushhWnd

74pophWinMain

75call_init

76.elseifeax==WM_COMMAND;菜单

77moveax,wParam

78.ifeax==IDM_EXIT;退出

79invokeEndDialog,hWnd,NULL

80.elseifeax==IDM_OPEN;打开文件

81.elseifeax==IDM_1;其他菜单项

82.elseifeax==IDM_2

83.elseifeax==IDM_3

84.endif

85.else

86moveax,FALSE

87ret

88.endif

89moveax,TRUE

90ret

91_ProcDlgMainendp

92

93start:

94invokeLoadLibrary,offsetszDllEdit

95movhRichEdit,eax

96invokeGetModuleHandle,NULL

97movhInstance,eax

98invokeDialogBoxParam,hInstance,\

99DLG_MAIN,NULL,offset_ProcDlgMain,NULL

100invokeFreeLibrary,hRichEdit

101invokeExitProcess,NULL

102endstart

代码清单2-2第98行通过调用DialogBoxParam函数创建了一个弹出式窗口作为整个程序的主窗口,并将内部函数_ProcDlgMain的地址当成该函数的参数之一传入该函数。

函数_ProcDlgMain是弹出窗口的回调函数,如果我们要对发生在窗口中的消息进行捕获,则需要在此函数中设置对不同消息响应的代码,由于编写的只是一个基本程序框架,所以回调函数只对菜单中的“退出”选项做了响应,如下所示:

70.ifeax==WM_CLOSE

71invokeEndDialog,hWnd,NULL

代码编写完成以后保存为pe.asm文件,然后进行编译生成目标文件。

2.编译生成目标文件pe.obj

在编写一些大程序时,通常会根据功能将源代码分别写到不同的文件里,有时为了项目分工合作,在一个项目中也会出现使用不同语言编写的源代码。

这些源代码文件都需要在各自独立的环境中被编译生成各自的目标文件,目标文件是符合通用对象文件格式(COFF)的文件,该格式的定制主要是为了方便混合编程。

生成目标文件的过程是处理源代码中可能会出现错误(如引入外部符号错误、源代码语法错误等)的过程,生成的目标文件最终会被链接程序拼接到最终的可执行文件中,当然,除了编译源代码生成的目标文件外,可执行文件还包含资源目标文件、外部引入的符号等信息。

在命令提示符下输入以下命令,编译源文件pe.asm:

D:

\masm32\source\chapter2>ml–c–coffpe.asm

如果没有错误,则会在当前目录下生成目标文件pe.obj。

接下来链接所有的目标文件(包括资源目标文件和源代码目标文件)生成最终的可执行文件:

3.链接生成可执行文件pe.exe

在命令提示符下输入以下命令:

D:

\masm32\source\chapter2>link–subsystem:

windowspe.objpe.res

上述命令指定最终生成的EXE文件的运行平台为Windows,链接程序将根据pe.obj中的描述构造PE文件,并将相关资源内容附加到PE文件里,最终生成可执行的pe.exe。

在命令提示符下输入pe,然后回车,即可看到最终的运行效果,效果见图2-1。

至此,一个基本的基于汇编语言的窗口程序就编写完成了。

接下来的工作就是在此基础上进行扩展,开发三个基于WindowsPE的小工具,首先来看字节码查看器PEDump的编写。

2.2PEDump的实现

PEDump是字节码查看器,利用它可以查看和阅读指定的PE文件的十六进制字节码,帮助我们更好地分析PE结构。

2.2.1编写PEDump程序的流程

PEDump的编写重点在于显示功能,首先来看一看最终可能的输出效果如图2-2所示:

列一:

地址列二:

字节码内容列三:

ASCII字符

000001400E1FBA0E00B409CD-21B8014CCD215468........!

..L.!

Th

0000015069732070726F6772-616D2063616E6E6Fisprogramcanno

00000160742062652072756E-20696E20444F5320tberuninDOS

000001706D6F64652E0D0D0A-240000mode....$..

图2-2PEDump的输出效果

如图所示,最终输出包含三列内容。

❑第一列是地址,地址的值是第(n*16+1)个字节在文件中的位置。

❑第二列是由空格分隔符分隔的16个字节的16进制显示。

❑第三列是这16个字节对应的ASCII码值,如果ASCII码中无对应值,或者这些值是一些功能键,则以“.”代替。

有的查看器(如FlexHex)还增加了Unicode字符一列,用以显示字节码中包含的Unicode字符。

编程时要考虑到最后一行可能会少于16个字节,这时候第二列和第三列不足的地方就可以使用空格补足。

程序编写的流程如图2-3所示。

图2-3:

编写PEDump程序的流程

如图所示,第1步是打开PE文件。

需要说明的是,打开的PE文件会被映射为内存文件,因为内存文件中的内容是线性存放的,存取方便,速度也快,并且操作起来比在文件中使用指针定位要更容易些。

第2步,使用API函数GetFileSize得到打开的PE文件的大小。

第3步至第5步,将上步获取的值与16相除,商作为循环计数,余数则是字节码查看器最后一行的字节个数。

在程序中构造一个循环,用来显示PE文件除最后一行外其他行的字节内容。

为了更好地理解该开发过程,我们需要理解两个概念:

内存映射文件与PE内存映像。

内存映射文件是指将硬盘上的文件不做修改地装载到内存中。

这样,文件中字节与字节之间就是顺序的了。

在硬盘上,文件被分割成若干簇,这些簇不一定会按照文件内容顺序排列在一起,当我们访问磁盘上的文件时,需要计算机首先将不同位置的内容读取到内存。

有了内存映射文件,访问就会变得更轻松和快捷,由于读取磁盘的操作集中到了一起进行,读写效率会提高很多。

被一次性读取到内存的文件字节按线性排序,访问相对简单,速度也提升了不少。

所以我们在许多大型的编辑软件设计中经常会见到使用内存映射文件存取磁盘文件的示例。

PE内存映像是指将PE文件按照一定的规则装载到内存中,装入后的整个文件头内容不会发生变化,但PE文件的某一部分如节的内容会按照字段中的对齐方式在内存中对齐,从而使得内存中的PE映像和装载前的PE文件出现不同。

那么,为什么PE内存映像不能和一般的内存映射文件一样呢?

答案很简单:

PE文件是由操作系统装载进内存,其目的是为了运行。

为了配合操作系统的运行,方便调度,提高运行效率,PE映像必须按照一定的格式对齐,所以内存中的PE映像和原来硬盘上的文件是不同的,当然与内存映射文件也就不一样了。

2.2.2PEDump编码

简单了解了程序开发的流程,接下来进入编码阶段。

此处将会用到2.1节中的源程序文件pe.asm。

PEDump.asm在pe.asm的基础上增加了对菜单项IDM_OPEN的响应代码,如下所示:

.elseifeax==IDM_OPEN;打开文件

invoke_openFile

函数_openFile的代码详见代码清单2-3。

代码清单2-3:

PEDump主要代码实现(chapter2\pedump.asm的_openFile函数)

1;--------------------

2;打开PE文件并处理

3;--------------------

4_openFileproc

5local@stOF:

OPENFILENAME

6local@hFile,@hMapFile

7local@bufTemp1;十六进制字节码

8local@bufTemp2;第一列

9local@dwCount;计数,逢16则重新计

10local@dwCount1;地址顺号

11local@dwBlanks;最后一行空格数

12

13invokeRtlZeroMemory,addr@stOF,sizeof@stOF

14mov@stOF.lStructSize,sizeof@stOF

15pushhWinMain

16pop@stOF.hwndOwner

17mov@stOF.lpstrFilter,offsetszExtPe

18mov@stOF.lpstrFile,offsetszFileName

19mov@stOF.nMaxFile,MAX_PATH

20mov@stOF.Flags,OFN_PATHMUSTEXISTorOFN_FILEMUSTEXIST

21invokeGetOpenFileName,addr@stOF;让用户选择打开的文件

22.if!

eax

23jmp@F

24.endif

25invokeCreateFile,addrszFileName,GENERIC_READ,\

26FILE_SHARE_READorFILE_SHARE_WRITE,NULL,\

27OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL

28.ifeax!

=INVALID_HANDLE_VALUE

29mov@hFile,eax

30invokeGetFileSize,eax,NULL;获取文件大小

31movtotalSize,eax

32

33.ifeax

34invokeCreateFileMapping,@hFile,\;内存映射文件

35NULL,PAGE_READONLY,0,0,NULL

36.ifeax

37mov@hMapFile,eax

38invokeMapViewOfFile,eax,\

39FILE_MAP_READ,0,0,0

40.ifeax

41movlpMemory,eax;获得文件在内存的映象起始位置

42assumefs:

nothing

43pushebp

44pushoffset_ErrFormat

45pushoffset_Handler

46pushfs:

[0]

47movfs:

[0],esp

48

49;开始处理文件

50……

177……

178;处理文件结束

179

180jmp_ErrorExit

181

182_ErrFormat:

183invokeMessageBox,hWinMain,offsetszErrFormat,NULL,MB_OK

184_ErrorExit:

185popfs:

[0]

186addesp,0ch

187invokeUnmapViewOfFile,lpMemory

188.endif

189invokeCloseHandle,@hMapFile

190.endif

191invokeCloseHandle,@hFile

192.endif

193.endif

194@@:

195ret

196_openFileendp

子程序_openFile首先调用GetOpenFileName,显示一个文件选择对话框,让用户选择要打开的PE文件,然后获取指定文件的大小,并用这个值使用函数CreateFileMapping在内存中建立该文件的映像,全局变量lpMemory指向了内存映像的起始地址。

有了这个地址,再对文件进行各种操作就简单多了。

行50~177是对内存映像文件的处理过程,这个过程如果太复杂,可以继续使用子程序,如果不很复杂,则可以直接在此编写处理代码,十六进制字节码查看器的主要代码如下:

51;缓冲区初始化

52invokeRtlZeroMemory,addr@bufTemp1,10

53invokeRtlZeroMemory,addr@bufTemp2,20

54invokeRtlZeroMemory,addrlpServicesBuffer,100

55invokeRtlZeroMemory,addrbufDisplay,50

56

57mov@dwCount,1

58mo

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工程科技 > 建筑土木

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2