簡單的順序結構逆向分析-->四則運算
使用工具:VS2013,Ollydbg
源代碼:
#include <windows.h>
//定義全局變量
int nGlobal = 5;
char cGlobal = 'a';
int main()
{
//定義局部變量
int nLocal_1 = 0;
int nLocal_2 = 8;
//變量之間進行運算
nLocal_1 += nGlobal;
nLocal_2 = nLocal_1 * 4;
nLocal_1 += cGlobal;
cGlobal += 2;
nLocal_1 -= 5;
nLocal_2 /= 2;
return 0;
}
爲了更好的鍛鍊讀彙編的能力,在VS的debug或者release目錄下,把pdb符號文件刪除,否則加載到Ollydbg中會出現很多提示,導致分析難度大大降低
使用OllyDbg加載後,main()函數:
00121380 55 push ebp
00121381 8BEC mov ebp,esp
00121383 81EC D8000000 sub esp,0xD8
00121389 53 push ebx
0012138A 56 push esi ; Reverse_.<ModuleEntryPoint>
0012138B 57 push edi
0012138C 8DBD 28FFFFFF lea edi,dword ptr ss:[ebp-0xD8]
00121392 B9 36000000 mov ecx,0x36
00121397 B8 CCCCCCCC mov eax,0xCCCCCCCC
0012139C F3:AB rep stos dword ptr es:[edi]
0012139E C745 F8 0000000>mov dword ptr ss:[ebp-0x8],0x0 ; 局部變量1 int nLocal_1 = 0;
001213A5 C745 EC 0800000>mov dword ptr ss:[ebp-0x14],0x8 ; 局部變量2 int nLocal_2 = 8;
001213AC 8B45 F8 mov eax,dword ptr ss:[ebp-0x8] ; 局部變量1放到EAX中,爲後面的加法做準備
001213AF 0305 00801200 add eax,dword ptr ds:[0x128000] ; nLocal_1 = nLocal_1+nGlobal
001213B5 8945 F8 mov dword ptr ss:[ebp-0x8],eax ; 把加完之後的值賦值給nLocal_1,相當於更新nLocal_1的值
001213B8 8B45 F8 mov eax,dword ptr ss:[ebp-0x8] ; 把新的nLocal_1的值放到EAX中,爲後面的乘法做準備
001213BB C1E0 02 shl eax,0x2 ; 左移2,就相當於*4
001213BE 8945 EC mov dword ptr ss:[ebp-0x14],eax ; nLocal_2 = nLocal_1 *
001213C1 0FBE05 04801200 movsx eax,byte ptr ds:[0x128004] ; 把全局變量cGlobal放到EAX中,準備加法
001213C8 0345 F8 add eax,dword ptr ss:[ebp-0x8] ; nLocal_1 = nLocal_1+cGlobal
001213CB 8945 F8 mov dword ptr ss:[ebp-0x8],eax ; 更新nLocal_1的值
001213CE 0FBE05 04801200 movsx eax,byte ptr ds:[0x128004]
001213D5 83C0 02 add eax,0x2
001213D8 A2 04801200 mov byte ptr ds:[0x128004],al ; cGlobal = cGlobal + 2;
001213DD 8B45 F8 mov eax,dword ptr ss:[ebp-0x8]
001213E0 83E8 05 sub eax,0x5
001213E3 8945 F8 mov dword ptr ss:[ebp-0x8],eax ; nLocal_1 = nLocal_1 - 5;
001213E6 8B45 EC mov eax,dword ptr ss:[ebp-0x14]
001213E9 99 cdq ; 下面會有介紹
001213EA 2BC2 sub eax,edx
001213EC D1F8 sar eax,1 ; 右移1位,相當於除以2
001213EE 8945 EC mov dword ptr ss:[ebp-0x14],eax ; nLocal_2 = nLocal_2 / 2;
001213F1 33C0 xor eax,eax ; 把EAX清零
001213F3 5F pop edi ; 還原edi,保證edi的值和剛進入函數時的值相同
001213F4 5E pop esi ; 還原esi
001213F5 5B pop ebx ; 還原ebx
001213F6 8BE5 mov esp,ebp
001213F8 5D pop ebp ; Reverse_.<ModuleEntryPoint>
001213F9 C3 retn
上面出現了幾個不是很常見的指令,接下來單獨介紹一下:
1、rep stos
rep是重複指令,stos表示把EAX中的值放到EDI指向的地址中,相當於是給堆棧初始化一片區域
EDI地址變化的方向由DF決定,DF = 1,EDI的值會往遞減的方向變化;如果DF= 0,那麼EDI的值就會往遞增的方向變化
完整的指令:
mov ecx,0x36
mov eax,0xCCCCCCCC
rep stos dword ptr es:[edi]
上面的指令功能就是把edi中地址指向的值賦值成EAX中的值,賦值的次數爲ECX中的值
可以在OD中觀察一下指令執行之後堆棧中的變化
在指令執行之前,EDI的值是0xDDFB40
DF = 0
堆棧中情況是這樣的:
接下來執行一下rep stos這條指令
可以看到從0xDDFB40這個地址開始,堆棧中的值都被賦值成了0xCCCCCCCC
因爲 DF = 0,所以可以看到EDI的地址是往遞增的方向變化的
循環次數ECX = 0x36,所以地址的變化是0x36 * 4 = 0xD8,也就是賦值一直到0xDDFB40 + 0xD8 = 0xDDFC18 爲止
2、movsx
movsx eax,byte ptr ds:[0x128004]
帶符號擴展,並把擴展之後的值給eax
如果最高位是1,那麼擴展位就用1填充,如果最高位是0,那麼擴展位就用0填充
比如說
mov BL,0x80
movsx AX,BL
執行完movsx之後AX中的值就是0xFF80,因爲0x80轉換成二進制來看的話就是1000 0000,對於有符號的數來說,最高位爲1就是表示負數,所以由一個字節擴展成兩個字節,結果就是1111 1111 1000 0000,擴展位用1填充,轉換成十六進制就是0xFF80
如果是
mov BL,0x50
movsx AX,BL
那就是0x50 = 0101 0000,最高位爲0,擴展位也是用0填充,一個字節擴展成兩字節就是 0000 0000 0101 0000,執行完movsx之後AX=0x0050
3、cdq
Convert Double to Quad,意思就是把雙字(四字節,一個字 = 兩字節)擴展爲四字(八字節),因爲擴展成了8字節,一個EAX放不到,所以把八字節的高四字節放到了EDX中。
這個指令常用於擴展 被除數 ,在以前指令集規定除數必須是被除數的一半長,目前還在用這個規定。
這個指令一般是在計算除法的時候出現
4、shl
邏輯左移,最低位補0
格式:
SHL DST,常量
或者
SHL DST,CL
左移的位數根據常量的值和CL的值來確定
比如說:
mov eax,0x12
shl eax,2
首先0x12 = 0001 0010
左移2位,結果變成 0100 1000=0x48
左移指令可以用在乘法計算中,左移1位表示乘以2,左移2位表示乘以4,以此類推
所以0x12左移2位就是0x12*4=0x48
5、sar
算術右移,最高位補什麼值由符號位決定,如果最高位是0,那麼補0;如果最高位是1,那麼補1,也就是算術右移最高位保持不變
比如說
mov eax,0x80
sar eax,1
由於0x80最高位是符號位,所以右移的時候最高位補1
1000 0000 -> 1110 0000
如果是
mov eax,0x52
sar eax,2
那麼結果就是 0101 0010 -> 0001 0100
右移也相當於是除法,右移一位除以2,右移2位除以4
6、xor
用來計算兩個數異或的結果,如果是異或兩個相同的寄存器,那就是在執行寄存器置零操作
搜索關注公衆號[逆向小生],不定期更新逆向工程師需要掌握的技能,包括Windows和Android方面的逆向,還有作爲一個逆向工程師的思維模式。