2019-10-05 15:57:58 +00:00
|
|
|
# Iced [](https://www.nuget.org/packages/Iced/) [](https://github.com/0xd4d/iced/actions) [](https://codecov.io/gh/0xd4d/iced)
|
2018-09-07 20:48:32 +00:00
|
|
|
|
2018-09-21 19:30:08 +00:00
|
|
|
|
|
|
|
<img align="right" width="160px" height="160px" src="logo.png">
|
|
|
|
|
2020-01-05 12:12:25 +00:00
|
|
|
High performance x86 (16/32/64-bit) instruction decoder, disassembler and assembler.
|
2018-09-05 23:29:23 +00:00
|
|
|
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.
|
|
|
|
|
2018-09-12 21:33:12 +00:00
|
|
|
- Supports all Intel and AMD instructions
|
2020-01-24 08:04:13 +00:00
|
|
|
- High level [Assembler](#Assembler) providing a simple and lean syntax (e.g `asm.mov(eax, edx)`))
|
|
|
|
- [Decoding](#Decoding) and disassembler support:
|
|
|
|
- The decoder doesn't allocate any memory and is 2x-5x+ faster than other similar libraries written in C or C#
|
|
|
|
- Small decoded instructions, only 32 bytes
|
|
|
|
- The formatter supports masm, nasm, gas (AT&T), Intel (XED) and there are many options to customize the output
|
|
|
|
- Encoding support:
|
|
|
|
- The encoder can be used to re-encode decoded instructions at any address
|
|
|
|
- The block encoder encodes a list of instructions and optimizes branches to short, near or 'long' (64-bit: 1 or more instructions)
|
2018-09-05 23:29:23 +00:00
|
|
|
- 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)
|
2020-01-24 08:04:13 +00:00
|
|
|
- Supports of `.NET Standard 2.0/2.1+` and `.NET Framework 4.5+`
|
2018-09-05 23:29:23 +00:00
|
|
|
|
2018-09-07 19:33:05 +00:00
|
|
|
# Classes
|
2018-09-05 23:29:23 +00:00
|
|
|
|
2018-09-06 18:56:16 +00:00
|
|
|
See below for some examples. All classes are in the `Iced.Intel` namespace.
|
2018-09-05 23:29:23 +00:00
|
|
|
|
|
|
|
Decoder:
|
|
|
|
|
|
|
|
- `Decoder`
|
2019-12-30 21:10:38 +00:00
|
|
|
- `Instruction` (and `Instruction.Create()` methods)
|
2018-09-05 23:29:23 +00:00
|
|
|
- `CodeReader`
|
|
|
|
- `ByteArrayCodeReader`
|
2020-01-24 08:04:13 +00:00
|
|
|
- `StreamCodeReader`
|
2018-10-04 19:03:30 +00:00
|
|
|
- `InstructionList`
|
2018-09-05 23:29:23 +00:00
|
|
|
- `ConstantOffsets`
|
2019-02-23 11:15:10 +00:00
|
|
|
- `IcedFeatures.Initialize()`
|
2018-09-05 23:29:23 +00:00
|
|
|
|
|
|
|
Formatters:
|
|
|
|
|
|
|
|
- `Formatter`
|
|
|
|
- `MasmFormatter`
|
|
|
|
- `NasmFormatter`
|
|
|
|
- `GasFormatter`
|
2019-08-09 19:17:51 +00:00
|
|
|
- `IntelFormatter`
|
2018-09-05 23:29:23 +00:00
|
|
|
- `FormatterOptions`
|
|
|
|
- `MasmFormatterOptions`
|
|
|
|
- `NasmFormatterOptions`
|
|
|
|
- `GasFormatterOptions`
|
2019-08-09 19:17:51 +00:00
|
|
|
- `IntelFormatterOptions`
|
2018-09-05 23:29:23 +00:00
|
|
|
- `FormatterOutput`
|
2020-01-15 19:25:43 +00:00
|
|
|
- `StringOutput`
|
2018-10-27 18:50:44 +00:00
|
|
|
- `ISymbolResolver`
|
|
|
|
- `IFormatterOptionsProvider`
|
2018-09-05 23:29:23 +00:00
|
|
|
|
|
|
|
Encoder:
|
|
|
|
|
|
|
|
- `Encoder`
|
|
|
|
- `BlockEncoder`
|
|
|
|
- `CodeWriter`
|
2020-01-24 08:04:13 +00:00
|
|
|
- `StreamCodeWriter`
|
2018-09-05 23:29:23 +00:00
|
|
|
- `ConstantOffsets`
|
2019-08-22 19:45:33 +00:00
|
|
|
- `OpCodeInfo` (`Instruction.OpCode` and `Code.ToOpCode()`)
|
2018-09-05 23:29:23 +00:00
|
|
|
|
|
|
|
Instruction info:
|
|
|
|
|
|
|
|
- `InstructionInfo`
|
|
|
|
- `InstructionInfoFactory`
|
|
|
|
- `InstructionInfoExtensions`
|
|
|
|
- `MemorySizeExtensions`
|
|
|
|
- `RegisterExtensions`
|
|
|
|
|
2020-01-18 08:26:20 +00:00
|
|
|
High Level Assembler:
|
|
|
|
|
|
|
|
- `Assembler`
|
2020-01-24 08:04:13 +00:00
|
|
|
- `Label`
|
2020-01-18 08:26:20 +00:00
|
|
|
- `AssemblerRegisters` (use `using static` to have access directly to registers e.g `eax`, `rdi`, `xmm1`...)
|
|
|
|
|
2018-09-07 19:33:05 +00:00
|
|
|
# Examples
|
2018-09-05 23:29:23 +00:00
|
|
|
|
2020-01-18 08:26:20 +00:00
|
|
|
## Decoding
|
|
|
|
|
2019-02-03 15:25:26 +00:00
|
|
|
For another example, see [JitDasm](https://github.com/0xd4d/JitDasm).
|
|
|
|
|
2018-09-07 19:09:29 +00:00
|
|
|
```C#
|
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using Iced.Intel;
|
|
|
|
|
|
|
|
namespace Iced.Examples {
|
|
|
|
static class Program {
|
2019-02-03 15:25:26 +00:00
|
|
|
const int HEXBYTES_COLUMN_BYTE_LENGTH = 10;
|
|
|
|
|
2018-09-07 19:09:29 +00:00
|
|
|
static void Main(string[] args) {
|
2019-02-23 11:15:10 +00:00
|
|
|
IcedFeatures.Initialize();
|
2018-09-07 19:09:29 +00:00
|
|
|
DecoderFormatterExample();
|
|
|
|
EncoderExample();
|
2019-02-18 19:46:34 +00:00
|
|
|
CreateInstructionsExample();
|
2018-09-07 19:09:29 +00:00
|
|
|
InstructionInfoExample();
|
|
|
|
}
|
|
|
|
|
|
|
|
const int exampleCodeBitness = 64;
|
|
|
|
const ulong exampleCodeRIP = 0x00007FFAC46ACDA4;
|
|
|
|
static readonly byte[] exampleCode = new byte[] {
|
|
|
|
0x48, 0x89, 0x5C, 0x24, 0x10, 0x48, 0x89, 0x74, 0x24, 0x18, 0x55, 0x57, 0x41, 0x56, 0x48, 0x8D,
|
|
|
|
0xAC, 0x24, 0x00, 0xFF, 0xFF, 0xFF, 0x48, 0x81, 0xEC, 0x00, 0x02, 0x00, 0x00, 0x48, 0x8B, 0x05,
|
|
|
|
0x18, 0x57, 0x0A, 0x00, 0x48, 0x33, 0xC4, 0x48, 0x89, 0x85, 0xF0, 0x00, 0x00, 0x00, 0x4C, 0x8B,
|
|
|
|
0x05, 0x2F, 0x24, 0x0A, 0x00, 0x48, 0x8D, 0x05, 0x78, 0x7C, 0x04, 0x00, 0x33, 0xFF
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This method produces the following output:
|
2019-02-03 15:25:26 +00:00
|
|
|
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
|
2018-09-07 19:09:29 +00:00
|
|
|
*/
|
|
|
|
static void DecoderFormatterExample() {
|
|
|
|
// You can also pass in a hex string, eg. "90 91 929394", or you can use your own CodeReader
|
|
|
|
// reading data from a file or memory etc
|
2019-02-03 15:25:26 +00:00
|
|
|
var codeBytes = exampleCode;
|
|
|
|
var codeReader = new ByteArrayCodeReader(codeBytes);
|
2018-09-07 19:09:29 +00:00
|
|
|
var decoder = Decoder.Create(exampleCodeBitness, codeReader);
|
2019-02-03 15:25:49 +00:00
|
|
|
decoder.IP = exampleCodeRIP;
|
|
|
|
ulong endRip = decoder.IP + (uint)codeBytes.Length;
|
2018-09-07 19:09:29 +00:00
|
|
|
|
2018-10-04 19:03:30 +00:00
|
|
|
// This list is faster than List<Instruction> since it uses refs to the Instructions
|
|
|
|
// instead of copying them (each Instruction is 32 bytes in size). It has a ref indexer,
|
|
|
|
// and a ref iterator. Add() uses 'in' (ref readonly).
|
|
|
|
var instructions = new InstructionList();
|
2019-02-03 15:25:49 +00:00
|
|
|
while (decoder.IP < endRip) {
|
2018-10-04 19:03:30 +00:00
|
|
|
// The method allocates an uninitialized element at the end of the list and
|
|
|
|
// returns a reference to it which is initialized by Decode().
|
|
|
|
decoder.Decode(out instructions.AllocUninitializedElement());
|
|
|
|
}
|
|
|
|
|
2019-08-17 16:15:42 +00:00
|
|
|
// Formatters: Masm*, Nasm*, Gas* (AT&T) and Intel* (XED)
|
2018-09-07 19:09:29 +00:00
|
|
|
var formatter = new NasmFormatter();
|
|
|
|
formatter.Options.DigitSeparator = "`";
|
|
|
|
formatter.Options.FirstOperandCharIndex = 10;
|
2020-01-15 19:25:43 +00:00
|
|
|
var output = new StringOutput();
|
2018-10-04 19:03:30 +00:00
|
|
|
// Use InstructionList's ref iterator (C# 7.3) to prevent copying 32 bytes every iteration
|
|
|
|
foreach (ref var instr in instructions) {
|
|
|
|
// Don't use instr.ToString(), it allocates more, uses masm syntax and default options
|
2019-05-21 20:49:45 +00:00
|
|
|
formatter.Format(instr, output);
|
2019-02-03 15:25:49 +00:00
|
|
|
Console.Write(instr.IP.ToString("X16"));
|
2019-02-03 15:25:26 +00:00
|
|
|
Console.Write(" ");
|
2019-11-02 23:00:25 +00:00
|
|
|
int instrLen = instr.Length;
|
2019-02-03 15:25:49 +00:00
|
|
|
int byteBaseIndex = (int)(instr.IP - exampleCodeRIP);
|
2019-02-03 15:25:26 +00:00
|
|
|
for (int i = 0; i < instrLen; i++)
|
|
|
|
Console.Write(codeBytes[byteBaseIndex + i].ToString("X2"));
|
|
|
|
int missingBytes = HEXBYTES_COLUMN_BYTE_LENGTH - instrLen;
|
|
|
|
for (int i = 0; i < missingBytes; i++)
|
|
|
|
Console.Write(" ");
|
|
|
|
Console.Write(" ");
|
|
|
|
Console.WriteLine(output.ToStringAndReset());
|
2018-09-07 19:09:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This method produces the following output:
|
|
|
|
New code bytes:
|
|
|
|
0x48, 0x89, 0x5C, 0x24, 0x10, 0x48, 0x89, 0x74, 0x24, 0x18, 0x55, 0x57, 0x41, 0x56, 0x48, 0x8D
|
|
|
|
0xAC, 0x24, 0x00, 0xFF, 0xFF, 0xFF, 0x48, 0x81, 0xEC, 0x00, 0x02, 0x00, 0x00, 0x48, 0x8B, 0x05
|
|
|
|
0x18, 0x57, 0xEA, 0xFF, 0x48, 0x33, 0xC4, 0x48, 0x89, 0x85, 0xF0, 0x00, 0x00, 0x00, 0x4C, 0x8B
|
|
|
|
0x05, 0x2F, 0x24, 0xEA, 0xFF, 0x48, 0x8D, 0x05, 0x78, 0x7C, 0xE4, 0xFF, 0x33, 0xFF
|
|
|
|
Disassembled code:
|
|
|
|
00007FFAC48ACDA4 mov [rsp+10h],rbx
|
|
|
|
00007FFAC48ACDA9 mov [rsp+18h],rsi
|
|
|
|
00007FFAC48ACDAE push rbp
|
|
|
|
00007FFAC48ACDAF push rdi
|
|
|
|
00007FFAC48ACDB0 push r14
|
|
|
|
00007FFAC48ACDB2 lea rbp,[rsp-100h]
|
|
|
|
00007FFAC48ACDBA sub rsp,200h
|
|
|
|
00007FFAC48ACDC1 mov rax,[rel 7FFA`C475`24E0h]
|
|
|
|
00007FFAC48ACDC8 xor rax,rsp
|
|
|
|
00007FFAC48ACDCB mov [rbp+0F0h],rax
|
|
|
|
00007FFAC48ACDD2 mov r8,[rel 7FFA`C474`F208h]
|
|
|
|
00007FFAC48ACDD9 lea rax,[rel 7FFA`C46F`4A58h]
|
|
|
|
00007FFAC48ACDE0 xor edi,edi
|
|
|
|
*/
|
|
|
|
static void EncoderExample() {
|
|
|
|
var codeReader = new ByteArrayCodeReader(exampleCode);
|
|
|
|
var decoder = Decoder.Create(exampleCodeBitness, codeReader);
|
2019-02-03 15:25:49 +00:00
|
|
|
decoder.IP = exampleCodeRIP;
|
|
|
|
ulong endRip = decoder.IP + (uint)exampleCode.Length;
|
2018-09-07 19:09:29 +00:00
|
|
|
|
2018-10-04 19:03:30 +00:00
|
|
|
var instructions = new InstructionList();
|
2019-02-03 15:25:49 +00:00
|
|
|
while (decoder.IP < endRip)
|
2018-10-04 19:03:30 +00:00
|
|
|
decoder.Decode(out instructions.AllocUninitializedElement());
|
2018-09-07 19:09:29 +00:00
|
|
|
|
|
|
|
// Relocate the code to some new location. It can fix short/near branches and
|
|
|
|
// convert them to short/near/long forms if needed. This also works even if it's a
|
|
|
|
// jrcxz/loop/loopcc instruction which only has a short form.
|
|
|
|
//
|
|
|
|
// It can currently only fix RIP relative operands if the new location is within 2GB
|
|
|
|
// of the target data location.
|
|
|
|
//
|
|
|
|
// There's also a simpler Encoder class which is used by BlockEncoder, but it can only
|
|
|
|
// encode one instruction at a time and doesn't fix branches.
|
|
|
|
//
|
|
|
|
// Note that a block is not the same thing as a basic block. A block can contain any
|
|
|
|
// number of instructions, including any number of branch instructions. One block
|
|
|
|
// should be enough unless you must relocate different blocks to different locations.
|
|
|
|
var codeWriter = new CodeWriterImpl();
|
|
|
|
ulong relocatedBaseAddress = exampleCodeRIP + 0x200000;
|
|
|
|
var block = new InstructionBlock(codeWriter, instructions, relocatedBaseAddress);
|
|
|
|
// This method can also encode more than one block but that's rarely needed, see above comment.
|
2020-01-03 21:01:49 +00:00
|
|
|
bool success = BlockEncoder.TryEncode(decoder.Bitness, block, out var errorMessage, out _);
|
2018-10-26 20:22:22 +00:00
|
|
|
if (!success) {
|
2018-09-07 19:09:29 +00:00
|
|
|
Console.WriteLine($"ERROR: {errorMessage}");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var newCode = codeWriter.ToArray();
|
|
|
|
Console.WriteLine("New code bytes:");
|
|
|
|
for (int i = 0; i < newCode.Length;) {
|
|
|
|
for (int j = 0; j < 16 && i < newCode.Length; i++, j++) {
|
|
|
|
if (j != 0)
|
|
|
|
Console.Write(", ");
|
|
|
|
Console.Write("0x");
|
|
|
|
Console.Write(newCode[i].ToString("X2"));
|
|
|
|
}
|
|
|
|
Console.WriteLine();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Disassemble the new relocated code. It's identical to the original code except that
|
|
|
|
// the RIP relative instructions have been updated.
|
|
|
|
Console.WriteLine("Disassembled code:");
|
|
|
|
var formatter = new NasmFormatter();
|
|
|
|
formatter.Options.DigitSeparator = "`";
|
|
|
|
formatter.Options.FirstOperandCharIndex = 10;
|
2020-01-15 19:25:43 +00:00
|
|
|
var output = new StringOutput();
|
2018-09-07 19:09:29 +00:00
|
|
|
var newDecoder = Decoder.Create(decoder.Bitness, new ByteArrayCodeReader(newCode));
|
2019-02-03 15:25:49 +00:00
|
|
|
newDecoder.IP = block.RIP;
|
|
|
|
endRip = newDecoder.IP + (uint)newCode.Length;
|
|
|
|
while (newDecoder.IP < endRip) {
|
2018-09-07 19:09:29 +00:00
|
|
|
newDecoder.Decode(out var instr);
|
2019-05-21 20:49:45 +00:00
|
|
|
formatter.Format(instr, output);
|
2019-02-03 15:25:49 +00:00
|
|
|
Console.WriteLine($"{instr.IP:X16} {output.ToStringAndReset()}");
|
2018-09-07 19:09:29 +00:00
|
|
|
}
|
|
|
|
}
|
2018-10-04 19:03:30 +00:00
|
|
|
// Simple and inefficient code writer that stores the data in a List<byte>, with a ToArray() method
|
|
|
|
// to get the data
|
2018-09-07 19:09:29 +00:00
|
|
|
sealed class CodeWriterImpl : CodeWriter {
|
|
|
|
readonly List<byte> allBytes = new List<byte>();
|
|
|
|
public override void WriteByte(byte value) => allBytes.Add(value);
|
|
|
|
public byte[] ToArray() => allBytes.ToArray();
|
|
|
|
}
|
|
|
|
|
2019-02-18 19:46:34 +00:00
|
|
|
/*
|
|
|
|
* This method produces the following output:
|
|
|
|
Disassembled code:
|
|
|
|
00007FFAC48ACDA4 push rbp
|
|
|
|
00007FFAC48ACDA5 push rdi
|
|
|
|
00007FFAC48ACDA6 push rsi
|
|
|
|
00007FFAC48ACDA7 sub rsp,50h
|
|
|
|
00007FFAC48ACDAE vzeroupper
|
|
|
|
00007FFAC48ACDB1 lea rbp,[rsp+60h]
|
|
|
|
00007FFAC48ACDB6 mov rsi,rcx
|
|
|
|
00007FFAC48ACDB9 lea rdi,[rbp-38h]
|
|
|
|
00007FFAC48ACDBD mov ecx,0Ah
|
|
|
|
00007FFAC48ACDC2 xor eax,eax
|
|
|
|
00007FFAC48ACDC4 rep stosd
|
|
|
|
00007FFAC48ACDC6 mov rcx,rsi
|
|
|
|
00007FFAC48ACDC9 mov [rbp+10h],rcx
|
|
|
|
00007FFAC48ACDCD mov [rbp+18h],rdx
|
|
|
|
*/
|
|
|
|
static void CreateInstructionsExample() {
|
|
|
|
const int bitness = 64;
|
|
|
|
|
|
|
|
var instructions = new InstructionList();
|
|
|
|
// push rbp
|
|
|
|
instructions.Add(Instruction.Create(Code.Push_r64, Register.RBP));
|
|
|
|
// push rdi
|
|
|
|
instructions.Add(Instruction.Create(Code.Push_r64, Register.RDI));
|
|
|
|
// push rsi
|
|
|
|
instructions.Add(Instruction.Create(Code.Push_r64, Register.RSI));
|
|
|
|
// sub rsp,50h
|
|
|
|
instructions.Add(Instruction.Create(Code.Sub_rm64_imm32, Register.RSP, 0x50));
|
|
|
|
// vzeroupper
|
|
|
|
instructions.Add(Instruction.Create(Code.VEX_Vzeroupper));
|
|
|
|
// lea rbp,[rsp+60h]
|
|
|
|
instructions.Add(Instruction.Create(Code.Lea_r64_m, Register.RBP, new MemoryOperand(Register.RSP, 0x60)));
|
|
|
|
// mov rsi,rcx
|
|
|
|
instructions.Add(Instruction.Create(Code.Mov_r64_rm64, Register.RSI, Register.RCX));
|
|
|
|
// lea rdi,[rbp-38h]
|
|
|
|
instructions.Add(Instruction.Create(Code.Lea_r64_m, Register.RDI, new MemoryOperand(Register.RBP, -0x38)));
|
|
|
|
// mov ecx,0Ah
|
|
|
|
instructions.Add(Instruction.Create(Code.Mov_r32_imm32, Register.ECX, 0x0A));
|
|
|
|
// xor eax,eax
|
|
|
|
instructions.Add(Instruction.Create(Code.Xor_r32_rm32, Register.EAX, Register.EAX));
|
|
|
|
// rep stosd
|
2020-01-03 21:01:49 +00:00
|
|
|
instructions.Add(Instruction.CreateStosd(bitness, RepPrefixKind.Repe));
|
2019-02-18 19:46:34 +00:00
|
|
|
// mov rcx,rsi
|
|
|
|
instructions.Add(Instruction.Create(Code.Mov_r64_rm64, Register.RCX, Register.RSI));
|
|
|
|
// mov [rbp+10h],rcx
|
|
|
|
instructions.Add(Instruction.Create(Code.Mov_rm64_r64, new MemoryOperand(Register.RBP, 0x10), Register.RCX));
|
|
|
|
// mov [rbp+18h],rdx
|
|
|
|
instructions.Add(Instruction.Create(Code.Mov_rm64_r64, new MemoryOperand(Register.RBP, 0x18), Register.RDX));
|
|
|
|
|
|
|
|
var codeWriter = new CodeWriterImpl();
|
|
|
|
ulong relocatedBaseAddress = exampleCodeRIP + 0x200000;
|
|
|
|
var block = new InstructionBlock(codeWriter, instructions, relocatedBaseAddress);
|
2020-01-03 21:01:49 +00:00
|
|
|
bool success = BlockEncoder.TryEncode(bitness, block, out var errorMessage, out _);
|
2019-02-18 19:46:34 +00:00
|
|
|
if (!success) {
|
|
|
|
Console.WriteLine($"ERROR: {errorMessage}");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var newCode = codeWriter.ToArray();
|
|
|
|
Console.WriteLine("Disassembled code:");
|
|
|
|
var formatter = new NasmFormatter();
|
|
|
|
formatter.Options.DigitSeparator = "`";
|
|
|
|
formatter.Options.FirstOperandCharIndex = 10;
|
2020-01-15 19:25:43 +00:00
|
|
|
var output = new StringOutput();
|
2019-02-18 19:46:34 +00:00
|
|
|
var newDecoder = Decoder.Create(bitness, new ByteArrayCodeReader(newCode));
|
|
|
|
newDecoder.IP = block.RIP;
|
|
|
|
ulong endRip = newDecoder.IP + (uint)newCode.Length;
|
|
|
|
while (newDecoder.IP < endRip) {
|
|
|
|
newDecoder.Decode(out var instr);
|
2019-05-21 20:49:45 +00:00
|
|
|
formatter.Format(instr, output);
|
2019-02-18 19:46:34 +00:00
|
|
|
Console.WriteLine($"{instr.IP:X16} {output.ToStringAndReset()}");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-07 19:09:29 +00:00
|
|
|
/*
|
|
|
|
* This method produces the following output:
|
|
|
|
00007FFAC46ACDA4 mov [rsp+10h],rbx
|
2019-08-22 19:44:40 +00:00
|
|
|
OpCode: REX.W 89 /r
|
2019-09-12 21:06:08 +00:00
|
|
|
Instruction: MOV r/m64, r64
|
2018-09-07 19:09:29 +00:00
|
|
|
Encoding: Legacy
|
2019-05-22 16:57:52 +00:00
|
|
|
Mnemonic: Mov
|
2019-07-18 19:58:13 +00:00
|
|
|
Code: Mov_rm64_r64
|
2019-02-06 18:08:19 +00:00
|
|
|
CpuidFeature: X64
|
2018-09-07 19:09:29 +00:00
|
|
|
FlowControl: Next
|
2019-02-03 15:25:26 +00:00
|
|
|
Displacement offset = 4, size = 1
|
2019-02-12 21:02:42 +00:00
|
|
|
Memory size: 8
|
2018-09-07 19:09:29 +00:00
|
|
|
Op0Access: Write
|
|
|
|
Op1Access: Read
|
2019-09-01 17:07:36 +00:00
|
|
|
Op0: r64_or_mem
|
2019-08-22 19:44:40 +00:00
|
|
|
Op1: r64_reg
|
2018-09-07 19:09:29 +00:00
|
|
|
RSP:Read
|
|
|
|
RBX:Read
|
2018-10-26 20:21:37 +00:00
|
|
|
[SS:RSP+0x10;UInt64;Write]
|
2018-09-07 19:09:29 +00:00
|
|
|
00007FFAC46ACDA9 mov [rsp+18h],rsi
|
2019-08-22 19:44:40 +00:00
|
|
|
OpCode: REX.W 89 /r
|
2019-09-12 21:06:08 +00:00
|
|
|
Instruction: MOV r/m64, r64
|
2018-09-07 19:09:29 +00:00
|
|
|
Encoding: Legacy
|
2019-05-22 16:57:52 +00:00
|
|
|
Mnemonic: Mov
|
2019-07-18 19:58:13 +00:00
|
|
|
Code: Mov_rm64_r64
|
2019-02-06 18:08:19 +00:00
|
|
|
CpuidFeature: X64
|
2018-09-07 19:09:29 +00:00
|
|
|
FlowControl: Next
|
2019-02-03 15:25:26 +00:00
|
|
|
Displacement offset = 4, size = 1
|
2019-02-12 21:02:42 +00:00
|
|
|
Memory size: 8
|
2018-09-07 19:09:29 +00:00
|
|
|
Op0Access: Write
|
|
|
|
Op1Access: Read
|
2019-09-01 17:07:36 +00:00
|
|
|
Op0: r64_or_mem
|
2019-08-22 19:44:40 +00:00
|
|
|
Op1: r64_reg
|
2018-09-07 19:09:29 +00:00
|
|
|
RSP:Read
|
|
|
|
RSI:Read
|
2018-10-26 20:21:37 +00:00
|
|
|
[SS:RSP+0x18;UInt64;Write]
|
2018-09-07 19:09:29 +00:00
|
|
|
00007FFAC46ACDAE push rbp
|
2019-08-22 19:44:40 +00:00
|
|
|
OpCode: 50+ro
|
2019-09-12 21:06:08 +00:00
|
|
|
Instruction: PUSH r64
|
2018-09-07 19:09:29 +00:00
|
|
|
Encoding: Legacy
|
2019-05-22 16:57:52 +00:00
|
|
|
Mnemonic: Push
|
2019-07-18 19:58:13 +00:00
|
|
|
Code: Push_r64
|
2019-02-06 18:08:19 +00:00
|
|
|
CpuidFeature: X64
|
2018-09-07 19:09:29 +00:00
|
|
|
FlowControl: Next
|
|
|
|
SP Increment: -8
|
|
|
|
Op0Access: Read
|
2019-08-22 19:44:40 +00:00
|
|
|
Op0: r64_opcode
|
2018-09-07 19:09:29 +00:00
|
|
|
RBP:Read
|
|
|
|
RSP:ReadWrite
|
2018-10-26 20:21:37 +00:00
|
|
|
[SS:RSP+0xFFFFFFFFFFFFFFF8;UInt64;Write]
|
2018-09-07 19:09:29 +00:00
|
|
|
00007FFAC46ACDAF push rdi
|
2019-08-22 19:44:40 +00:00
|
|
|
OpCode: 50+ro
|
2019-09-12 21:06:08 +00:00
|
|
|
Instruction: PUSH r64
|
2018-09-07 19:09:29 +00:00
|
|
|
Encoding: Legacy
|
2019-05-22 16:57:52 +00:00
|
|
|
Mnemonic: Push
|
2019-07-18 19:58:13 +00:00
|
|
|
Code: Push_r64
|
2019-02-06 18:08:19 +00:00
|
|
|
CpuidFeature: X64
|
2018-09-07 19:09:29 +00:00
|
|
|
FlowControl: Next
|
|
|
|
SP Increment: -8
|
|
|
|
Op0Access: Read
|
2019-08-22 19:44:40 +00:00
|
|
|
Op0: r64_opcode
|
2018-09-07 19:09:29 +00:00
|
|
|
RDI:Read
|
|
|
|
RSP:ReadWrite
|
2018-10-26 20:21:37 +00:00
|
|
|
[SS:RSP+0xFFFFFFFFFFFFFFF8;UInt64;Write]
|
2018-09-07 19:09:29 +00:00
|
|
|
00007FFAC46ACDB0 push r14
|
2019-08-22 19:44:40 +00:00
|
|
|
OpCode: 50+ro
|
2019-09-12 21:06:08 +00:00
|
|
|
Instruction: PUSH r64
|
2018-09-07 19:09:29 +00:00
|
|
|
Encoding: Legacy
|
2019-05-22 16:57:52 +00:00
|
|
|
Mnemonic: Push
|
2019-07-18 19:58:13 +00:00
|
|
|
Code: Push_r64
|
2019-02-06 18:08:19 +00:00
|
|
|
CpuidFeature: X64
|
2018-09-07 19:09:29 +00:00
|
|
|
FlowControl: Next
|
|
|
|
SP Increment: -8
|
|
|
|
Op0Access: Read
|
2019-08-22 19:44:40 +00:00
|
|
|
Op0: r64_opcode
|
2018-09-07 19:09:29 +00:00
|
|
|
R14:Read
|
|
|
|
RSP:ReadWrite
|
2018-10-26 20:21:37 +00:00
|
|
|
[SS:RSP+0xFFFFFFFFFFFFFFF8;UInt64;Write]
|
2018-09-07 19:09:29 +00:00
|
|
|
00007FFAC46ACDB2 lea rbp,[rsp-100h]
|
2019-08-22 19:44:40 +00:00
|
|
|
OpCode: REX.W 8D /r
|
2019-09-12 21:06:08 +00:00
|
|
|
Instruction: LEA r64, m
|
2018-09-07 19:09:29 +00:00
|
|
|
Encoding: Legacy
|
2019-05-22 16:57:52 +00:00
|
|
|
Mnemonic: Lea
|
2019-07-18 19:58:13 +00:00
|
|
|
Code: Lea_r64_m
|
2019-02-06 18:08:19 +00:00
|
|
|
CpuidFeature: X64
|
2018-09-07 19:09:29 +00:00
|
|
|
FlowControl: Next
|
2019-02-03 15:25:26 +00:00
|
|
|
Displacement offset = 4, size = 4
|
2018-09-07 19:09:29 +00:00
|
|
|
Op0Access: Write
|
|
|
|
Op1Access: NoMemAccess
|
2019-08-22 19:44:40 +00:00
|
|
|
Op0: r64_reg
|
|
|
|
Op1: mem
|
2018-09-07 19:09:29 +00:00
|
|
|
RBP:Write
|
|
|
|
RSP:Read
|
|
|
|
00007FFAC46ACDBA sub rsp,200h
|
2019-08-22 19:44:40 +00:00
|
|
|
OpCode: REX.W 81 /5 id
|
2019-09-12 21:06:08 +00:00
|
|
|
Instruction: SUB r/m64, imm32
|
2018-09-07 19:09:29 +00:00
|
|
|
Encoding: Legacy
|
2019-05-22 16:57:52 +00:00
|
|
|
Mnemonic: Sub
|
2019-07-18 19:58:13 +00:00
|
|
|
Code: Sub_rm64_imm32
|
2019-02-06 18:08:19 +00:00
|
|
|
CpuidFeature: X64
|
2018-09-07 19:09:29 +00:00
|
|
|
FlowControl: Next
|
2019-02-03 15:25:26 +00:00
|
|
|
Immediate offset = 3, size = 4
|
2018-09-07 19:09:29 +00:00
|
|
|
RFLAGS Written: OF, SF, ZF, AF, CF, PF
|
|
|
|
RFLAGS Modified: OF, SF, ZF, AF, CF, PF
|
|
|
|
Op0Access: ReadWrite
|
|
|
|
Op1Access: Read
|
2019-09-01 17:07:36 +00:00
|
|
|
Op0: r64_or_mem
|
2019-08-22 19:44:40 +00:00
|
|
|
Op1: imm32sex64
|
2018-09-07 19:09:29 +00:00
|
|
|
RSP:ReadWrite
|
|
|
|
00007FFAC46ACDC1 mov rax,[7FFAC47524E0h]
|
2019-08-22 19:44:40 +00:00
|
|
|
OpCode: REX.W 8B /r
|
2019-09-12 21:06:08 +00:00
|
|
|
Instruction: MOV r64, r/m64
|
2018-09-07 19:09:29 +00:00
|
|
|
Encoding: Legacy
|
2019-05-22 16:57:52 +00:00
|
|
|
Mnemonic: Mov
|
2019-07-18 19:58:13 +00:00
|
|
|
Code: Mov_r64_rm64
|
2019-02-06 18:08:19 +00:00
|
|
|
CpuidFeature: X64
|
2018-09-07 19:09:29 +00:00
|
|
|
FlowControl: Next
|
2019-02-03 15:25:26 +00:00
|
|
|
Displacement offset = 3, size = 4
|
2019-02-12 21:02:42 +00:00
|
|
|
Memory size: 8
|
2018-09-07 19:09:29 +00:00
|
|
|
Op0Access: Write
|
|
|
|
Op1Access: Read
|
2019-08-22 19:44:40 +00:00
|
|
|
Op0: r64_reg
|
2019-09-01 17:07:36 +00:00
|
|
|
Op1: r64_or_mem
|
2018-09-07 19:09:29 +00:00
|
|
|
RAX:Write
|
2018-10-26 20:21:37 +00:00
|
|
|
[DS:0x7FFAC47524E0;UInt64;Read]
|
2018-09-07 19:09:29 +00:00
|
|
|
00007FFAC46ACDC8 xor rax,rsp
|
2019-08-22 19:44:40 +00:00
|
|
|
OpCode: REX.W 33 /r
|
2019-09-12 21:06:08 +00:00
|
|
|
Instruction: XOR r64, r/m64
|
2018-09-07 19:09:29 +00:00
|
|
|
Encoding: Legacy
|
2019-05-22 16:57:52 +00:00
|
|
|
Mnemonic: Xor
|
2019-07-18 19:58:13 +00:00
|
|
|
Code: Xor_r64_rm64
|
2019-02-06 18:08:19 +00:00
|
|
|
CpuidFeature: X64
|
2018-09-07 19:09:29 +00:00
|
|
|
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
|
2019-08-22 19:44:40 +00:00
|
|
|
Op0: r64_reg
|
2019-09-01 17:07:36 +00:00
|
|
|
Op1: r64_or_mem
|
2018-09-07 19:09:29 +00:00
|
|
|
RAX:ReadWrite
|
|
|
|
RSP:Read
|
|
|
|
00007FFAC46ACDCB mov [rbp+0F0h],rax
|
2019-08-22 19:44:40 +00:00
|
|
|
OpCode: REX.W 89 /r
|
2019-09-12 21:06:08 +00:00
|
|
|
Instruction: MOV r/m64, r64
|
2018-09-07 19:09:29 +00:00
|
|
|
Encoding: Legacy
|
2019-05-22 16:57:52 +00:00
|
|
|
Mnemonic: Mov
|
2019-07-18 19:58:13 +00:00
|
|
|
Code: Mov_rm64_r64
|
2019-02-06 18:08:19 +00:00
|
|
|
CpuidFeature: X64
|
2018-09-07 19:09:29 +00:00
|
|
|
FlowControl: Next
|
2019-02-03 15:25:26 +00:00
|
|
|
Displacement offset = 3, size = 4
|
2019-02-12 21:02:42 +00:00
|
|
|
Memory size: 8
|
2018-09-07 19:09:29 +00:00
|
|
|
Op0Access: Write
|
|
|
|
Op1Access: Read
|
2019-09-01 17:07:36 +00:00
|
|
|
Op0: r64_or_mem
|
2019-08-22 19:44:40 +00:00
|
|
|
Op1: r64_reg
|
2018-09-07 19:09:29 +00:00
|
|
|
RBP:Read
|
|
|
|
RAX:Read
|
2018-10-26 20:21:37 +00:00
|
|
|
[SS:RBP+0xF0;UInt64;Write]
|
2018-09-07 19:09:29 +00:00
|
|
|
00007FFAC46ACDD2 mov r8,[7FFAC474F208h]
|
2019-08-22 19:44:40 +00:00
|
|
|
OpCode: REX.W 8B /r
|
2019-09-12 21:06:08 +00:00
|
|
|
Instruction: MOV r64, r/m64
|
2018-09-07 19:09:29 +00:00
|
|
|
Encoding: Legacy
|
2019-05-22 16:57:52 +00:00
|
|
|
Mnemonic: Mov
|
2019-07-18 19:58:13 +00:00
|
|
|
Code: Mov_r64_rm64
|
2019-02-06 18:08:19 +00:00
|
|
|
CpuidFeature: X64
|
2018-09-07 19:09:29 +00:00
|
|
|
FlowControl: Next
|
2019-02-03 15:25:26 +00:00
|
|
|
Displacement offset = 3, size = 4
|
2019-02-12 21:02:42 +00:00
|
|
|
Memory size: 8
|
2018-09-07 19:09:29 +00:00
|
|
|
Op0Access: Write
|
|
|
|
Op1Access: Read
|
2019-08-22 19:44:40 +00:00
|
|
|
Op0: r64_reg
|
2019-09-01 17:07:36 +00:00
|
|
|
Op1: r64_or_mem
|
2018-09-07 19:09:29 +00:00
|
|
|
R8:Write
|
2018-10-26 20:21:37 +00:00
|
|
|
[DS:0x7FFAC474F208;UInt64;Read]
|
2018-09-07 19:09:29 +00:00
|
|
|
00007FFAC46ACDD9 lea rax,[7FFAC46F4A58h]
|
2019-08-22 19:44:40 +00:00
|
|
|
OpCode: REX.W 8D /r
|
2019-09-12 21:06:08 +00:00
|
|
|
Instruction: LEA r64, m
|
2018-09-07 19:09:29 +00:00
|
|
|
Encoding: Legacy
|
2019-05-22 16:57:52 +00:00
|
|
|
Mnemonic: Lea
|
2019-07-18 19:58:13 +00:00
|
|
|
Code: Lea_r64_m
|
2019-02-06 18:08:19 +00:00
|
|
|
CpuidFeature: X64
|
2018-09-07 19:09:29 +00:00
|
|
|
FlowControl: Next
|
2019-02-03 15:25:26 +00:00
|
|
|
Displacement offset = 3, size = 4
|
2018-09-07 19:09:29 +00:00
|
|
|
Op0Access: Write
|
|
|
|
Op1Access: NoMemAccess
|
2019-08-22 19:44:40 +00:00
|
|
|
Op0: r64_reg
|
|
|
|
Op1: mem
|
2018-09-07 19:09:29 +00:00
|
|
|
RAX:Write
|
|
|
|
00007FFAC46ACDE0 xor edi,edi
|
2019-08-22 19:44:40 +00:00
|
|
|
OpCode: o32 33 /r
|
2019-09-12 21:06:08 +00:00
|
|
|
Instruction: XOR r32, r/m32
|
2018-09-07 19:09:29 +00:00
|
|
|
Encoding: Legacy
|
2019-05-22 16:57:52 +00:00
|
|
|
Mnemonic: Xor
|
2019-07-18 19:58:13 +00:00
|
|
|
Code: Xor_r32_rm32
|
2019-02-06 18:08:19 +00:00
|
|
|
CpuidFeature: INTEL386
|
2018-09-07 19:09:29 +00:00
|
|
|
FlowControl: Next
|
2018-10-24 19:23:59 +00:00
|
|
|
RFLAGS Cleared: OF, SF, CF
|
|
|
|
RFLAGS Set: ZF, PF
|
2018-09-07 19:09:29 +00:00
|
|
|
RFLAGS Undefined: AF
|
|
|
|
RFLAGS Modified: OF, SF, ZF, AF, CF, PF
|
2018-10-24 19:23:59 +00:00
|
|
|
Op0Access: Write
|
|
|
|
Op1Access: None
|
2019-08-22 19:44:40 +00:00
|
|
|
Op0: r32_reg
|
2019-09-01 17:07:36 +00:00
|
|
|
Op1: r32_or_mem
|
2018-09-07 19:09:29 +00:00
|
|
|
RDI:Write
|
|
|
|
*/
|
|
|
|
static void InstructionInfoExample() {
|
|
|
|
var codeReader = new ByteArrayCodeReader(exampleCode);
|
|
|
|
var decoder = Decoder.Create(exampleCodeBitness, codeReader);
|
2019-02-03 15:25:49 +00:00
|
|
|
decoder.IP = exampleCodeRIP;
|
|
|
|
ulong endRip = decoder.IP + (uint)exampleCode.Length;
|
2018-09-07 19:09:29 +00:00
|
|
|
|
2020-01-05 22:17:27 +00:00
|
|
|
// Use a factory to create the instruction info if you need register and
|
|
|
|
// memory usage. If it's something else, eg. encoding, flags, etc, there
|
|
|
|
// are properties on Instruction that can be used instead.
|
2018-09-07 19:09:29 +00:00
|
|
|
var instrInfoFactory = new InstructionInfoFactory();
|
2019-02-03 15:25:49 +00:00
|
|
|
while (decoder.IP < endRip) {
|
2018-09-07 19:09:29 +00:00
|
|
|
decoder.Decode(out var instr);
|
|
|
|
|
2019-02-03 15:25:26 +00:00
|
|
|
// Gets offsets in the instruction of the displacement and immediates and their sizes.
|
|
|
|
// This can be useful if there are relocations in the binary. The encoder has a similar
|
|
|
|
// method. This method must be called after Decode() and you must pass in the last
|
|
|
|
// instruction Decode() returned.
|
2019-05-23 16:28:54 +00:00
|
|
|
var offsets = decoder.GetConstantOffsets(instr);
|
2019-02-03 15:25:26 +00:00
|
|
|
|
2018-09-07 19:09:29 +00:00
|
|
|
// A formatter is recommended since this ToString() method defaults to masm syntax,
|
|
|
|
// uses default options, and allocates every single time it's called.
|
|
|
|
var disasmStr = instr.ToString();
|
2019-02-03 15:25:49 +00:00
|
|
|
Console.WriteLine($"{instr.IP:X16} {disasmStr}");
|
2018-09-07 19:09:29 +00:00
|
|
|
|
2019-08-22 19:45:33 +00:00
|
|
|
var opCode = instr.OpCode;
|
2019-05-21 20:49:45 +00:00
|
|
|
var info = instrInfoFactory.GetInfo(instr);
|
2018-09-07 19:09:29 +00:00
|
|
|
const string tab = " ";
|
2019-09-12 21:06:08 +00:00
|
|
|
Console.WriteLine($"{tab}OpCode: {opCode.ToOpCodeString()}");
|
|
|
|
Console.WriteLine($"{tab}Instruction: {opCode.ToInstructionString()}");
|
2019-02-13 21:51:34 +00:00
|
|
|
Console.WriteLine($"{tab}Encoding: {instr.Encoding}");
|
2019-05-22 16:57:52 +00:00
|
|
|
Console.WriteLine($"{tab}Mnemonic: {instr.Mnemonic}");
|
2019-07-18 19:58:13 +00:00
|
|
|
Console.WriteLine($"{tab}Code: {instr.Code}");
|
2019-02-13 21:51:34 +00:00
|
|
|
Console.WriteLine($"{tab}CpuidFeature: {string.Join(" and ", instr.CpuidFeatures)}");
|
|
|
|
Console.WriteLine($"{tab}FlowControl: {instr.FlowControl}");
|
2019-02-03 15:25:26 +00:00
|
|
|
if (offsets.HasDisplacement)
|
|
|
|
Console.WriteLine($"{tab}Displacement offset = {offsets.DisplacementOffset}, size = {offsets.DisplacementSize}");
|
|
|
|
if (offsets.HasImmediate)
|
|
|
|
Console.WriteLine($"{tab}Immediate offset = {offsets.ImmediateOffset}, size = {offsets.ImmediateSize}");
|
|
|
|
if (offsets.HasImmediate2)
|
|
|
|
Console.WriteLine($"{tab}Immediate #2 offset = {offsets.ImmediateOffset2}, size = {offsets.ImmediateSize2}");
|
2019-02-16 16:34:02 +00:00
|
|
|
if (instr.IsStackInstruction)
|
2018-09-07 19:09:29 +00:00
|
|
|
Console.WriteLine($"{tab}SP Increment: {instr.StackPointerIncrement}");
|
2019-09-18 19:44:01 +00:00
|
|
|
if (instr.ConditionCode != ConditionCode.None)
|
|
|
|
Console.WriteLine($"{tab}Condition code: {instr.ConditionCode}");
|
2018-09-07 19:09:29 +00:00
|
|
|
if (instr.RflagsRead != RflagsBits.None)
|
|
|
|
Console.WriteLine($"{tab}RFLAGS Read: {instr.RflagsRead}");
|
|
|
|
if (instr.RflagsWritten != RflagsBits.None)
|
|
|
|
Console.WriteLine($"{tab}RFLAGS Written: {instr.RflagsWritten}");
|
|
|
|
if (instr.RflagsCleared != RflagsBits.None)
|
|
|
|
Console.WriteLine($"{tab}RFLAGS Cleared: {instr.RflagsCleared}");
|
|
|
|
if (instr.RflagsSet != RflagsBits.None)
|
|
|
|
Console.WriteLine($"{tab}RFLAGS Set: {instr.RflagsSet}");
|
|
|
|
if (instr.RflagsUndefined != RflagsBits.None)
|
|
|
|
Console.WriteLine($"{tab}RFLAGS Undefined: {instr.RflagsUndefined}");
|
|
|
|
if (instr.RflagsModified != RflagsBits.None)
|
|
|
|
Console.WriteLine($"{tab}RFLAGS Modified: {instr.RflagsModified}");
|
2019-02-18 19:46:34 +00:00
|
|
|
for (int i = 0; i < instr.OpCount; i++) {
|
|
|
|
var opKind = instr.GetOpKind(i);
|
|
|
|
if (opKind == OpKind.Memory || opKind == OpKind.Memory64) {
|
|
|
|
int size = instr.MemorySize.GetSize();
|
|
|
|
if (size != 0)
|
|
|
|
Console.WriteLine($"{tab}Memory size: {size}");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (int i = 0; i < instr.OpCount; i++)
|
2018-09-07 19:09:29 +00:00
|
|
|
Console.WriteLine($"{tab}Op{i}Access: {info.GetOpAccess(i)}");
|
2019-08-22 19:45:33 +00:00
|
|
|
for (int i = 0; i < opCode.OpCount; i++)
|
|
|
|
Console.WriteLine($"{tab}Op{i}: {opCode.GetOpKind(i)}");
|
2018-09-07 19:09:29 +00:00
|
|
|
// The returned iterator is a struct, nothing is allocated unless you box it
|
|
|
|
foreach (var regInfo in info.GetUsedRegisters())
|
|
|
|
Console.WriteLine($"{tab}{regInfo.ToString()}");
|
|
|
|
foreach (var memInfo in info.GetUsedMemory())
|
|
|
|
Console.WriteLine($"{tab}{memInfo.ToString()}");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
2018-09-05 23:29:23 +00:00
|
|
|
|
2020-01-18 08:26:20 +00:00
|
|
|
## Assembler
|
|
|
|
|
2020-01-24 08:04:13 +00:00
|
|
|
Iced provide a high level assembler by providing a friendly syntax close to what a regular assembler could provide:
|
2020-01-18 08:26:20 +00:00
|
|
|
|
|
|
|
```c#
|
|
|
|
using Iced.Intel;
|
2020-01-24 08:04:13 +00:00
|
|
|
// The following using static allows to import assembler registers
|
|
|
|
// e.g `eax` directly accessible as variables
|
|
|
|
using static Iced.Intel.AssemblerRegisters;
|
2020-01-18 08:26:20 +00:00
|
|
|
|
|
|
|
public static class AssemblerPlay
|
|
|
|
{
|
|
|
|
public static MemoryStream GenerateCode()
|
|
|
|
{
|
2020-01-24 08:04:13 +00:00
|
|
|
var c = Assembler.Create(64);
|
2020-01-18 08:26:20 +00:00
|
|
|
|
|
|
|
c.push(r15);
|
|
|
|
c.mov(r15, rsi);
|
|
|
|
c.mov(rax, __[rdi]);
|
|
|
|
c.add(rax, r15);
|
|
|
|
c.pop(r15);
|
|
|
|
c.ret();
|
|
|
|
|
2020-01-24 08:04:13 +00:00
|
|
|
var stream = new MemoryStream();
|
|
|
|
var writer = new StreamCodeWriter(stream)
|
|
|
|
c.Encode(writer);
|
2020-01-18 08:26:20 +00:00
|
|
|
|
|
|
|
return stream;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
The assembler supports the entire instruction set available through the `Encoder` class.
|
|
|
|
|
|
|
|
- For prefixes (e.g `rep`, `xacquire`) they are directly accessible on the `Assembler`. For example: `c.rep.movsd()`.
|
|
|
|
- AVX512+ k1z/sae/rounding flags can be set directly on registers: `c.vaddpd(zmm1.k3.z, zmm2, zmm3.rz_sae)`
|
|
|
|
- AVX512+ broadcasting can be specified via e.g `__dword_bcst`: `c.vunpcklps(xmm2.k5.z, xmm6, __dword_bcst[rax])`
|
|
|
|
|
2020-01-24 08:04:13 +00:00
|
|
|
Labels can be created via `Assembler.CreateLabel`, placed just before an instruction via `Assembler.Label` and referenced by branch instructions:
|
2020-01-18 08:26:20 +00:00
|
|
|
|
|
|
|
```c#
|
|
|
|
using Iced.Intel;
|
2020-01-24 08:04:13 +00:00
|
|
|
// The following using static allows to import assembler registers
|
|
|
|
// e.g `eax` directly accessible as variables
|
|
|
|
using static Iced.Intel.AssemblerRegisters;
|
2020-01-18 08:26:20 +00:00
|
|
|
|
|
|
|
public static class AssemblerPlay
|
|
|
|
{
|
|
|
|
public static MemoryStream GenerateCode()
|
|
|
|
{
|
2020-01-24 08:04:13 +00:00
|
|
|
var c = Assembler.Create(64);
|
2020-01-18 08:26:20 +00:00
|
|
|
|
2020-01-24 08:04:13 +00:00
|
|
|
// Create a label
|
2020-01-18 08:26:20 +00:00
|
|
|
var label1 = c.CreateLabel();
|
|
|
|
|
|
|
|
c.push(r15);
|
|
|
|
c.add(rax, r15);
|
|
|
|
c.jne(label1); // Jump to Label1
|
|
|
|
|
|
|
|
c.inc(rax);
|
|
|
|
|
|
|
|
// Emit label1:
|
2020-01-24 08:04:13 +00:00
|
|
|
c.Label(ref label1);
|
2020-01-18 08:26:20 +00:00
|
|
|
c.pop(r15);
|
|
|
|
c.ret();
|
|
|
|
|
2020-01-24 08:04:13 +00:00
|
|
|
var stream = new MemoryStream();
|
|
|
|
var writer = new StreamCodeWriter(stream)
|
|
|
|
c.Encode(writer);
|
2020-01-18 08:26:20 +00:00
|
|
|
|
|
|
|
return stream;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2018-09-07 19:33:05 +00:00
|
|
|
# License
|
2018-09-05 23:29:23 +00:00
|
|
|
|
2019-01-01 12:40:59 +00:00
|
|
|
MIT
|
2018-09-21 19:30:08 +00:00
|
|
|
|
|
|
|
|
2018-12-26 15:00:56 +00:00
|
|
|
# Icon
|
2018-09-21 19:30:08 +00:00
|
|
|
|
|
|
|
Logo `processor` by [Creative Stall](https://thenounproject.com/creativestall/) from the Noun Project
|