Krypton v0.3加的壳就是一大堆的
PUSH ECX
JMP xxxxxxxx
POP ECX
JMP xxxxxxxx
令人看到就烦, 还有就是还原程序除了call API外极少见到call, ret指令,
我们的F12就没用武之地, 想偷懒都不行, 要找到OEP还真的不容易.
尽管已脱过该壳, 还没有想到十分有效, 快捷找OEP的方法. 有都是要按F8很久才找到.
要是从程序入口开始看, 程序先是找kernel32.dll的ImageBase(exe中不用Import的方法),
再找GetProcAddress的地址, 好“长”的一段程序(一大堆花指令), 然后就.....(烦!)
下面说说怎么找OEP, 加壳程序一定要还原原程序吧, 一般程序的imagebase是400000,
section alignment是1000, 我们可以 bpmb cs:401001 w (为什么不是401000 ? 第一个
一般是比较特殊的, 我们就用第二个), 然后 g, 看 g了多少次原程序就运行, 就从最后
一次看起, 跳出该还原程序, 我看到的是:
dec ecx
jnz continue_restore ; 还没有还原完就跳
jmp xxxxxxxx
之后是:
dec esi ; 还剩的section数
jnz continue_restore_next_section ; 还没有还原完所有的section就跳
jmp xxxxxxxx
经过一阵的F8后来到:
016F:006F25D0 CMP WORD [EBP+00406596],FEEB
016F:006F25D9 JNZ NEAR 006F086E
016F:006F25DF MOV [EBP+0040764C],EAX
016F:006F25E5 MOV DWORD [EBP+00407650],00
016F:006F25EF CMP DWORD [EBP+0041CD81],BYTE +00
016F:006F25F6 JNZ 006F261E
016F:006F25F8 MOV EDX,[EBP+00407665]
016F:006F25FE ADD EDX,[EBP+00407660] ; EDX =
OEP
016F:006F2604 MOV [EBP+0041CD81],EDX
016F:006F260A MOV EDX,004077ED
016F:006F260F ADD EDX,EBP
016F:006F2611 PUSH EDX
016F:006F2612 PUSH DWORD [WORD FS:00]
016F:006F2618 MOV [WORD FS:00],ESP
016F:006F261E MOV EDX,[EBP+00407660]
016F:006F2624 MOV EAX,[ESI]
016F:006F2626 OR EAX,EAX
016F:006F2628 JNZ 006F262D
016F:006F262A MOV EAX,[ESI+10]
016F:006F262D ADD EAX,EDX
016F:006F262F ADD EAX,[EBP+00407650]
016F:006F2635 MOV EBX,[EAX]
016F:006F2637 MOV EDI,[ESI+10]
016F:006F263A ADD EDI,EDX
016F:006F263C ADD EDI,[EBP+00407650]
016F:006F2642 TEST EBX,EBX
016F:006F2644 JZ NEAR 006F3016
; 处理完Import table就跳
016F:006F264A TEST EBX,11000000
016F:006F376B MOV BYTE [EBX],00
; 清空运行过的代码
016F:006F376E INC EBX
016F:006F376F CMP EBX,ECX
016F:006F3771 JNZ 006F376B
016F:006F3773 SUB EAX,EAX
016F:006F3775 MOVZX ECX,WORD [ESI+EDX+06]
016F:006F377A SHL EAX,05
016F:006F377D SHL ECX,03
016F:006F3780 MOV [EAX],ECX ;
Raise exception!
dd fs:0
37BF:0000 0065FE08 xxxxxxxx xxxxxxxx xxxxxxxx
dd ds:65FE08
0177:0065FE08 0065FF68 006F3825 xxxxxxxx xxxxxxxx
u cs:6F3825
016F:006F3825 MOV EAX,`DOSMGR_BackFill_Allowed`
016F:006F382A MOV ESP,[EAX]
016F:006F382C POP DWORD [WORD FS:00]
016F:006F3832 CALL 006F3837
016F:006F3837 POP EBP
016F:006F3838 SUB EBP,004077FF
016F:006F383E CMP BYTE [EBP+0040948A],FF ; K-Execution
?
016F:006F3845 JZ 006F3858
; jump when yes ?
016F:006F3847 MOV ECX,[EBP+0041CD7A]
016F:006F384D MOV [ESP],ECX
016F:006F3850 MOV EDX,[EBP+0041CD81]
016F:006F3856 JMP EDX
; jump to OEP
016F:006F3858 CALL 006F385D
016F:006F385D POP EBP
016F:006F385E SUB EBP,00407825
016F:006F3864 JMP SHORT 006F38A4
如果是K-Execution则将 FF1500000000 替换为 FF15xxxxxxxx :
即 CALL NEAR [00000000] --> CALL NEAR [xxxxxxxx], 用来动态还原代码.
跟着是将 CALL NEAR [00000001] 替换为 ? (不知道:) (难道是K-Loader?)
好, 先bpx OEP, dump file, 再用Import REConstructor Get Import, 可以得到Import table的RVA,
但不知道是哪个API.
如: rva:00006000 ptr:0067001F
u 67001F
016F:0067001F ADD DWORD [0067003A],75188466
;[0067003A] --> 4AE04B7A
016F:00670029 MOV EAX,[0067003A]
;eax = BFF8CFE0 SetHandleCount
016F:0067002E SUB DWORD [0067003A],75188466
016F:00670038 JMP EAX
这下可就有点麻烦了, 怎样才能重建Import table呢? 最初是想用程序来把上面的代码替换为
JMP BFF8CFE0 的, 但经过细看其重定向过程, 发现只需改一下该过程, 就可以直接把 BFF8CFE0
放到rva:00006000里去. 先简单说一下其重定向过程如下:
eax = GetProcAddress
pusha
生成016F:016F:0067001F处的代码
popa
mov eax, [ebp+xxxxxxxx] ; [ebp+xxxxxxxx] = 0067001F , 将这句nop掉, eax 就是
BFF8CFE0, 就这样搞定Import table的问题
mov [406000], eax
跟着就是还原K-Execution的 call 为 push 代码:
K-Execution的描述请看上面的贴, 这里不重复了. 加壳程序是靠返回地址来动态还原代码的,
而且都是用同一个地址的还原程序(上面所说的 CALL NEAR [00000000] --> CALL NEAR [xxxxxxxx],
而 CALL NEAR [00000001] --> ? 的, 因为我加壳后的程序没有, 所以暂且忽律, 我想是同理).
我们可以写一程序, 在还原后的程序里查找 CALL NEAR [xxxxxxxx], 机器码是 FF15xxxxxxxx,
先push我们要其返回的地址, 再将找到后的地址加6(push ... 为6个字节)入栈,
再跳到[xxxxxxxx]让其来还原, 呵呵, 我们就像是坐收渔人之利.
当然其还原程序还要作些修改, 就是只让其还原我们想要的 push ..., push 之后的指令不让其改动, 就是:
MOV WORD [ECX+06], 15FF
MOV [ECX+08], EDX
把这两句nop掉(幸好这里没有自检), 最后在ret指令前, 将我们push进去的查找地址出栈后才执行ret指令回到到我们写的程序继续执行.
程序如下, 写得很丑, 见笑了.
要是直接用汇编写就更好, 最后就是把这段程序搬到被加壳的程序里, 放哪里? 不用说了吧:)
void GetDumpAddr(LPVOID pmapbase, DWORD dwSize, unsigned char *restore_proc)
{ //假设我们的pmapbase=0x401000, restore_proc为还原程序地址
unsigned long i, fixaddr;
for(i=0;i<dwSize-6;)
{ //我这里查找 FF15A78D7000
if (*(DWORD *)((unsigned char*)pmapbase+i) == 0x8da715ff &&
*(DWORD *)((unsigned char*)pmapbase+i+2) == 0x00708da7)
{
fixaddr = (unsigned long)(unsigned char*)pmapbase + i +
6;
__asm push offset conti //运行完还原程序的返回地址, 实际搬到被加壳程序空间后看看要不要改
__asm push fixaddr //找到的地址
__asm jmp restore_proc //跳到还原程序
conti:
i+=6;
}
else
i++;
}
return;
}
- 标 题:脱Krypton The Krypter v0.3加的壳 (5千字)
- 作 者:fs0
- 时 间:2001-7-21 19:52:49
- 链 接:http://bbs.pediy.com