小资料:ASPr API修复
kongfoo/2004.6.22
ASPr处理后有部分API已经面目全非,手动分析会毫无头绪,只能
靠经验或插件,下面记录一下ASPr对一些API的处理,手动分析起来就
事半功倍了。
代码:
kernel32.GetCommandLineA: 00D9139C 6A 00 PUSH 0 00D9139E E8 B53DFFFF CALL 00D85158 ; JMP to kernel32.GetModuleHandleA 00D913A3 FF35 E46CD900 PUSH DWORD PTR DS:[D96CE4] 00D913A9 58 POP EAX 00D913AA 8B05 F46CD900 MOV EAX,DWORD PTR DS:[D96CF4] ==d96cf4放的是命令行参数 00D913B0 C3 RETN
这个是比较简单的,前面的都是烟雾弹,最后mov eax,[xx]实现了原
API的功能。
代码:
kernel32.GetModuleHandleA: 00D9133C 55 PUSH EBP 00D9133D 8BEC MOV EBP,ESP 00D9133F 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8] 00D91342 85C0 TEST EAX,EAX 00D91344 75 07 JNZ SHORT 00D9134D 00D91346 A1 7869D900 MOV EAX,DWORD PTR DS:[D96978] ==d96978放的是40000,哪么这个是GetModuleHandleA的功能了 00D9134B EB 06 JMP SHORT 00D91353 00D9134D 50 PUSH EAX 00D9134E E8 053EFFFF CALL 00D85158 ; JMP to kernel32.GetModuleHandleA 00D91353 5D POP EBP 00D91354 C2 0400 RETN 4
这个也是根据返回值就能判断出API的例子。
代码:
kernel32.GetProcAddress: 00D90EE8 55 PUSH EBP 00D90EE9 8BEC MOV EBP,ESP 00D90EEB 8B55 0C MOV EDX,DWORD PTR SS:[EBP+C] 00D90EEE 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8] 00D90EF1 8B0D 3C54D900 MOV ECX,DWORD PTR DS:[D9543C] 00D90EF7 8B09 MOV ECX,DWORD PTR DS:[ECX] 00D90EF9 3BC8 CMP ECX,EAX 00D90EFB 75 09 JNZ SHORT 00D90F06 00D90EFD 8B0495 5053D900 MOV EAX,DWORD PTR DS:[EDX*4+D95350] 00D90F04 EB 07 JMP SHORT 00D90F0D 00D90F06 52 PUSH EDX 00D90F07 50 PUSH EAX 00D90F08 E8 5342FFFF CALL 00D85160 ; JMP to kernel32.GetProcAddress 00D90F0D 5D POP EBP 00D90F0E C2 0800 RETN 8
上面GetModuleHandleA的例子告诉我们这种情形的答案:GetProcAddress。
代码:
kernel32.GetVersion: 00D91358 6A 00 PUSH 0 00D9135A E8 F93DFFFF CALL 00D85158 ; JMP to kernel32.GetModuleHandleA 00D9135F FF35 E46CD900 PUSH DWORD PTR DS:[D96CE4] ==d96ce4放的是版本信息,API是GetVersion 00D91365 58 POP EAX 00D91366 C3 RETN
这个和GetCommandLineA是一样的了,根据返回值即可判断出API。
代码:
kernel32.GetCurrentProcess: 00D91388 MOV EAX,[D96CE8] ==d96ce8放的是-1 00D9138D RETN
这个是用插件找出来的,积累经验,(至少XP是)以-1作为当前进程句柄的,
所以以后遇到这个情况就好处理了。
代码:
kernel32.LockResource: 00D913B4 55 PUSH EBP 00D913B5 8BEC MOV EBP,ESP 00D913B7 8B05 F46CD900 MOV EAX,DWORD PTR DS:[D96CF4] 00D913BD 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8] 00D913C0 5D POP EBP 00D913C1 C2 0400 RETN 4
这个是也用插件找出来的,积累一下经验。再看看原版LockResource的代码:
代码:
77E5C931 > 8B4424 04 MOV EAX,DWORD PTR SS:[ESP+4] 77E5C935 C2 0400 RETN 4
以上资料来自CrystalButton 1.40A ASP1.23RC1
==========================================
代码:
user32.CharNextA: 00970FE4 A1 60D0D677 MOV EAX,DWORD PTR DS:[77D6D060] ==已经去掉花指令 00970FE9 F640 02 04 TEST BYTE PTR DS:[EAX+2],4 00970FED 56 PUSH ESI 00970FEE 8B7424 08 MOV ESI,DWORD PTR SS:[ESP+8] 00970FF9 - 0F85 6F433D77 JNZ USER32.77D4536E 00970FFF 803E 00 CMP BYTE PTR DS:[ESI],0 0097100B - 0F84 F5623A77 JE USER32.77D17306 00971011 46 INC ESI 00971012 8BC6 MOV EAX,ESI 00971014 5E POP ESI 00971019 68 0973D177 PUSH 77D17309 ==这种类型的API处理就最简单了,根据这个地址就可以找到API 0097101E C3 RETN kernel32.GetModuleHandleA: 009712D4 837C24 04 00 CMP DWORD PTR SS:[ESP+4],0 009712E0 - 0F84 DB924E77 JE kernel32.77E5A5C1 009712E6 FF7424 04 PUSH DWORD PTR SS:[ESP+4] 009712EF 68 A79FE577 PUSH 77E59FA7 009712F8 55 PUSH EBP 009712F9 8BEC MOV EBP,ESP 009712FB 51 PUSH ECX 009712FC 51 PUSH ECX 009712FD 56 PUSH ESI 009712FE 64:A1 18000000 MOV EAX,DWORD PTR FS:[18] 00971304 FF75 08 PUSH DWORD PTR SS:[EBP+8] 00971307 8DB0 F80B0000 LEA ESI,DWORD PTR DS:[EAX+BF8] 0097130D 8D45 F8 LEA EAX,DWORD PTR SS:[EBP-8] 00971310 50 PUSH EAX 00971315 68 15A8E577 PUSH 77E5A815 0097131A C3 RETN
这个GetModuleHandleA和上面asp1.23rc1又有所不同,是将整API的代码
搬了过来,其处理API里面的调用(CALL)方法很值得学习一下。
代码:
原API代码: 77E59F93 > 837C24 04 00 CMP DWORD PTR SS:[ESP+4],0 77E59F98 0F84 23060000 JE kernel32.77E5A5C1 77E59F9E FF7424 04 PUSH DWORD PTR SS:[ESP+4] 77E59FA2 E8 55080000 CALL kernel32.77E5A7FC 77E59FA7 85C0 TEST EAX,EAX 77E59FA9 74 08 JE SHORT kernel32.77E59FB3 77E59FAB FF70 04 PUSH DWORD PTR DS:[EAX+4] 77E59FAE E8 B0060000 CALL kernel32.GetModuleHandleW 77E59FB3 C2 0400 RETN 4 77E5A7FC 55 PUSH EBP 77E5A7FD 8BEC MOV EBP,ESP 77E5A7FF 51 PUSH ECX 77E5A800 51 PUSH ECX 77E5A801 56 PUSH ESI 77E5A802 64:A1 18000000 MOV EAX,DWORD PTR FS:[18] 77E5A808 FF75 08 PUSH DWORD PTR SS:[EBP+8] 77E5A80B 8DB0 F80B0000 LEA ESI,DWORD PTR DS:[EAX+BF8] 77E5A811 8D45 F8 LEA EAX,DWORD PTR SS:[EBP-8] 77E5A814 50 PUSH EAX 77E5A815 FF15 8C10E477 CALL DWORD PTR DS:[<&ntdll.RtlInitAnsiSt>; ntdll.RtlInitAnsiString 77E5A81B 6A 00 PUSH 0 77E5A81D 8D45 F8 LEA EAX,DWORD PTR SS:[EBP-8] 77E5A820 50 PUSH EAX 77E5A821 56 PUSH ESI 77E5A822 FF15 1C61EB77 CALL DWORD PTR DS:[77EB611C] ; ntdll.RtlAnsiStringToUnicodeString 77E5A828 85C0 TEST EAX,EAX 77E5A82A 0F8C 19000200 JL kernel32.77E7A849 77E5A830 8BC6 MOV EAX,ESI 77E5A832 5E POP ESI 77E5A833 C9 LEAVE 77E5A834 C2 0400 RETN 4
以上资料来自asp1.3b的unpackme(notepad.exe)。这个版本的壳把FF15的CALL
都变成:
00401101 FF15 D80F9700 CALL DWORD PTR DS:[970FD8]
CALL到壳申请的空间了,哪么程序空间里面就不需要有IAT信息了,ImpREC
就会找不到IAT(提示Could not find anything good at this OEP)。
==============================================================
再来到asp1.4,壳把程序中的FF15 xxxxxxxx改成E8 xxxxxxxx xx,最后一个字节
是随机的。而且去伪API前还有一段代码:
代码:
00401268 E8 83FF8C00 CALL 00CD11F0 00CD11F0 BA 5A904800 MOV EDX,48905A 00CD11F5 BA D2E14400 MOV EDX,44E1D2 00CD11FA 58 POP EAX 00CD11FB 83C0 01 ADD EAX,1 00CD11FE 50 PUSH EAX 00CD11FF 68 800FCD00 PUSH 0CD0F80 00CD1204 C3 RETN 00CD0F80 55 PUSH EBP 00CD0F81 8BEC MOV EBP,ESP 00CD0F83 83EC 0C SUB ESP,0C ......
但具体对API的处理还是差不多。
================================
asp2.0a对FF15的处理既有1.3b的模式又有1.4的模式,但采用1.3b模式处理的
CALL和1.3b又有点不同。
举个例子:
1.3b:
call [900000] ==900000放的是9000xx(跟着900000)即伪API的地址。
即所CALL的地址后面就是伪API代码,没有伪API地址表。
call [9001ba] ==接着的一个CALL会是相隔比较远的地址。
2.0a:
call [900000] ==900000是伪API地址表项目,有伪API地址表。
call [900004] ==接着的CALL的地址是地址表相应的项目。