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