吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3267|回复: 13
收起左侧

[原创] 脱壳之反硬件调试壳

  [复制链接]
Nattevak 发表于 2021-12-24 21:26
本帖最后由 Nattevak 于 2021-12-24 21:53 编辑

清除硬件断点的方法有哪些?
修改调试寄存器,CONTEXT结构体
1. API
Kernel32.SetThreadContext
ntdll.ZwSetContextThread
2.异常
异常回调中可以修改CONTEXT

1.对API下断点,测试是否会断下
应该是存在判断敏感API的机器码,检测第一个字节是否是0xCC,故此处导致程序崩溃了,破解方法就是在第二行反汇编下断点。

1.1

1.1


尝试在下一行重新下断点,结果程序直接运行了?并没有断下。

1.2

1.2


再次尝试在API对应的底层函数调用的位置下断点

1.3

1.3

1.4

1.4


结果发现程序还是运行起来了,并没有断下,所以应该不是API,而是异常

2.搭建异常触发环境
首先我们需要对OD进行一些配置,在菜单中找到调试选项,将一些异常取消忽略,按照以下配置。

2.1

2.1


除了OD调试选项的配置之外,一些反反调试插件也需要做些配置,这里我们使用的是StrongOD插件,在插件中找到StrongOD,取消插件对一些异常的跳过。按照以下配置对插件进行设置。

2.2

2.2


程序运行起来,发现一共有7个异常,需要排查出对硬件断点清0的地方,这里采用在异常点设置硬件断点的方法,尝试看能不能断下来,如果能断下来说明当前异常点前面的异常处理函数中没有对硬件断点清0。

第一个异常:

2.3

2.3


第二个异常:

2.4

2.4


第三个异常:

2.5

2.5


第四个异常:

2.6

2.6


第五个异常:

2.7

2.7


第六个异常:

2.8

2.8


第七个异常:

2.9

2.9


按照上面的思路,首先在第二个异常点设置硬件执行断点,然后动态调试程序,如果硬件执行断点有效(在状态栏中可以发现硬件断点命中的提示信息)说明第一个异常点的异常回调函数中没有清除硬件断点的代码。

硬件执行断点的特点是到了这个地址就会停下来,而异常是必须触发,即必须执行了这段代码,执行了这条指令才能够触发,如果先触发了硬件断点,就意味着这个异常前面的异常处理函数是没有清除硬件断点的,

按照这样的方式,依次测试每一个异常的回调函数。
第二个异常:
这条指令还没有执行之前就已经触发了硬件断点,说明第一个函数内没有清除硬件断点

2.10

2.10


清除第二个异常处的硬件断点,依次向下一个异常继续下硬件执行断点

第三个异常

2.11

2.11


这条指令还没有执行之前就已经触发了硬件断点,说明第二个函数内没有清除硬件断点

2.12

2.12


第四个异常
这条指令直接触发了异常,说明第三个函数内有清除硬件断点的代码

2.13

2.13


综上所述,发现第三个异常,即第一个STI特权指令异常回调是清除硬件断点的代码。
打开SEH链观察

2.14

2.14


在0043AF42的位置下断点

2.15

2.15


继续shift+F9进入第三个异常处理函数

2.16

2.16


上面代码由于是和异常、清除硬件断点有关的,所以其中肯定有异常相关的结构体和寄存器相关的Context结构,直接分析代码不太容易看出来,这个时候我们就可以将其直接在这个地方进行DUMP,这里DUMP不是为了脱壳,只是单纯的DUMP,然后方便在IDA中查看其中的代码,使用IDA特有的解析结构体的功能,解析可能存在的结构体。

2.17

2.17


进入IDA,我直接一手F5......

2.18

2.18


在结构体中Inser添加一个Context结构

2.19

2.19


在伪代码中转换结构体

2.20

2.20

2.21

2.21

2.22

2.22


继续回到OD,分析这段代码应该就是清除硬件断点的代码

2.23

2.23


初步思路:在0043AF59的位置设置一个断点,到了这个断点之后将清除硬件断点的这段代码清除一下,将其NOP掉,后面的硬件断点就能正常的触发了

将之前更改的设置还原,把异常重新跳过

在OEP和清除硬件断点的位置下硬件断点,然后重新运行程序

2.24

2.24


当程序运行至清除硬件断点的位置时将其NOP掉

2.25

2.25


再运行就发现硬件断点正常的触发了

2.26

2.26


继续向下分析,发现IAT加密了

2.27

2.27


所以就需要解密IAT,照常设置硬件写入断点

2.28

2.28


重新运行程序,NOP清除硬件断点的位置,然后程序断在此处,一翻完全看不清代码啊

2.29

2.29


点击EIP回到原来的位置,按Ctrl+↑(微调反汇编引擎,向上一个字节),找到正确的代码,这里看起来不是填充IAT的位置

2.30

2.30


继续运行,仍然看不出来,继续按Ctrl+↑,找到正确的代码,这里看起来应该就是填充IAT的位置

2.31

2.31


