From 538e51ac29ee8abf3fa739dd4262c0a9be7c5bf0 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 8 Sep 2024 10:27:14 -0700 Subject: [PATCH 1/2] Port UnhollowerPdbGen to Il2CppInterop --- .../Il2CppInterop.Pdb.Generator.csproj | 17 ++ .../MethodAddressToTokenMap.cs | 29 ++++ Il2CppInterop.Pdb.Generator/MsPdbCore.cs | 157 ++++++++++++++++++ Il2CppInterop.Pdb.Generator/Program.cs | 101 +++++++++++ Il2CppInterop.Pdb.Generator/README.md | 17 ++ Il2CppInterop.sln | 24 ++- 6 files changed, 336 insertions(+), 9 deletions(-) create mode 100644 Il2CppInterop.Pdb.Generator/Il2CppInterop.Pdb.Generator.csproj create mode 100644 Il2CppInterop.Pdb.Generator/MethodAddressToTokenMap.cs create mode 100644 Il2CppInterop.Pdb.Generator/MsPdbCore.cs create mode 100644 Il2CppInterop.Pdb.Generator/Program.cs create mode 100644 Il2CppInterop.Pdb.Generator/README.md diff --git a/Il2CppInterop.Pdb.Generator/Il2CppInterop.Pdb.Generator.csproj b/Il2CppInterop.Pdb.Generator/Il2CppInterop.Pdb.Generator.csproj new file mode 100644 index 00000000..fdb093bc --- /dev/null +++ b/Il2CppInterop.Pdb.Generator/Il2CppInterop.Pdb.Generator.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + Exe + Il2CppInterop.Pdb.Generator + + + + + + + + + + + diff --git a/Il2CppInterop.Pdb.Generator/MethodAddressToTokenMap.cs b/Il2CppInterop.Pdb.Generator/MethodAddressToTokenMap.cs new file mode 100644 index 00000000..a06323a0 --- /dev/null +++ b/Il2CppInterop.Pdb.Generator/MethodAddressToTokenMap.cs @@ -0,0 +1,29 @@ +using AsmResolver.DotNet; +using Il2CppInterop.Common.Maps; + +#nullable enable + +namespace Il2CppInterop.Pdb.Generator; + +public class MethodAddressToTokenMap : MethodAddressToTokenMapBase +{ + public MethodAddressToTokenMap(string filePath) : base(filePath) + { + } + + protected override AssemblyDefinition? LoadAssembly(string assemblyName) + { + var filesDirt = Path.GetDirectoryName(myFilePath)!; + assemblyName = assemblyName.Substring(0, assemblyName.IndexOf(',')); + return AssemblyDefinition.FromFile(Path.Combine(filesDirt, assemblyName + ".dll")); + } + + protected override MethodDefinition? ResolveMethod(AssemblyDefinition? assembly, int token) + { + if (assembly?.ManifestModule?.TryLookupMember(token, out MethodDefinition? result) ?? false) + { + return result; + } + return null; + } +} diff --git a/Il2CppInterop.Pdb.Generator/MsPdbCore.cs b/Il2CppInterop.Pdb.Generator/MsPdbCore.cs new file mode 100644 index 00000000..0f5c5821 --- /dev/null +++ b/Il2CppInterop.Pdb.Generator/MsPdbCore.cs @@ -0,0 +1,157 @@ +using System.Runtime.InteropServices; +using System.Text; + +// Source/reference: https://github.com/microsoft/microsoft-pdb, MIT license +namespace Il2CppInterop.Pdb.Generator; + +enum PDBErrors : int +{ + EC_OK, // no problem + EC_USAGE, // invalid parameter or call order + EC_OUT_OF_MEMORY, // out of heap + EC_FILE_SYSTEM, // "pdb name", can't write file, out of disk, etc. + EC_NOT_FOUND, // "pdb name", PDB file not found + EC_INVALID_SIG, // "pdb name", PDB::OpenValidate() and its clients only + EC_INVALID_AGE, // "pdb name", PDB::OpenValidate() and its clients only + EC_PRECOMP_REQUIRED, // "obj name", Mod::AddTypes() only + EC_OUT_OF_TI, // "pdb name", TPI::QueryTiForCVRecord() only + EC_NOT_IMPLEMENTED, // - + EC_V1_PDB, // "pdb name", PDB::Open* only (obsolete) + EC_UNKNOWN_FORMAT = EC_V1_PDB, // pdb can't be opened because it has newer versions of stuff + EC_FORMAT, // accessing pdb with obsolete format + EC_LIMIT, + EC_CORRUPT, // cv info corrupt, recompile mod + EC_TI16, // no 16-bit type interface present + EC_ACCESS_DENIED, // "pdb name", PDB file read-only + EC_ILLEGAL_TYPE_EDIT, // trying to edit types in read-only mode + EC_INVALID_EXECUTABLE, // not recogized as a valid executable + EC_DBG_NOT_FOUND, // A required .DBG file was not found + EC_NO_DEBUG_INFO, // No recognized debug info found + EC_INVALID_EXE_TIMESTAMP, // Invalid timestamp on Openvalidate of exe + EC_CORRUPT_TYPEPOOL, // A corrupted type record was found in a PDB + EC_DEBUG_INFO_NOT_IN_PDB, // returned by OpenValidateX + EC_RPC, // Error occured during RPC + EC_UNKNOWN, // Unknown error + EC_BAD_CACHE_PATH, // bad cache location specified with symsrv + EC_CACHE_FULL, // symsrv cache is full + EC_TOO_MANY_MOD_ADDTYPE, // Addtype is called more then once per mod + EC_MAX +} + +[Flags] +enum CV_PUBSYMFLAGS_e : int +{ + cvpsfNone = 0, + cvpsfCode = 0x00000001, + cvpsfFunction = 0x00000002, + cvpsfManaged = 0x00000004, + cvpsfMSIL = 0x00000008, +} + +[StructLayout(LayoutKind.Sequential)] +public struct PdbPtr +{ + public IntPtr InnerPtr; +} + +[StructLayout(LayoutKind.Sequential)] +public struct DbiPtr +{ + public IntPtr InnerPtr; +} + +[StructLayout(LayoutKind.Sequential)] +public struct ModPtr +{ + public IntPtr InnerPtr; +} + +public static unsafe class MsPdbCore +{ + private const string dllName = "mspdbcore.dll"; + + [DllImport(dllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern bool PDBOpen2W(char* wszPDB, byte* szMode, out PDBErrors pec, char* wszError, nuint cchErrMax, out PdbPtr pppdb); + + [DllImport(dllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern bool PDBCommit(PdbPtr ppdb); + + [DllImport(dllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern bool PDBOpenDBI(PdbPtr ppdb, byte* szMode, byte* szTarget, out DbiPtr ppdbi); + + [DllImport(dllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern bool DBIOpenModW(DbiPtr pdbi, char* szModule, char* szFile, out ModPtr ppmod); + + [DllImport(dllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern bool DBIAddPublic2(DbiPtr pdbi, byte* szPublic, ushort isect, int off, CV_PUBSYMFLAGS_e cvpsf = 0); + + [DllImport(dllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern bool ModAddPublic2(ModPtr pmod, byte* szPublic, ushort isect, int off, CV_PUBSYMFLAGS_e cvpsf = 0); + + [DllImport(dllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern bool DBIAddSec(DbiPtr pdbi, ushort isect, ushort flags, int off, int cb); + + [DllImport(dllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern bool ModClose(ModPtr ppdb); + + [DllImport(dllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern bool DBIClose(DbiPtr ppdb); + + [DllImport(dllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern bool PDBClose(PdbPtr ppdb); + + [DllImport(dllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern bool PDBQuerySignature2(PdbPtr ppdb, out Guid guid); + + [DllImport(dllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint PDBQueryAge(PdbPtr ppdb); + + + internal static bool PDBOpen2W(string wszPDB, string szMode, out PDBErrors pec, out string error, out PdbPtr pppdb) + { + wszPDB += '\0'; + szMode += '\0'; + + var chars = wszPDB.ToCharArray(); + var bytes = Encoding.UTF8.GetBytes(szMode); + var errorChars = new char[2048]; + bool result = false; + + fixed (char* cp = chars) + fixed (byte* bp = bytes) + fixed (char* ep = errorChars) + result = PDBOpen2W(cp, bp, out pec, ep, (nuint)errorChars.Length, out pppdb); + + var firstZero = Array.IndexOf(errorChars, '\0'); + error = new string(errorChars, 0, firstZero); + + return result; + } + + internal static bool PDBOpenDBI(PdbPtr ppdb, string szMode, string szTarget, out DbiPtr ppdbi) + { + szMode += '\0'; + szTarget += '\0'; + + fixed (byte* mb = Encoding.UTF8.GetBytes(szMode)) + fixed (byte* tb = Encoding.UTF8.GetBytes(szTarget)) + return PDBOpenDBI(ppdb, mb, tb, out ppdbi); + } + + internal static bool DBIOpenModW(DbiPtr pdbi, string szModule, string szFile, out ModPtr ppmod) + { + szFile += '\0'; + szModule += '\0'; + + fixed (char* fp = szFile) + fixed (char* mp = szModule) + return DBIOpenModW(pdbi, mp, fp, out ppmod); + } + + internal static bool ModAddPublic2(ModPtr pmod, string szPublic, ushort isect, int off, CV_PUBSYMFLAGS_e cvpsf = 0) + { + szPublic += '\0'; + fixed (byte* mb = Encoding.UTF8.GetBytes(szPublic)) + return ModAddPublic2(pmod, mb, isect, off, cvpsf); + } +} diff --git a/Il2CppInterop.Pdb.Generator/Program.cs b/Il2CppInterop.Pdb.Generator/Program.cs new file mode 100644 index 00000000..932eb181 --- /dev/null +++ b/Il2CppInterop.Pdb.Generator/Program.cs @@ -0,0 +1,101 @@ +using System.Reflection.PortableExecutable; + +namespace Il2CppInterop.Pdb.Generator; + +internal static class Program +{ + public static void Main(string[] args) + { + if (args.Length <= 1) + { + Console.WriteLine($"Usage: Il2CppInterop.Pdb.Generator.exe "); + } + var rootPath = Path.GetDirectoryName(args[0])!; + var map = new MethodAddressToTokenMap(args[1]); + + using var peStream = new FileStream(args[0], FileMode.Open, FileAccess.Read); + using var peReader = new PEReader(peStream); + + + string openError; + PDBErrors err; + var pdbFilePath = Path.Combine(rootPath, "GameAssembly.pdb"); + MsPdbCore.PDBOpen2W(pdbFilePath, "w", out err, out openError, out var pdb); + + MsPdbCore.PDBOpenDBI(pdb, "w", "", out var dbi); + + MsPdbCore.DBIOpenModW(dbi, "__Globals", "__Globals", out var mod); + + ushort secNum = 1; + ushort i2cs = 1; + foreach (var sectionHeader in peReader.PEHeaders.SectionHeaders) + { + if (sectionHeader.Name == "il2cpp") i2cs = secNum; + MsPdbCore.DBIAddSec(dbi, secNum++, 0 /* TODO? */, sectionHeader.VirtualAddress, sectionHeader.VirtualSize); + } + + foreach (var valueTuple in map) + { + ushort targetSect = 0; + long tsva = 0; + ushort sc = 1; + foreach (var sectionHeader in peReader.PEHeaders.SectionHeaders) + { + if (valueTuple.Item1 > sectionHeader.VirtualAddress) + { + targetSect = sc; + tsva = sectionHeader.VirtualAddress; + } + else + break; + + sc++; + } + + if (targetSect == 0) throw new ApplicationException("Bad segment"); + MsPdbCore.ModAddPublic2(mod, valueTuple.Item2.FullName, targetSect, (int)(valueTuple.Item1 - tsva * 2), CV_PUBSYMFLAGS_e.cvpsfFunction); + } + + MsPdbCore.ModClose(mod); + MsPdbCore.DBIClose(dbi); + + MsPdbCore.PDBCommit(pdb); + + MsPdbCore.PDBQuerySignature2(pdb, out var wrongGuid); + + MsPdbCore.PDBClose(pdb); + + // Hack: manually replace guid and age in generated .pdb, because there's no API on mspdbcore to set them manually + var targetDebugInfo = peReader.ReadCodeViewDebugDirectoryData(peReader.ReadDebugDirectory() + .Single(it => it.Type == DebugDirectoryEntryType.CodeView)); + + var wrongGuidBytes = wrongGuid.ToByteArray(); + var allPdbBytes = File.ReadAllBytes(pdbFilePath); + + var patchTarget = IndexOfBytes(allPdbBytes, wrongGuidBytes); + targetDebugInfo.Guid.TryWriteBytes(allPdbBytes.AsSpan(patchTarget)); + + Console.WriteLine(targetDebugInfo.Guid); + Console.WriteLine(targetDebugInfo.Age); + + BitConverter.TryWriteBytes(allPdbBytes.AsSpan(patchTarget - 4), targetDebugInfo.Age); + File.WriteAllBytes(pdbFilePath, allPdbBytes); + } + + private static int IndexOfBytes(byte[] haystack, byte[] needle) + { + for (var i = 0; i < haystack.Length - needle.Length; i++) + { + for (var j = 0; j < needle.Length; j++) + { + if (haystack[i + j] != needle[j]) + goto moveOn; + } + + return i; + moveOn:; + } + + return -1; + } +} diff --git a/Il2CppInterop.Pdb.Generator/README.md b/Il2CppInterop.Pdb.Generator/README.md new file mode 100644 index 00000000..70be3bb9 --- /dev/null +++ b/Il2CppInterop.Pdb.Generator/README.md @@ -0,0 +1,17 @@ +# PDB generator + +This is an executable that can be ran to generate a Microsoft PDB file (debug symbols) for GameAssembly.dll based on unhollower-generated names. + +This can be useful for analyzing code of obfuscated games. For unobfuscated games, using [Il2CppInspector](https://github.com/djkaty/Il2CppInspector) might provide better results for code analysis. + +Generated PDBs were tested with windbg, lldb, WPA viewer/ETL performance analysis and IDA. + +Generated PDBs only include generated methods, and don't include type info, generic method info and IL2CPP internals. + +You need to manually copy the following Microsoft-provided libraries from Visual Studio (or other build tools) for this to work. They cannot be redistributed because the license on them is not clear. + + * `mspdbcore.dll` + * `msobj140.dll` + * `tbbmalloc.dll` + +These need to be placed next to the built executable file. Use file search to find `mspdbcore` in the Visual Studio install directory. By default, they are in `C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\`. diff --git a/Il2CppInterop.sln b/Il2CppInterop.sln index 80d120c6..a4aa5698 100644 --- a/Il2CppInterop.sln +++ b/Il2CppInterop.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.31402.337 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35222.181 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Il2CppInterop.Generator", "Il2CppInterop.Generator\Il2CppInterop.Generator.csproj", "{7C3FD45B-A563-47AF-90DF-8B051A8C33A0}" EndProject @@ -10,9 +10,9 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{463B7E3B-94E8-4EEB-B54A-EF15AD9C7C7E}" ProjectSection(SolutionItems) = preProject .gitignore = .gitignore - README.md = README.md - Directory.Build.props = Directory.Build.props build.cake = build.cake + Directory.Build.props = Directory.Build.props + README.md = README.md EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documentation", "Documentation", "{99E71726-78FB-4376-89DA-90E5C08F5CD4}" @@ -20,11 +20,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documentation", "Documentat Documentation\Class-Injection.md = Documentation\Class-Injection.md Documentation\Command-Line-Usage.md = Documentation\Command-Line-Usage.md Documentation\Common-Problems.md = Documentation\Common-Problems.md - Documentation\Injected-Components-In-Asset-Bundles.md = Documentation\Injected-Components-In-Asset-Bundles.md Documentation\Implementing-Interfaces.md = Documentation\Implementing-Interfaces.md + Documentation\Injected-Components-In-Asset-Bundles.md = Documentation\Injected-Components-In-Asset-Bundles.md EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Il2CppInterop.CLI", "Il2CppInterop.CLI\Il2CppInterop.CLI.csproj", "{F5AA88D1-5E62-46B8-A11C-3FAC40C25600}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Il2CppInterop.CLI", "Il2CppInterop.CLI\Il2CppInterop.CLI.csproj", "{F5AA88D1-5E62-46B8-A11C-3FAC40C25600}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Workflows", "Workflows", "{771D8BE3-C373-4754-94EA-4A68B117BAEF}" ProjectSection(SolutionItems) = preProject @@ -32,11 +32,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Workflows", "Workflows", "{ .github\workflows\format_check.yml = .github\workflows\format_check.yml EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Il2CppInterop.StructGenerator", "Il2CppInterop.StructGenerator\Il2CppInterop.StructGenerator.csproj", "{DE781BD4-650F-4ED8-B615-5CB36E6D476A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Il2CppInterop.StructGenerator", "Il2CppInterop.StructGenerator\Il2CppInterop.StructGenerator.csproj", "{DE781BD4-650F-4ED8-B615-5CB36E6D476A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Il2CppInterop.Common", "Il2CppInterop.Common\Il2CppInterop.Common.csproj", "{E7D3A81B-11CD-402C-A447-015B00DCA3FD}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Il2CppInterop.Common", "Il2CppInterop.Common\Il2CppInterop.Common.csproj", "{E7D3A81B-11CD-402C-A447-015B00DCA3FD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Il2CppInterop.HarmonySupport", "Il2CppInterop.HarmonySupport\Il2CppInterop.HarmonySupport.csproj", "{EBC23884-3417-4F24-8623-E913C5151CC3}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Il2CppInterop.HarmonySupport", "Il2CppInterop.HarmonySupport\Il2CppInterop.HarmonySupport.csproj", "{EBC23884-3417-4F24-8623-E913C5151CC3}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Il2CppInterop.Pdb.Generator", "Il2CppInterop.Pdb.Generator\Il2CppInterop.Pdb.Generator.csproj", "{55566454-FF96-4C35-9CF4-479F7130E4D1}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -68,6 +70,10 @@ Global {EBC23884-3417-4F24-8623-E913C5151CC3}.Debug|Any CPU.Build.0 = Debug|Any CPU {EBC23884-3417-4F24-8623-E913C5151CC3}.Release|Any CPU.ActiveCfg = Release|Any CPU {EBC23884-3417-4F24-8623-E913C5151CC3}.Release|Any CPU.Build.0 = Release|Any CPU + {55566454-FF96-4C35-9CF4-479F7130E4D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {55566454-FF96-4C35-9CF4-479F7130E4D1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {55566454-FF96-4C35-9CF4-479F7130E4D1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {55566454-FF96-4C35-9CF4-479F7130E4D1}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From a3065435702f35deff3214e4331824d7c441fea0 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Wed, 27 Nov 2024 15:29:59 -0800 Subject: [PATCH 2/2] Update to use AssetRipper.Bindings.MsPdbCore --- .../Il2CppInterop.Pdb.Generator.csproj | 3 +- Il2CppInterop.Pdb.Generator/MsPdbCore.cs | 157 ------------------ Il2CppInterop.Pdb.Generator/Program.cs | 7 +- 3 files changed, 6 insertions(+), 161 deletions(-) delete mode 100644 Il2CppInterop.Pdb.Generator/MsPdbCore.cs diff --git a/Il2CppInterop.Pdb.Generator/Il2CppInterop.Pdb.Generator.csproj b/Il2CppInterop.Pdb.Generator/Il2CppInterop.Pdb.Generator.csproj index fdb093bc..a064321a 100644 --- a/Il2CppInterop.Pdb.Generator/Il2CppInterop.Pdb.Generator.csproj +++ b/Il2CppInterop.Pdb.Generator/Il2CppInterop.Pdb.Generator.csproj @@ -1,13 +1,14 @@ - net6.0 + net9.0 Exe Il2CppInterop.Pdb.Generator + diff --git a/Il2CppInterop.Pdb.Generator/MsPdbCore.cs b/Il2CppInterop.Pdb.Generator/MsPdbCore.cs deleted file mode 100644 index 0f5c5821..00000000 --- a/Il2CppInterop.Pdb.Generator/MsPdbCore.cs +++ /dev/null @@ -1,157 +0,0 @@ -using System.Runtime.InteropServices; -using System.Text; - -// Source/reference: https://github.com/microsoft/microsoft-pdb, MIT license -namespace Il2CppInterop.Pdb.Generator; - -enum PDBErrors : int -{ - EC_OK, // no problem - EC_USAGE, // invalid parameter or call order - EC_OUT_OF_MEMORY, // out of heap - EC_FILE_SYSTEM, // "pdb name", can't write file, out of disk, etc. - EC_NOT_FOUND, // "pdb name", PDB file not found - EC_INVALID_SIG, // "pdb name", PDB::OpenValidate() and its clients only - EC_INVALID_AGE, // "pdb name", PDB::OpenValidate() and its clients only - EC_PRECOMP_REQUIRED, // "obj name", Mod::AddTypes() only - EC_OUT_OF_TI, // "pdb name", TPI::QueryTiForCVRecord() only - EC_NOT_IMPLEMENTED, // - - EC_V1_PDB, // "pdb name", PDB::Open* only (obsolete) - EC_UNKNOWN_FORMAT = EC_V1_PDB, // pdb can't be opened because it has newer versions of stuff - EC_FORMAT, // accessing pdb with obsolete format - EC_LIMIT, - EC_CORRUPT, // cv info corrupt, recompile mod - EC_TI16, // no 16-bit type interface present - EC_ACCESS_DENIED, // "pdb name", PDB file read-only - EC_ILLEGAL_TYPE_EDIT, // trying to edit types in read-only mode - EC_INVALID_EXECUTABLE, // not recogized as a valid executable - EC_DBG_NOT_FOUND, // A required .DBG file was not found - EC_NO_DEBUG_INFO, // No recognized debug info found - EC_INVALID_EXE_TIMESTAMP, // Invalid timestamp on Openvalidate of exe - EC_CORRUPT_TYPEPOOL, // A corrupted type record was found in a PDB - EC_DEBUG_INFO_NOT_IN_PDB, // returned by OpenValidateX - EC_RPC, // Error occured during RPC - EC_UNKNOWN, // Unknown error - EC_BAD_CACHE_PATH, // bad cache location specified with symsrv - EC_CACHE_FULL, // symsrv cache is full - EC_TOO_MANY_MOD_ADDTYPE, // Addtype is called more then once per mod - EC_MAX -} - -[Flags] -enum CV_PUBSYMFLAGS_e : int -{ - cvpsfNone = 0, - cvpsfCode = 0x00000001, - cvpsfFunction = 0x00000002, - cvpsfManaged = 0x00000004, - cvpsfMSIL = 0x00000008, -} - -[StructLayout(LayoutKind.Sequential)] -public struct PdbPtr -{ - public IntPtr InnerPtr; -} - -[StructLayout(LayoutKind.Sequential)] -public struct DbiPtr -{ - public IntPtr InnerPtr; -} - -[StructLayout(LayoutKind.Sequential)] -public struct ModPtr -{ - public IntPtr InnerPtr; -} - -public static unsafe class MsPdbCore -{ - private const string dllName = "mspdbcore.dll"; - - [DllImport(dllName, CallingConvention = CallingConvention.Cdecl)] - internal static extern bool PDBOpen2W(char* wszPDB, byte* szMode, out PDBErrors pec, char* wszError, nuint cchErrMax, out PdbPtr pppdb); - - [DllImport(dllName, CallingConvention = CallingConvention.Cdecl)] - internal static extern bool PDBCommit(PdbPtr ppdb); - - [DllImport(dllName, CallingConvention = CallingConvention.Cdecl)] - internal static extern bool PDBOpenDBI(PdbPtr ppdb, byte* szMode, byte* szTarget, out DbiPtr ppdbi); - - [DllImport(dllName, CallingConvention = CallingConvention.Cdecl)] - internal static extern bool DBIOpenModW(DbiPtr pdbi, char* szModule, char* szFile, out ModPtr ppmod); - - [DllImport(dllName, CallingConvention = CallingConvention.Cdecl)] - internal static extern bool DBIAddPublic2(DbiPtr pdbi, byte* szPublic, ushort isect, int off, CV_PUBSYMFLAGS_e cvpsf = 0); - - [DllImport(dllName, CallingConvention = CallingConvention.Cdecl)] - internal static extern bool ModAddPublic2(ModPtr pmod, byte* szPublic, ushort isect, int off, CV_PUBSYMFLAGS_e cvpsf = 0); - - [DllImport(dllName, CallingConvention = CallingConvention.Cdecl)] - internal static extern bool DBIAddSec(DbiPtr pdbi, ushort isect, ushort flags, int off, int cb); - - [DllImport(dllName, CallingConvention = CallingConvention.Cdecl)] - internal static extern bool ModClose(ModPtr ppdb); - - [DllImport(dllName, CallingConvention = CallingConvention.Cdecl)] - internal static extern bool DBIClose(DbiPtr ppdb); - - [DllImport(dllName, CallingConvention = CallingConvention.Cdecl)] - internal static extern bool PDBClose(PdbPtr ppdb); - - [DllImport(dllName, CallingConvention = CallingConvention.Cdecl)] - internal static extern bool PDBQuerySignature2(PdbPtr ppdb, out Guid guid); - - [DllImport(dllName, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint PDBQueryAge(PdbPtr ppdb); - - - internal static bool PDBOpen2W(string wszPDB, string szMode, out PDBErrors pec, out string error, out PdbPtr pppdb) - { - wszPDB += '\0'; - szMode += '\0'; - - var chars = wszPDB.ToCharArray(); - var bytes = Encoding.UTF8.GetBytes(szMode); - var errorChars = new char[2048]; - bool result = false; - - fixed (char* cp = chars) - fixed (byte* bp = bytes) - fixed (char* ep = errorChars) - result = PDBOpen2W(cp, bp, out pec, ep, (nuint)errorChars.Length, out pppdb); - - var firstZero = Array.IndexOf(errorChars, '\0'); - error = new string(errorChars, 0, firstZero); - - return result; - } - - internal static bool PDBOpenDBI(PdbPtr ppdb, string szMode, string szTarget, out DbiPtr ppdbi) - { - szMode += '\0'; - szTarget += '\0'; - - fixed (byte* mb = Encoding.UTF8.GetBytes(szMode)) - fixed (byte* tb = Encoding.UTF8.GetBytes(szTarget)) - return PDBOpenDBI(ppdb, mb, tb, out ppdbi); - } - - internal static bool DBIOpenModW(DbiPtr pdbi, string szModule, string szFile, out ModPtr ppmod) - { - szFile += '\0'; - szModule += '\0'; - - fixed (char* fp = szFile) - fixed (char* mp = szModule) - return DBIOpenModW(pdbi, mp, fp, out ppmod); - } - - internal static bool ModAddPublic2(ModPtr pmod, string szPublic, ushort isect, int off, CV_PUBSYMFLAGS_e cvpsf = 0) - { - szPublic += '\0'; - fixed (byte* mb = Encoding.UTF8.GetBytes(szPublic)) - return ModAddPublic2(pmod, mb, isect, off, cvpsf); - } -} diff --git a/Il2CppInterop.Pdb.Generator/Program.cs b/Il2CppInterop.Pdb.Generator/Program.cs index 932eb181..0727db5f 100644 --- a/Il2CppInterop.Pdb.Generator/Program.cs +++ b/Il2CppInterop.Pdb.Generator/Program.cs @@ -1,8 +1,9 @@ -using System.Reflection.PortableExecutable; +using AssetRipper.Bindings.MsPdbCore; +using System.Reflection.PortableExecutable; namespace Il2CppInterop.Pdb.Generator; -internal static class Program +internal static unsafe class Program { public static void Main(string[] args) { @@ -53,7 +54,7 @@ public static void Main(string[] args) } if (targetSect == 0) throw new ApplicationException("Bad segment"); - MsPdbCore.ModAddPublic2(mod, valueTuple.Item2.FullName, targetSect, (int)(valueTuple.Item1 - tsva * 2), CV_PUBSYMFLAGS_e.cvpsfFunction); + MsPdbCore.ModAddPublic2(mod, valueTuple.Item2.FullName, targetSect, (int)(valueTuple.Item1 - tsva * 2), CV_PUBSYMFLAGS_e.Function); } MsPdbCore.ModClose(mod);