找回密码
 开放注册

QQ登录

只需一步,快速开始

微信登录

微信扫码,快速开始

搜索
查看: 2718|回复: 4

SEH暗桩反高启发过无数杀软之SEH in ASM 研究

[复制链接]

321

主题

4191

回帖

6336

牛毛

二级牛人

你的加入是对黑狼最大的支持.

积分
6366
QQ
发表于 2009-1-2 21:49:15 | 显示全部楼层 来自 广东省惠州市
跟我找的贴子差不多,哈哈。

735

主题

1102

回帖

3076

牛毛

二级牛人

积分
3096
QQ
 楼主| 发表于 2009-1-3 11:45:59 | 显示全部楼层 来自 山东省威海市
- - !就是你找的帖子```

735

主题

1102

回帖

3076

牛毛

二级牛人

积分
3096
QQ
 楼主| 发表于 2009-1-2 20:22:43 | 显示全部楼层 |阅读模式 来自 山东省威海市
http://www.nb5.cn/read.php?tid=38566&page=e&#a
先看↑
SEHin ASM 研究(一)
By Hume/冷雨飘心

为什么老调重弹:
SEH出现已绝非一日,但很多人可能还不彻底了解Seh的运行机制;有关seh的知识资料不是很多,asm级的详细资料就
更少!seh不仅可以简化程序错误处理,使你的程序更加健壮,还被广泛应用于反跟踪以及加解密中,因此,了解seh非常必要,
但遗憾的是关于seh详细介绍的中文资料非常少,在实践的基础上,把自己学习的一点笔记奉献给大家,希望对喜欢ASM的朋
友有所帮助.如有错误,请高手不吝指正.

PARTI简单接触

一、SEH背景知识
SEH(\"Structured Exception Handling\"),即结构化异常处理.是操作系统提供给程序设计者的强有力的处理程序错
误或异常的武器.在VISUAL C++中你或许已经熟悉了_try{} _finally{} 和_try{} _except {} 结构,这些并不是
编译程序本身所固有的,本质上只不过是对windows内在提供的结构化异常处理的包装,不用这些高级语言编译器所提供
的包装 ,照样可以利用系统提供的强大seh处理功能,在后面你将可以看到,用系统本身提供seh结构和规则以及ASM语言,
我们将对SEH的机制以及实现有一个彻底的了解.

发生异常时系统的处理顺序(by Jeremy Gordon):

1.系统首先判断异常是否应发送给目标程序的异常处理例程,如果决定应该发送,并且目标程序正在被调试,则系统
挂起程序并向调试器发送EXCEPTION_DEBUG_EVENT消息.呵呵,这不是正好可以用来探测调试器的存在吗?

2.如果你的程序没有被调试或者调试器未能处理异常,系统就会继续查找你是否安装了线程相关的异常处理例程,如果
你安装了线程相关的异常处理例程,系统就把异常发送给你的程序seh处理例程,交由其处理.

3.每个线程相关的异常处理例程可以处理或者不处理这个异常,如果他不处理并且安装了多个线程相关的异常处理例程,
可交由链起来的其他例程处理.

4.如果这些例程均选择不处理异常,如果程序处于被调试状态,操作系统仍会再次挂起程序通知debugger.

5.如果程序未处于被调试状态或者debugger没有能够处理,并且你调用SetUnhandledExceptionFilter安装了最后异
常处理例程的话,系统转向对它的调用.

6.如果你没有安装最后异常处理例程或者他没有处理这个异常,系统会调用默认的系统处理程序,通常显示一个对话框,
你可以选择关闭或者最后将其附加到调试器上的调试按钮.如果没有调试器能被附加于其上或者调试器也处理不了,系统
就调用ExitProcess终结程序.

7.不过在终结之前,系统仍然对发生异常的线程异常处理句柄来一次展开,这是线程异常处理例程最后清理的机会.

如果你看了上面的步骤一头雾水的话,别着急,化点时间慢慢理解或者进入下一部分实例操作.

二.初步实战演习:

安装异常处理句柄.

有两种类型的异常处理句柄,一种是final型的,这是在你的异常未能得到线程相关处理例程处理操作系统在即将关闭程序之前会
回调的例程,这个例程是进程相关的而不是线程相关的,因此无论是哪个线程发生异常未能被处理,都会调用这个例程.
I. 见下面的例子1:
;//================================例子1---final型的异常处理=================
;// ex. 1,by Hume,2001,just copy make your own hd.h and compile&link
;//========================================================================
.386
.model flat, stdcall
option casemap :none; case sensitive
include hd.h;//相关的头文件,你自己维护一个吧
;//============================
.data
szCapdb \"By Hume[AfO],2001...\",0
szMsgOK db \"OK,the exceptoin was handled by final handler!\",0
szMsgERR1 db \"It would never Get here!\",0
buffdb 200 dup(0)

.code
_start:
;//========prog begin====================
leaeax,Final_Handler
invokeSetUnhandledExceptionFilter,eax;//调用SetUnhandledExceptionFilter来安装final SEH
;//原型很简单SetUnhandledExceptionFilter proto
;//pTopLevelExceptionFilter:DWORD
xorecx,ecx
moveax,200
cdq
divecx
;//以下永远不会被执行
invokeMessageBox,NULL,addr szMsgERR1,addr szCap,MB_OK+MB_ICONEXCLAMATION
invokeExitProcess,NULL


;//============================
Final_Handler:
invokeMessageBox,NULL,addr szMsgOK,addr szCap,MB_OK+MB_ICONEXCLAMATION
moveax,EXCEPTION_EXECUTE_HANDLER;//==1 这时不出现非法操作的讨厌对话框
;moveax,EXCEPTION_CONTINUE_SEARCH;//==0 出现,这时是调用系统默认的异常处理过程,程序被终结了
;moveax,EXCEPTION_CONTINUE_EXECUTION;//==-1 不断出现对话框,你将陷入死循环,可别怪我
ret;因为我们并没有修复ecx,所以不断产生异常,然后不断调用这个例程

;//=============================Prog Ends==============
end _start
COMMENT $
简单来解释几句,windows根据你的异常处理程序的返回值来决定如何进一步处理
EXCEPTION_EXECUTE_HANDLERequ 1表示我已经处理了异常,可以优雅地结束了
EXCEPTION_CONTINUE_SEARCHequ 0表示我不处理,其他人来吧,于是windows调用默认的处理程序
显示一个错误框,并结束
EXCEPTION_CONTINUE_EXECUTIONequ -1表示错误已经被修复,请从异常发生处继续执行
你可以试着让程序返回0和-1然后编译程序,就会理解我所有苍白无力的语言...
$

;//========================================================================

II.另一种是per_Thread Exception Handler->线程相关的异常处理,通常每个线程初始化准备好运行时fs指向一个TIB结构
(THREAD INFORMATION BLOCK),这个结构的第一个元素fs:[0]指向一个_EXCEPTION_REGISTRATION结构
后面_EXCEPTION_REGISTRATION为了简化,用ERR来代替这个结构...不要说没见过啊...
fs:[0]->
_EXCEPTION_REGISTRATION struc
prev dd ?;前一个_EXCEPTION_REGISTRATION结构
handler dd ?;异常处理例程入口....呵呵,现在明白该怎么作了吧
_EXCEPTION_REGISTRATION ends
我们可以建立一个ERR结构然后将fs:[0]换成指向他的指针,当然最常用的是堆栈,如果你用静态内存区也可以,没有人阻止你
在asm世界,放心地干吧,除了多S几次之外,通常不会有更大的损失
把handler域换成你的程序入口,就可以在发生异常时调用你的代码了,好马上实践一下,见例子2
;//========================================================================
;// ex. 2,by Hume,2001线程相关的异常处理
;//========================================================================
.386
.model flat, stdcall
option casemap :none; case sensitive
include hd.h;//相关的头文件,你自己维护一个吧
;//============================
.data
szCapdb \"By Hume[AfO],2001...\",0
szMsgOK db \"It's now in the Per_Thread handler!\",0
szMsgERR1 db \"It would never Get here!\",0
buffdb 200 dup(0)

.code
_start:
;//========prog begin====================
ASSUME FS:NOTHING
pushoffset perThread_Handler
pushfs:[0]
movfs:[0],esp;//建立SEH的基本ERR结构,如果不明白,就仔细研究一下吧
xorecx,ecx
moveax,200
cdq
divecx
;//以下永远不会被执行
invokeMessageBox,NULL,addr szMsgERR1,addr szCap,MB_OK+MB_ICONINFORMATION
popfs:[0]
addesp,4
invokeExitProcess,NULL

;//============================
perThread_Handler:
invokeMessageBox,NULL,addr szMsgOK,addr szCap,MB_OK+MB_ICONINFORMATION
moveax,1;//ExceptionContinueSearch,不处理,由其他例程或系统处理
;moveax,0;//ExceptionContinueExecution,表示已经修复CONTEXT,可从异常发生处继续执行
ret;//这里如果返回0,你会陷入死循环,不断跳出对话框....

;//=============================Prog Ends==============
end _start
COMMENT $
嘿嘿,这个简单吧,我们由于没有足够的资料,暂时还不能修复ecx的值使之从异常发生处继续执行,只是简单显示一个MSG,然后
让系统处理,自然跳出讨厌的对话框了....
注意和final返回值的含义不同...
$
;//==================================================================================================

好像到此为止,我们并没有从异常处理中得到任何好处,除了在异常发生后可以执行一点我们微不足道的代码,事实上SEH可以修复这些
异常或者干我们想干的事情然后从希望的地方继续执行,嘿嘿,很爽吧,可惜我们没有足够的信息,那里找到我们所需要的信息?
欲知后事如何,且看下回分解...



PARTII继续深入
....(待续,睡个觉先)

--------------------------------------------------------------------------------

标 题:SEH in ASM 研究(二) (6千字)
发信人:hume
时 间:2001-12-29 11:54:47
详细信息:


PART II 继续深入

三、传递给异常处理句柄的参数

要想明白seh处理例程如何得到感兴趣的信息,首先要明白SEH的作用机制.事实上,当异常
发生时,系统给了我们一个处理异常的机会,他首先会调用我们自定义的seh处理例程,当然也包括
了相关信息,在调用之前,系统把包含这些信息结构的指针压入stack,供我们的异常处理例程调用,
传递给例程的参数通常是四个,其中只有三个有明确意义,另一个到现在为止还没有发现有什么作用,
这些参数是:pExcept:DWORD,pErr:DWORD,pContext:DWORD,pDispatch意义如下:
pExcept:---EXCEPTION_RECORD结构的指针
pErr:---前面ERR结构的指针
pContext: --- CONTEXT结构的指针
pDispatch:---没有发现有啥意义

ERR结构是前面介绍的_EXCEPTION_REGISTRATION结构,往前翻翻,Dispatch省略,下面介绍
EXCEPTION_RECORD和CONTEXT结构的定义:

;//================================以下是两个成员的详细结构========================================

EXCEPTION_RECORD STRUCT
ExceptionCodeDWORD?;//异常码
ExceptionFlagsDWORD?;//异常标志
pExceptionRecordDWORD?;//指向另外一个EXCEPTION_RECORD的指针
ExceptionAddressDWORD?;//异常发生的地址
NumberParametersDWORD?;//下面ExceptionInformation所含有的dword数目
ExceptionInformationDWORD EXCEPTION_MAXIMUM_PARAMETERS dup(?)
EXCEPTION_RECORD ENDS;//EXCEPTION_MAXIMUM_PARAMETERS ==15

;//================================具体解释========================================

ExceptionCode 异常类型,SDK里面有很多类型,你可以在windows.inc里查找STATUS_来找到更多
的异常类型,下面只给出hex值,具体标识定义请查阅windows.inc,你最可能遇到的几种类型如下:

C0000005h----读写内存冲突
C0000094h----非法除0
C00000FDh----堆栈溢出或者说越界
80000001h----由Virtual Alloc建立起来的属性页冲突
C0000025h----不可持续异常,程序无法恢复执行,异常处理例程不应处理这个异常
C0000026h----在异常处理过程中系统使用的代码,如果系统从某个例程莫名奇妙的返回,则出现此代码,
如果RtlUnwind时没有Exception Record参数也同样会填入这个代码
80000003h----调试时因代码中int3中断
80000004h----处于被单步调试状态

注:也可以自己定义异常代码,遵循如下规则:
_____________________________________________________________________+

位:31~3029~2827~1615~0
_____________________________________________________________________+
含义:严重程度29位功能代码异常代码
0==成功0==McrosoftMICROSOFT定义用户定义
1==通知1==客户
2==警告28位
3==错误被保留必须为0
ExceptionFlags 异常标志
0----可修复异常
1----不可修复异常
2----正在展开,不要试图修复什么,需要的话,释放必要的资源
pExceptionRecord 如果程序本身导致异常,指向那个异常结构
ExceptionAddress 发生异常的eip地址
ExceptionInformation 附加消息,在调用RaiseException可指定或者在异常号为C0000005h即内存异常时含义如下
第一个dword 0==读冲突 1==写冲突
第二个dword 读写冲突地址
;//================================解释结束========================================
off.
CONTEXT STRUCT; _
ContextFlagsDWORD?;|+0
iDr0DWORD?;|+4
iDr1DWORD?;|+8
iDr2DWORD?;>调试寄存器+C
iDr3DWORD?;|+10
iDr6DWORD?;|+14
iDr7DWORD?; _|+18
FloatSaveFLOATING_SAVE_AREA <>;浮点寄存器区 +1C~~~88h
regGsDWORD?;--|+8C
regFsDWORD?;|\\段寄存器+90
regEsDWORD?;|/+94
regDsDWORD?;--|+98
regEdiDWORD?;____________+9C
regEsiDWORD?;|通用+A0
regEbxDWORD?;|寄+A4
regEdxDWORD?;|存+A8
regEcxDWORD?;|器+AC
regEaxDWORD?;_______|___组_+B0
regEbpDWORD?;++++++++++++++++ +B4
regEipDWORD?;|控制+B8
regCsDWORD?;|寄存+BC
regFlagDWORD?;|器组+C0
regEspDWORD?;|+C4
regSsDWORD?;++++++++++++++++ +C8
ExtendedRegisters db MAXIMUM_SUPPORTED_EXTENSION dup(?)
CONTEXT ENDS
;//================================以上是两个成员的详细结构========================================


I、传递给final句柄的参数,只有两个可描述为EXCEPTION_POINTERS结构,定义如下:
EXCEPTION_POINTERS STRUCT
pExceptionRecordDWORD?
ContextRecordDWORD?
EXCEPTION_POINTERS ENDS

在call xHandler之前,堆栈结构如下:
esp-> *EXCEPTION_RECORD
esp+4-> *CONTEXT record;//具体结构见下面

然后执行call _Final_Handler,这样在程序里要调用什么不轻而易举了吗?



II、 传递给per_thread句柄的参数,如下:
在call xHandler之前,在堆栈中形成如下结构
esp-> *EXCEPTION_RECORD
esp+4-> *ERR;//注意这也就是fs:[0]的指向
esp-> *CONTEXT record;//point to registers
esp-> *Param;//呵呵,没有啥意义

然后执行 call _Per_Thread_Handler

调用handler的原型是这样
invoke HANDLER,*EXCEPTION_RECORD,*_EXCEPTION_REGISTRATION,*CONTEXT record,*Param
即编译代码如下:
PUSH *Param;//通常不重要,没有什么意义
push *CONTEXT record;//上面的结构
push *ERR;//the struc above
push *EXCEPTION_RECORD;//see above
CALL HANDLER
ADD ESP,10h


好现在你明白了应该如何访问具体有关系统信息的细节了吧,下一部分,让我们来看看如何应用...(待续)

--------------------------------------------------------------------------------

标 题:一家之言,一种利用SEH技术脱壳的思路。 (699字)
发信人:idtemu
时 间:2001-12-29 17:30:24
详细信息:


利用Apihook到进程的入口,建立自己的SEH链表,在SEH的异常处理程序中建立Debuger功能,\\(也就是修改Context.Eflags的TF标志,然后单步异常时重新修改该标志\\),有了这个粗糙的Debuger,我们可以在让其在单步中断到SIDT指令时修改SIDT指令的结果,让其取的是自己建立的一个假的IDTR植,同时自己建立一个假的IDT表,这样程序修改的将是自己的假IDT表,如果程序想int 3或int 1来反跟踪的话,就会发生异常,我们又可以处理以下了。。。。,然后如果只是为了脱壳的话,就HOOK到某个API或则修改程序的某处代码为INT3,然后在异常处理程序中处理开始脱壳。特殊一点如果你想让利用修改IDT进入Ring0进行反跟踪的加壳的程序在NT下执行的话,也可以模拟一个它需要的环境给他吧:-)当然这中方法有一定的局限性.

SEH不仅仅是加壳者的宝刀,也是脱壳者的利箭。
--------------------------------------------------------------------------------
SEH IN ASM 研究(二)
---提高篇
By Hume[AfO]/冷雨飘心

part 4关于异常处理的嵌套和堆栈展开

在实际程序设计过程中,不可能只有一个异常处理例程,这就产生了异常处理程序嵌套的问题,可能很多
处理例程分别监视若干子程序并处理其中某种异常,另外一个监视所有子程序可能产生的共性异常,这作
起来实际很容易,也方便调试.你只要依次建立异常处理框架就可以了.
关于VC++异常处理可以嵌套很多人可能比较熟悉,用起来更容易不过实现比这里也就复杂得多,在VC++
中一个程序所有异常只指向一个相同的处理句例程,然后在这个处理例程里再实现对各个子异常处理例程的
调用,他的大致方法是建立一个子异常处理例程入口的数组表,然后根据指针来调用子处理例程,过程比较烦
琐,原来打算大致写一点,现在发现自己对C/C++了解实在太少,各位有兴趣还是自己
参考MSDN Matt Pietrek 1996年写的一篇文章<
ctured Exception Handling>>,里面有非常详细的说明,对于系统的实现细节也有所讨论,不过相信很多
人都没有兴趣.hmmm...:)实际上Kernel的异常处理过程和VC++的很相似.

有异常嵌套就涉及到异常展开的问题,也许你注意到了如果按照我前面的例子包括final都不处理异常的话,
最后系统在终结程序之前会来一次展开,在试验之后发现,展开不会调用final只是对per_thread例程展开
(right?).什么是堆栈展开?为什么要进行堆栈展开?如何进行堆栈展开?

我曾经为堆栈展开迷惑过,原因是各种资料的描述很不一致,Matt Pietrek说展开后前面的ERR结构被释放,
并且好像链后面如果决定处理必须展开,很多C/C++讲述异常处理的书也如斯说这使人很迷惑,我们再来看看Jeremy
Gordon的描述,堆栈展开是处理异常的例程自愿进行的.呵呵,究竟事实如何?

在迷惑好久之后我终于找到了答案:Matt Pietrek讲的没有错,那是VC++以及系统kernel的处理方法,Jeremy
Gordon说的也是正确的,那是我门asm Fans的自由!

好了现在来说堆栈展开,堆栈展开是异常处理例程在决定处理某个异常的时候给前面不处理这个异常的处理
例程的一个清洗的机会,前面拒绝处理这个异常的例程可以释放必要的句柄对象或者释放堆栈或者干点别的工作...
那完全是你的自由,叫stack unwind似乎有点牵强.堆栈展开有一个重要的标志就是
EXCEPTION_RECORD.ExceptionFlag为2,表示正在展开,你可以进行相应的处理工作,但实际上经常用的是6这是
因为还有一个UNWIND_EXIT什么的,具体含义我也没有搞明白,不过对我们的工作好像没有什么影响.

注意在自己的异常处理例程中,unwind不是自动的,必须你自己自觉地引发,如果所有例程都不处理系统最后的
展开是注定的,当然如果没有必要你也可以不展开.
win32提供了一个api RtlUnwind来引发展开,如果你想展开一下,就调用这个api吧,少候讲述自己代码如何展开

RtlUnwind调用描述如下:
PUSH Return value;返回值,一般不用
PUSH pExceptionRecord;指向EXCEPTION_RECORD的指针
PUSH OFFSET CodeLabel;展开后从哪里执行
PUSH LastStackFrame;展开到哪个处理例程终止返回,通常是处理异常的Err结构
CALL RtlUnwind
调用这个api之前要注意保护ebx,esi和edi,否则...嘿嘿

MASM格式如下:
invoke RtlUnwind,pFrame,OFFSET return_code_Address,pExceptionRecord,Return_value

这样在展开的时候,就以pExceptionRecord.flag=2 依次调用前面的异常处理例程,到决定异常的处理例程停止,
Jeremy Gordon手动展开代码和我下面的例子有所不同.他描述最后决定处理异常的ERR结构的prev成员为-1,好像
我的结果和他的有所差异,因此采用了另外的方法,具体看下面的例子.

最后一点要注意在嵌套异常处理程序的时候要注意保存寄存器,否则你经常会得到系统异常代码为C00000027h
的异常调用,然后就是被终结.

一下给出一点垃圾代码演示可能有助于理解,注意link的时候要加入 /section:.text,RWE 否则例子里面的
代码段不能写,SMC功能会产生异常以致整个程序不能进行.

注意:2K/XP下非法指令异常的代码不一致,另外用下面的方法SMC代码段也不可以!不知如何解决?
只用于9X,为了在2k/Xp下也能运行我加了点代码,有兴趣看看,另外帮我解决一下2K/Xp下SMC的问题?thx!

下面例子很烂,不过MASM格式写起来容易一点,也便于理解.
;-----------------------------------------
;Ex4,演示堆栈展开和异常嵌套处理 by Hume,2002
;humewen@21cn.com
;hume.longcity.net
;-----------------------------------------
.586
.model flat, stdcall
option casemap :none; case sensitive
include hd.h
include mac.h

;;--------------
per_xHandler1proto C :DWORD,:DWORD,:DWORD,:DWORD
per_xHandler2proto C :DWORD,:DWORD,:DWORD,:DWORD
per_xHandler3proto C :DWORD,:DWORD,:DWORD,:DWORD
;-----------------------------------------

.data
sztitdb \"except Mess,by hume[AfO]\",0
countdd 0,0
Expt1_frmdd 0;ERR结构指针,用于堆栈展开手动代码
Expt2_frmdd 0
Expt3_frmdd 0

;;-----------------------------------------
.CODE
_Start:
assumefs:nothing
pushoffset per_xHandler3
pushfs:[0]
movfs:[0],esp
movExpt3_frm,esp

pushoffset per_xHandler2
pushfs:[0]
movfs:[0],esp
movExpt2_frm,esp

pushoffset per_xHandler1
pushfs:[0]
movfs:[0],esp
movExpt1_frm,esp
;--------------------------
;install xhnadler
;-----------------------------------------

xorebx,ebx
moveax,200
cdq
divebx;除法错误

invokeMessageBox,0,ddd(\"Good,divide overflow was solved!\"),addr sztit,40h

subeax,eax
mov[eax],ebx;内存写错误

succ:
invokeMessageBox,0,ddd(\"Good,memory write violation solved!\"),addr sztit,40h

db0F0h,0Fh,0C7h,0C8h;什么cmpchg8b指令的非法形式?我从来没有成功过!!
;演示程序中使用seh实现SMC技术,加密??...
invokeMessageBox,0,ddd(\"illeagal instruction was solved!\"),addr sztit,20h
;--------------------------
;uninstall xhnadler
;-----------------------------------------

popfs:[0]
addesp,4
popfs:[0]
addesp,4
;或者add esp,10h

popfs:[0]
addesp,4

invokeExitProcess,0
;-----------------------------------------
;异常处理句柄1,处理除法异常错误
per_xHandler1 PROC C pExcept:DWORD,pFrame:DWORD,pContext:DWORD,pDispatch:DWORD
pushad
MOVESI,pExcept
ASSUMEESI:PTR EXCEPTION_RECORD
TEST[ESI].ExceptionFlags,1
JNZ@cantdo1
TEST[ESI].ExceptionFlags,6
JNZ@unwind1
CMP[ESI].ExceptionCode,0C0000094h
JNZ@cantdo1
MOVEDI,pContext

ASSUMEEDI:PTR CONTEXT
m2m[edi].regEbx,20;将ebx置20,修复除法错误,继续执行
popad
MOVEAX, ExceptionContinueExecution
RET

@unwind1:
invokeMessageBox,0,CTEXT(\"state: unwinding in xhandler1...\"),addr sztit,0
@cantdo1:
popad
MOVEAX,ExceptionContinueSearch
RET
per_xHandler1 ENDP
;-----------------------------------------
;异常处理句柄2,处理内存写错误,扩展可以有其他的例子如自动扩充堆栈
per_xHandler2 PROC C pExcept:DWORD,pFrame:DWORD,pContext:DWORD,pDispatch:DWORD

pushad
MOVESI,pExcept
ASSUMEESI:PTR EXCEPTION_RECORD
MOVEDI,pContext
ASSUMEEDI:PTR CONTEXT

callDispcont;显示一点lame的消息,自己调试用

TEST[ESI].ExceptionFlags,1
JNZ@cantdo2
TEST[ESI].ExceptionFlags,6
JNZ@unwind2
CMP[ESI].ExceptionCode,0C0000005h
JNZ@cantdo2
.data;ASM的数据定义灵活性,如果需要这是可以的
validAddress dd 0
.code

m2m[EDI].regEax,<offsetvalidAddress>;置eax为有效地址
popad
MOVEAX, ExceptionContinueExecution
RET

@unwind2:
invokeMessageBox,0,CTEXT(\"hmmm... unwinding in xhandler2...\"),addr sztit,40h
@cantdo2:
popad
MOVEAX,ExceptionContinueSearch
RET
per_xHandler2 ENDP
;-----------------------------------------

per_xHandler3 PROC C pExcept:DWORD,pFrame:DWORD,pContext:DWORD,pDispatch:DWORD
pushad
MOVESI,pExcept
ASSUMEESI:PTR EXCEPTION_RECORD
MOVEDI,pContext
ASSUMEEDI:PTR CONTEXT

TEST[ESI].ExceptionFlags,1
JNZ@cantdo3
TEST[ESI].ExceptionFlags,6
JNZ@unwind3
;-----------------------------------------

pushecx
movecx,cs
xorcl,cl
jecxzwin2k_Xp
win9X:
popecx
CMP[ESI].ExceptionCode,0C000001DH;非法指令异常,与2K/XP下的不一致
JNZ@cantdo3
jmpok_here
win2k_Xp:
popecx;注意,只有在9X下才可以
CMP[ESI].ExceptionCode,0C000001EH;非法指令异常->2K/XP
JNZ@cantdo3;sMc不成

mov[edi].regEip,offset safereturn
popad
moveax,0
ret



pushebx
pushesi
pushedi
comment $ 调用RtlUnwind展开堆栈
leaebx,unwindback
invokeRtlUnwind,Expt3_frm,ebx,esi,0
$
movdword ptr [esi+4],2;置展开标志,准备展开,这里是
;手动代码
movebx,fs:[0]


selfun:
;moveax,Expt2_frm;这里显示了ASM手动展开的灵活性
moveax,Expt3_frm
cmpebx,eax;按照Jeremy Gordon的好像不大对头
;cmpdword ptr [ebx],-1;这样好像有问题,只好如上,请教答案
jzunwindback
pushebx
pushesi; 压入Err和Exeption_registration结构
calldword ptr[ebx+4]
addesp,8
movebx,[ebx]
jmpselfun

unwindback:
invokeMessageBox,0,CTEXT(\"I am Back!\"),addr sztit,40h
popedi
popesi
popebx;一定要保存这三个寄存器!

MOVEAX,[EDI].regEip
MOVDWORD PTR[EAX],90909090H;改为nop指令...SMC呵呵这次不神秘了吧
;SMC注意连接选项
popad
MOVEAX, ExceptionContinueExecution
RET

@unwind3:
invokeMessageBox,0,CTEXT(\"Note... unwinding in xhandler3...\"),addr sztit,40h
@cantdo3:
popad
MOVEAX,ExceptionContinueSearch
RET
per_xHandler3 ENDP
;-----------------------------------------
;lame routine for debug
Dispcontproc
inccount
calldispMsg
ret
Dispcontendp

dispMsgproc
local szbuf[200]:byte
pushad
moveax,dword ptr[esi]
movebx,dword ptr[esi+4]
movecx,dword ptr[edi+0b8h]
movedx,dword ptr[edi+0a4h]
.data
fmtdb \"Context eip--> %8Xebx--> %8X \",0dh,0ah
db \"FlagsEx.c-> %8xflg--> %8X\",0dh,0ah
db \"it&#39;s the %d times xhandler was called!\",0
.code
invokewsprintf,addr szbuf,addr fmt,ecx,edx,eax,ebx,count
invokeMessageBox,0,addr szbuf,CTEXT(\"related Mess of context\"),0
popad
ret
dispMsgendp

;;------------------------------------------------
END_Start
;---------------------------------下面是上面用到的宏,我的mac.h比较长,就不贴了-----
dddMACRO Text;define data in .data section
local name;This and other can be used as: ddd(\"My god!\")
.data;isn&#39;t cool?
namedb Text,0
.code
EXITM <addr name>
ENDM

CTEXT MACRO y:VARARG;This is a good macro
LOCAL sym
CONST segment
IFIDNI <y>,<>
sym db 0
ELSE
sym db y,0
ENDIF
CONST ends
EXITM <OFFSET sym>
ENDM

m2m MACRO M1, M2;mov is too boring sometimes!
push M2
popM1
ENDM
;-----------------------------------------
最后更正一点前面介绍的传送给final型的参数是指向EXCEPTION_POINTERS 的指针,压栈前的堆栈
是如下的,不好意思,原来写的时候我也没深入研究,可能模糊了一点,如有错误,请大家指正
pushptEXCEPTION_POINTERS
callxHandler
下面补充一个final参数获得的一个例子
;--------------------------------------------
; Ex5,演示final处理句柄的参数获取,更正前面
; 模糊的介绍
;--------------------------------------------
.586
.model flat, stdcall
option casemap :none; case sensitive
include hd.h
include mac.h

;;--------------
.data
sztitdb \"exceptION MeSs,by hume[AfO]\",0
fmtdb \"Context eip--> %8Xebx--> %8X \",0dh,0ah
db \"FlagsEx.c-> %8xflg--> %8X\",0
szbufdb 200 dup(0)
;;-----------------------------------------
.CODE
_Start:
assumefs:nothing
pushoffset _final_xHandler0
callSetUnhandledExceptionFilter
xorebx,ebx
moveax,200
cdq
divebx
invokeMessageBox,0,ddd(\"Good,divide overflow was solved!\"),addr sztit,40h
xoreax,eax
mov[eax],ebx

invokeExitProcess,0

;-----------------------------------------
_final_xHandler0:
pushebp
movebp,esp

moveax,[ebp+8];the pointer to EXCEPTION_POINTERS
movesi,[eax];pointer to _EXCEPTION_RECORD
movedi,[eax+4];pointer to _CONTEXT
testdword ptr[esi+4],1
jnz@_final_cnotdo
testdword ptr[esi+4],6
jnz@_final_unwind

;calldispMsg


cmpdword ptr[esi],0c0000094h
jnz@_final_cnotdo

movdword ptr [edi+0a4h],10
calldispMsg

moveax,EXCEPTION_CONTINUE_EXECUTION;GO ON
jmp@f

@_final_unwind:
invokeMessageBox,0,CTEXT(\"state:In final unwind...\"),addr sztit,0
;好像不论处理不处理异常,系统展开的时候
;都不会被调用,right?
@_final_cnotdo:;请教是真的吗?还是我写的有问题
moveax,EXCEPTION_CONTINUE_SEARCH
jmp@f
@@:
movesp,ebp
popebp
ret
;-----------------------------------------
dispMsgproc
pushad
moveax,[esi]
movebx,[esi+4]
movecx,[edi+0b8h]
movedx,[edi+0a4h]
invokewsprintf,addr szbuf,addr fmt,ecx,edx,eax,ebx
invokeMessageBox,0,addr szbuf,CTEXT(\"related Mess of context\"),0
popad
ret
dispMsgendp
;;------------------------------------------------

END_Start
;====================================================================================

BTW:够长了吧,基本内容介绍完毕,更多内容下一部分介绍一点利用Seh的tricks,哪位大侠有什么好的想法
或者有什么错误,请不吝指正,毕竟我是菜鸟吗...

=====================================================================================
一点闲话:请CUT--------------------------
最近很郁闷,生活上的工作上的,就这样懒懒懒散散地目无光彩地苟活于世,最近看了一点C++,有的地方
头大,于是拿起老家伙asm写了点以前许诺过的东西,感觉还是ASM最有助于理解基本原理~~~不过C/C++给了我
们另外的工具,虽然目标代码不够紧凑(理想状态),毕竟不需要我们每个人写内核,C/C++可以提高生产能力.
crack也一样,如果一些基本概念都不懂明白还谈什么crack?昨天看精华III一些高手的文章,真是惭愧啊!

我的专业不是计算机或者以后永远也不会搞计算机,这些当也许只是业余爱好,永远不会放弃的业余爱好.
以后也许很长一段时间里面我会离开大家,毕竟,面临的还有生活.
感谢CCG,BCG的各位高手,AfO的成员们,以及那些曾无私指导过以及给我生活动力的朋友们!
我要奋斗!
我以此激励自己也同样希望能够激励大家!
2002.1.28深夜~~沉思中
----------------------------------------cut------------------------------------
--------------------------------------------------------------------------------

33

主题

37

回帖

145

牛毛

一级牛人

连衣裙www.woitao.net

积分
145
发表于 2011-4-21 23:15:24 | 显示全部楼层 来自 广东省佛山市三水区
55***55,不是很明白。

8

主题

314

回帖

485

牛毛

一级牛人

积分
485
QQ
发表于 2011-4-22 19:52:18 | 显示全部楼层 来自 广东省汕尾市
哇塞  太强大了。。。。。。。。。。。。。。。。
您需要登录后才可以回帖 登录 | 开放注册

本版积分规则

帮助|Archiver|小黑屋|通信管理局专项备案号:[2008]238号|NB5社区 ( 皖ICP备08004151号;皖公网安备34010402700514号 )

GMT+8, 2025-4-25 13:27 , Processed in 0.183094 second(s), 52 queries .

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表