OPCode 詳解


OpCode

操作碼(Operation Code, OPCode):描述機器語言指令中,指令要執行某種操作的機器碼

OPCode在不同的場合中通常具有不同的含義,例如PHP虛擬機(Zend VM)、java虛擬機(JVM)以及一些軟件保護虛擬機中的最小操作單元都可以稱之為OPCode。

常用字節

常用單字節OPCode概覽A -- 40~4F

         opcode                                 asm                      using
          
          0x40                                  inc eax                 emit(0x40)
          0x41                                  inc ecx                 emit(0x41)
          0x42                                  inc edx                 emit(0x42)
          0x43                                  inc ebx                 emit(0x43)
          0x44                                  inc esp                 emit(0x44)
          0x45                                  inc ebp                 emit(0x45)
          0x46                                  inc esi                 emit(0x46)
          0x47                                  inc edi                 emit(0x47)
          0x48                                  dec eax                 emit(0x48)
          0x49                                  dec ecx                 emit(0x49)
          0x4a                                  dec ebx                 emit(0x4a)
          0x4b                                  dec ebx                 emit(0x4b)
          0x4c                                  dec esp                 emit(0x4c)
          0x4d                                  dec ebp                 emit(0x4d)
          0x4e                                  dec esi                 emit(0x4e)
          0x4f                                  dec edi                 emit(0x4f)

常用單字節OPCode概覽B -- 50~5F

           opcode                                asm                        using
           0x50                                  push eax                 emit(0x50)
           0x51                                  push  ecx                emit(0x51)
           0x52                                  push  edx                emit(0x52)
           0x53                                  push  ebx                emit(0x53)
           0x54                                  push  esp                emit(0x54)
           0x55                                  push  ebp                emit(0x55)
           0x56                                  push  esi                emit(0x56)
           0x57                                  push  edi                emit(0x57)
           0x58                                  pop eax                  emit(0x58)
           0x59                                  pop  ecx                 emit(0x59)
           0x5a                                  pop  edx                 emit(0x5a)
           0x5b                                  pop  ebx                 emit(0x5b)
           0x5c                                  pop  esp                 emit(0x5c)
           0x5d                                  pop  ebp                 emit(0x5d)
           0x5e                                  pop  esi                 emit(0x5e)
           0x5f                                  pop  edi                 emit(0x5f)

常用單字節OPCode概覽C -- 70~7F

         opcode                            asm                            using
         0x70  0x12                        Jo 0x12          {_emit(0x70)} {_emit(0x12)}
         0x71  ...                         Jno ...                        ... ...
         0x72  ...                         Jb  ...                        ... ...
         0x73  ...                         Jae ...                        ... ...
         0x74  ...                         Je  ...                        ... ...
         0x75  ...                         Jne ...                        ... ...
         0x76  ...                         Jbe ...                        ... ...
         0x77  ...                         Ja  ...                        ... ...
         0x78  ...                         Js  ...                        ... ...
         0x79  ...                         Jns ...                        ... ...
         0x7a  ...                         Jp  ...                        ... ...
         0x7b  ...                         Jnp ...                        ... ...
         0x7c  ...                         Jl  ...                        ... ...
         0x7d  ...                         Jge ...                        ... ...
         0x7e  ...                         Jle ...                        ... ...
         0x7f  ...                         Jg  ...                        ... ...

常用單字節OPCode概覽D -- 90~9F

        Opcode                       asm                   Using
         0x90                    Nop/xchg eax,eax       _emit(0x90)
         0x91                    Xchg eax,ecx       
         0x92                    Xchg eax,edx       
         0x93                    Xchg eax,ebx       
         0x94                    Xchg eax,esp       
         0x95                    Xchg eax,ebp      
         0x96                    Xchg eax,esi       
         0x97                    Xchg eax,edi  

OPCode與指令的對應關系

同類型的指令OPCode不一定相同

B8 01000000    mov eax, 1
8B C3          mov eax, ebx
8B C7          mov eax, edi

OPCode相同的情況下指令也不一定相同

90 nop
90 xchg ax, ax
90 xchg eax, eax    

結論: OPCode與匯編指令並非是單純的對應關系

那么它是如何進行解釋的呢?

首先它分為6個主要數據域,其中只有代碼是必須存在的,指令長度在1-16個字節

所以指令獨此一份,不可能為其他機器碼

x86與x86-64指令集的指令的格式為:

指令前綴 指令碼 ModR/M SIB 偏移 直接數
Instruction Prefixes Opcode Displacement Immediate
可選。 最多4個單字節前綴。 任何順序均可。 單字節、雙字節、三字節 按需。 0-2位:R/M 3-5位:Reg/Opcode 6-7位:Mod 按需。 0-2位:Base 3-5位:Index 6-7位:Scale 0、1、2、4字節長 0、1、2、4字節長

1, 指令前綴 Instruction Prefixes

分為4組,每組用1個字節編碼。每組在指令中至多指定1個前綴值。4組的順序可以任意。

  • 第1組鎖與重復(Lock and repeat)
    • 鎖(LOCK)編碼為:F0H。用於互斥訪問共享內存的操作。
    • 非零時重復(REPNE/REPNZ)編碼為:F2H。用於字符串操作指令。
    • 為零時重復(REP/REPE/REPZ)編碼為:F3H。用於字符串操作指令。
  • 第2組
    • 段覆蓋(Segment override):CS、SS、DS、ES、FS、GS的段覆蓋前綴的編碼分別是2EH、36H、3EH、26H、64H、65H.
    • 分支提示(Branch hints),用於條件分支指令Jcc。提示分支不發生編碼為2EH;提示分支發生編碼為3EH。
  • 第3組操作數長度覆蓋(Operand-size override)編碼為66H。用於在16位與32位操作數切換。
  • 第4組地址長度覆蓋(Address-size override)編碼為67H.用於在16位與32位地址切換。
;切換操作數大小
;切換順序: 從大到小
40             INC EAX
66 40          INC AX

;無效的前綴應用
8AC1          MOV AL, CL
66 BAC1       MOV AL, CL

;重復操作段前綴
F3 66 AD      REP LODSW
F2 AC         REPNE LODSB

;段超越前綴
8B 03          MOV EAX, [DWORD DS:EBX]
658B 03        MOV EAX, [DWORD GS:EBX]

前綴的具體含義可以在Intel手冊中查到,比如2E,從手冊可以看出是鎖定CS段

2, 代碼 code

長度為1、2或3字節,此外ModR/M中還可能有3位。對於雙字節指令碼或三字節指令碼,其中的第1個字節為0FH,用於與指令前綴區分。

3,構造模式 ModR/M

構造模式(Mode): 主要解析邏輯集中在ModeR/M域,通過查找Intel手冊解析該域確定指令的具體格式

分為三個部分

  • 模式 Mode
  • 寄存器 Reg
  • 寄存器 R/M

對照Intel手冊中的表來解析OPCode中的ModR/M域來確定指令的具體格式.

89  D8          mov eax, ebx
D8 = 11011000
Mod  Reg  R/M
11   011  000

許多指令的內存操作數需要使用ModR/M字節作為尋址模式說明符。其中的mod與r/m組合,共有32個值,表示8個寄存器與24種尋址模式。reg/opcode表示寄存器號或者額外的3位指令碼,其具體含義依賴基本指令碼。Mod與R/M的5位表示的第一操作數(源與目的操作數中尋址方式更復雜的那個操作數,指令碼中的“方向位”direction bit(d)給出源或目的操作數哪個是第一操作數)的尋址方式如下:

尋址方式 Mod R/M
[EAX] 00 000
[ECX] 001
[EDX] 002
[EBX] 003
[--][--] 004
disp32 005
[ESI] 006
[EDI] 007
[EAX]+disp8 01 000
[ECX]+disp8 001
[EDX]+disp8 002
[EBX]+disp8 003
[--][--]+disp8 004
[EBP]+disp8 005
[ESI]+disp8 006
[EDI]+disp8 007
[EAX]+disp32 10 000
[ECX]+disp32 001
[EDX]+disp32 002
[EBX]+disp32 003
[--][--]+disp32 004
[EBP]+disp32 005
[ESI]+disp32 006
[EDI]+disp32 007
EAX/AX/AL/MM0/XMM0 11 000
ECX/CX/CL/MM/XMM1 001
EDX/DX/DL/MM2/XMM2 002
EBX/BX/BL/MM3/XMM3 003
ESP/SP/AH/MM4/XMM4 004
EBP/BP/CH/MM5/XMM5 005
ESI/SI/DH/MM6/XMM6 006
EDI/DI/BH/MM7/XMM7 007
1.[--][--]表示隨后的SIB字節指明尋址方式; 2.Mod為11B時,表示寄存器操作數。對於R/M的每個值,根據指令碼與操作數長度屬性確定具體的寄存器號。 3.當指令需要第2操作數時,由Reg/Opcode的3位給出。第2操作數只能是寄存器操作數。寄存器的指定方式,與Mod為11B時指定作為第1操作數的寄存器的方式完全相同。

某些ModR/M字節表示的尋找模式,需要SIB字節來補充尋址方式。scale表示比例系數;index表示變址寄存器號;base表示基址寄存器號。使用scale與index的5位定義比例變址寄存器如下:

4,輔助分析 SIB

分為三個部分:

  • 比例 Scale
  • 索引 IndexOf
  • 基數 Base
比例變址 基數 Index
[EAX] 00 000
[ECX] 001
[EDX] 002
[EBX] 003
004
[EBP] 005
[ESI] 006
[EDI] 007
[EAX*2] 01 000
[ECX*2] 001
[EDX*2] 002
[EBX*2] 003
004
[EBP*2] 005
[ESI*2] 006
[EDI*2] 007
[EAX*4] 10 000
[ECX*4] 001
[EDX*4] 002
[EBX*4] 003
004
[EBP*4] 005
[ESI*4] 006
[EDI*4] 007
[EAX*8] 11 000
[ECX*8] 001
[EDX*8] 002
[EBX*8] 003
004
[EBP*8] 005
[ESI*8] 006
[EDI*8] 007

3位base表示的基址寄存器號,定義如下:

EAX ECX EDX EBX ESP [*] ESI EDI
000 001 002 003 004 005 006 007
[*]有兩種含義:1.如果Mod為00B,則[scaled index] + disp32,即沒有基址寄存器。 2.如果Mod為01B或10B,表示基址寄存器為EBP。

在匯編程序設計中,一般把第1操作數的尋址方式總結為如下8種:

尋址方式 英文術語 舉例
立即(數)尋址 immediate addressing mov EAX, 01F2H
寄存器尋址 register addressing mov EAX, ESI
直接尋址 direct addressing mov EAX, DWORD PTR [1FFA00H]
寄存器間接尋址 register indirect addressing mov EAX, DWORD PTR [EBX]
基址加變址尋址 base-plus-index addressing mov EAX, DWORD PTR [EBX+ESI]
寄存器相對尋址 或基址相對尋址 register relative addressing mov EAX, DWORD PTR [EDI+01F4H]
基址相對加變址尋址 base relative-plus-index addressing mov EAX, DWORD PTR 01F4H[EDI+EBX]
比例變址尋址 scaled-index addressing mov EAX, DWORD PTR 01F4H[EDI*8+EBX]

綜合指令格式中的ModR/M與SIB兩個字節的語義規定,指令的第1操作數的尋址方式可總結為4種物理實現:

  • 立即數:表示在指令的“立即數”部分。包括了直接尋址,即立即數作為內存的地址。
  • 寄存器操作數:Mod為11B,根據R/B部分的值、指令碼、操作數長度屬性,確定具體的寄存器號。
  • 基址相對尋址:即[Reg+disp8或disp32]。包括了寄存器間接尋址。這種情況計算第1操作數地址時使用了1個寄存器。
  • 基址加比例變址的相對尋址:即[BaseReg+IndexReg*scale+disp8或disp32]。這種情況計算第1操作數地址時使用了2個寄存器。

5,位移 Displacement

6,立即數 Immediate

手工在Intel手冊中查找OPCode的匯編代碼:

​ F0: 26: C78491 AA000000 11000000

    F0:    26:     C7      84       91    AA000000  11000000
  鎖定前綴  段超越    OPCode ModeR/M   SIB      偏移       立即數
查找前綴

F0 - Prefixes:鎖定前綴,即 Lock

26 - Prefixes:修改默認段,即段超越前綴,查"Opcode Map"如圖,段超越前綴為 ES

查找Code

C7 - Code:查"Opcode Map"如圖,可知:Grp 11 MOV Ev,Iz

查找ModeR/M

84 - ModR/M:轉為二進制 10 000 100
模式(Mod)段 :2位 10
寄存器(Reg)段 :3位 000
寄存器(R/M)段 :3位 100
查"ModR/M"表如圖,得到 [..][..]+disp32

查找SIB

91 - SIB:轉為二進制 10 010 001
比例(Scale)段 :2位 10
索引(Index)段 :3位 010
基數(Base)段 :3位 001
查"SIB"表如圖,可知 [EDX*4]+ECX

AA000000 - Displacement:此為小端模式,即為 0xAA
11000000 - Immediate:小端模式,即為 0x11
綜上,得到:
LOCK MOV ES:[EDX4+ECX+0xAA],0x11
即為:
LOCK MOV DWORD PTR ES:[EDX
4+ECX+0x0AA],0x11

3、內聯匯編

 ;內聯匯編可以有兩種形式,一種是行內聯匯編,一種是塊內聯匯編,二者可交叉使用;
 ;行內聯匯編:
 __asm mov eax,a
 __asm add  eax,b
 __asm mov c,eax
 ; 塊內聯匯編:
 __asm{
          mov eax,a
          add  eax,b
          mov c,eax
 }

4、裸函數

// ;定義:沒有任何可執行代碼的空函數,在內存中僅僅是一條地址信息.
// ; 使用關鍵字“__declspec(naked)”定義;
// ; 例:
void __declspec(naked) TestFun( ){
	__asm  ret     
}

總結:

ModR/M信息與確認是否有SIB字節

當Mod != 11b並且R/M的值為100b的時候,表示指令后續有SIB字節,並且該內存操作對象由SIB編碼。

MODR/M里有三種情況會有SIB字節

參考鏈接

  1. https://blog.csdn.net/brunomarss/article/details/50589556
  2. https://blog.csdn.net/sqzxwq/article/details/47786345


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM