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

来源:互联网 发布:淘宝提醒买家付款 编辑:程序博客网 时间:2024/05/01 15:55
被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断点检查的呢? 

 

 

 

原创粉丝点击