SEH鏈和展開操作


每次我們定義了一個新的SEH異常處理回調函數,EXCEPTION_REGISTRATION結構的prev字段都被要求填寫上一個EXCEPTION_REGISTRATION結構的地址,隨著應用程序對模塊的調用一層層深入下去的時候,那么最后回調函數會形成一個SEH鏈

?

當程序中有多個線程在運行的時候,每個線程中都會存在各自的SEH鏈,這些SEH鏈中指定了多個回調函數,除他們以外,系統中可能還會存在一個全局性的篩選器,再者如果進程被調試,調試器進程也相當于一個異常處理的程序存在.那么當一個異常發生的時候,系統究竟該聽誰的呢?

?

在這種情況下,系統按一定的步驟選擇一個回調函數并執行他,如果這個回調函數可以執行這個異常,那么其他的回調函數都不會執行,否則系統執行下一個回調函數

(1).系統查看產生異常的進程是否正在被調試,如果正在被調試的話,那么向調試器發送EXCEPTION_DEBUG_EVENT事件

(2).如果進程沒有被調試或者調試器不去處理這個異常,那么系統 檢查異常所處的線程,并在這個線程環境中查看fs:[0]來確定是否安裝有SEH異常處理回調函數,如果有則調用它.

(3).回調函數嘗試處理這個異常,如果可以正確處理的話,則修正錯誤并將返回值設置為ExceptionContinueExecution,這時系統將結束整個查找過程

(4).如果回調函數返回ExceptionContinueSearch,告知系統他無法處理這個異常,那么系統將根據SEH鏈中的prev字段得到上一個回調函數地址,并重復步驟(3)過程,直到鏈中某個回調函數返回ExceptionContinueExecution為止,查找結束?

(5).如果到了SEH鏈的尾部,卻沒有一個回調函數愿意處理這個異常,那么系統將再次檢測進程是否正在被調試,如果被調試的話,則再次通知調試器

(6).如果調試器還是不去處理這個異常或者進程沒有被調試 ,那么系統檢查有沒有安裝篩選器回調函數,如果有,則去調用他,篩選器回調函數返回的時候,系統默認的異常處理程序根據這個返回值將做出相應的動作

(7).如果沒有安裝篩選器回調函數,系統直接 調用默認的異常處理程序終止進程

一個 比較形象的比喻就是:

Windows拿著一份異常處理的活挨個問每個回調函數
"你干不干" ,"不干","你呢","我也不干"... ... 當問到某一個的時候,
他說:"那我來干好了!"那么Windows就不會在去問其他人了,于是相安無事

有時,問完一圈后,誰都不愿意干(當然是干不了)Windows大怒:"誰都不干,看我炒了你們!"于是就把整個進程終止掉,所有的異常處理回調函數全部完蛋啦
(篩選器-全局的-進程的? SEH-線程的)

?完整的異常處理回調函數

<span style="font-family:Microsoft YaHei;font-size:13px;">_Handler1	proc	C _lpExceptionRecord,_lpSEH,_lpContext,_lpDispatcherContext;C調用方式-調用者自己平衡堆棧.if	(異常代碼 == 0c0000027h) || (異常標志 & EXCEPTION_UNWINDING) || (異常標志 & EXCEPTION_UNWINDING_FOR_EXIT);進行資源釋放等掃尾工作mov	eax,ExceptionContinueSearch.elseif 異常代碼 == 可以處理的異常代碼;處理異常,對CONTEXT進行修正;進行展開操作mov	eax,ExceptionContinueExecution.else;其他無法處理的異常代碼mov eax,ExceptionContinueSearch.endifret_Handler1	endp</span>


?

二.展開操作(Unwinding)

如果把第一個SEH處理的函數的返回值改成ExceptionContinueSearch這個時候函數將會進行循環查找

這個時候回調函數應該進行一些掃尾工作,因為其將被卸載

注冊 Unwinding操作可以使用RtlUnwinding函數

invoke RtlUnwinding,lpLastStackFrame,lpCodeLabel,lpExceptionRecord,dwRet

(1).lpLastStackFrame:這個參數設置為NULL,那么他將對所有的SEH鏈進行展開操作,這時所有的回調函數參數中的異常標志在帶有EXCEPTION_UNWINDING的同時也帶有EXCEPTION_UNWINDING_FOR_EXIT標志位,這種方式稱為展開退出

