📄 lion-petut-c02.htm
字号:
<html>
<head>
<meta http-equiv="Content-Type"
content="text/html; charset=gb_2312-80">
<meta name="GENERATOR" content="Microsoft FrontPage Express 2.0">
<title>PE教程2: 检验PE文件的有效性</title>
</head>
<body bgcolor="#000066" text="#FFFFFF" link="#FFFFCC"
vlink="#FFCCCC" alink="#CCFFCC">
<h1 align="center"><font color="#FFFFCC">PE教程2: 检验PE文件的有效性</font></h1>
<p><font size="2">本教程中我们将学习如何检测给定文件是一有效</font><font
size="2" face="MS Sans Serif">PE</font><font size="2">文件。<br>
下载 </font><a href="files/PE-tut02.zip"><font size="2">范例</font></a></p>
<h3>理论<font face="Arial, Helvetica, sans-serif">:</font></h3>
<p><font size="2">如何才能校验指定文件是否为一有效</font><font
size="2" face="MS Sans Serif">PE</font><font size="2">文件呢</font><font
size="2" face="MS Sans Serif">? </font><font size="2">这个问题很难回答,完全取决于想要的精准程度。您可以检验</font><font
size="2" face="MS Sans Serif">PE</font><font size="2">文件格式里的各个数据结构,或者仅校验一些关键数据结构。大多数情况下,没有必要校验文件里的每一个数据结构,只要一些关键数据结构有效,我们就认为是有效的</font><font
size="2" face="MS Sans Serif">PE</font><font size="2">文件了。下面我们就来实现前面的假设。</font></p>
<p><font size="2">我们要验证的重要数据结构就是 </font><font
size="2" face="MS Sans Serif">PE header</font><font size="2">。从编程角度看,</font><font
size="2" face="MS Sans Serif">PE header </font><font size="2">实际就是一个
</font><font size="2" face="MS Sans Serif">IMAGE_NT_HEADERS </font><font
size="2">结构。定义如下</font><font size="2"
face="MS Sans Serif">:</font></p>
<p><font size="2" face="MS Sans Serif"><b>IMAGE_NT_HEADERS STRUCT
<br>
Signature dd ? <br>
FileHeader IMAGE_FILE_HEADER <> <br>
OptionalHeader IMAGE_OPTIONAL_HEADER32 <> <br>
IMAGE_NT_HEADERS ENDS </b></font></p>
<p><font color="#FFFFCC" size="2" face="MS Sans Serif"><b>Signature</b></font><font
size="2" face="MS Sans Serif"> </font><font size="2">一</font><font
size="2" face="MS Sans Serif">dword</font><font size="2">类型,值为</font><font
size="2" face="MS Sans Serif">50h, 45h, 00h, 00h</font><font
size="2">(</font><font size="2" face="MS Sans Serif">PE\0\0</font><font
size="2">)。</font><font size="2" face="MS Sans Serif"> </font><font
size="2">本域为</font><font size="2" face="MS Sans Serif">PE</font><font
size="2">标记,我们可以此识别给定文件是否为有效</font><font
size="2" face="MS Sans Serif">PE</font><font size="2">文件。</font><br>
<font color="#FFFFCC" size="2" face="MS Sans Serif"><b>FileHeader
</b></font><font size="2">该结构域包含了关于</font><font
size="2" face="MS Sans Serif">PE</font><font size="2">文件物理分布的信息,</font><font
size="2" face="MS Sans Serif"> </font><font size="2">比如节数目、文件执行机器等。</font><font
size="2" face="MS Sans Serif"><br>
</font><font color="#FFFFCC" size="2" face="MS Sans Serif"><b>OptionalHeader</b></font><font
size="2" face="MS Sans Serif"> </font><font size="2">该结构域包含了关于</font><font
size="2" face="MS Sans Serif">PE</font><font size="2">文件逻辑分布的信息,虽然域名有</font><font
size="2" face="MS Sans Serif">"</font><font size="2">可选</font><font
size="2" face="MS Sans Serif">"</font><font size="2">字样,但实际上本结构总是存在的。</font></p>
<p><font size="2">我们目的很明确。如果</font><font
color="#CCFFCC" size="2" face="MS Sans Serif"><b>IMAGE_NT_HEADERS</b></font><font
size="2">的</font><font size="2" face="MS Sans Serif">signature</font><font
size="2">域值等于</font><font size="2" face="MS Sans Serif">"PE\0\0"</font><font
size="2">,那么就是有效的</font><font size="2"
face="MS Sans Serif">PE</font><font size="2">文件。实际上,为了比较方便,</font><font
size="2" face="MS Sans Serif">Microsoft</font><font size="2">已定义了常量</font><font
color="#CCFFCC" size="2" face="MS Sans Serif"><b>IMAGE_NT_SIGNATURE</b></font><font
size="2">供我们使用。</font></p>
<p><font color="#FFCCFF" size="2" face="MS Sans Serif"><b>IMAGE_DOS_SIGNATURE
equ 5A4Dh </b></font><font size="2" face="MS Sans Serif"><b><br>
IMAGE_OS2_SIGNATURE equ 454Eh <br>
IMAGE_OS2_SIGNATURE_LE equ 454Ch <br>
IMAGE_VXD_SIGNATURE equ 454Ch <br>
</b></font><font color="#FFCCFF" size="2" face="MS Sans Serif"><b>IMAGE_NT_SIGNATURE
equ 4550h </b></font></p>
<p><font size="2">接下来的问题是</font><font size="2"
face="MS Sans Serif">: </font><font size="2">如何定位 </font><font
size="2" face="MS Sans Serif">PE header? </font><font size="2">答案很简单</font><font
size="2" face="MS Sans Serif">: DOS MZ header </font><font
size="2">已经包含了指向 </font><font size="2"
face="MS Sans Serif">PE header </font><font size="2">的文件偏移量。</font><font
size="2" face="MS Sans Serif">DOS MZ header </font><font size="2">又定义成结构</font><font
color="#CCFFCC" size="2"><b> </b></font><font color="#CCFFCC"
size="2" face="MS Sans Serif"><b>IMAGE_DOS_HEADER</b></font><font
size="2" face="MS Sans Serif"> </font><font size="2">。查询</font><font
size="2" face="MS Sans Serif">windows.inc</font><font size="2">,我们知道
</font><font color="#CCFFCC" size="2" face="MS Sans Serif"><b>IMAGE_DOS_HEADER</b></font><font
size="2" face="MS Sans Serif"> </font><font size="2">结构的</font><font
color="#CC9900" size="2" face="MS Sans Serif"><b>e_lfanew</b></font><font
size="2">成员就是指向 </font><font size="2"
face="MS Sans Serif">PE header </font><font size="2">的文件偏移量。
</font></p>
<p><font size="2">现在将所有步骤总结如下</font><font
size="2" face="MS Sans Serif">:</font></p>
<ol>
<li><font size="2">首先检验文件头部第一个字的值是否等于
</font><font color="#CCFFCC" size="2"
face="MS Sans Serif"><b>IMAGE_DOS_SIGNATURE</b></font><font
color="#CCFFCC" size="2"><b>,</b></font><font size="2">是则
</font><font size="2" face="MS Sans Serif">DOS MZ header </font><font
size="2">有效。</font></li>
<li><font size="2">一旦证明文件的 </font><font
size="2" face="MS Sans Serif">DOS header </font><font
size="2">有效后,就可用</font><font size="2"
face="MS Sans Serif">e_lfanew</font><font size="2">来定位
</font><font size="2" face="MS Sans Serif">PE header </font><font
size="2">了。</font></li>
<li><font size="2">比较 </font><font size="2"
face="MS Sans Serif">PE header </font><font size="2">的第一个字的值是否等于</font><font
color="#CCFFCC" size="2"><b> </b></font><font
color="#CCFFCC" size="2" face="MS Sans Serif"><b>IMAGE_NT_HEADER</b></font><font
size="2">。如果前后两个值都匹配,那我们就认为该文件是一个有效的</font><font
size="2" face="MS Sans Serif">PE</font><font size="2">文件。</font></li>
</ol>
<h3><font face="Arial, Helvetica, sans-serif">Example:</font></h3>
<p><font face="Fixedsys">.386 <br>
.model flat,stdcall <br>
option casemap:none <br>
include \masm32\include\windows.inc <br>
include \masm32\include\kernel32.inc <br>
include \masm32\include\comdlg32.inc <br>
include \masm32\include\user32.inc <br>
includelib \masm32\lib\user32.lib <br>
includelib \masm32\lib\kernel32.lib <br>
includelib \masm32\lib\comdlg32.lib <br>
<br>
SEH struct <br>
PrevLink dd ? ; the address of the previous seh
structure <br>
CurrentHandler dd ? ; the address of the
exception handler <br>
SafeOffset dd ? ; The offset where it's safe to
continue execution <br>
PrevEsp dd ? ; the old value in esp
<br>
PrevEbp dd ? ; The old value in ebp <br>
SEH ends<br>
<br>
.data <br>
AppName db "PE tutorial no.2",0 <br>
ofn OPENFILENAME <> <br>
FilterString db "Executable Files (*.exe,
*.dll)",0,"*.exe;*.dll",0 <br>
db "All Files",0,"*.*",0,0 <br>
FileOpenError db "Cannot open the file for reading",0 <br>
FileOpenMappingError db "Cannot open the file for memory
mapping",0 <br>
FileMappingError db "Cannot map the file into memory",0
<br>
FileValidPE db "This file is a valid PE",0 <br>
FileInValidPE db "This file is not a valid PE",0 <br>
<br>
.data? <br>
buffer db 512 dup(?) <br>
hFile dd ? <br>
hMapping dd ? <br>
pMapping dd ? <br>
ValidPE dd ? <br>
<br>
.code <br>
start proc <br>
LOCAL seh:SEH <br>
mov ofn.lStructSize,SIZEOF ofn <br>
mov ofn.lpstrFilter, OFFSET FilterString <br>
mov ofn.lpstrFile, OFFSET buffer <br>
mov ofn.nMaxFile,512 <br>
mov ofn.Flags, OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or
OFN_LONGNAMES or OFN_EXPLORER or OFN_HIDEREADONLY <br>
invoke GetOpenFileName, ADDR ofn <br>
.if eax==TRUE <br>
invoke CreateFile, addr buffer, GENERIC_READ,
FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
<br>
.if eax!=INVALID_HANDLE_VALUE <br>
mov hFile, eax <br>
invoke CreateFileMapping,
hFile, NULL, PAGE_READONLY,0,0,0 <br>
.if eax!=NULL <br>
mov
hMapping, eax <br>
invoke
MapViewOfFile,hMapping,FILE_MAP_READ,0,0,0 <br>
.if
eax!=NULL <br>
mov pMapping,eax <br>
assume fs:nothing <br>
push fs:[0] <br>
pop seh.PrevLink <br>
mov seh.CurrentHandler,offset SEHHandler <br>
mov seh.SafeOffset,offset FinalExit <br>
lea eax,seh <br>
mov fs:[0], eax <br>
mov seh.PrevEsp,esp <br>
mov seh.PrevEbp,ebp <br>
mov edi, pMapping <br>
assume edi:ptr IMAGE_DOS_HEADER <br>
.if [edi].e_magic==IMAGE_DOS_SIGNATURE <br>
add edi, [edi].e_lfanew <br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -