程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 關於編譯型語言函數的調用(三)

關於編譯型語言函數的調用(三)

編輯:C++入門知識

關於編譯型語言函數的調用(三)


 

類delete就不說了,有興趣的朋友自己跟蹤看看吧,提示一下:析構函數也有參數和返回值.

 

下面我們看下裸函數,裸函數從執行效率上是可以與匯編語言媲美的,然而它不太好逆過來說,我們就順著說吧

前面說得構造函數的臨時堆棧,恢復寄存器等等,有人給了個名稱叫prolog和epilog

而裸函數並沒有自動編譯這些部分,其實說白了,裸函數相當於匯編語言中的一個標簽,其調用受前面幾種約定約束

此外空的裸函數是什麼都不做的,非必要的不做,必要的也不做,就是什麼都要自己實現,其實就是要自己匯編

當然了,裸函數不能是類的成員函數,舉例中我們使用__cdecl約定,直接照搬fnDefaultCall的,不管執行效率

 

132:      ret = fnNakedCall(19, 20, 21, &var1);
00401428   lea         edx,[ebp-14h]
0040142B   push        edx
0040142C   push        15h
0040142E   push        14h
00401430   push        13h
00401432   call        @ILT+15(fnNakedCall) (00401014)
00401437   add         esp,10h
0040143A   mov         dword ptr [ebp-18h],eax
133:
可以看出調用約定符合__cdecl的約定,那麼跟蹤一下看看:

 

 

