自修改代码(Self-Modifying Code),指在段代码执行前对它进行修改。把代码以加密的形式保存在可执行文件中(或静态资源中),然后在程序执行的时候进行动态解密。这样我们在采用静态分析:时,看到的都是加密的内容,从而减缓甚至队目止静态分析。
一段展示SMC思路的代码:
1 2 3 4 5 6 7
| if(运行条件满足){ DecryptProc(Address of check) check(); EncryptProc(Address of check) }
|
以下打造一个使用SMC进行静态分析对抗的示例,首先正常写一个程序:
1 2 3 4 5 6 7 8 9 10 11 12
| #include<stdio.h> int check(int in) { return in == 12345; } int main() { int input; scanf("%d", &input); if (check(input)) printf("good!"); return 0; }
|
然后我们想把check这个函数保护起来,先把其机器码摘出来进行加密:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| #include<stdio.h> #include<windows.h> int check(int in) { return in == 12345; } void decryption() { DWORD old; VirtualProtect(check, 4096, PAGE_EXECUTE_READWRITE, &old); int de = 0x11; for (int j = 0; j < 36; j++) { *((char*)check + j) ^= de; de++; } VirtualProtect(check, 4096, old, NULL); } int main() { int input; scanf("%d", &input);
decryption();
if (check(input)) printf("good!"); return 0; }
|
另一种常见的实现方法是通过新增一个具备RWX属性的程序段,将需要保护的代码书写在其中,这样就可以避免调用 virtualAl1oc/virtualProtect/mprotect 这类API来暴露SMC 的意图。
对抗思路:
能动态调试最好直接动态调试,因为在程序运行的某一时刻,它一定是解密完成的,这时也就暴露了,使用动态分析运行到这一时刻即可过掉保护。
其次是根据静态分析获得解密算法,写出解密脚本提前解密这段代码。
解密得到的机器码可以通过IDAPython的patch_byte接口很方便地写回。