Union of four fields: value, base, index and scaled (see below).
vex
uint8_t[3]
0xC4 or 0xC5 followed by 1 or 2 bytes
length
int
The instruction length (in bytes)
disp_len
int
The displacement size (in bytes)
imm_len
int
The imm size
vex_cnt
int8_t
Count how many VEX prefixes are available
prefix_cnt
int8_t
Count how many prefixes are available
set_prefix
uint16_t
A field against which is possible to check if a determined prefix (belonging to prefixes enum) is present.
set_field
uint16_t
A field against which is possible to check if a determined feature (belonging to instruction_feature enum) is available (e.g. FPU, SIB, DISP,…)
jcc_type
uint8_t
The type of jump: Jcc or JMP with 1 or 2-bytes (refer to jmp_type enum)
REX union
Field Name
Type
Description
rex.value
uint8_t
The rex prefix if present (x64 only)
rex.bits.rex_b
uint8_t
rex_b field
rex.bits.rex_x
uint8_t
rex_x field
rex.bits.rex_r
uint8_t
rex_r field
rex.bits.rex_w
uint8_t
rex_w field
For more information on REX prefix, refer to section 2.2.1 REX Prefixes of the Intel Developer Manual Vol.2 [2].
ModRm union
Field Name
Type
Description
modrm.value
uint8_t
The ModRm value
modrm.bits.rm
uint8_t
The rm part of ModRm
modrm.bits.reg
uint8_t
The reg part of ModRm
modrm.bits.mod
uint8_t
The mod part of ModRm. When mod=11b source and destination are registers, otherwise one of the operands involves memory access (displacement field)
More information on ModRm field can be found at the section 2.1.3 ModR/M and SIB Bytes of the Intel Developer Manual Vol.2 [2].
SIB union
Field Name
Type
Description
sib.value
uint8_t
If present, is the Scaled Index Base
sib.bits.base
uint8_t
base field
sib.bits.index
uint8_t
index field
sib.bits.scaled
uint8_t
scaled field
For more information refer to section 2.1.5 Addressing-Mode Encoding of ModR/M and SIB Bytes of the Intel Developer Manual Vol.2 [2].
vex_info struct
Field Name
Type
Description
type
uint8_t
0xC4 used when 3-byte prefix is present or 0xC5 used when 2-byte prefix is present
vexc5b
struct
_vex.val5
uint8_t
The byte after 0xC5 with its filds described below
_vex.vexc5b.vex_pp
uint8_t
Equivalent to a SIMD prefix: 00: none, 01: 0x66, 02: 0xF3, 03: 0xF2
_vex.vexc5b.vex_l
uint8_t
0 for 128-bit vector or 1 for 256-bit vector
_vex.vexc5b.vex_v
uint8_t
An additional operand for the instruction
_vex.vexc5b.vex_r
uint8_t
_vex.val4
uint16_t
_vex.vexc4b.vex_pp
uint8_t
_vex.vexc4b.vex_l
uint8_t
_vex.vexc4b.vex_v
uint8_t
_vex.vexc4b.vex_r
uint8_t
_vex.vexc4b.vex_m
uint8_t
Values: 00001: implied 0F leading opcode byte, 00010: implied 0F 38 leading opcode bytes, 00011: implied 0F 3A leading opcode bytes. Other values will #UD.
_vex.vexc4b.vex_b
uint8_t
_vex.vexc4b.vex_x
uint8_t
_vex.vexc4b.vex_r
uint8_t
For all the details about VEX prefix look at section 2.3.5 The VEX Prefix of the Intel Developer Manual Vol.2 [2].
Examples
A practical example: sum of two vectors using SIMD instruction
Lets have a pratical example, the sum of two vectors (using inline assembly):
Of course you can gather more information about each instruction.
Here below a sample detailed report created by x64ID processing of two of the instructions of the set above, inst. 1 and inst. 10:
pFunctionInfo is an anonymous struct defined as follows:
Field Name
Type
Description
pVisited
vector *
A pointer to a vector data structure
length
int
The length of the function in bytes
The vector data structure is a dynamic array with three members:
Field Name
Type
Description
vect
uint32_t *
contains the detected addresses
size
int
allocated memory of the array
tos
int
index of the last inserted element
An example can be found in main.c, function in_memory().
Notes
Jump Table are not handled; be careful when you use switch case and compiling with MSVC (GCC/MinGw seems use other techniques).
Handling jmp table require heuristics (eg. as IDA do and other tools) and more info on the target.
Tests
After googling for a better solution, I came back with one of the first things I was thinking: assembly.
Tests have been written using NASM and must be compiled using the “bin” flag:
nasm -f bin <filename.asm>
The tested instructions are the following:
x86: 1-byte OP, 2-byte OP, 3-byte OP and 2-byte OP with VEX prefix
x64: 1-byte OP, 2-byte OP, 3-byte OP; some of which have VEX prefix
Tests have been written by hand using the Intel Developer Manual book [2].
I can’t guarantee a 100% coverage, however all the opcodes have been tested.
[1] By VM protection is meant a code obscator that converts x86/x64 machine code into “virtual opcodes” that are understandable by a VM. Two commercial examples can be VMProtect and CodeVirtualizer
x64ID ~ x64 Instruction Decoder
A x86/x64 machine code decoder. It is useful to get instructions’ length and identify each of its fields.
Here some scenarios where x64ID can be used:
MOV EAX, 0withXOR EAX, EAX)REXunionModRmunionSIBunionvex_infostructSupported architectures and features
Architectures:
✅ x86
✅ x64
Opcodes:
✅ 1-byte OPs
✅ 2-byte OPs
✅ 3-byte OPs, 0x38 and 0x3A
Fields:
✅ prefixes
✅ VEX prefix (0xC4, 0xC5)
✅ ModRm
✅ REX prefix
✅ SIB
✅ Imm
✅ Disp
❌ XOP prefix
Instruction Set:
✅ x86 & x64
✅ SIMD extension
✅ AVX extension
❌ AVX-512 (EVEX prefix)
❌ 3DNow!
Features on development
🎯 XOP support
🎯 AVX-512 (EVEX prefix)
🎯 Machine code to assembly mnemonics
🎯 Others (as ideas will come to mind…)
API
x64ID exposes only one function and some structs to complete its goal:
instrstruct instructionarchenum supported_architecture1forx86and2forx64data_sourcechar*offsetintdata_bufferReturn:
x64id_decodereturns the length of the decoded instruction. Its value can also be accessed frominstr.length.Instruction struct
Here below how you can use the struct. More infos and the other structs can be found in the header file.
prefixesuint8_t[4]rexunionvalue,rex_b,rex_r,rex_x,rex_w(see below).opuint8_tmodrmunionvalue,rm,regandmod(see below).dispuint64_timmuint64_tlabeluint32_t_vexstruct vex_info_ENABLED_VEX_INFOis defined. Described below.instruint8_t[15]_ENABLE_RAW_BYTESis defined.sibunionvalue,base,indexandscaled(see below).vexuint8_t[3]lengthintdisp_lenintimm_lenintvex_cntint8_tprefix_cntint8_tset_prefixuint16_tprefixesenum) is present.set_fielduint16_tinstruction_featureenum) is available (e.g. FPU, SIB, DISP,…)jcc_typeuint8_tREXunionrex.valueuint8_trexprefix if present (x64 only)rex.bits.rex_buint8_trex_bfieldrex.bits.rex_xuint8_trex_xfieldrex.bits.rex_ruint8_trex_rfieldrex.bits.rex_wuint8_trex_wfieldFor more information on REX prefix, refer to section 2.2.1 REX Prefixes of the Intel Developer Manual Vol.2 [2].
ModRmunionmodrm.valueuint8_tmodrm.bits.rmuint8_trmpart of ModRmmodrm.bits.reguint8_tregpart of ModRmmodrm.bits.moduint8_tmodpart of ModRm. When mod=11b source and destination are registers, otherwise one of the operands involves memory access (displacement field)More information on ModRm field can be found at the section 2.1.3 ModR/M and SIB Bytes of the Intel Developer Manual Vol.2 [2].
SIBunionsib.valueuint8_tsib.bits.baseuint8_tbasefieldsib.bits.indexuint8_tindexfieldsib.bits.scaleduint8_tscaledfieldFor more information refer to section 2.1.5 Addressing-Mode Encoding of ModR/M and SIB Bytes of the Intel Developer Manual Vol.2 [2].
vex_infostructtypeuint8_t0xC4used when 3-byte prefix is present or0xC5used when 2-byte prefix is presentvexc5bstruct_vex.val5uint8_t0xC5with its filds described below_vex.vexc5b.vex_ppuint8_t00: none,01: 0x66,02: 0xF3,03: 0xF2_vex.vexc5b.vex_luint8_t_vex.vexc5b.vex_vuint8_t_vex.vexc5b.vex_ruint8_t_vex.val4uint16_t_vex.vexc4b.vex_ppuint8_t_vex.vexc4b.vex_luint8_t_vex.vexc4b.vex_vuint8_t_vex.vexc4b.vex_ruint8_t_vex.vexc4b.vex_muint8_t_vex.vexc4b.vex_buint8_t_vex.vexc4b.vex_xuint8_t_vex.vexc4b.vex_ruint8_tFor all the details about VEX prefix look at section 2.3.5 The VEX Prefix of the Intel Developer Manual Vol.2 [2].
Examples
A practical example: sum of two vectors using SIMD instruction
Lets have a pratical example, the sum of two vectors (using inline assembly):
Compiling through MS Compiler (with
/Otflag), the result will be what follows:We can write a sample code that uses x64ID to read and print the instructions.
This is what gets printed in output by giving to it the “sum of two vectors” code above (each line is an instruction):
Of course you can gather more information about each instruction. Here below a sample detailed report created by x64ID processing of two of the instructions of the set above, inst. 1 and inst. 10:
Another example: architecture x64, VEX prefix with YMM register
vmovsldup ymm1, [rbp*4 + var]As compiled output we’ll get:
C5 FE 12 0C AD 00 10 00 00Output after x64ID parsing:
Enabling / Disabling features
Some features can be toggled by adding / removing comments on these lines:
_ENABLE_RAW_BYTESinstrstruct passed tox64id_decode(instr.instr);_ENABLE_VEX_INFOinstr; see previous example for moreFind length of a function
An extension has been added to compute the length of a specified function:
pFunctionInfois an anonymous struct defined as follows:pVisitedvector *vectordata structurelengthintThe
vectordata structure is a dynamic array with three members:vectuint32_t *sizeinttosintAn example can be found in
main.c, functionin_memory().Tests
After googling for a better solution, I came back with one of the first things I was thinking: assembly.
Tests have been written using NASM and must be compiled using the “bin” flag:
The tested instructions are the following:
1-byte OP,2-byte OP,3-byte OPand2-byte OP with VEX prefix1-byte OP,2-byte OP,3-byte OP; some of which haveVEX prefixTests have been written by hand using the Intel Developer Manual book [2]. I can’t guarantee a 100% coverage, however all the opcodes have been tested.
Useful resources
Notes
[1] By VM protection is meant a code obscator that converts x86/x64 machine code into “virtual opcodes” that are understandable by a VM. Two commercial examples can be VMProtect and CodeVirtualizer
[2] Intel Developer Manual (2nd book)
Crafted with ❤ by DispatchCode. Documentation created along with Alexander Cerutti