Unity: Try really hard to find the best IL2CPP API header match for the binary
This commit is contained in:
@@ -6,8 +6,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
@@ -27,13 +25,13 @@ namespace Il2CppInspector.Cpp.UnityHeaders
|
|||||||
public UnityVersionRange VersionRange { get; }
|
public UnityVersionRange VersionRange { get; }
|
||||||
|
|
||||||
// The fully qualified names of the embedded resources
|
// The fully qualified names of the embedded resources
|
||||||
private readonly UnityResource typeHeaderResource;
|
public UnityResource TypeHeaderResource { get; }
|
||||||
private readonly UnityResource apiHeaderResource;
|
public UnityResource APIHeaderResource { get; }
|
||||||
|
|
||||||
// Initialize from a type header and an API header
|
// Initialize from a type header and an API header
|
||||||
private UnityHeaders(UnityResource typeHeaders, UnityResource apiHeaders) {
|
private UnityHeaders(UnityResource typeHeaders, UnityResource apiHeaders) {
|
||||||
typeHeaderResource = typeHeaders;
|
TypeHeaderResource = typeHeaders;
|
||||||
apiHeaderResource = apiHeaders;
|
APIHeaderResource = apiHeaders;
|
||||||
|
|
||||||
VersionRange = typeHeaders.VersionRange.Intersect(apiHeaders.VersionRange);
|
VersionRange = typeHeaders.VersionRange.Intersect(apiHeaders.VersionRange);
|
||||||
MetadataVersion = GetMetadataVersionFromFilename(typeHeaders.Name);
|
MetadataVersion = GetMetadataVersionFromFilename(typeHeaders.Name);
|
||||||
@@ -41,7 +39,7 @@ namespace Il2CppInspector.Cpp.UnityHeaders
|
|||||||
|
|
||||||
// Return the contents of the type header file as a string
|
// Return the contents of the type header file as a string
|
||||||
public string GetTypeHeaderText(int WordSize) {
|
public string GetTypeHeaderText(int WordSize) {
|
||||||
var str = (WordSize == 32 ? "#define IS_32BIT\n" : "") + typeHeaderResource.GetText();
|
var str = (WordSize == 32 ? "#define IS_32BIT\n" : "") + TypeHeaderResource.GetText();
|
||||||
|
|
||||||
// Versions 5.3.6-5.4.6 don't include a definition for VirtualInvokeData
|
// Versions 5.3.6-5.4.6 don't include a definition for VirtualInvokeData
|
||||||
if (VersionRange.Min.CompareTo("5.3.6") >= 0 && VersionRange.Max.CompareTo("5.4.6") <= 0) {
|
if (VersionRange.Min.CompareTo("5.3.6") >= 0 && VersionRange.Max.CompareTo("5.4.6") <= 0) {
|
||||||
@@ -55,7 +53,7 @@ namespace Il2CppInspector.Cpp.UnityHeaders
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return the contents of the API header file as a string
|
// Return the contents of the API header file as a string
|
||||||
public string GetAPIHeaderText() => apiHeaderResource.GetText();
|
public string GetAPIHeaderText() => APIHeaderResource.GetText();
|
||||||
|
|
||||||
// Return the contents of the API header file translated to typedefs as a string
|
// Return the contents of the API header file translated to typedefs as a string
|
||||||
public string GetAPIHeaderTypedefText() => GetTypedefsFromAPIHeader(GetAPIHeaderText());
|
public string GetAPIHeaderTypedefText() => GetTypedefsFromAPIHeader(GetAPIHeaderText());
|
||||||
@@ -126,8 +124,52 @@ namespace Il2CppInspector.Cpp.UnityHeaders
|
|||||||
typeHeaders.Add(r);
|
typeHeaders.Add(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Replace this with an implementation which searches for the correct API header
|
// Get total range of selected headers
|
||||||
return typeHeaders.Select(t => new UnityHeaders(t, GetAPIHeaderForVersion(t.VersionRange.Min))).ToList();
|
// Sort is needed because 5.x.x comes before 20xx.x.x in the resource list
|
||||||
|
typeHeaders = typeHeaders.OrderBy(x => x.VersionRange).ToList();
|
||||||
|
var totalRange = new UnityVersionRange(typeHeaders.First().VersionRange.Min, typeHeaders.Last().VersionRange.Max);
|
||||||
|
|
||||||
|
// Get all API versions in this range
|
||||||
|
var apis = GetAllAPIHeaders().Where(a => a.VersionRange.Intersect(totalRange) != null).ToList();
|
||||||
|
|
||||||
|
// Get the API exports for the binary
|
||||||
|
var exports = binary.GetAPIExports();
|
||||||
|
|
||||||
|
// No il2cpp exports? Just return the earliest version from the header range
|
||||||
|
// The API version may be incorrect but should be a subset of the real API and won't cause C++ compile errors
|
||||||
|
if (!exports.Any()) {
|
||||||
|
Console.WriteLine("No IL2CPP API exports found in binary - IL2CPP APIs will be unavailable in C++ project");
|
||||||
|
|
||||||
|
return typeHeaders.Select(t => new UnityHeaders(t, apis[0])).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go through all of the possible API versions and see how closely they match the binary
|
||||||
|
// Note: if apis.Count == 1, we can't actually narrow down the version range further,
|
||||||
|
// but we still need to check that the APIs actually exist in the binary
|
||||||
|
var apiMatches = new List<UnityResource>();
|
||||||
|
foreach (var api in apis) {
|
||||||
|
var apiFunctionList = GetFunctionNamesFromAPIHeaderText(api.GetText());
|
||||||
|
|
||||||
|
// Every single function in the API list must be an export for a match
|
||||||
|
if (!apiFunctionList.Except(exports.Keys).Any()) {
|
||||||
|
apiMatches.Add(api);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apiMatches.Any()) {
|
||||||
|
// Intersect all API ranges with all header ranges to produce final list of possible ranges
|
||||||
|
Console.WriteLine("IL2CPP API discovery was successful");
|
||||||
|
|
||||||
|
return typeHeaders.SelectMany(
|
||||||
|
t => apis.Where(a => t.VersionRange.Intersect(a.VersionRange) != null)
|
||||||
|
.Select(a => new UnityHeaders(t, a))).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// None of the possible API versions match the binary
|
||||||
|
// Select the oldest API version from the group - C++ project compilation will fail
|
||||||
|
Console.WriteLine("No exact match for IL2CPP APIs found in binary - IL2CPP API availability in C++ project will be partial");
|
||||||
|
|
||||||
|
return typeHeaders.Select(t => new UnityHeaders(t, apis[0])).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert il2cpp-api-functions.h from "DO_API(r, n, p)" to "typedef r (*n)(p)"
|
// Convert il2cpp-api-functions.h from "DO_API(r, n, p)" to "typedef r (*n)(p)"
|
||||||
|
|||||||
Reference in New Issue
Block a user