68:
69:   __declspec(naked) int __cdecl fnNakedCall(int arg1, short arg2, char arg3, void *arg4)
70:   {
004012D0   push        ebp
71:       // 1. 到這裡所有寄存器的值與調用前一樣
72:       // 2. 用變量名引用任何局部變量等同於引用主調函數變量或參數
73:       // 3. 必須負責寄存器的維護, 這裡函數作為__cdecl
74:       __asm{
75:           push        ebp                 ; prolog begin
76:           mov         ebp, esp
004012D1   mov         ebp,esp
77:           sub         esp, 50h
004012D3   sub         esp,50h
78:           push        ebx
004012D6   push        ebx
79:           push        esi
004012D7   push        esi
80:           push        edi
004012D8   push        edi
81:           lea         edi, [ebp-50h]
004012D9   lea         edi,[ebp-50h]
82:           mov         ecx, 14h
004012DC   mov         ecx,14h
83:           mov         eax, 0CCCCCCCCh
004012E1   mov         eax,0CCCCCCCCh
84:           rep stos    dword ptr [edi]     ; prolog end
004012E6   rep stos    dword ptr [edi]
85:
86:           // var1 = arg1;
87:           mov         eax, dword ptr [ebp + 8]        ; [esp + 8]
004012E8   mov         eax,dword ptr [ebp+8]
88:           mov         dword ptr [ebp-4], eax          ; [esp - 4]
004012EB   mov         dword ptr [ebp-4],eax
89:           // var2 = arg2;
90:           mov         cx, word ptr [ebp + 0Ch]
004012EE   mov         cx,word ptr [ebp+0Ch]
91:           mov         word ptr [ebp - 8], cx
004012F2   mov         word ptr [ebp-8],cx
92:           // var3 = arg3;
93:           mov         dl, byte ptr [ebp + 10h]
004012F6   mov         dl,byte ptr [ebp+10h]
94:           mov         byte ptr [ebp - 0Ch], dl
004012F9   mov         byte ptr [ebp-0Ch],dl
95:           // p = (int *)arg4;
96:           mov         eax, dword ptr [ebp + 14h]
004012FC   mov         eax,dword ptr [ebp+14h]
97:           mov         dword ptr [ebp - 10h], eax
004012FF   mov         dword ptr [ebp-10h],eax
98:           // *p = -1;
99:           mov         ecx, dword ptr [ebp - 10h]
00401302   mov         ecx,dword ptr [ebp-10h]
100:          mov         dword ptr [ecx], 0FFFFFFFFh
00401305   mov         dword ptr [ecx],0FFFFFFFFh
101:          // return 22;
102:          mov         eax, 16h            ; 0x16 = 22
0040130B   mov         eax,16h
103:
104:          pop         edi                 ; epilog begin
00401310   pop         edi
105:          pop         esi
00401311   pop         esi
106:          pop         ebx
00401312   pop         ebx
107:          mov         esp, ebp
00401313   mov         esp,ebp
108:          pop         ebp                 ; epilog end
00401315   pop         ebp
109:          // return to caller function(do not use ret 10h)
110:          ret
00401316   ret
--- No source file  --------------------------------------------------------------
00401317   int         3
雖然復制過來有點錯位,不過不難看出,我們的匯編代碼被照搬了,用曾泰的話說:絲毫不差.

 

這就意味著,我們只要保證寄存器調用後符合調用約定,此外就可以為所欲為了

我不希望大家墮入哲學的深淵,不過我只能用這樣的語句來描述:

什麼都要自己做和什麼都能自己做,往往是一回事,這就是辯證.

 

還記得前面說的fastcall中變量被存來存去嗎,嘿嘿,用naked就可以避免,實現真正的fastcall

此外,一些常用的內聯匯編的函數,也可以用這種方式輸出,當然了,需要具備一定的匯編語言基礎

再如,我們可以連堆棧都不構造,直接使用esp代替ebp,即省去prolog和epilog.

 

文章似乎到這裡就結束了,那麼知道這些有什麼用呢?如果你有這樣的想法,那就再好不過了,通常人知道了也就知道了

能有這樣的想法,說明有學以致用的習慣或者說性格.

那麼,我們就試著提出幾個用處吧:

 

1. 提升調試程序的能力,更深入的找出BUG的根源,並得出更深一層的解決方法

比如莫名其妙的崩潰,緩沖區溢出,還有這種:

\

 

2.提升程序開發水平,比如常用的strcpy,memset等等函數,應該自己寫,更好的發揮機器的性能,

法國一個科學家,用一台普通的計算機計算圓周率,其效率居然可以與一台超級計算機相媲美

單靠數學是無法完成這樣的工作的.他必然對計算機的指令架構十分熟悉

 

3.對逆向和軟件加密有一定程度的認知

比如單單知道eax作為返回值這一點,你就該認識到,僅用一個函數去做授權驗證是很容易繞過的!

既然能想到繞過別人程序的辦法,就應該想出防止別人簡單繞過的方案

實際的軟件加密和破解雖然並沒有那麼簡單,不過起碼有這樣的一個認知,

 

說起破解,我到還想再廢話一下,有些學習破解的朋友,反匯編出來,修改指令,就認為天下的軟件就這麼干就能破解了

對軟件行業充滿了失落感,那麼我們來舉個例子:

使用OD載入一個程序:

 

00531001 >  60              pushad
00531002    E8 03000000     call    0053100A
00531007  - E9 EB045D45     jmp     45B014F7
0053100C    55              push    ebp
0053100D    C3              retn

一開始就發現情形不太對,當然專職搞破解的朋友馬上看得出來,這是加殼以後的程序,一開始便運行的是殼的程序,

 

解壓或解密出實際的代碼,然後跳到實際入口去執行,那麼脫殼即可啦,那我們再繼續看

 

046620D1    81EC 00040000   sub     esp, 400
046620D7    55              push    ebp
046620D8    8BEC            mov     ebp, esp
046620DA    50              push    eax
046620DB    EB 0E           jmp     short 046620EB
046620DD    838B 84240804 0>or      dword ptr [ebx+4082484], 0
046620E4    00EB            add     bl, ch
046620E6    01F0            add     eax, esi
046620E8    EB 04           jmp     short 046620EE
046620EA    54              push    esp
046620EB  ^ EB F1           jmp     short 046620DE
046620ED    6BEB 0C         imul    ebp, ebx, 0C
046620F0    B7 6B           mov     bh, 6B
046620F2    8D40 FB         lea     eax, dword ptr [eax-5]
046620F5    EB 01           jmp     short 046620F8
046620F7    09EB            or      ebx, ebp
046620F9    06              push    es
046620FA    9B              wait
046620FB    0D EBF4E7E8     or      eax, E8E7F4EB
04662100    EB 0D           jmp     short 0466210F
04662102    9C              pushfd
04662103    FE89 45ECEB03   dec     byte ptr [ecx+3EBEC45]
04662109    BB 4B62EB06     mov     ebx, 6EB624B
0466210E  - 66:EB F3        jmp     short 00002104

在046620EB處 jmp short 046620DE,然而反匯編出來並沒有開始為0x046620DE的指令

 

只有046620DD 是 or dword ptr[ebx+....], 0,這是怎麼回事呢

我們把046620DD的字節改為int 3即0xCC再看一下

\

直接輸入16進制CC一個字節

\

再看反匯編窗口

\

居然變成了

046620DE 8B8424 08040000 mov eax, dword ptr [esp+408]

恰好在jmp的目的地址,這不是欺負老實人嗎?

 

不錯,這就是花指令,而且是花指令的一種,讓你反匯編了以後也是亂的

當然,花指令直接匯編級別的加密,如果你逆向360的程序,你會發現,加載就出現異常了,只能使用靜態反匯編

父老常講,道高一尺,魔高一丈,

世界是美好的,也是丑陋的,既要勇於奉獻,也要知道保護自己,才是真正的道理

 

好吧,關於函數的調用,我們就扯這麼多,回想起<黑客帝國>,有時候都不知道這世界是不是真實,至少代碼應該是真實的吧

好像,又是夜深人靜的時候了...

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved