脱壳-Armadillo1.x

前言

今天练习脱Armadillo. 记录下流程点.

记录

查壳

PEID => Armadillo 1.xx - 2.xx -> Silicon Realms Toolworks [Overlay]
DetectItEasy => Armadillo(6.X-9.X)[-]
RDG => Armadillo

脱壳环境

目标程序在原版WinXpSp3虚拟机中启动不了, 可能有虚拟机检测吧.
在真机环境(Win7X64Sp1)中可以直接启动运行.
在52pj虚拟机(WinXpSp3)中可以直接启动运行.
因为是X86程序, 选择在52pj虚拟机中脱壳.

52pjOD太强了, 用异常计数法不行, 去掉OD的异常检测后, F9直接跑起来了.
使用看雪OD+hideOD插件可以用异常计数法脱壳.

查找OEP前的设置

异常检测的设置
脱壳-Armadillo1.x_第1张图片
重新运行程序, F9跑起来, 目标程序会不断制造异常,这时会停在OD中, 按SHIFT+F9, 将异常返回给目标程序处理, 记录”按SHIFT+F9”的次数, 我这里按了22次, 第23次程序跑起来了.
这里写图片描述

查找OEP的流程记录


0115CA3E    8900            mov     dword ptr [eax], eax             ; F9后,按下22次(SHIFT+F9), 来到这里
这里写上22次来这了,重新运行程序,下次来这里,就可以在Memory代码区下F2断点了.

第23次(SHIFT+F9), 程序就跑起来了

第22次(SHIFT+F9)返回后,再Memory代码区下F2断点, F9跑起来.
Memory map, 条目 24
 地址=00914000
 大小=00040000 (262144.)
 属主=RegMech  00400000
 区段=.text1
 包含=代码
 类型=Imag 01001002
 访问=R
 初始访问=RWE

还会有第23次(异常来),再按下(SHIFT+F9)继续,这时会来到代码区中(因为对代码区下了F2断点).
0092A202    83C4 04         add     esp, 4                           ; 第23次SHIFT+F9后, 中断在代码区

F8往下走, 看看OEP在哪?
0092B76C    FF15 54AA9600   call    dword ptr [96AA54]               ; F8到这里, 程序跑起来了0092B76C这里,下一个硬执行断点,重新跑程序,断在这后,F7进入看OEP在哪?
F7进入了call    dword ptr [96AA54], 再F8找OEP在哪?

0115BF62    FFD7            call    edi                              ; F8程序跑起来了

去掉硬断点, 在0115BF62处下一个硬执行断点, 重新跑程序来到这.
F7进入 CALL edi, F8往下走.

0041262C    68 1C364100     push    0041361C
00412631    E8 EEFFFFFF     call    00412624                         ; F8卡住了, F7进去
去掉硬断点, 在00412631下一个硬执行断点, 重新跑程序来到这(F9一次,23次SHIFT+F9)
F7进入call    00412624, F8往下走. 最后又走进7xx函数去了(见下面的2个片段<<0041262C EIP处F7经过的2个代码片段>>), 像是进了一个框架的接口.

看看push    0041361C是压入得什么?
0041361C  56 42 35 21 F0 1F 2A 00 00 00 00 00 00 00 00 00  VB5!?*.........
在memory小窗口看到, 压入了"VB5!"给一个函数, 在VB程序里,只有OEP处是这样的.
看看call    00412624调用的是哪个函数?
dword ptr [401358] = 733935A4
看看733935A4在哪个DLL里面,是哪个函数?
在可执行模块列表中, 可以看到733935A4在MSVBVM60.DLL中。
Executable modules, 条目 10
 基址=73390000
 大小=00153000 (1388544.)
 入口=73391AF8 MSVBVM60.<模块入口点>
 名称=MSVBVM60 (系统)
 文件版本=6.00.9802
 路径=C:\WINDOWS\system32\MSVBVM60.DLL

用IDA将MsVBVM60.dll拖进来,看看733935A4是啥函数?
在IDA中看到, 733935A4 是 ThunRTMain

