VC下防止反匯編的辦法(1)


最近在看IDA的書,講匯編語言的部分提到了一種防止遞歸向下匯編器逆向程序的方法

這里esp指向棧頂,也就是調用方最后入棧的返回地址。然而實際在VC2017里用內聯匯編這么做是不行的,原因可以看看VC生成的匯編 代碼:

 

 1 int __stdcall func1(int param)
 2 {
 3 00AC10A0  push        ebp  
 4 00AC10A1  mov         ebp,esp  
 5 00AC10A3  sub         esp,8  
 6     int local = param;
 7 00AC10A6  mov         eax,dword ptr [param]  
 8 00AC10A9  mov         dword ptr [local],eax  
 9     int local2 = 1 + param;
10 00AC10AC  mov         ecx,dword ptr [param]  
11 00AC10AF  add         ecx,1  
12 00AC10B2  mov         dword ptr [local2],ecx  
13     _asm{
14         add dword ptr[ebp+4],13
15 00AC10B5  add         dword ptr [ebp+4],0Dh  
16     }
17     return param*2;
18 00AC10B9  mov         eax,dword ptr [param]  
19 00AC10BC  shl         eax,1  
20 }
21 00AC10BE  mov         esp,ebp  
22 00AC10C0  pop         ebp  
23 }

可以看到VC生成的匯編代碼中添加了一些前綴后綴:

前綴用來保存調用前堆棧頂ebp,還有設置新的堆棧頂位置到ebp。如果有局部變量,還要減少esp位置(相當於入棧幾個未知數據)以留出局部變量的位置。注意函數堆棧是從內存大編號向小編號堆疊的,越大的地址編號越靠下,就像一個金字塔,下大上小。

后綴用來清理堆棧(mov esp,ebp),並且從堆棧中恢復此次調用之前的ebp(pop ebp)。不難發現在被調用的函數體內修改函數返回地址的話,就需略過ebp的位置。因此內嵌匯編的那一句需要用ebp+4來得到返回地址指針。后面地址+13是略過的調用方的一個printf方法調用,要跳過多少代碼可以在反匯編窗口自行查看地址計算一下。

下面是調用方的代碼:

int main()
{
00AC1002  in          al,dx  
00AC1003  sub         esp,1Ch  
00AC1006  mov         eax,dword ptr [__security_cookie (0AC3000h)]  
00AC100B  xor         eax,ebp  
00AC100D  mov         dword ptr [ebp-4],eax  
    int d = 10;
00AC1010  mov         dword ptr [d],0Ah  
    func1(10);
00AC1017  push        0Ah  
00AC1019  call        func1 (0AC10A0h)  
    printf("loc1\n");
00AC101E  push        0AC20F8h  
00AC1023  call        printf (0AC1140h)  
00AC1028  add         esp,4  
    printf("loc2\n");
00AC102B  push        0AC2100h  
00AC1030  call        printf (0AC1140h)  
00AC1035  add         esp,4  
    int a[] = {0,1,2,3,4};
00AC1038  mov         dword ptr [a],0  
00AC103F  mov         dword ptr [ebp-14h],1  
00AC1046  mov         dword ptr [ebp-10h],2  
00AC104D  mov         dword ptr [ebp-0Ch],3  
00AC1054  mov         dword ptr [ebp-8],4  
    printf("%d\b",func2(a));
00AC105B  lea         eax,[a]  
00AC105E  push        eax  
00AC105F  call        func2 (0AC10D0h)  
00AC1064  add         esp,4  
00AC1067  push        eax  
00AC1068  push        0AC2108h  
00AC106D  call        printf (0AC1140h)  
00AC1072  add         esp,8  
    printf("writing code...\n");
00AC1075  push        0AC210Ch  
00AC107A  call        printf (0AC1140h)  
00AC107F  add         esp,4  
    func3();
00AC1082  call        __vcrt_va_start_verify_argument_type<char const * const> (0AC10F0h)  
    getchar();
00AC1087  call        dword ptr [__imp__getchar (0AC20A8h)]  
    return 0;
00AC108D  xor         eax,eax  
}

 

還有要注意的是這里為了防止代碼優化,要關閉vc的編譯優化選項。用以上這種方法可以配合一些跳轉讓反匯編的工具不能正確預測哪部分是代碼區,從而達到隱藏一部分代碼的目的。

以上是STDCALL調用約定的例子,cdecl和其他約定的以后再嘗試整理。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM