论坛: 编程破解 标题: [转帖]手脱ASProtect2.0xRegistered 复制本贴地址    
作者: yongmin [yongmin]    论坛用户   登录
作者:sskey
转贴自:一蓑烟雨
【文章作者】: sskey
【软件名称】: ASPR-test.exe
【保护方式】: ASProtect 2.0x Registered -> Alexey Solodovnikov
【使用工具】: od,lordPE,ImportREC,winxp
【程序语言】: vc

      ----------------------------------------------------------------------
【说明】:
        实验程序是syscom大侠一篇文章里的附件,有stolen code,对于stolen code一般
可以用手动还原(所偷的代码少时,可以手动跟出或用未加壳的同类语言编的程序对比来还原),
但所偷代码比较多时,就只有用补区段的方法了,我正是为了了解一下脱壳时的补区段,才下了
这个附件,结果弄得我很郁闷,断断续续用了4天的时间才搞定,还到论坛上发了求助的帖子,没
人回(更郁闷!!!),后终于想通,是我在补区段后没修正好Voffset,呵呵(听到后你们都晕了吧,
被这么简单的问题困扰了几天,太有才了.......)
    口水有点多了,下面来分享一下脱壳过程吧(高手就飘过了)
【脱壳流程】:
1、找oep
2、修复call xxxxxx
3、补区段
4、去掉壳代码校验(Route CHECK) 
【详细过程】:
1、找oep
od载入后停在这里:
00401000 >  68 01C04800    push    0048C001      //壳入口
00401005    E8 01000000    call    0040100B
0040100A    C3              retn
0040100B    C3              retn
0040100C    47              inc    edi
0040100D    EF              out    dx, eax
0040100E    6D              ins    dword ptr es:[edi], dx
0040100F    60              pushad
00401010    FD              std
00401011    FE              ???                                      ; 未知命令
00401012    7A FB          jpe    short 0040100F

可以用多次内存断点来找,不过对这个壳来说不是很精确(会超过oep几行),下面这种方法比较
准确:忽略所有异常,然后直接shift+F9让程序运行起来,然后ALt+L来到记录窗口查看经过些什么异常:
71A10000  模块 C:\windows\system32\WS2HELP.dll
00AFA8ED  访问违规: 正在写入到 [00000000]
00AF9ED6  访问违规: 正在写入到 [00000000]
00AFA0E7  访问违规: 正在写入到 [00000000]
00AFA225  访问违规: 正在写入到 [00000000]
00AF7E76  访问违规: 正在写入到 [00000000]
00AF7FCB  访问违规: 正在写入到 [00000000]
00AF8145  访问违规: 正在写入到 [00000000]
00AF8221  访问违规: 正在写入到 [00000000]
00AF8392  访问违规: 正在写入到 [00000000]
00AFA3A9  访问违规: 正在写入到 [00000000]
00AFA490  访问违规: 正在写入到 [00000000]
00AFA5FD  访问违规: 正在写入到 [00000000]
00AF6AFE  INT3 命令位于00AF6AFE
00AF7884  访问违规: 正在写入到 [00000000]
00AF7A7B  访问违规: 正在写入到 [00000000]
00AF871A  访问违规: 正在写入到 [00000000]
00AF8901  访问违规: 正在写入到 [00000000]
00AF985E  访问违规: 正在写入到 [00000000]
00AF8C31  访问违规: 正在写入到 [00000000]
00AF8E9A  访问违规: 正在写入到 [00000000]
00AF9101  访问违规: 正在写入到 [00000000]
00AF92FA  访问违规: 正在写入到 [00000000]
00AF9407  访问违规: 正在写入到 [00000000]
00AF9554  访问违规: 正在写入到 [00000000]
00AFB3B0  访问违规: 正在写入到 [00000000]
00AFB4AC  访问违规: 正在写入到 [00000000]
00AFB833  访问违规: 正在写入到 [00000000]
00AFBAB5  访问违规: 正在写入到 [00000000]
00AFBD03  访问违规: 正在写入到 [00000000]
00AFBED0  访问违规: 正在写入到 [00000000]
00AF6AFE  INT3 命令位于00AF6AFE
5ADC0000  模块 C:\windows\system32\uxtheme.dll
00AF8575  访问违规: 正在写入到 [00000000]
00AF9BF7  访问违规: 正在写入到 [00000000]
10000000  模块 E:\aspr\5\BetterJPEG\BJPEG07.dll
73D30000  模块 C:\windows\system32\MFC42.DLL
75FF0000  模块 C:\windows\system32\MSVCP60.dll
61BE0000  模块 C:\windows\system32\MFC42LOC.DLL
74680000  模块 C:\windows\system32\MSCTF.dll
7C810659  ID 00000ACC 的新线程已创建
7C810659  ID 00000AD0 的新线程已创建
          线程 00000ACC 已终止, 退出代码 0
          线程 00000AD0 已终止, 退出代码 0

