您的位置:首页 > 编程语言 > ASP

处理ASProtect的Advanced Import Protect的一些想法和过程(1)

2012-12-16 21:09 239 查看
被Advanced Import Protect方法处理后,原来的Call [********]和JMP [********]变成call 01ba0000(在别的机器上可能不是01ba0000),面对这个困难,我也拜读过不少大牛的文章,但始终有点迷糊,个中困难不再说了;试想一下,既然是修改了调用API的代码,那么在虚拟内存中还是会走进系统DLL中的,那么在进入01ba0000中后,对几个系统DLL比如kernel32和user32下断的话还是会停下的,第一次停下的地方:
7C8099C0 > 64:A1 18000000 MOV EAX,DWORD PTR FS:[18]

7C8099C6 8B40 20 MOV EAX,DWORD PTR DS:[EAX+20]

7C8099C9 C3 RETN

这个从各个寄存器里看到这是对GetCurrentProcessId函数的调用,不是我想要的。

第二次停下:

7C801D7B > 8BFF MOV EDI,EDI

7C801D7D 55 PUSH EBP

从堆栈和寄存器看到是调用LoadLibraryA得到kernel32的基址,对于正常的程序一般不会执行这个函数的,也不是我想要的。用ALT+F9返回到调用的地方。

第三次停下:

00AFCAD2 8B78 20 MOV EDI,DWORD PTR DS:[EAX+20]

00AFCAD5 03FB ADD EDI,EBX

可以看到这是VM的领空,我在这里从寄存器和堆栈看到GetCommandLineA函数字符串,感觉这个像是正常程序调用的函数,然后单步走。

没几步来到一个循环,通过单步走我发现这个循环的作用:从刚才调用LoadLibraryA得到kernel32的基址,到现在用到这个基址,以及各个函数 的字符串出现,这个循环是通过kernel32的导出表来遍历每个函数的字符串并且和“GetCommandLineA”这个字符串进行比较,一直到相同才会走出循环;

这是比较字符串的代码:

00ACC2E1 F3:A6 REPE CMPS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]

ESI指向“GetCommandLineA”字符串,EDI指向kernel32中的其他遍历的字符串,在这句上下条件日志断点SHIFT+F4 条件设置为STRING[EDI]=="GetCommandLineA",然后F9运行停在这里,这时就会比较结果相同了,到此,函数是知道了,但是这个函数是从哪个call 01ba0000处真正对应的呢?正是我们进入VM时的那个call 01ba0000吗?对于这个我感觉应该是吧,如果不放心的话,可以在从call 01ba0000进入到VM后对程序的CODE段下断点,看壳代码会不会偷偷执行完一个函数调用又从另一个call
01ba0000进入VM从而欺骗我。。。

从两个字符串比较相同后再单步跟踪一下,不知道怎么工拐八拐就到得到的GetCommandLineA的地址7C 81 2F BD,但是我始终找不到ret call jmp 直接或者间接到达这个地方,于是进入看一下什么代码:

7C812FBD > A1 F455887C MOV EAX,DWORD PTR DS:[7C8855F4]

7C812FC2 C3 RETN 从这里就能返回到VM或者CODE段,我猜想这么少的代码,被偷取到VM中也不是什么难事啊!于是对7C812FBD下读取硬断,来到这里:

00AE426B 8A01 MOV AL,BYTE PTR DS:[ECX]

00AE426D 41 INC ECX ; kernel32.GetCommandLineA 这里的读取没有看到保存

下面也会读取:

00AE441A 8A06 MOV AL,BYTE PTR DS:[ESI] 此时的ESI和EDI都是kernel32.GetCommandLineA的开始处,

00AE441C 8D7E 01 LEA EDI,DWORD PTR DS:[ESI+1]

00AE441F 8A1F MOV BL,BYTE PTR DS:[EDI]

00AE4421 881C24 MOV BYTE PTR SS:[ESP],BL

这是明显的保存了,只是不在VM中,而是在堆栈中,得到第一个BYTE的数据会与EB,E9比较,在代码中找到一个EB和E9看一下,是JMP的16进制码,再往下走。。。来到这里也是取第一个BYTE:

00AE43FC 8A08 MOV CL,BYTE PTR DS:[EAX]

00AE43FE 80F9 E8 CMP CL,0E8

和E8比较,E8是call的16进制码。。。再走来到:

00AF4E96 66:813F FF25 CMP WORD PTR DS:[EDI],25FF

前两个BYTE和FF25比较,FF25是call [*****]的16进制,到这里算是明白了,都是在比较是不是满足条件的。。。。。

最后算保存了一个DD和一个BYTE:

00AC266B F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]保存在B44340

00AC2672 F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]

最后总算是比较完了,于是到这:

00AEBE0C A1 B02BB000 MOV EAX,DWORD PTR DS:[B02BB0]

00AEBE11 8B40 2C MOV EAX,DWORD PTR DS:[EAX+2C]

00AEBE14 FFD0 CALL EAX 调用VirtualAlloc申请一块内存,保存从kernel32.GetCommandLineA函数处抽取的代码。。。。

接下来的流程是壳代码(VM中)修改原来的call 01ba0000成为call 【刚才VirtualAlloc】得到的内存,再从VM执行到CODE的call 【】处,从call 【】处走到申请的内存中,这时申请的内存中的很少的数据就是偷的GetCommandLineA的代码,执行完又回到CODE接着往下执行。。。。。。。。。。。其他的函数可能也是这样偷的代码。。。

现在说一下第二个被抽取的函数GetStartupInfoA,这个偷的和第一个不同,这一个偷到第一个call ***********处,在保存到VM中时又用了一点代码变形,把call 这句修改为

push &&&&&&&&(call 执行伴随压栈下一句代码地址,&&&&&&&&就是call这句的下一句) push ********** ret 总之偷的不多。。。。

再面临一个问题:壳会不会偷取call 01ba0000的下几行代码呢?现在假如偷取了,过程会这样,肯定会是先从VM进入系统DLL的领空,对于回来嘛,如果偷取了的话,被偷取的代码会在VM里面,那么会从系统DLL中回到VM中,如果没有偷取的话,会从系统DLL的领空直接回到CODE段执行,为人验证到底是哪种情况,我对CODE段和VM中下内存断点,实施一下看。。。

00AE426B 8A01 MOV AL,BYTE PTR DS:[ECX]

00AE426D 41 INC ECX

在这里时,ECX是保存函数的地址,有点像是对CC断点检查的呢?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: