為了理解反彙編引擎而寫的X86/X64反彙編引擎

2021-02-26 看雪學院

本文為看雪論壇精華文章

看雪論壇作者ID:不化的雪 

自己學習逆向一段時間了,發現很不得法。就想自己寫個東西來鞏固一下。翻了論壇,發現很多人都寫了自己的反彙編引擎。自己翻看了獲益良多。但是發現沒有人詳細的寫過X64指令的解析過程。所以自己就打算寫一個X64的反彙編引擎。後來研究過後發現,其實X86和X64的解析差不多的,就把X86和X64一起合起來寫了。為了寫一個反彙編引擎發現自己也是夠拼了。自己翻譯了Intel手冊的幾個章節。後來發現intel手冊的一個很大缺點,就是X64的說明很少。例如X64下的ModR/M、SIB解析表根本沒有。我就去翻看了AMD的文檔,發現了寶貝。AMD不愧是X64的發明人,手冊把X64的各種資料都包含了進去。自己很是興奮,就把介紹指令概述的章節給翻譯了。能夠把X86/X64講明白的,我就服AMD的文檔。他用一張圖把怎麼解析指令給概括了。就是下圖:原本我在看完Intel文檔之後各種思路被這個圖串聯起來了。這裡不能不說一聲AMD YES!還有就是要感謝大神@ mik,是大神的文檔幫我省了很多時間。我寫代碼的過程中無意中發現了大神的文檔。是從X度文庫下來下的,花了我一個月的會員啊,為了一篇文檔。不過大神的網站上不了了。非常遺憾。附上大神在看雪的主頁@mik。我在寫的過程之中發現X86/X64指令的解析過程很麻煩,有些前面部分的解析和後面的字節有關,後面的字節的解析也可能和前面的字節有關。指令各部分長度的不一致。寫得我心煩。接下來我會先分析Intel/AMD手冊說明解析一條指令跟什麼有關係。讓然後再逐個分析解析指令的各個部分的詳細過程。手冊裡對解析指令最重要的就是 OPCODE TABLES。 一個字節是一條指令裡的什麼部分都能從 OPCODE TABLES裡面查出來。

(1)Opcode:例如PUSH(注意縮寫還有就是簡寫)一對多的放在類型說明裡面

(2)Addressing Method + Operand Type:例如 Gv, Ev  一對多的單獨作為一個類型

(3)Register Codes:例如 rBX/r11   一對多的單獨作為一個類型

(4)Superscripts:例如 1A、i64   視情況而定,也是比較少。不適合做單獨的類型

(5)Opcode Extensions Group Number: 例如 Grp 2  (intel的前面可能會有對該組的描述性文字如 Immediate)

(6)Prefix:例如Operand Size (Prefix)

(7)REX Prefix:例如REX.X  類型說明

(8 ) 描述性文字:例如word、double-word or quad-word register with rAX

(9)距離:例如near  類型說明,或者其他

(10)說明位於其他表:例如3-byte escape,VEX+2byte

(11)空白:直接類型說明,為0,與通用的一樣,不過後面的opcode沒有name

(12)異常代碼:例如UD0,   太少不放進去結構體了

那麼應該怎麼使用 OPCODE TABLES建議大家去看Intel文檔的Volume 2 (2A, 2B, 2C & 2D):Instruction Set Reference, A-Z中的Appendix A Opcode Map面的。A.1 USING OPCODE TABLES ,我已經做了翻譯(見附件)。我概括如下:

1、看位於哪個OPCODE表

2、取出指令,尋址類型還有操作數類型

3、注意符合寄存器表示方式的解析與操作數類型相關

4、寫死在opcode裡面的寄存器需要表示,這個是單獨的。跟第5點不是存在一樣的表示

5、根據尋址類型還有操作數類型確定後面是否有 ModR/M字節、SIB字節、偏移量字節(1、2、4、8位元組)、立即數字節(1、2、4、8位元組)。

6、依次解碼opcode還有操作數1-3

我的代碼是首先構造一個和OPCODE表const OPCODE_STRUCT Primary_opcodemap[0x10][0x10] ,這個表是由結構體數組組成的,其實就是AMD文檔裡的 OPCODE TABLES的基本結構:
typedef struct OPCODE_STRUCT{    const char *opcode;    int  AddressingMethod1st;    int  OperandType1st;    int  AddressingMethod2nd;    int  OperandType2nd;    int  AddressingMethod3rd;    int  OperandType3rd;    int  SelfType;     }OPCODE_STRUCT, *POPCODE_STRUCT;

因為 OPCODE TABLES裡包含各種各種類型的元素,有些OPCODE有多種解析方式。所以在解析之前需要做處理。
           decode_struct.AddressingMethod[0] = popcodemap[(int)HighNibble(*POpcode)][(int)LowNibble(*POpcode)].AddressingMethod1st;    decode_struct.OperandType[0] = popcodemap[(int)HighNibble(*POpcode)][(int)LowNibble(*POpcode)].OperandType1st;    decode_struct.AddressingMethod[1] = popcodemap[(int)HighNibble(*POpcode)][(int)LowNibble(*POpcode)].AddressingMethod2nd;    decode_struct.OperandType[1] = popcodemap[(int)HighNibble(*POpcode)][(int)LowNibble(*POpcode)].OperandType2nd;    decode_struct.AddressingMethod[2] = popcodemap[(int)HighNibble(*POpcode)][(int)LowNibble(*POpcode)].AddressingMethod3rd;    decode_struct.OperandType[2] = popcodemap[(int)HighNibble(*POpcode)][(int)LowNibble(*POpcode)].OperandType3rd;    switch (popcodemap[(int)HighNibble(*POpcode)][(int)LowNibble(*POpcode)].SelfType)    {    case 0:        Result = Result + popcodemap[(int)HighNibble(*POpcode)][(int)LowNibble(*POpcode)].opcode;                        break;    case PUPO:        if (REX_B_Flag)        {            decode_struct.AddressingMethod[0] = decode_struct.AddressingMethod[1];            decode_struct.AddressingMethod[1] = UNCON;        }        else            decode_struct.AddressingMethod[1] = UNCON;        Result = Result + Result + popcodemap[(int)HighNibble(*POpcode)][(int)LowNibble(*POpcode)].opcode;        break;

先根據 SelfType 還有具體的情況確認opcode,然後再確定尋址方式還有尋址類型(需要做統一的處理)。
for (int icount = 0; icount <3;icount++){    switch (decode_struct.AddressingMethod[icount])    {    case C:    case D:    case G:    case P:    case S:    case V:    case E:    case M:    case N:    case Q:    case R:    case U:    case W:        ModRM_Flag = true;        if (0x4== RM(*(POpcode + 1)) && 0x3 != MOD(*(POpcode + 1)))            SIB_Flag = true;        if (0x0 == MOD(*(POpcode + 1)) && 0x5 == RM(*(POpcode + 1)))            idispcount = 4;        if (0x1 == MOD(*(POpcode + 1)))            idispcount = 1;        if (0x2 == MOD(*(POpcode + 1)))            idispcount = 4;        if (true == SIB_Flag && 0x5 == BASE(*(POpcode + 2)) && 0x0 == MOD(*(POpcode + 1)))            idispcount = 4;        if (true == SIB_Flag && 0x5 == BASE(*(POpcode + 2)) && 0x1 == MOD(*(POpcode + 1)))            idispcount = 1;        if (true == SIB_Flag && 0x5 == BASE(*(POpcode + 2)) && 0x2 == MOD(*(POpcode + 1)))            idispcount = 4;        break;    default:        break;    }}

確定一條指令包含什麼部分:先確定有沒有ModRM字節-->然後確定有沒有SIB字節                    I-->確定有沒有Disp字節(有幾字節?)3的尋址方式還有類型確認後面的有什麼字節再確定有沒有 immediate 字節(有幾字節)這個可以到最後解碼immediate字節的時候再做。
const char *GPRs32[0x3][0x8] ={  {"AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" },  {"AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI" },  {"EAX","ECX","EDX","EBX","ESP","EBP","ESI","EDI"} }; const char *GPRs64[0x4][0x10] ={  {"AL", "CL", "DL", "BL", "SPL", "BPL", "SIL", "DIL", "R8B", "R9B", "R10B", "R11B", "R12B", "R13B", "R14B", "R15B"},  {"AX", "CX", "DX", "BX", "SP" , "BP" , "SI" , "DI" , "R8W", "R9W", "R10W", "R11W", "R12W", "R13W", "R14W", "R15W"},  {"EAX","ECX","EDX","EBX","ESP", "EBP", "ESI", "EDI", "R8D", "R9D", "R10D", "R11D", "R12D", "R13D", "R14D", "R15D"},  {"RAX","RCX","RDX","RBX","RSP", "RBP", "RSI", "RDI", "R8" , "R9" , "R10" , "R11" , "R12",  "R13" , "R14" , "R15" } };        switch (decode_struct.AddressingMethod[icount])        {        case rAX:        case rCX:        case rDX:        case rBX:        case rSP:        case rBP:        case rSI:        case rDI:        case r8:        case r9:        case r10:        case r11:        case r12:        case r13:        case r14:        case r15:            if (UNCON != decode_struct.OperandType[icount])                Result = Result + GPRs64[decode_struct.OperandType[icount]][decode_struct.AddressingMethod[icount]];            else            {                if (MODE32 == Mode)                {                    if (OPSizeFlag)                        Result = Result + GPRs32[_16BIT][decode_struct.AddressingMethod[icount]];                    else                        Result = Result + GPRs32[_32BIT][decode_struct.AddressingMethod[icount]];                }                else                {                    if (REX_W_Flag || REX_B_Flag)                        Result = Result + GPRs64[_64BIT][decode_struct.AddressingMethod[icount]];                    else                    {                        if (OPSizeFlag)                            Result = Result + GPRs64[_16BIT][decode_struct.AddressingMethod[icount]];                        else                            Result = Result + GPRs64[_32BIT][decode_struct.AddressingMethod[icount]];                    }                }            }            break;

1、根據當前的模式還有就是有沒有操作數大小覆蓋前綴來確定(沒有大小描述的情況)

2、直接解碼返回(有大小描述的情況)


const char *ModRM_REG0[0xA][0x8] ={  {"AL",  "CL",  "DL",  "BL",  "AH",  "CH",  "DH",  "BH" },  {"AX",  "CX",  "DX",  "BX",  "SP",  "BP",  "SI",  "DI" },  {"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI"},  {"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI"},  {"MMX0","MMX1","MMX2","MMX3","MMX4","MMX5","MMX6","MMX7"},  {"XMM0","XMM1","XMM2","XMM3","XMM4","XMM5","XMM6","XMM7"},  {"YMM0","YMM1","YMM2","YMM3","YMM4","YMM5","YMM6","YMM7"},  {"ES",  "CS",  "SS",  "DS",  "FS",  "GS",  "invalid","invalid"},  {"CR0", "CR1", "CR2", "CR3", "CR4", "CR5", "CR6", "CR7" },  {"DR0", "DR1", "DR2", "DR3", "DR4", "DR5", "DR6", "DR7" } };const char *ModRM_REG10[0xA][0x8] ={  {"AL",  "CL",  "DL",  "BL",  "SPL", "BPL", "SIL", "DIL"},  {"AX",  "CX",  "DX",  "BX",  "SP",  "BP",  "SI",  "DI" },  {"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI"},  {"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI"},  {"MMX0","MMX1","MMX2","MMX3","MMX4","MMX5","MMX6","MMX7"},  {"XMM0","XMM1","XMM2","XMM3","XMM4","XMM5","XMM6","XMM7"},  {"YMM0","YMM1","YMM2","YMM3","YMM4","YMM5","YMM6","YMM7"},  {"ES",  "CS",  "SS",  "DS",  "FS",  "GS","invalid","invalid"},  {"CR0", "CR1", "CR2", "CR3", "CR4", "CR5", "CR6", "CR7"},  {"DR0", "DR1", "DR2", "DR3", "DR4", "DR5", "DR6", "DR7"} };const char *ModRM_REG11[0xA][0x8] ={  {"R8B", "R9B", "R10B", "R11B", "R12B", "R13B", "R14B", "R15B"},  {"R8W", "R9W", "R10W", "R11W", "R12W", "R13W", "R14W", "R15W"},  {"R8D", "R9D", "R10D", "R11D", "R12D", "R13D", "R14D", "R15D"},  {"R8",  "R9",  "R10",  "R11",  "R12",  "R13",  "R14",  "R15"},  {"MMX0","MMX1","MMX2", "MMX3", "MMX4", "MMX5", "MMX6", "MMX7"},  {"XMM8","XMM9","XMM10","XMM11","XMM12","XMM13","XMM14","XMM15"},  {"YMM8","YMM9","YMM10","YMM11","YMM12","YMM13","YMM14","YMM15"},  {"ES",  "CS",  "SS",   "DS",   "FS",   "GS",   "invalid","invalid"},      {"CR8", "CR9", "CR10", "CR11", "CR12", "CR13", "CR14", "CR15" },  {"DR8", "DR9", "DR10", "DR11", "DR12", "DR13", "DR14", "DR15" } };static void DecodeREG(BYTE* PModRM, CString &Result, bool REX_Flag, bool REX_W_Flag, bool REX_R_Flag, int Mode, bool OPSizeFlag, int DecodeType){    if (MODE32 == Mode)    {        if (GPRS != DecodeType)            Result = Result + " " + ModRM_REG0[DecodeType][REG(*PModRM)] + " ";        else        {            if (OPSizeFlag)                Result = Result + " " + ModRM_REG0[REG16][REG(*PModRM)] + " ";            else                Result = Result + " " + ModRM_REG0[REG32][REG(*PModRM)] + " ";        }    }    else    {        if (REX_Flag)        {            if (REX_R_Flag)            {                if (GPRS != DecodeType)                    Result = Result + " " + ModRM_REG11[DecodeType][REG(*PModRM)] + " ";                else                {                    if (REX_W_Flag)                        Result = Result + " " + ModRM_REG11[REG64][REG(*PModRM)] + " ";                    else                    {                        if (OPSizeFlag)                            Result = Result + " " + ModRM_REG11[REG16][REG(*PModRM)] + " ";                        else                            Result = Result + " " + ModRM_REG11[REG32][REG(*PModRM)] + " ";                    }                }            }            else            {                if (GPRS != DecodeType)                    Result = Result + " " + ModRM_REG10[DecodeType][REG(*PModRM)] + " ";                else                {                    if (REX_W_Flag)                        Result = Result + " " + ModRM_REG10[REG64][REG(*PModRM)] + " ";                    else                    {                        if (OPSizeFlag)                            Result = Result + " " + ModRM_REG10[REG16][REG(*PModRM)] + " ";                        else                            Result = Result + " " + ModRM_REG10[REG32][REG(*PModRM)] + " ";                    }                }            }        }        else        {            if (GPRS != DecodeType)                Result = Result + " " + ModRM_REG0[DecodeType][REG(*PModRM)] + " ";            else            {                if (REX_W_Flag)                    Result = Result + " " + ModRM_REG0[REG64][REG(*PModRM)] + " ";                else                {                    if (OPSizeFlag)                        Result = Result + " " + ModRM_REG0[REG16][REG(*PModRM)] + " ";                    else                        Result = Result + " " + ModRM_REG0[REG32][REG(*PModRM)] + " ";                }            }        }     }}

具體的選項包括reg8、reg16、reg32、reg64、mmx、xmm、ymm,其中通用寄存器需要確定大小(reg8~reg64)使用一個函數解碼,需要用到一個指向二維數組的指針(因為數組大小都是一樣的)。  
 const char *ModRM_RM32[0x3][0x8] ={  {"EAX","ECX","EDX","EBX","","",   "ESI","EDI"},  {"EAX","ECX","EDX","EBX","","EBP","ESI","EDI"},  {"EAX","ECX","EDX","EBX","","EBP","ESI","EDI"}};const char *ModRM_RM64_0[0x3][0x8] ={  {"RAX","RCX","RDX","RBX","","",   "RSI","RDI"},  {"RAX","RCX","RDX","RBX","","RBP","RSI","RDI"},  {"RAX","RCX","RDX","RBX","","RBP","RSI","RDI"}};const char *ModRM_RM64_1[0x3][0x8] ={  {"R8","R9","R10","R11","","",   "R14","R15"},  {"R8","R9","R10","R11","","R13","R14","R15"},  {"R8","R9","R10","R11","","R13","R14","R15"}};const char *ModRM_RM32_11[0x5][0x8] ={  {"AL",  "CL",  "DL",  "BL",  "AH",  "CH",  "DH",  "BH"  },  {"AX",  "CX",  "DX",  "BX",  "SP",  "BP",  "SI",  "DI"  },  {"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI" },  {"MMX0","MMX1","MMX2","MMX3","MMX4","MMX5","MMX6","MMX7"},  {"XMM0","XMM1","XMM2","XMM3","XMM4","XMM5","XMM6","XMM7"} };const char *ModRM_RM64_110[0x7][0x8] ={  {"AL",  "CL",  "DL",  "BL",  "SPL", "BPL", "SIL", "DIL" },  {"AX",  "CX",  "DX",  "BX",  "SP",  "BP",  "SI",  "DI"  },  {"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI" },  {"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI" },  {"MMX0","MMX1","MMX2","MMX3","MMX4","MMX5","MMX6","MMX7"},  {"XMM0","XMM1","XMM2","XMM3","XMM4","XMM5","XMM6","XMM7"},  {"YMM0","YMM1","YMM2","YMM3","YMM4","YMM5","YMM6","YMM7"},};const char *ModRM_RM64_111[0x7][0x8] ={  {"R8B", "R9B", "R10B",  "R11B",  "R12B",  "R13B",  "R14B",  "R15B" },  {"R8W", "R9W", "R10W",  "R11W",  "R12W",  "R13W",  "R14W",  "R15W" },  {"R8D", "R9D", "R10D",  "R11D",  "R12D",  "R13D",  "R14D",  "R15D" },  {"R8" , "R9" , "R10" ,  "R11" ,  "R12",   "R13" ,  "R14" ,  "R15"  },  {"MMX0","MMX1","MMX2",  "MMX3",  "MMX4",  "MMX5",  "MMX6",  "MMX7" },  {"XMM8","XMM9","XMM10", "XMM11", "XMM12", "XMM13", "XMM14", "XMM15"},  {"YMM8","YMM9","YMM10", "YMM11", "YMM12", "YMM13", "YMM14", "YMM15"},};

Mod為00b~10b使用三個二維數[Mod][R/M](32位,64位的當REX.B = 0與REX.B = 1,三種情況,其中01,10需要解析出disp字節),Mod為11b單獨使用[具體的選項][R/M]為三個二維數組32位,64位的當REX.B = 0與REX.B = 1,三種情況),根據具體的情況傳入[具體選項]與[R/M],返回字符串。

先通過位數(模式)、REX.B和Mod來確定二維數組

1、Mod ≠ 11b,直接通過[Mod][R/M]就可以返回,通過Mod與R/M確定有沒有SIB需要特殊處理,有Disp就解析出來。

2、Mod = 11b,通用寄存器需要確定大小(reg8~reg64)作為[具體的選項],mmx xmm ymm不需要。不需要解析SIB和Disp。

const char *ScaledIndex32[0x4][0x8]{    {"EAX",  "ECX",  "EDX",  "EBX",  "","EBP",  "ESI",  "EDI"},    {"EAX*2","ECX*2","EDX*2","EBX*2","","EBP*2","ESI*2","EDI*2"},    {"EAX*4","ECX*4","EDX*4","EBX*4","","EBP*4","ESI*4","EDI*4"},    {"EAX*8","ECX*8","EDX*8","EBX*8","","EBP*8","ESI*8","EDI*8"}};const char *ScaledIndex64_0[0x4][0x8]{    {"RAX",  "RCX",  "RDX",  "RBX",  "","RBP",  "RSI",  "RDI"},    {"RAX*2","RCX*2","RDX*2","RBX*2","","RBP*2","RSI*2","RDI*2"},    {"RAX*4","RCX*4","RDX*4","RBX*4","","RBP*4","RSI*4","RDI*4"},    {"RAX*8","RCX*8","RDX*8","RBX*8","","RBP*8","RSI*8","RDI*8"}};const char *ScaledIndex64_1[0x4][0x8]{    {"R8",  "R9",  "R10",  "R11",  "R12",  "R13",  "RR14",  "R15"},    {"R8*2","R9*2","R10*2","R11*2","R12*2","R13*2","RR14*2","R15*2"},    {"R8*4","R9*4","R10*4","R11*4","R12*4","R13*4","RR14*4","R15*4"},    {"R8*8","R9*8","R10*8","R11*8","R12*8","R13*8","RR14*8","R15*8"}};

SIB 字節由 ModRM.r/m = 100且Mod ≠ 11 引導出來。三個[scale][index]二維數組(32位,64位的當REX.X = 0與REX.X = 1,三種情況)SIB解析數組[scale][index]確定索引和比例 64位的base域是有兩種情況的即REX.B = 0 或 REX.B = 1.當base域為101b時與Mod域有關聯   函數參數(指向ModR/M的指針,用來返回結果的CString對象的引用,REX_W_Flag,REX_X_Flag,REX_B_Flag,ModRM_Flag,SIB_Flag,idispcount(用來確定disp),Mode,OPSizeFlag,ADSizeFlag(用來確定操作數大小)。根據前面判斷的位置和大小取出(先轉換指針類型,然後解指針)。詳細的解碼只貼一個代碼片段,就是通過操作數尋址類型和操作數大小判斷出操作數位於上面指出的哪個位置然後解碼的:
case E:    if (0x3 != MOD(*(POpcode + 1)) && "" != StrPrefix1)        Result = Result + " " + StrPrefix1 + ":";    switch (decode_struct.OperandType[icount])    {    case v:        if (0x3 != MOD(*(POpcode + 1)))            DecodeModRM((POpcode + 1), Result, REX_W_Flag, REX_X_Flag, REX_B_Flag, ModRM_Flag, SIB_Flag, idispcount, Mode, OPSizeFlag, ADSizeFlag, 0);        else            DecodeModRM((POpcode + 1), Result, REX_W_Flag, REX_X_Flag, REX_B_Flag, ModRM_Flag, SIB_Flag, idispcount, Mode, OPSizeFlag, ADSizeFlag, GPRS);        break;    case b:        if (0x3 != MOD(*(POpcode + 1)))            DecodeModRM((POpcode + 1), Result, REX_W_Flag, REX_X_Flag, REX_B_Flag, ModRM_Flag, SIB_Flag, idispcount, Mode, OPSizeFlag, ADSizeFlag, _BYTEP);        else            DecodeModRM((POpcode + 1), Result, REX_W_Flag, REX_X_Flag, REX_B_Flag, ModRM_Flag, SIB_Flag, idispcount, Mode, OPSizeFlag, ADSizeFlag, REG8);        break;    default:        break;    }    break;

我只是做了Primary Opcode Map一個表,所以會出現問題。不過這個主要是用來理解指令的,所以就這樣子了。不想去打磨了,生命無價,不要浪費時間在造輪子上。理解原理就夠了。(intel的文檔我就不上傳了,自己去官網下),還有就是原始碼我是使用VS2017構建的。那個壓縮文件就是原始碼,還有測試代碼。

看雪ID:不化的雪

https://bbs.pediy.com/user-620577.htm 

*本文由看雪論壇 不化的雪 原創,轉載請註明來自看雪社區。

好書推薦

相關焦點

  • [系統安全] 三.IDA Pro反彙編工具初識及逆向解密實戰
    前文普及了逆向分析基礎知識,告訴大家如何學好逆向分析;這篇文章將詳細講解IDA Pro反彙編工具的基礎用法,並簡單講解一個EXE逆向工程解密實戰方法。希望對入門的同學有幫助,作者的目的是與安全人共同進步,加油~IDA和OD是逆向分析和系統安全領域的「倚天屠龍」,掌握它們的用法至關重要,甚至決定你的深度。
  • Windows10下搭建彙編語言開發環境(利用DOSBOX和MASM32)
    由於彙編語言的特殊性,不少初學者會擔心自己直接對寄存器進行操作會不會導致系統崩潰或者系統硬體損壞,再加上現如今高級程序設計語言大行其道,真正需要寫彙編語言的情境已經不那麼多了,所以不少初學彙編語言的同學都還停留在紙上談兵的狀態。
  • Android逆向實戰之smali彙編
    本篇文章基於解包之後的內容介紹smali彙編。彙編語言說到彙編語言,給人的感覺是很高端,很深奧,甚至於很神秘。其實這東西就是另一種形式的語言,一種非常底層的低級語言,大多數的編譯型語言在編譯過程中都要經歷彙編的過程。
  • 彙編:定位kernel32的基地址
    x86和x64的彙編內容。圖 6:位於偏移 0x08 處的 Kernel32.dll 的基地址64 位版本現在,在 64 位系統上嘗試同樣的事情。我將嘗試 32 位代碼,看看它是否有效。馬上,問題來了:
  • Win10(64位)安裝彙編環境(MASM)
    1:需要的文件需要的安裝包:這些百度都能下載找到1)、DOSBox 連結:2) 、MASM5.0 連結:3)、DEBUG 連結:下面給出我們打包的環境 直接可用: (彙編我並不需要關注安裝這些,真的不需要)彙編環境: https://files-cdn.cnblogs.com/files/dgwblog/DOSBox.rar彙編文檔: https://files-cdn.cnblogs.com/files/dgwblog/%E6%B1%87%E7%BC%96%E6%89%8B%E5%86%8C%E4%B8%AD%E6%96%87.rar  2:
  • 收藏:飛碟的反重力引擎技術、飛船材料,及外星人的身體結構介紹!
    夢幻般的80號機庫反重力超級流體引擎我會從最基礎,最重要的技術,反重力流體引擎技術開始。它是可以讓智慧生物穿越數千光年的距離,來到地球的技術。反重力引擎的基本原理圖,下面我會給大家慢慢講到反重力引擎模型首先,絕大多數飛碟型的飛行器都使用著非常相似的引擎-超級流體反重力引擎。在每個蝶形飛行器的內部是如圖所示的,像手鐲一樣的中空圓形金屬管道。這些金屬管道被金屬線圈以螺旋形式纏繞著。
  • 完全理解協程機制(4)—— SplitStack動態擴棧
    int foo(int x) {  return ++x;}int bar(int x) {  return foo(x);}O0編譯後彙編代碼如下:foo:  在x86_64下分別用%r10,%r11傳遞。例如這裡如果在新棧中運行bar函數需要8位元組,bar額外需要棧傳遞的參數0個。當前函數運行需要多少棧空間,編譯器基本上是確定的,所以這裡%r10,%r11都是賦值的立即數。可以看到__morestack返回後,立即執行ret指令。豈不是沒法往後執行?
  • 彙編語言(1)
    1、每一種CPU都有自己的彙編指令集。2、在存儲器中指令和數據沒有任何區別,都是二進位信息。
  • ARM彙編基礎教程——ARM指令集
    為了在Thumb狀態下支持條件執行,「it」指令被引入。然而,可能是為了簡化指令集,這個指令在後來的版本中被刪除了。我認為這種設計反而增加了兼容的複雜度。不過,當然我認為沒必要知道所有ARM版本的ARM/Thumb指令集變體,我建議你也不必在這上面浪費太多時間。你只需要知道目標設備的版本和該版本對Thumb指令有哪些特殊支持,然後調整你的代碼就好了。
  • 兩個案例,從根上理解JVM字節碼執行
    本文來源:http://r6d.cn/s6ee前言最近在看《Java 虛擬機規範》和《深入理解JVM虛擬機》,對於字節碼的執行有了進一步的了解。字節碼就像是彙編語言,是 JVM 的指令集。下面我們先對 JVM 執行引擎做一下簡單介紹,然後根據實例分析 JVM 字節碼的執行過程。
  • 虛幻引擎學習之路:相機圖像後處理
    在此,特別感謝Unreal中國團隊對於本篇文章中Unreal引擎相關內容的審核,並在UWA團隊學習其引擎的道路上提供的大力支持。1、Anti-AliasingUnreal 4引擎中Anti-Aliasing也是圖像後處理的一部分,可以在「Project Settings」->「Engine」->」Rendering」中找到其設置。Unreal 4引擎目前支持了三種反走樣算法,如下圖所示: