• 标 题:Arm3.70a对IAT保护的一点心得
  • 作 者:fxyang
  • 时 间:2004年3月22日 11:44
  • 链 接:http://bbs.pediy.com

Arm3.61版后加强了对IAT解码的保护,这里只谈到IAT解码前的保护代码跟踪心得。
本次使用的程序是goodmorning发在http://bbs2.pediy.com/viewtopic.php?t=5395&sid=9f24b627dcfe6d35be45f9f2244142a7
的Armadillo 3.70完全版加的记事本。
前面都是定式了,不要我说……
我从bp OpenMutexA 后,修改代码完成,F9运行再次被中断在OpenMutexA函数的入口地址处开始:

去掉以前的所有断点,bp VirtualProtect F9运行,中断后看看堆栈中:
0012F484   0101FAC6  /CALL 到 VirtualProtect 来自 notepad.0101FAC0
0012F488   009A1000  |Address = 009A1000         <--这里是代码解码的开始
0012F48C   00029CCA  |Size = 29CCA (171210.)
0012F490   00000040  |NewProtect = PAGE_EXECUTE_READWRITE
0012F494   0012F4B0  pOldProtect = 0012F4B0


一直F9运行4次,到堆栈中:
0012F484   0101FAC6  /CALL 到 VirtualProtect 来自 notepad.0101FAC0
0012F488   009DE000  |Address = 009DE000         <--代码解码完成地址
0012F48C   00003216  |Size = 3216 (12822.)
0012F490   00000002  |NewProtect = PAGE_READONLY
0012F494   0012F4B0  pOldProtect = 0012F4B0

如果再次F9运行,就会出现第一个anti “错误:不知道如何在地址009C7E13处绕过命令……”,这说明程序开始在解码的代码中运行
并且运行到第一个有效验的地方,关闭OD的这个提示窗口,F12就会来到:
009C7E0E   >PUSH 9C7E16
009C7E13   >???                ; 未知命令  <--就是这个anti
009C7E15   >IRETD

向上看看:
009C7D59   >PUSH EBP
009C7D5A   >MOV EBP,ESP
009C7D5C   >PUSH ECX
009C7D5D   >PUSH EBX
009C7D5E   >XOR EBX,EBX
009C7D60   >CMP BYTE PTR DS:[9D9075],BL
009C7D66   >PUSH ESI
009C7D67   >PUSH EDI
009C7D68   >JNZ SHORT 009C7D7B
009C7D6A   >CMP BYTE PTR DS:[9D8CB1],BL
009C7D70   >JNZ SHORT 009C7D7B
009C7D72   >CALL 009A72FD
009C7D77   >TEST EAX,EAX
009C7D79   >JNZ SHORT 009C7D82
009C7D7B   >XOR AL,AL
009C7D7D   >JMP 009C7EAE
009C7D82   >MOV DWORD PTR SS:[EBP-4],EBX
009C7D85   >MOV DWORD PTR DS:[9D8CD8],EBX
009C7D8B   >PUSH ECX
009C7D8C   >BSWAP ECX
009C7D8E   >NOT ECX
009C7D90   >PUSH EAX
009C7D91   >NOT EAX
009C7D93   >MOV EAX,6C65696D
009C7D98   >XCHG EAX,ECX
009C7D99   >MOV ECX,DEADC0DE
009C7D9E   >XCHG EAX,ECX
009C7D9F   >NOT EAX
009C7DA1   >POP EAX
009C7DA2   >NOT ECX
009C7DA4   >POP ECX
009C7DA5   >PUSHFD
009C7DA6   >PUSHAD
009C7DA7   >XOR EBX,EBX
009C7DA9   >JE SHORT 009C7DAE
009C7DAB   >JMP SHORT 009C7DCF
009C7DAD   >JMP SHORT 009C7DE2
009C7DAF   >???                                      ; 未知命令
009C7DB0   >JE SHORT 009C7DB2
009C7DB2   >JMP SHORT 009C7DC1
009C7DB4   >MOV EAX,87B90FEB
009C7DB9   >LEAVE
009C7DBA   >STC
009C7DBB   >XOR AL,90
009C7DBD   >STC
009C7DBE   >JE SHORT 009C7DC5
009C7DC0   >JMP SHORT 009C7DF5
009C7DC2   >SAL BYTE PTR DS:[EDX+ESI*8-48],87        ; 移动常数超出 1..31 的范围
009C7DC7   >LEAVE
009C7DC8   >INC EAX
009C7DC9   >DEC EAX
009C7DCA   >TEST EAX,EAX
009C7DCC  ^>JNZ SHORT 009C7DAB
009C7DCE  ->JMP 93031B34
009C7DD3   >XCHG AX,DX
009C7DD5   >MOV EAX,EAX
009C7DD7   >MOV EAX,DWORD PTR DS:[9D9200]
009C7DDC   >PUSH 9C7E25
009C7DE1   >PUSH DWORD PTR FS:[0]
009C7DE8   >MOV DWORD PTR FS:[0],ESP
009C7DEF   >XOR ESI,ESI
009C7DF1   >PUSH 4
009C7DF3   >PUSH 1000
009C7DF8   >PUSH 1000
009C7DFD   >PUSH 0
009C7DFF   >CALL EAX
009C7E01   >PUSHFW
009C7E03   >BTS DWORD PTR SS:[ESP],10
009C7E08   >BTS DWORD PTR SS:[ESP],8
009C7E0D   >PUSH CS
009C7E0E   >PUSH 9C7E16
009C7E13   >???                                      ; 未知命令
009C7E15   >IRETD
009C7E16   >INC DWORD PTR DS:[EAX]
009C7E18   >PUSH EAX
009C7E19   >MOV EAX,DWORD PTR DS:[9D9204]
009C7E1E   >CALL EAX
009C7E20   >MOV DWORD PTR SS:[EBP-4],ESI
009C7E23   >JMP SHORT 009C7E9D
009C7E25   >PUSHAD
009C7E26   >LEA EDI,DWORD PTR SS:[ESP+24]
009C7E2A   >MOV ESI,DWORD PTR DS:[EDI]
009C7E2C   >MOV EDI,DWORD PTR DS:[EDI+8]
009C7E2F   >MOV EAX,DWORD PTR DS:[ESI]
009C7E31   >CMP EAX,80000004
009C7E36   >JE SHORT 009C7E71
009C7E38   >CMP EAX,C000001D
009C7E3D   >JE SHORT 009C7E44
009C7E3F   >POPAD
009C7E40   >XOR EAX,EAX
009C7E42   >INC EAX
009C7E43   >RETN

分析发现是这个函数引起的错误:
009C7D72   >CALL 009A72FD
009C7D77   >TEST EAX,EAX
009C7D79   >JNZ SHORT 009C7D82

修改上面的EAX值为 0 就可以跳过这个anti,重新来做:

bp VirtualProtect F9运行4次,Ctrl+F9返回:
0101FAC0   >CALL DWORD PTR DS:[<&KERNEL32.VirtualPro>; kernel32.VirtualProtect
0101FAC6   >TEST EAX,EAX                 <---   返回到这里
0101FAC8   >JNZ SHORT notepad.0101FAD8
0101FACA   >MOV DWORD PTR DS:[1050504],4
0101FAD4   >XOR EAX,EAX
0101FAD6   >JMP SHORT notepad.0101FB13

F8运行到:
0101EF84    >PUSH 0
0101EF86    >PUSH 1
0101EF88    >MOV EDX,DWORD PTR DS:[10504F8]
0101EF8E    >PUSH EDX
0101EF8F    >CALL DWORD PTR DS:[10504FC]
上面的CALL就是进入解码代码的入口,F7进入:
009CAA0B   >PUSH EBP
009CAA0C   >MOV EBP,ESP
009CAA0E   >PUSH EBX
009CAA0F   >MOV EBX,DWORD PTR SS:[EBP+8]
009CAA12   >PUSH ESI

在这里用Ctrl+S搜索命令序列:

PUSH EBP
MOV EBP,ESP
PUSH ECX
PUSH EBX
XOR EBX,EBX

(这个代码是固定的,可以用于别的Arm3.70a加的程序)

来到这里,第一个anti的地方:

009C7D59   >PUSH EBP
009C7D5A   >MOV EBP,ESP
009C7D5C   >PUSH ECX
009C7D5D   >PUSH EBX
009C7D5E   >XOR EBX,EBX
009C7D60   >CMP BYTE PTR DS:[9D9075],BL
009C7D66   >PUSH ESI
009C7D67   >PUSH EDI
009C7D68   >JNZ SHORT 009C7D7B
009C7D6A   >CMP BYTE PTR DS:[9D8CB1],BL
009C7D70   >JNZ SHORT 009C7D7B
009C7D72   >CALL 009A72FD
009C7D77   >TEST EAX,EAX
009C7D79   >JNZ SHORT 009C7D82

光标停在:

009C7D77   >TEST EAX,EAX

F4直接到这个地方,修改EAX的值为0 第一个anti过去了:)

F9运行,又一次出现错误,再次运行到过了第一个anti后,F8运行到:

009C36E0   >MOV EAX,DWORD PTR DS:[9D9560]
009C36E5   >MOV AL,BYTE PTR DS:[EAX+3D2F]
009C36EB   >MOV BYTE PTR SS:[EBP-31B0],AL
009C36F1   >MOVZX EAX,BYTE PTR SS:[EBP-31B0]
009C36F8   >TEST EAX,EAX
009C36FA   >JE 009C382A

发现错误是上面的这效验引起的,修改SS:[EBP-31B0]地址中的值为0 后F9运行,在地址01001000地址里发现写入了数据了。又一次被中断在:

77E1F149 > >PUSH EBP
77E1F14A   >MOV EBP,ESP
77E1F14C   >PUSH DWORD PTR SS:[EBP+14]
77E1F14F   >PUSH DWORD PTR SS:[EBP+10]
77E1F152   >PUSH DWORD PTR SS:[EBP+C]
77E1F155   >PUSH DWORD PTR SS:[EBP+8]
77E1F158   >PUSH -1
77E1F15A   >CALL kernel32.VirtualProtectEx
77E1F15F   >POP EBP
77E1F160   >RETN 10


停止在函数VirtualProtect的入口地址处。

以后可以对bp GetModuleHandleA 下中断,查找那个Magic Jmp的地方,或者利用bp VirtualProtect这个断点到IAT解码的代码处

在解码IAT的代码处还有anti这个以后再讨论。

个人心得,未必正确,仅作参考。


                               
                                  fxyang[OCN][BCG][FCG]

                                                     2003.3.22