?? lion-petut-c02.htm
字號:
assume edi:ptr IMAGE_NT_HEADERS <br>
.if [edi].Signature==IMAGE_NT_SIGNATURE <br>
mov ValidPE, TRUE <br>
.else <br>
mov ValidPE, FALSE <br>
.endif <br>
.else <br>
mov ValidPE,FALSE <br>
.endif <br>
FinalExit: <br>
.if ValidPE==TRUE <br>
invoke MessageBox, 0, addr FileValidPE, addr AppName,
MB_OK+MB_ICONINFORMATION <br>
.else <br>
invoke MessageBox, 0, addr FileInValidPE, addr AppName,
MB_OK+MB_ICONINFORMATION <br>
.endif <br>
push seh.PrevLink <br>
pop fs:[0] <br>
invoke UnmapViewOfFile, pMapping <br>
.else <br>
invoke MessageBox, 0, addr FileMappingError, addr AppName,
MB_OK+MB_ICONERROR <br>
.endif <br>
invoke
CloseHandle,hMapping <br>
.else <br>
invoke
MessageBox, 0, addr FileOpenMappingError, addr AppName,
MB_OK+MB_ICONERROR <br>
.endif <br>
invoke CloseHandle, hFile <br>
.else <br>
invoke MessageBox, 0, addr
FileOpenError, addr AppName, MB_OK+MB_ICONERROR <br>
.endif <br>
.endif <br>
invoke ExitProcess, 0 <br>
start endp <br>
<br>
SEHHandler proc uses edx pExcept:DWORD, pFrame:DWORD,
pContext:DWORD, pDispatch:DWORD <br>
mov edx,pFrame <br>
assume edx:ptr SEH <br>
mov eax,pContext <br>
assume eax:ptr CONTEXT <br>
push [edx].SafeOffset <br>
pop [eax].regEip <br>
push [edx].PrevEsp <br>
pop [eax].regEsp <br>
push [edx].PrevEbp <br>
pop [eax].regEbp <br>
mov ValidPE, FALSE <br>
mov eax,ExceptionContinueExecution <br>
ret <br>
SEHHandler endp <br>
end start </font></p>
<h3>分析<font face="Arial, Helvetica, sans-serif">:</font></h3>
<p><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">PE header</font><font size="2">的有效性,</font><font
size="2" face="MS Sans Serif">ok</font><font size="2">就認為是有效的</font><font
size="2" face="MS Sans Serif">PE</font><font size="2">文件了。這里,我們還運用了結(jié)構(gòu)異常處理</font><font
size="2" face="MS Sans Serif">(SEH)</font><font size="2">,這樣就不必檢查每個可能的錯誤</font><font
size="2" face="MS Sans Serif">: </font><font size="2">如果有錯誤出現(xiàn),就認為</font><font
size="2" face="MS Sans Serif">PE</font><font size="2">檢測失效所致,于是給出我們的報錯信息。其實</font><font
size="2" face="MS Sans Serif">Windows</font><font size="2">內(nèi)部普遍使用</font><font
size="2" face="MS Sans Serif">SEH</font><font size="2">來檢驗參數(shù)傳遞的有效性。若對</font><font
size="2" face="MS Sans Serif">SEH</font><font size="2">感興趣的話,可閱讀</font><font
size="2" face="MS Sans Serif">Jeremy Gordon</font><font size="2">的</font><font
size="2" face="MS Sans Serif"> </font><a
href="Exceptionhandling.html"><font size="2">文章</font></a><font
size="2">。</font></p>
<p><font size="2">程序調(diào)用打開文件通用對話框,用戶選定執(zhí)行文件后,程序便打開文件并映射到內(nèi)存。并在有效性檢驗前建立一</font><font
size="2" face="MS Sans Serif"> SEH:</font></p>
<p><font face="Fixedsys"> 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 </font></p>
<p><font size="2">一開始就假設(shè)寄存器</font><font
size="2" face="MS Sans Serif"> fs</font><font size="2">為空(</font><font
size="2" face="MS Sans Serif">assume fs:nothing</font><font
size="2">)。</font><font size="2" face="MS Sans Serif"> </font><font
size="2">記住這一步不能省卻,因為</font><font
size="2" face="MS Sans Serif">MASM</font><font size="2">假設(shè)</font><font
size="2" face="MS Sans Serif">fs</font><font size="2">寄存器為</font><font
size="2" face="MS Sans Serif">ERROR</font><font size="2">。接下來保存</font><font
size="2" face="MS Sans Serif"> Windows</font><font size="2">使用的舊</font><font
size="2" face="MS Sans Serif">SEH</font><font size="2">處理函數(shù)地址到我們自己定義的結(jié)構(gòu)中,同時保存我們的</font><font
size="2" face="MS Sans Serif">SEH</font><font size="2">處理函數(shù)地址和異常處理時的執(zhí)行恢復地址,這樣一旦錯誤發(fā)生就能由異常處理函數(shù)安全地恢復執(zhí)行了。同時還保存當前</font><font
size="2" face="MS Sans Serif">esp</font><font size="2">及</font><font
size="2" face="MS Sans Serif">ebp</font><font size="2">的值,以便我們的</font><font
size="2" face="MS Sans Serif">SEH</font><font size="2">處理函數(shù)將堆棧恢復到正常狀態(tài)。</font></p>
<p><font face="Fixedsys"> mov edi, pMapping <br>
assume edi:ptr IMAGE_DOS_HEADER <br>
.if [edi].e_magic==IMAGE_DOS_SIGNATURE </font></p>
<p><font size="2">成功建立</font><font size="2"
face="MS Sans Serif">SEH</font><font size="2">后繼續(xù)校驗工作。置目標文件的首字節(jié)地址給</font><font
size="2" face="MS Sans Serif">edi</font><font size="2">,使其指向</font><font
size="2" face="MS Sans Serif">DOS header</font><font size="2">的首字節(jié)。為便于比較,我們告訴編譯器可以假定</font><font
size="2" face="MS Sans Serif">edi</font><font size="2">正指向</font><font
color="#CCFFCC" size="2" face="MS Sans Serif"><b>IMAGE_DOS_HEADER</b></font><font
size="2">結(jié)構(gòu)</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><font
size="2" face="MS Sans Serif">DOS header</font><font size="2">的首字是否等于字符串</font><font
size="2" face="MS Sans Serif">"MZ"</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_SIGNATURE</b></font><font
size="2">常量。若比較成功,繼續(xù)轉(zhuǎn)到</font><font
size="2" face="MS Sans Serif">PE header</font><font size="2">,否則設(shè)</font><font
color="#FFFFCC" size="2" face="MS Sans Serif"><b>ValidPE</b></font><font
size="2" face="MS Sans Serif"> </font><font size="2">值為</font><font
size="2" face="MS Sans Serif">FALSE</font><font size="2">,意味著文件不是有效</font><font
size="2" face="MS Sans Serif">PE</font><font size="2">文件。</font></p>
<p><font face="Fixedsys"> add
edi, [edi].e_lfanew <br>
assume edi:ptr
IMAGE_NT_HEADERS <br>
.if
[edi].Signature==IMAGE_NT_SIGNATURE <br>
mov
ValidPE, TRUE <br>
.else <br>
mov
ValidPE, FALSE <br>
.endif </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">DOS header</font><font size="2">中的</font><font
color="#FFFFCC" 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><font
size="2" face="MS Sans Serif">edi</font><font size="2">加上該值正好定位到</font><font
size="2" face="MS Sans Serif">PE header</font><font size="2">的首字節(jié)。這兒可能會出錯,如果文件不是</font><font
size="2" face="MS Sans Serif">PE</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">SEH</font><font size="2">,我們必須校驗</font><font
color="#FFFFCC" size="2" face="MS Sans Serif"><b>e_lfanew</b></font><font
size="2">值是否超出文件尺寸,這不是一個好辦法。如果一切</font><font
size="2" face="MS Sans Serif">OK</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">"PE"</font><font size="2">。這里在此用到了常量</font><font
color="#CCFFCC" size="2" face="MS Sans Serif"><b>IMAGE_NT_SIGNATURE</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"><br>
</font><font size="2">如果</font><font color="#FFFFCC" size="2"
face="MS Sans Serif"><b>e_lfanew</b></font><font size="2">的值不正確導致異常,我們的</font><font
size="2" face="MS Sans Serif">SEH</font><font size="2">處理函數(shù)就得到執(zhí)行控制權(quán),簡單恢復堆棧指針和基棧指針后,就根據(jù)</font><font
size="2" face="MS Sans Serif">safeoffset</font><font size="2">的值恢復執(zhí)行到</font><font
size="2" face="MS Sans Serif">FinalExit</font><font size="2">標簽處。</font></p>
<p><font face="Fixedsys">FinalExit: <br>
.if ValidPE==TRUE <br>
invoke MessageBox, 0, addr
FileValidPE, addr AppName, MB_OK+MB_ICONINFORMATION <br>
.else <br>
invoke MessageBox, 0, addr
FileInValidPE, addr AppName, MB_OK+MB_ICONINFORMATION <br>
.endif </font></p>
<p><font size="2">上述代碼簡單明確,根據(jù)</font><font
size="2" face="MS Sans Serif">ValidPE</font><font size="2">的值顯示相應(yīng)信息。</font></p>
<p><font face="Fixedsys"> push seh.PrevLink <br>
pop fs:[0] </font></p>
<p><font size="2">一旦</font><font size="2"
face="MS Sans Serif">SEH</font><font size="2">不再使用,必須從</font><font
size="2" face="MS Sans Serif">SEH</font><font size="2">鏈上斷開。</font></p>
<hr>
<p align="center"><font size="2"><b>翻譯:</b></font><font
size="2" face="MS Sans Serif"><b>iamgufeng [</b></font><a
href="http://win32asm.cjb.net/"><font size="2"
face="MS Sans Serif"><b>Iczelion's Win32 Assembly Homepage</b></font></a><font
size="2" face="MS Sans Serif"><b>]</b><strong>[</strong></font><a
href="http://asm.yeah.net"><font size="2" face="MS Sans Serif"><strong>LuoYunBin's
Win32 ASM Page</strong></font></a><font size="2"
face="MS Sans Serif"><strong>]</strong></font></p>
<p> </p>
</body>
</html>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -