|
正如你能猜到的,Armadillo 储存了已经解码的内存块数量,以确保在任何时刻,并非所有的块都被同时解码到内存中。如果你查看"允许解码块数的最大值",你将会看到Armadillo通过把.text size除以1000h (单个内存块的大小)然后再除以2,来获得此值。这里你有两种方法, 给跳转打补丁以确保它始终跳转或者我们可以改变"允许解码块数的最大值"为某些很大的值如1000h,!!!!
看一下dump窗口
006106A4 C5 00 00 00 00 00 00 00 Å...
.text size187D90/1000/2=C5
做完这些后,按F12我们将在Armadillo"server"的调试循环中了。调试循环代码将产生页面异常的地址进行页对齐,并在005F7831 CALL 005F87A8解码。
注意:这是在找到OEP后单步顺着走下来的。
005F7773 LOOP:
; 从这里开始强迫循环
005F7773 . 8B8D 2CFAFFFF MOV ECX,DWORD PTR SS:[EBP-5D4]
; 解码整个代码段
005F7779 . 3B0D C43A6100 CMP ECX,DWORD PTR DS:[613AC4]
005F777F . 0F8D C7000000 JGE getright.005F784C
;change to "jmp eip",当完成后进入死循环
005F7785 . 8B95 9CFAFFFF MOV EDX,DWORD PTR SS:[EBP-564]
;SS:[EBP-564] =[ebp+trap_flag_not_set_flag]
;armadillo在开始之前设置了一个flag,可以解码时ECX被置0了
005F778B . 81E2 FF000000 AND EDX,0FF
005F7791 . 85D2 TEST EDX,EDX
;its debug loop to check if it is being traced(edx=edx and 0FFh=000h)
005F7793 . 0F84 A9000000 JE getright.005F7842
; 现在检测flag!
005F7799 . 6A 00 PUSH 0
; instruct to 解码 code
005F779B . 8BB5 2CFAFFFF MOV ESI,DWORD PTR SS:[EBP-5D4]
;SS:[EBP-5D4]= [ebp+mem_块]
005F77A1 . C1E6 04 SHL ESI,4
005F77A4 . 8B85 2CFAFFFF MOV EAX,DWORD PTR SS:[EBP-5D4]
;SS:[EBP-5D4]= [ebp+mem_块]
----------SNIP--------------- ; 解码 key Generation
005F781B . 83E7 0F AND EDI,0F
005F781E . 03F7 ADD ESI,EDI
;反汇编
005F7820 . 8B15 B43A6100 MOV EDX,DWORD PTR DS:[613AB4]
005F7826 . 8D04B2 LEA EAX,DWORD PTR DS:[EDX+ESI*4]
005F7829 . 50 PUSH EAX
; push crypt_flag
005F782A . 8B8D 2CFAFFFF MOV ECX,DWORD PTR SS:[EBP-5D4]
;SS:[EBP-5D4][ebp+mem_块]
005F7830 . 51 PUSH ECX 005F7831 . E8 720F0000 CALL getright.005F87A8
;call了005F87A8解码,进入这个call,走几步就到了005F88C7
;也就是API WriteProcessMemory返回的地方<, /P>
005F7836 . 83C4 0C ADD ESP,0C
;你应该回到这里
005F7839 . 25 FF000000 AND EAX,0FF
005F783E . 85C0 TEST EAX,EAX
;这里打补丁去增加内存块的数量,变值强迫解码下一个内存块,然后跳回循坏。
005F7840 . 74 0A JE SHORT getright.005F784C
现在我们知道Armadillo如何为每个内存块 generates keys,然后把它传递解码routine。 同样的, 我们可以理解为什么当我们单步跟踪调试"server-debugger code"时Armadillo会悄无声息的退出了。这里,我们应该使得包含key generation routine的大loop去强迫armadillo 解码整个代码段。
首先,应该修改计数 byte 005F88EE 83C0 01 ADD EAX,1改为ADD EDX,0,只改了一个byte。目的就是防止父进程把解码过的页面从新加密,并且确保005F8944 0F8E FA000000 JLE getright.005F8A44始终跳转去继续解码。DS:[6106A4]存放着允许解码块数的最大值,如果将其改为某个很大的值,那么内存会崩溃的。而且这个值本来就是对的正好对应了代码段的大小,所以不要动它。然后,在地址005F783E处,打两行补丁代码:
INC DWORD PTR SS:[EBP-5D4]
JMP LOOP:005F7773 ;跳回循环头
然后我们edit在"ebp+mem_块"处的值为0 (告诉Armadillo从第一个内存块开始解码), 并且设置终止点于 005F777F 通过改变那儿的指针为"jmp eip"。这儿Armadillo在检查内存块是否超过了代码段,我们简单的设了一个无限循环在那儿。让程序运行, 等一会儿以后启动LordPE 去dump 整个内存映像。 如果LordPE 报告"Can’t grab memory"那么你可能做错了什么,Armadillo 没有完全解码代码段。完成这一步, 我们进入下一阶段rebuild IAT。
另外,还有一个地方要注意,最好在OEP处挂起进程再dump,因为这时程序的初始化变量还没有被修改。大家可对比一下,当程序运行后dump出的文件和在OEP处dump出的有何不同。
有时会修改PE头(本例未使用) 被加壳的程序运行后,用procdump没法dump出,会非法操作。用ring3的调试器没法 “attach”,用peditor dump出的文件是无效的exe。为什么呢?通过比较dump出的PE头, 发现偏移0x3C处被修改。重新装入,7ffdf002改字节。Bp WriteProcessMemory运行一下,断下后,设断400003c内存写入 ,运行 共修改3C和FE两处,参考有关PE头的资料,可知偏移3C的DWORD是PE表头的偏移(原值是F8)。偏移FE的WORD是sections 的个数(原值是8)。Armadillo故意将PE头改错,难怪没法dump出。解决方法:在41EF80下断点。中断后,将PE头改回,40003C处是000000F8,4000FE处是0008,注意高位在前!!!
第二关Rebuild Import data
(四)修复IAT
没什么方便的方法!:(
我的方法是用peditor查看,得知IAT在426000处,下断点“bpm 426000 w” 在这停下:
然后把[ESI]前后的内容保存下来,以后手工修复IAT时参考。
用LordPE打开dump 下来的文件然后研究section header, 你将会发现import data应该在section.idata1 为什么。因为名字name已经告诉了……你可以再确认一下,用Hex Workshop打开文件然后去那个section的偏移地址,你将会看到诸如"kernel32.dll" "user32.dll" 等等分散的字符…… Import data应该就在那儿!
我们的任务是找到API redirection routine, 研究它,然后在此基础去rebuild Import。
为了找到IAT redirection routine,使用softice 的"addr"命令进入被保护子进程的领空,然后bpm IAT_address W(一旦中断,disable 这个断点) bpx GetProcAddress(一旦中断,disable 这个断点) F12 两次,我们现在应该在这儿。
10006622 39 3D E8 C7 01 10 cmp dll_handle_table,edi
00A4A496 load_next_dl_import:
那个dll_handle_Table看起来象这样的:
1001C7E8 18 C8 01 10 dd offset strKernel32_dll
上一页 1 2 3 4 下一页 |