ITA中API地址混淆实质——20171209
1. ITA中API地址混淆是做什么?
ITA中存放着API地址,调用API时,则是取ITA表中的地址,然后再call,如假设EAX为ITA首地址,那么调用其中第一个API方式为call DWORD PTR [EAX]。ITA中API地址混淆则是将原来ITA表中内容去除,将IAT表中的API地址,转到一个新的入口,经过一些算法处理,并添加一些混淆无用指令,但最后总是能获得真正的API地址,然后调用,如源代码中的调用API指令call DWORD PTR [EAX]改成call 00201234,从00201234地址又有很多的call和jmp等跳转指令,最后会得到真正API地址,并实现跳转。不管中间它如何跳,最后总是以push API地址和retn mem结尾。
2. ITA中API地址混淆有什么作用?
ITA中API地址混淆是一种对抗逆向分析员逆向的对抗方法,试想call一个地址,进去后都是混乱的代码,对于不知道是ITA混淆的程序员来说是会崩溃的,自然容易放弃,对于一个有经验的程序员,他会知道遇到call、jmp等指令就跳,到最后push 和retn才能获得真正的API地址,但也大大加强了工作量。ITA中API地址混淆一般在病毒和木马中会用的比较多。
3. ITA中API地址混淆原理是什么?
从一个新的地址进去,然后call、jmp十几回之后,就会到一段含有push 和retn 指令的代码处,这就是混淆的终点。前边的call和jmp都只是实现跳转的,注意这里的call进去后,大多是没有ret的,所以只会push call后边的地址,但并不能真正跳回来,所以在这里下单步步过F8,往往就会跑飞了,因为F8是在call后边的地址下单步断点,但不会断下来,所以在对抗混淆代码中,使用F7会更保险一些。稍微难理解的是最后的push APIAddr和retn Mem指令为什么就能调到API并且返回到原来最初的入口地址处,如以下一段最后出口代码:
10030312 FF7424 58 PUSH DWORD PTR SS:[ESP+58] 10030316 C2 5C00 RETN 5C
先回顾一下在正常的一个__stdcall函数中入栈和出栈整个栈结构:
//C代码 int __stdcall test(int m, int n){return 0;} int main() {int nRet = test(1, 3);}
相应的调用test函数汇编代码会是如下:
;调用call时指令 push 3 push 1 call test ;该指令<==>push retAddr jmp test ;test函数中出栈指令 retn 8 ;该指令<==>pop retAddr add esp, 8 jmp retAddr
再看混淆过的代码:
call AddrConfuse …… 10030312 FF7424 58 PUSH DWORD PTR SS:[ESP+58] 10030316 C2 5C00 RETN 5C ;最后的RETN 5C <==>pop DWORD PTR SS:[ESP+58] add esp, 5C ;这一加将混淆中所有的push的东西去掉,到AddrConfuse的参数处 jmp DWORD PTR SS:[ESP+58] ;到了API的汇编实现代码处,还会有retn指令,这一指令就正好处理AddrConfuse的参数,并最后跳会原地址处
所以通过以上代码中注释分析,最后的push和retn指令就必然是最后混淆代码的出口了,并且能够会到原来的地址处。
4. ITA中API地址混淆如何写及如何反混淆
本人经过对一些混淆代码的复制分析及对比,同一个API混淆的中途跳转可以是随机的,这点可以通过对API地址多给几套混淆方案,然后随机选择便实现随机,当然也能是固定的,但最后的push的API地址一定是相同的,只是因为中间的处理不同,所以retn mem中立即数mem是不同的额,因为中间push的方式和数量都不同。在所有的跳转段中真正计算API地址的代码指令就三四行,其它的都是做混淆用的,必须要做到的是retn mem中mem的大小一定是中途push 的字节数的总大小,不然最后真正API无法运行。
反混淆的方法可以是(1)按以上方法手动F7一直运行,直到最后push 和retn 便获得API地址,这时常见的方法,(2)写个反混淆的工具,给OD写插件,使用相应插件时,提示输入call地址,然后写一个函数,将混淆的代码清除,留下算真正API的指令代码。具体的代码实现可以使用反汇编引擎,每3行反汇编代码一获取,判断call、jmp,则跳至对应的地址处,去那边的代码,并反汇编成汇编代码,如此将所有的代码跳转整合到一处,判断最后push 中值是来自哪个寄存器,然后溯源,最初始的会是给寄存器赋一常量值。最后将清理掉混淆代码后的处理API代码,整合一起写到最后的push retn前面,将初始入口的call指令改到新的整合的代码地址处,当然最后retn后的立即数就可以去掉了。
5.ITA中同一API地址两种混淆代码
(1)1000AEED E8 E9EA0100 CALL bmjewm.100299DB 混淆方案1
1) 100299DB 0F88 B6480000 JS bmjewm.1002E297 100299E1 68 8E5124FB PUSH FB24518E 100299E6 60 PUSHAD 100299E7 90 NOP 100299E8 E9 95CB0000 JMP bmjewm.10036582 ;转 2) 10036582 60 PUSHAD 10036583 877C24 40 XCHG DWORD PTR SS:[ESP+40],EDI 10036587 8D3C8D 993F81FF LEA EDI,DWORD PTR DS:[ECX*4+FF813F99] 1003658E 0FCF BSWAP EDI 10036590 8B7C24 44 MOV EDI,DWORD PTR SS:[ESP+44] 10036594 54 PUSH ESP 10036595 C64424 04 77 MOV BYTE PTR SS:[ESP+4],77 1003659A E8 6BBBFFFF CALL bmjewm.1003210A ;转 3) 1003210A E8 98080100 CALL bmjewm.100429A7 ;转 4) 100429A7 8DBF 01000000 LEA EDI,DWORD PTR DS:[EDI+1] 100429AD ^E9 2CE9FFFF JMP bmjewm.100412DE ;转 5) 100412DE C64424 18 44 MOV BYTE PTR SS:[ESP+18],44 100412E3 57 PUSH EDI 100412E4 8D6424 50 LEA ESP,DWORD PTR SS:[ESP+50] 100412E8 ^0F85 A51DFFFF JNZ bmjewm.10033093 ;转 6) 10033093 60 PUSHAD 10033094 885C24 0C MOV BYTE PTR SS:[ESP+C],BL 10033098 FF3424 PUSH DWORD PTR SS:[ESP] 1003309B 60 PUSHAD 1003309C 897C24 48 MOV DWORD PTR SS:[ESP+48],EDI 100330A0 FF7424 04 PUSH DWORD PTR SS:[ESP+4] 100330A4 BF 07610110 MOV EDI,bmjewm.10016107 100330A9 56 PUSH ESI 100330AA ^E9 3883FFFF JMP bmjewm.1002B3E7 ;转 7) 1002B3E7 9C PUSHFD 1002B3E8 8BBF A8DE0100 MOV EDI,DWORD PTR DS:[EDI+1DEA8] 1002B3EE E8 FFEFFFFF CALL bmjewm.1002A3F2 ;转 8) 1002A3F2 66:C70424 0DAB MOV WORD PTR SS:[ESP],0AB0D 1002A3F8 E8 547E0000 CALL bmjewm.10032251 ;转 9) 10032251 C64424 04 18 MOV BYTE PTR SS:[ESP+4],18 10032256 8DBF DBDFD276 LEA EDI,DWORD PTR DS:[EDI+76D2DFDB] 1003225C ^E9 A5E0FFFF JMP bmjewm.10030306 ;转 10) 10030306 877C24 58 XCHG DWORD PTR SS:[ESP+58],EDI ; kernel32.GetModuleFileNameA 1003030A 887C24 04 MOV BYTE PTR SS:[ESP+4],BH 1003030E C60424 52 MOV BYTE PTR SS:[ESP],52 10030312 FF7424 58 PUSH DWORD PTR SS:[ESP+58] 10030316 C2 5C00 RETN 5C
(2)1000AEED E8 E9EA0100 CALL bmjewm.100299DB 混淆方案2
1) 1000AEED E8 E9EA0100 CALL bmjewm.100299DB 2) 100299DB 0F88 B6480000 JS bmjewm.1002E297 //sf = 1 100299E1 68 8E5124FB PUSH FB24518E 100299E6 60 PUSHAD 100299E7 90 NOP 100299E8 E9 95CB0000 JMP bmjewm.10036582 3) 1002E297 60 PUSHAD 1002E298 66:891424 MOV WORD PTR SS:[ESP],DX 1002E29C 90 NOP 1002E29D 881C24 MOV BYTE PTR SS:[ESP],BL 1002E2A0 897C24 1C MOV DWORD PTR SS:[ESP+1C],EDI 1002E2A4 F7D7 NOT EDI 1002E2A6 60 PUSHAD 1002E2A7 C74424 08 350E28>MOV DWORD PTR SS:[ESP+8],C5280E35 1002E2AF 8B7C24 40 MOV EDI,DWORD PTR SS:[ESP+40] 1002E2B3 E8 FFBDFFFF CALL bmjewm.1002A0B7 4) 1002A0B7 68 E1299C26 PUSH 269C29E1 1002A0BC C64424 04 82 MOV BYTE PTR SS:[ESP+4],82 1002A0C1 8DBF 01000000 LEA EDI,DWORD PTR DS:[EDI+1] 1002A0C7 9C PUSHFD 1002A0C8 C60424 06 MOV BYTE PTR SS:[ESP],6 1002A0CC 897C24 4C MOV DWORD PTR SS:[ESP+4C],EDI 1002A0D0 5F POP EDI 1002A0D1 66:0FBEFA MOVSX DI,DL 1002A0D5 E8 19400000 CALL bmjewm.1002E0F3 5) 1002E0F3 68 31C040AC PUSH AC40C031 1002E0F8 BF 07610110 MOV EDI,bmjewm.10016107 1002E0FD E9 B77B0100 JMP bmjewm.10045CB9 6) 10045CB9 ^E9 0FE2FEFF JMP bmjewm.10033ECD 7) 10033ECD 8BBF A8DE0100 MOV EDI,DWORD PTR DS:[EDI+1DEA8] 10033ED3 887C24 04 MOV BYTE PTR SS:[ESP+4],BH 10033ED7 E9 56B80000 JMP bmjewm.1003F732 8) 1003F732 E8 0C000000 CALL bmjewm.1003F743 9) 1003F743 C60424 3F MOV BYTE PTR SS:[ESP],3F 1003F747 8DBF DBDFD276 LEA EDI,DWORD PTR DS:[EDI+76D2DFDB] 1003F74D E8 3037FFFF CALL bmjewm.10032E82 10) 10032E82 E9 B9730100 JMP bmjewm.1004A240 11) 1004A240 C60424 8E MOV BYTE PTR SS:[ESP],8E 1004A244 C64424 04 26 MOV BYTE PTR SS:[ESP+4],26 1004A249 877C24 54 XCHG DWORD PTR SS:[ESP+54],EDI 1004A24D 883C24 MOV BYTE PTR SS:[ESP],BH 1004A250 C60424 50 MOV BYTE PTR SS:[ESP],50 1004A254 FF7424 54 PUSH DWORD PTR SS:[ESP+54] 1004A258 C2 5800 RETN 58
浙公网安备 33010602011771号