关于seh(2)
by sssa2000
马家爵被捕了,心中极度的痛苦呀。
Aaah说我中了毒,mydoom,我下了专杀工具,没发现,现在我变得异常警惕,连rundll32这个进程一看就关。
正题。
1、首先,怎么使用seh
昨天我们说的是c++中封装好的东西,现在我们接触的是赤裸裸的seh哦。
seh工作原理就是预先设置好处理异常的函数,然后如果有异常
首先,要使用seh必须先设置处理异常的回调函数。
怎么设置呢?很简单,3句就可以搞定:
把回调函数的地址入栈 push offset _handler
把fs:[0]入栈 push fs:[0]
把esp存入fs:[0] mov fs:[0],esp
为什么要这样呢?这就要说说tib了。
win32为每个线程定义一个线程信息块tib,这个结构中有一个
Exceptionlist的指针,它是seh的链入口。
这个指针指向一个EXCEPTION_REGISTRATION结构,定义如下:
EXCEPTION_REGISTRATION STRUCT
prev dd ? ;前一个EXCEPTION_REGISTRATION的地址
handler dd ? ;回调函数的地址
EXCEPTION_REGISTRATION ENDS
有了这个结构才能把很多seh联结成链状,注意,这里讲的是基本节构,很多其他资料上还有其他的什么附加数据,那都是自己加上去的,最基本的就这两个。
现在在来讲解前面的那三句
由于tib永远载fs:[0] 所以,fs[0]指向的就是Exceptionlist指向的东西,也就是EXCEPTION_REGISTRATION。
push fs:[0] 把fs:[0]入栈,这时候esp会指向压入的东西,为什么?先去复习一下汇编。 [esp]就是这个EXCEPTION_REGISTRATION的地址。
这个时候,[esp+0]就是prev字段 [esp+4]是回调函数的地址
mov fs:[0],esp
esp放入fs:[0]。我们知道 现在的fs:[0]就是prev,他还没有被附值。现在的esp里面放的就是prev需要的地址,我们要做的就是把prev=esp
好了,是不是觉得有点不好理解?
如果第一次接触,那就不妨死记下来
push offset _handler
push fs:[0]
mov fs:[0],esp
这3句话,只需要把回调函数的名字变一下就可以了,随着以后的学习,你就会熟悉的,别急别急。
看看罗云彬这段代码:
.386
.model flat,stdcall
option casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.const
szMsg db '异常发生位置:%08X,异常代码:%08X,标志:%08X',0
szSafe db '回到了安全的地方!',0
szCaption db 'SEH例子',0
.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 错误 Handler
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_Handler proc _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,addr szMsg, [edi].regEip,[esi].ExceptionCode,[esi].ExceptionFlags
invoke MessageBox,NULL,addr @szBuffer,NULL,MB_OK
;********************************************************************
; 将 EIP 指向安全的位置并恢复堆栈
;********************************************************************
mov eax,_lpSEH
push [eax + 8]
pop [edi].regEip
push [eax + 0ch]
pop [edi].regEbp
push eax
pop [edi].regEsp
assume esi:nothing,edi:nothing
popad
mov eax,ExceptionContinueExecution
ret
_Handler endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_Test proc
;********************************************************************
; 在堆栈中构造一个 EXCEPTION_REGISTRATION 结构
;********************************************************************
assume fs:nothing
push ebp
push offset _SafePlace
push offset _Handler
push fs:[0]
mov fs:[0],esp
;********************************************************************
; 会引发异常的指令
;********************************************************************
pushad
xor ebp,ebp
xor eax,eax
mov dword ptr [eax],0
popad ;这一句将无法被执行
_SafePlace:
invoke MessageBox,NULL,addr szSafe,addr szCaption,MB_OK
;********************************************************************
; 恢复原来的 SEH 链
;********************************************************************
pop fs:[0]
add esp,0ch
ret
_Test endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
invoke _Test
invoke ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
end start
这段代码我不解释,有一些我还要再下一讲说的,不懂得先记下,好好想一下,下一讲主要就讲一下关于seh的回调函数的问题
好了,现在离我们的目标进入ring0又进了一步,呵呵,虽说技术有点过时,对我们这些小菜还是很有用的,我也是在边学边写哦,cih进入ring0的代码我这几天随身携带,一有空就看,呵呵。 其实我一次写这么一点,是怕到时候我写不出来,延缓以下,呵呵呵。