Win32为每个线程定义了一个线程信息块,其中保存了线程的一些属性数据,线程信息块的属性被定义为NT_TIB结构
typedef struct _NT_TIB {
struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList;
PVOID StackBase;
PVOID StackLimit;
PVOID SubSystemTib;
union {
PVOID FiberData;
ULONG Version;
};
PVOID ArbitraryUserPointer;
struct _NT_TIB *Self;
} NT_TIB;
ExceptionList指向一个EXCEPTION_REGISTRATION结构-也就是SEH链的入口地址
EXCEPTION_REGISTRATION STRUCT
prev dd ? ;前一个EXCEPTION_REGISTRATION结构的地址
handler dd ? ;异常处理回调函数的地址
EXCEPTION_REGISTRATION ends
所以 一系列的EXCEPTION_REGISTRATION结构 就组成了一个SEH链...
TIB是放在fs段寄存器指向的数据段的0偏移处 所以 fs;[0]指向TIB结构的ExceptionList字段,由于同一个进程中 有不同的线程,所以不同线程中的fs段寄存器可以使用不同的值,这种特性使得每个线程都可以设置不同的回调函数
如果内存是从高到低构建...栈则也是从高到低构建....那么对于栈而言
push offset _Handler ;异常处理程序的回调函数地址
push fs:[0] ;上一个EXCEPTION_REGISTRATION结构的地址
mov fs:[0],esp ;设置当前EXCEPTION_REGISTRATION结构的地址
esp此时 正好指向你构建的EXCEPTION_REGISTRATION结构体
SEH异常处理回调函数的参数定义与筛选器器的回调函数的参数定义有所不同,其定义如下,其调用约定为C格式,
_Handler proc C _lpExceptionRecord,_lpSEH,_lpContext,_lpDispatcherContext
_lpExceptionRecord 指向EXCEPTION_RECORD结构(保存异常的相关信息)
_lpContext 指向一个Thread Context结构-保存线程上下文
_lpSEH 指向注册回调函数时EXCEPTION_REGISTRATION结构的首地址--利用这个字段可以用栈来传递一些自定义数据如SafeCode地址
回调函数的返回值:
ExceptionContinueExecution(等于0):回调函数返回后,系统将线程环境设置为_lpContext参数指定的CONTEXT结构并继续执行
ExceptionContinueSearch(等于1):回调函数拒绝处理这个异常,系统将通过 EXCEPTION_REGISTRATION结构的prev字段得到前一个回调函数的地址并调用他
ExceptionNestedException(等于2):回调函数执行过程中,又发生了新的异常,即触发了嵌套异常
ExceptionCollidedUnwind(等于3):发生了嵌套展开操作
代码:
.386
.model flat,stdcall
option casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
L macro var:VARARG
LOCAL @lbl
.const
@lbl db var,0
.code
exitm
endm
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;Code Segment
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;SEH Handler
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_Handler proc C _lpExceptionRecord,_lpSEH,_lpContext,_lpDispatcherContext
LOCAL @szBuffer[256]:BYTE
pushad
mov esi,_lpExceptionRecord
mov edi,_lpContext
assume esi:ptr EXCEPTION_RECORD,edi:ptr CONTEXT
invoke wsprintf,addr @szBuffer,L("异常位置:%08x,异常代码:%08x,异常标志:%08x"),[edi].regEip,[esi].ExceptionCode,[esi].ExceptionFlags
invoke MessageBox,NULL,addr @szBuffer,L("---"),MB_OK
mov eax,_lpSEH
push [eax + 8]
pop [edi].regEip
push [eax + 0ch]
pop [edi].regEsp ;这个是属于当前线程的-而不是当前的栈指针
assume esi:nothing,edi:nothing
popad
mov eax,ExceptionContinueExecution ;这个会先返回到内核里面去
ret
_Handler endp
start:
assume fs:nothing
push ebp ;添加的自定义数据
push offset _SafePlace ;添加的自定义数据......
push offset _Handler
push fs:[0]
mov fs:[0],esp
xor eax,eax
mov dword ptr [eax],0
_SafePlace:
invoke MessageBox,NULL,L("----"),L("----"),MB_OK
pop fs:[0]
add esp,0ch ;恢复栈平衡
invoke ExitProcess,NULL
end start