.text:733935A4                 public ThunRTMain
.text:733935A4 ThunRTMain      proc near               ; DATA XREF: .text:off_733B2D78o
.text:733935A4
.text:733935A4 var_64          = dword ptr -64h
.text:733935A4 StartupInfo     = _STARTUPINFOA ptr -60h
.text:733935A4 var_1C          = dword ptr -1Ch
.text:733935A4 var_18          = dword ptr -18h
.text:733935A4 var_4           = dword ptr -4
.text:733935A4 arg_0           = dword ptr  8
.text:733935A4
.text:733935A4 ; FUNCTION CHUNK AT .text:733AF9B7 SIZE 0000000B BYTES
.text:733935A4
.text:733935A4                 push    ebp
.text:733935A5                 mov     ebp, esp
.text:733935A7                 push    0FFFFFFFFh
.text:733935A9                 push    offset dword_733A97D0

push "VB5!"
call MSVBVM60.ThunRTMain
这是VB程序的OEP代码了.

0041262C    68 1C364100     push    0041361C
00412631    E8 EEFFFFFF     call    00412624                         ; F8卡住了, F7进去

最后得到结论 0041262C 是OEP.
去掉所有断点(硬件断点和F2断点), 在0041262C处下硬件执行断点, 重新运行程序(F9 + 23次SHIFT+F), 来到OEP = 0041262C

////////////////////////////////////////////////////////////
0041262C EIP处F7经过的2个代码片段
////////////////////////////////////////////////////////////
00412624  - FF25 58134000   jmp     dword ptr [401358]

733935A4    55              push    ebp
733935A5    8BEC            mov     ebp, esp
733935A7    6A FF           push    -1
733935A9    68 D0973A73     push    733A97D0
733935AE    68 FDBA4773     push    7347BAFD
733935B3    64:A1 00000000  mov     eax, dword ptr fs:[0]
733935B9    50              push    eax
733935BA    64:8925 0000000>mov     dword ptr fs:[0], esp
733935C1    51              push    ecx
733935C2    51              push    ecx
733935C3    83EC 4C         sub     esp, 4C
733935C6    53              push    ebx
733935C7    56              push    esi
733935C8    57              push    edi
733935C9    8965 E8         mov     dword ptr [ebp-18], esp
733935CC    8B75 08         mov     esi, dword ptr [ebp+8]
733935CF    8935 70E84973   mov     dword ptr [7349E870], esi
733935D5    8365 FC 00      and     dword ptr [ebp-4], 0
733935D9    8D45 A0         lea     eax, dword ptr [ebp-60]
733935DC    50              push    eax
733935DD    FF15 A0103973   call    dword ptr [733910A0]             ; kernel32.GetStartupInfoA
733935E3    0FB745 D0       movzx   eax, word ptr [ebp-30]
733935E7    A3 6CE84973     mov     dword ptr [7349E86C], eax
733935EC    FF35 D8E74973   push    dword ptr [7349E7D8]             ; RegMech.00400000
733935F2    56              push    esi
733935F3    BE 70E44973     mov     esi, 7349E470
733935F8    8BCE            mov     ecx, esi
733935FA    90              nop
733935FB    E8 5C000000     call    7339365C                         ; F8卡住了

脱壳

脱壳前的设置:
* 将异常检测选项恢复,都打上勾.
* 将hideod开启
* 在内存列表中,将目标程序的区段,全部改为全部可访问的属性.

用OllyDump脱2个版本(不带引入表修复和带引入表修复).
发现带引入表修复的dump操作运行后, OD的UI挂掉了(没反应)

根据这种场景,到了OEP之后, 只dump一个不带引入表修复的版本出来, 或者将OD最小化之后,等一会(1分钟左右), 等OD醒过来.

直接运行脱壳后的程序,报错:"不是有效的Win32程序"

修复导入表
使用ImpREC
* OEP填入 0001262C, 点击AutoSearch.
得到 RVA = 00001000, SIZE = 0000041C
---------------------------
Found something!
---------------------------
Found address which may be in the Original IAT. Try 'Get Import'.(If it is not correct, try RVA: 00001000 Size:00504538)
---------------------------
确定   
---------------------------

* 点击"Get Imports"
发现 rva = 00001048处的函数不识别, 其他函数都正常.
无效函数上面的函数是 : __vbaStrVarMove
无效函数下面的函数是 : __vbaFreeVarList
综合上面文的msvbvm60的API ord, 并不是按照顺序排列的, 也不好猜这个API的序号.
右击这个无效函数, 在菜单中选择反汇编, 看反汇编,也看不出是什么API.
选择HexView, 将函数的字节码抄下来,在msvbvm60.dll中搜索,看看是哪个函数?
有可能壳, 将这个API代码偷去了, 他不可能是自己写吧?

0113F261   55 8B EC 6A FF 68 D8 26 16 01 68 50 0D 16 01 64
0113F271   A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 10

在OD中切换到msvbvm60.dll中,搜索这32个字节码(2进制字符串查找)
没找到这32个特征码

在目标程序中找到了几个vb函数的调用点
008F2C7E     .  FF15 14144000 call    dword ptr [401414]               ;  MSVBVM60.__vbaFreeStr
008F2C84     .  C745 FC 04000>mov     dword ptr [ebp-4], 4
008F2C8B     .  68 00080000   push    800
008F2C90     .  FF15 8C114000 call    dword ptr [40118C]               ;  MSVBVM60.rtcSpaceBstr
008F2C96     .  8BD0          mov     edx, eax
008F2C98     .  8D4D C4       lea     ecx, dword ptr [ebp-3C]
008F2C9B     .  FF15 D0134000 call    dword ptr [4013D0]               ;  MSVBVM60.__vbaStrMove

去IAT看一下.
00401040  734768DF  MSVBVM60.__vbaLenBstr
00401044  73471766  MSVBVM60.__vbaStrVarMove
00401048  0113F261
0040104C  73497262  MSVBVM60.__vbaFreeVarList
00401050  734800FA  MSVBVM60._adj_fdiv_m64

果真,00401048就是被偷了一个Vb的API.

重新跑程序,在00401048下硬件写入断点,看看被偷走之前,写的是哪个API?
现在只有2个断点
* OEP 硬件执行断点
* 00401048 硬件写入断点(DWORD)
重新跑程序.

no.1    00401048  660CBDA8
no.2    00401048  0113F261

当被写时,跟出去,发现了写IAT的代码.
01157ACD      E8 14920000     call    01160CE6                                       ; jmp 到 msvcrt.memcpy
01157AD2      83C4 0C         add     esp, 0C
01157AD5      8D85 B4C4FFFF   lea     eax, dword ptr [ebp-3B4C]
01157ADB      50              push    eax
01157ADC      FFB5 B4C4FFFF   push    dword ptr [ebp-3B4C]
01157AE2      FFB5 BCC4FFFF   push    dword ptr [ebp-3B44]
01157AE8      8B85 00C7FFFF   mov     eax, dword ptr [ebp-3900]
01157AEE      0385 B8C4FFFF   add     eax, dword ptr [ebp-3B48]
01157AF4      50              push    eax
01157AF5      FF15 5C211601   call    dword ptr [116215C]                            ; kernel32.VirtualProtect
01157AFB      8B85 C0C4FFFF   mov     eax, dword ptr [ebp-3B40]
01157B01      8985 C09EFFFF   mov     dword ptr [ebp+FFFF9EC0], eax
01157B07      FFB5 C09EFFFF   push    dword ptr [ebp+FFFF9EC0]
01157B0D      E8 CE910000     call    01160CE0                                       ; jmp 到 msvcrt.operator delete

// 这里开始写IAT了, 011575AC处下硬件执行断点
011575AC      6A 01           push    1

为了跟踪00401048谁写的, 对00401044下硬件写入断点. 等00401044被写入时, 再仔细跟踪00401048怎么写.

01158D02               8B8D 58B9FFFF   mov     ecx, dword ptr [ebp+FFFFB958]                  ; 这里是系统API地址

堆栈 ss:[00128638]=0113F261
ecx=00127D28, (ASCII "__vbaEnd")

00127D28  5F 5F 76 62 61 45 6E 64 00 00 00 00 00 00 00 00  __vbaEnd........

00128638  61 F2 13 01 00 00 00 00 5F 5F 76 62 61 45 6E 64  a?....__vbaEnd
00128648  00 00 00 00 00 00 00 00 72 00 00 00 00 00 00 00  ........r.......

IAT中最终填的值是0113F261, 经过这里猜测, 对应的功能是__vbaEnd
00128638这里好像一个结构体, 前面放着函数指针,后面放着这个指针对应的函数名称.

先按IAT项 0113F261 为__vbaEnd,修复IAT试试.
在ImpREC中, 双击无效项,在弹出的API列表中选择__vbaEnd, 点击确定, 导入函数都有效了.

用ImpREC修复前面dump出来的2个版本.
ImpREC提示, 不能添加任何节.
用PETools重建PE(前面dump出来的2个版本).
再用ImpREC进行IAT修复, IAT修复成功.

测试脱壳后的程序
2个版本都可用, 开心啊:)

简便脱壳方法-CreateThread硬件执行断点

有的cm, 用异常计数法,次数非常多(e.g. 将近100次), 需要换CreateThread硬断点法.
这时, 对CreatThreaad下硬件断点, 返回用户领空后, 下面不远处,就是进入OEP的call.

做试验, 还是用的同一个cm, 注释都标注好了(做异常计数法时标注好的)
可以验证, 这种方法找OEP同样正确.
采用这种方法的原因是: 找个异常计数法次数少的cm(也是这种壳), 可以看到OEP处是执行了CreateThread之后过来的.

将OD异常检测选项都勾上, 对CreateThread下硬件执行断点.
F9将程序跑起来, 断在CreateThread.

7C8106C7 kernel32.CreateThread      8BFF            mov     edi, edi               ; ALT+F9返回返回用户领空
7C8106C9                            55              push    ebp
7C8106CA                            8BEC            mov     ebp, esp
7C8106CC                            FF75 1C         push    dword ptr [ebp+1C]
7C8106CF                            FF75 18         push    dword ptr [ebp+18]
7C8106D2                            FF75 14         push    dword ptr [ebp+14]
7C8106D5                            FF75 10         push    dword ptr [ebp+10]
7C8106D8                            FF75 0C         push    dword ptr [ebp+C]
7C8106DB                            FF75 08         push    dword ptr [ebp+8]
7C8106DE                            6A FF           push    -1
7C8106E0                            E8 D7FDFFFF     call    CreateRemoteThread
7C8106E5                            5D              pop     ebp
7C8106E6                            C2 1800         retn    18
011410FC       FF15 A0211601   call    dword ptr [11621A0]    ; kernel32.CreateThread
01141102       5E              pop     esi                    ; RegMech.0096AA30 一路F8返回到调用点
01141103       C9              leave
01141104       C3              retn