填充IAT的循环
[Asm] 纯文本查看 复制代码
① 循环读取API字符串,判断第一个字节是否指定字符
00438F44      8>MOV EDI,DWORD PTR DS:[EBX]
00438F46      0>ADD EDI,DWORD PTR SS:[EBP+0x40421E]     ; kernel32.75E20000
00438F4C      8>CMP BYTE PTR DS:[EDI],0x48
00438F4F      7>JNZ SHORT 06.00438FA1
                
00438FA1      8>ADD EBX,0x4
00438FA4      4>INC ECX
00438FA5      8>CMP ECX,0x54F
00438FAB    ^ 7>JNZ SHORT 06.00438F44

② 循环读取API字符串中的字符,求HASH
0043A70E      8>MOV AL,BYTE PTR DS:[EDI]
0043A710      0>OR AL,AL
0043A712      7>JE SHORT 06.0043A746  ;退出循环
0043A725      4>INC EDI                                 ; kernel32.75EDBBDF
0043A726      3>XOR DL,AL
0043A728      B>MOV AL,0x8
0043A72A      E>JMP SHORT 06.0043A72D
0043A736      D>SHR EDX,1
0043A738      7>JNB SHORT 06.0043A740
0043A73A      8>XOR EDX,0xEDB88320
0043A740      F>DEC AL
0043A742    ^ 7>JNZ SHORT 06.0043A72A

③ 判断hash值是否与当前一致,不一致继续循环,一致进行下一步
00438F7A      3>CMP EAX,0xA124E28D
00438F7F      7>JNZ SHORT 06.00438FA1
00438F81      8>MOV EAX,DWORD PTR SS:[EBP+0x40421A]     ; 已经寻找到正确的hash


④ 根据hash值,寻找API偏移,求出API地址
00438F81      8>MOV EAX,DWORD PTR SS:[EBP+0x40421A]     ; kernel32.75ED7848
00438F87      D>SHL ECX,1
00438F89      0>ADD EAX,ECX
00438F8B      0>MOVZX EAX,WORD PTR DS:[EAX]
00438F8E      C>SHL EAX,0x2
00438F91      0>ADD EAX,DWORD PTR SS:[EBP+0x404226]     ; kernel32.75ED4DD0
00438F97      8>MOV EAX,DWORD PTR DS:[EAX]
00438F99      0>ADD EAX,DWORD PTR SS:[EBP+0x40421E]     ; 计算完之后,EAX是API地址

特殊情况,需要特殊处理一下

⑤ 读取API中的代码,生成加密API代码
代码特别长,只复制了一部分
00439333      AC             LODS BYTE PTR DS:[ESI]
00439334      8AF8           MOV BH,AL
00439336      8A27           MOV AH,BYTE PTR DS:[EDI]
00439338      47             INC EDI
00439339      C0EC 04        SHR AH,0x4
0043933C      2AC4           SUB AL,AH
0043933E    ^ 73 F6          JNB SHORT 06.00439336

⑥ 填充IAT

再接着在写入IAT附件寻找获取API的位置
可以使用RUN跟踪的方法,设置EIP == 0043918C 即可(只需要翻一万两千七百多行就可以找到了)
获取API地址(通过RUN跟踪找到)
[Asm] 纯文本查看 复制代码
00438F91                        0385 26>ADD EAX,DWORD PTR SS:[EBP+0x404226]                        ; kernel32.75ED4DD0
00438F97                        8B00    MOV EAX,DWORD PTR DS:[EAX]
00438F99                        0385 1E>ADD EAX,DWORD PTR SS:[EBP+0x40421E]                        ; kernel32.75E20000
00438F9F                        EB 10   JMP SHORT 06.00438FB1   ; eax=API地址

004399A1                        8D8428 >LEA EAX,DWORD PTR DS:[EAX+EBP+0x404D09]
004399A8                        894424 >MOV DWORD PTR SS:[ESP+0x8],EAX                             ; 06.004399B7
004399AC                        5A      POP EDX                                                    ; 06.004292E5
004399AD                        58      POP EAX                                                    ; 06.004292E5
004399AE                        8D6424 >LEA ESP,DWORD PTR SS:[ESP+0x4]  ; eax=API地址

004399D7                        8D8428 >LEA EAX,DWORD PTR DS:[EAX+EBP+0x404D4B]
004399DE                        894424 >MOV DWORD PTR SS:[ESP+0x8],EAX                             ; 06.004399F9
004399E2                        5A      POP EDX                                                    ; 06.004292E5
004399E3                        58      POP EAX                                                    ; 06.004292E5
004399E4                        EB 07   JMP SHORT 06.004399ED  ; eax=API地址

继续单步跟踪分析

2.32

2.32


继续跟踪发现将EAX进行比较,说明在判断hash,不相等的时候会跳转,所以直接在00438F81的位置下断点,让程序运行至此

2.33

2.33


继续跟踪,发现到这个位置后EAX中就变成API地址了

2.34

2.34


后来发现在这个位置填充IAT的话会有问题,这里就要提到导入表中的特殊API
有些API 在Kernel32导出,实际代码却在ntdll
比如:Kernel32.HeapAlloc,实际代码是在ntdll.RtlAllocateHeap
这种情况下从kernel32中获取HeapAlloc函数的地址,地址里面保存的是函数字符串,NTDLL.RtlAllocateHeap

遇到这种情况,需要特殊处理
①先判断地址处是不是NTDLL打头,是的话就需要二次获取API地址
②解析字符串,获取模块名以及API地址
NTDLL
RtlAllocateHeap
③加载模块获取模块地址,获取API地址
00438FE2      57             PUSH EDI                                ; 06.00438000
00438FE3      FF95 70584000  CALL DWORD PTR SS:[EBP+0x405870]        ; kernel32.LoadLibraryA
00438FE9      50             PUSH EAX                                ; 06.00428C00
00438FEA      FF95 75584000  CALL DWORD PTR SS:[EBP+0x405875]        ; kernel32.GetProcAddress
00438FF0      EB 01          JMP SHORT 06.00438FF3


拿到这四个地址后就可以编写脚本了。
编写脚本的思路:
①设置必要的断点
②构建运行循环
③第一个断下的是清除硬件断点的异常回调函数,将其NOP掉
④再次循环会断到获取API的点,保存API地址
⑤再次循环会断到写入IAT的点,将保存的API填充IAT
⑥一直循环,最终到达原始OEP
[Asm] 纯文本查看 复制代码
// 1.定义变量
MOV dwOEP,00409486 
MOV dwClearBPH, 0043AF59 
MOV dwGetAPI,004399E4  
MOV dwWriteIAT,0043918C 

// 2. 清除环境
BC    // 清除所有软件断点
BPHWC // 清除所有硬件断点
BPMC  // 清除内存断点

// 3. 设置断点
BPHWS dwOEP, "x" //当执行到此地址时产生中断.
BPHWS dwClearBPH, "x" //当执行到此地址时产生中断.
BPHWS dwGetAPI, "x" //当执行到此地址时产生中断.
BPHWS dwWriteIAT, "x" //当执行到此地址时产生中断.

// 4. 循环
LOOP0:
  RUN // F9      
  CMP dwClearBPH,eip  
  JNZ CASE0        
  FILL dwClearBPH,1A,90  
  BPHWC dwClearBPH  
  JMP LOOP0
CASE0:
  CMP dwGetAPI,eip  
  JNZ CASE1  
  MOV dwTMP,eax
  JMP LOOP0
CASE1:
  CMP dwWriteIAT,eip    
  JNZ CASE2
  MOV [edi],dwTMP       //MOV DWORD PTR DS:[EDI],EAX
  JMP LOOP0
CASE2:
  CMP dwOEP,eip  
  JNZ LOOP0  
  MSG "OEP已到达"

2.35

2.35


观察数据窗口,发现每一个API地址中间都用00隔开了

2.36

2.36


而且观察地址,发现咋跑到壳这个区段来了,正常来说VC6.0的程序应该在第二个区段才对

2.37

2.37


查看以下422000,发现也有IAT

2.38

2.38


查看一下模块间调用,发现有43的也有42的,这里的原因上文已经提到过了

2.39

2.39


因为这里的IAT比较诡异,所以我们在内存中重新规划IAT表
先申请一块内存

2.40

2.40


复制地址

2.41

2.41

2.42

2.42


以此类推,我们把所有的调用都复制粘贴过来就可以了。

还是用工具吧,这也太累了...顺便修复一下输入表

2.43

2.43


修复完成了

2.44

2.44


再看一下,都填充好了,确实比我手工快一点点

2.45

2.45


接下来就是日常DUMP,修复,完活儿

2.46

2.46

2.47

2.47


至此,分析完毕。

附件图片

附件图片


反硬件调试壳.zip (343.05 KB, 下载次数: 33)

免费评分

参与人数 8威望 +1 吾爱币 +29 热心值 +8 收起 理由
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
xxqui1111 + 1 谢谢@Thanks!
董督秀 + 1 + 1 用心讨论,共获提升!
13699513436 + 1 热心回复!
FleTime + 3 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
lyl610abc + 3 + 1 我很赞同!
笙若 + 1 + 1 谢谢@Thanks!
arvin1024 + 1 + 1 热心回复!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

咔c君 发表于 2021-12-24 21:47
不错了学习了
woflant 发表于 2021-12-25 09:32
最近正学到脱壳,看了楼主的教程有很大收获,希望楼主更新下去
5455123 发表于 2021-12-25 13:55
qqpoly 发表于 2021-12-25 14:24
硬件也可以?这有点意思啊,学习破解思路去
Van192 发表于 2021-12-25 16:01
不错,学习了。
13699513436 发表于 2021-12-25 16:13
不错,学习了。,学习破解思路去
douluodalu 发表于 2021-12-25 22:35
不错!学习了。
csjwaman 发表于 2021-12-26 15:15
思路清晰,很好!
用温柔将我杀死 发表于 2021-12-26 18:51
好东西学习了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-25 13:54

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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