【文章标题】: 手脱Armadillo 5.0 (Standard + Debug-Blocker).学习笔记.
【文章作者】: wuhanqi
【作者邮箱】: wuhanqi@qq.com
【软件名称】: 一个unpackme
【下载地址】: 自己搜索下载
【加壳方式】: Armadillo 5.0 (Standard + Debug-Blocker)
【编写语言】: Delphi
【使用工具】: OD.ImportREC.LordPE.Arma Detach.PEID 0.94.FastScanner 2.1
【操作平台】: 盗版XP3
【作者声明】: 小菜一个.高手别笑话我哦~嘿嘿.
--------------------------------------------------------------------------------
【详细过程】
  废话不多说.进入正题.脱壳目标为一个unpackme.
  
  FastScan 2.1 查壳为 Microsoft Visual C++ 8
  PEID 0.94 查壳为 Armadillo V5.0X -> Silicon Realms Toolworks   * Sign.By.fly *
  
  首先运行Armadillo Process Detach.将unpackme脱入Arma Detach中。
  会显示内容如下:
  DONE!
  Child process ID: 000002C8
  Entry point: 004A2DC2
  Original bytes: E8E3
  
  这时我们打开一个od.文件--附加.然后选中PID为2C8的进程.即为Armadillo的子进程.
  我们载入后.F9.再F12.便断到如下代码处:
  

代码:
  004A2DC2 >- EB FE           JMP SHORT <ModuleEntryPoint>
  004A2DC4    40              INC EAX
  004A2DC5    0000            ADD BYTE PTR DS:[EAX],AL
  004A2DC7  ^ E9 16FEFFFF     JMP 004A2BE2
  004A2DCC    6A 0C           PUSH 0C
  004A2DCE    68 B0104D00     PUSH 004D10B0
  004A2DD3    E8 44150000     CALL 004A431C
  004A2DD8    8B4D 08         MOV ECX,DWORD PTR SS:[EBP+8]
  004A2DDB    33FF            XOR EDI,EDI
  004A2DDD    3BCF            CMP ECX,EDI
  004A2DDF    76 2E           JBE SHORT 004A2E0F
  004A2DE1    6A E0           PUSH -20
  004A2DE3    58              POP EAX
  004A2DE4    33D2            XOR EDX,EDX
  004A2DE6    F7F1            DIV ECX
  004A2DE8    3B45 0C         CMP EAX,DWORD PTR SS:[EBP+C]
  
  
  入口点是一个跳转.其实是Arma Detach为了防止穿山甲检测.才修改了入口点.
  我们根据Arma Detach给我们的数据:Original bytes: E8E3.将jmp那两个字节修改为E8E3.即可恢复正常的入口点.
  
代码:
  004A2DC2 >  E8 E3400000     CALL 004A6EAA
  004A2DC7  ^ E9 16FEFFFF     JMP 004A2BE2
  004A2DCC    6A 0C           PUSH 0C
  004A2DCE    68 B0104D00     PUSH 004D10B0
  004A2DD3    E8 44150000     CALL 004A431C
  004A2DD8    8B4D 08         MOV ECX,DWORD PTR SS:[EBP+8]
  004A2DDB    33FF            XOR EDI,EDI
  004A2DDD    3BCF            CMP ECX,EDI
  004A2DDF    76 2E           JBE SHORT 004A2E0F
  004A2DE1    6A E0           PUSH -20
  004A2DE3    58              POP EAX
  004A2DE4    33D2            XOR EDX,EDX
  004A2DE6    F7F1            DIV ECX
  004A2DE8    3B45 0C         CMP EAX,DWORD PTR SS:[EBP+C]
  
  
  接下来我们需要确认OD没有硬件断点.以及Alt+B确认没有任何切换断点.
  然后我们下bp VirtualProtect.可以使我们来到穿山甲处理IAT的地址.
  shift+f9运行程序.我们要注意堆栈的变化:
  
