X64: Generalize Il2CppCodegenRegistration scan (part of #21)

This commit is contained in:
Katy Coe
2020-02-15 06:30:12 +01:00
parent 0a99f549ff
commit 538810f441

View File

@@ -5,7 +5,8 @@
*/ */
using System; using System;
using System.ComponentModel.Design; using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq; using System.Linq;
namespace Il2CppInspector namespace Il2CppInspector
@@ -95,7 +96,7 @@ namespace Il2CppInspector
var xor32Size = 2; // the length of a XOR instruction of two 32-bit registers var xor32Size = 2; // the length of a XOR instruction of two 32-bit registers
var pushSize = 2; // the length of a PUSH instruction with a 64-bit register var pushSize = 2; // the length of a PUSH instruction with a 64-bit register
int RAX = 0, RBX = 3, RCX = 1, RDX = 2, R8 = 8; int RAX = 0, RBX = 3, RCX = 1, RDX = 2, RSI = 6, RDI = 7, R8 = 8;
ulong pCgr = 0; // the point to the code registration function ulong pCgr = 0; // the point to the code registration function
@@ -180,43 +181,45 @@ namespace Il2CppInspector
// Find the first 2 LEAs which we'll hope contain pointers to CodeRegistration and MetadataRegistration // Find the first 2 LEAs which we'll hope contain pointers to CodeRegistration and MetadataRegistration
// There are two options here: // There are two options here:
// 1. il2cpp::vm::MetadataCache::Register is called directly with arguments in rcx, rdx and r8 (lea, lea, lea, jmp) // 1. il2cpp::vm::MetadataCache::Register is called directly with arguments in rcx, rdx, r8 or rdi, rsi, rdx (lea, lea, lea, jmp)
// 2. The two functions being inlined. The arguments are loaded sequentially into rax after the prologue // 2. The two functions being inlined. The arguments are loaded sequentially into rax after the prologue
if (pCgr != 0) { if (pCgr != 0) {
var buff2Size = 0x40; var buff2Size = 0x50;
var buff2 = image.ReadBytes(buffSize); var buff2 = image.ReadBytes(buffSize);
var offset = 0; var offset = 0;
(int foundOffset, int reg, uint operand)? lea1 = null, lea2 = null; var leas = new Dictionary<(int index, ulong address), int>();
// We skip over "lea r8". This will leave us with two LEAs containing our desired pointers. // Find the first three LEAs in the function
while (offset + leaSize < buff2Size && (!lea1.HasValue || lea1.Value.reg == R8)) { while (offset + leaSize < buff2Size && leas.Count < 3) {
lea1 = findLea(buff2, offset, buff2Size - (offset + leaSize)); var nextLea = findLea(buff2, offset, buff2Size - (offset + leaSize));
offset = lea1?.foundOffset + leaSize ?? buff2Size;
// Use the original pointer found, not the file location + GlobalOffset because the data may be in a different section
if (nextLea != null)
leas.Add((leas.Count, pCgr + (uint) nextLea.Value.foundOffset + (uint) leaSize + nextLea.Value.operand), nextLea.Value.reg);
offset = nextLea?.foundOffset + leaSize ?? buff2Size;
} }
if (lea1 != null) { if (leas.Count == 3) {
// Register-based argument passing?
var leaRSI = leas.FirstOrDefault(l => l.Value == RSI).Key.address;
var leaRDI = leas.FirstOrDefault(l => l.Value == RDI).Key.address;
while (offset + leaSize < buff2Size && (!lea2.HasValue || lea2.Value.reg == R8)) { if (leaRSI != 0 && leaRDI != 0)
lea2 = findLea(buff2, offset, buff2Size - (offset + leaSize)); return (leaRDI, leaRSI);
offset = lea2?.foundOffset + leaSize ?? buff2Size;
}
if (lea2 != null) { var leaRCX = leas.FirstOrDefault(l => l.Value == RCX).Key.address;
var leaRDX = leas.FirstOrDefault(l => l.Value == RDX).Key.address;
// Use the original pointer found, not the file location + GlobalOffset because the data may be in a different section if (leaRCX != 0 && leaRDX != 0)
var ptr1 = pCgr + (uint) lea1.Value.foundOffset + (uint) leaSize + lea1.Value.operand; return (leaRCX, leaRDX);
var ptr2 = pCgr + (uint) lea2.Value.foundOffset + (uint) leaSize + lea2.Value.operand;
// RCX and RDX argument passing? // RAX sequential loading? If so, take the first two arguments
if (lea1.Value.reg == RDX && lea2.Value.reg == RCX) var leasRAX = leas.Where(l => l.Value == RAX).OrderBy(l => l.Key.index).Select(l => l.Key.address).ToArray();
return (ptr2, ptr1); if (leasRAX.Length > 1)
return (leasRAX[0], leasRAX[1]);
// RAX sequential loading?
if (lea1.Value.reg == RAX && lea2.Value.reg == RAX)
return (ptr1, ptr2);
}
} }
} }