Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions SharpDisasm.Tests/Decode64bitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@ public void Disp64Test()
//0000000000000018 4c03849800000080 add r8, [rax+rbx*4-0x80000000]
//0000000000000020 48a1000000000080 mov rax, [0x800000000000]

Instruction insn = null;

insn = disasm.NextInstruction();
var insn = disasm.NextInstruction();
Assert.AreEqual("mov ax, [eax-0x10]", insn.ToString());

insn = disasm.NextInstruction();
Expand Down Expand Up @@ -61,9 +60,8 @@ public void NegativeRIPAddress()
0xFF, 0x15, 0xF7, 0xFF, 0xFF, 0xFF, // call qword [rip-0x9]
}, ArchitectureMode.x86_64);

Instruction insn = null;

insn = disasm.NextInstruction();
var insn = disasm.NextInstruction();
Assert.AreEqual("mov rax, [rip-0x9]", insn.ToString());

insn = disasm.NextInstruction();
Expand Down
4 changes: 2 additions & 2 deletions SharpDisasm.Tests/DisassemblerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public void DisassembleBytesDecoded()
0x00, 0x67, // invalid
}, ArchitectureMode.x86_32, 0, false);

foreach (SharpDisasm.Instruction instruction in disasm.Disassemble())
foreach (SharpDisasm.IInstruction instruction in disasm.Disassemble())
{
Assert.IsTrue(instruction.Length > 0);
}
Expand Down Expand Up @@ -55,7 +55,7 @@ where insn.Length > 5
select insn).First().ToString());


foreach (SharpDisasm.Instruction instruction in results)
foreach (SharpDisasm.IInstruction instruction in results)
{
Assert.IsFalse(instruction.Error);
Assert.IsTrue(instruction.Length > 0);
Expand Down
70 changes: 70 additions & 0 deletions SharpDisasm.nuspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>SharpDisasm</id>
<version>$version$</version>
<title>SharpDisasm</title>
<authors>Justin Stenning</authors>
<owners>Justin Stenning</owners>
<requireLicenseAcceptance>true</requireLicenseAcceptance>
<licenseUrl>https://github.com/spazzarama/SharpDisasm/blob/master/LICENSE.md</licenseUrl>
<projectUrl>https://github.com/spazzarama/SharpDisasm</projectUrl>
<description>SharpDisam is a disassembler written in C# able to decode the x86 and x86-64 instruction set architectures.

It features:
* a full C# port of the libudis86 C library
* a set of simple C# classes wrapping the udis86 API
* support for x86 16-bit, 32-bit and 64-bit instruction set architectures
* support for outputting in Intel and AT&amp;T syntax
* support for all x86 and x86-64 (AMD64) General purpose and System instructions.
* support for the following ISA extensions:
- MMX, FPU (x87), AMD 3DNow
- SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AES,
- AMD-V, INTEL-VMX, SMX
* instructions are defined in an XML document that is consumed by a T4 template to generate opcode tables for performance.
* the XML instructions document is exactly the same as that found within the udis86 project. The generated C# opcode tables is also very similar except in syntax to those generated by the Python script in the libudis86 C-library.
* able to decode more than 4 million 64-bit instructions per second (with an average instruction size of 7-bytes)

Usage: http://sharpdisasm.codeplex.com/documentation</description>
<summary>A C# port of the udis86 x86 disassembler.</summary>
<releaseNotes>$version$
1. Added ability to resolve RIP relative addresses in ASM outputting
2. 64-bit definition fixes for a number of instructions
3. Support for .NET Standard target

1. Added support for offset into IAssemblyCode
2. Fix exceptions on invalid instructions (contributed by ste-art)
3. Fix ATT syntax for enter/bound mnemonics being dropped
4. Translator internals refactored (better code reuse)
5. A few Debug.Asserts replaced with exceptions for Translator and Instruction.ToString
1.1.5
1. Use of unsafe replaced with an assembly code reader interface
1.0.2
1. Full port of udis86 C-library into C#
2. Wrapper class Disassembler for those not familiar with the libudis86 C-library</releaseNotes>
<copyright>Copyright (c) 2015 Justin Stenning</copyright>
<tags>ASM disassembler x86 x86-64 instructions opcodes decoder AMD Intel</tags>
<dependencies>
</dependencies>
</metadata>
<files>
<file src=".\bin\Release\Net45\SharpDisasm.dll" target="lib\netstandard2.0" />
<file src=".\bin\Release\Net45\SharpDisasm.pdb" target="lib\netstandard2.0" />
<file src=".\bin\Release\Net45\SharpDisasm.xml" target="lib\netstandard2.0" />
<file src=".\bin\Release\Net45\SharpDisasm.dll" target="lib\net45" />
<file src=".\bin\Release\Net45\SharpDisasm.pdb" target="lib\net45" />
<file src=".\bin\Release\Net45\SharpDisasm.xml" target="lib\net45" />
<file src=".\bin\Release\Net4\SharpDisasm.dll" target="lib\net40" />
<file src=".\bin\Release\Net4\SharpDisasm.pdb" target="lib\net40" />
<file src=".\bin\Release\Net4\SharpDisasm.xml" target="lib\net40" />
<file src=".\bin\Release\Net35\SharpDisasm.dll" target="lib\net35" />
<file src=".\bin\Release\Net35\SharpDisasm.pdb" target="lib\net35" />
<file src=".\bin\Release\Net35\SharpDisasm.xml" target="lib\net35" />
<file src=".\SharpDisasm\*.cs" target="src" />
<file src=".\SharpDisasm\Translators\*.cs" target="src\Translators" />
<file src=".\SharpDisasm\udis86\*.cs" target="src\udis86" />
<file src="**\*.tt" target="src" />
<file src="**\optable.xml" target="src" />
<file src="**\optable.xsl" target="src" />
</files>
</package>
71 changes: 54 additions & 17 deletions SharpDisasm/Disassembler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
using System.Text;

using SharpDisasm.Helpers;
using SharpDisasm.Factory;

namespace SharpDisasm
{
Expand Down Expand Up @@ -86,6 +87,8 @@ public sealed class Disassembler : IDisposable
/// </summary>
private Udis86.ud _u = new Udis86.ud();

private readonly IInstructionFactory _instructionFactory;

#endregion

/// <summary>
Expand All @@ -98,39 +101,61 @@ public sealed class Disassembler : IDisposable
/// </summary>
public int BytesDecoded { get; private set; }

/// <summary>
/// Initializes a new instance of the <see cref="Disassembler" /> class.

/// <summary>Initializes a new instance of the <see cref="Disassembler" /> class.
/// </summary>
/// <param name="code">The code.</param>
/// <param name="architecture">The architecture.</param>
/// <param name="offset">The offset.</param>
/// <param name="address">The address.</param>
/// <param name="copyBinaryToInstruction">if set to <c>true</c> [copy binary to instruction].</param>
/// <param name="vendor">The vendor.</param>
public Disassembler(IAssemblyCode code, ArchitectureMode architecture, ulong offset = 0x0, ulong address = 0x0, bool copyBinaryToInstruction = false, Vendor vendor = Vendor.Any)
/// <param name="instructionFactory">instruction factory, when null
/// <see cref="Instruction"/> class is created</param>
public Disassembler(IAssemblyCode code, ArchitectureMode architecture,
ulong offset = 0x0, ulong address = 0x0,
bool copyBinaryToInstruction = false, Vendor vendor = Vendor.Any,
IInstructionFactory instructionFactory = null)
{
this.Code = code;

this.Architecture = architecture;
this.Address = address;
this.CopyBinaryToInstruction = copyBinaryToInstruction;
this.Vendor = vendor;
this.Offset = offset;
if (instructionFactory == null)
{
_instructionFactory = new InstructionFactory();
}
else
{
_instructionFactory = instructionFactory;
}

InitUdis86();
}

/// <summary>
/// Prepares a new disassembler instance for the code provided. The instructions can then be disassembled with a call to <see cref="Disassemble" />. The base address used to resolve relative addresses should be provided in <paramref name="address" />.
/// Prepares a new disassembler instance for the code provided.The instructions
/// can then be disassembled with a call to <see cref="Disassemble" />.
/// The base address used to resolve relative addresses should be provided
/// in <paramref name="address" />.
/// </summary>
/// <param name="code">The code to be disassembled</param>
/// <param name="architecture">The target x86 instruction set architecture of the code (e.g. 64-bit, 32-bit or 16-bit).</param>
/// <param name="address">The address of the first byte of code. This value is used to resolve relative addresses into absolute addresses while disassembling.</param>
/// <param name="copyBinaryToInstruction">Keeps a copy of the binary code for the instruction. This will increase the memory usage for each instruction. This is necessary if planning on using the <see cref="Translators.Translator.IncludeBinary" /> option.</param>
/// <param name="vendor">What vendor instructions to support during disassembly, default is Any. Other options are AMD or Intel.</param>
/// <param name="offset">The offset.</param>
public Disassembler(byte[] code, ArchitectureMode architecture, ulong address = 0x0, bool copyBinaryToInstruction = false, Vendor vendor = Vendor.Any, ulong offset = 0)
: this(new AssemblyCodeArray(code), architecture, offset, address, copyBinaryToInstruction, vendor)
/// <param name="instructionFactory">instruction factory, when null
/// <see cref="Instruction"/> class is created</param>
public Disassembler(byte[] code, ArchitectureMode architecture,
ulong address = 0x0, bool copyBinaryToInstruction = false,
Vendor vendor = Vendor.Any, ulong offset = 0,
IInstructionFactory instructionFactory = null)
: this(new AssemblyCodeArray(code),architecture, offset,
address, copyBinaryToInstruction,
vendor,instructionFactory)
{
}

Expand All @@ -139,12 +164,24 @@ public Disassembler(byte[] code, ArchitectureMode architecture, ulong address =
/// </summary>
/// <param name="codePtr">A pointer to memory to be disassembled.</param>
/// <param name="codeLength">The maximum length to be disassembled.</param>
/// <param name="architecture">The architecture of the code (e.g. 64-bit, 32-bit or 16-bit).</param>
/// <param name="address">The address of the first byte of code. This value is used to resolve relative addresses into absolute addresses while disassembling.</param>
/// <param name="copyBinaryToInstruction">Keeps a copy of the binary code for the instruction. This will increase the memory usage for each instruction. This is necessary if planning on using the <see cref="Translators.Translator.IncludeBinary"/> option.</param>
/// <param name="vendor">What vendors to support for disassembly, default is Any. Other options are AMD or Intel.</param>
public Disassembler(IntPtr codePtr, int codeLength, ArchitectureMode architecture, ulong address = 0x0, bool copyBinaryToInstruction = false, Vendor vendor = Vendor.Any)
: this(new AssemblyCodeMemory(codePtr, codeLength), architecture, 0, address, copyBinaryToInstruction, vendor)
/// <param name="architecture">The architecture of the code
///
/// (e.g. 64-bit, 32-bit or 16-bit).</param>
/// <param name="address">The address of the first byte of code.
/// This value is used to resolve relative addresses into absolute addresses while disassembling.</param>
/// <param name="copyBinaryToInstruction">Keeps a copy of the binary code for the
/// instruction. This will increase the memory usage for each instruction.
/// This is necessary if planning on using the
/// <see cref="Translators.Translator.IncludeBinary"/> option.</param>
/// <param name="vendor">What vendors to support for disassembly, default is Any.
/// Other options are AMD or Intel.</param>
/// <param name="instructionFactory">instruction factory, when null
/// <see cref="Instruction"/> class is created</param>
public Disassembler(IntPtr codePtr, int codeLength, ArchitectureMode architecture,
ulong address = 0x0, bool copyBinaryToInstruction = false,
Vendor vendor = Vendor.Any,IInstructionFactory instructionFactory = null)
: this(new AssemblyCodeMemory(codePtr, codeLength), architecture,
0, address, copyBinaryToInstruction, vendor,instructionFactory)
{
if (codePtr == IntPtr.Zero)
throw new ArgumentOutOfRangeException("codePtr");
Expand Down Expand Up @@ -175,10 +212,10 @@ private void InitUdis86()
/// Disassemble instructions and yield the result. Breaking out of the enumerator will prevent further instructions being disassembled.
/// </summary>
/// <returns>An IEnumerable collection of disassembled instructions</returns>
public IEnumerable<Instruction> Disassemble()
public IEnumerable<IInstruction> Disassemble()
{
Reset();
Instruction instruction = null;
IInstruction instruction = null;
while ((instruction = NextInstruction()) != null)
{
yield return instruction;
Expand All @@ -199,12 +236,12 @@ public void Reset()
/// Decodes a single instruction and increments buffer position.
/// </summary>
/// <returns></returns>
public Instruction NextInstruction()
public IInstruction NextInstruction()
{
int length = 0;
if ((length = Udis86.udis86.ud_disassemble(ref _u)) > 0)
{
var instruction = new Instruction(ref _u, CopyBinaryToInstruction);
var instruction = _instructionFactory.Create(ref _u, CopyBinaryToInstruction);
if (!instruction.Error)
{
BytesDecoded += length;
Expand Down
22 changes: 22 additions & 0 deletions SharpDisasm/Factory/IInstructionFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace SharpDisasm.Factory
{
/// <summary>
/// interface for instruction factory
/// </summary>
public interface IInstructionFactory
{
/// <summary>
/// The create method of the factory
/// </summary>
/// <param name="u">the internal instruction parser</param>
/// <param name="keepBinary">To copy the binary bytes to instruction</param>
/// <returns>Instructuion instance</returns>
IInstruction Create(ref Udis86.ud u, bool keepBinary);
}
}
25 changes: 25 additions & 0 deletions SharpDisasm/Factory/InstructionFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace SharpDisasm.Factory
{
/// <summary>
/// Instruction factory
/// </summary>
public class InstructionFactory : IInstructionFactory
{
/// <summary>
/// The create method of the factory
/// </summary>
/// <param name="u">the internal instruction parser</param>
/// <param name="keepBinary">To copy the binary bytes to instruction</param>
/// <returns>Instructuion instance</returns>
public IInstruction Create(ref Udis86.ud u, bool keepBinary)
{
return new Instruction( ref u, keepBinary);
}
}
}
54 changes: 54 additions & 0 deletions SharpDisasm/IInstruction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using SharpDisasm.Udis86;

namespace SharpDisasm
{
/// <summary>
/// instruction interface
/// </summary>
public interface IInstruction
{
/// <summary>
/// Instruction Offset
/// </summary>
byte[] Bytes { get; }

/// <summary>
/// Indicates whether the instruction was successfully decoded.
/// </summary>
bool Error { get; }

/// <summary>
/// The reason an instruction was not successfully decoded.
/// </summary>
string ErrorMessage { get; }

/// <summary>
/// The length of the instruction in bytes
/// </summary>
int Length { get; }

/// <summary>
/// Mnemonic
/// </summary>
ud_mnemonic_code Mnemonic { get; }

/// <summary>
/// Instruction offset
/// </summary>
ulong Offset { get; }

/// <summary>
/// Instruction Operends (maximum 3)
/// </summary>
Operand[] Operands { get; }

/// <summary>
/// Program counter
/// </summary>
ulong PC { get; }




}
}
Loading