代码:
  0012F648   0048E8F7  /CALL to VirtualProtect from UnpackMe.0048E8F1
  0012F64C   00EB1000  |Address = 00EB1000
  0012F650   0006C82C  |Size = 6C82C (444460.)
  0012F654   00000040  |NewProtect = PAGE_EXECUTE_READWRITE
  0012F658   0012F67C  \pOldProtect = 0012F67C
  
  0012F648   0048E8F7  /CALL to VirtualProtect from UnpackMe.0048E8F1
  0012F64C   00F1E000  |Address = 00F1E000
  0012F650   000088F4  |Size = 88F4 (35060.)
  0012F654   00000002  |NewProtect = PAGE_READONLY
  0012F658   0012F67C  \pOldProtect = 0012F67C
  
  0012F648   0048E8F7  /CALL to VirtualProtect from UnpackMe.0048E8F1
  0012F64C   00F27000  |Address = 00F27000
  0012F650   00012AC4  |Size = 12AC4 (76484.)
  0012F654   00000004  |NewProtect = PAGE_READWRITE
  0012F658   0012F67C  \pOldProtect = 0012F67C
  
  0012F648   0048E8F7  /CALL to VirtualProtect from UnpackMe.0048E8F1
  0012F64C   00F3A000  |Address = 00F3A000
  0012F650   000024C0  |Size = 24C0 (9408.)
  0012F654   00000002  |NewProtect = PAGE_READONLY
  0012F658   0012F67C  \pOldProtect = 0012F67C
  
  0012F648   0048E8F7  /CALL to VirtualProtect from UnpackMe.0048E8F1
  0012F64C   00F3D000  |Address = 00F3D000
  0012F650   00006464  |Size = 6464 (25700.)
  0012F654   00000002  |NewProtect = PAGE_READONLY
  0012F658   0012F67C  \pOldProtect = 0012F67C
  
  00129470   00EF9946  /CALL to VirtualProtect from 00EF9940
  00129474   00401000  |Address = UnpackMe.00401000
  00129478   0005B000  |Size = 5B000 (372736.)
  0012947C   00000004  |NewProtect = PAGE_READWRITE
  00129480   0012C164  \pOldProtect = 0012C164
  
  00129470   00EF9991  /CALL to VirtualProtect from 00EF998B
  00129474   00401000  |Address = UnpackMe.00401000
  00129478   0005B000  |Size = 5B000 (372736.)
  0012947C   00000020  |NewProtect = PAGE_EXECUTE_READ
  00129480   0012C164  \pOldProtect = 0012C164
  
  00129470   00EF9946  /CALL to VirtualProtect from 00EF9940
  00129474   0045C000  |Address = UnpackMe.0045C000
  00129478   00002000  |Size = 2000 (8192.)
  0012947C   00000004  |NewProtect = PAGE_READWRITE
  00129480   0012C164  \pOldProtect = 0012C164
  
  00129470   00EF9991  /CALL to VirtualProtect from 00EF998B
  00129474   0045C000  |Address = UnpackMe.0045C000
  00129478   00002000  |Size = 2000 (8192.)
  0012947C   00000004  |NewProtect = PAGE_READWRITE
  00129480   0012C164  \pOldProtect = 0012C164
  
  00129470   00EF9946  /CALL to VirtualProtect from 00EF9940
  00129474   0045F000  |Address = UnpackMe.0045F000
  00129478   00003000  |Size = 3000 (12288.)
  0012947C   00000004  |NewProtect = PAGE_READWRITE
  00129480   0012C164  \pOldProtect = 0012C164
  
  00129470   00EF9991  /CALL to VirtualProtect from 00EF998B
  00129474   0045F000  |Address = UnpackMe.0045F000
  00129478   00003000  |Size = 3000 (12288.)
  0012947C   00000004  |NewProtect = PAGE_READWRITE
  00129480   0012C164  \pOldProtect = 0012C164
  
  00129470   00EFA814  /CALL to VirtualProtect from 00EFA80E
  00129474   0045F118  |Address = UnpackMe.0045F118
  00129478   0000008C  |Size = 8C (140.)    <<--我们一直shift+f9.直到size显示为8c.这样.我们就到了关键处.
  0012947C   00000004  |NewProtect = PAGE_READWRITE
  00129480   0012C028  \pOldProtect = 0012C028
  
  
  我们需要注意的是.在此之前断下来的VM都是EXE在执行IAT的处理.我们所需要断下来的地方是开始读写IAT的地方.
  为什么我们需要当size为8c的时候返回呢?这里size 8c所代表的是1000个字节以上的意思.
  即.如果我们的应用程序大小超过了1000个字节.那么便会显示8c.如果超过了2000个字节.那么便会显示16c.以此类推...
  (我也不知道我解释清楚没...哎.语文功底不好...)
  Let's go on!
  此时我们Ctrl+f9.或F8.回到VM处!!
  我们看下回到了哪里...
  
