Skip to content

Instantly share code, notes, and snippets.

@apkd
Created January 26, 2019 14:47
Show Gist options
  • Save apkd/145e8416ab230b712b78a572165cca43 to your computer and use it in GitHub Desktop.
Save apkd/145e8416ab230b712b78a572165cca43 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Reflection;
namespace CommunityCoreLibrary
{
public static class Detours
{
private static List<string> detoured = new List<string>();
private static List<string> destinations = new List<string>();
/**
This is a basic first implementation of the IL method 'hooks' (detours) made possible by RawCode's work;
https://ludeon.com/forums/index.php?topic=17143.0
Performs detours, spits out basic logs and warns if a method is detoured multiple times.
**/
public static unsafe bool TryDetourFromTo ( MethodInfo source, MethodInfo destination )
{
// error out on null arguments
if( source == null )
{
CCL_Log.Trace( Verbosity.FatalErrors,
"Source MethodInfo is null",
"Detours"
);
return false;
}
if( destination == null )
{
CCL_Log.Trace( Verbosity.FatalErrors,
"Destination MethodInfo is null",
"Detours"
);
return false;
}
// keep track of detours and spit out some messaging
string sourceString = source.DeclaringType.FullName + "." + source.Name + " @ 0x" + source.MethodHandle.GetFunctionPointer().ToString( "X" + ( IntPtr.Size * 2 ).ToString() );
string destinationString = destination.DeclaringType.FullName + "." + destination.Name + " @ 0x" + destination.MethodHandle.GetFunctionPointer().ToString( "X" + ( IntPtr.Size * 2 ).ToString() );
#if DEBUG
if( detoured.Contains( sourceString ) )
{
CCL_Log.Trace( Verbosity.Warnings,
"Source method ('" + sourceString + "') is previously detoured to '" + destinations[ detoured.IndexOf( sourceString ) ] + "'",
"Detours"
);
}
CCL_Log.Trace( Verbosity.Injections,
"Detouring '" + sourceString + "' to '" + destinationString + "'",
"Detours"
);
#endif
detoured.Add( sourceString );
destinations.Add( destinationString );
if( IntPtr.Size == sizeof( Int64 ) )
{
// 64-bit systems use 64-bit absolute address and jumps
// 12 byte destructive
// Get function pointers
long Source_Base = source .MethodHandle.GetFunctionPointer().ToInt64();
long Destination_Base = destination.MethodHandle.GetFunctionPointer().ToInt64();
// Native source address
byte* Pointer_Raw_Source = (byte*)Source_Base;
// Pointer to insert jump address into native code
long* Pointer_Raw_Address = (long*)( Pointer_Raw_Source + 0x02 );
// Insert 64-bit absolute jump into native code (address in rax)
// mov rax, immediate64
// jmp [rax]
*( Pointer_Raw_Source + 0x00 ) = 0x48;
*( Pointer_Raw_Source + 0x01 ) = 0xB8;
*Pointer_Raw_Address = Destination_Base; // ( Pointer_Raw_Source + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 )
*( Pointer_Raw_Source + 0x0A ) = 0xFF;
*( Pointer_Raw_Source + 0x0B ) = 0xE0;
}
else
{
// 32-bit systems use 32-bit relative offset and jump
// 5 byte destructive
// Get function pointers
int Source_Base = source .MethodHandle.GetFunctionPointer().ToInt32();
int Destination_Base = destination.MethodHandle.GetFunctionPointer().ToInt32();
// Native source address
byte* Pointer_Raw_Source = (byte*)Source_Base;
// Pointer to insert jump address into native code
int* Pointer_Raw_Address = (int*)( Pointer_Raw_Source + 1 );
// Jump offset (less instruction size)
int offset = ( Destination_Base - Source_Base ) - 5;
// Insert 32-bit relative jump into native code
*Pointer_Raw_Source = 0xE9;
*Pointer_Raw_Address = offset;
}
// done!
return true;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment