首页
论坛
课程
招聘
[调试逆向] [软件保护] [原创]基于SEH的静态反调试(实例分析)
2021-5-2 23:22 1288

[调试逆向] [软件保护] [原创]基于SEH的静态反调试(实例分析)

2021-5-2 23:22
1288

基于SEH的静态反调试(实例分析)

程序在附件中,后续会更新基于SEH的动态反调和动静结合的反调
学知识ing

 

该实例是利用异常机制检查PEB的BeingDebugged(+0x2)从而实现反调试

一:运行和初步调试

先大致运行和调试一下

 

就是弹出一个窗口
图片描述

 

拖入x32dbg中进行调试

 

程序除了拖入之后在入口的断点处停下,再次F9的时候,会在如下地方停下,然后我们shift+F9,将程序发生的异常派发给程序自身处理
图片描述

 

之后就会弹出窗口
图片描述

 

可以发现这和我们之前正常运行时产生的代码不同(其实这是正常程序自己发生异常后,先调用了自生的SEH异常处理器处理的结果,在处理该异常的那个异常处理器中含有反调试代码,会造成程序有不同的结果)

二:分析汇编

使用PEview查看代码的入口点(是程序关键代码,不是EP)

 

图片描述

 

得到为0x401000(对于exe来说一般这个默认的基地址是对的)

 

然后我们将程序拖入,从代码入口处开始分析(OD颜色好看些,这里就用OD吧)

 

图片描述
首先这三行,是在安装SEH新的SEH异常处理器

1
2
3
00401000   68 5A104000   push static_s.0040105A    
00401005   64:FF35 00000>push dword ptr fs:[0]
0040100C   64:8925 00000>mov dword ptr fs:[0],esp

先压入这一个SEH异常处理器的地址,然后再压入原先程序SEH链的第一个SEH处理器的地址,最后将esp栈顶地址设置为新的SEH链的首地址

1
2
3
栈如下:
                (esp)原先seh首地址
                     0x0040105A

再往下

1
2
00401017   33C0          xor eax,eax
00401019   .  C700 01000000 mov dword ptr ds:[eax],0x1

这两行向地址0(非法地址)处写入1,触发了内存访问异常(0xC0000005)

 

再往下

1
2
3
4
5
00401023   6A 00         push 0x0                      ; /Style = MB_OK|MB_APPLMODAL
00401025   68 84924000   push static_s.00409284        ; |Title = "SYJ-Reverse"
0040102A   68 90924000   push static_s.00409290        ; |Text = "Debugger detected :("
0040102F   6A 00         push 0x0                      ; |hOwner = NULL
00401031   .  FF15 E8804000 call dword ptr ds:[<&USER32.MessageBoxA>]; \MessageBoxA

这里是调用那个调试时弹出的窗口的代码

1
00401037   . /EB 14         jmp Xstatic_s.0040104D

跳转到0x0040104D

1
2
3
4
5
00401039   6A 00         push 0x0                          ; /Style = MB_OK|MB_APPLMODAL
0040103B   68 84924000   push static_s.00409284            ; |Title = "SYJ-Reverse"
00401040   68 A5924000   push static_s.004092A5            ; |Text = "SEH_ANTI_DEBUG"
00401045   6A 00         push 0x0                          ; |hOwner = NULL
00401047   .  FF15 E8804000 call dword ptr ds:[<&USER32.MessageBoxA>] ; \MessageBoxA

这里是程序正常运行的时候调用的MessageBoxA弹出的窗口代码

1
2
3
0040104D   > \64:8F05 00000>pop dword ptr fs:[0]
00401054   83C4 04       add esp,0x4
00401057   .  C3            retn

前两行就是删除SEH链的第一个SEH异常处理器

 

弹出第一个异常处理器(_EXCEPTION_REGISTERATION_RECORD)结构体的第一个成员,即指向下一个SEH异常处理器的指针,然后add esp,0x4,删除了异常处理函数的地址

 

最后retn退出程序

1
2
3
4
5
6
7
8
9
0040105A  /8B7424 0C     mov esi,dword ptr ss:[esp+0xC]     ;  结构异常处理程序
0040105E  |.  64:A1 3000000>mov eax,dword ptr fs:[0x30]
00401064  |.  8078 02 01    cmp byte ptr ds:[eax+0x2],0x1
00401068  |.  75 0C         jnz Xstatic_s.00401076
0040106A  |.  C786 B8000000>mov dword ptr ds:[esi+0xB8],static_s.00401023
00401074  |.  EB 0A         jmp Xstatic_s.00401080
00401076  |>  C786 B8000000>mov dword ptr ds:[esi+0xB8],static_s.00401039
00401080  |>  33C0          xor eax,eax
00401082  \.  C3            retn

这里就是安装的那个SEH异常处理器的异常处理函数

 

mov esi,dword ptr ss:[esp+0xC] 将异常处理函数第三个参数:指向CONTEXT结构体的指针mov给esi

 

mov eax,dword ptr fs:[0x30] 将PEB地址给eax

 

cmp byte ptr ds:[eax+0x2],0x1 将PEB的偏移为0x2的BeingDebugged成员和1进行比较

 

(如果是1代表在调试,如果是0代表没调试)

 

下面就分别对应调试了和没调试的两种情况

 

[esi+0xB8]这个就是CONTEXT结构体偏移0xB8的成员,代表的EIP

 

执行完这个异常之后,会返回程序的这个地址处继续执行

 

汇编至此分析完毕(其实就是一个安装SEH中的检测PEB.BeingDebugged的反调试)

三:破解

将程序拖入,调试器会暂停在EP处,这里调试器暂停在EP处就是利用了int3(0xCC)

 

图片描述

 

然后再次F9,直达那个内存访问异常处(程序处于调试状态,会将异常先派发给调试器处理,调试器会先暂停在异常地址处)

 

图片描述

 

x32dbg和od都可以查看程序的SEH链

 

图片描述

 

这里找到第一个SEH异常处理器(我们在代码入口处安装的那个),地址为0x40105A

 

我们分析汇编代码之后,在这个cmp的地方下个断点
图片描述

 

让程序执行完 0040105E | 64:A1 30000000 | mov eax,dword ptr fs:[30]

 

之后我们将异常派发给程序之后,在断点处停下后,查看eax的值便可以得到PEB的地址

 

我们按shift+f9将异常派发给程序,然后就会停在第一个SEH异常处理函数我们下的断点处

 

查看eax的值

 

图片描述

 

0x240000

 

内存窗口中跳转到PEB然后修改BeingDebugged(+0x2)的值

 

图片描述
改为0即可

 

然后我们F9运行程序

 

就可以发现已经恢复到正常运行时弹出的窗口

 

图片描述


第五届安全开发者峰会(SDC 2021)议题征集正式开启!

最后于 2021-5-2 23:35 被SYJ-Re编辑 ,原因:
上传的附件:
收藏
点赞1
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回