Beispiel #1
0
        private void Init()
        {
            try
            {
                var methodField = UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(Original);

                if (methodField == null)
                {
                    throw new Exception($"No IL2CPP equivalent found for {Original.FullDescription()}. The target might have been automatically generated by Unhollower (e.g. field accessor).");
                }

                // Get the native MethodInfo struct for the target method
                originalNativeMethodInfo = (Il2CppMethodInfo *)(IntPtr)methodField.GetValue(null);

                // Create a trampoline from the original target method

                var trampolinePtr = DetourGenerator.CreateTrampolineFromFunction(originalNativeMethodInfo->methodPointer, out _, out _);

                // Create a modified native MethodInfo struct to point towards the trampoline

                modifiedNativeMethodInfo = (Il2CppMethodInfo *)Marshal.AllocHGlobal(Marshal.SizeOf <Il2CppMethodInfo>());
                Marshal.StructureToPtr(*originalNativeMethodInfo, (IntPtr)modifiedNativeMethodInfo, false);

                modifiedNativeMethodInfo->methodPointer = trampolinePtr;
                isValid = true;
            }
            catch (Exception e)
            {
                DetourLogger.LogWarning($"Failed to init IL2CPP patch backend for {Original.FullDescription()}, using normal patch handlers: {e.Message}");
            }
        }
Beispiel #2
0
    private void GenerateTrampolineInner(out int trampolineLength, out int jmpLength)
    {
        if (TrampolinePtr != IntPtr.Zero)
        {
            trampolineLength = TrampolineSize;
            jmpLength        = TrampolineJmpSize;
            return;
        }

        var instructionBuffer = new byte[32];

        Marshal.Copy(OriginalFunctionPtr, instructionBuffer, 0, 32);

        var trampolineAlloc = PageAllocator.Instance.Allocate(OriginalFunctionPtr);

        logger.Log(LogLevel.Debug,
                   $"Original: {OriginalFunctionPtr.ToInt64():X}, Trampoline: {trampolineAlloc:X}, diff: {Math.Abs(OriginalFunctionPtr.ToInt64() - trampolineAlloc):X}; is within +-1GB range: {PageAllocator.IsInRelJmpRange(OriginalFunctionPtr, trampolineAlloc)}");

        DetourHelper.Native.MakeWritable(trampolineAlloc, PageAllocator.PAGE_SIZE);

        var arch = IntPtr.Size == 8 ? Architecture.X64 : Architecture.X86;

        DetourGenerator.CreateTrampolineFromFunction(instructionBuffer, OriginalFunctionPtr, trampolineAlloc,
                                                     DetourGenerator.GetDetourLength(arch), arch,
                                                     out trampolineLength, out jmpLength);

        DetourHelper.Native.MakeExecutable(trampolineAlloc, PageAllocator.PAGE_SIZE);

        TrampolinePtr     = trampolineAlloc;
        TrampolineSize    = trampolineLength;
        TrampolineJmpSize = jmpLength;
    }
Beispiel #3
0
        private void GenerateTrampolineInner(out int trampolineLength, out int jmpLength)
        {
            if (TrampolinePtr != IntPtr.Zero)
            {
                trampolineLength = TrampolineSize;
                jmpLength        = TrampolineJmpSize;
                return;
            }

            byte[] instructionBuffer = new byte[32];
            Marshal.Copy(OriginalFunctionPtr, instructionBuffer, 0, 32);

            var trampolineAlloc = DetourHelper.Native.MemAlloc(80);

            DetourHelper.Native.MakeWritable(trampolineAlloc, 80);

            var arch = IntPtr.Size == 8 ? Architecture.X64 : Architecture.X86;

            DetourGenerator.CreateTrampolineFromFunction(instructionBuffer, OriginalFunctionPtr, trampolineAlloc,
                                                         DetourGenerator.GetDetourLength(arch), arch, out trampolineLength, out jmpLength);

            DetourHelper.Native.MakeExecutable(trampolineAlloc, 80);

            TrampolinePtr     = trampolineAlloc;
            TrampolineSize    = trampolineLength;
            TrampolineJmpSize = jmpLength;
        }
Beispiel #4
0
        public void Apply(ManualLogSource debuggerLogSource)
        {
            if (IsApplied)
            {
                return;
            }


            DetourHelper.Native.MakeWritable(OriginalFunctionPtr, 32);


            if (debuggerLogSource != null)
            {
                debuggerLogSource.LogDebug($"Detouring 0x{OriginalFunctionPtr.ToString("X")} -> 0x{DetourFunctionPtr.ToString("X")}");


                debuggerLogSource.LogDebug("Original (32) asm");

                DetourGenerator.Disassemble(debuggerLogSource, OriginalFunctionPtr, 32);
            }

            var arch = IntPtr.Size == 8 ? Architecture.X64 : Architecture.X86;

            GenerateTrampolineInner(out int trampolineLength, out int jmpLength);

            DetourGenerator.ApplyDetour(OriginalFunctionPtr, DetourFunctionPtr, arch, trampolineLength - jmpLength);


            if (debuggerLogSource != null)
            {
                debuggerLogSource.LogDebug($"Trampoline allocation: 0x{TrampolinePtr.ToString("X")}");

                debuggerLogSource.LogDebug("Modified (32) asm");

                DetourGenerator.Disassemble(debuggerLogSource, OriginalFunctionPtr, 32);

                debuggerLogSource.LogDebug($"Trampoline ({trampolineLength}) asm");

                DetourGenerator.Disassemble(debuggerLogSource, TrampolinePtr, trampolineLength);
            }

            DetourHelper.Native.MakeExecutable(OriginalFunctionPtr, 32);

            IsApplied = true;
        }
Beispiel #5
0
        public void TrampolineTest(int bitness)
        {
            byte[] exampleCode =
            {
                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(bitness, 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());

            DetourGenerator.CreateTrampolineFromFunction(exampleCodePointer, out var trampolineLength, out _);

            Console.WriteLine("Modified:");
            Console.WriteLine();


            Marshal.Copy(exampleCodePointer, exampleCode, 0, exampleCode.Length);
            Disassemble(exampleCode, (ulong)exampleCodePointer.ToInt64());


            Console.WriteLine();
            Console.WriteLine("Trampoline:");
            Console.WriteLine();

            var trampolineArray = new byte[trampolineLength];

            Marshal.Copy(trampolineCodePointer, trampolineArray, 0, trampolineLength);

            Disassemble(trampolineArray, (ulong)trampolineCodePointer.ToInt64());


            Marshal.FreeHGlobal(exampleCodePointer);
            Marshal.FreeHGlobal(trampolineCodePointer);

            Assert.IsFalse(false);
        }