X64: Generalize Il2CppCodegenRegistration scan (part of #21)
This commit is contained in:
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user