如何用OllyDBG跟踪EXECryptor v1.53?
举例:
EXECryptor v1.53是目前利用SEH反跟踪最完美的一个壳,在SEH处理中对DR0-DR7等调试寄存器进行清零并修改EIP寄存器来实现跳转。如果对SEH缺乏完全的了解,跟踪起来简直是一头雾水。
一、SEH复习
1、建立SEH的框架
ASSUME FS:NOTHING ;否则Masm编译报错
push offset SEH_Handler
push fs:[0]
mov fs:[0],esp
2、传递给异常处理例程的参数
传递给final型的参数,只有一个即指向EXCEPTION_POINTERS结构的指针, EXCEPTION_POINTERS定义如下:
EXCEPTION_POINTERS STRUCT
pExceptionRecord DWORD ?
ContextRecord DWORD ?
EXCEPTION_POINTERS ENDS
执行时堆栈结构如下:
esp -> ptEXCEPTION_POINTERS
然后执行call _Final_Handler
注意堆栈中的参数是指向EXCEPTION_POINTERS 的指针,而不是指向pExceptionRecord的指针
以下是EXCEPTION_POINTERS两个成员的详细结构
EXCEPTION_RECORD STRUCT
ExceptionCode DWORD ? ;异常码
ExceptionFlags DWORD ? ;异常标志
PExceptionRecord DWORD ? ;指向另外一个EXCEPTION_RECORD的指针
ExceptionAddress DWORD ? ;异常发生的地址
NumberParameters DWORD ? ;下面ExceptionInformation所含有的dword数目
ExceptionInformation DWORD EXCEPTION_MAXIMUM_PARAMETERS dup(?)
EXCEPTION_RECORD ENDS
;EXCEPTION_MAXIMUM_PARAMETERS ==15
具体参数解释:
ExceptionCode 异常类型,SDK里面有很多类型,但你最可能遇到的几种类型如下:
C0000005h----读写内存冲突
C0000094h----非法除0
C00000FDh----堆栈溢出或者说越界
80000001h----由Virtual Alloc建立起来的属性页冲突
C0000025h----不可持续异常,程序无法恢复执行,异常处理例程不应处理这个异常
C0000026h----在异常处理过程中系统使用的代码,如果系统从某个例程莫名奇妙的返回,则出现此代码,例如调用RtlUnwind时没有Exception Record参数时产生的异常填入的就是这个代码
80000003h----调试时因代码中int3中断
80000004h----处于被单步调试状态
注:也可以自己定义异常代码,遵循如下规则:
位: 31~30 29~28 27~16 15~0
含义: 严重程度 29位 功能代码 异常代码
0==成功 0==Mcrosoft MICROSOFT定义 用户定义
1==通知 1==客户
2==警告 28位
3==错误 被保留必须为0
ExceptionFlags 异常标志
0----可修复异常
1----不可修复异常
2----正在展开,不要试图修复什么,需要的话,释放必要的资源
pExceptionRecord 如果程序本身导致异常,指向那个异常结构
ExceptionAddress 发生异常的eip地址
ExceptionInformation 附加消息,在调用RaiseException可指定或者在异常号为C0000005h即内存异常时(ExceptionCode=C0000005h) 的含义如下,其他情况下一般没有意义
第一个dword 0==读冲突 1==写冲突
第二个dword 读写冲突地址
CONTEXT具体结构含义:
CONTEXT STRUCT ; _
ContextFlags DWORD ? ; |--------------- +00
iDr0 DWORD ? ; | +04
iDr1 DWORD ? ; | +08
iDr2 DWORD ? ; >调试寄存器 +0C
iDr3 DWORD ? ; | +10
iDr6 DWORD ? ; | +14
iDr7 DWORD ? ; _| +18
FloatSave FLOATING_SAVE_AREA <> ;浮点寄存器区 +1C~~+88
regGs DWORD ? ;--| +8C
regFs DWORD ? ; |段寄存器 +90
regEs DWORD ? ; |/ +94
regDs DWORD ? ;--| +98
regEdi DWORD ? ;____________ +9C
regEsi DWORD ? ; | 通用 +A0
regEbx DWORD ? ; | 寄 +A4
regEdx DWORD ? ; | 存 +A8
regEcx DWORD ? ; | 器 +AC
regEax DWORD ? ;_______|___组_ +B0
regEbp DWORD ? ;++++++++++++++++ +B4
regEip DWORD ? ; |控制 +B8
regCs DWORD ? ; |寄存 +BC
regFlag DWORD ? ; |器组 +C0
regEsp DWORD ? ; | +C4
regSs DWORD ? ;+++++++++++++++++ +C8
ExtendedRegisters db MAXIMUM_SUPPORTED_EXTENSION dup(?)
CONTEXT ENDS
二、EXECryptor v1.53跟踪要点
1、密切注意建立SEH框架结构,并随时在命令窗口用D fs:[0]察看,其中fs:[4]就是SEH_handler.然后到该地址按F2设断点。
2、进入SEH处理后,注意修改EIP寄存器指令。EXECryptor v1.53典型修改指令为mov [ECX+B8],XXXXXX或add [ecx+b8],0b等。并在所修改的EIP处设断点(按F2)
3、跟到Lock cmpxchg8b eax(非法指令)时,修改指令为int3(0CC),这是全程跟踪的关键点,直到没有执行到该地址指令后要恢复原来的值。这段代码主要是搜索kernel32.dll得到函数入口地址,这部分函数为:getmodulehandle;getprocaddress;loadlibrarya;freelibrary等。
4、防止进入单步SEH陷阱。
5、EXECryptor v1.53典型SEH结构分析
00401000 >call EXECrypt.00401029
00401005 mov ecx,dword ptr ss:[esp+C] //ContextRecord地址
00401009 mov dword ptr ds:[ecx],10017
0040100F mov dword ptr ds:[ecx+B8],EXECrypt.004FC000 //改变EIP为4FC000
00401019 xor eax,eax
0040101B mov dword ptr ds:[ecx+14],eax //Dr6=0
0040101E mov dword ptr ds:[ecx+18],eax //Dr7=0
00401021 and byte ptr ds:[ecx+C1],0FE //修改标志寄存器的T位。
00401028 retn
00401029 xor eax,eax
0040102B push dword ptr fs:[eax]
0040102E mov dword ptr fs:[eax],esp //建立SEH框架
00401031 int3 //异常转移到00401005
00401032 retn
00401000 >call EXECrypt.00401029
00401005 mov ecx,dword ptr ss:[esp+C] //ContextRecord地址
00401009 mov dword ptr ds:[ecx],10017
0040100F mov dword ptr ds:[ecx+B8],EXECrypt.004FC000 //改变EIP为4FC000
00401019 xor eax,eax
0040101B mov dword ptr ds:[ecx+14],eax //Dr6=0
0040101E mov dword ptr ds:[ecx+18],eax //Dr7=0
00401021 and byte ptr ds:[ecx+C1],0FE //修改标志寄存器的T位。
00401028 retn
00401029 xor eax,eax
0040102B push dword ptr fs:[eax]
0040102E mov dword ptr fs:[eax],esp //建立SEH框架
00401031 int3 //异常转移到00401005
00401032 retn
在00401005处F2设断点,f9运行,断下后察看堆栈,就知道了。
EXCEPTION_POINTERS STRUCT
pExceptionRecord DWORD ?
ContextRecord DWORD ?
EXCEPTION_POINTERS ENDS