代码:
  00EFA814    6A 14           PUSH 14                            <<--这里有像之前穿山甲版本一样的push 14.
  00EFA816    E8 FBCA0000     CALL 00F07316
  00EFA81B    83C4 04         ADD ESP,4
  00EFA81E    8985 84ABFFFF   MOV DWORD PTR SS:[EBP+FFFFAB84],EAX
  00EFA824    83BD 84ABFFFF 0>CMP DWORD PTR SS:[EBP+FFFFAB84],0
  00EFA82B    74 59           JE SHORT 00EFA886
  00EFA82D    8B0D EC53F300   MOV ECX,DWORD PTR DS:[F353EC]
  00EFA833    898D 10AAFFFF   MOV DWORD PTR SS:[EBP+FFFFAA10],ECX
  00EFA839    8B95 74D8FFFF   MOV EDX,DWORD PTR SS:[EBP-278C]
  00EFA83F    0395 78D3FFFF   ADD EDX,DWORD PTR SS:[EBP-2C88]
  00EFA845    8B85 84ABFFFF   MOV EAX,DWORD PTR SS:[EBP+FFFFAB84]
  00EFA84B    8910            MOV DWORD PTR DS:[EAX],EDX
  
  
  哈哈.既然又像以前一样了.那我们也就好办了.
  现在我们需要寻找push 100.这条命令.重点是这条命令下面的call的地址.call所调用的地址就是移动处理IAT的地址!
  我们把滚轮向下滚...来到这里:
  
代码:
  00EFAA7B    8B85 40C2FFFF   MOV EAX,DWORD PTR SS:[EBP-3DC0]
  00EFAA81    8378 08 00      CMP DWORD PTR DS:[EAX+8],0
  00EFAA85    74 4A           JE SHORT 00EFAAD1
  00EFAA87    68 00010000     PUSH 100                   <<---我们要找的PUSH 100
  00EFAA8C    8D8D 40C1FFFF   LEA ECX,DWORD PTR SS:[EBP-3EC0]
  00EFAA92    51              PUSH ECX
  00EFAA93    8B95 40C2FFFF   MOV EDX,DWORD PTR SS:[EBP-3DC0]
  00EFAA99    8B02            MOV EAX,DWORD PTR DS:[EDX]
  00EFAA9B    50              PUSH EAX
  00EFAA9C    E8 2F7CFBFF     CALL 00EB26D0            <<---关键F7入!
  00EFAAA1    83C4 0C         ADD ESP,0C
  00EFAAA4    8D8D 40C1FFFF   LEA ECX,DWORD PTR SS:[EBP-3EC0]
  00EFAAAA    51              PUSH ECX
  
  
  跟进 CALL 00EB26D0  来到:
  
代码:
  00EB26D0    55              PUSH EBP          <<---不管他.直接retn.避开处理IAT!
  00EB26D1    8BEC            MOV EBP,ESP
  00EB26D3    83EC 2C         SUB ESP,2C
  00EB26D6    833D 00A6F200 0>CMP DWORD PTR DS:[F2A600],0
  
  
  此时我们删除VirtualProtect断点.通过下bp CreateThread 寻找真正的OEP!
  下好断点后.shift+f9!断下来后Crtl+f9回到VM!来到这里:
  
代码:
  00EE364C    50              PUSH EAX
  00EE364D    FF15 84E2F100   CALL DWORD PTR DS:[F1E284]               ; KERNEL32.CloseHandle
  00EE3653    5E              POP ESI
  00EE3654    5B              POP EBX
  00EE3655    8BE5            MOV ESP,EBP
  00EE3657    5D              POP EBP
  00EE3658    C3              RETN
  
  
  继续Crtl+F9!!
  
代码:
  00EFF1C5    B9 04A6F200     MOV ECX,0F2A604
  00EFF1CA    E8 B136FBFF     CALL 00EB2880
  00EFF1CF    E9 25010000     JMP 00EFF2F9
  00EFF1D4    E8 073CFDFF     CALL 00ED2DE0
  00EFF1D9    C705 3877F200 1>MOV DWORD PTR DS:[F27738],0F21C10
  00EFF1E3    E8 A894FDFF     CALL 00ED8690
  00EFF1E8    6A 00           PUSH 0
  00EFF1EA    E8 2143FEFF     CALL 00EE3510
  00EFF1EF    83C4 04         ADD ESP,4                 <<---出来后到这里!!
  00EFF1F2    B9 B8B4F200     MOV ECX,0F2B4B8
  00EFF1F7    E8 B4BFFBFF     CALL 00EBB1B0
  00EFF1FC    0FB6D0          MOVZX EDX,AL
  00EFF1FF    85D2            TEST EDX,EDX
  00EFF201    74 0C           JE SHORT 00EFF20F
  00EFF203    6A 01           PUSH 1
  00EFF205    B9 B8B4F200     MOV ECX,0F2B4B8
  00EFF20A    E8 11A6FCFF     CALL 00EC9820
  00EFF20F    C705 3877F200 0>MOV DWORD PTR DS:[F27738],0F21C08
  00EFF219    B9 04A6F200     MOV ECX,0F2A604
  00EFF21E    E8 5D36FBFF     CALL 00EB2880
  00EFF223    C745 F0 0000000>MOV DWORD PTR SS:[EBP-10],0
  00EFF22A    8D45 E8         LEA EAX,DWORD PTR SS:[EBP-18]
  00EFF22D    50              PUSH EAX
  00EFF22E    68 10F3EF00     PUSH 0EFF310
  00EFF233    FF15 74B1F200   CALL DWORD PTR DS:[F2B174]
  
  
  这样我们就到了VM中Armadillo 运行程序的地方!
  我们向下拉.寻找call ecx.找到的第一个call ecx不是重点.我们需要的是第二个!!
  
代码:
  00EFF29B    8B48 14         MOV ECX,DWORD PTR DS:[EAX+14]
  00EFF29E    51              PUSH ECX
  00EFF29F    8B55 08         MOV EDX,DWORD PTR SS:[EBP+8]
  00EFF2A2    8B42 10         MOV EAX,DWORD PTR DS:[EDX+10]
  00EFF2A5    50              PUSH EAX
  00EFF2A6    8B4D F4         MOV ECX,DWORD PTR SS:[EBP-C]
  00EFF2A9    2B4D E0         SUB ECX,DWORD PTR SS:[EBP-20]
  00EFF2AC    FFD1            CALL ECX                           <<---第一个ECX.不重要.忽略!
  00EFF2AE    8945 FC         MOV DWORD PTR SS:[EBP-4],EAX
  00EFF2B1    EB 46           JMP SHORT 00EFF2F9
  00EFF2B3    8B55 08         MOV EDX,DWORD PTR SS:[EBP+8]
  00EFF2B6    833A 01         CMP DWORD PTR DS:[EDX],1
  00EFF2B9    75 3E           JNZ SHORT 00EFF2F9
  00EFF2BB    A1 04BBF200     MOV EAX,DWORD PTR DS:[F2BB04]
  00EFF2C0    8B0D 04BBF200   MOV ECX,DWORD PTR DS:[F2BB04]            ; UnpackMe.004CB378
  00EFF2C6    8B50 68         MOV EDX,DWORD PTR DS:[EAX+68]
  00EFF2C9    3351 34         XOR EDX,DWORD PTR DS:[ECX+34]
  00EFF2CC    A1 04BBF200     MOV EAX,DWORD PTR DS:[F2BB04]
  00EFF2D1    3350 60         XOR EDX,DWORD PTR DS:[EAX+60]
  00EFF2D4    8955 DC         MOV DWORD PTR SS:[EBP-24],EDX
  00EFF2D7    8B4D 08         MOV ECX,DWORD PTR SS:[EBP+8]
  00EFF2DA    8B51 04         MOV EDX,DWORD PTR DS:[ECX+4]
  00EFF2DD    52              PUSH EDX
  00EFF2DE    8B45 08         MOV EAX,DWORD PTR SS:[EBP+8]
  00EFF2E1    8B48 08         MOV ECX,DWORD PTR DS:[EAX+8]
  00EFF2E4    51              PUSH ECX
  00EFF2E5    6A 00           PUSH 0
  00EFF2E7    8B55 08         MOV EDX,DWORD PTR SS:[EBP+8]
  00EFF2EA    8B42 0C         MOV EAX,DWORD PTR DS:[EDX+C]
  00EFF2ED    50              PUSH EAX
  00EFF2EE    8B4D F4         MOV ECX,DWORD PTR SS:[EBP-C]
  00EFF2F1    2B4D DC         SUB ECX,DWORD PTR SS:[EBP-24]
  00EFF2F4    FFD1            CALL ECX                            <<----第二个ECX.重要.跟进飞向OEP!!
  00EFF2F6    8945 FC         MOV DWORD PTR SS:[EBP-4],EAX
  00EFF2F9    8B45 FC         MOV EAX,DWORD PTR SS:[EBP-4]
  00EFF2FC    5E              POP ESI
  00EFF2FD    8BE5            MOV ESP,EBP
  00EFF2FF    5D              POP EBP
  00EFF300    C3              RETN
  
  
  此时我们运行LordPE.纠正一下映像大小.完整dump一下子进程.注意.PID一定要为2C8的进程!!!
  dump好之后.运行ImportREC.载入PID为2C8的进程!输入OEP:5B52C.获取输入表.有12个无效指针.直接剪掉!然后修复程序.
  修复后程序可运行啦~哈哈~
  FastScan查壳为 Borland Delphi 2006
  PEID 查壳为 Borland Delphi 6.0
  
  
--------------------------------------------------------------------------------
【经验总结】
  菜鸟最近才开始学各大强壳手脱方法.
  学习一个国外高人的脱壳方法笔记.没什么技术含量.拉出来与大家分享一下而已.
  献丑了.
  
--------------------------------------------------------------------------------
【版权声明】: 还不是踩在巨人的肩膀上说话?哪里来的版权.随便怎么样.哈哈~

                                                       2009年07月02日 15:27:41
上传的附件 UnpackMe_Armadillo_5.0.rar [附件请到:http://bbs.pediy.com/showthread.php?t=92699 ]