GUC 发表于 2009-12-16 17:04

..考研词汇 1.0 InlineHook API 爆破之解文

本帖最后由 GUC 于 2009-12-16 19:04 编辑

原版:http://www.onlinedown.net/soft/82461.htm

破解不是本文的重点,这里简略带过。
软件会找目录下的key.bb文件,其实就是个记事本文件,里面写上16个数字就可以了,接下来关键点如下:
004EED6B    55                         push    ebp                       ; 这是关键call内部,eax返回非0就是注册成功
004EED6C    8BEC                       mov     ebp, esp
004EED6E    8B4D 0C                    mov     ecx, dword ptr
004EED71    E8 B4FDFFFF                call    004EEB2A
004EED76    50                         push    eax
004EED77    8B4D 08                    mov     ecx, dword ptr
004EED7A    E8 E4FDFFFF                call    004EEB63
004EED7F    F7D8                       neg     eax                       ; 爆破方式n多,我用这里的三行共5个字节写mov eax,-1
004EED81    1BC0                       sbb     eax, eax                  ; 爆破方式n多,我用这里的三行共5个字节写mov eax,-1
004EED83    40                         inc     eax                       ; 爆破方式n多,我用这里的三行共5个字节写mov eax,-1
004EED84    5D                         pop     ebp
004EED85    C2 0800                    retn    8
这个地方共被11个地方调用。

软件的壳很少见,是PEX 0.99 -> bart/CrackPl,脱壳后本机运行成功,但在虚拟机里测试发现不能跨平台,看一下,原来这个壳处理后程序调用api的方式都是:
00866780  - E9 1077FA7B                jmp     7C80DE95                  ; kernel32.7C80DE95
00866785  - E9 85C1FC7B                jmp     7C83290F                  ; kernel32.ResumeThread
0086678A  - E9 9440FA7B                jmp     7C80A823                  ; kernel32.GetThreadPriority
0086678F  - E9 045AFA7B                jmp     7C80C198                  ; kernel32.SetThreadPriority
00866794  - E9 D1AAFA7B                jmp     7C81126A                  ; kernel32.GetVersion
。。。
彻底晕倒。

放弃脱壳,可以通过多层SMC去搞定他,也可以简单地用loader、lpk,但本文讲另外一个思路:InlineHook API进行爆破。

但是找哪个api呢?
我们通过esp定律发现他在OEP之前第一次用了VirtualFree函数,那时候代码全已出现但未执行,时机很perfect!就它了!

载入程序,Ctrl+N看一下:
Address    Section    Type    Name                                    Comment
00866379              Import  KERNEL32.ExitProcess
00866371              Import  KERNEL32.GetProcAddress
00866375              Import  KERNEL32.LoadLibraryA
00866369              Import  USER32.MessageBoxA
008DB000              Export  <ModuleEntryPoint>
0086637D              Import  KERNEL32.VirtualAlloc
00866381              Import  KERNEL32.VirtualFree
已经有KERNEL32.LoadLibraryA和KERNEL32.GetProcAddress的地址了(分别在dword 和dword ),有这对搭档在足够我们干很多事了!乐啊
这里还已经有了KERNEL32.VirtualFree,在dword ,可以直接拿来用(即使没有,咱们也可以通过LoadLibraryA跟GetProcAddress获取)。
强调,下面的代码里,KERNEL32.VirtualFree的地址dword 是直接拿来用的,不要看到dword 感到莫名其妙。。。

基本信息有了,咱们开工!
1、首先找个空地。
程序空地不少,但是我仍喜欢加个区段,所以我加了个区段,大小只要200个字节左右就行了,因为补丁的代码只需要大概170个字节。
我加的段VA:008DB000

