1.寄存器
x64系統通用寄存器名稱,第一個字母從“E”改為“R”,數量增加了8個,(R8-R15),增加了8個128位XMM寄存器(XMM寄存器用來優化代碼)
用表格示意:
說明:

2.棧平衡
棧的基本入棧出棧操作和32位一樣,需要注意就是在64位環境下,匯編指令對棧頂的對其值有要求,因此在VS編譯器申請空間的時候,會盡力保證棧頂地址為對其值16.(被16整除) 在逆向中發現棧空間不使用的情況,可能為了實現對齊
3.調用約定
64位應用程序只有1種寄存器快速調用,前4個參數使用寄存器傳遞,超過4個參數就放到棧里,入棧的順序是從右往左,
前四個寄存器是固定的 RCX,RDX,R8,R9.
所有大於8字節的,不是1.2.4.8字節的參數都由引用來傳遞
所有的浮點參數的傳遞都是使用XMM寄存器完成,他們在XMM0,XMM1,XMM2,XMM3中傳遞
例如:如果存在一個函數為 void fun(float,int float,int)
那么參數傳遞順序第一個參數(XMM0),第二個參數(RDX) 第三個參數(XMM2) 第四個參數(R9)
函數的前4個參數雖然使用寄存器來傳遞,但是棧還會為這4個參數保留空間(32字節) 這里稱為預留棧空間
為什么要這么做? 因為我們使用寄存器傳參的缺點是如果我們的函數調用較為復雜,寄存器會存在不夠用的情況(4個用來傳參了)這是就會利用棧空間暫時保存寄存器的數值,當函數調用完畢再由調用者恢復堆棧。
4.64位的數據結構
局部變量
例如函數入口指令為sub rsp,30h.從rsp+0h到rsp+20h為32字節預留棧空間,rsp+20h到rsp+30h為局部變量空間,也等於預留棧空間在低地址,局部變量空間在高地址
局部變量通常都在棧中保存,如果是Release編譯並寄存器夠用,局部變量可能會在寄存器中保存
全局變量
全局變量的地址在編譯器時候就固定了,先定義的在低地址,后定義的在高地址。根據這個特征可以確定定義順序
數組
數組的結構相對來說是較為“整齊”,數組中的數據在內存中的存儲是線性連續的,從低地址到高地址的存儲。
Ps:int型數據在64位系統下還是32位的大小,如果要用64位則可以用long 或者 __int64
訪問數組的時候就是數組首地址+數據類型大小*下標
控制語句
if語句和32位一樣,不多贅述
switch-case效率高於if 。switch分支數小於6時,會直接用if else來實現,大於等於6時候會進行編譯器優化。優化方式就是case的值間隔比較小就會采用case表的方式去調用case內容
當case的內容較多的時候,就需要用二叉樹來講case比較次數進行優化(折中比較,逐漸縮小范圍)
64位下轉移指令機器碼的計算
JMP: 和32位的計算方式相同:
位移量=目的地址-起始地址-跳轉指令的長度
轉移指令機器碼=轉移類別機器碼+位移量 (JMP xxxx E9 xx)
CALL: call的使用方式和32位下略有不同
32位下例如
CALL dword ptr ds:[42413C] 對應的機器碼就是 FF15 3C414200.這里的43413C是絕對地址
64位就是相對地址:

相對地址=14000B388-1400018CB-指令長度=9ABD-6=9AB7
機器碼=FF15+相對地址=FF157B79A0000