0115BEC7       A1 D81E1701     mov     eax, dword ptr [1171ED8]
0115BECC       59              pop     ecx
0115BECD       8B48 68         mov     ecx, dword ptr [eax+68]
0115BED0       3348 64         xor     ecx, dword ptr [eax+64]
0115BED3       3348 5C         xor     ecx, dword ptr [eax+5C]
0115BED6       F6C1 40         test    cl, 40
0115BED9       75 08           jnz     short 0115BEE3
0115BEDB       6A 01           push    1
0115BEDD       E8 15BEFDFF     call    01137CF7
0115BEE2       59              pop     ecx
0115BEE3       53              push    ebx
0115BEE4       C705 E0791601 A>mov     dword ptr [11679E0], 11687A4   ; ASCII "RC"
0115BEEE       E8 22EAFDFF     call    0113A915
0115BEF3       59              pop     ecx
0115BEF4       E8 8BE7FEFF     call    0114A684
0115BEF9       8BF8            mov     edi, eax
0115BEFB       A1 D81E1701     mov     eax, dword ptr [1171ED8]
0115BF00       8B48 7C         mov     ecx, dword ptr [eax+7C]
0115BF03       3348 68         xor     ecx, dword ptr [eax+68]
0115BF06       3348 10         xor     ecx, dword ptr [eax+10]
0115BF09       03F9            add     edi, ecx
0115BF0B       8B0E            mov     ecx, dword ptr [esi]
0115BF0D       3BCB            cmp     ecx, ebx
0115BF0F       75 2F           jnz     short 0115BF40
0115BF11       8B78 68         mov     edi, dword ptr [eax+68]
0115BF14       E8 6BE7FEFF     call    0114A684
0115BF19       8B0D D81E1701   mov     ecx, dword ptr [1171ED8]       ; RegMech.00964370
0115BF1F       FF76 14         push    dword ptr [esi+14]
0115BF22       8B51 7C         mov     edx, dword ptr [ecx+7C]
0115BF25       FF76 10         push    dword ptr [esi+10]
0115BF28       3351 10         xor     edx, dword ptr [ecx+10]
0115BF2B       FF76 0C         push    dword ptr [esi+C]
0115BF2E       33D7            xor     edx, edi
0115BF30       03C2            add     eax, edx
0115BF32       8B51 34         mov     edx, dword ptr [ecx+34]
0115BF35       3351 20         xor     edx, dword ptr [ecx+20]
0115BF38       33D7            xor     edx, edi
0115BF3A       2BC2            sub     eax, edx
0115BF3C       FFD0            call    eax
0115BF3E       EB 24           jmp     short 0115BF64
0115BF40       83F9 01         cmp     ecx, 1
0115BF43       75 22           jnz     short 0115BF67
0115BF45       FF76 04         push    dword ptr [esi+4]
0115BF48       FF76 08         push    dword ptr [esi+8]
0115BF4B       53              push    ebx
0115BF4C       E8 33E7FEFF     call    0114A684
0115BF51       50              push    eax
0115BF52       A1 D81E1701     mov     eax, dword ptr [1171ED8]
0115BF57       8B48 68         mov     ecx, dword ptr [eax+68]
0115BF5A       3348 34         xor     ecx, dword ptr [eax+34]
0115BF5D       3348 20         xor     ecx, dword ptr [eax+20]
0115BF60       2BF9            sub     edi, ecx
0115BF62       FFD7            call    edi                            ; F8程序跑起来了
0115BF64       8945 FC         mov     dword ptr [ebp-4], eax
0115BF67       8B45 FC         mov     eax, dword ptr [ebp-4]
0115BF6A       5F              pop     edi
0115BF6B       5E              pop     esi
0115BF6C       5B              pop     ebx
0115BF6D       C9              leave
0115BF6E       C3              retn

0115BF62处的call edi, F7进去后就是OEP

0041262C       68 1C364100     push    0041361C                       ; OEP
00412631       E8 EEFFFFFF     call    00412624                       ; F8卡住了, F7进去
00412636       0000            add     byte ptr [eax], al

后面的IAT修复,PE重建过程同异常计数法.
这壳用OllyDump脱的时候, 只能选非修复引用表方式.
如果选修复引用表方式, OD会挂掉, 不一定能恢复正常.
当ImpREC得到的导入函数没得到时,可以尝试在无效项上右击菜单 => Trace_Level1(Disasm)
脱壳-Armadillo1.x_第2张图片
脱壳-Armadillo1.x_第3张图片
ImpREC按照导入函数反汇编去找导入函数名称时, 有时能找对几个.
像这个cm, 则找的不对(将vbApi找成了GetModuleHandleA),遇到这种情况, 那就要自己去找缺失的导入函数名称(异常计数法里,找缺失的导入函数的方法,是通过追踪IAT里填导入函数地址的反汇编实现来做的,这是最朴素,最靠谱的方法).

你可能感兴趣的:(脱壳-Armadillo1.x)