我的是2个int3异常和20次左右的内存访问异常,那么我们就可以利用这些异常找到OEP,这里当然选int3
异常了(只有2次,比你shift+f9 20次快多了),好了,重新载入od,异常设置里int3选不忽略,然后shift+f9
两次,再在代码段下访问断点,shift+f9就来到真正的oep处了:
00431EB8    55              push    ebp                    //oep
00431EB9    8BEC            mov    ebp, esp
00431EBB    6A FF          push    -1
00431EBD    68 F08D4600    push    00468DF0
00431EC2    68 04734300    push    00437304
00431EC7    64:A1 00000000  mov    eax, dword ptr fs:[0]
00431ECD    50              push    eax
00431ECE    64:8925 0000000>mov    dword ptr fs:[0], esp
00431ED5    83EC 58        sub    esp, 58
00431ED8    53              push    ebx
00431ED9    56              push    esi
00431EDA    57              push    edi
00431EDB    8965 E8        mov    dword ptr [ebp-18], esp
00431EDE    FF15 88134600  call    dword ptr [461388]              ; kernel32.GetVersion
00431EE4    33D2            xor    edx, edx
00431EE6    8AD4            mov    dl, ah
00431EE8    8915 84B34700  mov    dword ptr [47B384], edx

可以看到oep处没有被偷,那再来看看输入表,数据窗口中跟随00431ede处中ds段的地址,然后上下翻看一下,
发现输入表也没有被加密:
00461000  77DA6BF0  ADVAPI32.RegCloseKey              //IAT-start
00461004  77DA761B  ADVAPI32.RegOpenKeyExA
00461008  77DA7883  ADVAPI32.RegQueryValueExA
0046100C  77DAEBE7  ADVAPI32.RegSetValueExA
00461010  77DAEDE5  ADVAPI32.RegDeleteValueA
00461014  77DCC123  ADVAPI32.RegDeleteKeyA
00461018  77DAEAF4  ADVAPI32.RegCreateKeyExA
0046101C  00000000
00461020  77195140  COMCTL32.ImageList_GetImageCount
00461024  77195323  COMCTL32.ImageList_Replace
00461028  77195650  COMCTL32.ImageList_GetIconSize
0046102C  77195572  COMCTL32.ImageList_Remove

(一阵窃喜,这么容易的壳),那我们dump吧,呵呵,要是现在dump就上当了,我们在oep处上下看一下,你就
不会说简单了:
00431F2E    E8 B2000000    call    00431FE5
00431F33    59              pop    ecx
00431F34    33F6            xor    esi, esi
00431F36    8975 FC        mov    dword ptr [ebp-4], esi
00431F39    E8 1E6C0000    call    00438B5C
00431F3E    E8 BDE09100    call    00D50000                      //到壳里去了
00431F43    51              push    ecx
00431F44    A3 E8CA4700    mov    dword ptr [47CAE8], eax
00431F49    E8 DC6A0000    call    00438A2A
00431F4E    A3 B8B34700    mov    dword ptr [47B3B8], eax
00431F53    E8 85680000    call    004387DD
00431F58    E8 C7670000    call    00438724
00431F5D    E8 33FBFFFF    call    00431A95
00431F62    8975 D0        mov    dword ptr [ebp-30], esi
00431F65    8D45 A4        lea    eax, dword ptr [ebp-5C]
00431F68    50              push    eax
00431F69    E8 92E09100    call    00D50000                    //这里也是
00431F6E    19E8            sbb    eax, ebp

还有n多处,ctrl+f:call 00d50000,搜索一下,搜出来的数量很惊人,200多处,函数调用的高级保护......

2、修复call xxxxxxxx
当然我们可以在00D50000处下短点,然后跟出它每次调用什么函数,但数量太大,我们就想到了patch,前段日子学了
一下脚本,干脆就自己写了个脚本来修复call xxxxxxxx:
*****************************************************************
var tmp1
var tmp2
var vmadd
var oepbase

