iced-x86 is a high performance x86 (16/32/64-bit) instruction decoder, disassembler and assembler written in Rust.
It can be used for static analysis of x86/x64 binaries, to rewrite code (eg. remove garbage instructions), to relocate code or as a disassembler.
- ✔️Supports all Intel and AMD instructions
- ✔️100% Rust code
- ✔️The formatter supports masm, nasm, gas (AT&T), Intel (XED) and there are many options to customize the output
- ✔️The decoder is 4x+ faster than other similar libraries and doesn't allocate any memory
- ✔️Small decoded instructions, only 32 bytes
- ✔️The encoder can be used to re-encode decoded instructions at any address
- ✔️API to get instruction info, eg. read/written registers, memory and rflags bits; CPUID feature flag, flow control info, etc
- ✔️All instructions are tested (decode, encode, format, instruction info)
- ✔️Supports
#![no_std]
andWebAssembly
- ✔️Supports
rustc
1.20.0
or later - ✔️Few dependencies (
static_assertions
andlazy_static
) - ✔️License: MIT
Usage
Add this to your Cargo.toml
:
[]
= "1.2.0"
Or to customize which features to use:
[]
= "1.2.0"
= false
# See below for all features
= ["std", "decoder", "masm"]
If you're using Rust 2015 edition you must also add this to your lib.rs
or main.rs
:
extern crate iced_x86;
Crate feature flags
You can enable/disable these in your Cargo.toml
file.
decoder
: (✔️Enabled by default) Enables the decoderencoder
: (✔️Enabled by default) Enables the encoderblock_encoder
: (✔️Enabled by default) Enables theBlockEncoder
. This feature enablesencoder
op_code_info
: (✔️Enabled by default) Enables getting instruction metadata (OpCodeInfo
). This feature enablesencoder
instr_info
: (✔️Enabled by default) Enables the instruction info codegas
: (✔️Enabled by default) Enables the GNU Assembler (AT&T) formatterintel
: (✔️Enabled by default) Enables the Intel (XED) formattermasm
: (✔️Enabled by default) Enables the masm formatternasm
: (✔️Enabled by default) Enables the nasm formatterdb
: Enables creatingdb
,dw
,dd
,dq
instructions. It's not enabled by default because it's possible to store up to 16 bytes in the instruction and then use another method to read an enum value.std
: (✔️Enabled by default) Enables thestd
crate.std
orno_std
must be defined, but not both.no_std
: Enables#![no_std]
.std
orno_std
must be defined, but not both. This feature uses thealloc
crate (rustc
1.36.0+
) and thehashbrown
crate.exhaustive_enums
: Enables exhaustive enums, i.e., no enum has the#[non_exhaustive]
attributeno_vex
: Disables allVEX
instructions. See below for more info.no_evex
: Disables allEVEX
instructions. See below for more info.no_xop
: Disables allXOP
instructions. See below for more info.no_d3now
: Disables all3DNow!
instructions. See below for more info.
If you use no_vex
, no_evex
, no_xop
or no_d3now
, you should run the generator again (before building iced) to generate even smaller output.
.NET Core is required. Help:
No VEX, EVEX, XOP, 3DNow!:
How-tos
- Disassemble (decode and format instructions)
- Create and encode instructions
- Disassemble with a symbol resolver
- Disassemble with colorized text
- Move code in memory (eg. hook a function)
- Get instruction info, eg. read/written regs/mem, control flow info, etc
- Get the virtual address of a memory operand
Disassemble (decode and format instructions)
This example uses a Decoder
and one of the Formatter
s to decode and format the code,
eg. GasFormatter
, IntelFormatter
, MasmFormatter
, NasmFormatter
.
use ;
/*
This method produces the following output:
00007FFAC46ACDA4 48895C2410 mov [rsp+10h],rbx
00007FFAC46ACDA9 4889742418 mov [rsp+18h],rsi
00007FFAC46ACDAE 55 push rbp
00007FFAC46ACDAF 57 push rdi
00007FFAC46ACDB0 4156 push r14
00007FFAC46ACDB2 488DAC2400FFFFFF lea rbp,[rsp-100h]
00007FFAC46ACDBA 4881EC00020000 sub rsp,200h
00007FFAC46ACDC1 488B0518570A00 mov rax,[rel 7FFA`C475`24E0h]
00007FFAC46ACDC8 4833C4 xor rax,rsp
00007FFAC46ACDCB 488985F0000000 mov [rbp+0F0h],rax
00007FFAC46ACDD2 4C8B052F240A00 mov r8,[rel 7FFA`C474`F208h]
00007FFAC46ACDD9 488D05787C0400 lea rax,[rel 7FFA`C46F`4A58h]
00007FFAC46ACDE0 33FF xor edi,edi
*/
pub
const HEXBYTES_COLUMN_BYTE_LENGTH: usize = 10;
const EXAMPLE_CODE_BITNESS: u32 = 64;
const EXAMPLE_CODE_RIP: u64 = 0x0000_7FFA_C46A_CDA4;
static EXAMPLE_CODE: & = &;
Create and encode instructions
This example uses a BlockEncoder
to encode created Instruction
s. This example needs the db
feature because it creates db
"instructions".
use ;
pub
/*
Output:
00001248FC840000 push %rbp
00001248FC840001 push %rdi
00001248FC840002 push %rsi
00001248FC840003 sub $0x50,%rsp
00001248FC84000A vzeroupper
00001248FC84000D lea 0x60(%rsp),%rbp
00001248FC840012 mov %rcx,%rsi
00001248FC840015 lea -0x38(%rbp),%rdi
00001248FC840019 mov $0xA,%ecx
00001248FC84001E xor %eax,%eax
00001248FC840020 rep stos %eax,(%rdi)
00001248FC840022 cmp $0x12345678,%rsi
00001248FC840029 jne 0x00001248FC84002C
00001248FC84002B nop
00001248FC84002C xor %r15d,%r15d
00001248FC84002F lea 0x1248FC840037,%r14
00001248FC840036 nop
00001248FC840037 .byte 0x12,0x34,0x56,0x78
*/
Disassemble with a symbol resolver
Creates a custom SymbolResolver
that is called by a Formatter
.
use ;
use HashMap;
pub
Disassemble with colorized text
Creates a custom FormatterOutput
that is called by a Formatter
.
This example will fail to compile unless you install the colored
crate, see below.
// This example uses crate colored = "1.9.2"
use ;
use ;
// Custom formatter output that stores the output in a vector.
pub
const EXAMPLE_CODE_BITNESS: u32 = 64;
const EXAMPLE_CODE_RIP: u64 = 0x0000_7FFA_C46A_CDA4;
static EXAMPLE_CODE: & = &;
Move code in memory (eg. hook a function)
Uses instruction info API and the encoder to patch a function to jump to the programmer's function.
use ;
// Decodes instructions from some address, then encodes them starting at some
// other address. This can be used to hook a function. You decode enough instructions
// until you have enough bytes to add a JMP instruction that jumps to your code.
// Your code will then conditionally jump to the original code that you re-encoded.
//
// This code uses the BlockEncoder which will help with some things, eg. converting
// short branches to longer branches if the target is too far away.
//
// 64-bit mode also supports RIP relative addressing, but the encoder can't rewrite
// those to use a longer displacement. If any of the moved instructions have RIP
// relative addressing and it tries to access data too far away, the encoder will fail.
// The easiest solution is to use OS alloc functions that allocate memory close to the
// original code (+/-2GB).
/*
This method produces the following output:
Original code:
00007FFAC46ACDA4 mov [rsp+10h],rbx
00007FFAC46ACDA9 mov [rsp+18h],rsi
00007FFAC46ACDAE push rbp
00007FFAC46ACDAF push rdi
00007FFAC46ACDB0 push r14
00007FFAC46ACDB2 lea rbp,[rsp-100h]
00007FFAC46ACDBA sub rsp,200h
00007FFAC46ACDC1 mov rax,[rel 7FFAC47524E0h]
00007FFAC46ACDC8 xor rax,rsp
00007FFAC46ACDCB mov [rbp+0F0h],rax
00007FFAC46ACDD2 mov r8,[rel 7FFAC474F208h]
00007FFAC46ACDD9 lea rax,[rel 7FFAC46F4A58h]
00007FFAC46ACDE0 xor edi,edi
Original + patched code:
00007FFAC46ACDA4 mov rax,123456789ABCDEF0h
00007FFAC46ACDAE jmp rax
00007FFAC46ACDB0 push r14
00007FFAC46ACDB2 lea rbp,[rsp-100h]
00007FFAC46ACDBA sub rsp,200h
00007FFAC46ACDC1 mov rax,[rel 7FFAC47524E0h]
00007FFAC46ACDC8 xor rax,rsp
00007FFAC46ACDCB mov [rbp+0F0h],rax
00007FFAC46ACDD2 mov r8,[rel 7FFAC474F208h]
00007FFAC46ACDD9 lea rax,[rel 7FFAC46F4A58h]
00007FFAC46ACDE0 xor edi,edi
Moved code:
00007FFAC48ACDA4 mov [rsp+10h],rbx
00007FFAC48ACDA9 mov [rsp+18h],rsi
00007FFAC48ACDAE push rbp
00007FFAC48ACDAF push rdi
00007FFAC48ACDB0 jmp 00007FFAC46ACDB0h
*/
pub
const EXAMPLE_CODE_BITNESS: u32 = 64;
const EXAMPLE_CODE_RIP: u64 = 0x0000_7FFA_C46A_CDA4;
static EXAMPLE_CODE: & = &;
Get instruction info, eg. read/written regs/mem, control flow info, etc
Shows how to get used registers/memory and other info. It uses Instruction
methods
and an InstructionInfoFactory
to get this info.
use ;
/*
This method produces the following output:
00007FFAC46ACDA4 mov [rsp+10h],rbx
OpCode: REX.W 89 /r
Instruction: MOV r/m64, r64
Encoding: Legacy
Mnemonic: Mov
Code: Mov_rm64_r64
CpuidFeature: X64
FlowControl: Next
Displacement offset = 4, size = 1
Memory size: 8
Op0Access: Write
Op1Access: Read
Op0: r64_or_mem
Op1: r64_reg
Used reg: RSP:Read
Used reg: RBX:Read
Used mem: [SS:RSP+0x10;UInt64;Write]
00007FFAC46ACDA9 mov [rsp+18h],rsi
OpCode: REX.W 89 /r
Instruction: MOV r/m64, r64
Encoding: Legacy
Mnemonic: Mov
Code: Mov_rm64_r64
CpuidFeature: X64
FlowControl: Next
Displacement offset = 4, size = 1
Memory size: 8
Op0Access: Write
Op1Access: Read
Op0: r64_or_mem
Op1: r64_reg
Used reg: RSP:Read
Used reg: RSI:Read
Used mem: [SS:RSP+0x18;UInt64;Write]
00007FFAC46ACDAE push rbp
OpCode: 50+ro
Instruction: PUSH r64
Encoding: Legacy
Mnemonic: Push
Code: Push_r64
CpuidFeature: X64
FlowControl: Next
SP Increment: -8
Op0Access: Read
Op0: r64_opcode
Used reg: RBP:Read
Used reg: RSP:ReadWrite
Used mem: [SS:RSP+0xFFFFFFFFFFFFFFF8;UInt64;Write]
00007FFAC46ACDAF push rdi
OpCode: 50+ro
Instruction: PUSH r64
Encoding: Legacy
Mnemonic: Push
Code: Push_r64
CpuidFeature: X64
FlowControl: Next
SP Increment: -8
Op0Access: Read
Op0: r64_opcode
Used reg: RDI:Read
Used reg: RSP:ReadWrite
Used mem: [SS:RSP+0xFFFFFFFFFFFFFFF8;UInt64;Write]
00007FFAC46ACDB0 push r14
OpCode: 50+ro
Instruction: PUSH r64
Encoding: Legacy
Mnemonic: Push
Code: Push_r64
CpuidFeature: X64
FlowControl: Next
SP Increment: -8
Op0Access: Read
Op0: r64_opcode
Used reg: R14:Read
Used reg: RSP:ReadWrite
Used mem: [SS:RSP+0xFFFFFFFFFFFFFFF8;UInt64;Write]
00007FFAC46ACDB2 lea rbp,[rsp-100h]
OpCode: REX.W 8D /r
Instruction: LEA r64, m
Encoding: Legacy
Mnemonic: Lea
Code: Lea_r64_m
CpuidFeature: X64
FlowControl: Next
Displacement offset = 4, size = 4
Op0Access: Write
Op1Access: NoMemAccess
Op0: r64_reg
Op1: mem
Used reg: RBP:Write
Used reg: RSP:Read
00007FFAC46ACDBA sub rsp,200h
OpCode: REX.W 81 /5 id
Instruction: SUB r/m64, imm32
Encoding: Legacy
Mnemonic: Sub
Code: Sub_rm64_imm32
CpuidFeature: X64
FlowControl: Next
Immediate offset = 3, size = 4
RFLAGS Written: OF, SF, ZF, AF, CF, PF
RFLAGS Modified: OF, SF, ZF, AF, CF, PF
Op0Access: ReadWrite
Op1Access: Read
Op0: r64_or_mem
Op1: imm32sex64
Used reg: RSP:ReadWrite
00007FFAC46ACDC1 mov rax,[7FFAC47524E0h]
OpCode: REX.W 8B /r
Instruction: MOV r64, r/m64
Encoding: Legacy
Mnemonic: Mov
Code: Mov_r64_rm64
CpuidFeature: X64
FlowControl: Next
Displacement offset = 3, size = 4
Memory size: 8
Op0Access: Write
Op1Access: Read
Op0: r64_reg
Op1: r64_or_mem
Used reg: RAX:Write
Used mem: [DS:0x7FFAC47524E0;UInt64;Read]
00007FFAC46ACDC8 xor rax,rsp
OpCode: REX.W 33 /r
Instruction: XOR r64, r/m64
Encoding: Legacy
Mnemonic: Xor
Code: Xor_r64_rm64
CpuidFeature: X64
FlowControl: Next
RFLAGS Written: SF, ZF, PF
RFLAGS Cleared: OF, CF
RFLAGS Undefined: AF
RFLAGS Modified: OF, SF, ZF, AF, CF, PF
Op0Access: ReadWrite
Op1Access: Read
Op0: r64_reg
Op1: r64_or_mem
Used reg: RAX:ReadWrite
Used reg: RSP:Read
00007FFAC46ACDCB mov [rbp+0F0h],rax
OpCode: REX.W 89 /r
Instruction: MOV r/m64, r64
Encoding: Legacy
Mnemonic: Mov
Code: Mov_rm64_r64
CpuidFeature: X64
FlowControl: Next
Displacement offset = 3, size = 4
Memory size: 8
Op0Access: Write
Op1Access: Read
Op0: r64_or_mem
Op1: r64_reg
Used reg: RBP:Read
Used reg: RAX:Read
Used mem: [SS:RBP+0xF0;UInt64;Write]
00007FFAC46ACDD2 mov r8,[7FFAC474F208h]
OpCode: REX.W 8B /r
Instruction: MOV r64, r/m64
Encoding: Legacy
Mnemonic: Mov
Code: Mov_r64_rm64
CpuidFeature: X64
FlowControl: Next
Displacement offset = 3, size = 4
Memory size: 8
Op0Access: Write
Op1Access: Read
Op0: r64_reg
Op1: r64_or_mem
Used reg: R8:Write
Used mem: [DS:0x7FFAC474F208;UInt64;Read]
00007FFAC46ACDD9 lea rax,[7FFAC46F4A58h]
OpCode: REX.W 8D /r
Instruction: LEA r64, m
Encoding: Legacy
Mnemonic: Lea
Code: Lea_r64_m
CpuidFeature: X64
FlowControl: Next
Displacement offset = 3, size = 4
Op0Access: Write
Op1Access: NoMemAccess
Op0: r64_reg
Op1: mem
Used reg: RAX:Write
00007FFAC46ACDE0 xor edi,edi
OpCode: o32 33 /r
Instruction: XOR r32, r/m32
Encoding: Legacy
Mnemonic: Xor
Code: Xor_r32_rm32
CpuidFeature: INTEL386
FlowControl: Next
RFLAGS Cleared: OF, SF, CF
RFLAGS Set: ZF, PF
RFLAGS Undefined: AF
RFLAGS Modified: OF, SF, ZF, AF, CF, PF
Op0Access: Write
Op1Access: None
Op0: r32_reg
Op1: r32_or_mem
Used reg: RDI:Write
*/
pub
const EXAMPLE_CODE_BITNESS: u32 = 64;
const EXAMPLE_CODE_RIP: u64 = 0x0000_7FFA_C46A_CDA4;
static EXAMPLE_CODE: & = &;
Get the virtual address of a memory operand
use ;
pub
Minimum supported rustc
version
iced-x86 supports rustc
1.20.0
or later.
This is checked in CI builds where the minimum supported version and the latest stable version are used to build the source code and run tests.
If you use an older version of rustc
, you may need to update the versions of some iced-x86 dependencies because cargo
prefers to use the latest version which may not support your rustc
.
Eg. iced-x86 needs lazy_static
1.1.1
(or later), but cargo
wants to use the latest version which is currently 1.4.0
and it doesn't support the minimum supported rustc
version.
Here's how you can force a compatible version of any iced-x86 dependency without updating iced-x86's Cargo.toml
:
Bumping the minimum supported version of rustc
is considered a minor breaking change. The minor version of iced-x86 will be incremented.