|
作者: 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号