《软件调试分析技术》学习笔记
《軟件調(diào)試分析技術(shù)》學(xué)習(xí)筆記(一)
今天開始寫寫一些心得體驗。
《軟件調(diào)試分析技術(shù)》是好友Monster的處女作品。作為一直以的好伙伴,他是我看著長大的,(*^__^*) 嘻嘻……之所以有今天這樣的成績,是與他的努力和天賦脫不了關(guān)系的。他大方地給了我PDF版的,我也大方的給了我們?nèi)唷5覀儼嘤型瑢W(xué)說,“這是撒子呦,看不看不懂”。我決心寫一些學(xué)習(xí)筆記,和我班的同學(xué)一起來多交流,讓更多熱愛次行業(yè)的人都進入軟件調(diào)試這個神殿。
?
好了,閑話不說。
1)逆向工程(reverse engineering)簡介
逆向工程是通過對現(xiàn)有的二進制可執(zhí)行文件進過反匯編、反編譯、調(diào)試模擬程序運行等手段,分析出程序的執(zhí)行流程、數(shù)據(jù)結(jié)構(gòu)等。
逆向工程不是簡單的復(fù)制和模仿,而是運用相關(guān)手段對產(chǎn)品進行分析再設(shè)計等創(chuàng)新處理,從而使程序表現(xiàn)出更加優(yōu)良的性能、縮短新程序的開發(fā)周期、提高設(shè)計開發(fā)效率。
2)學(xué)習(xí)前提
建議在學(xué)習(xí)逆向分析技術(shù)之前有一定的編程功底。具有一定的代碼邏輯能力,最好還做過一些Windows應(yīng)用程序,了解一些常用的API,PE文件格式、COM原理、Windows的消息處理機制、異常處理機制等。需要和二進程代碼打交道,所以一定要掌握好匯編語言(更重要的是反匯編)
由此可以看出來,同學(xué)們不是智商不夠,而是基礎(chǔ)知識比較薄弱
3)常用工具
調(diào)試工具OllyDBG、SoftICE、WinDBG、Syser Debugger,分析工具PEID、ExeInfo、FI、FFI…… 等,常見的PE工具有:LoadPE、PETools、Stud_PE、PEditor等,常見的反匯編工具有:IDA pro、W32dASM、C32ASM等。
M運用了很多篇幅簡單介紹了各個工具的使用,我認為,這些工具的使用要在平常實戰(zhàn)中漸漸熟悉,所以沒必要將此章目看的過細。本人也只用過OllyDBG。
4)windows消息處理機制
5)PE文件格式
PE 的意思就是Portable Executable(可移植的執(zhí)行體)。它是Win32環(huán)境自身所帶的執(zhí)行體文件格式。它的一些特性繼承自Unix的Coff (common object file format)文件格式。PE文件格式給了我們洞悉Windows結(jié)構(gòu)的良機。
| DOS MZ header |
| DOS stub |
| PE header |
| Section table |
| Section 1 |
| Section 2 |
| Section ... |
| Section n |
?
?
上圖是 PE文件結(jié)構(gòu)的總體層次分布。所有PE文件(甚至32位的DLLs)必須以一個簡單的DOS MZ header開始。我們通常對此結(jié)構(gòu)沒有太大興趣。有了它,一旦程序在DOS下執(zhí)行,DOS就能識別出這是有效的執(zhí)行體,然后運行緊隨MZ header 之后的DOS stub。DOS stub實際上是個有效的EXE,在不支持PE文件格式的操作系統(tǒng)中,它將簡單顯示一個錯誤提示,類似于字符串"This program requires Windows"或者程序員可根據(jù)自己的意圖實現(xiàn)完整的 DOS代碼。通常我們也不對DOS stub太感興趣:因為大多數(shù)情況下它是由匯編器/編譯器自動生成。通常,它簡單調(diào)用中斷21h服務(wù)9來顯示字符串"This program cannot run in DOS mode"。
緊接著 DOS stub的是PE header。PE header是PE相關(guān)結(jié)構(gòu)IMAGE_NT_HEADERS的簡稱,其中包含了許多PE裝載器用到的重要域。當(dāng)我們更加深入研究PE文件格式后,將對這些重要域耳目能詳。執(zhí)行體在支持PE文件結(jié)構(gòu)的操作系統(tǒng)中執(zhí)行時,PE裝載器將從DOS MZ header 中找到PE header 的起始偏移量。因而跳過了DOS stub直接定位到真正的文件頭PE header。PE文件的真正內(nèi)容劃分成塊,稱之為sections(節(jié))。每節(jié)是一塊擁有共同屬性的數(shù)據(jù),比如代碼/數(shù)據(jù)、讀/寫等。我們可以把PE文件想象成一邏輯磁盤,PE header 是磁盤的boot扇區(qū),而sections就是各種文件,每種文件自然就有不同屬性如只讀、系統(tǒng)、隱藏、文檔等等。
上述為摘抄,翻譯的不是很好
PE文件最前面緊隨DOS MZ文件頭的是一個DOS可執(zhí)行文件(Stub)。這使得PE文件成為一個合法的MS-DOS可執(zhí)行文件。DOS? MZ文件頭后面是一個32位的PE文件標志0x50450000(IMAGE_NT_SIGNATURE),即PE00。接下來的是PE的映像文件頭,包含的信息有該程序的運行平臺,有多少個節(jié),文件鏈接的時間,文件命名格式,后面還緊跟一個可選映像頭,包含PE文件的邏輯分布信息,程序加載信息,開始地址,保留的堆棧數(shù)量,數(shù)據(jù)段大小等。可選頭還有一個重要的域,稱為“數(shù)據(jù)目錄表”的數(shù)組,表的每一項都是指向某一節(jié)的指針。可選映像頭后面緊跟的是節(jié)表和節(jié)。節(jié)通過節(jié)表來實現(xiàn)索引。實際上,節(jié)的內(nèi)容才是真正執(zhí)行的數(shù)據(jù)和程序。每一個節(jié)都有相關(guān)的標志。每一個節(jié)會被一個或多個目錄表指向,目錄表可通過可選頭的“數(shù)據(jù)目錄表”的入口找到。就像輸出函數(shù)表或基址重定位表。也存在沒有目錄表指向的節(jié)。
具體PE還有很多,這里只是一個初步的探究,如果想深入,網(wǎng)上找資料。
《軟件調(diào)試分析技術(shù)》學(xué)習(xí)筆記(二)
1.寄存器
寄存器M講的比較透徹。寄存器是中央處理器CPU的組成部分,是有限存貯容量的高速存貯部件,它們可用來暫存指
令、數(shù)據(jù)和位址,是內(nèi)存階層中的最頂端,也是系統(tǒng)獲得操作資料的最快速途徑。
1.1數(shù)據(jù)寄存器??
??? 數(shù)據(jù)寄存器主要用來保存操作數(shù)和運算結(jié)果等信息,從而節(jié)省讀取操作數(shù)所需占用總線和訪問
存儲器的時間。這些 低16位寄存器分別命名為:AX、BX、CX和DX,它和先前的CPU中的寄存器
相一致。在16位CPU中,AX、BX、CX和DX不能作為基址和變址寄存器來存放存儲單元的地址,
但在32位CPU中,其32位寄存器EAX、EBX、ECX和EDX不僅可傳送數(shù)據(jù)、暫存數(shù)據(jù)保存算術(shù)邏輯
運算結(jié)果,而且也可作為指針寄存器, 所以,這些32位寄存器更具有通用性。
1.2變址寄存器
??? 寄存器ESI、EDI、SI和DI稱為變址寄存器(Index Register),它們主要用于存放存儲單元在段內(nèi)
的偏移量, 用它們可實現(xiàn)多種存儲器操作數(shù)的尋址方式,為以不同的地址形式訪問存儲單元提供
方便。它們可作一般的存儲器指針使用。在字符串操作指令的執(zhí)行過程中,對它們有特定的要求,
而且還具有特 殊的功能。
1.3指針寄存器
??? 寄存器EBP、ESP、BP和SP稱為指針寄存器(Pointer Register),主要用于存放堆棧內(nèi)存儲單元
的偏移量, 用它們可實現(xiàn)多種存儲器操作數(shù)的尋址方式,為以不同的地址形式訪問存儲單元提供
方便。指針寄存器不可分割成8位寄存器。作為通用寄存器,也可存儲算術(shù)邏輯運算的操作數(shù)和運
算結(jié)果
它們主要用于訪問堆棧內(nèi)的存儲單元,并且規(guī)定:
BP為基指針(Base Pointer)寄存器,用它可直接存取堆棧中的數(shù)據(jù);?
SP為堆棧指針(Stack Pointer)寄存器,用它只可訪問棧頂。
1.4段寄存器
??? 段寄存器是根據(jù)內(nèi)存分段的管理模式而設(shè)置的。內(nèi)存單元的物理地址由段寄存器的值和一個偏
移量組合而成 的,這樣可用兩個較少位數(shù)的值組合成一個可訪問較大物理空間的內(nèi)存地址
1.5指令指針寄存器
??? 指令指針EIP、IP(Instruction Pointer)是存放下次將要執(zhí)行的指令在代碼段的偏移量。在具有預(yù)
取指令功能的系統(tǒng)中,下次要執(zhí)行的指令通常已被預(yù)取到指令隊列中,除非發(fā)生轉(zhuǎn)移情況。
1.6標志寄存器
??? 標志寄存器(Flags Register,FR)又稱程序狀態(tài)字(Program Status Word,PSW)。這是一個存
放條件標志、控制標志寄存器,主要用于反映處理器的狀態(tài)和運算結(jié)果的某些特征及控制指令的執(zhí)
行。
其中有些要有一定的匯編基礎(chǔ),希望大家好好在實踐里體驗。
2? 匯編指令
??? 匯編指令是匯編語言中使用的一些操作符和助記符,還包括一些偽指令(如assume,end)。用
于告訴匯編程序如何進行匯編的指令,它既不控制機器的操作也不被匯編成機器代碼,只能為匯編
程序所識別并指導(dǎo)匯編如何進行。匯編指令多到數(shù)不過來。這里來介紹些常用到的:
一、數(shù)據(jù)傳輸指令
MOV??????? 傳送字或字節(jié)
PUSH?????? 把字壓入堆棧
POP??????? 把字彈出堆棧
PUSHA????? 把AX,CX,DX,BX,SP,BP,SI,DI依次壓入堆棧
POPA?????? 把DI,SI,BP,SP,BX,DX,CX,AX依次彈出堆棧
PUSHAD???? 把EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI依次壓入堆棧
POPAD????? 把EDI,ESI,EBP,ESP,EBX,EDX,ECX,EAX依次彈出堆棧
PUSHF????? 標志入棧
POPF?????? 標志出棧
LEA??????? 裝入有效地址
LDS??????? 傳送目標指針,把指針內(nèi)容裝入DS
LES??????? 傳送目標指針,把指針內(nèi)容裝入ES
LAHF?????? 標志寄存器傳送,把標志裝入AH
SAHF?????? 標志寄存器傳送,把AH內(nèi)容裝入標志寄存器
二、算術(shù)運算指令
ADD??????? 加法
ADC??????? 帶進位加法
INC??????? 加 1?
SUB??????? 減法
SBB??????? 帶借位減法
DEC??????? 減 1
NEC??????? 求相反數(shù)(以 0 減之)
CMP??????? 比較(兩操作數(shù)作減法,僅修改標志位,不回送結(jié)果)
MUL??????? 無符號乘法
IMUL?????? 整數(shù)乘法
DIV??????? 無符號除法
IDIV?????? 整數(shù)除法
三、邏輯運算指令
OR???????? 或運算
AND??????? 與運算
XOR??????? 異或運算
NOT??????? 取反
TEST?????? 測試,兩操作數(shù)作與運算,僅修改標志位,不回送結(jié)果
SHL??????? 邏輯左移
SHR??????? 邏輯右移
ROL??????? 循環(huán)左移
ROR??????? 循環(huán)右移
RCL??????? 通過進位的循環(huán)左移
RCR??????? 通過進位的循環(huán)右移
四、串指令
MOVSX????? 先符號擴展,再傳送
MOVZX????? 先零擴展,再傳送
MOVS?????? 串傳送
CMPS?????? 串比較
五、程序轉(zhuǎn)移指令
JMP??????? 無條件轉(zhuǎn)移指令
CALL?????? 過程調(diào)用
RET??????? 過程返回
JG/JNLE??? 大于轉(zhuǎn)移
JGE/JNL??? 大于或等于轉(zhuǎn)移
JL/JNGE??? 小于轉(zhuǎn)移
JLE/JNG??? 小于或等于轉(zhuǎn)移
JE/JZ????? 等于轉(zhuǎn)移
JNE/JNZ??? 不等于時轉(zhuǎn)移
LOOP?????? CX不為零時循環(huán)
《軟件調(diào)試分析技術(shù)》學(xué)習(xí)筆記(三)
M給出一個C程序
[cpp] view plaincopy
?
這段代碼定義了一個整型全局變量a,在主函數(shù)main()中定義了一個整型局部變量b和一個整形指針變量c,然后調(diào)用malloc()函數(shù)申請大小為1個整形變量的內(nèi)存并把申請到的內(nèi)存地址賦值給指針變量c,再依次給變量a、b和c指向的內(nèi)存賦值1、2、3,接下來釋放剛才申請到的堆內(nèi)存,釋放后退出主函數(shù)main()。
?
用OD加載
[plain] view plaincopy這里把棧頂向下壓8個字節(jié),為整型變量b和指針變量c開辟空間。它們都是局部變量。
[plain] view plaincopy一個整型變量占用的空間為4個字節(jié),這里調(diào)用函數(shù)malloc()申請大小為4個字節(jié)的堆空間,然
后把申請到的內(nèi)存空間地址賦值給變量c。
這里分別給三個變量賦值1、2、3。可以看到變量a所使用的內(nèi)存空間地址是一個常量,它存在于程序的數(shù)據(jù)段中;變量b所使用到的內(nèi)存空間地址是ebp+b,它位于棧區(qū);指針變量c儲存的數(shù)據(jù)是剛才由函數(shù)malloc()申請到的堆空間地址。
《軟件調(diào)試分析技術(shù)》學(xué)習(xí)筆記(四)
[plain] view plaincopy
?
這段代碼定義了一個大小為2的整型數(shù)組,給數(shù)組下標為1的變量賦值0,然后取數(shù)組下標為1的變量的值作為新的下標,給該變量賦值1,這里數(shù)組下標為1的變量的值為0,就是說給數(shù)組下標為0的變量賦值1,最后退出主函數(shù)main()。
載入OD看看反匯編代碼:
?
[plain] view plaincopy
這里為數(shù)組a開辟內(nèi)存空間。一個整型變量所占的內(nèi)存空間為4字節(jié),數(shù)組a的大小為2,因此把棧頂向下壓8個字節(jié)。
?
[plain] view plaincopy
? 只要知道數(shù)組就是一個指針,這句代碼就很容易理解了。OD是一個好工具,這里它已經(jīng)分析出a是一個數(shù)組了,而ebp+a是數(shù)組的基地址。a是一個整型數(shù)組,其中的每一個變量占用的大小都是4字節(jié),因此在數(shù)組中下標為i的變量的地址就可以表示為數(shù)組的基地址加上數(shù)組下標為i的變量與數(shù)組下標為0的變量的偏移量,即ebp+a+i*4,這一句代碼中的地址ebp+a+1*4就是數(shù)組下標為1的變量的地址。
這兩句代碼,獲取數(shù)組中下標為1的變量的值,把這個值作為新的數(shù)組下標eax,并給數(shù)組下標為eax的變量賦值1。
[plain] view plaincopy《軟件調(diào)試分析技術(shù)》學(xué)習(xí)筆記(五)
在了解了變量的使用方式之后,本節(jié)來講講數(shù)在反匯編代碼中的簡單運算。??計算機在使用數(shù)的時候一般會用到二進制,十進制和十六進制。
二進制是計算機技術(shù)中廣泛采用的一種數(shù)制。二進制數(shù)據(jù)是用0和1兩個數(shù)碼來表示的數(shù)。它的基數(shù)為2,進位規(guī)則是“逢二進一”,借位規(guī)則是“借一當(dāng)二”。現(xiàn)在的CPU使用的基本都是二進程數(shù),用高電平表示1,低電平表示0。為了方便區(qū)別,一般在二進程數(shù)后追加一個字母B,例如二進制數(shù)10則表示為10B。B是二進制的英文binary的首字母。
??? 在人們的日常生活使用的數(shù)一般都是十進制數(shù)。人類的各種古文明都很有默契地使用十進制數(shù),這與人類有十根手指有密切的關(guān)系。十進制數(shù)使用十個數(shù)碼0123456789來表示,逢十進一。為了方便區(qū)別,一般在十進程數(shù)后追加一個字母D,例如十進制數(shù)10則表示為10D。D是十進制的英文decimal的首字母。
??? 在計算機中使用的十進制數(shù)一般是BCD碼,BCD碼用4位二進制數(shù)來表示1位十進制數(shù)。例如在二進制數(shù)10000B表示十進制數(shù)的16D,而BCD碼10000卻表示十進制數(shù)10D,它們在內(nèi)存中的儲存形式完全相同,但表示的數(shù)卻不同。
??? 雖然計算機在處理數(shù)據(jù)時使用的是二進制數(shù),但是二進制數(shù)表示起來是很不方便的,例如一個十進制數(shù)1000000D要表示成二進制數(shù)則為11110100001001000000B。4位二進制數(shù)能表示的最小的數(shù)為0000B,能表示的最大的數(shù)是1111B,即十進制數(shù)15D,這樣就可以用4位二進制數(shù)來表示16個數(shù)字,把這十六個數(shù)字分別用一個數(shù)碼來表示,于是就行成了十六進制數(shù)。十六進制數(shù)用01234567890ABCDEF這十六個數(shù)碼來表示0-15D這十六個數(shù),每逢十六進一。為了方便表示,為了方便區(qū)別,一般在十六進程數(shù)后追加一個字母H,例如十六進制數(shù)10則表示為10H。H是十六進制的英文hexadecimal的首字母。一般在程序中用到的十六進制數(shù)的表示方法是在數(shù)之前加前綴0x,例如十六進制數(shù)10則表示為0x10。
??? 通常這三種進制的數(shù)之間還需要互相轉(zhuǎn)化。一位十六進程數(shù)和四位二進制數(shù)是互相對應(yīng)的,對應(yīng)關(guān)系如下:
十六進制數(shù)??? 二進制數(shù)??????? 十六進制數(shù)??? 二進制數(shù)
0???????????? 0?????????????? 8???????????? 1000
1???????????? 1?????????????? 9???????????? 1001
2???????????? 10????????????? A???????????? 1010
3???????????? 11????????????? B???????????? 1011
4???????????? 100???????????? C???????????? 1100
5???????????? 101???????????? D???????????? 1101
6???????????? 110???????????? E???????????? 1110
7???????????? 111???????????? F???????????? 1111
??? 了解了這個轉(zhuǎn)化方式那要轉(zhuǎn)化就很容易了,例如十六進制數(shù)0xBC就可以用二進制數(shù)10111100B;相反地,二進制數(shù)1001010B也可以表示為十六進制數(shù)0x4A。二進程數(shù)與十進制數(shù)之間的轉(zhuǎn)換也是比較容易的。我記得當(dāng)年學(xué)《微型計算機原理》的時候課本上有一句口訣:十進制數(shù)轉(zhuǎn)化二進制數(shù),除二取余;二進制數(shù)轉(zhuǎn)化十進制數(shù),乘二取整。聽起來可能不太好理解,但這是轉(zhuǎn)化方法的精髓。把十進制數(shù)轉(zhuǎn)換成二進制數(shù),是一個連續(xù)除2的過程,把要轉(zhuǎn)換的十進制數(shù)數(shù),除以2,得到一組商和余數(shù);再用計算得到的商來計算,除以2,又得到另一組商和余數(shù)。這樣一直計算到得到的商為零為止,計算結(jié)束后把每一次計算的余數(shù)從后往前連起來就得到了這個十進制數(shù)對應(yīng)的二進程數(shù)。例如現(xiàn)在有一個十進制11D,轉(zhuǎn)化過程如下:
11 / 2??????? 商:5?? 余:1
5? / 2??????? 商:2?? 余:1
2? / 2??????? 商:1?? 余:0
1? / 2??????? 商:0?? 余:1
??? 把每一次計算的余數(shù)從后往前連起來則為1011,這樣就計算出了十進制數(shù)11D對應(yīng)的二進制數(shù)1011B。二進制數(shù)轉(zhuǎn)化十進制數(shù)相對簡單一點。二進制數(shù)從右往左數(shù)第n位表示2的n-1次冪,當(dāng)?shù)趎位為0時忽略,把第n位為1的所有冪加起來就得到了這個十進制數(shù)。例如一個二進制數(shù)1011B,轉(zhuǎn)化過程如下:
2^3 + 2^1 + 2^0 = 8 + 2 + 1 = 11
??? 那么11D就是二進制數(shù)1011B所對應(yīng)的十進制數(shù)。
??? 再來看看另一個問題,機器碼的表示方法。機器碼的出現(xiàn)主要是為了解決計算機中數(shù)的符號和計算問題。這里介紹計算機的原碼、反碼、補碼。
??? 原碼是一種計算機中對數(shù)字的二進制定點表示方法。原碼表示法在數(shù)值前面增加了一位符號位(即最高位為符號位),符號位為0表示正數(shù)或者0,符號位為1表示負數(shù),其余位表示數(shù)值的大小。例如一個int型的十進制數(shù)100,用原碼表示則為:0000000001100100;同樣一個int型的十進制數(shù)-100,用原碼表示則為:1000000001100100。用原碼這樣來表示一個數(shù)是很直觀的,但是它有一個很嚴重的缺點,就是源碼不可以直接進行運算。1 + (-1) = 0,這是很顯然的,用源碼計算:
0000000000000001 + 1000000000000001 = 1000000000000010
??? 用原碼計算的結(jié)果為1000000000000010,轉(zhuǎn)換為十進制數(shù)則是-2,這顯然是錯誤的。 反碼是原碼到補碼之間的一個過渡產(chǎn)品,它的求法很簡單,正數(shù)的反碼與其原碼相同;負數(shù)的反碼對其絕對值的原碼逐位求反例如一個int 型的十進制數(shù)100,用原碼表示則為:
0000000001100100
同樣一個int型的十進制數(shù)-100,其絕對值為100,其絕對值的原碼為
0000000001100100,逐位求反則得-100的反碼為:1111111110011011。
??? 補碼是計算機程序在進行運算時統(tǒng)一使用的機器碼,他可以將符號位和其它位統(tǒng)一處理。另外,兩個用補碼表示的數(shù)相加時,如果最高位(符號位)有進位,則進位被舍棄。補碼的計算方法也很簡單,正數(shù)的補碼和它的原碼相等,負數(shù)的補碼等于它的反碼加一。例如一個int型的十進制數(shù)-1,其補碼計算過程為:首先求出它的絕對值為1,計算它的絕對值1的原碼
0000000000000001,
逐位求反則得-1的反碼為:1111111111111110,給它加1就變成了:
1111111111111111。
反碼可以直接帶入運算,例如用反碼來計算1 + (-1):
0000000000000001 + 1111111111111111 = 0
??? 然后來看看幾種基本的邏輯運算。邏輯常量只有兩個,即0和1,用來表示兩個對立的邏輯狀態(tài)。邏輯運算通常用來測試邏輯常量的真假值。大于、大于等于、小于、小于等于、等于、不等于……這些用來比較的邏輯運算就不講了,上過小學(xué)的讀者肯定都會的。這里來看看與運算、或運算、異或運算以及非運算。
??? 與運算,把兩個操作數(shù)的逐位進行比較,若兩個操作數(shù)的第n位全為1,則運算結(jié)果的第n位為
1,否則為0。匯編語言中用and指令來表示與運算,例如:
0010110011010100
1010110010011010
and
-------------------
0010110010010000
??? 或運算,把兩個操作數(shù)的逐位進行比較,若兩個操作數(shù)的第n位若有一個為1,則運算結(jié)果的第n位為1,否則為0。匯編語言中用or指令來表示或運算,例如:
0010110011010100
1010110010011010
or
-------------------
1010110011011110
??? 異或運算,把兩個操作數(shù)的逐位進行比較,若兩個操作數(shù)的第n位有一個為0,而另一個為1,則運算結(jié)果的第n位為1,否則為0。匯編語言中用xor指令來表示異或運算,例如:
0010110011010100
1010110010011010
xor
-------------------
1000000001001110
??? 非運算,只有一個操作數(shù),它的計算方法是把該操作數(shù)逐位求反。匯編語言中用not指令來表示非運算,例如:
1010110010011010
not
-------------------
0101001101100101
??? 筆者猶記得,當(dāng)年教的模擬電路老師的幾句簡單的口令:與運算,有零則零;或運算,有一則
《軟件調(diào)試分析技術(shù)》學(xué)習(xí)筆記(六)
異或運算,相同則1,不同則0;非運算,零則一,一則零。
??? 明白了機器數(shù)和運算的原理以后來看看它們在程序運算中的具體使用方法。C語言代碼如下:
這段代碼定義了三個整型變量a、b、c,給變量a賦值1,給變量b賦值2,然后分別進行加、減、乘、除、模、與、或、異或還有非運算。看反匯編代碼:
這里抬高棧頂,用來為定義的局部變量開辟儲存空間。一個整型變量占4字節(jié),那么0x0C字節(jié)則可開辟出三個整型變量的空間,用來儲存整型變量a、b、c。
?
這兩句分別對應(yīng)C語言代碼a = 1;和b = 2;。用來給整型變量a、b賦值。
[plain] view plaincopy? 這里取變量a到eax中,然后把eax和變量b相加,最后把結(jié)果放到變量c里。
[plain] view plaincopy
這里取變量a到ecx中,然后把ecx和變量b相減,最后把結(jié)果放到變量c里。
這里取變量a到edx中,然后把edx和變量b相乘,最后把結(jié)果放到變量c里。
這里取變量a到eax中,接著擴展符號位,然后除以變量b,最后把商放到變量c里。
[plain] view plaincopy
這里取變量a到eax中,接著擴展符號位,然后除以變量b,最后把余數(shù)放到變量c里,這里和上面的除法運算的代碼是很像的,只有最后儲存運算結(jié)果的時候不同,除法運算儲存的是eax的值,而模運算儲存的是edx的值。細心的讀者可能注意到了,做除法運算的時候多了一條cdq指令,它是干什么的?還有,idiv指令只有一個操作數(shù)它是怎么完成除法運算的。
??? 其實dcq指令的作用是將雙字符號擴展至8字節(jié),指的是擴展eax的符號位至edx寄存器中,也就是說,當(dāng)eax小于80000000時使edx為00000000,當(dāng)eax大于等于80000000時使edx為FFFFFFFF。
??? idiv指令是有符號除法,被除數(shù)沒有的指令中標出來,它是edx:eax。當(dāng)idiv指令有操作數(shù)的時候,除數(shù)是操作數(shù);如果沒有操作數(shù),那么除數(shù)就是ecx。指令的運算結(jié)果:eax為商,edx是余數(shù)。
這里取變量a到ecx中,然后把ecx和變量b做與運算,最后把結(jié)果放到變量c里。
這里取變量a到ecx中,然后把ecx和變量b做或運算,最后把結(jié)果放到變量c里。
?
[plain] view plaincopy?這里取變量a到edx中,然后把edx和變量b做異或運算,最后把結(jié)果放到變量c里。
[plain] view plaincopy這里取變量a到eax中,然后把eax和變量b做非運算,最后把結(jié)果放到變量c里。
[plain] view plaincopy總結(jié)
以上是生活随笔為你收集整理的《软件调试分析技术》学习笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WPF Application启动界面设
- 下一篇: 什么样的项目经历会让面试官眼前一亮