Skip to content
forked from blurt/X86.Interop

.NET library to write/patch X86 asm at runtime and marshal complex unmanaged structures.

Notifications You must be signed in to change notification settings

inrg/X86.Interop

 
 

Repository files navigation

X86.Interop

A .NET library to:

  • write X86 asm to memory
  • patch native dlls at runtime, intercept execution
  • create wrappers for complex unmanaged structures
  • support FastCall delegates

Built on top of Managed.X86 project (http://code.google.com/p/managed-x86/) This is only compatible with 32bit applications, X86_64 not supported.

Available on NuGet. Supports net40, net45 and higher

Example: Writing to memory

// Write a no op instruction at memory address 0xFFFF8000
X86Asm.At(0xFFFF8000).Write(writer => writer.Nop());
// or use the equivalent raw bytes
X86Asm.At(0xFFFF8000).Write(new byte[] { 0x90 });


// Write a new block of asm, managed by our application
var asm = X86Asm.Create(writer =>
{
	writer.Add32(X86Register32.EAX, 1);
	writer.Cmp32(X86Register32.EAX, 1);
});
Console.WriteLine($"Asm block allocated at {asm.Address}");
asm.Dispose(); // free asm block

Example: Patching native code

At runtime, patch a native dll that is loaded in memory. An offset is specified, the patch is applied relative to the base address of the loaded dll. This allows us to intercept or modify execution of the application.

// Patch the native dll with a NO OP
var patch = new Patch("myNativeDll.dll", 0x4FF2, writer => writer.Nop())

// Patch the native dll with a CALL instruction to execute the (managed) block of asm generated by the delegate:
var patch = new CallPatch("myNativeDll.dll", 0x4FF2,
	writer =>
	{
		writer.PushAd(); //push all registers to stack
		// TODO: write intercept asm .. don't mess up the stack!
		// we can intercept execution here by invoking a .NET delegate:
		//		writer.Call( Marshal.GetFunctionPointerForDelegate(..) )
		// we can also pass arguments to the .NET delegate by pushing them onto the stack
		// see https://en.wikipedia.org/wiki/X86_calling_conventions for more info
		writer.PopAd(); // restore registers
	});

// or specify exact address:
var patch = new JumpPatch(0x12341234, writer => {..}) // applies a JMP patch

patch.Install();   // installs the patch
patch.Uninstall(); // swaps back / restores the original asm
patch.Dispose();   // Uninstall and dispose managed asm block

Example: Marshalling complex structures

Traditional marshalling requires you to marshal over the entire unmanaged structure. There are also limitations with marshalling pointers to other structures.

Using the base class X86.Interop.Structure, we can create c# wrappers for the unmanaged structures. The class is opaque -- values are marshalled over as needed.


public class MyStructure : X86.Interop.Structure
{
	// constructor: create a wrapper for an unmanaged structure at a particular location in memory
	public MyStructure(IntPtr baseAddress) : base(baseAddress) { }

	// constructor: allocate unmanaged memory for a new instance of MyStructure
	public MyStructure() : base() { }
	
	// you must specify the size of the unmanaged structure, so that the library
	// knows how much memory to allocate and how to iterate over a contiguous array
	public override int GetSize() => 0x14;

	// WORD at 0x00
	public UInt16 My16BitInteger
	{
		get { return ReadUInt16(0x00); } // read 16 bit integer at offset 0x00
		set { WriteUInt16(0x00, value); }
	}

	// DWORD at 0x02 -- pointer to NestedStructure
	// a nice pattern emerges to dynamically create a reference to a nested unmanaged structure
	public NestedStructure NestedStruct
	{
		get { return TryReadIntPtr(0x02, out IntPtr nestedStructPtr) ? new NestedStruct(nestedStructPtr) : null; }
		set { WriteStructPointer(0x02, value); }
	}

	// DWORD at 0x06 -- pointer to an array of structures stored contiguously in memory
	public Array<OtherStruct> Items
	{
		get { return TryReadIntPtr(0x06, out IntPtr arrayPtr) ? new Array<OtherStruct>(arrayPtr) { Length = ItemsCount } : null; }
		set { WriteStructPointer(0x06, value); }
	}

	// DWORD at 0x10 -- length of above array
	public UInt32 ItemsCount
	{
		get { return ReadUInt32(0x10); }
		set { WriteUInt32(0x10, value); }
	}

	// also have type PointerArray<T> for an array-of-pointers that point to structures of type T

}

About

.NET library to write/patch X86 asm at runtime and marshal complex unmanaged structures.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages

  • C# 100.0%