• 标 题:小资料:ASPr API修复
  • 作 者:kongfoo
  • 时 间:004-07-02,11:24
  • 链 接:http://bbs.pediy.com

小资料: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的地址是地址表相应的项目。