dbh
gpa "GetSystemTime","kernel32.dll"
mov tmp1,$RESULT
cmp tmp1,0
je erro
bp tmp1
esto
bc tmp1
rtu
mov tmp1,eip
gmemi tmp1,MEMORYBASE
mov tmp1,$RESULT
cmp tmp1,0
je erro
mov vmadd,tmp1
gpa "GetVersion","kernel32.dll"
mov tmp1,$RESULT
cmp tmp1,0
je erro
bp tmp1
esto
bc tmp1
rtu
mov tmp1,eip
gmemi tmp1,MEMORYBASE
mov oepbase,$RESULT
cmp oepbase,0
je erro
mov tmp2,00460b00
mov [tmp2],#BA00104000803AE875128B420103C283C0053D0000D500750360FFE24281FA00#
add tmp2,20
mov [tmp2],#10460076E0EB36B9001046008B55F43911751D890D0008460081C43C02000061#
add tmp2,20
mov [tmp2],#8B1D00084600895A0266C702FF15EBCC83C10481F9AC1646007CD4EB009090#
mov tmp1,vmadd
find tmp1,#68A443B0008D85C4FEFFFF#
mov tmp2,$RESULT
cmp tmp2,0
je erro
asm tmp2,"push 00460b27"
mov eip,00460b00
bp 00460b5d
run
cmp eip,00460b5d
jne erro
bc eip
fill 00460b00,70,00
mov [tmp2],#68A443B000#
find oepbase,#558BEC6AFF68F08D46006804734300#
mov tmp1,$RESULT
cmp tmp1,0
je erro
mov eip, tmp1
jmp end
erro:
msg "error!"
end:
msg "now,you can dump!"
ret
******************************************************************************

讲一下脚本的处理思路:从代码段的开头到结尾搜索call 00d50000这条指令,找到后直接跳去壳代码里去执行,
不过得到函数的地址我们用脚本写回代码段,而不是壳里了,具体代码我也不多说了..........
用od重新加载目标程序,忽略所有异常,然后直接运行脚本,完成后我们就可以dump了,然后再建一下输入表,
注意有一个输入表指针ImportREC不识别,用它的反汇编可以看一下它的代码,就是GetProcAddress

3、补区段
这时运行dump.exe会提示"xxxxxxxx地址的内存不可读.......",我们跟踪一下原程序可发现:
00432348    68 0000D900    push    0D90000           
0043234D    C3              retn                          //变形的jmp
0043234E    9E              sahf
0043234F    03CB            add    ecx, ebx
00432351    3AF8            cmp    bh, al

jmp的变形,又到壳代码去了,还有多处,我不帖出代码了,这些其实是solen code,代码少的话,可以手工还原,
但这个壳的stolen code是不少的,那就只有用补区段的方法了,现在问题有来了,你怎么知道哪些区段要补,我
的思路是这样的,先让原程序走到oep,这时代码已基本解压完毕,然后在壳在内存中申请的所有区段下访问断点,
然后一直shift+F9,直到程序启动,这时直接ALT+M到内存窗口看用了哪些段,再区域转存下来,(当然也可以在下
好所有的访问断点后,每次shift+f9中断的时候记下访问了哪个段):
地址                  大小                        类型
00990000          00008000 (32768.)              Priv 00021004
00A90000          00003000 (12288.)              Priv 00021004
.
.
.
00DE0000          00001000 (4096.)              Priv 00021040

总共下断30多个,shift+f9完后,我数了下,用了22个段,记录下来,然后就是体力活了,用 lordpe区域转存把
那22个段全dump下来,然后再用lordpe的pe编辑功能,把刚才那些段全部添加到dump.exe文件的尾部,(注意要按地址
的先后顺序添加,要不到时就会出错了),添加完后还有很重要的一步就是修改刚才添加段的Voffset:
如:00990000--> 改为:00990000-00400000=00590000
    00DE0000--> 改为:00DE0000-00400000=009E0000
(我脱这个壳时就是因为这里没弄对,还以为自己没脱成功,弄得我郁闷了好几天..........)
修改完Voffset后,保存再重建一下pe,(完了没有,我看都看累了),还有最后一步

4、去掉壳代码校验(Route CHECK)
Route check:代码完整性校验,不修改它的话脱掉的程序是运行不起的,怎么找了,用特征码吧:

MOV  EAX,[EAX+34] 
CALL EAX           
SUB  [EBP+C],EAX     
MOV  EAX,[EBP+C]
二进制搜索:8B 40 34 FF D0 29 45 0C 8B 45 0C
          地址            大小
我的是在:00AE0000        00030000  段中
找到后把上面几句改为:

MOV  EAX,[EAX+34]    =>  NOP
CALL EAX            =>  NOP
SUB  [EBP+C],EAX    =>  MOV  EAX,[ESP+58] 
MOV  EAX,[EBP+C]    =>  SUB  EAX,5
(具体的原因请参考syscom的帖子,我再写上来就显得重复了)
再复制到可执行文件
运行一下,正常,打完收工了.........



地主 发表时间: 08-04-01 10:49

论坛: 编程破解

20CN网络安全小组版权所有
Copyright © 2000-2010 20CN Security Group. All Rights Reserved.
论坛程序编写:NetDemon

粤ICP备05087286号