類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的程序,你會發現,加載就出現異常了,只能使用靜態反匯編
父老常講,道高一尺,魔高一丈,
世界是美好的,也是丑陋的,既要勇於奉獻,也要知道保護自己,才是真正的道理
好吧,關於函數的調用,我們就扯這麼多,回想起<黑客帝國>,有時候都不知道這世界是不是真實,至少代碼應該是真實的吧
好像,又是夜深人靜的時候了...