浅析VS2010反汇编 VS 反汇编方法及常用汇编指令介绍 VS2015使用技巧 调试-反汇编 查看C语言代码对应的汇编代码...
淺析VS2010反匯編
2015年07月25日 21:53:11 閱讀數(shù):4374第一篇
1. 如何進(jìn)行反匯編
在調(diào)試的環(huán)境下,我們可以很方便地通過(guò)反匯編窗口查看程序生成的反匯編信息。如下圖所示。
記得中斷程序的運(yùn)行,不然看不到反匯編的指令
看一個(gè)簡(jiǎn)單的程序及其生成的匯編指令
#include<stdio.h> #include<windows.h> const long Lenth=5060000/5; int main(){while(true){for(long i=0;i<Lenth;i++){;}Sleep(10);} }匯編窗口
?
?
2. ?預(yù)備知識(shí):
?
函數(shù)調(diào)用大家都不陌生,調(diào)用者向被調(diào)用者傳遞一些參數(shù),然后執(zhí)行被調(diào)用者的代碼,最后被調(diào)用者向調(diào)用者返回結(jié)果,還有大家比較熟悉的一句話(huà),就是函數(shù)調(diào)用是在棧上發(fā)生的,那么在計(jì)算機(jī)內(nèi)部到底是如何實(shí)現(xiàn)的呢? 對(duì)于程序,編譯器會(huì)對(duì)其分配一段內(nèi)存,在邏輯上可以分為代碼段,數(shù)據(jù)段,堆,棧 代碼段:保存程序文本,指令指針EIP就是指向代碼段,可讀可執(zhí)行不可寫(xiě) 數(shù)據(jù)段:保存初始化的全局變量和靜態(tài)變量,可讀可寫(xiě)不可執(zhí)行 BSS:未初始化的全局變量和靜態(tài)變量 堆(Heap):動(dòng)態(tài)分配內(nèi)存,向地址增大的方向增長(zhǎng),可讀可寫(xiě)可執(zhí)行 棧(Stack):存放局部變量,函數(shù)參數(shù),當(dāng)前狀態(tài),函數(shù)調(diào)用信息等,向地址減小的方向增長(zhǎng),非常非常重要,可讀可寫(xiě)可執(zhí)行 如圖所示 寄存器 EAX:累加(Accumulator)寄存器,常用于函數(shù)返回值 EBX:基址(Base)寄存器,以它為基址訪問(wèn)內(nèi)存 ECX:計(jì)數(shù)器(Counter)寄存器,常用作字符串和循環(huán)操作中的計(jì)數(shù)器 EDX:數(shù)據(jù)(Data)寄存器,常用于乘除法和I/O指針 ESI:源變址寄存器 DSI:目的變址寄存器 ESP:堆棧(Stack)指針寄存器,指向堆棧頂部 EBP:基址指針寄存器,指向當(dāng)前堆棧底部 EIP:指令寄存器,指向下一條指令的地址第二篇
?
一、VS反匯編方法
1、調(diào)出反匯編窗口。
2、調(diào)用寄存器窗口(只有在反匯編下才可見(jiàn))
如果在調(diào)試狀態(tài)還是沒(méi)有此菜單項(xiàng),可試著以下操作:
在VS中點(diǎn)擊“工具”->“導(dǎo)入和導(dǎo)出設(shè)置”,選擇“重置所有設(shè)置”,下一步,這時(shí)你可以保存當(dāng)前設(shè)置或不保存,我覺(jué)得無(wú)所謂,下一步,選擇“Visual C**開(kāi)發(fā)設(shè)置”,“完成”。這樣,“調(diào)試”->“窗口”->“寄存器”菜單項(xiàng)應(yīng)該用顯示出來(lái)了,記得要確保你的程序是在調(diào)試的過(guò)程中。
3、查看內(nèi)存
點(diǎn)擊“調(diào)試”->“窗口”->“內(nèi)存”->“內(nèi)存1”...“內(nèi)存4”(選一個(gè)就可以了。)。在內(nèi)存窗口中的“地址”欄輸入地址,按回車(chē)即可看到該地地址處的內(nèi)存信息。
?二、常用匯編指令介紹
1、常用指令
為了照顧到?jīng)]學(xué)過(guò)匯編程序的同志們,這里簡(jiǎn)單介紹一下常見(jiàn)的幾種匯編指令。
A、add:加法指令,第一個(gè)是目標(biāo)操作數(shù),第二個(gè)是源操作數(shù),格式為:目標(biāo)操作數(shù) = 目標(biāo)操作數(shù) + 源操作數(shù);
B、sub:減法指令,格式同 add;
C、call:調(diào)用函數(shù),一般函數(shù)的參數(shù)放在寄存器中;
D、ret:跳轉(zhuǎn)會(huì)調(diào)用函數(shù)的地方。對(duì)應(yīng)于call,返回到對(duì)應(yīng)的call調(diào)用的下一條指令,若有返回值,則放入eax中;
E、push:把一個(gè)32位的操作數(shù)壓入堆棧中,這個(gè)操作在32位機(jī)中會(huì)使得esp被減4(字節(jié)),esp通常是指向棧頂?shù)?#xff08;這里要指出的是:學(xué)過(guò)單片機(jī)的同學(xué)請(qǐng)注意單片機(jī)種的堆棧與Windows下的堆棧是不同的,請(qǐng)參考相應(yīng)資料),這里頂部是地址小的區(qū)域,那么,壓入堆棧的數(shù)據(jù)越多,esp也就越來(lái)越小;
F、pop:與push相反,esp每次加4(字節(jié)),一個(gè)數(shù)據(jù)出棧。pop的參數(shù)一般是一個(gè)寄存器,棧頂?shù)臄?shù)據(jù)被彈出到這個(gè)寄存器中;
一般不會(huì)把sub、add這樣的算術(shù)指令,以及call、ret這樣的跳轉(zhuǎn)指令歸入堆棧相關(guān)指令中。但是實(shí)際上在函數(shù)參數(shù)傳遞過(guò)程中,sub和add最常用來(lái)操作堆棧;call和ret對(duì)堆棧也有影響。
?
G、mov:數(shù)據(jù)傳送。第一個(gè)參數(shù)是目的操作數(shù),第二個(gè)參數(shù)是源操作數(shù),就是把源操作數(shù)拷貝到目的一份。
H、xor:異或指令,這本身是一個(gè)邏輯運(yùn)算指令,但在匯編指令中通常會(huì)見(jiàn)到它被用來(lái)實(shí)現(xiàn)清零功能。
????????????? 用 xor eax,eax這種操作來(lái)實(shí)現(xiàn) mov eax,0,可以使速度更快,占用字節(jié)數(shù)更少。
I、lea:取得第二個(gè)參數(shù)地址后放入到前面的寄存器(第一個(gè)參數(shù))中。
???????????????然而lea也同樣可以實(shí)現(xiàn)mov的操作,例如:
????????????????????????????????? lea edi,[ebx-0ch]
方括號(hào)表示存儲(chǔ)單元,也就是提取方括號(hào)中的數(shù)據(jù)所指向的內(nèi)容,然而lea提取內(nèi)容的地址,這樣就實(shí)現(xiàn)了把(ebx-0ch)放入到了edi中,但是mov指令是不支持第二個(gè)操作數(shù)是一個(gè)寄存器減去一個(gè)數(shù)值的。
?
J、stos:串行存儲(chǔ)指令,它實(shí)現(xiàn)把eax中的數(shù)據(jù)放入到edi所指的地址中,同時(shí)edi后移4個(gè)字節(jié),這里的stos實(shí)際上對(duì)應(yīng)的是stosd,其他的還有stosb,stosw分別對(duì)應(yīng)1,2個(gè)字節(jié)。
K、jmp:無(wú)條件跳轉(zhuǎn)指令,對(duì)應(yīng)于大量的條件跳轉(zhuǎn)指令。
L、jg:條件跳轉(zhuǎn),大于時(shí)成立,進(jìn)行跳轉(zhuǎn),通常條件跳轉(zhuǎn)之前會(huì)有一條比較指令(用于設(shè)置標(biāo)志位)。
M、jl:小于時(shí)跳轉(zhuǎn)。
N、jge:大于等于時(shí)跳轉(zhuǎn)。
O、cmp:比較大小指令,結(jié)果用來(lái)設(shè)置標(biāo)志位。
P ,rep 根據(jù)ECX寄存器的值進(jìn)行重復(fù)循環(huán)操作
?
注:mov ax,[bx]
[ ]表示是間接尋址,bx和[bx]的區(qū)別是,前者操作數(shù)就是bx中存放的數(shù),后者操作數(shù)是以bx中存放的數(shù)為地址的單元中的數(shù)。比如bx中存放的數(shù)是40F6H,40F6H、40F7H兩個(gè)單元中存放的數(shù)是22H、23H,則
mov ax,[bx];2223H傳送到ax中
mov ax,bx;40F6H傳送到ax中
?
ILT是INCREMENTAL?LINK?TABLE的縮寫(xiě),這個(gè)@ILT其實(shí)就是一個(gè)靜態(tài)函數(shù)跳轉(zhuǎn)的表,它記錄了一些函數(shù)的入口然后跳過(guò)去,每個(gè)跳轉(zhuǎn)jmp占一個(gè)字節(jié),然后就是一個(gè)四字節(jié)的內(nèi)存地址,加起為五個(gè)字節(jié)
比如代碼中有多處地方調(diào)用boxer函數(shù),別處的調(diào)用也通過(guò)這個(gè)ILT表的入口來(lái)間接調(diào)用,而不是直接call?該函數(shù)的偏移,這樣在編譯程序時(shí),如果boxer函數(shù)更新了,地址變了,只需要修改跳表中的地址就可以,有利于提高鏈接生成程序的效率。這個(gè)是用在程序的調(diào)試階段,當(dāng)編譯release程序時(shí),就不再用這種方法。
?
我試著將HEX數(shù)據(jù)改成00 00,對(duì)應(yīng)的匯編指令變成了add byte ptr [eax],al ,反過(guò)來(lái),如果將一個(gè)地方的匯編指令改成add byte ptr [eax],al ,對(duì)應(yīng)的HEX數(shù)據(jù)就成了00 00,也就是說(shuō),他們是一一對(duì)應(yīng)的,編譯器認(rèn)為,00 00 這樣兩個(gè)字節(jié)寬度的二進(jìn)制數(shù)對(duì)應(yīng)的匯編指令就是add byte ptr [eax],al?;
?
dword?雙字 就是四個(gè)字節(jié)
ptr?pointer縮寫(xiě) 即指針
2? 、函數(shù)參數(shù)傳遞方式
函數(shù)調(diào)用規(guī)則指的是調(diào)用者和被調(diào)用函數(shù)間傳遞參數(shù)及返回參數(shù)的方法,在Windows上,常用的有Pascal方式、WINAPI方式(_stdcall)、C方式(_cdecl)。
A、_cdecl C調(diào)用規(guī)則:
(a)參數(shù)從右到左進(jìn)入堆棧;
(b)在函數(shù)返回后,調(diào)用者要負(fù)責(zé)清除堆棧,這種調(diào)用方式通常會(huì)生成較大的可執(zhí)行程序。
B、_stdcall又稱(chēng)為WINAPI,調(diào)用規(guī)則如下:
(a)參數(shù)從右到左進(jìn)入堆棧;
(b)被調(diào)用的函數(shù)在返回前自行清理堆棧,這種方式生成的代碼比cdecl小。
C、Pascal調(diào)用規(guī)則(主要用于Win16函數(shù)庫(kù)中,現(xiàn)在基本不用):
(a)參數(shù)從左到右進(jìn)入堆棧;
(b)被調(diào)用的函數(shù)在返回前自行清理堆棧。
(c)不支持可變參數(shù)的函數(shù)調(diào)用。
第三篇
?
了解反匯編的一些小知識(shí)對(duì)于我們?cè)陂_(kāi)發(fā)軟件時(shí)進(jìn)行編程與調(diào)試大有好處,下面以簡(jiǎn)單介紹一下反匯編的一些小東西!如果有些解釋有問(wèn)題的地方,希望大家能夠指出。
1、新建簡(jiǎn)單的VC控制臺(tái)應(yīng)用程序(對(duì)此熟悉的同學(xué)可以略過(guò))
A、打開(kāi)Microsoft Visual Studio 2010,選擇主菜單“File”
B、選擇子菜單“New”下面的“Project”,打開(kāi)“New Project”對(duì)話(huà)框。
C、左邊選擇Visual C++下的win32,右邊選擇Win32 Console Application,然后輸入一個(gè)工程名,點(diǎn)擊“OK”即可,在出現(xiàn)的向?qū)е?#xff0c;一切默認(rèn),點(diǎn)擊Finish即可。
D、在出現(xiàn)的編輯區(qū)域內(nèi)會(huì)出現(xiàn)以你設(shè)定的工程名命名的CPP文件。內(nèi)容如下:
????? #include "stdafx.h"
????? int _tmain(int argc, _TCHAR* argv[])
????? {
??????????? return 0;
??????}
2、VS查看匯編代碼
A、VC處于調(diào)試狀態(tài)才能看到匯編指令窗口。因此,可以在 return 0 上設(shè)置一個(gè)斷點(diǎn):把光標(biāo)移到 return 0 那一行上,然后按下F9鍵設(shè)置一個(gè)斷點(diǎn)。
B、按下F5鍵進(jìn)入調(diào)試狀態(tài),當(dāng)程序停在 return 0?這一行上時(shí),打開(kāi)菜單“Debug”下的“Windows”子菜單,選擇“Disassembly”。這樣,出現(xiàn)一個(gè)反匯編的窗口,顯示下面的信息:
--- d:/my documents/visual studio 2008/projects/casmtest/casmtest/casmtest_main.cpp?
// CAsmTest.cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)。
//
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
00411370? push??????? ebp??
00411371? mov???????? ebp,esp?
00411373? sub???????? esp,0C0h?
00411379? push??????? ebx??
0041137A? push??????? esi??
0041137B? push??????? edi??
0041137C? lea???????? edi,[ebp-0C0h]?
00411382? mov???????? ecx,30h?
00411387? mov???????? eax,0CCCCCCCCh?
0041138C? rep stos??? dword ptr es:[edi]?
?return 0;
0041138E? xor???????? eax,eax?
}
00411390? pop???????? edi??
00411391? pop???????? esi??
00411392? pop???????? ebx??
00411393? mov???????? esp,ebp?
00411395? pop???????? ebp??
00411396? ret??
上面就是系統(tǒng)生成的main函數(shù)原型,確切的說(shuō)是_tmain()的反匯編的相關(guān)信息,相信學(xué)過(guò)匯編語(yǔ)言的肯定就能夠了解它所做的操作了。
?
VC中訪問(wèn)無(wú)效變量出錯(cuò)原因
我們看上面主函數(shù)反匯編后的其中一段代碼如下:
0041137C? lea???????? edi,[ebp-0C0h]?
00411382? mov???????? ecx,30h?
00411387? mov???????? eax,0CCCCCCCCh?
0041138C? rep stos??? dword ptr es:[edi]
從代碼的表面上看,它是實(shí)現(xiàn)把從ebp-0C0h開(kāi)始的30h個(gè)字的空間寫(xiě)入0CCCCCCCCh。其中eax為四位的數(shù)據(jù),這樣可以計(jì)算:
????????????????????? 0C0h = 30h * 4
也就是把從ebp-0C0h 到ebp之間的空間初始化為0CCCCCCCCh。大家在學(xué)習(xí)反匯編的過(guò)程中會(huì)發(fā)現(xiàn),其實(shí)編譯器會(huì)根據(jù)情況把相應(yīng)長(zhǎng)度的這樣一段作為局部變量的空間,而這里把局部變量區(qū)域全都初始化成0CCCCCCCCh也是有其用意的,做VC編程的工作者,特別是初學(xué)者可能不會(huì)對(duì)0CCCCCCCCh這個(gè)常量陌生。0cch實(shí)際上是int 3指令的機(jī)器碼,這是一個(gè)斷點(diǎn)中斷指令(在反編譯出的信息中大家會(huì)看到int 3),因?yàn)榫植孔兞坎豢杀粓?zhí)行,或者如果在沒(méi)有初始化的時(shí)候進(jìn)行了訪問(wèn),則就會(huì)出現(xiàn)訪問(wèn)失敗錯(cuò)誤。這個(gè)在VC編譯Debug版本中才能看到提示這個(gè)錯(cuò)誤,在Release版本中,會(huì)以另外一種錯(cuò)誤形式體現(xiàn)。下面,我們修改主程序看下new與delete的反匯編的效果(注釋直接加到反匯編的代碼中了)。
VC生成工程,寫(xiě)入源代碼如下:
(1)情況1
// ASM_Test.cpp : Defines the entry point for the console application.??????????????????? (? 源代碼1 )
//
#include "stdafx.h"
#include "stdlib.h"
int _tmain(int argc, _TCHAR* argv[])
{
??? int *pTest = new int(3);??? ??? ??? ??? //定義一個(gè)整型指針,并初始化為 3
??? printf( "*pTest = %d/r/n", *pTest );??? //調(diào)用庫(kù)函數(shù)printf輸出數(shù)據(jù)
??? delete []pTest;??? ??? ??? ??? ??? ??? ??? //刪除這個(gè)指針
??? return 0;
}
這里僅僅看下在new與delete進(jìn)行空間管理時(shí)進(jìn)行反匯編時(shí)可能出現(xiàn)的一些情況,我們把上面源代碼稱(chēng)為源代碼(1),我們按照前面講解的查看VS下反匯編的方法可以看到對(duì)應(yīng)于上面代碼的反匯編代碼如下:
--- f:/mysource/asm_test/asm_test/asm_test.cpp ---------------------------------????????????????????? ( 反匯編代碼 1)
// ASM_Test.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "stdlib.h"
int _tmain(int argc, _TCHAR* argv[])
{
;(1)函數(shù)預(yù)處理部分
004113C0? push??????? ebp??
004113C1? mov???????? ebp,esp ;保存堆棧的棧頂位置
004113C3? sub???????? esp,0E8h ;要置為0CCCCCCCCh 保留變量空間長(zhǎng)度
004113C9? push??????? ebx?????? ;保存寄存器ebx、esi、edi
004113CA? push??????? esi??
004113CB? push??????? edi??
004113CC? lea???????? edi,[ebp-0E8h]??? ;提出要置為0CCCCCCCCh 的空間起始地址
004113D2? mov???????? ecx,3Ah????? ;要置為0CCCCCCCCh 的個(gè)數(shù),每個(gè)占4個(gè)字節(jié)
004113D7? mov???????? eax,0CCCCCCCCh? ;于是3Ah * 4 = 0E8h
004113DC? rep stos??? dword ptr es:[edi]? ;進(jìn)行置為0CCCCCCCCh操作;
?
(2)定義一個(gè)int 型指針,分配空間后,并初始化為 3 ,
??? int *pTest = new int(3);??? ??? ??? ??? //定義一個(gè)整型指針,并初始化為 3
004113DE? push??????? 4??? ;要分配的空間長(zhǎng)度,會(huì)根據(jù)定義的數(shù)據(jù)類(lèi)型而不同
004113E0? call??????? operator new (411186h)?? ;分配空間,并把分配空間的起始地址放入eax中
004113E5? add???????? esp,4??? ;由于new與delete函數(shù)本身沒(méi)有對(duì)棧進(jìn)行彈出操作,所以,要編寫(xiě)者自己處理
004113E8? mov???????? dword ptr [ebp-0E0h],eax? ;比較分配的空間是否為0,如果為0?
004113EE? cmp???????? dword ptr [ebp-0E0h],0?
004113F5? je????????? wmain+51h (411411h)?
004113F7? mov???????? eax,dword ptr [ebp-0E0h]????? ;對(duì)于分配的地址分配空間進(jìn)行賦值為:3
004113FD? mov???????? dword ptr [eax],3?
00411403? mov???????? ecx,dword ptr [ebp-0E0h]?
00411409? mov???????? dword ptr [ebp-0E8h],ecx?? ;似乎用[ebp - 0E0h]和[ebp - 0E8h]作為了中間存儲(chǔ)單元
0041140F? jmp???????? wmain+5Bh (41141Bh)?
00411411? mov???????? dword ptr [ebp-0E8h],0???? ;上面分配空間失敗是的操作
0041141B? mov???????? edx,dword ptr [ebp-0E8h]?
00411421? mov???????? dword ptr [pTest],edx?????????? ;數(shù)據(jù)最后送入pTest變量中
;調(diào)用printf函數(shù)進(jìn)行數(shù)據(jù)輸出
??? printf( "*pTest = %d/r/n", *pTest );??? //調(diào)用庫(kù)函數(shù)printf輸出數(shù)據(jù)
00411424? mov???????? esi,esp?? ;用于調(diào)用printf后的Esp檢測(cè),不明白編譯器為什么這樣做
00411426? mov???????? eax,dword ptr [pTest]?? ;提取要打印的數(shù)據(jù),先是地址,下面一條是提取具體數(shù)據(jù)
00411429? mov???????? ecx,dword ptr [eax]?
0041142B? push??????? ecx???????? ;兩個(gè)參數(shù)入棧
0041142C? push??????? offset string "*pTest = %d/r/n" (41573Ch)?
00411431? call??????? dword ptr [__imp__printf (4182C4h)]????? ;調(diào)用函數(shù)
00411437? add???????? esp,8???????? ;由于庫(kù)函數(shù)無(wú)出棧管理操作,同new與delete,所以要加 8,進(jìn)行堆棧處理
0041143A? cmp???????? esi,esp??????? ;對(duì)堆棧的棧頂進(jìn)行測(cè)試
0041143C? call??????? @ILT+325(__RTC_CheckEsp) (41114Ah)?
;進(jìn)行指針變量的清理工作
??? delete []pTest;??? ??? ??? ??? ??? ??? ??? //刪除這個(gè)指針
00411441? mov???????? eax,dword ptr [pTest]?? ;[pTest] 中放入的是分配的地址,下面幾條指令轉(zhuǎn)悠一圈
00411444? mov???????? dword ptr [ebp-0D4h],eax?? ;就是要把要清理的地址送入堆棧,然后調(diào)用delete函數(shù)
0041144A? mov???????? ecx,dword ptr [ebp-0D4h]?
00411450? push??????? ecx??
00411451? call??????? operator delete (411091h)?
00411456? add???????? esp,4???? ;對(duì)堆棧進(jìn)行處理,同new與printf函數(shù)
;函數(shù)結(jié)束后,進(jìn)行最終的清理工作
??? return 0;
00411459? xor???????? eax,eax?? ;做相應(yīng)的清理工作,堆棧中保存的變量送回原寄存器
}
0041145B? pop???????? edi??
0041145C? pop???????? esi??
0041145D? pop???????? ebx??
0041145E? add???????? esp,0E8h?????? ;進(jìn)行堆棧的棧頂判斷
00411464? cmp???????? ebp,esp?
00411466? call??????? @ILT+325(__RTC_CheckEsp) (41114Ah)?
0041146B? mov???????? esp,ebp?
0041146D? pop???????? ebp??
0041146E? ret??
--- No source file -------------------------------------------------------------;后面不再是源代碼
?
在列出反匯編程序時(shí)把反匯編代碼的上下的分解注釋也列了出來(lái),親手去查看的朋友可能會(huì)發(fā)現(xiàn)在這段代碼的之外的其他部分會(huì)有大量的int 3匯編中的中斷指令,這個(gè)是與上面的所說(shuō)的0CCCCCCCCh具有一致性,這些區(qū)域是無(wú)效區(qū)域,但代碼訪問(wèn)這些區(qū)域時(shí)就會(huì)出現(xiàn)非法訪問(wèn)提示。當(dāng)然,你應(yīng)該可以想到,那個(gè)提示是可以被屏蔽掉的,你可以把這部分區(qū)域填充上數(shù)據(jù)或者修改 iint 3 調(diào)用的中斷程序。
從以上反匯編程序,我們可以發(fā)現(xiàn)幾點(diǎn):
A、一些內(nèi)部的庫(kù)函數(shù)是不會(huì)對(duì)堆棧進(jìn)行出棧管理的,所以若要對(duì)反匯編程序進(jìn)行操作時(shí),一點(diǎn)要注意這一點(diǎn)
B、編譯器會(huì)自動(dòng)的加上一些對(duì)棧頂?shù)臋z查工作,這個(gè)是我們?cè)谧鯲C調(diào)試時(shí)經(jīng)常遇到的一個(gè)問(wèn)題,就是堆棧錯(cuò)誤
當(dāng)然以上只是對(duì)debug版本下的程序進(jìn)行反匯編,如果為release 版本,代碼就會(huì)進(jìn)行大量的優(yōu)化,在理解時(shí)會(huì)有一定的難度,有興趣朋友可以試著反匯編一下,推薦大家有IDA返回工具,感覺(jué)挺好用的。
?
?
?
?
版權(quán)聲明:本文為原創(chuàng)文章,轉(zhuǎn)載請(qǐng)標(biāo)明出處。 https://blog.csdn.net/u013467442/article/details/47060261VS 反匯編方法及常用匯編指令介紹
2012年09月27日 09:33:58 閱讀數(shù):11296?
?
在調(diào)試沒(méi)有源碼的文件時(shí),我們可能要用到反匯編設(shè)計(jì)。
一、VS反匯編方法
1、調(diào)出反匯編窗口。
2、調(diào)用寄存器窗口(只有在反匯編下才可見(jiàn))
如果在調(diào)試狀態(tài)還是沒(méi)有此菜單項(xiàng),可試著以下操作:
在VS中點(diǎn)擊“工具”->“導(dǎo)入和導(dǎo)出設(shè)置”,選擇“重置所有設(shè)置”,下一步,這時(shí)你可以保存當(dāng)前設(shè)置或不保存,我覺(jué)得無(wú)所謂,下一步,選擇“Visual C#開(kāi)發(fā)設(shè)置”,“完成”。這樣,“調(diào)試”->“窗口”->“寄存器”菜單項(xiàng)應(yīng)該用顯示出來(lái)了,記得要確保你的程序是在調(diào)試的過(guò)程中。
3、查看內(nèi)存
點(diǎn)擊“調(diào)試”->“窗口”->“內(nèi)存”->“內(nèi)存1”...“內(nèi)存4”(選一個(gè)就可以了。)。在內(nèi)存窗口中的“地址”欄輸入地址,按回車(chē)即可看到該地地址處的內(nèi)存信息。
?二、常用匯編指令介紹
1、常用指令
為了照顧到?jīng)]學(xué)過(guò)匯編程序的同志們,這里簡(jiǎn)單介紹一下常見(jiàn)的幾種匯編指令。
A、add:加法指令,第一個(gè)是目標(biāo)操作數(shù),第二個(gè)是源操作數(shù),格式為:目標(biāo)操作數(shù) = 目標(biāo)操作數(shù) + 源操作數(shù);
B、sub:減法指令,格式同 add;
C、call:調(diào)用函數(shù),一般函數(shù)的參數(shù)放在寄存器中;
D、ret:跳轉(zhuǎn)會(huì)調(diào)用函數(shù)的地方。對(duì)應(yīng)于call,返回到對(duì)應(yīng)的call調(diào)用的下一條指令,若有返回值,則放入eax中;
E、push:把一個(gè)32位的操作數(shù)壓入堆棧中,這個(gè)操作在32位機(jī)中會(huì)使得esp被減4(字節(jié)),esp通常是指向棧頂?shù)?#xff08;這里要指出的是:學(xué)過(guò)單片機(jī)的同學(xué)請(qǐng)注意單片機(jī)種的堆棧與Windows下的堆棧是不同的,請(qǐng)參考相應(yīng)資料),這里頂部是地址小的區(qū)域,那么,壓入堆棧的數(shù)據(jù)越多,esp也就越來(lái)越小;
F、pop:與push相反,esp每次加4(字節(jié)),一個(gè)數(shù)據(jù)出棧。pop的參數(shù)一般是一個(gè)寄存器,棧頂?shù)臄?shù)據(jù)被彈出到這個(gè)寄存器中;
一般不會(huì)把sub、add這樣的算術(shù)指令,以及call、ret這樣的跳轉(zhuǎn)指令歸入堆棧相關(guān)指令中。但是實(shí)際上在函數(shù)參數(shù)傳遞過(guò)程中,sub和add最常用來(lái)操作堆棧;call和ret對(duì)堆棧也有影響。
?
G、mov:數(shù)據(jù)傳送。第一個(gè)參數(shù)是目的操作數(shù),第二個(gè)參數(shù)是源操作數(shù),就是把源操作數(shù)拷貝到目的一份。
H、xor:異或指令,這本身是一個(gè)邏輯運(yùn)算指令,但在匯編指令中通常會(huì)見(jiàn)到它被用來(lái)實(shí)現(xiàn)清零功能。
????????????? 用 xor eax,eax這種操作來(lái)實(shí)現(xiàn) mov eax,0,可以使速度更快,占用字節(jié)數(shù)更少。
I、lea:取得第二個(gè)參數(shù)地址后放入到前面的寄存器(第一個(gè)參數(shù))中。
???????????????然而lea也同樣可以實(shí)現(xiàn)mov的操作,例如:
????????????????????????????????? lea edi,[ebx-0ch]
方括號(hào)表示存儲(chǔ)單元,也就是提取方括號(hào)中的數(shù)據(jù)所指向的內(nèi)容,然而lea提取內(nèi)容的地址,這樣就實(shí)現(xiàn)了把(ebx-0ch)放入到了edi中,但是mov指令是不支持第二個(gè)操作數(shù)是一個(gè)寄存器減去一個(gè)數(shù)值的。
?
J、stos:串行存儲(chǔ)指令,它實(shí)現(xiàn)把eax中的數(shù)據(jù)放入到edi所指的地址中,同時(shí)edi后移4個(gè)字節(jié),這里的stos實(shí)際上對(duì)應(yīng)的是stosd,其他的還有stosb,stosw分別對(duì)應(yīng)1,2個(gè)字節(jié)。
K、jmp:無(wú)條件跳轉(zhuǎn)指令,對(duì)應(yīng)于大量的條件跳轉(zhuǎn)指令。
L、jg:條件跳轉(zhuǎn),大于時(shí)成立,進(jìn)行跳轉(zhuǎn),通常條件跳轉(zhuǎn)之前會(huì)有一條比較指令(用于設(shè)置標(biāo)志位)。
M、jl:小于時(shí)跳轉(zhuǎn)。
N、jge:大于等于時(shí)跳轉(zhuǎn)。
O、cmp:比較大小指令,結(jié)果用來(lái)設(shè)置標(biāo)志位。
2? 、函數(shù)參數(shù)傳遞方式
函數(shù)調(diào)用規(guī)則指的是調(diào)用者和被調(diào)用函數(shù)間傳遞參數(shù)及返回參數(shù)的方法,在Windows上,常用的有Pascal方式、WINAPI方式(_stdcall)、C方式(_cdecl)。
A、_cdecl C調(diào)用規(guī)則:
(a)參數(shù)從右到左進(jìn)入堆棧;
(b)在函數(shù)返回后,調(diào)用者要負(fù)責(zé)清除堆棧,這種調(diào)用方式通常會(huì)生成較大的可執(zhí)行程序。
B、_stdcall又稱(chēng)為WINAPI,調(diào)用規(guī)則如下:
(a)參數(shù)從右到左進(jìn)入堆棧;
(b)被調(diào)用的函數(shù)在返回前自行清理堆棧,這種方式生成的代碼比cdecl小。
C、Pascal調(diào)用規(guī)則(主要用于Win16函數(shù)庫(kù)中,現(xiàn)在基本不用):
(a)參數(shù)從左到右進(jìn)入堆棧;
(b)被調(diào)用的函數(shù)在返回前自行清理堆棧。
(c)不支持可變參數(shù)的函數(shù)調(diào)用。
?
?
VS2015使用技巧 調(diào)試-反匯編 查看C語(yǔ)言代碼對(duì)應(yīng)的匯編代碼
時(shí)間:2017-02-26 21:27:26????? 閱讀:9414????? 評(píng)論:0????? 收藏:0??????[點(diǎn)我收藏+]標(biāo)簽:vs2015使用技巧???調(diào)試-反匯編???查看c語(yǔ)言代碼對(duì)應(yīng)的匯編代碼???
鎮(zhèn)場(chǎng)文:
?????? 學(xué)儒家經(jīng)世致用,行佛家普度眾生,修道家全生保真,悟易理象數(shù)通變。以科技光耀善法,成就一良心博客。
______________________________________________________________________________________________________
code:
?
查看反匯編步驟:
????step0?
????????在一行上設(shè)置斷點(diǎn),鼠標(biāo)挪到最左邊 豎著的條條 處,點(diǎn)擊一下即可設(shè)置斷點(diǎn)
?
?
????step1
????????按F5或者 調(diào)試->開(kāi)始調(diào)試
?
????step1 show:
?
????step2:
????????點(diǎn)擊 調(diào)試->窗口->反匯編
?
????step2 show:
????????這個(gè)就是C語(yǔ)言對(duì)應(yīng)的匯編語(yǔ)言啦。我的電腦是64位的。
總結(jié)
以上是生活随笔為你收集整理的浅析VS2010反汇编 VS 反汇编方法及常用汇编指令介绍 VS2015使用技巧 调试-反汇编 查看C语言代码对应的汇编代码...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: JDBC事务和JTA事务的区别 --包含
- 下一篇: 前端html笔记