2、用LordPE修改程序的入口为新段的地址008DB000,OD载入,开始写代码:
PS:008DB026这里call eax ; VirtualProtect是为了使VirtualFree函数前6个字节可写可读,防止api地址不可写导致我们挂钩失败。不清楚的自己去查下api手册。
008DB000 > $  68 92B08D00              push    8DB092                    ; /ASCII "kernel32.dll"   8DB092这里你自己去写下ASCII "kernel32.dll"
008DB005   .  FF15 75638600            call    dword ptr         ; \kernel32.LoadLibraryA  返回基址到eax
008DB00B   .  68 A2B08D00              push    8DB0A2                    ; /ASCII "VirtualProtect"   8DB0A2这里你自己去写下ASCII "VirtualProtect"
008DB010   .  50                       push    eax                       ; |这里是刚得到的kernel32.dll的基址
008DB011   .  FF15 71638600            call    dword ptr         ; \kernel32.GetProcAddress   返回VirtualProtect的函数的地址到eax
008DB017   .  68 B2B08D00              push    8DB0B2                    ;  原来的属性暂放空地8DB0B2
008DB01C   .  6A 40                    push    40                        ;  可读可写属性40
008DB01E   .  6A 06                    push    6                         ;  size = 6
008DB020   .  FF35 81638600            push    dword ptr         ;  程序初始化后dword ptr 里面就是VirtualFree函数的地址了
008DB026   .  FFD0                     call    eax                       ;  call刚得到的VirtualProtect的函数,使VirtualFree函数前6个字节可写可读,以便挂钩
008DB028   .  A1 81638600              mov     eax, dword ptr    ;  VirtualFree函数的地址给eax(开始保存api VirtualFree的前6个字节)
008DB02D   .  8B08                     mov     ecx, dword ptr       ;  VirtualFree函数的前4个字节给ecx
008DB02F   .  66:8B58 04               mov     bx, word ptr       ;  VirtualFree函数的第5-第6个字节给bx
008DB033   .  890D B6B08D00            mov     dword ptr , ecx   ;  把得到的前6个字节保存起来,前4个字节保存到空地8DB0B6
008DB039   .  66:891D BAB08D00         mov     word ptr , bx     ;  把得到的前6个字节保存起来,第5-第6个字节保存到空地8DB0BA(保存前6个字节完毕)
008DB040   .  C600 68                  mov     byte ptr , 68        ;  写下钩子,68是push的机器码(开始写钩子)
008DB043   .  40                       inc     eax                       ;  上面刚写完1个byte,所以要加1,继续写下面的
008DB044   .  C700 55B08D00            mov     dword ptr , 8DB055   ;  写上8DB055,让VirtualFree函数执行的时候返回到8DB055
008DB04A   .  83C0 04                  add     eax, 4                    ;  上面刚写完4个byte,所以要加4,继续写下面的
008DB04D   .  C600 C3                  mov     byte ptr , 0C3       ;  写上0C3,配合上面写入的push 8DB055就会回到8DB055,patch时机就到了(钩子写完毕)
008DB050   .- E9 A5B0F8FF              jmp     008660FA                  ;  程序原来入口就是跳到008660FA开始执行的,我们照搬
;-------------------------钩子到了之后就会来到下面-----------------------
008DB055   .  C705 7FED4E00 B8FFFFFF   mov     dword ptr , -48   ;  VirtualFree函数执行的时候由于我们的钩子所以会来到这里,开始写入爆破的代码
008DB05F   .  C605 83ED4E00 FF         mov     byte ptr , 0FF    ;  继续写入第5个,mov eax,-1总共是5个字节
008DB066   .  8B0D B6B08D00            mov     ecx, dword ptr    ;  把我们前面保存起来的VirtualFree函数的前4个字节给ecx(开始还原钩子)
008DB06C   .  66:8B1D BAB08D00         mov     bx, word ptr      ;  VirtualFree函数的第5-第6个字节给bx
008DB073   .  A1 81638600              mov     eax, dword ptr    ;  dword ptr 里面是VirtualFree函数的头部地址
008DB078   .  8908                     mov     dword ptr , ecx      ;  把ecx里的VirtualFree函数的前4个字节给写回去
008DB07A   .  83C0 04                  add     eax, 4                    ;  上面写完4个字节,所以加4继续写下面的
008DB07D   .  66:8918                  mov     word ptr , bx        ;  把bx里的VirtualFree函数的第5-第6个字节给写回去(还原钩子完毕)
008DB080   .  83E8 04                  sub     eax, 4                    ;  回到VirtualFree函数头部准备执行VirtualFree
008DB083   .  83C4 04                  add     esp, 4                    ;  平栈
008DB086   .  FFD0                     call    eax                       ;  这里call的就是VirtualFree函数了等于回到程序原路了
008DB088   .  68 07608600              push    866007                    ;  原文件call VirtualFree之后就是回到866007的,我们照搬
008DB08D   .  C3                       retn                              ;  push+retn 都知道干嘛的吧
008DB08E      00                       db      00
008DB08F      00                       db      00
008DB090      00                       db      00
008DB091      00                       db      00
008DB092   .  6B 65 72 6E 65 6C 33 32 >ascii   "kernel32.dll",0          ;  这个是自己写的
008DB09F      00                       db      00
008DB0A0      00                       db      00
008DB0A1      00                       db      00
008DB0A2   .  56 69 72 74 75 61 6C 50 >ascii   "VirtualProtect",0        ;  这个是自己写的
008DB0B1      00                       db      00
008DB0B2      00                       db      00
008DB0B3      00                       db      00
008DB0B4      00                       db      00
008DB0B5      00                       db      00
008DB0B6   .  00000000                 dd      00000000
008DB0BA   .  0000                     dw      0000
008DB0BC      00                       db      00
008DB0BD      00                       db      00
所有的代码我都写了注释,不要嫌我罗嗦,写的很土,可能还有错误的地方,请多多海涵,偶是文盲。

保存代码,在本机xp,虚拟机xp、win7都测试完毕,破解成功。





推销下偶的皮肤,有兴趣的找我。

Hmily 发表于 2009-12-16 18:01

GUC兄弟来吾爱第一篇破文,加精鼓励!

GUC 发表于 2009-12-16 18:18

谢谢Hmily GG,Squn MM

Squn就是小芊芊啊?

ericalan 发表于 2009-12-16 18:23

没留下什么联系方式啊?怎么得到皮肤?

GUC 发表于 2009-12-16 18:36

4# ericalan

还是直接发到这里好了,一个个发很麻烦。。。

小举 发表于 2009-12-16 20:27

你是牛魔王他大爷!

missviola 发表于 2009-12-16 20:38

好文支持下,lz应该素来自upk的大侠啊。。。

87334433 发表于 2009-12-17 09:40

这个得学,感谢感谢

GUC 发表于 2009-12-17 12:01

本帖最后由 GUC 于 2009-12-17 12:05 编辑

澄清下
不知道昨天怎么回事,1级修复后不能跨平台,今天试了下,1级修复后是可以跨平台的,没那么复杂,2000 xp win7都能运行,怪异,应该是昨天哪里操作错误了。。。

太壳盲了,努力学习:dizzy:

=====
明白了,昨天1级修复后忘记再次点“Show Invalid”了,导致剪切的时候把1级修复成功修复的那部分iat也给切了,结果就等于跟没用1级修复一样,唉,粗心害死人。

lovettww 发表于 2009-12-17 12:20

拜读了。。。。
页: [1] 2
查看完整版本: ..考研词汇 1.0 InlineHook API 爆破之解文