首页
社区
课程
招聘
[旧帖] ProcPort/ASPack 2.12 的分析和手工脱壳 0.00雪花
发表于: 2008-1-25 19:14 5560

[旧帖] ProcPort/ASPack 2.12 的分析和手工脱壳 0.00雪花

2008-1-25 19:14
5560
[分析]
Aspack是Alexey Solodovnikov设计的一款压缩软件。你可以到http://www.aspack.com下载试用版。之所以选择版本2.12,纯粹是因为我手头的目标软件procport v3.0 final被PeiD识别为“ASPack 2.12 -> Alexey Solodovnikov”,procport可至http://www.cnasm.com下载。我不想去修改Peid的数据库的错误(以后有可能),或去研究aspack的版本2.12, 2.10, 1.20, 1.21…之间的细微差别在哪里,这两个对我的生活都没有意义,我只想在procport程序结束时,不要弹出网页,打扰我清净的世界,我就心满意足了
Procport V3.0 Final由二个文件组成,PeID检测的结果相同。首先从主程序文件入手。文件头被Aspack加入两个节,一个代码节,名为”.aspack”,大小为0x2000,一个数据节,名为”.adata”。其它没有什么特别之处。
开始分析程序。一开始二处花指令,使得IDA的分析结果与实际执行时指令序列不相同,按着实际执行指令序列走。到此处,获得程序基址,一般为0x00400000。
.aspack:004AF014 pop     ebp
.aspack:004AF015 mov     ebx, 0FFFFFFEDh
.aspack:004AF01A add     ebx, ebp
.aspack:004AF01C sub     ebx, 0AF000h
.aspack:004AF022 cmp     dword ptr [ebp+422h], 0
.aspack:004AF029 mov     [ebp+422h], ebx      ; 程序基址

利用GetModuleHandle()获取kernel32.dll的句柄,利用GetProcAddress()获取VirtualAlloc()和VirtualFree()两个函数的地址指针,然后进入解压缩的大循环。在解压缩循环中,调用VirtualAllo()分配指定的大小的虚拟内存。调用sub_4AF66C解压缩程序段。
.aspack:004AF0EE         push    dword ptr [ebp+156h] ; Param4 – 虚拟内存句柄2
.aspack:004AF0F4         push    dword ptr [esi+4] ; Param3 – 虚拟内存大小
.aspack:004AF0F7         push    eax         ; Param2 -  虚拟内存句柄1
.aspack:004AF0F8         push    ebx         ; Param1 – 起址
.aspack:004AF0F9         call    sub_4AF66C

下面代码段干扰分析,实际还是继续执行,因为C3是retn的机器码,call edi后立刻返回。
.aspack:004AF113 FF 37                   push    dword ptr [edi]
.aspack:004AF115 C6 07 C3                mov     byte ptr [edi], 0C3h
.aspack:004AF118 FF D7                   call    edi
.aspack:004AF11A 8F 07                   pop     dword ptr [edi]

修补Call调用,寄存器入栈保存可看作这一功能代码段的开始,寄存器出栈恢复可看作结束,初始化ESI为起址,ECX为长度。下面的代码段是将虚拟内存中解压缩成功的程序移回程序内存映像中。
.aspack:004AF16D 8B C8                   mov     ecx, eax
.aspack:004AF16F 8B 3E                   mov     edi, [esi]
.aspack:004AF171 03 BD 22 04 00 00       add     edi, [ebp+422h]
.aspack:004AF177 8B B5 52 01 00 00       mov     esi, [ebp+152h]
.aspack:004AF17D C1 F9 02                sar     ecx, 2
.aspack:004AF180 F3 A5                   rep movsd
.aspack:004AF182 8B C8                   mov     ecx, eax
.aspack:004AF184 83 E1 03                and     ecx, 3
.aspack:004AF187 F3 A4                   rep movsb

解压缩大循环结束后就是经典的装载输入函数的代码段,分析后可知,原始程序中的每一个代表DLL库的IMAGE_IMPORT_DESCRIPTOR、每一个代表DLL函数的IMAGE_IMPORT_BY_NAME都没有被破坏,可以直接使用。而且原程序的输入数据目录的指针也被硬编码进代码中。
.aspack:004AF278 BE 00 60 09 00          mov     esi, 96000h   ; 原程序的输入数据目录的指针
.aspack:004AF27D 8B 95 22 04 00 00       mov     edx, [ebp+422h]
.aspack:004AF283 03 F2                   add     esi, edx
.aspack:004AF285 ImportFunc:
.aspack:004AF285 mov     eax, [esi+0Ch] ; DLL文件的名字指针
.aspack:004AF288 test    eax, eax       ; 名字指针是否有效
.aspack:004AF28A jz      AllDone
.aspack:004AF290 add     eax, edx
.aspack:004AF292 mov     ebx, eax
.aspack:004AF294 push    eax
.aspack:004AF295 call    dword ptr [ebp+0F4Dh] ; 首先尝试用GetModuleHandleA获取DLL句柄
.aspack:004AF29B test    eax, eax
.aspack:004AF29D jnz     short loc_4AF2A6   ; 然后尝试用LoadLibraryA获取DLL句柄
.aspack:004AF29F push    ebx
.aspack:004AF2A0 call    dword ptr [ebp+0F51h]
.aspack:004AF2A6 mov     [ebp+545h], eax
.aspack:004AF2AC mov     dword ptr [ebp+549h], 0
                                  ; 进入获取函数地址的循环
.aspack:004AF2B6 mov     edx, [ebp+422h]
.aspack:004AF2BC mov     eax, [esi]
.aspack:004AF2BE test    eax, eax
.aspack:004AF2C0 jnz     short loc_4AF2C5
.aspack:004AF2C2 mov     eax, [esi+10h]
.aspack:004AF2C5 add     eax, edx
.aspack:004AF2C7 add     eax, [ebp+549h]
.aspack:004AF2CD mov     ebx, [eax]
.aspack:004AF2CF mov     edi, [esi+10h]
.aspack:004AF2D2 add     edi, edx
.aspack:004AF2D4 add     edi, [ebp+549h]
.aspack:004AF2DA test    ebx, ebx
.aspack:004AF2DC jz      loc_4AF384
.aspack:004AF2E2 test    ebx, 80000000h
.aspack:004AF2E8 jnz     short loc_4AF2EE ; 如果以指定Ordinal的方式调用
.aspack:004AF2EA add     ebx, edx      ; 如果以指定函数名的方式调用
.aspack:004AF2EC inc     ebx
.aspack:004AF2ED inc     ebx           ; ebx是指向函数名字的指针
.aspack:004AF2EE push    ebx
.aspack:004AF2EF and     ebx, 7FFFFFFFh
.aspack:004AF2F5 push    ebx
.aspack:004AF2F6 push    dword ptr [ebp+545h]
.aspack:004AF2FC call    dword ptr [ebp+0F49h] ; 调用GetProcAddress()获取函数指针
.aspack:004AF302 test    eax, eax
…… 略,略,略
.aspack:004AF373 push    edi
.aspack:004AF374 jmp     short loc_4AF3C0
.aspack:004AF376 loc_4AF376:         ; CODE XREF: start+304 j start+35D j
.aspack:004AF376 mov     [edi], eax
.aspack:004AF378 add     dword ptr [ebp+549h], 4
.aspack:004AF37F jmp     loc_4AF2B6

.aspack:004AF384 mov     [esi], eax             ; 获取完毕这个DLL文件的输入函数的地址
.aspack:004AF386 mov     [esi+0Ch], eax         ; 将I_I_Descriptor破坏掉
.aspack:004AF389 mov     [esi+10h], eax
.aspack:004AF38C add     esi, 14h
.aspack:004AF38F mov     edx, [ebp+422h]
.aspack:004AF395 jmp     ImportFunc            ; 继续循环

AllDone是在返回OEP之前的最后一段代码,分析可知,OEP被硬编码进最后一段。

.aspack:004AF39A AllDone:           
.aspack:004AF39A mov     eax, 9243Ch          ; OEP为9243C
.aspack:004AF39F push    eax
.aspack:004AF3A0 add     eax, [ebp+422h]
.aspack:004AF3A6 pop     ecx
.aspack:004AF3A7 or      ecx, ecx
.aspack:004AF3A9 mov     [ebp+3A8h], eax
.aspack:004AF3AF popa
.aspack:004AF3B0 jnz     short loc_4AF3BA
.aspack:004AF3B2 mov     eax, 1
.aspack:004AF3B7 retn    0Ch
.aspack:004AF3BA
.aspack:004AF3BA loc_4AF3BA:         ; CODE XREF: start+3AF j
.aspack:004AF3BA push    0
.aspack:004AF3BF retn

[手工脱壳]

在装载输入函数之前转储,可以保留住原程序的输入数据目录。
修改文件头。
修改AddressOfEntryPoint/IOH :OEP被硬编码进壳的最后一段,为9243C,。
修改IMAGE_OPTIONAL_HEADER中的数据目录第二项——输入数据目录:VirtualAddress被硬编码进壳中,为96000。观察以96000为起址的节大小为3000,Size修改为3000。
完成修改后,脱壳程序现在可以运行。

[修改]

坐下来静静想想,程序结束时打开网页,最简单地一种方式就是调用ShellExecute()。在程序的输入表中发现了ShellExecuteA这一项,在程序运行后下断点,关闭程序时触发中断,来到此处。将push 1修改为jmp $+1A,机器码由6A 01改为EB 18。成功。
CODE:004921BD push    1            ; 修改这里,跨过调用ShellExecute
CODE:004921BF push    0
CODE:004921C1 push    offset unk_4921D8
CODE:004921C6 push    offset aHttpWww_cnasm_ ; "HTTP:\\\\WWW.CNASM.COM"
CODE:004921CB push    offset aOpen ; "open"
CODE:004921D0 push    0
CODE:004921D2 call    ShellExecuteA

文章到此结束。当在脱壳和分析代码的过程中,发现:如果文件改名,程序主界面无任何显示。脑袋中没有什么灵感,下一篇文章再解决吧。
跟以往一样,在程序中留点记号吧。下面图片中的窗口的标题已经被改为“TNTTOOLS到此一游”。


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 0
支持
分享
最新回复 (2)
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
先学习一下,长长见识。谢谢
2008-1-26 18:26
0
雪    币: 297
活跃值: (27)
能力值: ( LV13,RANK:380 )
在线值:
发帖
回帖
粉丝
3
续1-ProcPort/ASPack 2.12 的分析和手工脱壳
上一篇文章提到:“当在脱壳和分析代码的过程中,发现:如果文件改名,程序主界面无任何显示。脑袋中没有什么灵感,下一篇文章再解决吧。”
一般出现这种情况,是因为程序把自己的名字硬编码进数据区,但查遍了经过脱壳的procport.exe,一点踪迹都没有。试着沿着GetModuleFileNameA(W)这条线去找,程序中使用到的有两处:
(1)
CODE:00405A02 E8 F1 B8 FF FF          call    GetModuleFileNameA
CODE:00405A07 8B C4                   mov     eax, esp
返回值被直接覆盖,不是此处
(2)
CODE:00405C3C E8 B7 B6 FF FF          call    GetModuleFileNameA
CODE:00405C41 C6 45 EE 00             mov     [ebp+String2], 0
CODE:00405C45 8D 45 F8                lea     eax, [ebp+hKey]
返回值被直接覆盖,不是此处

这样的话,我只好把希望放在procport.dll上。把procport.dll脱壳后,发现了这个地方。

.text:100026EC 6A 0D                   push    0Dh
.text:100026EE 8D 81 C8 6E 0A 10       lea     eax, aWArtReProcport30f_0[ecx] ; ""
.text:100026F4 68 30 1B 01 10          push    offset aProcport_exe ; "\\ProcPort.exe"
.text:100026F9 50                      push    eax         ; lpMultiByteStr
.text:100026FA E8 D2 46 00 00          call    sub_10006DD1
.text:100026FF 83 C4 04                add     esp, 4
.text:10002702 50                      push    eax
.text:10002703 E8 C8 45 00 00          call    sub_10006CD0
.text:10002708 83 C4 0C                add     esp, 0Ch
.text:1000270B 85 C0                   test    eax, eax
.text:1000270D 75 07                   jnz     short loc_10002716
.text:1000270F C6 05 D1 6F 0A 10 01    mov     byte_100A6FD1, 1

很明显,函数sub_10006CD0的作用就是判断两个文件名是否相等,如果相等,将布尔变量
byte_100A6FD填为1,否则仍旧为零。
将.text:1000270D处的机器码75 07改为90 90,大功告成。
Enjoy it. By TNTTOOLS
2008-1-27 13:50
0
游客
登录 | 注册 方可回帖
返回
//