using System; using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Runtime.InteropServices; using BepInEx.IL2CPP; using Iced.Intel; namespace BepInEx.Tests { [TestClass] public class TrampolineTests { [TestMethod] public void TrampolineTest() { 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 }; var exampleCodePointer = Marshal.AllocHGlobal(80); var trampolineCodePointer = Marshal.AllocHGlobal(80); Marshal.Copy(exampleCode, 0, exampleCodePointer, exampleCode.Length); void Disassemble(byte[] data, ulong ip) { var formatter = new NasmFormatter(); var output = new StringOutput(); var codeReader = new ByteArrayCodeReader(data); var decoder = Decoder.Create(64, codeReader); decoder.IP = ip; while (codeReader.CanReadByte) { decoder.Decode(out var instr); formatter.Format(instr, output); Console.WriteLine($"{instr.IP:X16} {output.ToStringAndReset()}"); } Console.WriteLine(); } Console.WriteLine("Original:"); Console.WriteLine(); Disassemble(exampleCode, (ulong)exampleCodePointer.ToInt64()); int trampolineLength = TrampolineGenerator.Generate(exampleCodePointer, new IntPtr(0xBEEF), trampolineCodePointer, 64); Console.WriteLine(); Console.WriteLine("Trampoline:"); Console.WriteLine(); byte[] trampolineArray = new byte[trampolineLength]; Marshal.Copy(trampolineCodePointer, trampolineArray, 0, trampolineLength); Disassemble(trampolineArray, (ulong)trampolineCodePointer.ToInt64()); Marshal.FreeHGlobal(exampleCodePointer); Marshal.FreeHGlobal(trampolineCodePointer); Assert.IsFalse(false); } } }