指定為當前回調函數的EXCEPTION_REGISTRATION結構的地址的話,表示對當前回調函數之后的所有其他回調函數進行展開操作,這樣RtlUnwinding函數調用的每一個回調函數時,異常標記位都會帶有EXCEPTION_UNWINDING標記位

(2).lpCodeLabel參數指明函數將要返回的位置,如果位NULL,那么RtlUnwinding函數將返回到其后面的一條指令,否則函數直接返回到lpCodeLabel指定的位置

(3).lpExceptionRecord指定一個EXCEPTION_RECORD結構,這個結構將在調用的時候傳給每一個回調函數

(4).dwRet參數一般不被使用,它可以指明為NULL

?

使用RtlUnwinding函數時要注意的是:這個函數并不像其他API函數一樣保存esi,edi和ebx寄存器的值,在函數返回時候這些寄存器的值可能會改變,所以如果程序用到這些寄存器的話,必須手動去保存和恢復他們

?

?

<span style="font-family:Microsoft YaHei;font-size:13px;">		.386.model flat,stdcalloption casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定義
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include		windows.inc
include		user32.inc
includelib	user32.lib
include		kernel32.inc
includelib	kernel32.libL macro var:VARARGLOCAL @lbl.const@lbl db var,0.codeexitm <offset @lbl>
endm
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 數據段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>.data
szMsg1		db	'這是外層異常處理程序(將處理異常)',0dh,0ahdb	'異常發生位置:%08X,異常代碼:%08X,標志:%08X',0
szMsg2		db	'這是內層異常處理程序(對異常不進行處理)',0dh,0ahdb	'異常發生位置:%08X,異常代碼:%08X,標志:%08X',0
szCaption	db	'提示信息',0
szBeforeUnwind	db	'現在將開始 Unwind,當前的 FS:[0] = %08X',0
szAfterUnwind	db	'Unwind 返回,當前的 FS:[0] = %08X',0
szSafe1		db	'回到了外層子程序的安全位置!',0
szSafe2		db	'回到了內層子程序的安全位置!',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代碼段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 外層錯誤 Handler,將處理異常
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_Handler1	proc	C _lpExceptionRecord,_lpSEH,_lpContext,_lpDispatcherContextlocal	@szBuffer[256]:bytepushadmov	esi,_lpExceptionRecordmov	edi,_lpContextassume	esi:ptr EXCEPTION_RECORD,edi:ptr CONTEXT,fs:nothinginvoke	wsprintf,addr @szBuffer,addr szMsg1,\[edi].regEip,[esi].ExceptionCode,[esi].ExceptionFlagsinvoke	MessageBox,NULL,addr @szBuffer,NULL,MB_OK
;********************************************************************
; 將 EIP 指向安全的位置并恢復堆棧
;********************************************************************mov	eax,_lpSEHpush	[eax + 8]pop	[edi].regEippush	_lpSEHpop	[edi].regEsp
;********************************************************************
; 對前面的 Handler 進行 Unwind 操作
;********************************************************************invoke	wsprintf,addr @szBuffer,addr szBeforeUnwind,dword ptr fs:[0]invoke	MessageBox,NULL,addr @szBuffer,addr szCaption,MB_OKinvoke	RtlUnwind,_lpSEH,NULL,NULL,NULLinvoke	wsprintf,addr @szBuffer,addr szAfterUnwind,dword ptr fs:[0]invoke	MessageBox,NULL,addr @szBuffer,addr szCaption,MB_OK
;********************************************************************assume	esi:nothing,edi:nothingpopadmov	eax,ExceptionContinueExecutionret_Handler1	endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 內層錯誤 Handler,不處理異常
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_Handler2	proc	C _lpExceptionRecord,_lpSEH,_lpContext,_lpDispatcherContextlocal	@szBuffer[256]:bytepushadmov	esi,_lpExceptionRecordmov	edi,_lpContextassume	esi:ptr EXCEPTION_RECORD,edi:ptr CONTEXTinvoke	wsprintf,addr @szBuffer,addr szMsg2,\[edi].regEip,[esi].ExceptionCode,[esi].ExceptionFlagsinvoke	MessageBox,NULL,addr @szBuffer,NULL,MB_OKassume	esi:nothing,edi:nothingpopadmov	eax,ExceptionContinueSearchret_Handler2	endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_Test2		procassume	fs:nothingpush	offset _SafePlacepush	offset _Handler2push	fs:[0]mov	fs:[0],esp
;********************************************************************
; 會引發異常的指令
;********************************************************************pushadxor	eax,eaxmov	dword ptr [eax],0popad		;這一句將無法被執行
_SafePlace:invoke	MessageBox,NULL,L("回到了內層子程序的安全位置!"),L("提示信息"),MB_OKpop	fs:[0]add	esp,8ret_Test2		endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_Test1		procassume	fs:nothingpush	offset _SafePlacepush	offset _Handler1push	fs:[0]mov	fs:[0],espinvoke	_Test2
_SafePlace:invoke	MessageBox,NULL,L("回到了外層子程序的安全位置!"),L("提示信息"),MB_OKpop	fs:[0]add	esp,8ret_Test1		endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:invoke	_Test1invoke	ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>end	start
</span>

?

?

?

?

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/375307.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/375307.shtml
英文地址,請注明出處:http://en.pswp.cn/news/375307.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

spring的基本知識

首先是回顧一下spring的基本知識 1、controller 控制器&#xff08;注入服務&#xff09; 2、service 服務&#xff08;注入dao&#xff09; 3、repository dao&#xff08;實現dao訪問&#xff09; 4、component &#xff08;把普通pojo實例化到spring容器中&#xff0c;相當于…

vs2010 EF4.0 訪問mysql

需要安裝mysql-connector-net-6.3.5 6.8.9的安裝完后在dbfirst里找不到對應的提供程序 鏈接字符串里需要 指定下編碼(如果不是gbk的話) <add name"sourceEntities" connectionString"metadatares://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;pr…

Win32ASM 變長參數的理解

C語言里面 提供了一些宏 可以使用變長參數 int MsgPrintf(INT dwszBuffer,TCHAR* szCaption,TCHAR* szFormat,...){LPVOID lpszBuffer;va_list pArgList;va_start(pArgList,szFormat);lpszBuffer HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,100);_vsntprintf((LPTSTR)lpsz…

jquery判斷一個div的邊界是否超出另外一個div的邊界

摘要&#xff1a;本文簡單介紹jquery判斷一個div的邊界是否超出另外一個div的邊界&#xff0c;如果超出邊界做出相應的處理。 1、實現效果 判斷前 判斷后 2、實現思路 實現類似的判斷&#xff0c;主要是獲取兩個div在瀏覽器中的上下左右的四至&#xff0c;在jquery中&#xff0…

Gson解析Json格式數據

//數據定義&#xff1a;class User{ String name; String password; String getName(){}void setName(){}}Gson gsonnew Gson(); ////解析一條json數據&#xff1a;令str為[{"name":"21001","password":"21001"}] User usernew User()…

進程的細節

從今天開始,重新學習一些細節性質的東西 一.在VS開發環境中,應用程序的入口點: _tWinMain WinMainCRTStartup _tWinMain wWinMainCRTStartup _tmain mainCRTStartup _tmain wmainCRTStartup 相關的介…

maven環境快速搭建(轉)

最近&#xff0c;開發中要用到maven&#xff0c;所以對maven進行了簡單的學習。因為有個maven高手在身邊&#xff0c;所以&#xff0c;很快就上手了&#xff0c;我這里算是自我總結吧。關于maven是什么東東&#xff0c;請參考其它文章。 ----------------準備工作-------------…

cocos2d-x3.0 相對布局(一)

2dx相對布局和Android非常類似。假設前完成Android它應該是easy入門。Size widgetSize Director::getInstance()->getWinSize();Text* alert Text::create("Layout", "fonts/Marker Felt.ttf", 30 );alert->setColor(Color3B(159, 168, 176));aler…

管理員以標準權限運行時

在XP時代,大多數用戶都用一個管理員(administrator)帳號來登錄Windows 利用這個賬戶,用戶幾乎能沒有任何限制的訪問重要的系統資源,因為該賬戶被授予了很高的權限,一旦用這個帳號登錄了xp以及xp之前的操作系統,Windows操作系統就會創建一個安全令牌(security token).每當有代碼…

HDU 4791 amp; ZOJ 3726 Alice#39;s Print Service (數學 打表)

題目鏈接&#xff1a; HDU:http://acm.hdu.edu.cn/showproblem.php?pid4791 ZJU:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId5072 Problem DescriptionAlice is providing print service, while the pricing doesnt seem to be reasonable, so people using…

奪命雷公狗---ECSHOP---08---商品頁的拇改成星星

<strong>用戶評價&#xff1a;</strong>{*---------商品評價星星開始----------*}<img src"./images/stars{$goods.comment_rank}.gif" alt"comment rank {$goods.comment_rank}">{*---------商品評價星星結束-------*} 這里主要是要有星…

文件指針

一.移動文件指針 SetFilePointer,hFile,lDistanceToMove,lpDistanceToMoveHigh,dwMoveMethod dwMoveMethod 指明移動的模式 FILE_BEGIN 不管文件處于什么地方,總是從文件的頭部開始移動,這時的位置參數相當于指定了一個絕對位置 FILE_CURRENT 從當前的文件指針處開始移…

見證下的自我變化-2014全年總結

又是一年總結季&#xff0c;回過頭看看看自己的成長&#xff0c;心里真的是滿滿的喜悅之情…… 一年前自己的總結博客&#xff1a;http://blog.csdn.net/huo065000/article/details/19632603 半年前自己的總結博客&#xff1a;http://blog.csdn.net/huo065000/article/details/…

【Linux學習篇】This virtual machine is configured for 64-bit guest operating systems.……

在學習Linux的基本操作的時候&#xff0c;安裝虛擬環境則提示自己 This virtualmachine is configured for 64-bit guest operatingsystems.……起初由于各種拒絕的心理&#xff0c;所以屏蔽了這個錯誤&#xff0c;但是屏蔽永遠也解決不了問題的&#xff0c;所以自己則嘗試百度…

圖解SSIS監視文件夾并自動導入數據

圖解SSIS監視文件夾并自動導入數據 原文:圖解SSIS監視文件夾并自動導入數據 演示案例&#xff1a;讓系統自動監視文件夾&#xff0c;并把文件夾下面的excel文件導入到sql中&#xff0c;之后清空目錄。這個過程以往都需要寫程序來實現或者定時執行&#xff0c;現在可以用ssis來訂…

DLL轉Lib

在C中,為了允許操作符重載和函數重載,C編譯器往往按照某種規則改寫每一個入口點的符號名,以便使用同一個名字(具有不同的參數類型或者是不同的作用域)有多種不同的用法,而不會打破現有基于C的鏈接器,.這項技術通常被稱為改編(Name Mangling)或者名稱修飾(Name Decoration),許多…

WP8手機解鎖時提示“請確保IPOVERUSBSVC服務正常運行”解決方法

如果你各種重啟服務 卸載手機 重裝驅動都試過了還不行&#xff0c;請看看你是否安裝了Hyper-v或Vitualbox虛擬機&#xff0c;很有可能是虛擬交換機造成的。 我在網絡連接屬性里看到這個 把它卸載后&#xff0c;解鎖成功。 解鎖后記得重新安裝卸載的那個網絡服務轉載于:https://…

Win32路徑操作相關API

一.路徑截斷與合并 PathRemoveArgs 去除路徑的參數 PathRemoveBackslash 去除路徑最后的反斜杠 "\" PathAddBackslash 在路徑最后加上反斜杠 "\" PathRemoveBlanks 去除路徑前后的空格 PathAddExtension 在文件路徑后面加上擴展名 PathRemoveExtension 去…

Openjudge-計算概論(A)-稱體重

描述&#xff1a; 趙、錢、孫、李四個人中既有大人也有小孩&#xff0c;給他們稱體重時發現&#xff0c;他們每個人的體重都不一樣&#xff0c;且體重&#xff08;單位&#xff1a;公斤&#xff09;恰好是10的整數倍&#xff0c;且他們的體重都不高 于50公斤&#xff0c;已知趙…

浮點數的存儲

-------------------------------------------------------------------------------- 在VC6.0----float環境一共32位 其中第一位是符號位 第二到第9位中間8位為小數點位置&#xff08;指數以127的二進制為原點向下為負指數 向上為正指數&#xff09;后面23位為數據位。 S EE…