[
  {
    "path": ".gitattributes",
    "content": "###############################################################################\n# Set default behavior to automatically normalize line endings.\n###############################################################################\n* text=auto\n\n###############################################################################\n# Set default behavior for command prompt diff.\n#\n# This is need for earlier builds of msysgit that does not have it on by\n# default for csharp files.\n# Note: This is only used by command line\n###############################################################################\n#*.cs     diff=csharp\n\n###############################################################################\n# Set the merge driver for project and solution files\n#\n# Merging from the command prompt will add diff markers to the files if there\n# are conflicts (Merging from VS is not affected by the settings below, in VS\n# the diff markers are never inserted). Diff markers may cause the following \n# file extensions to fail to load in VS. An alternative would be to treat\n# these files as binary and thus will always conflict and require user\n# intervention with every merge. To do so, just uncomment the entries below\n###############################################################################\n#*.sln       merge=binary\n#*.csproj    merge=binary\n#*.vbproj    merge=binary\n#*.vcxproj   merge=binary\n#*.vcproj    merge=binary\n#*.dbproj    merge=binary\n#*.fsproj    merge=binary\n#*.lsproj    merge=binary\n#*.wixproj   merge=binary\n#*.modelproj merge=binary\n#*.sqlproj   merge=binary\n#*.wwaproj   merge=binary\n\n###############################################################################\n# behavior for image files\n#\n# image files are treated as binary by default.\n###############################################################################\n#*.jpg   binary\n#*.png   binary\n#*.gif   binary\n\n###############################################################################\n# diff behavior for common document formats\n# \n# Convert binary document formats to text before diffing them. This feature\n# is only available from the command line. Turn it on by uncommenting the \n# entries below.\n###############################################################################\n#*.doc   diff=astextplain\n#*.DOC   diff=astextplain\n#*.docx  diff=astextplain\n#*.DOCX  diff=astextplain\n#*.dot   diff=astextplain\n#*.DOT   diff=astextplain\n#*.pdf   diff=astextplain\n#*.PDF   diff=astextplain\n#*.rtf   diff=astextplain\n#*.RTF   diff=astextplain\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/problem_report.md",
    "content": "---\nname: Problem report\nabout: Problem report\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\nNote: if you do not provide all of the following information I will directly ignore and close this issue\n\n- Il2CppDumper version\n\n- Target Unity version (optional)\n\n- Describe the issue\n\n- Upload executable file and global-metadata.dat\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/problem_report_cn.md",
    "content": "---\nname: 问题报告\nabout: 中文问题报告\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n请注意：如果你没有提供以下所有信息我将会直接无视并关闭这个issue\n\n- Il2CppDumper版本\n\n- 目标Unity版本 (可以不填)\n\n- 问题描述\n\n- 上传可执行文件和global-metadata.dat\n"
  },
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore\n\n# User-specific files\n*.rsuser\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Mono auto generated files\nmono_crash.*\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\n[Ww][Ii][Nn]32/\n[Aa][Rr][Mm]/\n[Aa][Rr][Mm]64/\nbld/\n[Bb]in/\n[Oo]bj/\n[Oo]ut/\n[Ll]og/\n[Ll]ogs/\n\n# Visual Studio 2015/2017 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# Visual Studio 2017 auto generated files\nGenerated\\ Files/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUnit\n*.VisualState.xml\nTestResult.xml\nnunit-*.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# Benchmark Results\nBenchmarkDotNet.Artifacts/\n\n# .NET Core\nproject.lock.json\nproject.fragment.lock.json\nartifacts/\n\n# ASP.NET Scaffolding\nScaffoldingReadMe.txt\n\n# StyleCop\nStyleCopReport.xml\n\n# Files built by Visual Studio\n*_i.c\n*_p.c\n*_h.h\n*.ilk\n*.meta\n*.obj\n*.iobj\n*.pch\n*.pdb\n*.ipdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*_wpftmp.csproj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# Visual Studio Trace Files\n*.e2e\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# AxoCover is a Code Coverage Tool\n.axoCover/*\n!.axoCover/settings.json\n\n# Coverlet is a free, cross platform Code Coverage Tool\ncoverage*.json\ncoverage*.xml\ncoverage*.info\n\n# Visual Studio code coverage results\n*.coverage\n*.coveragexml\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# Note: Comment the next line if you want to checkin your web deploy settings,\n# but database connection strings (with potential passwords) will be unencrypted\n*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n*.nupkg\n# NuGet Symbol Packages\n*.snupkg\n# The packages folder can be ignored because of Package Restore\n**/[Pp]ackages/*\n# except build/, which is used as an MSBuild target.\n!**/[Pp]ackages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/[Pp]ackages/repositories.config\n# NuGet v3's project.json files produces more ignorable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n*.appx\n*.appxbundle\n*.appxupload\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!?*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.jfm\n*.pfx\n*.publishsettings\norleans.codegen.cs\n\n# Including strong name files can present a security risk\n# (https://github.com/github/gitignore/pull/2483#issue-259490424)\n#*.snk\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\nServiceFabricBackup/\n*.rptproj.bak\n\n# SQL Server files\n*.mdf\n*.ldf\n*.ndf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n*.rptproj.rsuser\n*- [Bb]ackup.rdl\n*- [Bb]ackup ([0-9]).rdl\n*- [Bb]ackup ([0-9][0-9]).rdl\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\nnode_modules/\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)\n*.vbw\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# CodeRush personal settings\n.cr/personal\n\n# Python Tools for Visual Studio (PTVS)\n__pycache__/\n*.pyc\n\n# Cake - Uncomment if you are using it\n# tools/**\n# !tools/packages.config\n\n# Tabs Studio\n*.tss\n\n# Telerik's JustMock configuration file\n*.jmconfig\n\n# BizTalk build output\n*.btp.cs\n*.btm.cs\n*.odx.cs\n*.xsd.cs\n\n# OpenCover UI analysis results\nOpenCover/\n\n# Azure Stream Analytics local run output\nASALocalRun/\n\n# MSBuild Binary and Structured Log\n*.binlog\n\n# NVidia Nsight GPU debugger configuration file\n*.nvuser\n\n# MFractors (Xamarin productivity tool) working folder\n.mfractor/\n\n# Local History for Visual Studio\n.localhistory/\n\n# BeatPulse healthcheck temp database\nhealthchecksdb\n\n# Backup folder for Package Reference Convert tool in Visual Studio 2017\nMigrationBackup/\n\n# Ionide (cross platform F# VS Code tools) working folder\n.ionide/\n\n# Fody - auto-generated XML schema\nFodyWeavers.xsd"
  },
  {
    "path": "Il2CppDumper/Attributes/ArrayLengthAttribute.cs",
    "content": "﻿using System;\n\nnamespace Il2CppDumper\n{\n    [AttributeUsage(AttributeTargets.Field)]\n    class ArrayLengthAttribute : Attribute\n    {\n        public int Length { get; set; }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Attributes/VersionAttribute.cs",
    "content": "﻿using System;\n\nnamespace Il2CppDumper\n{\n    [AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]\n    class VersionAttribute : Attribute\n    {\n        public double Min { get; set; } = 0;\n        public double Max { get; set; } = 99;\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Config.cs",
    "content": "﻿namespace Il2CppDumper\n{\n    public class Config\n    {\n        public bool DumpMethod { get; set; } = true;\n        public bool DumpField { get; set; } = true;\n        public bool DumpProperty { get; set; } = false;\n        public bool DumpAttribute { get; set; } = false;\n        public bool DumpFieldOffset { get; set; } = true;\n        public bool DumpMethodOffset { get; set; } = true;\n        public bool DumpTypeDefIndex { get; set; } = true;\n        public bool GenerateDummyDll { get; set; } = true;\n        public bool GenerateStruct { get; set; } = true;\n        public bool DummyDllAddToken { get; set; } = true;\n        public bool RequireAnyKey { get; set; } = true;\n        public bool ForceIl2CppVersion { get; set; } = false;\n        public double ForceVersion { get; set; } = 24.3;\n        public bool ForceDump { get; set; } = false;\n        public bool NoRedirectedPointer { get; set; } = false;\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/ExecutableFormats/Elf.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing static Il2CppDumper.ElfConstants;\n\nnamespace Il2CppDumper\n{\n    public sealed class Elf : ElfBase\n    {\n        private Elf32_Ehdr elfHeader;\n        private Elf32_Phdr[] programSegment;\n        private Elf32_Dyn[] dynamicSection;\n        private Elf32_Sym[] symbolTable;\n        private Elf32_Shdr[] sectionTable;\n        private Elf32_Phdr pt_dynamic;\n\n        /*\n        * LDR R1, [X]\n        * ADD R0, X, X\n        * ADD R2, X, X\n        */\n        private static readonly string ARMFeatureBytes = \"? 0x10 ? 0xE7 ? 0x00 ? 0xE0 ? 0x20 ? 0xE0\";\n        private static readonly string X86FeatureBytes = \"? 0x10 ? 0xE7 ? 0x00 ? 0xE0 ? 0x20 ? 0xE0\"; //TODO\n\n        public Elf(Stream stream) : base(stream)\n        {\n            Is32Bit = true;\n            Load();\n        }\n\n        protected override void Load()\n        {\n            elfHeader = ReadClass<Elf32_Ehdr>(0);\n            programSegment = ReadClassArray<Elf32_Phdr>(elfHeader.e_phoff, elfHeader.e_phnum);\n            if (IsDumped)\n            {\n                FixedProgramSegment();\n            }\n            pt_dynamic = programSegment.First(x => x.p_type == PT_DYNAMIC);\n            dynamicSection = ReadClassArray<Elf32_Dyn>(pt_dynamic.p_offset, pt_dynamic.p_filesz / 8u);\n            if (IsDumped)\n            {\n                FixedDynamicSection();\n            }\n            ReadSymbol();\n            if (!IsDumped)\n            {\n                RelocationProcessing();\n                if (CheckProtection())\n                {\n                    Console.WriteLine(\"ERROR: This file may be protected.\");\n                }\n            }\n        }\n\n        protected override bool CheckSection()\n        {\n            try\n            {\n                var names = new List<string>();\n                sectionTable = ReadClassArray<Elf32_Shdr>(elfHeader.e_shoff, elfHeader.e_shnum);\n                var shstrndx = sectionTable[elfHeader.e_shstrndx].sh_offset;\n                foreach (var section in sectionTable)\n                {\n                    names.Add(ReadStringToNull(shstrndx + section.sh_name));\n                }\n                if (!names.Contains(\".text\"))\n                {\n                    return false;\n                }\n                return true;\n            }\n            catch\n            {\n                return false;\n            }\n        }\n\n        public override ulong MapVATR(ulong addr)\n        {\n            var phdr = programSegment.First(x => addr >= x.p_vaddr && addr <= x.p_vaddr + x.p_memsz);\n            return addr - phdr.p_vaddr + phdr.p_offset;\n        }\n\n        public override ulong MapRTVA(ulong addr)\n        {\n            var phdr = programSegment.FirstOrDefault(x => addr >= x.p_offset && addr <= x.p_offset + x.p_filesz);\n            if (phdr == null)\n            {\n                return 0;\n            }\n            return addr - phdr.p_offset + phdr.p_vaddr;\n        }\n\n        public override bool Search()\n        {\n            var _GLOBAL_OFFSET_TABLE_ = dynamicSection.First(x => x.d_tag == DT_PLTGOT).d_un;\n            var execs = programSegment.Where(x => x.p_type == PT_LOAD && (x.p_flags & PF_X) == 1).ToArray();\n            var resultList = new List<int>();\n            var featureBytes = elfHeader.e_machine == EM_ARM ? ARMFeatureBytes : X86FeatureBytes;\n            foreach (var exec in execs)\n            {\n                Position = exec.p_offset;\n                var buff = ReadBytes((int)exec.p_filesz);\n                foreach (var temp in buff.Search(featureBytes))\n                {\n                    var bin = buff[temp + 2].HexToBin();\n                    if (bin[3] == '1') //LDR\n                    {\n                        resultList.Add(temp);\n                    }\n                }\n            }\n            if (resultList.Count == 1)\n            {\n                uint codeRegistration = 0;\n                uint metadataRegistration = 0;\n                var result = (uint)resultList[0];\n                if (Version < 24)\n                {\n                    if (elfHeader.e_machine == EM_ARM)\n                    {\n                        Position = result + 0x14;\n                        codeRegistration = ReadUInt32() + _GLOBAL_OFFSET_TABLE_;\n                        Position = result + 0x18;\n                        var ptr = ReadUInt32() + _GLOBAL_OFFSET_TABLE_;\n                        Position = MapVATR(ptr);\n                        metadataRegistration = ReadUInt32();\n                    }\n                }\n                else if (Version >= 24)\n                {\n                    if (elfHeader.e_machine == EM_ARM)\n                    {\n                        Position = result + 0x14;\n                        codeRegistration = ReadUInt32() + result + 0xcu + (uint)ImageBase;\n                        Position = result + 0x10;\n                        var ptr = ReadUInt32() + result + 0x8;\n                        Position = MapVATR(ptr + ImageBase);\n                        metadataRegistration = ReadUInt32();\n                    }\n                }\n                Console.WriteLine(\"CodeRegistration : {0:x}\", codeRegistration);\n                Console.WriteLine(\"MetadataRegistration : {0:x}\", metadataRegistration);\n                Init(codeRegistration, metadataRegistration);\n                return true;\n            }\n            return false;\n        }\n\n        public override bool PlusSearch(int methodCount, int typeDefinitionsCount, int imageCount)\n        {\n            var sectionHelper = GetSectionHelper(methodCount, typeDefinitionsCount, imageCount);\n            var codeRegistration = sectionHelper.FindCodeRegistration();\n            var metadataRegistration = sectionHelper.FindMetadataRegistration();\n            return AutoPlusInit(codeRegistration, metadataRegistration);\n        }\n\n        public override bool SymbolSearch()\n        {\n            uint codeRegistration = 0;\n            uint metadataRegistration = 0;\n            var dynstrOffset = MapVATR(dynamicSection.First(x => x.d_tag == DT_STRTAB).d_un);\n            foreach (var symbol in symbolTable)\n            {\n                var name = ReadStringToNull(dynstrOffset + symbol.st_name);\n                switch (name)\n                {\n                    case \"g_CodeRegistration\":\n                        codeRegistration = symbol.st_value;\n                        break;\n                    case \"g_MetadataRegistration\":\n                        metadataRegistration = symbol.st_value;\n                        break;\n                }\n            }\n            if (codeRegistration > 0 && metadataRegistration > 0)\n            {\n                Console.WriteLine(\"Detected Symbol !\");\n                Console.WriteLine(\"CodeRegistration : {0:x}\", codeRegistration);\n                Console.WriteLine(\"MetadataRegistration : {0:x}\", metadataRegistration);\n                Init(codeRegistration, metadataRegistration);\n                return true;\n            }\n            Console.WriteLine(\"ERROR: No symbol is detected\");\n            return false;\n        }\n\n        private void ReadSymbol()\n        {\n            try\n            {\n                var symbolCount = 0u;\n                var hash = dynamicSection.FirstOrDefault(x => x.d_tag == DT_HASH);\n                if (hash != null)\n                {\n                    var addr = MapVATR(hash.d_un);\n                    Position = addr;\n                    var nbucket = ReadUInt32();\n                    var nchain = ReadUInt32();\n                    symbolCount = nchain;\n                }\n                else\n                {\n                    hash = dynamicSection.First(x => x.d_tag == DT_GNU_HASH);\n                    var addr = MapVATR(hash.d_un);\n                    Position = addr;\n                    var nbuckets = ReadUInt32();\n                    var symoffset = ReadUInt32();\n                    var bloom_size = ReadUInt32();\n                    var bloom_shift = ReadUInt32();\n                    var buckets_address = addr + 16 + (4 * bloom_size);\n                    var buckets = ReadClassArray<uint>(buckets_address, nbuckets);\n                    var last_symbol = buckets.Max();\n                    if (last_symbol < symoffset)\n                    {\n                        symbolCount = symoffset;\n                    }\n                    else\n                    {\n                        var chains_base_address = buckets_address + 4 * nbuckets;\n                        Position = chains_base_address + (last_symbol - symoffset) * 4;\n                        while (true)\n                        {\n                            var chain_entry = ReadUInt32();\n                            ++last_symbol;\n                            if ((chain_entry & 1) != 0)\n                                break;\n                        }\n                        symbolCount = last_symbol;\n                    }\n                }\n                var dynsymOffset = MapVATR(dynamicSection.First(x => x.d_tag == DT_SYMTAB).d_un);\n                symbolTable = ReadClassArray<Elf32_Sym>(dynsymOffset, symbolCount);\n            }\n            catch\n            {\n                // ignored\n            }\n        }\n\n        private void RelocationProcessing()\n        {\n            Console.WriteLine(\"Applying relocations...\");\n            try\n            {\n                var reldynOffset = MapVATR(dynamicSection.First(x => x.d_tag == DT_REL).d_un);\n                var reldynSize = dynamicSection.First(x => x.d_tag == DT_RELSZ).d_un;\n                var relTable = ReadClassArray<Elf32_Rel>(reldynOffset, reldynSize / 8);\n                var isx86 = elfHeader.e_machine == 0x3;\n                foreach (var rel in relTable)\n                {\n                    var type = rel.r_info & 0xff;\n                    var sym = rel.r_info >> 8;\n                    switch (type)\n                    {\n                        case R_386_32 when isx86:\n                        case R_ARM_ABS32 when !isx86:\n                            {\n                                var symbol = symbolTable[sym];\n                                Position = MapVATR(rel.r_offset);\n                                Write(symbol.st_value);\n                                break;\n                            }\n                    }\n                }\n            }\n            catch\n            {\n                // ignored\n            }\n        }\n\n        private bool CheckProtection()\n        {\n            try\n            {\n                //.init_proc\n                if (dynamicSection.Any(x => x.d_tag == DT_INIT))\n                {\n                    Console.WriteLine(\"WARNING: find .init_proc\");\n                    return true;\n                }\n                //JNI_OnLoad\n                var dynstrOffset = MapVATR(dynamicSection.First(x => x.d_tag == DT_STRTAB).d_un);\n                foreach (var symbol in symbolTable)\n                {\n                    var name = ReadStringToNull(dynstrOffset + symbol.st_name);\n                    switch (name)\n                    {\n                        case \"JNI_OnLoad\":\n                            Console.WriteLine(\"WARNING: find JNI_OnLoad\");\n                            return true;\n                    }\n                }\n                if (sectionTable != null && sectionTable.Any(x => x.sh_type == SHT_LOUSER))\n                {\n                    Console.WriteLine(\"WARNING: find SHT_LOUSER section\");\n                    return true;\n                }\n            }\n            catch\n            {\n                // ignored\n            }\n            return false;\n        }\n\n        public override ulong GetRVA(ulong pointer)\n        {\n            if (IsDumped)\n            {\n                return pointer - ImageBase;\n            }\n            return pointer;\n        }\n\n        private void FixedProgramSegment()\n        {\n            for (uint i = 0; i < programSegment.Length; i++)\n            {\n                Position = elfHeader.e_phoff + i * 32u + 4u;\n                var phdr = programSegment[i];\n                phdr.p_offset = phdr.p_vaddr;\n                Write(phdr.p_offset);\n                phdr.p_vaddr += (uint)ImageBase;\n                Write(phdr.p_vaddr);\n                Position += 4;\n                phdr.p_filesz = phdr.p_memsz;\n                Write(phdr.p_filesz);\n            }\n        }\n\n        private void FixedDynamicSection()\n        {\n            for (uint i = 0; i < dynamicSection.Length; i++)\n            {\n                Position = pt_dynamic.p_offset + i * 8 + 4;\n                var dyn = dynamicSection[i];\n                switch (dyn.d_tag)\n                {\n                    case DT_PLTGOT:\n                    case DT_HASH:\n                    case DT_STRTAB:\n                    case DT_SYMTAB:\n                    case DT_RELA:\n                    case DT_INIT:\n                    case DT_FINI:\n                    case DT_REL:\n                    case DT_JMPREL:\n                    case DT_INIT_ARRAY:\n                    case DT_FINI_ARRAY:\n                        dyn.d_un += (uint)ImageBase;\n                        Write(dyn.d_un);\n                        break;\n                }\n            }\n        }\n\n        public override SectionHelper GetSectionHelper(int methodCount, int typeDefinitionsCount, int imageCount)\n        {\n            var dataList = new List<Elf32_Phdr>();\n            var execList = new List<Elf32_Phdr>();\n            foreach (var phdr in programSegment)\n            {\n                if (phdr.p_memsz != 0ul)\n                {\n                    switch (phdr.p_flags)\n                    {\n                        case 1u: //PF_X\n                        case 3u:\n                        case 5u:\n                        case 7u:\n                            execList.Add(phdr);\n                            break;\n                        case 2u: //PF_W && PF_R\n                        case 4u:\n                        case 6u:\n                            dataList.Add(phdr);\n                            break;\n                    }\n                }\n            }\n            var data = dataList.ToArray();\n            var exec = execList.ToArray();\n            var sectionHelper = new SectionHelper(this, methodCount, typeDefinitionsCount, metadataUsagesCount, imageCount);\n            sectionHelper.SetSection(SearchSectionType.Exec, exec);\n            sectionHelper.SetSection(SearchSectionType.Data, data);\n            sectionHelper.SetSection(SearchSectionType.Bss, data);\n            return sectionHelper;\n        }\n    }\n}"
  },
  {
    "path": "Il2CppDumper/ExecutableFormats/Elf64.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing static Il2CppDumper.ElfConstants;\n\nnamespace Il2CppDumper\n{\n    public sealed class Elf64 : ElfBase\n    {\n        private Elf64_Ehdr elfHeader;\n        private Elf64_Phdr[] programSegment;\n        private Elf64_Dyn[] dynamicSection;\n        private Elf64_Sym[] symbolTable;\n        private Elf64_Shdr[] sectionTable;\n        private Elf64_Phdr pt_dynamic;\n\n        public Elf64(Stream stream) : base(stream)\n        {\n            Load();\n        }\n\n        protected override void Load()\n        {\n            elfHeader = ReadClass<Elf64_Ehdr>(0);\n            programSegment = ReadClassArray<Elf64_Phdr>(elfHeader.e_phoff, elfHeader.e_phnum);\n            if (IsDumped)\n            {\n                FixedProgramSegment();\n            }\n            pt_dynamic = programSegment.First(x => x.p_type == PT_DYNAMIC);\n            dynamicSection = ReadClassArray<Elf64_Dyn>(pt_dynamic.p_offset, pt_dynamic.p_filesz / 16L);\n            if (IsDumped)\n            {\n                FixedDynamicSection();\n            }\n            ReadSymbol();\n            if (!IsDumped)\n            {\n                RelocationProcessing();\n                if (CheckProtection())\n                {\n                    Console.WriteLine(\"ERROR: This file may be protected.\");\n                }\n            }\n        }\n\n        protected override bool CheckSection()\n        {\n            try\n            {\n                var names = new List<string>();\n                sectionTable = ReadClassArray<Elf64_Shdr>(elfHeader.e_shoff, elfHeader.e_shnum);\n                var shstrndx = sectionTable[elfHeader.e_shstrndx].sh_offset;\n                foreach (var section in sectionTable)\n                {\n                    names.Add(ReadStringToNull(shstrndx + section.sh_name));\n                }\n                if (!names.Contains(\".text\"))\n                {\n                    return false;\n                }\n                return true;\n            }\n            catch\n            {\n                return false;\n            }\n        }\n\n        public override ulong MapVATR(ulong addr)\n        {\n            var phdr = programSegment.First(x => addr >= x.p_vaddr && addr <= x.p_vaddr + x.p_memsz);\n            return addr - phdr.p_vaddr + phdr.p_offset;\n        }\n\n        public override ulong MapRTVA(ulong addr)\n        {\n            var phdr = programSegment.FirstOrDefault(x => addr >= x.p_offset && addr <= x.p_offset + x.p_filesz);\n            if (phdr == null)\n            {\n                return 0;\n            }\n            return addr - phdr.p_offset + phdr.p_vaddr;\n        }\n\n        public override bool Search()\n        {\n            return false;\n        }\n\n        public override bool PlusSearch(int methodCount, int typeDefinitionsCount, int imageCount)\n        {\n            var sectionHelper = GetSectionHelper(methodCount, typeDefinitionsCount, imageCount);\n            var codeRegistration = sectionHelper.FindCodeRegistration();\n            var metadataRegistration = sectionHelper.FindMetadataRegistration();\n            return AutoPlusInit(codeRegistration, metadataRegistration);\n        }\n\n        public override bool SymbolSearch()\n        {\n            ulong codeRegistration = 0ul;\n            ulong metadataRegistration = 0ul;\n            ulong dynstrOffset = MapVATR(dynamicSection.First(x => x.d_tag == DT_STRTAB).d_un);\n            foreach (var symbol in symbolTable)\n            {\n                var name = ReadStringToNull(dynstrOffset + symbol.st_name);\n                switch (name)\n                {\n                    case \"g_CodeRegistration\":\n                        codeRegistration = symbol.st_value;\n                        break;\n                    case \"g_MetadataRegistration\":\n                        metadataRegistration = symbol.st_value;\n                        break;\n                }\n            }\n            if (codeRegistration > 0 && metadataRegistration > 0)\n            {\n                Console.WriteLine(\"Detected Symbol !\");\n                Console.WriteLine(\"CodeRegistration : {0:x}\", codeRegistration);\n                Console.WriteLine(\"MetadataRegistration : {0:x}\", metadataRegistration);\n                Init(codeRegistration, metadataRegistration);\n                return true;\n            }\n            Console.WriteLine(\"ERROR: No symbol is detected\");\n            return false;\n        }\n\n        private void ReadSymbol()\n        {\n            try\n            {\n                var symbolCount = 0u;\n                var hash = dynamicSection.FirstOrDefault(x => x.d_tag == DT_HASH);\n                if (hash != null)\n                {\n                    var addr = MapVATR(hash.d_un);\n                    Position = addr;\n                    var nbucket = ReadUInt32();\n                    var nchain = ReadUInt32();\n                    symbolCount = nchain;\n                }\n                else\n                {\n                    hash = dynamicSection.First(x => x.d_tag == DT_GNU_HASH);\n                    var addr = MapVATR(hash.d_un);\n                    Position = addr;\n                    var nbuckets = ReadUInt32();\n                    var symoffset = ReadUInt32();\n                    var bloom_size = ReadUInt32();\n                    var bloom_shift = ReadUInt32();\n                    var buckets_address = addr + 16 + (8 * bloom_size);\n                    var buckets = ReadClassArray<uint>(buckets_address, nbuckets);\n                    var last_symbol = buckets.Max();\n                    if (last_symbol < symoffset)\n                    {\n                        symbolCount = symoffset;\n                    }\n                    else\n                    {\n                        var chains_base_address = buckets_address + 4 * nbuckets;\n                        Position = chains_base_address + (last_symbol - symoffset) * 4;\n                        while (true)\n                        {\n                            var chain_entry = ReadUInt32();\n                            ++last_symbol;\n                            if ((chain_entry & 1) != 0)\n                                break;\n                        }\n                        symbolCount = last_symbol;\n                    }\n                }\n                var dynsymOffset = MapVATR(dynamicSection.First(x => x.d_tag == DT_SYMTAB).d_un);\n                symbolTable = ReadClassArray<Elf64_Sym>(dynsymOffset, symbolCount);\n            }\n            catch\n            {\n                // ignored\n            }\n        }\n\n        private void RelocationProcessing()\n        {\n            Console.WriteLine(\"Applying relocations...\");\n            try\n            {\n                var relaOffset = MapVATR(dynamicSection.First(x => x.d_tag == DT_RELA).d_un);\n                var relaSize = dynamicSection.First(x => x.d_tag == DT_RELASZ).d_un;\n                var relaTable = ReadClassArray<Elf64_Rela>(relaOffset, relaSize / 24L);\n                foreach (var rela in relaTable)\n                {\n                    var type = rela.r_info & 0xffffffff;\n                    var sym = rela.r_info >> 32;\n                    (ulong value, bool recognized) result = (type, elfHeader.e_machine) switch\n                    {\n                        (R_AARCH64_ABS64, EM_AARCH64) => (symbolTable[sym].st_value + rela.r_addend, true),\n                        (R_AARCH64_RELATIVE, EM_AARCH64) => (rela.r_addend, true),\n\n                        (R_X86_64_64, EM_X86_64) => (symbolTable[sym].st_value + rela.r_addend, true),\n                        (R_X86_64_RELATIVE, EM_X86_64) => (rela.r_addend, true),\n\n                        _ => (0, false)\n                    };\n                    if (result.recognized)\n                    {\n                        Position = MapVATR(rela.r_offset);\n                        Write(result.value);\n                    }\n                }\n            }\n            catch\n            {\n                // ignored\n            }\n        }\n\n        private bool CheckProtection()\n        {\n            try\n            {\n                //.init_proc\n                if (dynamicSection.Any(x => x.d_tag == DT_INIT))\n                {\n                    Console.WriteLine(\"WARNING: find .init_proc\");\n                    return true;\n                }\n                //JNI_OnLoad\n                ulong dynstrOffset = MapVATR(dynamicSection.First(x => x.d_tag == DT_STRTAB).d_un);\n                foreach (var symbol in symbolTable)\n                {\n                    var name = ReadStringToNull(dynstrOffset + symbol.st_name);\n                    switch (name)\n                    {\n                        case \"JNI_OnLoad\":\n                            Console.WriteLine(\"WARNING: find JNI_OnLoad\");\n                            return true;\n                    }\n                }\n                if (sectionTable != null && sectionTable.Any(x => x.sh_type == SHT_LOUSER))\n                {\n                    Console.WriteLine(\"WARNING: find SHT_LOUSER section\");\n                    return true;\n                }\n            }\n            catch\n            {\n                // ignored\n            }\n            return false;\n        }\n\n        public override ulong GetRVA(ulong pointer)\n        {\n            if (IsDumped)\n            {\n                return pointer - ImageBase;\n            }\n            return pointer;\n        }\n\n        private void FixedProgramSegment()\n        {\n            for (uint i = 0; i < programSegment.Length; i++)\n            {\n                Position = elfHeader.e_phoff + i * 56u + 8u;\n                var phdr = programSegment[i];\n                phdr.p_offset = phdr.p_vaddr;\n                Write(phdr.p_offset);\n                phdr.p_vaddr += ImageBase;\n                Write(phdr.p_vaddr);\n                Position += 8;\n                phdr.p_filesz = phdr.p_memsz;\n                Write(phdr.p_filesz);\n            }\n        }\n\n        private void FixedDynamicSection()\n        {\n            for (uint i = 0; i < dynamicSection.Length; i++)\n            {\n                Position = pt_dynamic.p_offset + i * 16 + 8;\n                var dyn = dynamicSection[i];\n                switch (dyn.d_tag)\n                {\n                    case DT_PLTGOT:\n                    case DT_HASH:\n                    case DT_STRTAB:\n                    case DT_SYMTAB:\n                    case DT_RELA:\n                    case DT_INIT:\n                    case DT_FINI:\n                    case DT_REL:\n                    case DT_JMPREL:\n                    case DT_INIT_ARRAY:\n                    case DT_FINI_ARRAY:\n                        dyn.d_un += ImageBase;\n                        Write(dyn.d_un);\n                        break;\n                }\n            }\n        }\n\n        public override SectionHelper GetSectionHelper(int methodCount, int typeDefinitionsCount, int imageCount)\n        {\n            var dataList = new List<Elf64_Phdr>();\n            var execList = new List<Elf64_Phdr>();\n            foreach (var phdr in programSegment)\n            {\n                if (phdr.p_memsz != 0ul)\n                {\n                    switch (phdr.p_flags)\n                    {\n                        case 1u: //PF_X\n                        case 3u:\n                        case 5u:\n                        case 7u:\n                            execList.Add(phdr);\n                            break;\n                        case 2u: //PF_W && PF_R\n                        case 4u:\n                        case 6u:\n                            dataList.Add(phdr);\n                            break;\n                    }\n                }\n            }\n            var data = dataList.ToArray();\n            var exec = execList.ToArray();\n            var sectionHelper = new SectionHelper(this, methodCount, typeDefinitionsCount, metadataUsagesCount, imageCount);\n            sectionHelper.SetSection(SearchSectionType.Exec, exec);\n            sectionHelper.SetSection(SearchSectionType.Data, data);\n            sectionHelper.SetSection(SearchSectionType.Bss, data);\n            return sectionHelper;\n        }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/ExecutableFormats/ElfBase.cs",
    "content": "﻿using System.IO;\n\nnamespace Il2CppDumper\n{\n    public abstract class ElfBase : Il2Cpp\n    {\n        protected ElfBase(Stream stream) : base(stream) { }\n        protected abstract void Load();\n        protected abstract bool CheckSection();\n\n        public override bool CheckDump() => !CheckSection();\n\n        public void Reload() => Load();\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/ExecutableFormats/ElfClass.cs",
    "content": "﻿namespace Il2CppDumper\n{\n    public class Elf32_Ehdr\n    {\n        public uint ei_mag;\n        public byte ei_class;\n        public byte ei_data;\n        public byte ei_version;\n        public byte ei_osabi;\n        public byte ei_abiversion;\n        [ArrayLength(Length = 7)]\n        public byte[] ei_pad;\n        public ushort e_type;\n        public ushort e_machine;\n        public uint e_version;\n        public uint e_entry;\n        public uint e_phoff;\n        public uint e_shoff;\n        public uint e_flags;\n        public ushort e_ehsize;\n        public ushort e_phentsize;\n        public ushort e_phnum;\n        public ushort e_shentsize;\n        public ushort e_shnum;\n        public ushort e_shstrndx;\n    }\n\n    public class Elf32_Phdr\n    {\n        public uint p_type;\n        public uint p_offset;\n        public uint p_vaddr;\n        public uint p_paddr;\n        public uint p_filesz;\n        public uint p_memsz;\n        public uint p_flags;\n        public uint p_align;\n    }\n\n    public class Elf32_Shdr\n    {\n        public uint sh_name;\n        public uint sh_type;\n        public uint sh_flags;\n        public uint sh_addr;\n        public uint sh_offset;\n        public uint sh_size;\n        public uint sh_link;\n        public uint sh_info;\n        public uint sh_addralign;\n        public uint sh_entsize;\n    }\n\n    public class Elf32_Sym\n    {\n        public uint st_name;\n        public uint st_value;\n        public uint st_size;\n        public byte st_info;\n        public byte st_other;\n        public ushort st_shndx;\n    }\n\n    public class Elf32_Dyn\n    {\n        public int d_tag;\n        public uint d_un;\n    }\n\n    public class Elf32_Rel\n    {\n        public uint r_offset;\n        public uint r_info;\n    }\n\n    public class Elf64_Ehdr\n    {\n        public uint ei_mag;\n        public byte ei_class;\n        public byte ei_data;\n        public byte ei_version;\n        public byte ei_osabi;\n        public byte ei_abiversion;\n        [ArrayLength(Length = 7)]\n        public byte[] ei_pad;\n        public ushort e_type;\n        public ushort e_machine;\n        public uint e_version;\n        public ulong e_entry;\n        public ulong e_phoff;\n        public ulong e_shoff;\n        public uint e_flags;\n        public ushort e_ehsize;\n        public ushort e_phentsize;\n        public ushort e_phnum;\n        public ushort e_shentsize;\n        public ushort e_shnum;\n        public ushort e_shstrndx;\n    }\n\n    public class Elf64_Phdr\n    {\n        public uint p_type;\n        public uint p_flags;\n        public ulong p_offset;\n        public ulong p_vaddr;\n        public ulong p_paddr;\n        public ulong p_filesz;\n        public ulong p_memsz;\n        public ulong p_align;\n    }\n\n    public class Elf64_Shdr\n    {\n        public uint sh_name;\n        public uint sh_type;\n        public ulong sh_flags;\n        public ulong sh_addr;\n        public ulong sh_offset;\n        public ulong sh_size;\n        public uint sh_link;\n        public uint sh_info;\n        public ulong sh_addralign;\n        public ulong sh_entsize;\n    }\n\n    public class Elf64_Sym\n    {\n        public uint st_name;\n        public byte st_info;\n        public byte st_other;\n        public ushort st_shndx;\n        public ulong st_value;\n        public ulong st_size;\n    }\n\n    public class Elf64_Dyn\n    {\n        public long d_tag;\n        public ulong d_un;\n    }\n\n    public class Elf64_Rela\n    {\n        public ulong r_offset;\n        public ulong r_info;\n        public ulong r_addend;\n    }\n\n    public static class ElfConstants\n    {\n        //e_machine\n        public const int EM_386 = 3;\n        public const int EM_ARM = 40;\n        public const int EM_X86_64 = 62;\n        public const int EM_AARCH64 = 183;\n\n        //p_type\n        public const int PT_LOAD = 1;\n        public const int PT_DYNAMIC = 2;\n\n        //p_flags\n        public const int PF_X = 1;\n\n        //d_tag\n        public const int DT_PLTGOT = 3;\n        public const int DT_HASH = 4;\n        public const int DT_STRTAB = 5;\n        public const int DT_SYMTAB = 6;\n        public const int DT_RELA = 7;\n        public const int DT_RELASZ = 8;\n        public const int DT_INIT = 12;\n        public const int DT_FINI = 13;\n        public const int DT_REL = 17;\n        public const int DT_RELSZ = 18;\n        public const int DT_JMPREL = 23;\n        public const int DT_INIT_ARRAY = 25;\n        public const int DT_FINI_ARRAY = 26;\n        public const int DT_GNU_HASH = 0x6ffffef5;\n\n        //sh_type\n        public const uint SHT_LOUSER = 0x80000000;\n\n        //ARM relocs\n        public const int R_ARM_ABS32 = 2;\n\n        //i386 relocs\n        public const int R_386_32 = 1;\n\n        //AArch64 relocs\n        public const int R_AARCH64_ABS64 = 257;\n        public const int R_AARCH64_RELATIVE = 1027;\n\n        //AMD x86-64 relocations\n        public const int R_X86_64_64 = 1;\n        public const int R_X86_64_RELATIVE = 8;\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/ExecutableFormats/Macho.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing static Il2CppDumper.ArmUtils;\n\nnamespace Il2CppDumper\n{\n    public sealed class Macho : Il2Cpp\n    {\n        private static readonly byte[] FeatureBytes1 = { 0x0, 0x22 };//MOVS R2, #0\n        private static readonly byte[] FeatureBytes2 = { 0x78, 0x44, 0x79, 0x44 };//ADD R0, PC and ADD R1, PC\n        private readonly List<MachoSection> sections = new();\n        private readonly ulong vmaddr;\n\n        public Macho(Stream stream) : base(stream)\n        {\n            Is32Bit = true;\n            Position += 16; //skip magic, cputype, cpusubtype, filetype\n            var ncmds = ReadUInt32();\n            Position += 8; //skip sizeofcmds, flags\n            for (var i = 0; i < ncmds; i++)\n            {\n                var pos = Position;\n                var cmd = ReadUInt32();\n                var cmdsize = ReadUInt32();\n                switch (cmd)\n                {\n                    case 1: //LC_SEGMENT\n                        var segname = Encoding.UTF8.GetString(ReadBytes(16)).TrimEnd('\\0');\n                        if (segname == \"__TEXT\") //__PAGEZERO\n                        {\n                            vmaddr = ReadUInt32();\n                        }\n                        else\n                        {\n                            Position += 4;\n                        }\n                        Position += 20; //skip vmsize, fileoff, filesize, maxprot, initprot\n                        var nsects = ReadUInt32();\n                        Position += 4; //skip flags\n                        for (var j = 0; j < nsects; j++)\n                        {\n                            var section = new MachoSection();\n                            sections.Add(section);\n                            section.sectname = Encoding.UTF8.GetString(ReadBytes(16)).TrimEnd('\\0');\n                            Position += 16; //skip segname\n                            section.addr = ReadUInt32();\n                            section.size = ReadUInt32();\n                            section.offset = ReadUInt32();\n                            Position += 12; //skip align, reloff, nreloc\n                            section.flags = ReadUInt32();\n                            Position += 8; //skip reserved1, reserved2\n                        }\n                        break;\n                    case 0x21: //LC_ENCRYPTION_INFO\n                        Position += 8;\n                        var cryptID = ReadUInt32();\n                        if (cryptID != 0)\n                        {\n                            Console.WriteLine(\"ERROR: This Mach-O executable is encrypted and cannot be processed.\");\n                        }\n                        break;\n                }\n                Position = pos + cmdsize;//next\n            }\n        }\n\n        public override void Init(ulong codeRegistration, ulong metadataRegistration)\n        {\n            base.Init(codeRegistration, metadataRegistration);\n            methodPointers = methodPointers.Select(x => x - 1).ToArray();\n            customAttributeGenerators = customAttributeGenerators.Select(x => x - 1).ToArray();\n        }\n\n        public override ulong MapVATR(ulong addr)\n        {\n            var section = sections.First(x => addr >= x.addr && addr <= x.addr + x.size);\n            return addr - section.addr + section.offset;\n        }\n\n        public override ulong MapRTVA(ulong addr)\n        {\n            var section = sections.FirstOrDefault(x => addr >= x.offset && addr <= x.offset + x.size);\n            if (section == null)\n            {\n                return 0;\n            }\n            return addr - section.offset + section.addr;\n        }\n\n        public override bool Search()\n        {\n            if (Version < 21)\n            {\n                var __mod_init_func = sections.First(x => x.sectname == \"__mod_init_func\");\n                var addrs = ReadClassArray<uint>(__mod_init_func.offset, __mod_init_func.size / 4u);\n                foreach (var a in addrs)\n                {\n                    if (a > 0)\n                    {\n                        var i = a - 1;\n                        Position = MapVATR(i);\n                        Position += 4;\n                        var buff = ReadBytes(2);\n                        if (FeatureBytes1.SequenceEqual(buff))\n                        {\n                            Position += 12;\n                            buff = ReadBytes(4);\n                            if (FeatureBytes2.SequenceEqual(buff))\n                            {\n                                Position = MapVATR(i) + 10;\n                                var subaddr = DecodeMov(ReadBytes(8)) + i + 24u - 1u;\n                                var rsubaddr = MapVATR(subaddr);\n                                Position = rsubaddr;\n                                var ptr = DecodeMov(ReadBytes(8)) + subaddr + 16u;\n                                Position = MapVATR(ptr);\n                                var metadataRegistration = ReadUInt32();\n                                Position = rsubaddr + 8;\n                                buff = ReadBytes(4);\n                                Position = rsubaddr + 14;\n                                buff = buff.Concat(ReadBytes(4)).ToArray();\n                                var codeRegistration = DecodeMov(buff) + subaddr + 22u;\n                                Console.WriteLine(\"CodeRegistration : {0:x}\", codeRegistration);\n                                Console.WriteLine(\"MetadataRegistration : {0:x}\", metadataRegistration);\n                                Init(codeRegistration, metadataRegistration);\n                                return true;\n                            }\n                        }\n                    }\n                }\n                return false;\n            }\n            else\n            {\n                var __mod_init_func = sections.First(x => x.sectname == \"__mod_init_func\");\n                var addrs = ReadClassArray<uint>(__mod_init_func.offset, __mod_init_func.size / 4u);\n                foreach (var a in addrs)\n                {\n                    if (a > 0)\n                    {\n                        var i = a - 1;\n                        Position = MapVATR(i);\n                        Position += 4;\n                        var buff = ReadBytes(2);\n                        if (FeatureBytes1.SequenceEqual(buff))\n                        {\n                            Position += 12;\n                            buff = ReadBytes(4);\n                            if (FeatureBytes2.SequenceEqual(buff))\n                            {\n                                Position = MapVATR(i) + 10;\n                                var subaddr = DecodeMov(ReadBytes(8)) + i + 24u - 1u;\n                                var rsubaddr = MapVATR(subaddr);\n                                Position = rsubaddr;\n                                var ptr = DecodeMov(ReadBytes(8)) + subaddr + 16u;\n                                Position = MapVATR(ptr);\n                                var metadataRegistration = ReadUInt32();\n                                Position = rsubaddr + 8;\n                                buff = ReadBytes(4);\n                                Position = rsubaddr + 14;\n                                buff = buff.Concat(ReadBytes(4)).ToArray();\n                                var codeRegistration = DecodeMov(buff) + subaddr + 26u;\n                                Console.WriteLine(\"CodeRegistration : {0:x}\", codeRegistration);\n                                Console.WriteLine(\"MetadataRegistration : {0:x}\", metadataRegistration);\n                                Init(codeRegistration, metadataRegistration);\n                                return true;\n                            }\n                        }\n                    }\n                }\n                return false;\n            }\n        }\n\n        public override bool PlusSearch(int methodCount, int typeDefinitionsCount, int imageCount)\n        {\n            var sectionHelper = GetSectionHelper(methodCount, typeDefinitionsCount, imageCount);\n            var codeRegistration = sectionHelper.FindCodeRegistration();\n            var metadataRegistration = sectionHelper.FindMetadataRegistration();\n            return AutoPlusInit(codeRegistration, metadataRegistration);\n        }\n\n        public override bool SymbolSearch()\n        {\n            return false;\n        }\n\n        public override ulong GetRVA(ulong pointer)\n        {\n            return pointer - vmaddr;\n        }\n\n        public override SectionHelper GetSectionHelper(int methodCount, int typeDefinitionsCount, int imageCount)\n        {\n            var data = sections.Where(x => x.sectname == \"__const\").ToArray();\n            var code = sections.Where(x => x.flags == 0x80000400).ToArray();\n            var bss = sections.Where(x => x.flags == 1u).ToArray();\n            var sectionHelper = new SectionHelper(this, methodCount, typeDefinitionsCount, metadataUsagesCount, imageCount);\n            sectionHelper.SetSection(SearchSectionType.Exec, code);\n            sectionHelper.SetSection(SearchSectionType.Data, data);\n            sectionHelper.SetSection(SearchSectionType.Bss, bss);\n            return sectionHelper;\n        }\n\n        public override bool CheckDump() => false;\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/ExecutableFormats/Macho64.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing static Il2CppDumper.ArmUtils;\n\nnamespace Il2CppDumper\n{\n    public sealed class Macho64 : Il2Cpp\n    {\n        private static readonly byte[] FeatureBytes1 = { 0x2, 0x0, 0x80, 0xD2 };//MOV X2, #0\n        private static readonly byte[] FeatureBytes2 = { 0x3, 0x0, 0x80, 0x52 };//MOV W3, #0\n        private readonly List<MachoSection64Bit> sections = new();\n        private readonly ulong vmaddr;\n\n        public Macho64(Stream stream) : base(stream)\n        {\n            Position += 16; //skip magic, cputype, cpusubtype, filetype\n            var ncmds = ReadUInt32();\n            Position += 12; //skip sizeofcmds, flags, reserved\n            for (var i = 0; i < ncmds; i++)\n            {\n                var pos = Position;\n                var cmd = ReadUInt32();\n                var cmdsize = ReadUInt32();\n                switch (cmd)\n                {\n                    case 0x19: //LC_SEGMENT_64\n                        var segname = Encoding.UTF8.GetString(ReadBytes(16)).TrimEnd('\\0');\n                        if (segname == \"__TEXT\") //__PAGEZERO\n                        {\n                            vmaddr = ReadUInt64();\n                        }\n                        else\n                        {\n                            Position += 8;\n                        }\n                        Position += 32; //skip vmsize, fileoff, filesize, maxprot, initprot\n                        var nsects = ReadUInt32();\n                        Position += 4; //skip flags\n                        for (var j = 0; j < nsects; j++)\n                        {\n                            var section = new MachoSection64Bit();\n                            sections.Add(section);\n                            section.sectname = Encoding.UTF8.GetString(ReadBytes(16)).TrimEnd('\\0');\n                            Position += 16; //skip segname\n                            section.addr = ReadUInt64();\n                            section.size = ReadUInt64();\n                            section.offset = ReadUInt32();\n                            Position += 12; //skip align, reloff, nreloc\n                            section.flags = ReadUInt32();\n                            Position += 12; //skip reserved1, reserved2, reserved3\n                        }\n                        break;\n                    case 0x2C: //LC_ENCRYPTION_INFO_64\n                        Position += 8;\n                        var cryptID = ReadUInt32();\n                        if (cryptID != 0)\n                        {\n                            Console.WriteLine(\"ERROR: This Mach-O executable is encrypted and cannot be processed.\");\n                        }\n                        break;\n                }\n                Position = pos + cmdsize;//skip\n            }\n        }\n\n        public override ulong MapVATR(ulong addr)\n        {\n            var section = sections.First(x => addr >= x.addr && addr <= x.addr + x.size);\n            if (section.sectname == \"__bss\")\n            {\n                throw new Exception();\n            }\n            return addr - section.addr + section.offset;\n        }\n\n        public override ulong MapRTVA(ulong addr)\n        {\n            var section = sections.FirstOrDefault(x => addr >= x.offset && addr <= x.offset + x.size);\n            if (section == null)\n            {\n                return 0;\n            }\n            if (section.sectname == \"__bss\")\n            {\n                throw new Exception();\n            }\n            return addr - section.offset + section.addr;\n        }\n\n        public override bool Search()\n        {\n            var codeRegistration = 0ul;\n            var metadataRegistration = 0ul;\n            if (Version < 23)\n            {\n                var __mod_init_func = sections.First(x => x.sectname == \"__mod_init_func\");\n                var addrs = ReadClassArray<ulong>(__mod_init_func.offset, __mod_init_func.size / 8);\n                foreach (var i in addrs)\n                {\n                    if (i > 0)\n                    {\n                        var flag = false;\n                        var subaddr = 0ul;\n                        Position = MapVATR(i);\n                        var buff = ReadBytes(4);\n                        if (FeatureBytes1.SequenceEqual(buff))\n                        {\n                            buff = ReadBytes(4);\n                            if (FeatureBytes2.SequenceEqual(buff))\n                            {\n                                Position += 8;\n                                var inst = ReadBytes(4);\n                                if (IsAdr(inst))\n                                {\n                                    subaddr = DecodeAdr(i + 16, inst);\n                                    flag = true;\n                                }\n                            }\n                        }\n                        else\n                        {\n                            Position += 0xc;\n                            buff = ReadBytes(4);\n                            if (FeatureBytes2.SequenceEqual(buff))\n                            {\n                                buff = ReadBytes(4);\n                                if (FeatureBytes1.SequenceEqual(buff))\n                                {\n                                    Position -= 0x10;\n                                    var inst = ReadBytes(4);\n                                    if (IsAdr(inst))\n                                    {\n                                        subaddr = DecodeAdr(i + 8, inst);\n                                        flag = true;\n                                    }\n                                }\n                            }\n                        }\n                        if (flag)\n                        {\n                            var rsubaddr = MapVATR(subaddr);\n                            Position = rsubaddr;\n                            codeRegistration = DecodeAdrp(subaddr, ReadBytes(4));\n                            codeRegistration += DecodeAdd(ReadBytes(4));\n                            Position = rsubaddr + 8;\n                            metadataRegistration = DecodeAdrp(subaddr + 8, ReadBytes(4));\n                            metadataRegistration += DecodeAdd(ReadBytes(4));\n                        }\n                    }\n                }\n            }\n            if (Version == 23)\n            {\n                /* ADRP X0, unk\n                 * ADD X0, X0, unk\n                 * ADR X1, sub\n                 * NOP\n                 * MOV X2, #0\n                 * MOV W3, #0\n                 * B sub\n                 */\n                var __mod_init_func = sections.First(x => x.sectname == \"__mod_init_func\");\n                var addrs = ReadClassArray<ulong>(__mod_init_func.offset, __mod_init_func.size / 8);\n                foreach (var i in addrs)\n                {\n                    if (i > 0)\n                    {\n                        Position = MapVATR(i) + 16;\n                        var buff = ReadBytes(4);\n                        if (FeatureBytes1.SequenceEqual(buff))\n                        {\n                            buff = ReadBytes(4);\n                            if (FeatureBytes2.SequenceEqual(buff))\n                            {\n                                Position -= 16;\n                                var subaddr = DecodeAdr(i + 8, ReadBytes(4));\n                                var rsubaddr = MapVATR(subaddr);\n                                Position = rsubaddr;\n                                codeRegistration = DecodeAdrp(subaddr, ReadBytes(4));\n                                codeRegistration += DecodeAdd(ReadBytes(4));\n                                Position = rsubaddr + 8;\n                                metadataRegistration = DecodeAdrp(subaddr + 8, ReadBytes(4));\n                                metadataRegistration += DecodeAdd(ReadBytes(4));\n                            }\n                        }\n                    }\n                }\n            }\n            if (Version >= 24)\n            {\n                /* ADRP X0, unk\n                 * ADD X0, X0, unk\n                 * ADR X1, sub\n                 * NOP\n                 * MOV W3, #0\n                 * MOV X2, #0\n                 * B sub\n                 */\n                var __mod_init_func = sections.First(x => x.sectname == \"__mod_init_func\");\n                var addrs = ReadClassArray<ulong>(__mod_init_func.offset, __mod_init_func.size / 8);\n                foreach (var i in addrs)\n                {\n                    if (i > 0)\n                    {\n                        Position = MapVATR(i) + 16;\n                        var buff = ReadBytes(4);\n                        if (FeatureBytes2.SequenceEqual(buff))\n                        {\n                            buff = ReadBytes(4);\n                            if (FeatureBytes1.SequenceEqual(buff))\n                            {\n                                Position -= 16;\n                                var subaddr = DecodeAdr(i + 8, ReadBytes(4));\n                                var rsubaddr = MapVATR(subaddr);\n                                Position = rsubaddr;\n                                codeRegistration = DecodeAdrp(subaddr, ReadBytes(4));\n                                codeRegistration += DecodeAdd(ReadBytes(4));\n                                Position = rsubaddr + 8;\n                                metadataRegistration = DecodeAdrp(subaddr + 8, ReadBytes(4));\n                                metadataRegistration += DecodeAdd(ReadBytes(4));\n                            }\n                        }\n                    }\n                }\n            }\n            if (codeRegistration != 0 && metadataRegistration != 0)\n            {\n                Console.WriteLine(\"CodeRegistration : {0:x}\", codeRegistration);\n                Console.WriteLine(\"MetadataRegistration : {0:x}\", metadataRegistration);\n                Init(codeRegistration, metadataRegistration);\n                return true;\n            }\n            return false;\n        }\n\n        public override bool PlusSearch(int methodCount, int typeDefinitionsCount, int imageCount)\n        {\n            var sectionHelper = GetSectionHelper(methodCount, typeDefinitionsCount, imageCount);\n            var codeRegistration = sectionHelper.FindCodeRegistration();\n            var metadataRegistration = sectionHelper.FindMetadataRegistration();\n            return AutoPlusInit(codeRegistration, metadataRegistration);\n        }\n\n        public override bool SymbolSearch()\n        {\n            return false;\n        }\n\n        public override ulong GetRVA(ulong pointer)\n        {\n            return pointer - vmaddr;\n        }\n\n        public override SectionHelper GetSectionHelper(int methodCount, int typeDefinitionsCount, int imageCount)\n        {\n            var data = sections.Where(x => x.sectname == \"__const\" || x.sectname == \"__cstring\" || x.sectname == \"__data\").ToArray();\n            var code = sections.Where(x => x.flags == 0x80000400).ToArray();\n            var bss = sections.Where(x => x.flags == 1u).ToArray();\n            var sectionHelper = new SectionHelper(this, methodCount, typeDefinitionsCount, metadataUsagesCount, imageCount);\n            sectionHelper.SetSection(SearchSectionType.Exec, code);\n            sectionHelper.SetSection(SearchSectionType.Data, data);\n            sectionHelper.SetSection(SearchSectionType.Bss, bss);\n            return sectionHelper;\n        }\n\n        public override bool CheckDump() => false;\n\n        public override ulong ReadUIntPtr()\n        {\n            var pointer = ReadUInt64();\n            if (pointer > vmaddr + 0xFFFFFFFF)\n            {\n                var addr = Position;\n                var section = sections.First(x => addr >= x.offset && addr <= x.offset + x.size);\n                if (section.sectname == \"__const\" || section.sectname == \"__data\")\n                {\n                    var rva = pointer - vmaddr;\n                    rva &= 0xFFFFFFFF;\n                    pointer = rva + vmaddr;\n                }\n            }\n            return pointer;\n        }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/ExecutableFormats/MachoClass.cs",
    "content": "﻿namespace Il2CppDumper\n{\n    public class MachoSection\n    {\n        public string sectname;\n        public uint addr;\n        public uint size;\n        public uint offset;\n        public uint flags;\n    }\n\n    public class MachoSection64Bit\n    {\n        public string sectname;\n        public ulong addr;\n        public ulong size;\n        public ulong offset;\n        public uint flags;\n    }\n\n    public class Fat\n    {\n        public uint offset;\n        public uint size;\n        public uint magic;\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/ExecutableFormats/MachoFat.cs",
    "content": "﻿using System.Buffers.Binary;\nusing System.IO;\n\nnamespace Il2CppDumper\n{\n    public sealed class MachoFat : BinaryStream\n    {\n        public Fat[] fats;\n\n        public MachoFat(Stream stream) : base(stream)\n        {\n            Position += 4;\n            var size = BinaryPrimitives.ReadInt32BigEndian(ReadBytes(4));\n            fats = new Fat[size];\n            for (var i = 0; i < size; i++)\n            {\n                Position += 8;\n                fats[i] = new Fat\n                {\n                    offset = BinaryPrimitives.ReadUInt32BigEndian(ReadBytes(4)),\n                    size = BinaryPrimitives.ReadUInt32BigEndian(ReadBytes(4))\n                };\n                Position += 4;\n            }\n            for (var i = 0; i < size; i++)\n            {\n                Position = fats[i].offset;\n                fats[i].magic = ReadUInt32();\n            }\n        }\n\n        public byte[] GetMacho(int index)\n        {\n            Position = fats[index].offset;\n            return ReadBytes((int)fats[index].size);\n        }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/ExecutableFormats/NSO.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing static Il2CppDumper.ElfConstants;\n\nnamespace Il2CppDumper\n{\n    public sealed class NSO : Il2Cpp\n    {\n        private readonly NSOHeader header;\n        private readonly bool isTextCompressed;\n        private readonly bool isRoDataCompressed;\n        private readonly bool isDataCompressed;\n        private readonly List<NSOSegmentHeader> segments = new();\n        private Elf64_Sym[] symbolTable;\n        private readonly List<Elf64_Dyn> dynamicSection = new();\n        private bool IsCompressed => isTextCompressed || isRoDataCompressed || isDataCompressed;\n\n\n        public NSO(Stream stream) : base(stream)\n        {\n            header = new NSOHeader\n            {\n                Magic = ReadUInt32(),\n                Version = ReadUInt32(),\n                Reserved = ReadUInt32(),\n                Flags = ReadUInt32()\n            };\n            isTextCompressed = (header.Flags & 1) != 0;\n            isRoDataCompressed = (header.Flags & 2) != 0;\n            isDataCompressed = (header.Flags & 4) != 0;\n            header.TextSegment = new NSOSegmentHeader\n            {\n                FileOffset = ReadUInt32(),\n                MemoryOffset = ReadUInt32(),\n                DecompressedSize = ReadUInt32()\n            };\n            segments.Add(header.TextSegment);\n            header.ModuleOffset = ReadUInt32();\n            header.RoDataSegment = new NSOSegmentHeader\n            {\n                FileOffset = ReadUInt32(),\n                MemoryOffset = ReadUInt32(),\n                DecompressedSize = ReadUInt32()\n            };\n            segments.Add(header.RoDataSegment);\n            header.ModuleFileSize = ReadUInt32();\n            header.DataSegment = new NSOSegmentHeader\n            {\n                FileOffset = ReadUInt32(),\n                MemoryOffset = ReadUInt32(),\n                DecompressedSize = ReadUInt32()\n            };\n            segments.Add(header.DataSegment);\n            header.BssSize = ReadUInt32();\n            header.DigestBuildID = ReadBytes(0x20);\n            header.TextCompressedSize = ReadUInt32();\n            header.RoDataCompressedSize = ReadUInt32();\n            header.DataCompressedSize = ReadUInt32();\n            header.Padding = ReadBytes(0x1C);\n            header.APIInfo = new NSORelativeExtent\n            {\n                RegionRoDataOffset = ReadUInt32(),\n                RegionSize = ReadUInt32()\n            };\n            header.DynStr = new NSORelativeExtent\n            {\n                RegionRoDataOffset = ReadUInt32(),\n                RegionSize = ReadUInt32()\n            };\n            header.DynSym = new NSORelativeExtent\n            {\n                RegionRoDataOffset = ReadUInt32(),\n                RegionSize = ReadUInt32()\n            };\n            header.TextHash = ReadBytes(0x20);\n            header.RoDataHash = ReadBytes(0x20);\n            header.DataHash = ReadBytes(0x20);\n\n            if (!IsCompressed)\n            {\n                Position = header.TextSegment.FileOffset + 4;\n                var modOffset = ReadUInt32();\n                Position = header.TextSegment.FileOffset + modOffset + 4;\n                var dynamicOffset = ReadUInt32() + modOffset;\n                var bssStart = ReadUInt32();\n                var bssEnd = ReadUInt32();\n                header.BssSegment = new NSOSegmentHeader\n                {\n                    FileOffset = bssStart,\n                    MemoryOffset = bssStart,\n                    DecompressedSize = bssEnd - bssStart\n                };\n                var maxSize = (header.DataSegment.MemoryOffset + header.DataSegment.DecompressedSize - dynamicOffset) / 16;\n                Position = MapVATR(dynamicOffset);\n                for (int i = 0; i < maxSize; i++)\n                {\n                    var dynamic = ReadClass<Elf64_Dyn>();\n                    if (dynamic.d_tag == 0)\n                    {\n                        break;\n                    }\n                    else\n                    {\n                        dynamicSection.Add(dynamic);\n                    }\n                }\n                ReadSymbol();\n                RelocationProcessing();\n            }\n        }\n\n        private void ReadSymbol()\n        {\n            try\n            {\n                var symbolCount = 0u;\n                var hash = dynamicSection.FirstOrDefault(x => x.d_tag == DT_HASH);\n                if (hash != null)\n                {\n                    var addr = MapVATR(hash.d_un);\n                    Position = addr;\n                    var nbucket = ReadUInt32();\n                    var nchain = ReadUInt32();\n                    symbolCount = nchain;\n                }\n                else\n                {\n                    hash = dynamicSection.First(x => x.d_tag == DT_GNU_HASH);\n                    var addr = MapVATR(hash.d_un);\n                    Position = addr;\n                    var nbuckets = ReadUInt32();\n                    var symoffset = ReadUInt32();\n                    var bloom_size = ReadUInt32();\n                    var bloom_shift = ReadUInt32();\n                    var buckets_address = addr + 16 + (8 * bloom_size);\n                    var buckets = ReadClassArray<uint>(buckets_address, nbuckets);\n                    var last_symbol = buckets.Max();\n                    if (last_symbol < symoffset)\n                    {\n                        symbolCount = symoffset;\n                    }\n                    else\n                    {\n                        var chains_base_address = buckets_address + 4 * nbuckets;\n                        Position = chains_base_address + (last_symbol - symoffset) * 4;\n                        while (true)\n                        {\n                            var chain_entry = ReadUInt32();\n                            ++last_symbol;\n                            if ((chain_entry & 1) != 0)\n                                break;\n                        }\n                        symbolCount = last_symbol;\n                    }\n                }\n                var dynsymOffset = MapVATR(dynamicSection.First(x => x.d_tag == DT_SYMTAB).d_un);\n                symbolTable = ReadClassArray<Elf64_Sym>(dynsymOffset, symbolCount);\n            }\n            catch\n            {\n                // ignored\n            }\n        }\n\n        private void RelocationProcessing()\n        {\n            Console.WriteLine(\"Applying relocations...\");\n            try\n            {\n                var relaOffset = MapVATR(dynamicSection.First(x => x.d_tag == DT_RELA).d_un);\n                var relaSize = dynamicSection.First(x => x.d_tag == DT_RELASZ).d_un;\n                var relaTable = ReadClassArray<Elf64_Rela>(relaOffset, relaSize / 24L);\n                foreach (var rela in relaTable)\n                {\n                    var type = rela.r_info & 0xffffffff;\n                    var sym = rela.r_info >> 32;\n                    switch (type)\n                    {\n                        case R_AARCH64_ABS64:\n                            {\n                                var symbol = symbolTable[sym];\n                                Position = MapVATR(rela.r_offset);\n                                Write(symbol.st_value + (ulong)rela.r_addend);\n                                break;\n                            }\n                        case R_AARCH64_RELATIVE:\n                            {\n                                Position = MapVATR(rela.r_offset);\n                                Write(rela.r_addend);\n                                break;\n                            }\n                    }\n                }\n            }\n            catch\n            {\n                // ignored\n            }\n        }\n\n        public override ulong MapVATR(ulong addr)\n        {\n            var segment = segments.First(x => addr >= x.MemoryOffset && addr <= x.MemoryOffset + x.DecompressedSize);\n            return addr - segment.MemoryOffset + segment.FileOffset;\n        }\n\n        public override ulong MapRTVA(ulong addr)\n        {\n            var segment = segments.FirstOrDefault(x => addr >= x.FileOffset && addr <= x.FileOffset + x.DecompressedSize);\n            if (segment == null)\n            {\n                return 0;\n            }\n            return addr - segment.FileOffset + segment.MemoryOffset;\n        }\n\n        public override bool Search()\n        {\n            return false;\n        }\n\n        public override bool PlusSearch(int methodCount, int typeDefinitionsCount, int imageCount)\n        {\n            var sectionHelper = GetSectionHelper(methodCount, typeDefinitionsCount, imageCount);\n            var codeRegistration = sectionHelper.FindCodeRegistration();\n            var metadataRegistration = sectionHelper.FindMetadataRegistration();\n            return AutoPlusInit(codeRegistration, metadataRegistration);\n        }\n\n        public override bool SymbolSearch()\n        {\n            return false;\n        }\n\n        public NSO UnCompress()\n        {\n            if (isTextCompressed || isRoDataCompressed || isDataCompressed)\n            {\n                var unCompressedStream = new MemoryStream();\n                var writer = new BinaryWriter(unCompressedStream);\n                writer.Write(header.Magic);\n                writer.Write(header.Version);\n                writer.Write(header.Reserved);\n                writer.Write(0); //Flags\n                writer.Write(header.TextSegment.FileOffset);\n                writer.Write(header.TextSegment.MemoryOffset);\n                writer.Write(header.TextSegment.DecompressedSize);\n                writer.Write(header.ModuleOffset);\n                var roOffset = header.TextSegment.FileOffset + header.TextSegment.DecompressedSize;\n                writer.Write(roOffset); //header.RoDataSegment.FileOffset\n                writer.Write(header.RoDataSegment.MemoryOffset);\n                writer.Write(header.RoDataSegment.DecompressedSize);\n                writer.Write(header.ModuleFileSize);\n                writer.Write(roOffset + header.RoDataSegment.DecompressedSize); //header.DataSegment.FileOffset\n                writer.Write(header.DataSegment.MemoryOffset);\n                writer.Write(header.DataSegment.DecompressedSize);\n                writer.Write(header.BssSize);\n                writer.Write(header.DigestBuildID);\n                writer.Write(header.TextCompressedSize);\n                writer.Write(header.RoDataCompressedSize);\n                writer.Write(header.DataCompressedSize);\n                writer.Write(header.Padding);\n                writer.Write(header.APIInfo.RegionRoDataOffset);\n                writer.Write(header.APIInfo.RegionSize);\n                writer.Write(header.DynStr.RegionRoDataOffset);\n                writer.Write(header.DynStr.RegionSize);\n                writer.Write(header.DynSym.RegionRoDataOffset);\n                writer.Write(header.DynSym.RegionSize);\n                writer.Write(header.TextHash);\n                writer.Write(header.RoDataHash);\n                writer.Write(header.DataHash);\n                writer.BaseStream.Position = header.TextSegment.FileOffset;\n                Position = header.TextSegment.FileOffset;\n                var textBytes = ReadBytes((int)header.TextCompressedSize);\n                if (isTextCompressed)\n                {\n                    var unCompressedData = new byte[header.TextSegment.DecompressedSize];\n                    using (var decoder = new Lz4DecoderStream(new MemoryStream(textBytes)))\n                    {\n                        decoder.Read(unCompressedData, 0, unCompressedData.Length);\n                    }\n                    writer.Write(unCompressedData);\n                }\n                else\n                {\n                    writer.Write(textBytes);\n                }\n                var roDataBytes = ReadBytes((int)header.RoDataCompressedSize);\n                if (isRoDataCompressed)\n                {\n                    var unCompressedData = new byte[header.RoDataSegment.DecompressedSize];\n                    using (var decoder = new Lz4DecoderStream(new MemoryStream(roDataBytes)))\n                    {\n                        decoder.Read(unCompressedData, 0, unCompressedData.Length);\n                    }\n                    writer.Write(unCompressedData);\n                }\n                else\n                {\n                    writer.Write(roDataBytes);\n                }\n                var dataBytes = ReadBytes((int)header.DataCompressedSize);\n                if (isDataCompressed)\n                {\n                    var unCompressedData = new byte[header.DataSegment.DecompressedSize];\n                    using (var decoder = new Lz4DecoderStream(new MemoryStream(dataBytes)))\n                    {\n                        decoder.Read(unCompressedData, 0, unCompressedData.Length);\n                    }\n                    writer.Write(unCompressedData);\n                }\n                else\n                {\n                    writer.Write(dataBytes);\n                }\n                writer.Flush();\n                unCompressedStream.Position = 0;\n                return new NSO(unCompressedStream);\n            }\n            return this;\n        }\n\n        public override SectionHelper GetSectionHelper(int methodCount, int typeDefinitionsCount, int imageCount)\n        {\n            var sectionHelper = new SectionHelper(this, methodCount, typeDefinitionsCount, metadataUsagesCount, imageCount);\n            sectionHelper.SetSection(SearchSectionType.Exec, header.TextSegment);\n            sectionHelper.SetSection(SearchSectionType.Data, header.DataSegment, header.RoDataSegment);\n            sectionHelper.SetSection(SearchSectionType.Bss, header.BssSegment);\n            return sectionHelper;\n        }\n\n        public override bool CheckDump() => false;\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/ExecutableFormats/NSOClass.cs",
    "content": "﻿namespace Il2CppDumper\n{\n    public class NSOHeader\n    {\n        public uint Magic;\n        public uint Version;\n        public uint Reserved;\n        public uint Flags;\n        public NSOSegmentHeader TextSegment;\n        public uint ModuleOffset;\n        public NSOSegmentHeader RoDataSegment;\n        public uint ModuleFileSize;\n        public NSOSegmentHeader DataSegment;\n        public uint BssSize;\n        public byte[] DigestBuildID;\n        public uint TextCompressedSize;\n        public uint RoDataCompressedSize;\n        public uint DataCompressedSize;\n        public byte[] Padding;\n        public NSORelativeExtent APIInfo;\n        public NSORelativeExtent DynStr;\n        public NSORelativeExtent DynSym;\n        public byte[] TextHash;\n        public byte[] RoDataHash;\n        public byte[] DataHash;\n\n        public NSOSegmentHeader BssSegment;\n    }\n\n    public class NSOSegmentHeader\n    {\n        public uint FileOffset;\n        public uint MemoryOffset;\n        public uint DecompressedSize;\n    }\n\n    public class NSORelativeExtent\n    {\n        public uint RegionRoDataOffset;\n        public uint RegionSize;\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/ExecutableFormats/PE.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\n\nnamespace Il2CppDumper\n{\n    public sealed class PE : Il2Cpp\n    {\n        private readonly SectionHeader[] sections;\n\n        public PE(Stream stream) : base(stream)\n        {\n            var dosHeader = ReadClass<DosHeader>();\n            if (dosHeader.Magic != 0x5A4D)\n            {\n                throw new InvalidDataException(\"ERROR: Invalid PE file\");\n            }\n            Position = dosHeader.Lfanew;\n            if (ReadUInt32() != 0x4550u) //Signature\n            {\n                throw new InvalidDataException(\"ERROR: Invalid PE file\");\n            }\n            var fileHeader = ReadClass<FileHeader>();\n            var pos = Position;\n            var magic = ReadUInt16();\n            Position -= 2;\n            if (magic == 0x10b)\n            {\n                Is32Bit = true;\n                var optionalHeader = ReadClass<OptionalHeader>();\n                ImageBase = optionalHeader.ImageBase;\n            }\n            else if (magic == 0x20b)\n            {\n                var optionalHeader = ReadClass<OptionalHeader64>();\n                ImageBase = optionalHeader.ImageBase;\n            }\n            else\n            {\n                throw new NotSupportedException($\"Invalid Optional header magic {magic}\");\n            }\n            Position = pos + fileHeader.SizeOfOptionalHeader;\n            sections = ReadClassArray<SectionHeader>(fileHeader.NumberOfSections);\n        }\n\n        public void LoadFromMemory(ulong addr)\n        {\n            ImageBase = addr;\n            foreach (var section in sections)\n            {\n                section.PointerToRawData = section.VirtualAddress;\n                section.SizeOfRawData = section.VirtualSize;\n            }\n        }\n\n        public override ulong MapVATR(ulong absAddr)\n        {\n            var addr = absAddr - ImageBase;\n            var section = sections.FirstOrDefault(x => addr >= x.VirtualAddress && addr <= x.VirtualAddress + x.VirtualSize);\n            if (section == null)\n            {\n                return 0ul;\n            }\n            return addr - section.VirtualAddress + section.PointerToRawData;\n        }\n\n        public override ulong MapRTVA(ulong addr)\n        {\n            var section = sections.FirstOrDefault(x => addr >= x.PointerToRawData && addr <= x.PointerToRawData + x.SizeOfRawData);\n            if (section == null)\n            {\n                return 0ul;\n            }\n            return addr - section.PointerToRawData + section.VirtualAddress + ImageBase;\n        }\n\n        public override bool Search()\n        {\n            return false;\n        }\n\n        public override bool PlusSearch(int methodCount, int typeDefinitionsCount, int imageCount)\n        {\n            var sectionHelper = GetSectionHelper(methodCount, typeDefinitionsCount, imageCount);\n            var codeRegistration = sectionHelper.FindCodeRegistration();\n            var metadataRegistration = sectionHelper.FindMetadataRegistration();\n            return AutoPlusInit(codeRegistration, metadataRegistration);\n        }\n\n        public override bool SymbolSearch()\n        {\n            return false;\n        }\n\n        public override ulong GetRVA(ulong pointer)\n        {\n            return pointer - ImageBase;\n        }\n\n        public override SectionHelper GetSectionHelper(int methodCount, int typeDefinitionsCount, int imageCount)\n        {\n            var execList = new List<SectionHeader>();\n            var dataList = new List<SectionHeader>();\n            foreach (var section in sections)\n            {\n                switch (section.Characteristics)\n                {\n                    case 0x60000020:\n                        execList.Add(section);\n                        break;\n                    case 0x40000040:\n                    case 0xC0000040:\n                        dataList.Add(section);\n                        break;\n                }\n            }\n            var sectionHelper = new SectionHelper(this, methodCount, typeDefinitionsCount, metadataUsagesCount, imageCount);\n            var data = dataList.ToArray();\n            var exec = execList.ToArray();\n            sectionHelper.SetSection(SearchSectionType.Exec, ImageBase, exec);\n            sectionHelper.SetSection(SearchSectionType.Data, ImageBase, data);\n            sectionHelper.SetSection(SearchSectionType.Bss, ImageBase, data);\n            return sectionHelper;\n        }\n\n        public override bool CheckDump()\n        {\n            if (Is32Bit)\n            {\n                return ImageBase != 0x10000000;\n            }\n            else\n            {\n                return ImageBase != 0x180000000;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/ExecutableFormats/PEClass.cs",
    "content": "﻿using System;\n\nnamespace Il2CppDumper\n{\n    public class DosHeader\n    {\n        public ushort Magic;\n        public ushort Cblp;\n        public ushort Cp;\n        public ushort Crlc;\n        public ushort Cparhdr;\n        public ushort Minalloc;\n        public ushort Maxalloc;\n        public ushort Ss;\n        public ushort Sp;\n        public ushort Csum;\n        public ushort Ip;\n        public ushort Cs;\n        public ushort Lfarlc;\n        public ushort Ovno;\n        [ArrayLength(Length = 4)]\n        public ushort[] Res;\n        public ushort Oemid;\n        public ushort Oeminfo;\n        [ArrayLength(Length = 10)]\n        public ushort[] Res2;\n        public uint Lfanew;\n    }\n\n    public class FileHeader\n    {\n        public ushort Machine;\n        public ushort NumberOfSections;\n        public uint TimeDateStamp;\n        public uint PointerToSymbolTable;\n        public uint NumberOfSymbols;\n        public ushort SizeOfOptionalHeader;\n        public ushort Characteristics;\n    }\n\n    public class OptionalHeader\n    {\n        public ushort Magic;\n        public byte MajorLinkerVersion;\n        public byte MinorLinkerVersion;\n        public uint SizeOfCode;\n        public uint SizeOfInitializedData;\n        public uint SizeOfUninitializedData;\n        public uint AddressOfEntryPoint;\n        public uint BaseOfCode;\n        public uint BaseOfData;\n        public uint ImageBase;\n        public uint SectionAlignment;\n        public uint FileAlignment;\n        public ushort MajorOperatingSystemVersion;\n        public ushort MinorOperatingSystemVersion;\n        public ushort MajorImageVersion;\n        public ushort MinorImageVersion;\n        public ushort MajorSubsystemVersion;\n        public ushort MinorSubsystemVersion;\n        public uint Win32VersionValue;\n        public uint SizeOfImage;\n        public uint SizeOfHeaders;\n        public uint CheckSum;\n        public ushort Subsystem;\n        public ushort DllCharacteristics;\n        public uint SizeOfStackReserve;\n        public uint SizeOfStackCommit;\n        public uint SizeOfHeapReserve;\n        public uint SizeOfHeapCommit;\n        public uint LoaderFlags;\n        public uint NumberOfRvaAndSizes;\n        //public DataDirectory[] DataDirectory;\n    }\n\n    public class OptionalHeader64\n    {\n        public ushort Magic;\n        public byte MajorLinkerVersion;\n        public byte MinorLinkerVersion;\n        public uint SizeOfCode;\n        public uint SizeOfInitializedData;\n        public uint SizeOfUninitializedData;\n        public uint AddressOfEntryPoint;\n        public uint BaseOfCode;\n        public ulong ImageBase;\n        public uint SectionAlignment;\n        public uint FileAlignment;\n        public ushort MajorOperatingSystemVersion;\n        public ushort MinorOperatingSystemVersion;\n        public ushort MajorImageVersion;\n        public ushort MinorImageVersion;\n        public ushort MajorSubsystemVersion;\n        public ushort MinorSubsystemVersion;\n        public uint Win32VersionValue;\n        public uint SizeOfImage;\n        public uint SizeOfHeaders;\n        public uint CheckSum;\n        public ushort Subsystem;\n        public ushort DllCharacteristics;\n        public ulong SizeOfStackReserve;\n        public ulong SizeOfStackCommit;\n        public ulong SizeOfHeapReserve;\n        public ulong SizeOfHeapCommit;\n        public uint LoaderFlags;\n        public uint NumberOfRvaAndSizes;\n        //public DataDirectory[] DataDirectory;\n    }\n\n    /*public class DataDirectory\n    {\n        public uint VirtualAddress;\n        public uint Size;\n    }*/\n\n    public class SectionHeader\n    {\n        [ArrayLength(Length = 8)]\n        public byte[] Name;\n        public uint VirtualSize;\n        public uint VirtualAddress;\n        public uint SizeOfRawData;\n        public uint PointerToRawData;\n        public uint PointerToRelocations;\n        public uint PointerToLinenumbers;\n        public ushort NumberOfRelocations;\n        public ushort NumberOfLinenumbers;\n        public uint Characteristics;\n    }\n\n    [Flags]\n    public enum SectionCharacteristics : uint\n    {\n        IMAGE_SCN_MEM_EXECUTE = 0x20000000,\n        IMAGE_SCN_MEM_READ = 0x40000000,\n        IMAGE_SCN_MEM_WRITE = 0x80000000\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/ExecutableFormats/WebAssembly.cs",
    "content": "﻿using System;\nusing System.IO;\n\nnamespace Il2CppDumper\n{\n    public sealed class WebAssembly : BinaryStream\n    {\n        private readonly DataSection[] dataSections;\n\n        public WebAssembly(Stream stream) : base(stream)\n        {\n            Is32Bit = true;\n            var magic = ReadUInt32();\n            var version = ReadInt32();\n            while (Position < Length)\n            {\n                var id = ReadULeb128();\n                var len = ReadULeb128();\n                if (id == 11)\n                {\n                    var count = ReadULeb128();\n                    dataSections = new DataSection[count];\n                    for (int i = 0; i < count; i++)\n                    {\n                        var dataSection = new DataSection();\n                        dataSections[i] = dataSection;\n                        dataSection.Index = ReadULeb128();\n                        var opCode = ReadByte();\n                        if (opCode != 0x41) //i32.const\n                        {\n                            throw new InvalidOperationException();\n                        }\n                        dataSection.Offset = ReadULeb128();\n                        opCode = ReadByte();\n                        if (opCode != 0xB) //end\n                        {\n                            throw new InvalidOperationException();\n                        }\n                        dataSection.Data = ReadBytes((int)ReadULeb128());\n                    }\n                    break;\n                }\n                Position += len;\n            }\n        }\n\n        public WebAssemblyMemory CreateMemory()\n        {\n            var last = dataSections[^1];\n            var bssStart = last.Offset + (uint)last.Data.Length;\n            var stream = new MemoryStream(new byte[Length]);\n            foreach (var dataSection in dataSections)\n            {\n                stream.Position = dataSection.Offset;\n                stream.Write(dataSection.Data, 0, dataSection.Data.Length);\n            }\n            return new WebAssemblyMemory(stream, bssStart);\n        }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/ExecutableFormats/WebAssemblyClass.cs",
    "content": "﻿namespace Il2CppDumper\n{\n    public class DataSection\n    {\n        public uint Index;\n        public uint Offset;\n        public byte[] Data;\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/ExecutableFormats/WebAssemblyMemory.cs",
    "content": "﻿using System.IO;\n\nnamespace Il2CppDumper\n{\n    public sealed class WebAssemblyMemory : Il2Cpp\n    {\n        private readonly uint bssStart;\n\n        public WebAssemblyMemory(Stream stream, uint bssStart) : base(stream)\n        {\n            Is32Bit = true;\n            this.bssStart = bssStart;\n        }\n\n        public override ulong MapVATR(ulong addr)\n        {\n            return addr;\n        }\n\n        public override ulong MapRTVA(ulong addr)\n        {\n            return addr;\n        }\n\n        public override bool PlusSearch(int methodCount, int typeDefinitionsCount, int imageCount)\n        {\n            var sectionHelper = GetSectionHelper(methodCount, typeDefinitionsCount, imageCount);\n            var codeRegistration = sectionHelper.FindCodeRegistration();\n            var metadataRegistration = sectionHelper.FindMetadataRegistration();\n            return AutoPlusInit(codeRegistration, metadataRegistration);\n        }\n\n        public override bool Search()\n        {\n            return false;\n        }\n\n        public override bool SymbolSearch()\n        {\n            return false;\n        }\n\n        public override SectionHelper GetSectionHelper(int methodCount, int typeDefinitionsCount, int imageCount)\n        {\n            var exec = new SearchSection\n            {\n                offset = 0,\n                offsetEnd = (ulong)methodCount, //hack\n                address = 0,\n                addressEnd = (ulong)methodCount //hack\n            };\n            var data = new SearchSection\n            {\n                offset = 1024,\n                offsetEnd = Length,\n                address = 1024,\n                addressEnd = Length\n            };\n            var bss = new SearchSection\n            {\n                offset = bssStart,\n                offsetEnd = long.MaxValue, //hack\n                address = bssStart,\n                addressEnd = long.MaxValue //hack\n            };\n            var sectionHelper = new SectionHelper(this, methodCount, typeDefinitionsCount, metadataUsagesCount, imageCount);\n            sectionHelper.SetSection(SearchSectionType.Exec, exec);\n            sectionHelper.SetSection(SearchSectionType.Data, data);\n            sectionHelper.SetSection(SearchSectionType.Bss, bss);\n            return sectionHelper;\n        }\n\n        public override bool CheckDump() => false;\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Extensions/BinaryReaderExtensions.cs",
    "content": "﻿using System;\nusing System.IO;\nusing System.Text;\n\nnamespace Il2CppDumper\n{\n    public static class BinaryReaderExtensions\n    {\n        public static string ReadString(this BinaryReader reader, int numChars)\n        {\n            var start = reader.BaseStream.Position;\n            // UTF8 takes up to 4 bytes per character\n            var str = Encoding.UTF8.GetString(reader.ReadBytes(numChars * 4))[..numChars];\n            // make our position what it would have been if we'd known the exact number of bytes needed.\n            reader.BaseStream.Position = start;\n            reader.ReadBytes(Encoding.UTF8.GetByteCount(str));\n            return str;\n        }\n\n        public static uint ReadULeb128(this BinaryReader reader)\n        {\n            uint value = reader.ReadByte();\n            if (value >= 0x80)\n            {\n                var bitshift = 0;\n                value &= 0x7f;\n                while (true)\n                {\n                    var b = reader.ReadByte();\n                    bitshift += 7;\n                    value |= (uint)((b & 0x7f) << bitshift);\n                    if (b < 0x80)\n                        break;\n                }\n            }\n            return value;\n        }\n\n        public static uint ReadCompressedUInt32(this BinaryReader reader)\n        {\n            uint val;\n            var read = reader.ReadByte();\n\n            if ((read & 0x80) == 0)\n            {\n                // 1 byte written\n                val = read;\n            }\n            else if ((read & 0xC0) == 0x80)\n            {\n                // 2 bytes written\n                val = (read & ~0x80u) << 8;\n                val |= reader.ReadByte();\n            }\n            else if ((read & 0xE0) == 0xC0)\n            {\n                // 4 bytes written\n                val = (read & ~0xC0u) << 24;\n                val |= ((uint)reader.ReadByte() << 16);\n                val |= ((uint)reader.ReadByte() << 8);\n                val |= reader.ReadByte();\n            }\n            else if (read == 0xF0)\n            {\n                // 5 bytes written, we had a really large int32!\n                val = reader.ReadUInt32();\n            }\n            else if (read == 0xFE)\n            {\n                // Special encoding for Int32.MaxValue\n                val = uint.MaxValue - 1;\n            }\n            else if (read == 0xFF)\n            {\n                // Yes we treat UInt32.MaxValue (and Int32.MinValue, see ReadCompressedInt32) specially\n                val = uint.MaxValue;\n            }\n            else\n            {\n                throw new Exception(\"Invalid compressed integer format\");\n            }\n\n            return val;\n        }\n\n        public static int ReadCompressedInt32(this BinaryReader reader)\n        {\n            var encoded = reader.ReadCompressedUInt32();\n\n            // -UINT32_MAX can't be represted safely in an int32_t, so we treat it specially\n            if (encoded == uint.MaxValue)\n                return int.MinValue;\n\n            bool isNegative = (encoded & 1) != 0;\n            encoded >>= 1;\n            if (isNegative)\n                return -(int)(encoded + 1);\n            return (int)encoded;\n        }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Extensions/BoyerMooreHorspool.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace Il2CppDumper\n{\n    static class BoyerMooreHorspool\n    {\n        public static IEnumerable<int> Search(this byte[] source, byte[] pattern)\n        {\n            if (source == null)\n            {\n                throw new ArgumentNullException(nameof(source));\n            }\n\n            if (pattern == null)\n            {\n                throw new ArgumentNullException(nameof(pattern));\n            }\n\n            int valueLength = source.Length;\n            int patternLength = pattern.Length;\n\n            if (valueLength == 0 || patternLength == 0 || patternLength > valueLength)\n            {\n                yield break;\n            }\n\n            var badCharacters = new int[256];\n\n            for (var i = 0; i < 256; i++)\n            {\n                badCharacters[i] = patternLength;\n            }\n\n            var lastPatternByte = patternLength - 1;\n\n            for (int i = 0; i < lastPatternByte; i++)\n            {\n                badCharacters[pattern[i]] = lastPatternByte - i;\n            }\n\n            int index = 0;\n\n            while (index <= valueLength - patternLength)\n            {\n                for (var i = lastPatternByte; source[index + i] == pattern[i]; i--)\n                {\n                    if (i == 0)\n                    {\n                        yield return index;\n                        break;\n                    }\n                }\n\n                index += badCharacters[source[index + lastPatternByte]];\n            }\n        }\n\n        public static IEnumerable<int> Search(this byte[] source, string stringPattern)\n        {\n            if (source == null)\n            {\n                throw new ArgumentNullException(nameof(source));\n            }\n\n            if (stringPattern == null)\n            {\n                throw new ArgumentNullException(nameof(stringPattern));\n            }\n\n            var pattern = stringPattern.Split(' ');\n\n            int valueLength = source.Length;\n            int patternLength = pattern.Length;\n\n            if (valueLength == 0 || patternLength == 0 || patternLength > valueLength)\n            {\n                yield break;\n            }\n\n            var badCharacters = new int[256];\n\n            for (var i = 0; i < 256; i++)\n            {\n                badCharacters[i] = patternLength;\n            }\n\n            var lastPatternByte = patternLength - 1;\n\n            for (int i = 0; i < lastPatternByte; i++)\n            {\n                if (pattern[i] != \"?\")\n                {\n                    var result = Convert.ToInt32(pattern[i], 16);\n                    badCharacters[result] = lastPatternByte - i;\n                }\n            }\n\n            int index = 0;\n\n            while (index <= valueLength - patternLength)\n            {\n                for (var i = lastPatternByte; CheckEqual(source, pattern, index, i); i--)\n                {\n                    if (i == 0)\n                    {\n                        yield return index;\n                        break;\n                    }\n                }\n\n                index += badCharacters[source[index + lastPatternByte]];\n            }\n        }\n\n        private static bool CheckEqual(byte[] source, string[] pattern, int index, int i)\n        {\n            if (pattern[i] != \"?\")\n            {\n                var result = Convert.ToInt32(pattern[i], 16);\n                return source[index + i] == result;\n            }\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Extensions/HexExtensions.cs",
    "content": "﻿using System;\nusing System.Text;\n\nnamespace Il2CppDumper\n{\n    static class HexExtensions\n    {\n        public static string HexToBin(this byte b)\n        {\n            return Convert.ToString(b, 2).PadLeft(8, '0');\n        }\n\n        public static string HexToBin(this byte[] bytes)\n        {\n            var result = new StringBuilder(bytes.Length * 8);\n            foreach (var b in bytes)\n            {\n                result.Insert(0, b.HexToBin());\n            }\n            return result.ToString();\n        }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Extensions/StringExtensions.cs",
    "content": "﻿using System.Text;\n\nnamespace Il2CppDumper\n{\n    public static class StringExtensions\n    {\n        public static string ToEscapedString(this string s)\n        {\n            var re = new StringBuilder(s.Length);\n            foreach (var c in s)\n            {\n                switch (c)\n                {\n                    case '\\'':\n                        re.Append(@\"\\'\");\n                        break;\n                    case '\"':\n                        re.Append(@\"\\\"\"\");\n                        break;\n                    case '\\\\':\n                        re.Append(@\"\\\\\");\n                        break;\n                    case '\\0':\n                        re.Append(@\"\\0\");\n                        break;\n                    case '\\a':\n                        re.Append(@\"\\a\");\n                        break;\n                    case '\\b':\n                        re.Append(@\"\\b\");\n                        break;\n                    case '\\f':\n                        re.Append(@\"\\f\");\n                        break;\n                    case '\\n':\n                        re.Append(@\"\\n\");\n                        break;\n                    case '\\r':\n                        re.Append(@\"\\r\");\n                        break;\n                    case '\\t':\n                        re.Append(@\"\\t\");\n                        break;\n                    case '\\v':\n                        re.Append(@\"\\v\");\n                        break;\n                    case '\\u0085':\n                        re.Append(@\"\\u0085\");\n                        break;\n                    case '\\u2028':\n                        re.Append(@\"\\u2028\");\n                        break;\n                    case '\\u2029':\n                        re.Append(@\"\\u2029\");\n                        break;\n                    default:\n                        re.Append(c);\n                        break;\n                }\n            }\n            return re.ToString();\n        }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/IO/BinaryStream.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing System.Text;\n\nnamespace Il2CppDumper\n{\n    public class BinaryStream : IDisposable\n    {\n        public double Version;\n        public bool Is32Bit;\n        public ulong ImageBase;\n        private readonly Stream stream;\n        private readonly BinaryReader reader;\n        private readonly BinaryWriter writer;\n        private readonly MethodInfo readClass;\n        private readonly MethodInfo readClassArray;\n        private readonly Dictionary<Type, MethodInfo> genericMethodCache;\n        private readonly Dictionary<FieldInfo, VersionAttribute[]> attributeCache;\n\n        public BinaryStream(Stream input)\n        {\n            stream = input;\n            reader = new BinaryReader(stream, Encoding.UTF8, true);\n            writer = new BinaryWriter(stream, Encoding.UTF8, true);\n            readClass = GetType().GetMethod(\"ReadClass\", Type.EmptyTypes);\n            readClassArray = GetType().GetMethod(\"ReadClassArray\", new[] { typeof(long) });\n            genericMethodCache = new();\n            attributeCache = new();\n        }\n\n        public bool ReadBoolean() => reader.ReadBoolean();\n\n        public byte ReadByte() => reader.ReadByte();\n\n        public byte[] ReadBytes(int count) => reader.ReadBytes(count);\n\n        public sbyte ReadSByte() => reader.ReadSByte();\n\n        public short ReadInt16() => reader.ReadInt16();\n\n        public ushort ReadUInt16() => reader.ReadUInt16();\n\n        public int ReadInt32() => reader.ReadInt32();\n\n        public uint ReadUInt32() => reader.ReadUInt32();\n\n        public long ReadInt64() => reader.ReadInt64();\n\n        public ulong ReadUInt64() => reader.ReadUInt64();\n\n        public float ReadSingle() => reader.ReadSingle();\n\n        public double ReadDouble() => reader.ReadDouble();\n\n        public uint ReadCompressedUInt32() => reader.ReadCompressedUInt32();\n\n        public int ReadCompressedInt32() => reader.ReadCompressedInt32();\n\n        public uint ReadULeb128() => reader.ReadULeb128();\n\n        public void Write(bool value) => writer.Write(value);\n\n        public void Write(byte value) => writer.Write(value);\n\n        public void Write(sbyte value) => writer.Write(value);\n\n        public void Write(short value) => writer.Write(value);\n\n        public void Write(ushort value) => writer.Write(value);\n\n        public void Write(int value) => writer.Write(value);\n\n        public void Write(uint value) => writer.Write(value);\n\n        public void Write(long value) => writer.Write(value);\n\n        public void Write(ulong value) => writer.Write(value);\n\n        public void Write(float value) => writer.Write(value);\n\n        public void Write(double value) => writer.Write(value);\n\n        public ulong Position\n        {\n            get => (ulong)stream.Position;\n            set => stream.Position = (long)value;\n        }\n\n        public ulong Length => (ulong)stream.Length;\n\n        private object ReadPrimitive(Type type)\n        {\n            return type.Name switch\n            {\n                \"Int32\" => ReadInt32(),\n                \"UInt32\" => ReadUInt32(),\n                \"Int16\" => ReadInt16(),\n                \"UInt16\" => ReadUInt16(),\n                \"Byte\" => ReadByte(),\n                \"Int64\" => ReadIntPtr(),\n                \"UInt64\" => ReadUIntPtr(),\n                _ => throw new NotSupportedException()\n            };\n        }\n\n        public T ReadClass<T>(ulong addr) where T : new()\n        {\n            Position = addr;\n            return ReadClass<T>();\n        }\n\n        public T ReadClass<T>() where T : new()\n        {\n            var type = typeof(T);\n            if (type.IsPrimitive)\n            {\n                return (T)ReadPrimitive(type);\n            }\n            else\n            {\n                var t = new T();\n                foreach (var i in t.GetType().GetFields())\n                {\n                    if (!attributeCache.TryGetValue(i, out var versionAttributes))\n                    {\n                        if (Attribute.IsDefined(i, typeof(VersionAttribute)))\n                        {\n                            versionAttributes = i.GetCustomAttributes<VersionAttribute>().ToArray();\n                            attributeCache.Add(i, versionAttributes);\n                        }\n                    }\n                    if (versionAttributes?.Length > 0)\n                    {\n                        var read = false;\n                        foreach (var versionAttribute in versionAttributes)\n                        {\n                            if (Version >= versionAttribute.Min && Version <= versionAttribute.Max)\n                            {\n                                read = true;\n                                break;\n                            }\n                        }\n                        if (!read)\n                        {\n                            continue;\n                        }\n                    }\n                    var fieldType = i.FieldType;\n                    if (fieldType.IsPrimitive)\n                    {\n                        i.SetValue(t, ReadPrimitive(fieldType));\n                    }\n                    else if (fieldType.IsEnum)\n                    {\n                        var e = fieldType.GetField(\"value__\").FieldType;\n                        i.SetValue(t, ReadPrimitive(e));\n                    }\n                    else if (fieldType.IsArray)\n                    {\n                        var arrayLengthAttribute = i.GetCustomAttribute<ArrayLengthAttribute>();\n                        if (!genericMethodCache.TryGetValue(fieldType, out var methodInfo))\n                        {\n                            methodInfo = readClassArray.MakeGenericMethod(fieldType.GetElementType());\n                            genericMethodCache.Add(fieldType, methodInfo);\n                        }\n                        i.SetValue(t, methodInfo.Invoke(this, new object[] { arrayLengthAttribute.Length }));\n                    }\n                    else\n                    {\n                        if (!genericMethodCache.TryGetValue(fieldType, out var methodInfo))\n                        {\n                            methodInfo = readClass.MakeGenericMethod(fieldType);\n                            genericMethodCache.Add(fieldType, methodInfo);\n                        }\n                        i.SetValue(t, methodInfo.Invoke(this, null));\n                    }\n                }\n                return t;\n            }\n        }\n\n        public T[] ReadClassArray<T>(long count) where T : new()\n        {\n            var t = new T[count];\n            for (var i = 0; i < count; i++)\n            {\n                t[i] = ReadClass<T>();\n            }\n            return t;\n        }\n\n        public T[] ReadClassArray<T>(ulong addr, ulong count) where T : new()\n        {\n            return ReadClassArray<T>(addr, (long)count);\n        }\n\n        public T[] ReadClassArray<T>(ulong addr, long count) where T : new()\n        {\n            Position = addr;\n            return ReadClassArray<T>(count);\n        }\n\n        public string ReadStringToNull(ulong addr)\n        {\n            Position = addr;\n            var bytes = new List<byte>();\n            byte b;\n            while ((b = ReadByte()) != 0)\n                bytes.Add(b);\n            return Encoding.UTF8.GetString(bytes.ToArray());\n        }\n\n        public long ReadIntPtr()\n        {\n            return Is32Bit ? ReadInt32() : ReadInt64();\n        }\n\n        public virtual ulong ReadUIntPtr()\n        {\n            return Is32Bit ? ReadUInt32() : ReadUInt64();\n        }\n\n        public ulong PointerSize\n        {\n            get => Is32Bit ? 4ul : 8ul;\n        }\n\n        public BinaryReader Reader => reader;\n\n        public BinaryWriter Writer => writer;\n\n        protected virtual void Dispose(bool disposing)\n        {\n            if (disposing)\n            {\n                reader.Dispose();\n                writer.Dispose();\n                stream.Close();\n            }\n        }\n\n        public void Dispose()\n        {\n            Dispose(true);\n            GC.SuppressFinalize(this);\n        }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/IO/Lz4DecoderStream.cs",
    "content": "﻿#define CHECK_ARGS\n#define CHECK_EOF\n//#define LOCAL_SHADOW\n\nusing System;\nusing System.IO;\n\nnamespace Il2CppDumper\n{\n    public class Lz4DecoderStream : Stream\n    {\n        public Lz4DecoderStream(Stream input, long inputLength = long.MaxValue)\n        {\n            Reset(input, inputLength);\n        }\n\n        private void Reset(Stream input, long inputLength = long.MaxValue)\n        {\n            this.inputLength = inputLength;\n            this.input = input;\n\n            phase = DecodePhase.ReadToken;\n\n            decodeBufferPos = 0;\n\n            litLen = 0;\n            matLen = 0;\n            matDst = 0;\n\n            inBufPos = DecBufLen;\n            inBufEnd = DecBufLen;\n        }\n\n        protected override void Dispose(bool disposing)\n        {\n            try\n            {\n                if (disposing && input != null)\n                {\n                    input.Close();\n                }\n                input = null;\n                decodeBuffer = null;\n            }\n            finally\n            {\n                base.Dispose(disposing);\n            }\n        }\n\n        private long inputLength;\n        private Stream input;\n\n        //because we might not be able to match back across invocations,\n        //we have to keep the last window's worth of bytes around for reuse\n        //we use a circular buffer for this - every time we write into this\n        //buffer, we also write the same into our output buffer\n\n        private const int DecBufLen = 0x10000;\n        private const int DecBufMask = 0xFFFF;\n\n        private const int InBufLen = 128;\n\n        private byte[] decodeBuffer = new byte[DecBufLen + InBufLen];\n        private int decodeBufferPos, inBufPos, inBufEnd;\n\n        //we keep track of which phase we're in so that we can jump right back\n        //into the correct part of decoding\n\n        private DecodePhase phase;\n\n        private enum DecodePhase\n        {\n            ReadToken,\n            ReadExLiteralLength,\n            CopyLiteral,\n            ReadOffset,\n            ReadExMatchLength,\n            CopyMatch,\n        }\n\n        //state within interruptable phases and across phase boundaries is\n        //kept here - again, so that we can punt out and restart freely\n\n        private int litLen, matLen, matDst;\n\n        public override int Read(byte[] buffer, int offset, int count)\n        {\n#if CHECK_ARGS\n            if (buffer == null)\n                throw new ArgumentNullException(\"buffer\");\n            if (offset < 0 || count < 0 || buffer.Length - count < offset)\n                throw new ArgumentOutOfRangeException();\n\n            if (input == null)\n                throw new InvalidOperationException();\n#endif\n            int nRead, nToRead = count;\n\n            var decBuf = decodeBuffer;\n\n            //the stringy gotos are obnoxious, but their purpose is to\n            //make it *blindingly* obvious how the state machine transitions\n            //back and forth as it reads - remember, we can yield out of\n            //this routine in several places, and we must be able to re-enter\n            //and pick up where we left off!\n\n#if LOCAL_SHADOW\n\t\t\tvar phase = this.phase;\n\t\t\tvar inBufPos = this.inBufPos;\n\t\t\tvar inBufEnd = this.inBufEnd;\n#endif\n            switch (phase)\n            {\n                case DecodePhase.ReadToken:\n                    goto readToken;\n\n                case DecodePhase.ReadExLiteralLength:\n                    goto readExLiteralLength;\n\n                case DecodePhase.CopyLiteral:\n                    goto copyLiteral;\n\n                case DecodePhase.ReadOffset:\n                    goto readOffset;\n\n                case DecodePhase.ReadExMatchLength:\n                    goto readExMatchLength;\n\n                case DecodePhase.CopyMatch:\n                    goto copyMatch;\n            }\n\n        readToken:\n            int tok;\n            if (inBufPos < inBufEnd)\n            {\n                tok = decBuf[inBufPos++];\n            }\n            else\n            {\n#if LOCAL_SHADOW\n\t\t\t\tthis.inBufPos = inBufPos;\n#endif\n\n                tok = ReadByteCore();\n#if LOCAL_SHADOW\n\t\t\t\tinBufPos = this.inBufPos;\n\t\t\t\tinBufEnd = this.inBufEnd;\n#endif\n#if CHECK_EOF\n                if (tok == -1)\n                    goto finish;\n#endif\n            }\n\n            litLen = tok >> 4;\n            matLen = (tok & 0xF) + 4;\n\n            switch (litLen)\n            {\n                case 0:\n                    phase = DecodePhase.ReadOffset;\n                    goto readOffset;\n\n                case 0xF:\n                    phase = DecodePhase.ReadExLiteralLength;\n                    goto readExLiteralLength;\n\n                default:\n                    phase = DecodePhase.CopyLiteral;\n                    goto copyLiteral;\n            }\n\n        readExLiteralLength:\n            int exLitLen;\n            if (inBufPos < inBufEnd)\n            {\n                exLitLen = decBuf[inBufPos++];\n            }\n            else\n            {\n#if LOCAL_SHADOW\n\t\t\t\tthis.inBufPos = inBufPos;\n#endif\n                exLitLen = ReadByteCore();\n#if LOCAL_SHADOW\n\t\t\t\tinBufPos = this.inBufPos;\n\t\t\t\tinBufEnd = this.inBufEnd;\n#endif\n\n#if CHECK_EOF\n                if (exLitLen == -1)\n                    goto finish;\n#endif\n            }\n\n            litLen += exLitLen;\n            if (exLitLen == 255)\n                goto readExLiteralLength;\n\n            phase = DecodePhase.CopyLiteral;\n            goto copyLiteral;\n\n        copyLiteral:\n            int nReadLit = litLen < nToRead ? litLen : nToRead;\n            if (nReadLit != 0)\n            {\n                if (inBufPos + nReadLit <= inBufEnd)\n                {\n                    int ofs = offset;\n\n                    for (int c = nReadLit; c-- != 0;)\n                        buffer[ofs++] = decBuf[inBufPos++];\n\n                    nRead = nReadLit;\n                }\n                else\n                {\n#if LOCAL_SHADOW\n\t\t\t\t\tthis.inBufPos = inBufPos;\n#endif\n                    nRead = ReadCore(buffer, offset, nReadLit);\n#if LOCAL_SHADOW\n\t\t\t\t\tinBufPos = this.inBufPos;\n\t\t\t\t\tinBufEnd = this.inBufEnd;\n#endif\n#if CHECK_EOF\n                    if (nRead == 0)\n                        goto finish;\n#endif\n                }\n\n                offset += nRead;\n                nToRead -= nRead;\n\n                litLen -= nRead;\n\n                if (litLen != 0)\n                    goto copyLiteral;\n            }\n\n            if (nToRead == 0)\n                goto finish;\n\n            phase = DecodePhase.ReadOffset;\n            goto readOffset;\n\n        readOffset:\n            if (inBufPos + 1 < inBufEnd)\n            {\n                matDst = (decBuf[inBufPos + 1] << 8) | decBuf[inBufPos];\n                inBufPos += 2;\n            }\n            else\n            {\n#if LOCAL_SHADOW\n\t\t\t\tthis.inBufPos = inBufPos;\n#endif\n                matDst = ReadOffsetCore();\n#if LOCAL_SHADOW\n\t\t\t\tinBufPos = this.inBufPos;\n\t\t\t\tinBufEnd = this.inBufEnd;\n#endif\n#if CHECK_EOF\n                if (matDst == -1)\n                    goto finish;\n#endif\n            }\n\n            if (matLen == 15 + 4)\n            {\n                phase = DecodePhase.ReadExMatchLength;\n                goto readExMatchLength;\n            }\n            else\n            {\n                phase = DecodePhase.CopyMatch;\n                goto copyMatch;\n            }\n\n        readExMatchLength:\n            int exMatLen;\n            if (inBufPos < inBufEnd)\n            {\n                exMatLen = decBuf[inBufPos++];\n            }\n            else\n            {\n#if LOCAL_SHADOW\n\t\t\t\tthis.inBufPos = inBufPos;\n#endif\n                exMatLen = ReadByteCore();\n#if LOCAL_SHADOW\n\t\t\t\tinBufPos = this.inBufPos;\n\t\t\t\tinBufEnd = this.inBufEnd;\n#endif\n#if CHECK_EOF\n                if (exMatLen == -1)\n                    goto finish;\n#endif\n            }\n\n            matLen += exMatLen;\n            if (exMatLen == 255)\n                goto readExMatchLength;\n\n            phase = DecodePhase.CopyMatch;\n            goto copyMatch;\n\n        copyMatch:\n            int nCpyMat = matLen < nToRead ? matLen : nToRead;\n            if (nCpyMat != 0)\n            {\n                nRead = count - nToRead;\n\n                int bufDst = matDst - nRead;\n                if (bufDst > 0)\n                {\n                    //offset is fairly far back, we need to pull from the buffer\n\n                    int bufSrc = decodeBufferPos - bufDst;\n                    if (bufSrc < 0)\n                        bufSrc += DecBufLen;\n                    int bufCnt = bufDst < nCpyMat ? bufDst : nCpyMat;\n\n                    for (int c = bufCnt; c-- != 0;)\n                        buffer[offset++] = decBuf[bufSrc++ & DecBufMask];\n                }\n                else\n                {\n                    bufDst = 0;\n                }\n\n                int sOfs = offset - matDst;\n                for (int i = bufDst; i < nCpyMat; i++)\n                    buffer[offset++] = buffer[sOfs++];\n\n                nToRead -= nCpyMat;\n                matLen -= nCpyMat;\n            }\n\n            if (nToRead == 0)\n                goto finish;\n\n            phase = DecodePhase.ReadToken;\n            goto readToken;\n\n        finish:\n            nRead = count - nToRead;\n\n            int nToBuf = nRead < DecBufLen ? nRead : DecBufLen;\n            int repPos = offset - nToBuf;\n\n            if (nToBuf == DecBufLen)\n            {\n                Buffer.BlockCopy(buffer, repPos, decBuf, 0, DecBufLen);\n                decodeBufferPos = 0;\n            }\n            else\n            {\n                int decPos = decodeBufferPos;\n\n                while (nToBuf-- != 0)\n                    decBuf[decPos++ & DecBufMask] = buffer[repPos++];\n\n                decodeBufferPos = decPos & DecBufMask;\n            }\n\n#if LOCAL_SHADOW\n\t\t\tthis.phase = phase;\n\t\t\tthis.inBufPos = inBufPos;\n#endif\n            return nRead;\n        }\n\n        private int ReadByteCore()\n        {\n            var buf = decodeBuffer;\n\n            if (inBufPos == inBufEnd)\n            {\n                int nRead = input.Read(buf, DecBufLen,\n                    InBufLen < inputLength ? InBufLen : (int)inputLength);\n\n#if CHECK_EOF\n                if (nRead == 0)\n                    return -1;\n#endif\n\n                inputLength -= nRead;\n\n                inBufPos = DecBufLen;\n                inBufEnd = DecBufLen + nRead;\n            }\n\n            return buf[inBufPos++];\n        }\n\n        private int ReadOffsetCore()\n        {\n            var buf = decodeBuffer;\n\n            if (inBufPos == inBufEnd)\n            {\n                int nRead = input.Read(buf, DecBufLen,\n                    InBufLen < inputLength ? InBufLen : (int)inputLength);\n\n#if CHECK_EOF\n                if (nRead == 0)\n                    return -1;\n#endif\n\n                inputLength -= nRead;\n\n                inBufPos = DecBufLen;\n                inBufEnd = DecBufLen + nRead;\n            }\n\n            if (inBufEnd - inBufPos == 1)\n            {\n                buf[DecBufLen] = buf[inBufPos];\n\n                int nRead = input.Read(buf, DecBufLen + 1,\n                    InBufLen - 1 < inputLength ? InBufLen - 1 : (int)inputLength);\n\n#if CHECK_EOF\n                if (nRead == 0)\n                {\n                    inBufPos = DecBufLen;\n                    inBufEnd = DecBufLen + 1;\n\n                    return -1;\n                }\n#endif\n\n                inputLength -= nRead;\n\n                inBufPos = DecBufLen;\n                inBufEnd = DecBufLen + nRead + 1;\n            }\n\n            int ret = (buf[inBufPos + 1] << 8) | buf[inBufPos];\n            inBufPos += 2;\n\n            return ret;\n        }\n\n        private int ReadCore(byte[] buffer, int offset, int count)\n        {\n            int nToRead = count;\n\n            var buf = decodeBuffer;\n            int inBufLen = inBufEnd - inBufPos;\n\n            int fromBuf = nToRead < inBufLen ? nToRead : inBufLen;\n            if (fromBuf != 0)\n            {\n                var bufPos = inBufPos;\n\n                for (int c = fromBuf; c-- != 0;)\n                    buffer[offset++] = buf[bufPos++];\n\n                inBufPos = bufPos;\n                nToRead -= fromBuf;\n            }\n\n            if (nToRead != 0)\n            {\n                int nRead;\n\n                if (nToRead >= InBufLen)\n                {\n                    nRead = input.Read(buffer, offset,\n                        nToRead < inputLength ? nToRead : (int)inputLength);\n                    nToRead -= nRead;\n                }\n                else\n                {\n                    nRead = input.Read(buf, DecBufLen,\n                        InBufLen < inputLength ? InBufLen : (int)inputLength);\n\n                    inBufPos = DecBufLen;\n                    inBufEnd = DecBufLen + nRead;\n\n                    fromBuf = nToRead < nRead ? nToRead : nRead;\n\n                    var bufPos = inBufPos;\n\n                    for (int c = fromBuf; c-- != 0;)\n                        buffer[offset++] = buf[bufPos++];\n\n                    inBufPos = bufPos;\n                    nToRead -= fromBuf;\n                }\n\n                inputLength -= nRead;\n            }\n\n            return count - nToRead;\n        }\n\n        #region Stream internals\n\n        public override bool CanRead => true;\n\n        public override bool CanSeek => false;\n\n        public override bool CanWrite => false;\n\n        public override void Flush()\n        {\n        }\n\n        public override long Length => throw new NotSupportedException();\n\n        public override long Position\n        {\n            get => throw new NotSupportedException();\n            set => throw new NotSupportedException();\n        }\n\n        public override long Seek(long offset, SeekOrigin origin)\n        {\n            throw new NotSupportedException();\n        }\n\n        public override void SetLength(long value)\n        {\n            throw new NotSupportedException();\n        }\n\n        public override void Write(byte[] buffer, int offset, int count)\n        {\n            throw new NotSupportedException();\n        }\n\n        #endregion\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Il2Cpp/Il2Cpp.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\n\nnamespace Il2CppDumper\n{\n    public abstract class Il2Cpp : BinaryStream\n    {\n        private Il2CppMetadataRegistration pMetadataRegistration;\n        private Il2CppCodeRegistration pCodeRegistration;\n        public ulong[] methodPointers;\n        public ulong[] genericMethodPointers;\n        public ulong[] invokerPointers;\n        public ulong[] customAttributeGenerators;\n        public ulong[] reversePInvokeWrappers;\n        public ulong[] unresolvedVirtualCallPointers;\n        private ulong[] fieldOffsets;\n        public Il2CppType[] types;\n        private readonly Dictionary<ulong, Il2CppType> typeDic = new();\n        public ulong[] metadataUsages;\n        private Il2CppGenericMethodFunctionsDefinitions[] genericMethodTable;\n        public ulong[] genericInstPointers;\n        public Il2CppGenericInst[] genericInsts;\n        public Il2CppMethodSpec[] methodSpecs;\n        public Dictionary<int, List<Il2CppMethodSpec>> methodDefinitionMethodSpecs = new();\n        public Dictionary<Il2CppMethodSpec, ulong> methodSpecGenericMethodPointers = new();\n        private bool fieldOffsetsArePointers;\n        protected long metadataUsagesCount;\n        public Dictionary<string, Il2CppCodeGenModule> codeGenModules;\n        public Dictionary<string, ulong[]> codeGenModuleMethodPointers;\n        public Dictionary<string, Dictionary<uint, Il2CppRGCTXDefinition[]>> rgctxsDictionary;\n        public bool IsDumped;\n\n        public abstract ulong MapVATR(ulong addr);\n        public abstract ulong MapRTVA(ulong addr);\n        public abstract bool Search();\n        public abstract bool PlusSearch(int methodCount, int typeDefinitionsCount, int imageCount);\n        public abstract bool SymbolSearch();\n        public abstract SectionHelper GetSectionHelper(int methodCount, int typeDefinitionsCount, int imageCount);\n        public abstract bool CheckDump();\n\n        protected Il2Cpp(Stream stream) : base(stream) { }\n\n        public void SetProperties(double version, long metadataUsagesCount)\n        {\n            Version = version;\n            this.metadataUsagesCount = metadataUsagesCount;\n        }\n\n        protected bool AutoPlusInit(ulong codeRegistration, ulong metadataRegistration)\n        {\n            if (codeRegistration != 0)\n            {\n                var limit = this is WebAssemblyMemory ? 0x35000u : 0x50000u; //TODO\n                if (Version >= 24.2)\n                {\n                    pCodeRegistration = MapVATR<Il2CppCodeRegistration>(codeRegistration);\n                    if (Version == 31)\n                    {\n                        if (pCodeRegistration.genericMethodPointersCount > limit)\n                        {\n                            codeRegistration -= PointerSize * 2;\n                        }\n                        else\n                        {\n                            Version = 29;\n                            Console.WriteLine($\"Change il2cpp version to: {Version}\");\n                        }\n                    }\n                    if (Version == 29)\n                    {\n                        if (pCodeRegistration.genericMethodPointersCount > limit)\n                        {\n                            Version = 29.1;\n                            codeRegistration -= PointerSize * 2;\n                            Console.WriteLine($\"Change il2cpp version to: {Version}\");\n                        }\n                    }\n                    if (Version == 27)\n                    {\n                        if (pCodeRegistration.reversePInvokeWrapperCount > limit)\n                        {\n                            Version = 27.1;\n                            codeRegistration -= PointerSize;\n                            Console.WriteLine($\"Change il2cpp version to: {Version}\");\n                        }\n                    }\n                    if (Version == 24.4)\n                    {\n                        codeRegistration -= PointerSize * 2;\n                        if (pCodeRegistration.reversePInvokeWrapperCount > limit)\n                        {\n                            Version = 24.5;\n                            codeRegistration -= PointerSize;\n                            Console.WriteLine($\"Change il2cpp version to: {Version}\");\n                        }\n                    }\n                    if (Version == 24.2)\n                    {\n                        if (pCodeRegistration.interopDataCount == 0) //TODO\n                        {\n                            Version = 24.3;\n                            codeRegistration -= PointerSize * 2;\n                            Console.WriteLine($\"Change il2cpp version to: {Version}\");\n                        }\n                    }\n                }\n            }\n            Console.WriteLine(\"CodeRegistration : {0:x}\", codeRegistration);\n            Console.WriteLine(\"MetadataRegistration : {0:x}\", metadataRegistration);\n            if (codeRegistration != 0 && metadataRegistration != 0)\n            {\n                Init(codeRegistration, metadataRegistration);\n                return true;\n            }\n            return false;\n        }\n\n        public virtual void Init(ulong codeRegistration, ulong metadataRegistration)\n        {\n            pCodeRegistration = MapVATR<Il2CppCodeRegistration>(codeRegistration);\n            var limit = this is WebAssemblyMemory ? 0x35000u : 0x50000u; //TODO\n            if (Version == 27 && pCodeRegistration.invokerPointersCount > limit)\n            {\n                Version = 27.1;\n                Console.WriteLine($\"Change il2cpp version to: {Version}\");\n                pCodeRegistration = MapVATR<Il2CppCodeRegistration>(codeRegistration);\n            }\n            if (Version == 27.1)\n            {\n                var pCodeGenModules = MapVATR<ulong>(pCodeRegistration.codeGenModules, pCodeRegistration.codeGenModulesCount);\n                foreach (var pCodeGenModule in pCodeGenModules)\n                {\n                    var codeGenModule = MapVATR<Il2CppCodeGenModule>(pCodeGenModule);\n                    if (codeGenModule.rgctxsCount > 0)\n                    {\n                        var rgctxs = MapVATR<Il2CppRGCTXDefinition>(codeGenModule.rgctxs, codeGenModule.rgctxsCount);\n                        if (rgctxs.All(x => x.data.rgctxDataDummy > limit))\n                        {\n                            Version = 27.2;\n                            Console.WriteLine($\"Change il2cpp version to: {Version}\");\n                        }\n                        break;\n                    }\n                }\n            }\n            if (Version == 24.4 && pCodeRegistration.invokerPointersCount > limit)\n            {\n                Version = 24.5;\n                Console.WriteLine($\"Change il2cpp version to: {Version}\");\n                pCodeRegistration = MapVATR<Il2CppCodeRegistration>(codeRegistration);\n            }\n            if (Version == 24.2 && pCodeRegistration.codeGenModules == 0) //TODO\n            {\n                Version = 24.3;\n                Console.WriteLine($\"Change il2cpp version to: {Version}\");\n                pCodeRegistration = MapVATR<Il2CppCodeRegistration>(codeRegistration);\n            }\n            pMetadataRegistration = MapVATR<Il2CppMetadataRegistration>(metadataRegistration);\n            genericMethodPointers = MapVATR<ulong>(pCodeRegistration.genericMethodPointers, pCodeRegistration.genericMethodPointersCount);\n            invokerPointers = MapVATR<ulong>(pCodeRegistration.invokerPointers, pCodeRegistration.invokerPointersCount);\n            if (Version < 27)\n            {\n                customAttributeGenerators = MapVATR<ulong>(pCodeRegistration.customAttributeGenerators, pCodeRegistration.customAttributeCount);\n            }\n            if (Version > 16 && Version < 27)\n            {\n                metadataUsages = MapVATR<ulong>(pMetadataRegistration.metadataUsages, metadataUsagesCount);\n            }\n            if (Version >= 22)\n            {\n                if (pCodeRegistration.reversePInvokeWrapperCount != 0)\n                    reversePInvokeWrappers = MapVATR<ulong>(pCodeRegistration.reversePInvokeWrappers, pCodeRegistration.reversePInvokeWrapperCount);\n                if (pCodeRegistration.unresolvedVirtualCallCount != 0)\n                    unresolvedVirtualCallPointers = MapVATR<ulong>(pCodeRegistration.unresolvedVirtualCallPointers, pCodeRegistration.unresolvedVirtualCallCount);\n            }\n            genericInstPointers = MapVATR<ulong>(pMetadataRegistration.genericInsts, pMetadataRegistration.genericInstsCount);\n            genericInsts = Array.ConvertAll(genericInstPointers, MapVATR<Il2CppGenericInst>);\n            fieldOffsetsArePointers = Version > 21;\n            if (Version == 21)\n            {\n                var fieldTest = MapVATR<uint>(pMetadataRegistration.fieldOffsets, 6);\n                fieldOffsetsArePointers = fieldTest[0] == 0 && fieldTest[1] == 0 && fieldTest[2] == 0 && fieldTest[3] == 0 && fieldTest[4] == 0 && fieldTest[5] > 0;\n            }\n            if (fieldOffsetsArePointers)\n            {\n                fieldOffsets = MapVATR<ulong>(pMetadataRegistration.fieldOffsets, pMetadataRegistration.fieldOffsetsCount);\n            }\n            else\n            {\n                fieldOffsets = Array.ConvertAll(MapVATR<uint>(pMetadataRegistration.fieldOffsets, pMetadataRegistration.fieldOffsetsCount), x => (ulong)x);\n            }\n            var pTypes = MapVATR<ulong>(pMetadataRegistration.types, pMetadataRegistration.typesCount);\n            types = new Il2CppType[pMetadataRegistration.typesCount];\n            for (var i = 0; i < pMetadataRegistration.typesCount; ++i)\n            {\n                types[i] = MapVATR<Il2CppType>(pTypes[i]);\n                types[i].Init(Version);\n                typeDic.Add(pTypes[i], types[i]);\n            }\n            if (Version >= 24.2)\n            {\n                var pCodeGenModules = MapVATR<ulong>(pCodeRegistration.codeGenModules, pCodeRegistration.codeGenModulesCount);\n                codeGenModules = new Dictionary<string, Il2CppCodeGenModule>(pCodeGenModules.Length, StringComparer.Ordinal);\n                codeGenModuleMethodPointers = new Dictionary<string, ulong[]>(pCodeGenModules.Length, StringComparer.Ordinal);\n                rgctxsDictionary = new Dictionary<string, Dictionary<uint, Il2CppRGCTXDefinition[]>>(pCodeGenModules.Length, StringComparer.Ordinal);\n                foreach (var pCodeGenModule in pCodeGenModules)\n                {\n                    var codeGenModule = MapVATR<Il2CppCodeGenModule>(pCodeGenModule);\n                    var moduleName = ReadStringToNull(MapVATR(codeGenModule.moduleName));\n                    codeGenModules.Add(moduleName, codeGenModule);\n                    ulong[] methodPointers;\n                    try\n                    {\n                        methodPointers = MapVATR<ulong>(codeGenModule.methodPointers, codeGenModule.methodPointerCount);\n                    }\n                    catch\n                    {\n                        methodPointers = new ulong[codeGenModule.methodPointerCount];\n                    }\n                    codeGenModuleMethodPointers.Add(moduleName, methodPointers);\n\n                    var rgctxsDefDictionary = new Dictionary<uint, Il2CppRGCTXDefinition[]>();\n                    rgctxsDictionary.Add(moduleName, rgctxsDefDictionary);\n                    if (codeGenModule.rgctxsCount > 0)\n                    {\n                        var rgctxs = MapVATR<Il2CppRGCTXDefinition>(codeGenModule.rgctxs, codeGenModule.rgctxsCount);\n                        var rgctxRanges = MapVATR<Il2CppTokenRangePair>(codeGenModule.rgctxRanges, codeGenModule.rgctxRangesCount);\n                        foreach (var rgctxRange in rgctxRanges)\n                        {\n                            var rgctxDefs = new Il2CppRGCTXDefinition[rgctxRange.range.length];\n                            Array.Copy(rgctxs, rgctxRange.range.start, rgctxDefs, 0, rgctxRange.range.length);\n                            rgctxsDefDictionary.Add(rgctxRange.token, rgctxDefs);\n                        }\n                    }\n                }\n            }\n            else\n            {\n                methodPointers = MapVATR<ulong>(pCodeRegistration.methodPointers, pCodeRegistration.methodPointersCount);\n            }\n            genericMethodTable = MapVATR<Il2CppGenericMethodFunctionsDefinitions>(pMetadataRegistration.genericMethodTable, pMetadataRegistration.genericMethodTableCount);\n            methodSpecs = MapVATR<Il2CppMethodSpec>(pMetadataRegistration.methodSpecs, pMetadataRegistration.methodSpecsCount);\n            foreach (var table in genericMethodTable)\n            {\n                var methodSpec = methodSpecs[table.genericMethodIndex];\n                var methodDefinitionIndex = methodSpec.methodDefinitionIndex;\n                if (!methodDefinitionMethodSpecs.TryGetValue(methodDefinitionIndex, out var list))\n                {\n                    list = new List<Il2CppMethodSpec>();\n                    methodDefinitionMethodSpecs.Add(methodDefinitionIndex, list);\n                }\n                list.Add(methodSpec);\n                methodSpecGenericMethodPointers.Add(methodSpec, genericMethodPointers[table.indices.methodIndex]);\n            }\n        }\n\n        public T MapVATR<T>(ulong addr) where T : new()\n        {\n            return ReadClass<T>(MapVATR(addr));\n        }\n\n        public T[] MapVATR<T>(ulong addr, ulong count) where T : new()\n        {\n            return ReadClassArray<T>(MapVATR(addr), count);\n        }\n\n        public T[] MapVATR<T>(ulong addr, long count) where T : new()\n        {\n            return ReadClassArray<T>(MapVATR(addr), count);\n        }\n\n        public int GetFieldOffsetFromIndex(int typeIndex, int fieldIndexInType, int fieldIndex, bool isValueType, bool isStatic)\n        {\n            try\n            {\n                var offset = -1;\n                if (fieldOffsetsArePointers)\n                {\n                    var ptr = fieldOffsets[typeIndex];\n                    if (ptr > 0)\n                    {\n                        Position = MapVATR(ptr) + 4ul * (ulong)fieldIndexInType;\n                        offset = ReadInt32();\n                    }\n                }\n                else\n                {\n                    offset = (int)fieldOffsets[fieldIndex];\n                }\n                if (offset > 0)\n                {\n                    if (isValueType && !isStatic)\n                    {\n                        if (Is32Bit)\n                        {\n                            offset -= 8;\n                        }\n                        else\n                        {\n                            offset -= 16;\n                        }\n                    }\n                }\n                return offset;\n            }\n            catch\n            {\n                return -1;\n            }\n        }\n\n        public Il2CppType GetIl2CppType(ulong pointer)\n        {\n            if (!typeDic.TryGetValue(pointer, out var type))\n            {\n                return null;\n            }\n            return type;\n        }\n\n        public ulong GetMethodPointer(string imageName, Il2CppMethodDefinition methodDef)\n        {\n            if (Version >= 24.2)\n            {\n                var methodToken = methodDef.token;\n                var ptrs = codeGenModuleMethodPointers[imageName];\n                var methodPointerIndex = methodToken & 0x00FFFFFFu;\n                return ptrs[methodPointerIndex - 1];\n            }\n            else\n            {\n                var methodIndex = methodDef.methodIndex;\n                if (methodIndex >= 0)\n                {\n                    return methodPointers[methodIndex];\n                }\n            }\n            return 0;\n        }\n\n        public virtual ulong GetRVA(ulong pointer)\n        {\n            return pointer;\n        }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Il2Cpp/Il2CppClass.cs",
    "content": "﻿using System;\n\nnamespace Il2CppDumper\n{\n    public class Il2CppCodeRegistration\n    {\n        [Version(Max = 24.1)]\n        public ulong methodPointersCount;\n        [Version(Max = 24.1)]\n        public ulong methodPointers;\n        [Version(Max = 21)]\n        public ulong delegateWrappersFromNativeToManagedCount;\n        [Version(Max = 21)]\n        public ulong delegateWrappersFromNativeToManaged; // note the double indirection to handle different calling conventions\n        [Version(Min = 22)]\n        public ulong reversePInvokeWrapperCount;\n        [Version(Min = 22)]\n        public ulong reversePInvokeWrappers;\n        [Version(Max = 22)]\n        public ulong delegateWrappersFromManagedToNativeCount;\n        [Version(Max = 22)]\n        public ulong delegateWrappersFromManagedToNative;\n        [Version(Max = 22)]\n        public ulong marshalingFunctionsCount;\n        [Version(Max = 22)]\n        public ulong marshalingFunctions;\n        [Version(Min = 21, Max = 22)]\n        public ulong ccwMarshalingFunctionsCount;\n        [Version(Min = 21, Max = 22)]\n        public ulong ccwMarshalingFunctions;\n        public ulong genericMethodPointersCount;\n        public ulong genericMethodPointers;\n        [Version(Min = 24.5, Max = 24.5)]\n        [Version(Min = 27.1)]\n        public ulong genericAdjustorThunks;\n        public ulong invokerPointersCount;\n        public ulong invokerPointers;\n        [Version(Max = 24.5)]\n        public ulong customAttributeCount;\n        [Version(Max = 24.5)]\n        public ulong customAttributeGenerators;\n        [Version(Min = 21, Max = 22)]\n        public ulong guidCount;\n        [Version(Min = 21, Max = 22)]\n        public ulong guids; // Il2CppGuid\n        [Version(Min = 22)]\n        public ulong unresolvedVirtualCallCount; //29.1 unresolvedIndirectCallCount;\n        [Version(Min = 22)]\n        public ulong unresolvedVirtualCallPointers;\n        [Version(Min = 29.1)]\n        public ulong unresolvedInstanceCallPointers;\n        [Version(Min = 29.1)]\n        public ulong unresolvedStaticCallPointers;\n        [Version(Min = 23)]\n        public ulong interopDataCount;\n        [Version(Min = 23)]\n        public ulong interopData;\n        [Version(Min = 24.3)]\n        public ulong windowsRuntimeFactoryCount;\n        [Version(Min = 24.3)]\n        public ulong windowsRuntimeFactoryTable;\n        [Version(Min = 24.2)]\n        public ulong codeGenModulesCount;\n        [Version(Min = 24.2)]\n        public ulong codeGenModules;\n    }\n\n    public class Il2CppMetadataRegistration\n    {\n        public long genericClassesCount;\n        public ulong genericClasses;\n        public long genericInstsCount;\n        public ulong genericInsts;\n        public long genericMethodTableCount;\n        public ulong genericMethodTable;\n        public long typesCount;\n        public ulong types;\n        public long methodSpecsCount;\n        public ulong methodSpecs;\n        [Version(Max = 16)]\n        public long methodReferencesCount;\n        [Version(Max = 16)]\n        public ulong methodReferences;\n\n        public long fieldOffsetsCount;\n        public ulong fieldOffsets;\n\n        public long typeDefinitionsSizesCount;\n        public ulong typeDefinitionsSizes;\n        [Version(Min = 19)]\n        public ulong metadataUsagesCount;\n        [Version(Min = 19)]\n        public ulong metadataUsages;\n    }\n\n    public enum Il2CppTypeEnum\n    {\n        IL2CPP_TYPE_END = 0x00,       /* End of List */\n        IL2CPP_TYPE_VOID = 0x01,\n        IL2CPP_TYPE_BOOLEAN = 0x02,\n        IL2CPP_TYPE_CHAR = 0x03,\n        IL2CPP_TYPE_I1 = 0x04,\n        IL2CPP_TYPE_U1 = 0x05,\n        IL2CPP_TYPE_I2 = 0x06,\n        IL2CPP_TYPE_U2 = 0x07,\n        IL2CPP_TYPE_I4 = 0x08,\n        IL2CPP_TYPE_U4 = 0x09,\n        IL2CPP_TYPE_I8 = 0x0a,\n        IL2CPP_TYPE_U8 = 0x0b,\n        IL2CPP_TYPE_R4 = 0x0c,\n        IL2CPP_TYPE_R8 = 0x0d,\n        IL2CPP_TYPE_STRING = 0x0e,\n        IL2CPP_TYPE_PTR = 0x0f,       /* arg: <type> token */\n        IL2CPP_TYPE_BYREF = 0x10,       /* arg: <type> token */\n        IL2CPP_TYPE_VALUETYPE = 0x11,       /* arg: <type> token */\n        IL2CPP_TYPE_CLASS = 0x12,       /* arg: <type> token */\n        IL2CPP_TYPE_VAR = 0x13,       /* Generic parameter in a generic type definition, represented as number (compressed unsigned integer) number */\n        IL2CPP_TYPE_ARRAY = 0x14,       /* type, rank, boundsCount, bound1, loCount, lo1 */\n        IL2CPP_TYPE_GENERICINST = 0x15,     /* <type> <type-arg-count> <type-1> \\x{2026} <type-n> */\n        IL2CPP_TYPE_TYPEDBYREF = 0x16,\n        IL2CPP_TYPE_I = 0x18,\n        IL2CPP_TYPE_U = 0x19,\n        IL2CPP_TYPE_FNPTR = 0x1b,        /* arg: full method signature */\n        IL2CPP_TYPE_OBJECT = 0x1c,\n        IL2CPP_TYPE_SZARRAY = 0x1d,       /* 0-based one-dim-array */\n        IL2CPP_TYPE_MVAR = 0x1e,       /* Generic parameter in a generic method definition, represented as number (compressed unsigned integer)  */\n        IL2CPP_TYPE_CMOD_REQD = 0x1f,       /* arg: typedef or typeref token */\n        IL2CPP_TYPE_CMOD_OPT = 0x20,       /* optional arg: typedef or typref token */\n        IL2CPP_TYPE_INTERNAL = 0x21,       /* CLR internal type */\n\n        IL2CPP_TYPE_MODIFIER = 0x40,       /* Or with the following types */\n        IL2CPP_TYPE_SENTINEL = 0x41,       /* Sentinel for varargs method signature */\n        IL2CPP_TYPE_PINNED = 0x45,       /* Local var that points to pinned object */\n\n        IL2CPP_TYPE_ENUM = 0x55,        /* an enumeration */\n        IL2CPP_TYPE_IL2CPP_TYPE_INDEX = 0xff        /* an index into IL2CPP type metadata table */\n    }\n\n    public class Il2CppType\n    {\n        public ulong datapoint;\n        public uint bits;\n        public Union data { get; set; }\n        public uint attrs { get; set; }\n        public Il2CppTypeEnum type { get; set; }\n        public uint num_mods { get; set; }\n        public uint byref { get; set; }\n        public uint pinned { get; set; }\n        public uint valuetype { get; set; }\n\n        public void Init(double version)\n        {\n            attrs = bits & 0xffff;\n            type = (Il2CppTypeEnum)((bits >> 16) & 0xff);\n            if (version >= 27.2)\n            {\n                num_mods = (bits >> 24) & 0x1f;\n                byref = (bits >> 29) & 1;\n                pinned = (bits >> 30) & 1;\n                valuetype = bits >> 31;\n            }\n            else\n            {\n                num_mods = (bits >> 24) & 0x3f;\n                byref = (bits >> 30) & 1;\n                pinned = bits >> 31;\n            }\n            data = new Union { dummy = datapoint };\n        }\n\n        public class Union\n        {\n            public ulong dummy;\n            /// <summary>\n            /// for VALUETYPE and CLASS\n            /// </summary>\n            public long klassIndex => (long)dummy;\n            /// <summary>\n            /// for VALUETYPE and CLASS at runtime\n            /// </summary>\n            public ulong typeHandle => dummy;\n            /// <summary>\n            /// for PTR and SZARRAY\n            /// </summary>\n            public ulong type => dummy;\n            /// <summary>\n            /// for ARRAY\n            /// </summary>\n            public ulong array => dummy;\n            /// <summary>\n            /// for VAR and MVAR\n            /// </summary>\n            public long genericParameterIndex => (long)dummy;\n            /// <summary>\n            /// for VAR and MVAR at runtime\n            /// </summary>\n            public ulong genericParameterHandle => dummy;\n            /// <summary>\n            /// for GENERICINST\n            /// </summary>\n            public ulong generic_class => dummy;\n        }\n    }\n\n    public class Il2CppGenericClass\n    {\n        [Version(Max = 24.5)]\n        public long typeDefinitionIndex;    /* the generic type definition */\n        [Version(Min = 27)]\n        public ulong type;        /* the generic type definition */\n        public Il2CppGenericContext context;   /* a context that contains the type instantiation doesn't contain any method instantiation */\n        public ulong cached_class; /* if present, the Il2CppClass corresponding to the instantiation.  */\n    }\n\n    public class Il2CppGenericContext\n    {\n        /* The instantiation corresponding to the class generic parameters */\n        public ulong class_inst;\n        /* The instantiation corresponding to the method generic parameters */\n        public ulong method_inst;\n    }\n\n    public class Il2CppGenericInst\n    {\n        public long type_argc;\n        public ulong type_argv;\n    }\n\n    public class Il2CppArrayType\n    {\n        public ulong etype;\n        public byte rank;\n        public byte numsizes;\n        public byte numlobounds;\n        public ulong sizes;\n        public ulong lobounds;\n    }\n\n    public class Il2CppGenericMethodFunctionsDefinitions\n    {\n        public int genericMethodIndex;\n        public Il2CppGenericMethodIndices indices;\n    }\n\n    public class Il2CppGenericMethodIndices\n    {\n        public int methodIndex;\n        public int invokerIndex;\n        [Version(Min = 24.5, Max = 24.5)]\n        [Version(Min = 27.1)]\n        public int adjustorThunk;\n    };\n\n    public class Il2CppMethodSpec\n    {\n        public int methodDefinitionIndex;\n        public int classIndexIndex;\n        public int methodIndexIndex;\n    };\n\n    public class Il2CppCodeGenModule\n    {\n        public ulong moduleName;\n        public long methodPointerCount;\n        public ulong methodPointers;\n        [Version(Min = 24.5, Max = 24.5)]\n        [Version(Min = 27.1)]\n        public long adjustorThunkCount;\n        [Version(Min = 24.5, Max = 24.5)]\n        [Version(Min = 27.1)]\n        public ulong adjustorThunks;\n        public ulong invokerIndices;\n        public ulong reversePInvokeWrapperCount;\n        public ulong reversePInvokeWrapperIndices;\n        public long rgctxRangesCount;\n        public ulong rgctxRanges;\n        public long rgctxsCount;\n        public ulong rgctxs;\n        public ulong debuggerMetadata;\n        [Version(Min = 27, Max = 27.2)]\n        public ulong customAttributeCacheGenerator;\n        [Version(Min = 27)]\n        public ulong moduleInitializer;\n        [Version(Min = 27)]\n        public ulong staticConstructorTypeIndices;\n        [Version(Min = 27)]\n        public ulong metadataRegistration; // Per-assembly mode only\n        [Version(Min = 27)]\n        public ulong codeRegistaration; // Per-assembly mode only\n    }\n\n    public class Il2CppRange\n    {\n        public int start;\n        public int length;\n    }\n\n    public class Il2CppTokenRangePair\n    {\n        public uint token;\n        public Il2CppRange range;\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Il2Cpp/Metadata.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing System.Text;\n\nnamespace Il2CppDumper\n{\n    public sealed class Metadata : BinaryStream\n    {\n        public Il2CppGlobalMetadataHeader header;\n        public Il2CppImageDefinition[] imageDefs;\n        public Il2CppAssemblyDefinition[] assemblyDefs;\n        public Il2CppTypeDefinition[] typeDefs;\n        public Il2CppMethodDefinition[] methodDefs;\n        public Il2CppParameterDefinition[] parameterDefs;\n        public Il2CppFieldDefinition[] fieldDefs;\n        private readonly Dictionary<int, Il2CppFieldDefaultValue> fieldDefaultValuesDic;\n        private readonly Dictionary<int, Il2CppParameterDefaultValue> parameterDefaultValuesDic;\n        public Il2CppPropertyDefinition[] propertyDefs;\n        public Il2CppCustomAttributeTypeRange[] attributeTypeRanges;\n        public Il2CppCustomAttributeDataRange[] attributeDataRanges;\n        private readonly Dictionary<Il2CppImageDefinition, Dictionary<uint, int>> attributeTypeRangesDic;\n        public Il2CppStringLiteral[] stringLiterals;\n        private readonly Il2CppMetadataUsageList[] metadataUsageLists;\n        private readonly Il2CppMetadataUsagePair[] metadataUsagePairs;\n        public int[] attributeTypes;\n        public int[] interfaceIndices;\n        public Dictionary<Il2CppMetadataUsage, SortedDictionary<uint, uint>> metadataUsageDic;\n        public long metadataUsagesCount;\n        public int[] nestedTypeIndices;\n        public Il2CppEventDefinition[] eventDefs;\n        public Il2CppGenericContainer[] genericContainers;\n        public Il2CppFieldRef[] fieldRefs;\n        public Il2CppGenericParameter[] genericParameters;\n        public int[] constraintIndices;\n        public uint[] vtableMethods;\n        public Il2CppRGCTXDefinition[] rgctxEntries;\n\n        private readonly Dictionary<uint, string> stringCache = new();\n\n        public Metadata(Stream stream) : base(stream)\n        {\n            var sanity = ReadUInt32();\n            if (sanity != 0xFAB11BAF)\n            {\n                throw new InvalidDataException(\"ERROR: Metadata file supplied is not valid metadata file.\");\n            }\n            var version = ReadInt32();\n            if (version < 0 || version > 1000)\n            {\n                throw new InvalidDataException(\"ERROR: Metadata file supplied is not valid metadata file.\");\n            }\n            if (version < 16 || version > 31)\n            {\n                throw new NotSupportedException($\"ERROR: Metadata file supplied is not a supported version[{version}].\");\n            }\n            Version = version;\n            header = ReadClass<Il2CppGlobalMetadataHeader>(0);\n            if (version == 24)\n            {\n                if (header.stringLiteralOffset == 264)\n                {\n                    Version = 24.2;\n                    header = ReadClass<Il2CppGlobalMetadataHeader>(0);\n                }\n                else\n                {\n                    imageDefs = ReadMetadataClassArray<Il2CppImageDefinition>(header.imagesOffset, header.imagesSize);\n                    if (imageDefs.Any(x => x.token != 1))\n                    {\n                        Version = 24.1;\n                    }\n                }\n            }\n            imageDefs = ReadMetadataClassArray<Il2CppImageDefinition>(header.imagesOffset, header.imagesSize);\n            if (Version == 24.2 && header.assembliesSize / 68 < imageDefs.Length)\n            {\n                Version = 24.4;\n            }\n            var v241Plus = false;\n            if (Version == 24.1 && header.assembliesSize / 64 == imageDefs.Length)\n            {\n                v241Plus = true;\n            }\n            if (v241Plus)\n            {\n                Version = 24.4;\n            }\n            assemblyDefs = ReadMetadataClassArray<Il2CppAssemblyDefinition>(header.assembliesOffset, header.assembliesSize);\n            if (v241Plus)\n            {\n                Version = 24.1;\n            }\n            typeDefs = ReadMetadataClassArray<Il2CppTypeDefinition>(header.typeDefinitionsOffset, header.typeDefinitionsSize);\n            methodDefs = ReadMetadataClassArray<Il2CppMethodDefinition>(header.methodsOffset, header.methodsSize);\n            parameterDefs = ReadMetadataClassArray<Il2CppParameterDefinition>(header.parametersOffset, header.parametersSize);\n            fieldDefs = ReadMetadataClassArray<Il2CppFieldDefinition>(header.fieldsOffset, header.fieldsSize);\n            var fieldDefaultValues = ReadMetadataClassArray<Il2CppFieldDefaultValue>(header.fieldDefaultValuesOffset, header.fieldDefaultValuesSize);\n            var parameterDefaultValues = ReadMetadataClassArray<Il2CppParameterDefaultValue>(header.parameterDefaultValuesOffset, header.parameterDefaultValuesSize);\n            fieldDefaultValuesDic = fieldDefaultValues.ToDictionary(x => x.fieldIndex);\n            parameterDefaultValuesDic = parameterDefaultValues.ToDictionary(x => x.parameterIndex);\n            propertyDefs = ReadMetadataClassArray<Il2CppPropertyDefinition>(header.propertiesOffset, header.propertiesSize);\n            interfaceIndices = ReadClassArray<int>(header.interfacesOffset, header.interfacesSize / 4);\n            nestedTypeIndices = ReadClassArray<int>(header.nestedTypesOffset, header.nestedTypesSize / 4);\n            eventDefs = ReadMetadataClassArray<Il2CppEventDefinition>(header.eventsOffset, header.eventsSize);\n            genericContainers = ReadMetadataClassArray<Il2CppGenericContainer>(header.genericContainersOffset, header.genericContainersSize);\n            genericParameters = ReadMetadataClassArray<Il2CppGenericParameter>(header.genericParametersOffset, header.genericParametersSize);\n            constraintIndices = ReadClassArray<int>(header.genericParameterConstraintsOffset, header.genericParameterConstraintsSize / 4);\n            vtableMethods = ReadClassArray<uint>(header.vtableMethodsOffset, header.vtableMethodsSize / 4);\n            stringLiterals = ReadMetadataClassArray<Il2CppStringLiteral>(header.stringLiteralOffset, header.stringLiteralSize);\n            if (Version > 16)\n            {\n                fieldRefs = ReadMetadataClassArray<Il2CppFieldRef>(header.fieldRefsOffset, header.fieldRefsSize);\n                if (Version < 27)\n                {\n                    metadataUsageLists = ReadMetadataClassArray<Il2CppMetadataUsageList>(header.metadataUsageListsOffset, header.metadataUsageListsCount);\n                    metadataUsagePairs = ReadMetadataClassArray<Il2CppMetadataUsagePair>(header.metadataUsagePairsOffset, header.metadataUsagePairsCount);\n\n                    ProcessingMetadataUsage();\n                }\n            }\n            if (Version > 20 && Version < 29)\n            {\n                attributeTypeRanges = ReadMetadataClassArray<Il2CppCustomAttributeTypeRange>(header.attributesInfoOffset, header.attributesInfoCount);\n                attributeTypes = ReadClassArray<int>(header.attributeTypesOffset, header.attributeTypesCount / 4);\n            }\n            if (Version >= 29)\n            {\n                attributeDataRanges = ReadMetadataClassArray<Il2CppCustomAttributeDataRange>(header.attributeDataRangeOffset, header.attributeDataRangeSize);\n            }\n            if (Version > 24)\n            {\n                attributeTypeRangesDic = new Dictionary<Il2CppImageDefinition, Dictionary<uint, int>>();\n                foreach (var imageDef in imageDefs)\n                {\n                    var dic = new Dictionary<uint, int>();\n                    attributeTypeRangesDic[imageDef] = dic;\n                    var end = imageDef.customAttributeStart + imageDef.customAttributeCount;\n                    for (int i = imageDef.customAttributeStart; i < end; i++)\n                    {\n                        if (Version >= 29)\n                        {\n                            dic.Add(attributeDataRanges[i].token, i);\n                        }\n                        else\n                        {\n                            dic.Add(attributeTypeRanges[i].token, i);\n                        }\n                    }\n                }\n            }\n            if (Version <= 24.1)\n            {\n                rgctxEntries = ReadMetadataClassArray<Il2CppRGCTXDefinition>(header.rgctxEntriesOffset, header.rgctxEntriesCount);\n            }\n        }\n\n        private T[] ReadMetadataClassArray<T>(uint addr, int count) where T : new()\n        {\n            return ReadClassArray<T>(addr, count / SizeOf(typeof(T)));\n        }\n\n        public bool GetFieldDefaultValueFromIndex(int index, out Il2CppFieldDefaultValue value)\n        {\n            return fieldDefaultValuesDic.TryGetValue(index, out value);\n        }\n\n        public bool GetParameterDefaultValueFromIndex(int index, out Il2CppParameterDefaultValue value)\n        {\n            return parameterDefaultValuesDic.TryGetValue(index, out value);\n        }\n\n        public uint GetDefaultValueFromIndex(int index)\n        {\n            return (uint)(header.fieldAndParameterDefaultValueDataOffset + index);\n        }\n\n        public string GetStringFromIndex(uint index)\n        {\n            if (!stringCache.TryGetValue(index, out var result))\n            {\n                result = ReadStringToNull(header.stringOffset + index);\n                stringCache.Add(index, result);\n            }\n            return result;\n        }\n\n        public int GetCustomAttributeIndex(Il2CppImageDefinition imageDef, int customAttributeIndex, uint token)\n        {\n            if (Version > 24)\n            {\n                if (attributeTypeRangesDic[imageDef].TryGetValue(token, out var index))\n                {\n                    return index;\n                }\n                else\n                {\n                    return -1;\n                }\n            }\n            else\n            {\n                return customAttributeIndex;\n            }\n        }\n\n        public string GetStringLiteralFromIndex(uint index)\n        {\n            var stringLiteral = stringLiterals[index];\n            Position = (uint)(header.stringLiteralDataOffset + stringLiteral.dataIndex);\n            return Encoding.UTF8.GetString(ReadBytes((int)stringLiteral.length));\n        }\n\n        private void ProcessingMetadataUsage()\n        {\n            metadataUsageDic = new Dictionary<Il2CppMetadataUsage, SortedDictionary<uint, uint>>();\n            for (uint i = 1; i <= 6; i++)\n            {\n                metadataUsageDic[(Il2CppMetadataUsage)i] = new SortedDictionary<uint, uint>();\n            }\n            foreach (var metadataUsageList in metadataUsageLists)\n            {\n                for (int i = 0; i < metadataUsageList.count; i++)\n                {\n                    var offset = metadataUsageList.start + i;\n                    if (offset >= metadataUsagePairs.Length)\n                    {\n                        continue;\n                    }\n                    var metadataUsagePair = metadataUsagePairs[offset];\n                    var usage = GetEncodedIndexType(metadataUsagePair.encodedSourceIndex);\n                    var decodedIndex = GetDecodedMethodIndex(metadataUsagePair.encodedSourceIndex);\n                    metadataUsageDic[(Il2CppMetadataUsage)usage][metadataUsagePair.destinationIndex] = decodedIndex;\n                }\n            }\n            //metadataUsagesCount = metadataUsagePairs.Max(x => x.destinationIndex) + 1;\n            metadataUsagesCount = metadataUsageDic.Max(x => x.Value.Select(y => y.Key).DefaultIfEmpty().Max()) + 1;\n        }\n\n        public static uint GetEncodedIndexType(uint index)\n        {\n            return (index & 0xE0000000) >> 29;\n        }\n\n        public uint GetDecodedMethodIndex(uint index)\n        {\n            if (Version >= 27)\n            {\n                return (index & 0x1FFFFFFEU) >> 1;\n            }\n            return index & 0x1FFFFFFFU;\n        }\n\n        public int SizeOf(Type type)\n        {\n            var size = 0;\n            foreach (var i in type.GetFields())\n            {\n                var attr = (VersionAttribute)Attribute.GetCustomAttribute(i, typeof(VersionAttribute));\n                if (attr != null)\n                {\n                    if (Version < attr.Min || Version > attr.Max)\n                        continue;\n                }\n                var fieldType = i.FieldType;\n                if (fieldType.IsPrimitive)\n                {\n                    size += GetPrimitiveTypeSize(fieldType.Name);\n                }\n                else if (fieldType.IsEnum)\n                {\n                    var e = fieldType.GetField(\"value__\").FieldType;\n                    size += GetPrimitiveTypeSize(e.Name);\n                }\n                else if (fieldType.IsArray)\n                {\n                    var arrayLengthAttribute = i.GetCustomAttribute<ArrayLengthAttribute>();\n                    size += arrayLengthAttribute.Length;\n                }\n                else\n                {\n                    size += SizeOf(fieldType);\n                }\n            }\n            return size;\n\n            static int GetPrimitiveTypeSize(string name)\n            {\n                return name switch\n                {\n                    \"Int32\" or \"UInt32\" => 4,\n                    \"Int16\" or \"UInt16\" => 2,\n                    _ => 0,\n                };\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Il2Cpp/MetadataClass.cs",
    "content": "﻿using System;\n\nnamespace Il2CppDumper\n{\n    public class Il2CppGlobalMetadataHeader\n    {\n        public uint sanity;\n        public int version;\n        public uint stringLiteralOffset; // string data for managed code\n        public int stringLiteralSize;\n        public uint stringLiteralDataOffset;\n        public int stringLiteralDataSize;\n        public uint stringOffset; // string data for metadata\n        public int stringSize;\n        public uint eventsOffset; // Il2CppEventDefinition\n        public int eventsSize;\n        public uint propertiesOffset; // Il2CppPropertyDefinition\n        public int propertiesSize;\n        public uint methodsOffset; // Il2CppMethodDefinition\n        public int methodsSize;\n        public uint parameterDefaultValuesOffset; // Il2CppParameterDefaultValue\n        public int parameterDefaultValuesSize;\n        public uint fieldDefaultValuesOffset; // Il2CppFieldDefaultValue\n        public int fieldDefaultValuesSize;\n        public uint fieldAndParameterDefaultValueDataOffset; // uint8_t\n        public int fieldAndParameterDefaultValueDataSize;\n        public int fieldMarshaledSizesOffset; // Il2CppFieldMarshaledSize\n        public int fieldMarshaledSizesSize;\n        public uint parametersOffset; // Il2CppParameterDefinition\n        public int parametersSize;\n        public uint fieldsOffset; // Il2CppFieldDefinition\n        public int fieldsSize;\n        public uint genericParametersOffset; // Il2CppGenericParameter\n        public int genericParametersSize;\n        public uint genericParameterConstraintsOffset; // TypeIndex\n        public int genericParameterConstraintsSize;\n        public uint genericContainersOffset; // Il2CppGenericContainer\n        public int genericContainersSize;\n        public uint nestedTypesOffset; // TypeDefinitionIndex\n        public int nestedTypesSize;\n        public uint interfacesOffset; // TypeIndex\n        public int interfacesSize;\n        public uint vtableMethodsOffset; // EncodedMethodIndex\n        public int vtableMethodsSize;\n        public int interfaceOffsetsOffset; // Il2CppInterfaceOffsetPair\n        public int interfaceOffsetsSize;\n        public uint typeDefinitionsOffset; // Il2CppTypeDefinition\n        public int typeDefinitionsSize;\n        [Version(Max = 24.1)]\n        public uint rgctxEntriesOffset; // Il2CppRGCTXDefinition\n        [Version(Max = 24.1)]\n        public int rgctxEntriesCount;\n        public uint imagesOffset; // Il2CppImageDefinition\n        public int imagesSize;\n        public uint assembliesOffset; // Il2CppAssemblyDefinition\n        public int assembliesSize;\n        [Version(Min = 19, Max = 24.5)]\n        public uint metadataUsageListsOffset; // Il2CppMetadataUsageList\n        [Version(Min = 19, Max = 24.5)]\n        public int metadataUsageListsCount;\n        [Version(Min = 19, Max = 24.5)]\n        public uint metadataUsagePairsOffset; // Il2CppMetadataUsagePair\n        [Version(Min = 19, Max = 24.5)]\n        public int metadataUsagePairsCount;\n        [Version(Min = 19)]\n        public uint fieldRefsOffset; // Il2CppFieldRef\n        [Version(Min = 19)]\n        public int fieldRefsSize;\n        [Version(Min = 20)]\n        public int referencedAssembliesOffset; // int32_t\n        [Version(Min = 20)]\n        public int referencedAssembliesSize;\n        [Version(Min = 21, Max = 27.2)]\n        public uint attributesInfoOffset; // Il2CppCustomAttributeTypeRange\n        [Version(Min = 21, Max = 27.2)]\n        public int attributesInfoCount;\n        [Version(Min = 21, Max = 27.2)]\n        public uint attributeTypesOffset; // TypeIndex\n        [Version(Min = 21, Max = 27.2)]\n        public int attributeTypesCount;\n        [Version(Min = 29)]\n        public uint attributeDataOffset;\n        [Version(Min = 29)]\n        public int attributeDataSize;\n        [Version(Min = 29)]\n        public uint attributeDataRangeOffset;\n        [Version(Min = 29)]\n        public int attributeDataRangeSize;\n        [Version(Min = 22)]\n        public int unresolvedVirtualCallParameterTypesOffset; // TypeIndex\n        [Version(Min = 22)]\n        public int unresolvedVirtualCallParameterTypesSize;\n        [Version(Min = 22)]\n        public int unresolvedVirtualCallParameterRangesOffset; // Il2CppRange\n        [Version(Min = 22)]\n        public int unresolvedVirtualCallParameterRangesSize;\n        [Version(Min = 23)]\n        public int windowsRuntimeTypeNamesOffset; // Il2CppWindowsRuntimeTypeNamePair\n        [Version(Min = 23)]\n        public int windowsRuntimeTypeNamesSize;\n        [Version(Min = 27)]\n        public int windowsRuntimeStringsOffset; // const char*\n        [Version(Min = 27)]\n        public int windowsRuntimeStringsSize;\n        [Version(Min = 24)]\n        public int exportedTypeDefinitionsOffset; // TypeDefinitionIndex\n        [Version(Min = 24)]\n        public int exportedTypeDefinitionsSize;\n    }\n\n    public class Il2CppAssemblyDefinition\n    {\n        public int imageIndex;\n        [Version(Min = 24.1)]\n        public uint token;\n        [Version(Max = 24)]\n        public int customAttributeIndex;\n        [Version(Min = 20)]\n        public int referencedAssemblyStart;\n        [Version(Min = 20)]\n        public int referencedAssemblyCount;\n        public Il2CppAssemblyNameDefinition aname;\n    }\n\n    public class Il2CppAssemblyNameDefinition\n    {\n        public uint nameIndex;\n        public uint cultureIndex;\n        [Version(Max = 24.3)]\n        public int hashValueIndex;\n        public uint publicKeyIndex;\n        public uint hash_alg;\n        public int hash_len;\n        public uint flags;\n        public int major;\n        public int minor;\n        public int build;\n        public int revision;\n        [ArrayLength(Length = 8)]\n        public byte[] public_key_token;\n    }\n\n    public class Il2CppImageDefinition\n    {\n        public uint nameIndex;\n        public int assemblyIndex;\n\n        public int typeStart;\n        public uint typeCount;\n\n        [Version(Min = 24)]\n        public int exportedTypeStart;\n        [Version(Min = 24)]\n        public uint exportedTypeCount;\n\n        public int entryPointIndex;\n        [Version(Min = 19)]\n        public uint token;\n\n        [Version(Min = 24.1)]\n        public int customAttributeStart;\n        [Version(Min = 24.1)]\n        public uint customAttributeCount;\n    }\n\n    public class Il2CppTypeDefinition\n    {\n        public uint nameIndex;\n        public uint namespaceIndex;\n        [Version(Max = 24)]\n        public int customAttributeIndex;\n        public int byvalTypeIndex;\n        [Version(Max = 24.5)]\n        public int byrefTypeIndex;\n\n        public int declaringTypeIndex;\n        public int parentIndex;\n        public int elementTypeIndex; // we can probably remove this one. Only used for enums\n\n        [Version(Max = 24.1)]\n        public int rgctxStartIndex;\n        [Version(Max = 24.1)]\n        public int rgctxCount;\n\n        public int genericContainerIndex;\n\n        [Version(Max = 22)]\n        public int delegateWrapperFromManagedToNativeIndex;\n        [Version(Max = 22)]\n        public int marshalingFunctionsIndex;\n        [Version(Min = 21, Max = 22)]\n        public int ccwFunctionIndex;\n        [Version(Min = 21, Max = 22)]\n        public int guidIndex;\n\n        public uint flags;\n\n        public int fieldStart;\n        public int methodStart;\n        public int eventStart;\n        public int propertyStart;\n        public int nestedTypesStart;\n        public int interfacesStart;\n        public int vtableStart;\n        public int interfaceOffsetsStart;\n\n        public ushort method_count;\n        public ushort property_count;\n        public ushort field_count;\n        public ushort event_count;\n        public ushort nested_type_count;\n        public ushort vtable_count;\n        public ushort interfaces_count;\n        public ushort interface_offsets_count;\n\n        // bitfield to portably encode boolean values as single bits\n        // 01 - valuetype;\n        // 02 - enumtype;\n        // 03 - has_finalize;\n        // 04 - has_cctor;\n        // 05 - is_blittable;\n        // 06 - is_import_or_windows_runtime;\n        // 07-10 - One of nine possible PackingSize values (0, 1, 2, 4, 8, 16, 32, 64, or 128)\n        // 11 - PackingSize is default\n        // 12 - ClassSize is default\n        // 13-16 - One of nine possible PackingSize values (0, 1, 2, 4, 8, 16, 32, 64, or 128) - the specified packing size (even for explicit layouts)\n        public uint bitfield;\n        [Version(Min = 19)]\n        public uint token;\n\n        public bool IsValueType => (bitfield & 0x1) == 1;\n        public bool IsEnum => ((bitfield >> 1) & 0x1) == 1;\n    }\n\n    public class Il2CppMethodDefinition\n    {\n        public uint nameIndex;\n        public int declaringType;\n        public int returnType;\n        [Version(Min = 31)]\n        public int returnParameterToken;\n        public int parameterStart;\n        [Version(Max = 24)]\n        public int customAttributeIndex;\n        public int genericContainerIndex;\n        [Version(Max = 24.1)]\n        public int methodIndex;\n        [Version(Max = 24.1)]\n        public int invokerIndex;\n        [Version(Max = 24.1)]\n        public int delegateWrapperIndex;\n        [Version(Max = 24.1)]\n        public int rgctxStartIndex;\n        [Version(Max = 24.1)]\n        public int rgctxCount;\n        public uint token;\n        public ushort flags;\n        public ushort iflags;\n        public ushort slot;\n        public ushort parameterCount;\n    }\n\n    public class Il2CppParameterDefinition\n    {\n        public uint nameIndex;\n        public uint token;\n        [Version(Max = 24)]\n        public int customAttributeIndex;\n        public int typeIndex;\n    }\n\n    public class Il2CppFieldDefinition\n    {\n        public uint nameIndex;\n        public int typeIndex;\n        [Version(Max = 24)]\n        public int customAttributeIndex;\n        [Version(Min = 19)]\n        public uint token;\n    }\n\n    public class Il2CppFieldDefaultValue\n    {\n        public int fieldIndex;\n        public int typeIndex;\n        public int dataIndex;\n    }\n\n    public class Il2CppPropertyDefinition\n    {\n        public uint nameIndex;\n        public int get;\n        public int set;\n        public uint attrs;\n        [Version(Max = 24)]\n        public int customAttributeIndex;\n        [Version(Min = 19)]\n        public uint token;\n    }\n\n    public class Il2CppCustomAttributeTypeRange\n    {\n        [Version(Min = 24.1)]\n        public uint token;\n        public int start;\n        public int count;\n    }\n\n    public class Il2CppMetadataUsageList\n    {\n        public uint start;\n        public uint count;\n    }\n\n    public class Il2CppMetadataUsagePair\n    {\n        public uint destinationIndex;\n        public uint encodedSourceIndex;\n    }\n\n    public class Il2CppStringLiteral\n    {\n        public uint length;\n        public int dataIndex;\n    }\n\n    public class Il2CppParameterDefaultValue\n    {\n        public int parameterIndex;\n        public int typeIndex;\n        public int dataIndex;\n    }\n\n    public class Il2CppEventDefinition\n    {\n        public uint nameIndex;\n        public int typeIndex;\n        public int add;\n        public int remove;\n        public int raise;\n        [Version(Max = 24)]\n        public int customAttributeIndex;\n        [Version(Min = 19)]\n        public uint token;\n    }\n\n    public class Il2CppGenericContainer\n    {\n        /* index of the generic type definition or the generic method definition corresponding to this container */\n        public int ownerIndex; // either index into Il2CppClass metadata array or Il2CppMethodDefinition array\n        public int type_argc;\n        /* If true, we're a generic method, otherwise a generic type definition. */\n        public int is_method;\n        /* Our type parameters. */\n        public int genericParameterStart;\n    }\n\n    public class Il2CppFieldRef\n    {\n        public int typeIndex;\n        public int fieldIndex; // local offset into type fields\n    }\n\n    public class Il2CppGenericParameter\n    {\n        public int ownerIndex;  /* Type or method this parameter was defined in. */\n        public uint nameIndex;\n        public short constraintsStart;\n        public short constraintsCount;\n        public ushort num;\n        public ushort flags;\n    }\n\n    public enum Il2CppRGCTXDataType\n    {\n        IL2CPP_RGCTX_DATA_INVALID,\n        IL2CPP_RGCTX_DATA_TYPE,\n        IL2CPP_RGCTX_DATA_CLASS,\n        IL2CPP_RGCTX_DATA_METHOD,\n        IL2CPP_RGCTX_DATA_ARRAY,\n        IL2CPP_RGCTX_DATA_CONSTRAINED,\n    }\n\n    public class Il2CppRGCTXDefinitionData\n    {\n        public int rgctxDataDummy;\n        public int methodIndex => rgctxDataDummy;\n        public int typeIndex => rgctxDataDummy;\n    }\n\n    public class Il2CppRGCTXDefinition\n    {\n        public Il2CppRGCTXDataType type => type_post29 == 0 ? (Il2CppRGCTXDataType)type_pre29 : (Il2CppRGCTXDataType)type_post29;\n        [Version(Max = 27.1)]\n        public int type_pre29;\n        [Version(Min = 29)]\n        public ulong type_post29;\n        [Version(Max = 27.1)]\n        public Il2CppRGCTXDefinitionData data;\n        [Version(Min = 27.2)]\n        public ulong _data;\n    }\n\n    public enum Il2CppMetadataUsage\n    {\n        kIl2CppMetadataUsageInvalid,\n        kIl2CppMetadataUsageTypeInfo,\n        kIl2CppMetadataUsageIl2CppType,\n        kIl2CppMetadataUsageMethodDef,\n        kIl2CppMetadataUsageFieldInfo,\n        kIl2CppMetadataUsageStringLiteral,\n        kIl2CppMetadataUsageMethodRef,\n    };\n\n    public class Il2CppCustomAttributeDataRange\n    {\n        public uint token;\n        public uint startOffset;\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Il2CppBinaryNinja/__init__.py",
    "content": "from binaryninja import *\nfrom os.path import exists\n\ndef get_addr(bv: BinaryView, addr: int):\n    imageBase = bv.start\n    return imageBase + addr\n\nclass Il2CppProcessTask(BackgroundTaskThread):\n    def __init__(self, bv: BinaryView, script_path: str,\n                 header_path: str):\n        BackgroundTaskThread.__init__(self, \"Il2Cpp start\", True)\n        self.bv = bv\n        self.script_path = script_path\n        self.header_path = header_path\n        self.has_types = False\n    \n    def process_header(self):\n        self.progress = \"Il2Cpp types (1/3)\"\n        with open(self.header_path) as f:\n            result = self.bv.parse_types_from_string(f.read())\n        length = len(result.types)\n        i = 0\n        for name in result.types:\n            i += 1\n            if i % 100 == 0:\n                percent = i / length * 100\n                self.progress = f\"Il2Cpp types: {percent:.2f}%\"\n            if self.bv.get_type_by_name(name):\n                continue\n            self.bv.define_user_type(name, result.types[name])\n    \n    def process_methods(self, data: dict):\n        self.progress = f\"Il2Cpp methods (2/3)\"\n        scriptMethods = data[\"ScriptMethod\"]\n        length = len(scriptMethods)\n        i = 0\n        for scriptMethod in scriptMethods:\n            if self.cancelled:\n                self.progress = \"Il2Cpp cancelled, aborting\"\n                return\n            i += 1\n            if i % 100 == 0:\n                percent = i / length * 100\n                self.progress = f\"Il2Cpp methods: {percent:.2f}%\"\n            addr = get_addr(self.bv, scriptMethod[\"Address\"])\n            name = scriptMethod[\"Name\"].replace(\"$\", \"_\").replace(\".\", \"_\")\n            signature = scriptMethod[\"Signature\"]\n            func = self.bv.get_function_at(addr)\n            if func != None:\n                if func.name == name:\n                    continue\n                if self.has_types:\n                    func.function_type = signature\n                else:\n                    func.name = scriptMethod[\"Name\"]\n        \n    def process_strings(self, data: dict):\n        self.progress = \"Il2Cpp strings (3/3)\"\n        scriptStrings = data[\"ScriptString\"]\n        i = 0\n        for scriptString in scriptStrings:\n            i += 1\n            if self.cancelled:\n                self.progress = \"Il2Cpp cancelled, aborting\"\n                return\n            addr = get_addr(self.bv, scriptString[\"Address\"])\n            value = scriptString[\"Value\"]\n            var = self.bv.get_data_var_at(addr)\n            if var != None:\n                var.name = f\"StringLiteral_{i}\"\n            self.bv.set_comment_at(addr, value)\n    \n    def run(self):\n        if exists(self.header_path):\n            self.process_header()\n        else:\n            log_warn(\"Header file not found\")\n        if self.bv.get_type_by_name(\"Il2CppClass\"):\n            self.has_types = True\n        data = json.loads(open(self.script_path, 'rb').read().decode('utf-8'))\n        if \"ScriptMethod\" in data:\n            self.process_methods(data)\n        if \"ScriptString\" in data:\n            self.process_strings(data)\n\ndef process(bv: BinaryView):\n    scriptDialog = OpenFileNameField(\"Select script.json\", \"script.json\", \"script.json\")\n    headerDialog = OpenFileNameField(\"Select il2cpp_binja.h\", \"il2cpp_binja.h\", \"il2cpp_binja.h\")\n    if not get_form_input([scriptDialog, headerDialog], \"script.json from Il2CppDumper\"):\n        return log_error(\"File not selected, try again!\")\n    if not exists(scriptDialog.result):\n        return log_error(\"File not found, try again!\")\n    task = Il2CppProcessTask(bv, scriptDialog.result, headerDialog.result)\n    task.start()\n\nPluginCommand.register(\"Il2CppDumper\", \"Process file\", process)\n"
  },
  {
    "path": "Il2CppDumper/Il2CppBinaryNinja/plugin.json",
    "content": "{\n  \"pluginmetadataversion\": 2,\n  \"name\": \"Il2CppDumper\",\n  \"type\": [\n    \"core\",\n    \"ui\",\n    \"binaryview\"\n  ],\n  \"api\": [\n    \"python3\"\n  ],\n  \"description\": \"Add Il2Cpp structs and method signatures\",\n  \"longdescription\": \"\",\n  \"license\": {\n    \"name\": \"MIT\",\n    \"text\": \"Copyright (c) 2022 Il2CppDumper contributors\\n\\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \\\"Software\\\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\\n\\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\\n\\nTHE SOFTWARE IS PROVIDED \\\"AS IS\\\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\"\n  },\n  \"platforms\": [\n    \"Darwin\",\n    \"Linux\",\n    \"Windows\"\n  ],\n  \"installinstructions\": {\n    \"Darwin\": \"Install Il2CppDumper\",\n    \"Linux\": \"Install Il2CppDumper\",\n    \"Windows\": \"Install Il2CppDumper\"\n  },\n  \"dependencies\": {\n  },\n  \"version\": \"1.0.0\",\n  \"author\": \"Il2CppDumper contributors\",\n  \"minimumbinaryninjaversion\": 3164\n}\n"
  },
  {
    "path": "Il2CppDumper/Il2CppDumper.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFrameworks>net6.0;net8.0</TargetFrameworks>\n    <Version>1.0.0.0</Version>\n    <AssemblyVersion>1.0.0.0</AssemblyVersion>\n    <FileVersion>1.0.0.0</FileVersion>\n    <Copyright>Copyright © Perfare 2016-2024</Copyright>\n    <DebugType>embedded</DebugType>\n\t<BuiltInComInteropSupport>true</BuiltInComInteropSupport>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Mono.Cecil\" Version=\"0.11.4\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Compile Update=\"Resource1.Designer.cs\">\n      <DesignTime>True</DesignTime>\n      <AutoGen>True</AutoGen>\n      <DependentUpon>Resource1.resx</DependentUpon>\n    </Compile>\n  </ItemGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Update=\"Resource1.resx\">\n      <Generator>ResXFileCodeGenerator</Generator>\n      <LastGenOutput>Resource1.Designer.cs</LastGenOutput>\n    </EmbeddedResource>\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Update=\"config.json\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Update=\"ghidra.py\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Update=\"ghidra_wasm.py\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Update=\"ghidra_with_struct.py\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Update=\"ida.py\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Update=\"ida_py3.py\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Update=\"ida_with_struct.py\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Update=\"ida_with_struct_py3.py\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Update=\"il2cpp_header_to_ghidra.py\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Il2CppDumper/Outputs/DummyAssemblyExporter.cs",
    "content": "﻿using System.IO;\n\nnamespace Il2CppDumper\n{\n    public static class DummyAssemblyExporter\n    {\n        public static void Export(Il2CppExecutor il2CppExecutor, string outputDir, bool addToken)\n        {\n            Directory.SetCurrentDirectory(outputDir);\n            if (Directory.Exists(\"DummyDll\"))\n                Directory.Delete(\"DummyDll\", true);\n            Directory.CreateDirectory(\"DummyDll\");\n            Directory.SetCurrentDirectory(\"DummyDll\");\n            var dummy = new DummyAssemblyGenerator(il2CppExecutor, addToken);\n            foreach (var assembly in dummy.Assemblies)\n            {\n                using var stream = new MemoryStream();\n                assembly.Write(stream);\n                File.WriteAllBytes(assembly.MainModule.Name, stream.ToArray());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Outputs/HeaderConstants.cs",
    "content": "﻿namespace Il2CppDumper\n{\n    public static class HeaderConstants\n    {\n        public readonly static string GenericHeader =\n@\"typedef void(*Il2CppMethodPointer)();\n\nstruct MethodInfo;\n\nstruct VirtualInvokeData\n{\n    Il2CppMethodPointer methodPtr;\n    const MethodInfo* method;\n};\n\nstruct Il2CppType\n{\n    void* data;\n    unsigned int bits;\n};\n\nstruct Il2CppClass;\n\nstruct Il2CppObject\n{\n    Il2CppClass *klass;\n    void *monitor;\n};\n\nunion Il2CppRGCTXData\n{\n    void* rgctxDataDummy;\n    const MethodInfo* method;\n    const Il2CppType* type;\n    Il2CppClass* klass;\n};\n\nstruct Il2CppRuntimeInterfaceOffsetPair\n{\n    Il2CppClass* interfaceType;\n    int32_t offset;\n};\n\";\n\n        public readonly static string HeaderV29 =\n@\"struct Il2CppClass_1\n{\n    void* image;\n    void* gc_desc;\n    const char* name;\n    const char* namespaze;\n    Il2CppType byval_arg;\n    Il2CppType this_arg;\n    Il2CppClass* element_class;\n    Il2CppClass* castClass;\n    Il2CppClass* declaringType;\n    Il2CppClass* parent;\n    void *generic_class;\n    void* typeMetadataHandle;\n    void* interopData;\n    Il2CppClass* klass;\n    void* fields;\n    void* events;\n    void* properties;\n    void* methods;\n    Il2CppClass** nestedTypes;\n    Il2CppClass** implementedInterfaces;\n    Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets;\n};\n\nstruct Il2CppClass_2\n{\n    Il2CppClass** typeHierarchy;\n    void *unity_user_data;\n    uint32_t initializationExceptionGCHandle;\n    uint32_t cctor_started;\n    uint32_t cctor_finished;\n    size_t cctor_thread;\n    void* genericContainerHandle;\n    uint32_t instance_size;\n    uint32_t actualSize;\n    uint32_t element_size;\n    int32_t native_size;\n    uint32_t static_fields_size;\n    uint32_t thread_static_fields_size;\n    int32_t thread_static_fields_offset;\n    uint32_t flags;\n    uint32_t token;\n    uint16_t method_count;\n    uint16_t property_count;\n    uint16_t field_count;\n    uint16_t event_count;\n    uint16_t nested_type_count;\n    uint16_t vtable_count;\n    uint16_t interfaces_count;\n    uint16_t interface_offsets_count;\n    uint8_t typeHierarchyDepth;\n    uint8_t genericRecursionDepth;\n    uint8_t rank;\n    uint8_t minimumAlignment;\n    uint8_t naturalAligment;\n    uint8_t packingSize;\n    uint8_t bitflags1;\n    uint8_t bitflags2;\n};\n\nstruct Il2CppClass\n{\n    Il2CppClass_1 _1;\n    void* static_fields;\n    Il2CppRGCTXData* rgctx_data;\n    Il2CppClass_2 _2;\n    VirtualInvokeData vtable[255];\n};\n\ntypedef uintptr_t il2cpp_array_size_t;\ntypedef int32_t il2cpp_array_lower_bound_t;\nstruct Il2CppArrayBounds\n{\n    il2cpp_array_size_t length;\n    il2cpp_array_lower_bound_t lower_bound;\n};\n\ntypedef void (*InvokerMethod)(Il2CppMethodPointer, const MethodInfo*, void*, void**, void*);\nstruct MethodInfo\n{\n    Il2CppMethodPointer methodPointer;\n    Il2CppMethodPointer virtualMethodPointer;\n    InvokerMethod invoker_method;\n    const char* name;\n    Il2CppClass *klass;\n    const Il2CppType *return_type;\n    const Il2CppType** parameters;\n    union\n    {\n        const Il2CppRGCTXData* rgctx_data;\n        const void* methodMetadataHandle;\n    };\n    union\n    {\n        const void* genericMethod;\n        const void* genericContainerHandle;\n    };\n    uint32_t token;\n    uint16_t flags;\n    uint16_t iflags;\n    uint16_t slot;\n    uint8_t parameters_count;\n    uint8_t bitflags;\n};\n\n\";\n\n        public readonly static string HeaderV27 =\n@\"struct Il2CppClass_1\n{\n    void* image;\n    void* gc_desc;\n    const char* name;\n    const char* namespaze;\n    Il2CppType byval_arg;\n    Il2CppType this_arg;\n    Il2CppClass* element_class;\n    Il2CppClass* castClass;\n    Il2CppClass* declaringType;\n    Il2CppClass* parent;\n    void *generic_class;\n    void* typeMetadataHandle;\n    void* interopData;\n    Il2CppClass* klass;\n    void* fields;\n    void* events;\n    void* properties;\n    void* methods;\n    Il2CppClass** nestedTypes;\n    Il2CppClass** implementedInterfaces;\n    Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets;\n};\n\nstruct Il2CppClass_2\n{\n    Il2CppClass** typeHierarchy;\n    void *unity_user_data;\n    uint32_t initializationExceptionGCHandle;\n    uint32_t cctor_started;\n    uint32_t cctor_finished;\n    size_t cctor_thread;\n    void* genericContainerHandle;\n    uint32_t instance_size;\n    uint32_t actualSize;\n    uint32_t element_size;\n    int32_t native_size;\n    uint32_t static_fields_size;\n    uint32_t thread_static_fields_size;\n    int32_t thread_static_fields_offset;\n    uint32_t flags;\n    uint32_t token;\n    uint16_t method_count;\n    uint16_t property_count;\n    uint16_t field_count;\n    uint16_t event_count;\n    uint16_t nested_type_count;\n    uint16_t vtable_count;\n    uint16_t interfaces_count;\n    uint16_t interface_offsets_count;\n    uint8_t typeHierarchyDepth;\n    uint8_t genericRecursionDepth;\n    uint8_t rank;\n    uint8_t minimumAlignment;\n    uint8_t naturalAligment;\n    uint8_t packingSize;\n    uint8_t bitflags1;\n    uint8_t bitflags2;\n};\n\nstruct Il2CppClass\n{\n    Il2CppClass_1 _1;\n    void* static_fields;\n    Il2CppRGCTXData* rgctx_data;\n    Il2CppClass_2 _2;\n    VirtualInvokeData vtable[255];\n};\n\ntypedef uintptr_t il2cpp_array_size_t;\ntypedef int32_t il2cpp_array_lower_bound_t;\nstruct Il2CppArrayBounds\n{\n    il2cpp_array_size_t length;\n    il2cpp_array_lower_bound_t lower_bound;\n};\n\nstruct MethodInfo\n{\n    Il2CppMethodPointer methodPointer;\n    void* invoker_method;\n    const char* name;\n    Il2CppClass *klass;\n    const Il2CppType *return_type;\n    const void* parameters;\n    union\n    {\n        const Il2CppRGCTXData* rgctx_data;\n        const void* methodMetadataHandle;\n    };\n    union\n    {\n        const void* genericMethod;\n        const void* genericContainerHandle;\n    };\n    uint32_t token;\n    uint16_t flags;\n    uint16_t iflags;\n    uint16_t slot;\n    uint8_t parameters_count;\n    uint8_t bitflags;\n};\n\n\";\n\n        public readonly static string HeaderV242 =\n@\"struct Il2CppClass_1\n{\n    void* image;\n    void* gc_desc;\n    const char* name;\n    const char* namespaze;\n    Il2CppType byval_arg;\n    Il2CppType this_arg;\n    Il2CppClass* element_class;\n    Il2CppClass* castClass;\n    Il2CppClass* declaringType;\n    Il2CppClass* parent;\n    void *generic_class;\n    void* typeDefinition;\n    void* interopData;\n    Il2CppClass* klass;\n    void* fields;\n    void* events;\n    void* properties;\n    void* methods;\n    Il2CppClass** nestedTypes;\n    Il2CppClass** implementedInterfaces;\n    Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets;\n};\n\nstruct Il2CppClass_2\n{\n    Il2CppClass** typeHierarchy;\n    void *unity_user_data;\n    uint32_t initializationExceptionGCHandle;\n    uint32_t cctor_started;\n    uint32_t cctor_finished;\n    size_t cctor_thread;\n    int32_t genericContainerIndex;\n    uint32_t instance_size;\n    uint32_t actualSize;\n    uint32_t element_size;\n    int32_t native_size;\n    uint32_t static_fields_size;\n    uint32_t thread_static_fields_size;\n    int32_t thread_static_fields_offset;\n    uint32_t flags;\n    uint32_t token;\n    uint16_t method_count;\n    uint16_t property_count;\n    uint16_t field_count;\n    uint16_t event_count;\n    uint16_t nested_type_count;\n    uint16_t vtable_count;\n    uint16_t interfaces_count;\n    uint16_t interface_offsets_count;\n    uint8_t typeHierarchyDepth;\n    uint8_t genericRecursionDepth;\n    uint8_t rank;\n    uint8_t minimumAlignment;\n    uint8_t naturalAligment;\n    uint8_t packingSize;\n    uint8_t bitflags1;\n    uint8_t bitflags2;\n};\n\nstruct Il2CppClass\n{\n    Il2CppClass_1 _1;\n    void* static_fields;\n    Il2CppRGCTXData* rgctx_data;\n    Il2CppClass_2 _2;\n    VirtualInvokeData vtable[255];\n};\n\ntypedef uintptr_t il2cpp_array_size_t;\ntypedef int32_t il2cpp_array_lower_bound_t;\nstruct Il2CppArrayBounds\n{\n    il2cpp_array_size_t length;\n    il2cpp_array_lower_bound_t lower_bound;\n};\n\nstruct MethodInfo\n{\n    Il2CppMethodPointer methodPointer;\n    void* invoker_method;\n    const char* name;\n    Il2CppClass *klass;\n    const Il2CppType *return_type;\n    const void* parameters;\n    union\n    {\n        const Il2CppRGCTXData* rgctx_data;\n        const void* methodDefinition;\n    };\n    union\n    {\n        const void* genericMethod;\n        const void* genericContainer;\n    };\n    uint32_t token;\n    uint16_t flags;\n    uint16_t iflags;\n    uint16_t slot;\n    uint8_t parameters_count;\n    uint8_t bitflags;\n};\n\n\";\n\n        public readonly static string HeaderV241 =\n@\"struct Il2CppClass_1\n{\n    void* image;\n    void* gc_desc;\n    const char* name;\n    const char* namespaze;\n    Il2CppType byval_arg;\n    Il2CppType this_arg;\n    Il2CppClass* element_class;\n    Il2CppClass* castClass;\n    Il2CppClass* declaringType;\n    Il2CppClass* parent;\n    void *generic_class;\n    void* typeDefinition;\n    void* interopData;\n    Il2CppClass* klass;\n    void* fields;\n    void* events;\n    void* properties;\n    void* methods;\n    Il2CppClass** nestedTypes;\n    Il2CppClass** implementedInterfaces;\n    Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets;\n};\n\nstruct Il2CppClass_2\n{\n    Il2CppClass** typeHierarchy;\n    uint32_t initializationExceptionGCHandle;\n    uint32_t cctor_started;\n    uint32_t cctor_finished;\n    uint64_t cctor_thread;\n    int32_t genericContainerIndex;\n    uint32_t instance_size;\n    uint32_t actualSize;\n    uint32_t element_size;\n    int32_t native_size;\n    uint32_t static_fields_size;\n    uint32_t thread_static_fields_size;\n    int32_t thread_static_fields_offset;\n    uint32_t flags;\n    uint32_t token;\n    uint16_t method_count;\n    uint16_t property_count;\n    uint16_t field_count;\n    uint16_t event_count;\n    uint16_t nested_type_count;\n    uint16_t vtable_count;\n    uint16_t interfaces_count;\n    uint16_t interface_offsets_count;\n    uint8_t typeHierarchyDepth;\n    uint8_t genericRecursionDepth;\n    uint8_t rank;\n    uint8_t minimumAlignment;\n    uint8_t naturalAligment;\n    uint8_t packingSize;\n    uint8_t bitflags1;\n    uint8_t bitflags2;\n};\n\nstruct Il2CppClass\n{\n    Il2CppClass_1 _1;\n    void* static_fields;\n    Il2CppRGCTXData* rgctx_data;\n    Il2CppClass_2 _2;\n    VirtualInvokeData vtable[255];\n};\n\ntypedef uintptr_t il2cpp_array_size_t;\ntypedef int32_t il2cpp_array_lower_bound_t;\nstruct Il2CppArrayBounds\n{\n    il2cpp_array_size_t length;\n    il2cpp_array_lower_bound_t lower_bound;\n};\n\nstruct MethodInfo\n{\n    Il2CppMethodPointer methodPointer;\n    void* invoker_method;\n    const char* name;\n    Il2CppClass *klass;\n    const Il2CppType *return_type;\n    const void* parameters;\n    union\n    {\n        const Il2CppRGCTXData* rgctx_data;\n        const void* methodDefinition;\n    };\n    union\n    {\n        const void* genericMethod;\n        const void* genericContainer;\n    };\n    uint32_t token;\n    uint16_t flags;\n    uint16_t iflags;\n    uint16_t slot;\n    uint8_t parameters_count;\n    uint8_t bitflags;\n};\n\n\";\n\n        public readonly static string HeaderV240 =\n@\"struct Il2CppClass_1\n{\n    void* image;\n    void* gc_desc;\n    const char* name;\n    const char* namespaze;\n    Il2CppType* byval_arg;\n    Il2CppType* this_arg;\n    Il2CppClass* element_class;\n    Il2CppClass* castClass;\n    Il2CppClass* declaringType;\n    Il2CppClass* parent;\n    void *generic_class;\n    void* typeDefinition;\n    void* interopData;\n    void* fields;\n    void* events;\n    void* properties;\n    void* methods;\n    Il2CppClass** nestedTypes;\n    Il2CppClass** implementedInterfaces;\n    Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets;\n};\n\nstruct Il2CppClass_2\n{\n    Il2CppClass** typeHierarchy;\n    uint32_t cctor_started;\n    uint32_t cctor_finished;\n    uint64_t cctor_thread;\n    int32_t genericContainerIndex;\n    int32_t customAttributeIndex;\n    uint32_t instance_size;\n    uint32_t actualSize;\n    uint32_t element_size;\n    int32_t native_size;\n    uint32_t static_fields_size;\n    uint32_t thread_static_fields_size;\n    int32_t thread_static_fields_offset;\n    uint32_t flags;\n    uint32_t token;\n    uint16_t method_count;\n    uint16_t property_count;\n    uint16_t field_count;\n    uint16_t event_count;\n    uint16_t nested_type_count;\n    uint16_t vtable_count;\n    uint16_t interfaces_count;\n    uint16_t interface_offsets_count;\n    uint8_t typeHierarchyDepth;\n    uint8_t genericRecursionDepth;\n    uint8_t rank;\n    uint8_t minimumAlignment;\n    uint8_t packingSize;\n    uint8_t bitflags1;\n    uint8_t bitflags2;\n};\n\nstruct Il2CppClass\n{\n    Il2CppClass_1 _1;\n    void* static_fields;\n    Il2CppRGCTXData* rgctx_data;\n    Il2CppClass_2 _2;\n    VirtualInvokeData vtable[255];\n};\n\ntypedef int32_t il2cpp_array_size_t;\ntypedef int32_t il2cpp_array_lower_bound_t;\nstruct Il2CppArrayBounds\n{\n    il2cpp_array_size_t length;\n    il2cpp_array_lower_bound_t lower_bound;\n};\n\nstruct MethodInfo\n{\n    Il2CppMethodPointer methodPointer;\n    void* invoker_method;\n    const char* name;\n    Il2CppClass *declaring_type;\n    const Il2CppType *return_type;\n    const void* parameters;\n    union\n    {\n        const Il2CppRGCTXData* rgctx_data;\n        const void* methodDefinition;\n    };\n    union\n    {\n        const void* genericMethod;\n        const void* genericContainer;\n    };\n    int32_t customAttributeIndex;\n    uint32_t token;\n    uint16_t flags;\n    uint16_t iflags;\n    uint16_t slot;\n    uint8_t parameters_count;\n    uint8_t bitflags;\n};\n\n\";\n\n        public readonly static string HeaderV22 =\n@\"struct Il2CppClass_1\n{\n    void* image;\n    void* gc_desc;\n    const char* name;\n    const char* namespaze;\n    Il2CppType* byval_arg;\n    Il2CppType* this_arg;\n    Il2CppClass* element_class;\n    Il2CppClass* castClass;\n    Il2CppClass* declaringType;\n    Il2CppClass* parent;\n    void *generic_class;\n    void* typeDefinition;\n    void* fields;\n    void* events;\n    void* properties;\n    void* methods;\n    Il2CppClass** nestedTypes;\n    Il2CppClass** implementedInterfaces;\n    Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets;\n};\n\nstruct Il2CppClass_2\n{\n    Il2CppClass** typeHierarchy;\n    uint32_t cctor_started;\n    uint32_t cctor_finished;\n    uint64_t cctor_thread;\n    int32_t genericContainerIndex;\n    int32_t customAttributeIndex;\n    uint32_t instance_size;\n    uint32_t actualSize;\n    uint32_t element_size;\n    int32_t native_size;\n    uint32_t static_fields_size;\n    uint32_t thread_static_fields_size;\n    int32_t thread_static_fields_offset;\n    uint32_t flags;\n    uint32_t token;\n    uint16_t method_count;\n    uint16_t property_count;\n    uint16_t field_count;\n    uint16_t event_count;\n    uint16_t nested_type_count;\n    uint16_t vtable_count;\n    uint16_t interfaces_count;\n    uint16_t interface_offsets_count;\n    uint8_t typeHierarchyDepth;\n    uint8_t genericRecursionDepth;\n    uint8_t rank;\n    uint8_t minimumAlignment;\n    uint8_t packingSize;\n    uint8_t bitflags1;\n    uint8_t bitflags2;\n};\n\nstruct Il2CppClass\n{\n    Il2CppClass_1 _1;\n    void* static_fields;\n    Il2CppRGCTXData* rgctx_data;\n    Il2CppClass_2 _2;\n    VirtualInvokeData vtable[255];\n};\n\ntypedef int32_t il2cpp_array_size_t;\ntypedef int32_t il2cpp_array_lower_bound_t;\nstruct Il2CppArrayBounds\n{\n    il2cpp_array_size_t length;\n    il2cpp_array_lower_bound_t lower_bound;\n};\n\nstruct MethodInfo\n{\n    Il2CppMethodPointer methodPointer;\n    void* invoker_method;\n    const char* name;\n    Il2CppClass *declaring_type;\n    const Il2CppType *return_type;\n    const void* parameters;\n    union\n    {\n        const Il2CppRGCTXData* rgctx_data;\n        const void* methodDefinition;\n    };\n    union\n    {\n        const void* genericMethod;\n        const void* genericContainer;\n    };\n    int32_t customAttributeIndex;\n    uint32_t token;\n    uint16_t flags;\n    uint16_t iflags;\n    uint16_t slot;\n    uint8_t parameters_count;\n    uint8_t bitflags;\n};\n\n\";\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Outputs/Il2CppConstants.cs",
    "content": "﻿namespace Il2CppDumper\n{\n    class Il2CppConstants\n    {\n        /*\n         * Field Attributes (21.1.5).\n         */\n        public const int FIELD_ATTRIBUTE_FIELD_ACCESS_MASK = 0x0007;\n        public const int FIELD_ATTRIBUTE_COMPILER_CONTROLLED = 0x0000;\n        public const int FIELD_ATTRIBUTE_PRIVATE = 0x0001;\n        public const int FIELD_ATTRIBUTE_FAM_AND_ASSEM = 0x0002;\n        public const int FIELD_ATTRIBUTE_ASSEMBLY = 0x0003;\n        public const int FIELD_ATTRIBUTE_FAMILY = 0x0004;\n        public const int FIELD_ATTRIBUTE_FAM_OR_ASSEM = 0x0005;\n        public const int FIELD_ATTRIBUTE_PUBLIC = 0x0006;\n\n        public const int FIELD_ATTRIBUTE_STATIC = 0x0010;\n        public const int FIELD_ATTRIBUTE_INIT_ONLY = 0x0020;\n        public const int FIELD_ATTRIBUTE_LITERAL = 0x0040;\n\n        /*\n         * Method Attributes (22.1.9)\n         */\n        public const int METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK = 0x0007;\n        public const int METHOD_ATTRIBUTE_COMPILER_CONTROLLED = 0x0000;\n        public const int METHOD_ATTRIBUTE_PRIVATE = 0x0001;\n        public const int METHOD_ATTRIBUTE_FAM_AND_ASSEM = 0x0002;\n        public const int METHOD_ATTRIBUTE_ASSEM = 0x0003;\n        public const int METHOD_ATTRIBUTE_FAMILY = 0x0004;\n        public const int METHOD_ATTRIBUTE_FAM_OR_ASSEM = 0x0005;\n        public const int METHOD_ATTRIBUTE_PUBLIC = 0x0006;\n\n        public const int METHOD_ATTRIBUTE_STATIC = 0x0010;\n        public const int METHOD_ATTRIBUTE_FINAL = 0x0020;\n        public const int METHOD_ATTRIBUTE_VIRTUAL = 0x0040;\n\n        public const int METHOD_ATTRIBUTE_VTABLE_LAYOUT_MASK = 0x0100;\n        public const int METHOD_ATTRIBUTE_REUSE_SLOT = 0x0000;\n        public const int METHOD_ATTRIBUTE_NEW_SLOT = 0x0100;\n\n        public const int METHOD_ATTRIBUTE_ABSTRACT = 0x0400;\n\n        public const int METHOD_ATTRIBUTE_PINVOKE_IMPL = 0x2000;\n\n        /*\n        * Type Attributes (21.1.13).\n        */\n        public const int TYPE_ATTRIBUTE_VISIBILITY_MASK = 0x00000007;\n        public const int TYPE_ATTRIBUTE_NOT_PUBLIC = 0x00000000;\n        public const int TYPE_ATTRIBUTE_PUBLIC = 0x00000001;\n        public const int TYPE_ATTRIBUTE_NESTED_PUBLIC = 0x00000002;\n        public const int TYPE_ATTRIBUTE_NESTED_PRIVATE = 0x00000003;\n        public const int TYPE_ATTRIBUTE_NESTED_FAMILY = 0x00000004;\n        public const int TYPE_ATTRIBUTE_NESTED_ASSEMBLY = 0x00000005;\n        public const int TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM = 0x00000006;\n        public const int TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM = 0x00000007;\n\n\n        public const int TYPE_ATTRIBUTE_INTERFACE = 0x00000020;\n\n        public const int TYPE_ATTRIBUTE_ABSTRACT = 0x00000080;\n        public const int TYPE_ATTRIBUTE_SEALED = 0x00000100;\n\n        public const int TYPE_ATTRIBUTE_SERIALIZABLE = 0x00002000;\n\n        /*\n        * Flags for Params (22.1.12)\n        */\n        public const int PARAM_ATTRIBUTE_IN = 0x0001;\n        public const int PARAM_ATTRIBUTE_OUT = 0x0002;\n        public const int PARAM_ATTRIBUTE_OPTIONAL = 0x0010;\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Outputs/Il2CppDecompiler.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing static Il2CppDumper.Il2CppConstants;\n\nnamespace Il2CppDumper\n{\n    public class Il2CppDecompiler\n    {\n        private readonly Il2CppExecutor executor;\n        private readonly Metadata metadata;\n        private readonly Il2Cpp il2Cpp;\n        private readonly Dictionary<Il2CppMethodDefinition, string> methodModifiers;\n\n        public Il2CppDecompiler(Il2CppExecutor il2CppExecutor)\n        {\n            executor = il2CppExecutor;\n            metadata = il2CppExecutor.metadata;\n            il2Cpp = il2CppExecutor.il2Cpp;\n            methodModifiers = new();\n        }\n\n        public void Decompile(Config config, string outputDir)\n        {\n            var writer = new StreamWriter(new FileStream(outputDir + \"dump.cs\", FileMode.Create), new UTF8Encoding(false));\n            //dump image\n            for (var imageIndex = 0; imageIndex < metadata.imageDefs.Length; imageIndex++)\n            {\n                var imageDef = metadata.imageDefs[imageIndex];\n                writer.Write($\"// Image {imageIndex}: {metadata.GetStringFromIndex(imageDef.nameIndex)} - {imageDef.typeStart}\\n\");\n            }\n            //dump type\n            foreach (var imageDef in metadata.imageDefs)\n            {\n                try\n                {\n                    var imageName = metadata.GetStringFromIndex(imageDef.nameIndex);\n                    var typeEnd = imageDef.typeStart + imageDef.typeCount;\n                    for (int typeDefIndex = imageDef.typeStart; typeDefIndex < typeEnd; typeDefIndex++)\n                    {\n                        var typeDef = metadata.typeDefs[typeDefIndex];\n                        var extends = new List<string>();\n                        if (typeDef.parentIndex >= 0)\n                        {\n                            var parent = il2Cpp.types[typeDef.parentIndex];\n                            var parentName = executor.GetTypeName(parent, false, false);\n                            if (!typeDef.IsValueType && !typeDef.IsEnum && parentName != \"object\")\n                            {\n                                extends.Add(parentName);\n                            }\n                        }\n                        if (typeDef.interfaces_count > 0)\n                        {\n                            for (int i = 0; i < typeDef.interfaces_count; i++)\n                            {\n                                var @interface = il2Cpp.types[metadata.interfaceIndices[typeDef.interfacesStart + i]];\n                                extends.Add(executor.GetTypeName(@interface, false, false));\n                            }\n                        }\n                        writer.Write($\"\\n// Namespace: {metadata.GetStringFromIndex(typeDef.namespaceIndex)}\\n\");\n                        if (config.DumpAttribute)\n                        {\n                            writer.Write(GetCustomAttribute(imageDef, typeDef.customAttributeIndex, typeDef.token));\n                        }\n                        if (config.DumpAttribute && (typeDef.flags & TYPE_ATTRIBUTE_SERIALIZABLE) != 0)\n                            writer.Write(\"[Serializable]\\n\");\n                        var visibility = typeDef.flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;\n                        switch (visibility)\n                        {\n                            case TYPE_ATTRIBUTE_PUBLIC:\n                            case TYPE_ATTRIBUTE_NESTED_PUBLIC:\n                                writer.Write(\"public \");\n                                break;\n                            case TYPE_ATTRIBUTE_NOT_PUBLIC:\n                            case TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM:\n                            case TYPE_ATTRIBUTE_NESTED_ASSEMBLY:\n                                writer.Write(\"internal \");\n                                break;\n                            case TYPE_ATTRIBUTE_NESTED_PRIVATE:\n                                writer.Write(\"private \");\n                                break;\n                            case TYPE_ATTRIBUTE_NESTED_FAMILY:\n                                writer.Write(\"protected \");\n                                break;\n                            case TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM:\n                                writer.Write(\"protected internal \");\n                                break;\n                        }\n                        if ((typeDef.flags & TYPE_ATTRIBUTE_ABSTRACT) != 0 && (typeDef.flags & TYPE_ATTRIBUTE_SEALED) != 0)\n                            writer.Write(\"static \");\n                        else if ((typeDef.flags & TYPE_ATTRIBUTE_INTERFACE) == 0 && (typeDef.flags & TYPE_ATTRIBUTE_ABSTRACT) != 0)\n                            writer.Write(\"abstract \");\n                        else if (!typeDef.IsValueType && !typeDef.IsEnum && (typeDef.flags & TYPE_ATTRIBUTE_SEALED) != 0)\n                            writer.Write(\"sealed \");\n                        if ((typeDef.flags & TYPE_ATTRIBUTE_INTERFACE) != 0)\n                            writer.Write(\"interface \");\n                        else if (typeDef.IsEnum)\n                            writer.Write(\"enum \");\n                        else if (typeDef.IsValueType)\n                            writer.Write(\"struct \");\n                        else\n                            writer.Write(\"class \");\n                        var typeName = executor.GetTypeDefName(typeDef, false, true);\n                        writer.Write($\"{typeName}\");\n                        if (extends.Count > 0)\n                            writer.Write($\" : {string.Join(\", \", extends)}\");\n                        if (config.DumpTypeDefIndex)\n                            writer.Write($\" // TypeDefIndex: {typeDefIndex}\\n{{\");\n                        else\n                            writer.Write(\"\\n{\");\n                        //dump field\n                        if (config.DumpField && typeDef.field_count > 0)\n                        {\n                            writer.Write(\"\\n\\t// Fields\\n\");\n                            var fieldEnd = typeDef.fieldStart + typeDef.field_count;\n                            for (var i = typeDef.fieldStart; i < fieldEnd; ++i)\n                            {\n                                var fieldDef = metadata.fieldDefs[i];\n                                var fieldType = il2Cpp.types[fieldDef.typeIndex];\n                                var isStatic = false;\n                                var isConst = false;\n                                if (config.DumpAttribute)\n                                {\n                                    writer.Write(GetCustomAttribute(imageDef, fieldDef.customAttributeIndex, fieldDef.token, \"\\t\"));\n                                }\n                                writer.Write(\"\\t\");\n                                var access = fieldType.attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;\n                                switch (access)\n                                {\n                                    case FIELD_ATTRIBUTE_PRIVATE:\n                                        writer.Write(\"private \");\n                                        break;\n                                    case FIELD_ATTRIBUTE_PUBLIC:\n                                        writer.Write(\"public \");\n                                        break;\n                                    case FIELD_ATTRIBUTE_FAMILY:\n                                        writer.Write(\"protected \");\n                                        break;\n                                    case FIELD_ATTRIBUTE_ASSEMBLY:\n                                    case FIELD_ATTRIBUTE_FAM_AND_ASSEM:\n                                        writer.Write(\"internal \");\n                                        break;\n                                    case FIELD_ATTRIBUTE_FAM_OR_ASSEM:\n                                        writer.Write(\"protected internal \");\n                                        break;\n                                }\n                                if ((fieldType.attrs & FIELD_ATTRIBUTE_LITERAL) != 0)\n                                {\n                                    isConst = true;\n                                    writer.Write(\"const \");\n                                }\n                                else\n                                {\n                                    if ((fieldType.attrs & FIELD_ATTRIBUTE_STATIC) != 0)\n                                    {\n                                        isStatic = true;\n                                        writer.Write(\"static \");\n                                    }\n                                    if ((fieldType.attrs & FIELD_ATTRIBUTE_INIT_ONLY) != 0)\n                                    {\n                                        writer.Write(\"readonly \");\n                                    }\n                                }\n                                writer.Write($\"{executor.GetTypeName(fieldType, false, false)} {metadata.GetStringFromIndex(fieldDef.nameIndex)}\");\n                                if (metadata.GetFieldDefaultValueFromIndex(i, out var fieldDefaultValue) && fieldDefaultValue.dataIndex != -1)\n                                {\n                                    if (executor.TryGetDefaultValue(fieldDefaultValue.typeIndex, fieldDefaultValue.dataIndex, out var value))\n                                    {\n                                        writer.Write($\" = \");\n                                        if (value is string str)\n                                        {\n                                            writer.Write($\"\\\"{str.ToEscapedString()}\\\"\");\n                                        }\n                                        else if (value is char c)\n                                        {\n                                            var v = (int)c;\n                                            writer.Write($\"'\\\\x{v:x}'\");\n                                        }\n                                        else if (value != null)\n                                        {\n                                            writer.Write($\"{value}\");\n                                        }\n                                        else\n                                        {\n                                            writer.Write(\"null\");\n                                        }\n                                    }\n                                    else\n                                    {\n                                        writer.Write($\" /*Metadata offset 0x{value:X}*/\");\n                                    }\n                                }\n                                if (config.DumpFieldOffset && !isConst)\n                                    writer.Write(\"; // 0x{0:X}\\n\", il2Cpp.GetFieldOffsetFromIndex(typeDefIndex, i - typeDef.fieldStart, i, typeDef.IsValueType, isStatic));\n                                else\n                                    writer.Write(\";\\n\");\n                            }\n                        }\n                        //dump property\n                        if (config.DumpProperty && typeDef.property_count > 0)\n                        {\n                            writer.Write(\"\\n\\t// Properties\\n\");\n                            var propertyEnd = typeDef.propertyStart + typeDef.property_count;\n                            for (var i = typeDef.propertyStart; i < propertyEnd; ++i)\n                            {\n                                var propertyDef = metadata.propertyDefs[i];\n                                if (config.DumpAttribute)\n                                {\n                                    writer.Write(GetCustomAttribute(imageDef, propertyDef.customAttributeIndex, propertyDef.token, \"\\t\"));\n                                }\n                                writer.Write(\"\\t\");\n                                if (propertyDef.get >= 0)\n                                {\n                                    var methodDef = metadata.methodDefs[typeDef.methodStart + propertyDef.get];\n                                    writer.Write(GetModifiers(methodDef));\n                                    var propertyType = il2Cpp.types[methodDef.returnType];\n                                    writer.Write($\"{executor.GetTypeName(propertyType, false, false)} {metadata.GetStringFromIndex(propertyDef.nameIndex)} {{ \");\n                                }\n                                else if (propertyDef.set >= 0)\n                                {\n                                    var methodDef = metadata.methodDefs[typeDef.methodStart + propertyDef.set];\n                                    writer.Write(GetModifiers(methodDef));\n                                    var parameterDef = metadata.parameterDefs[methodDef.parameterStart];\n                                    var propertyType = il2Cpp.types[parameterDef.typeIndex];\n                                    writer.Write($\"{executor.GetTypeName(propertyType, false, false)} {metadata.GetStringFromIndex(propertyDef.nameIndex)} {{ \");\n                                }\n                                if (propertyDef.get >= 0)\n                                    writer.Write(\"get; \");\n                                if (propertyDef.set >= 0)\n                                    writer.Write(\"set; \");\n                                writer.Write(\"}\");\n                                writer.Write(\"\\n\");\n                            }\n                        }\n                        //dump method\n                        if (config.DumpMethod && typeDef.method_count > 0)\n                        {\n                            writer.Write(\"\\n\\t// Methods\\n\");\n                            var methodEnd = typeDef.methodStart + typeDef.method_count;\n                            for (var i = typeDef.methodStart; i < methodEnd; ++i)\n                            {\n                                writer.Write(\"\\n\");\n                                var methodDef = metadata.methodDefs[i];\n                                var isAbstract = (methodDef.flags & METHOD_ATTRIBUTE_ABSTRACT) != 0;\n                                if (config.DumpAttribute)\n                                {\n                                    writer.Write(GetCustomAttribute(imageDef, methodDef.customAttributeIndex, methodDef.token, \"\\t\"));\n                                }\n                                if (config.DumpMethodOffset)\n                                {\n                                    var methodPointer = il2Cpp.GetMethodPointer(imageName, methodDef);\n                                    if (!isAbstract && methodPointer > 0)\n                                    {\n                                        var fixedMethodPointer = il2Cpp.GetRVA(methodPointer);\n                                        writer.Write(\"\\t// RVA: 0x{0:X} Offset: 0x{1:X} VA: 0x{2:X}\", fixedMethodPointer, il2Cpp.MapVATR(methodPointer), methodPointer);\n                                    }\n                                    else\n                                    {\n                                        writer.Write(\"\\t// RVA: -1 Offset: -1\");\n                                    }\n                                    if (methodDef.slot != ushort.MaxValue)\n                                    {\n                                        writer.Write(\" Slot: {0}\", methodDef.slot);\n                                    }\n                                    writer.Write(\"\\n\");\n                                }\n                                writer.Write(\"\\t\");\n                                writer.Write(GetModifiers(methodDef));\n                                var methodReturnType = il2Cpp.types[methodDef.returnType];\n                                var methodName = metadata.GetStringFromIndex(methodDef.nameIndex);\n                                if (methodDef.genericContainerIndex >= 0)\n                                {\n                                    var genericContainer = metadata.genericContainers[methodDef.genericContainerIndex];\n                                    methodName += executor.GetGenericContainerParams(genericContainer);\n                                }\n                                if (methodReturnType.byref == 1)\n                                {\n                                    writer.Write(\"ref \");\n                                }\n                                writer.Write($\"{executor.GetTypeName(methodReturnType, false, false)} {methodName}(\");\n                                var parameterStrs = new List<string>();\n                                for (var j = 0; j < methodDef.parameterCount; ++j)\n                                {\n                                    var parameterStr = \"\";\n                                    var parameterDef = metadata.parameterDefs[methodDef.parameterStart + j];\n                                    var parameterName = metadata.GetStringFromIndex(parameterDef.nameIndex);\n                                    var parameterType = il2Cpp.types[parameterDef.typeIndex];\n                                    var parameterTypeName = executor.GetTypeName(parameterType, false, false);\n                                    if (parameterType.byref == 1)\n                                    {\n                                        if ((parameterType.attrs & PARAM_ATTRIBUTE_OUT) != 0 && (parameterType.attrs & PARAM_ATTRIBUTE_IN) == 0)\n                                        {\n                                            parameterStr += \"out \";\n                                        }\n                                        else if ((parameterType.attrs & PARAM_ATTRIBUTE_OUT) == 0 && (parameterType.attrs & PARAM_ATTRIBUTE_IN) != 0)\n                                        {\n                                            parameterStr += \"in \";\n                                        }\n                                        else\n                                        {\n                                            parameterStr += \"ref \";\n                                        }\n                                    }\n                                    else\n                                    {\n                                        if ((parameterType.attrs & PARAM_ATTRIBUTE_IN) != 0)\n                                        {\n                                            parameterStr += \"[In] \";\n                                        }\n                                        if ((parameterType.attrs & PARAM_ATTRIBUTE_OUT) != 0)\n                                        {\n                                            parameterStr += \"[Out] \";\n                                        }\n                                    }\n                                    parameterStr += $\"{parameterTypeName} {parameterName}\";\n                                    if (metadata.GetParameterDefaultValueFromIndex(methodDef.parameterStart + j, out var parameterDefault) && parameterDefault.dataIndex != -1)\n                                    {\n                                        if (executor.TryGetDefaultValue(parameterDefault.typeIndex, parameterDefault.dataIndex, out var value))\n                                        {\n                                            parameterStr += \" = \";\n                                            if (value is string str)\n                                            {\n                                                parameterStr += $\"\\\"{str.ToEscapedString()}\\\"\";\n                                            }\n                                            else if (value is char c)\n                                            {\n                                                var v = (int)c;\n                                                parameterStr += $\"'\\\\x{v:x}'\";\n                                            }\n                                            else if (value != null)\n                                            {\n                                                parameterStr += $\"{value}\";\n                                            }\n                                            else\n                                            {\n                                                writer.Write(\"null\");\n                                            }\n                                        }\n                                        else\n                                        {\n                                            parameterStr += $\" /*Metadata offset 0x{value:X}*/\";\n                                        }\n                                    }\n                                    parameterStrs.Add(parameterStr);\n                                }\n                                writer.Write(string.Join(\", \", parameterStrs));\n                                if (isAbstract)\n                                {\n                                    writer.Write(\");\\n\");\n                                }\n                                else\n                                {\n                                    writer.Write(\") { }\\n\");\n                                }\n\n                                if (il2Cpp.methodDefinitionMethodSpecs.TryGetValue(i, out var methodSpecs))\n                                {\n                                    writer.Write(\"\\t/* GenericInstMethod :\\n\");\n                                    var groups = methodSpecs.GroupBy(x => il2Cpp.methodSpecGenericMethodPointers[x]);\n                                    foreach (var group in groups)\n                                    {\n                                        writer.Write(\"\\t|\\n\");\n                                        var genericMethodPointer = group.Key;\n                                        if (genericMethodPointer > 0)\n                                        {\n                                            var fixedPointer = il2Cpp.GetRVA(genericMethodPointer);\n                                            writer.Write($\"\\t|-RVA: 0x{fixedPointer:X} Offset: 0x{il2Cpp.MapVATR(genericMethodPointer):X} VA: 0x{genericMethodPointer:X}\\n\");\n                                        }\n                                        else\n                                        {\n                                            writer.Write(\"\\t|-RVA: -1 Offset: -1\\n\");\n                                        }\n                                        foreach (var methodSpec in group)\n                                        {\n                                            (var methodSpecTypeName, var methodSpecMethodName) = executor.GetMethodSpecName(methodSpec);\n                                            writer.Write($\"\\t|-{methodSpecTypeName}.{methodSpecMethodName}\\n\");\n                                        }\n                                    }\n                                    writer.Write(\"\\t*/\\n\");\n                                }\n                            }\n                        }\n                        writer.Write(\"}\\n\");\n                    }\n                }\n                catch (Exception e)\n                {\n                    Console.WriteLine(\"ERROR: Some errors in dumping\");\n                    writer.Write(\"/*\");\n                    writer.Write(e);\n                    writer.Write(\"*/\\n}\\n\");\n                }\n            }\n            writer.Close();\n        }\n\n        public string GetCustomAttribute(Il2CppImageDefinition imageDef, int customAttributeIndex, uint token, string padding = \"\")\n        {\n            if (il2Cpp.Version < 21)\n                return string.Empty;\n            var attributeIndex = metadata.GetCustomAttributeIndex(imageDef, customAttributeIndex, token);\n            if (attributeIndex >= 0)\n            {\n                if (il2Cpp.Version < 29)\n                {\n                    var methodPointer = executor.customAttributeGenerators[attributeIndex];\n                    var fixedMethodPointer = il2Cpp.GetRVA(methodPointer);\n                    var attributeTypeRange = metadata.attributeTypeRanges[attributeIndex];\n                    var sb = new StringBuilder();\n                    for (var i = 0; i < attributeTypeRange.count; i++)\n                    {\n                        var typeIndex = metadata.attributeTypes[attributeTypeRange.start + i];\n                        sb.AppendFormat(\"{0}[{1}] // RVA: 0x{2:X} Offset: 0x{3:X} VA: 0x{4:X}\\n\",\n                            padding,\n                            executor.GetTypeName(il2Cpp.types[typeIndex], false, false),\n                            fixedMethodPointer,\n                            il2Cpp.MapVATR(methodPointer),\n                            methodPointer);\n                    }\n                    return sb.ToString();\n                }\n                else\n                {\n                    var startRange = metadata.attributeDataRanges[attributeIndex];\n                    var endRange = metadata.attributeDataRanges[attributeIndex + 1];\n                    metadata.Position = metadata.header.attributeDataOffset + startRange.startOffset;\n                    var buff = metadata.ReadBytes((int)(endRange.startOffset - startRange.startOffset));\n                    var reader = new CustomAttributeDataReader(executor, buff);\n                    if (reader.Count == 0)\n                    {\n                        return string.Empty;\n                    }\n                    var sb = new StringBuilder();\n                    for (var i = 0; i < reader.Count; i++)\n                    {\n                        sb.Append(padding);\n                        sb.Append(reader.GetStringCustomAttributeData());\n                        sb.Append('\\n');\n                    }\n                    return sb.ToString();\n                }\n            }\n            else\n            {\n                return string.Empty;\n            }\n        }\n\n        public string GetModifiers(Il2CppMethodDefinition methodDef)\n        {\n            if (methodModifiers.TryGetValue(methodDef, out string str))\n                return str;\n            var access = methodDef.flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;\n            switch (access)\n            {\n                case METHOD_ATTRIBUTE_PRIVATE:\n                    str += \"private \";\n                    break;\n                case METHOD_ATTRIBUTE_PUBLIC:\n                    str += \"public \";\n                    break;\n                case METHOD_ATTRIBUTE_FAMILY:\n                    str += \"protected \";\n                    break;\n                case METHOD_ATTRIBUTE_ASSEM:\n                case METHOD_ATTRIBUTE_FAM_AND_ASSEM:\n                    str += \"internal \";\n                    break;\n                case METHOD_ATTRIBUTE_FAM_OR_ASSEM:\n                    str += \"protected internal \";\n                    break;\n            }\n            if ((methodDef.flags & METHOD_ATTRIBUTE_STATIC) != 0)\n                str += \"static \";\n            if ((methodDef.flags & METHOD_ATTRIBUTE_ABSTRACT) != 0)\n            {\n                str += \"abstract \";\n                if ((methodDef.flags & METHOD_ATTRIBUTE_VTABLE_LAYOUT_MASK) == METHOD_ATTRIBUTE_REUSE_SLOT)\n                    str += \"override \";\n            }\n            else if ((methodDef.flags & METHOD_ATTRIBUTE_FINAL) != 0)\n            {\n                if ((methodDef.flags & METHOD_ATTRIBUTE_VTABLE_LAYOUT_MASK) == METHOD_ATTRIBUTE_REUSE_SLOT)\n                    str += \"sealed override \";\n            }\n            else if ((methodDef.flags & METHOD_ATTRIBUTE_VIRTUAL) != 0)\n            {\n                if ((methodDef.flags & METHOD_ATTRIBUTE_VTABLE_LAYOUT_MASK) == METHOD_ATTRIBUTE_NEW_SLOT)\n                    str += \"virtual \";\n                else\n                    str += \"override \";\n            }\n            if ((methodDef.flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) != 0)\n                str += \"extern \";\n            methodModifiers.Add(methodDef, str);\n            return str;\n        }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Outputs/ScriptJson.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace Il2CppDumper\n{\n    public class ScriptJson\n    {\n        public List<ScriptMethod> ScriptMethod = new();\n        public List<ScriptString> ScriptString = new();\n        public List<ScriptMetadata> ScriptMetadata = new();\n        public List<ScriptMetadataMethod> ScriptMetadataMethod = new();\n        public ulong[] Addresses;\n    }\n\n    public class ScriptMethod\n    {\n        public ulong Address;\n        public string Name;\n        public string Signature;\n        public string TypeSignature;\n    }\n\n    public class ScriptString\n    {\n        public ulong Address;\n        public string Value;\n    }\n\n    public class ScriptMetadata\n    {\n        public ulong Address;\n        public string Name;\n        public string Signature;\n    }\n\n    public class ScriptMetadataMethod\n    {\n        public ulong Address;\n        public string Name;\n        public ulong MethodAddress;\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Outputs/StructGenerator.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing System.Text.Json;\nusing System.Text.RegularExpressions;\nusing static Il2CppDumper.Il2CppConstants;\n\nnamespace Il2CppDumper\n{\n    public class StructGenerator\n    {\n        private readonly Il2CppExecutor executor;\n        private readonly Metadata metadata;\n        private readonly Il2Cpp il2Cpp;\n        private readonly Dictionary<Il2CppTypeDefinition, string> typeDefImageNames = new();\n        private readonly HashSet<string> structNameHashSet = new(StringComparer.Ordinal);\n        private readonly List<StructInfo> structInfoList = new();\n        private readonly Dictionary<string, StructInfo> structInfoWithStructName = new();\n        private readonly HashSet<StructInfo> structCache = new();\n        private readonly Dictionary<Il2CppTypeDefinition, string> structNameDic = new();\n        private readonly Dictionary<ulong, string> genericClassStructNameDic = new();\n        private readonly Dictionary<string, Il2CppType> nameGenericClassDic = new();\n        private readonly List<ulong> genericClassList = new();\n        private readonly StringBuilder arrayClassHeader = new();\n        private readonly StringBuilder methodInfoHeader = new();\n        private static readonly HashSet<ulong> methodInfoCache = new();\n        private static readonly HashSet<string> keyword = new(StringComparer.Ordinal)\n        { \"klass\", \"monitor\", \"register\", \"_cs\", \"auto\", \"friend\", \"template\", \"flat\", \"default\", \"_ds\", \"interrupt\",\n            \"unsigned\", \"signed\", \"asm\", \"if\", \"case\", \"break\", \"continue\", \"do\", \"new\", \"_\", \"short\", \"union\", \"class\", \"namespace\"};\n        private static readonly HashSet<string> specialKeywords = new(StringComparer.Ordinal)\n        { \"inline\", \"near\", \"far\" };\n\n        public StructGenerator(Il2CppExecutor il2CppExecutor)\n        {\n            executor = il2CppExecutor;\n            metadata = il2CppExecutor.metadata;\n            il2Cpp = il2CppExecutor.il2Cpp;\n        }\n\n        public void WriteScript(string outputDir)\n        {\n            var json = new ScriptJson();\n            // 生成唯一名称\n            for (var imageIndex = 0; imageIndex < metadata.imageDefs.Length; imageIndex++)\n            {\n                var imageDef = metadata.imageDefs[imageIndex];\n                var imageName = metadata.GetStringFromIndex(imageDef.nameIndex);\n                var typeEnd = imageDef.typeStart + imageDef.typeCount;\n                for (int typeIndex = imageDef.typeStart; typeIndex < typeEnd; typeIndex++)\n                {\n                    var typeDef = metadata.typeDefs[typeIndex];\n                    typeDefImageNames.Add(typeDef, imageName);\n                    CreateStructNameDic(typeDef);\n                }\n            }\n            // 生成后面处理泛型实例要用到的字典\n            foreach (var il2CppType in il2Cpp.types.Where(x => x.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST))\n            {\n                var genericClass = il2Cpp.MapVATR<Il2CppGenericClass>(il2CppType.data.generic_class);\n                var typeDef = executor.GetGenericClassTypeDefinition(genericClass);\n                if (typeDef == null)\n                {\n                    continue;\n                }\n                var typeBaseName = structNameDic[typeDef];\n                var typeToReplaceName = FixName(executor.GetTypeDefName(typeDef, true, true));\n                var typeReplaceName = FixName(executor.GetTypeName(il2CppType, true, false));\n                var typeStructName = typeBaseName.Replace(typeToReplaceName, typeReplaceName);\n                nameGenericClassDic[typeStructName] = il2CppType;\n                genericClassStructNameDic[il2CppType.data.generic_class] = typeStructName;\n            }\n            // 处理函数\n            foreach (var imageDef in metadata.imageDefs)\n            {\n                var imageName = metadata.GetStringFromIndex(imageDef.nameIndex);\n                var typeEnd = imageDef.typeStart + imageDef.typeCount;\n                for (int typeIndex = imageDef.typeStart; typeIndex < typeEnd; typeIndex++)\n                {\n                    var typeDef = metadata.typeDefs[typeIndex];\n                    AddStruct(typeDef);\n                    var typeName = executor.GetTypeDefName(typeDef, true, true);\n                    var methodEnd = typeDef.methodStart + typeDef.method_count;\n                    for (var i = typeDef.methodStart; i < methodEnd; ++i)\n                    {\n                        var methodDef = metadata.methodDefs[i];\n                        var methodName = metadata.GetStringFromIndex(methodDef.nameIndex);\n                        var methodPointer = il2Cpp.GetMethodPointer(imageName, methodDef);\n                        if (methodPointer > 0)\n                        {\n                            var methodTypeSignature = new List<Il2CppTypeEnum>();\n                            var scriptMethod = new ScriptMethod();\n                            json.ScriptMethod.Add(scriptMethod);\n                            scriptMethod.Address = il2Cpp.GetRVA(methodPointer);\n                            var methodFullName = typeName + \"$$\" + methodName;\n                            scriptMethod.Name = methodFullName;\n\n                            var methodReturnType = il2Cpp.types[methodDef.returnType];\n                            var returnType = ParseType(methodReturnType);\n                            if (methodReturnType.byref == 1)\n                            {\n                                returnType += \"*\";\n                            }\n                            methodTypeSignature.Add(methodReturnType.byref == 1 ? Il2CppTypeEnum.IL2CPP_TYPE_PTR : methodReturnType.type);\n                            var signature = $\"{returnType} {FixName(methodFullName)} (\";\n                            var parameterStrs = new List<string>();\n                            if ((methodDef.flags & METHOD_ATTRIBUTE_STATIC) == 0)\n                            {\n                                var thisType = ParseType(il2Cpp.types[typeDef.byvalTypeIndex]);\n                                methodTypeSignature.Add(il2Cpp.types[typeDef.byvalTypeIndex].type);\n                                parameterStrs.Add($\"{thisType} __this\");\n                            }\n                            else if (il2Cpp.Version <= 24)\n                            {\n                                methodTypeSignature.Add(Il2CppTypeEnum.IL2CPP_TYPE_PTR);\n                                parameterStrs.Add($\"Il2CppObject* __this\");\n                            }\n                            for (var j = 0; j < methodDef.parameterCount; j++)\n                            {\n                                var parameterDef = metadata.parameterDefs[methodDef.parameterStart + j];\n                                var parameterName = metadata.GetStringFromIndex(parameterDef.nameIndex);\n                                var parameterType = il2Cpp.types[parameterDef.typeIndex];\n                                var parameterCType = ParseType(parameterType);\n                                if (parameterType.byref == 1)\n                                {\n                                    parameterCType += \"*\";\n                                }\n                                methodTypeSignature.Add(parameterType.byref == 1 ? Il2CppTypeEnum.IL2CPP_TYPE_PTR : parameterType.type);\n                                parameterStrs.Add($\"{parameterCType} {FixName(parameterName)}\");\n                            }\n                            methodTypeSignature.Add(Il2CppTypeEnum.IL2CPP_TYPE_PTR);\n                            parameterStrs.Add(\"const MethodInfo* method\");\n                            signature += string.Join(\", \", parameterStrs);\n                            signature += \");\";\n                            scriptMethod.Signature = signature;\n                            scriptMethod.TypeSignature = GetMethodTypeSignature(methodTypeSignature);\n                        }\n                        //泛型实例函数\n                        if (il2Cpp.methodDefinitionMethodSpecs.TryGetValue(i, out var methodSpecs))\n                        {\n                            foreach (var methodSpec in methodSpecs)\n                            {\n                                var genericMethodPointer = il2Cpp.methodSpecGenericMethodPointers[methodSpec];\n                                if (genericMethodPointer > 0)\n                                {\n                                    var methodTypeSignature = new List<Il2CppTypeEnum>();\n                                    var scriptMethod = new ScriptMethod();\n                                    json.ScriptMethod.Add(scriptMethod);\n                                    scriptMethod.Address = il2Cpp.GetRVA(genericMethodPointer);\n                                    var methodInfoName = $\"MethodInfo_{scriptMethod.Address:X}\";\n                                    var structTypeName = structNameDic[typeDef];\n                                    var rgctxs = GenerateRGCTX(imageName, methodDef);\n                                    if (methodInfoCache.Add(genericMethodPointer))\n                                    {\n                                        GenerateMethodInfo(methodInfoName, structTypeName, rgctxs);\n                                    }\n                                    (var methodSpecTypeName, var methodSpecMethodName) = executor.GetMethodSpecName(methodSpec, true);\n                                    var methodFullName = methodSpecTypeName + \"$$\" + methodSpecMethodName;\n                                    scriptMethod.Name = methodFullName;\n\n                                    var genericContext = executor.GetMethodSpecGenericContext(methodSpec);\n                                    var methodReturnType = il2Cpp.types[methodDef.returnType];\n                                    var returnType = ParseType(methodReturnType, genericContext);\n                                    if (methodReturnType.byref == 1)\n                                    {\n                                        returnType += \"*\";\n                                    }\n                                    methodTypeSignature.Add(methodReturnType.byref == 1 ? Il2CppTypeEnum.IL2CPP_TYPE_PTR : methodReturnType.type);\n                                    var signature = $\"{returnType} {FixName(methodFullName)} (\";\n                                    var parameterStrs = new List<string>();\n                                    if ((methodDef.flags & METHOD_ATTRIBUTE_STATIC) == 0)\n                                    {\n                                        string thisType;\n                                        if (methodSpec.classIndexIndex != -1)\n                                        {\n                                            var typeBaseName = structNameDic[typeDef];\n                                            var typeToReplaceName = FixName(typeName);\n                                            var typeReplaceName = FixName(methodSpecTypeName);\n                                            var typeStructName = typeBaseName.Replace(typeToReplaceName, typeReplaceName);\n                                            if (nameGenericClassDic.TryGetValue(typeStructName, out var il2CppType))\n                                            {\n                                                thisType = ParseType(il2CppType);\n                                                methodTypeSignature.Add(il2CppType.type);\n                                            }\n                                            else\n                                            {\n                                                //没有单独的泛型实例类\n                                                thisType = ParseType(il2Cpp.types[typeDef.byvalTypeIndex]);\n                                                methodTypeSignature.Add(il2Cpp.types[typeDef.byvalTypeIndex].type);\n                                            }\n                                        }\n                                        else\n                                        {\n                                            thisType = ParseType(il2Cpp.types[typeDef.byvalTypeIndex]);\n                                            methodTypeSignature.Add(il2Cpp.types[typeDef.byvalTypeIndex].type);\n                                        }\n                                        parameterStrs.Add($\"{thisType} __this\");\n                                    }\n                                    else if (il2Cpp.Version <= 24)\n                                    {\n                                        methodTypeSignature.Add(Il2CppTypeEnum.IL2CPP_TYPE_PTR);\n                                        parameterStrs.Add($\"Il2CppObject* __this\");\n                                    }\n                                    for (var j = 0; j < methodDef.parameterCount; j++)\n                                    {\n                                        var parameterDef = metadata.parameterDefs[methodDef.parameterStart + j];\n                                        var parameterName = metadata.GetStringFromIndex(parameterDef.nameIndex);\n                                        var parameterType = il2Cpp.types[parameterDef.typeIndex];\n                                        var parameterCType = ParseType(parameterType, genericContext);\n                                        if (parameterType.byref == 1)\n                                        {\n                                            parameterCType += \"*\";\n                                        }\n                                        methodTypeSignature.Add(parameterType.byref == 1 ? Il2CppTypeEnum.IL2CPP_TYPE_PTR : parameterType.type);\n                                        parameterStrs.Add($\"{parameterCType} {FixName(parameterName)}\");\n                                    }\n                                    methodTypeSignature.Add(Il2CppTypeEnum.IL2CPP_TYPE_PTR);\n                                    parameterStrs.Add($\"const {methodInfoName}* method\");\n                                    signature += string.Join(\", \", parameterStrs);\n                                    signature += \");\";\n                                    scriptMethod.Signature = signature;\n                                    scriptMethod.TypeSignature = GetMethodTypeSignature(methodTypeSignature);\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n            //处理函数范围\n            List<ulong> orderedPointers;\n            if (il2Cpp.Version >= 24.2)\n            {\n                orderedPointers = new List<ulong>();\n                foreach (var pair in il2Cpp.codeGenModuleMethodPointers)\n                {\n                    orderedPointers.AddRange(pair.Value);\n                }\n            }\n            else\n            {\n                orderedPointers = il2Cpp.methodPointers.ToList();\n            }\n            orderedPointers.AddRange(il2Cpp.genericMethodPointers);\n            orderedPointers.AddRange(il2Cpp.invokerPointers);\n            if (il2Cpp.Version < 29)\n            {\n                orderedPointers.AddRange(executor.customAttributeGenerators);\n            }\n            if (il2Cpp.Version >= 22)\n            {\n                if (il2Cpp.reversePInvokeWrappers != null)\n                    orderedPointers.AddRange(il2Cpp.reversePInvokeWrappers);\n                if (il2Cpp.unresolvedVirtualCallPointers != null)\n                    orderedPointers.AddRange(il2Cpp.unresolvedVirtualCallPointers);\n            }\n            //TODO interopData内也包含函数\n            orderedPointers = orderedPointers.Distinct().OrderBy(x => x).ToList();\n            orderedPointers.Remove(0);\n            json.Addresses = new ulong[orderedPointers.Count];\n            for (int i = 0; i < orderedPointers.Count; i++)\n            {\n                json.Addresses[i] = il2Cpp.GetRVA(orderedPointers[i]);\n            }\n            // 处理MetadataUsage\n            if (il2Cpp.Version >= 27)\n            {\n                var sectionHelper = executor.GetSectionHelper();\n                foreach (var sec in sectionHelper.Data)\n                {\n                    il2Cpp.Position = sec.offset;\n                    var end = Math.Min(sec.offsetEnd, il2Cpp.Length) - il2Cpp.PointerSize;\n                    while (il2Cpp.Position < end)\n                    {\n                        var addr = il2Cpp.Position;\n                        var metadataValue = il2Cpp.ReadUIntPtr();\n                        var position = il2Cpp.Position;\n                        if (metadataValue < uint.MaxValue)\n                        {\n                            var encodedToken = (uint)metadataValue;\n                            var usage = Metadata.GetEncodedIndexType(encodedToken);\n                            if (usage > 0 && usage <= 6)\n                            {\n                                var decodedIndex = metadata.GetDecodedMethodIndex(encodedToken);\n                                if (metadataValue == ((usage << 29) | (decodedIndex << 1)) + 1)\n                                {\n                                    var va = il2Cpp.MapRTVA(addr);\n                                    if (va > 0)\n                                    {\n                                        switch ((Il2CppMetadataUsage)usage)\n                                        {\n                                            case Il2CppMetadataUsage.kIl2CppMetadataUsageInvalid:\n                                                break;\n                                            case Il2CppMetadataUsage.kIl2CppMetadataUsageTypeInfo:\n                                                if (decodedIndex < il2Cpp.types.Length)\n                                                {\n                                                    AddMetadataUsageTypeInfo(json, decodedIndex, va);\n                                                }\n                                                break;\n                                            case Il2CppMetadataUsage.kIl2CppMetadataUsageIl2CppType:\n                                                if (decodedIndex < il2Cpp.types.Length)\n                                                {\n                                                    AddMetadataUsageIl2CppType(json, decodedIndex, va);\n                                                }\n                                                break;\n                                            case Il2CppMetadataUsage.kIl2CppMetadataUsageMethodDef:\n                                                if (decodedIndex < metadata.methodDefs.Length)\n                                                {\n                                                    AddMetadataUsageMethodDef(json, decodedIndex, va);\n                                                }\n                                                break;\n                                            case Il2CppMetadataUsage.kIl2CppMetadataUsageFieldInfo:\n                                                if (decodedIndex < metadata.fieldRefs.Length)\n                                                {\n                                                    AddMetadataUsageFieldInfo(json, decodedIndex, va);\n                                                }\n                                                break;\n                                            case Il2CppMetadataUsage.kIl2CppMetadataUsageStringLiteral:\n                                                if (decodedIndex < metadata.stringLiterals.Length)\n                                                {\n                                                    AddMetadataUsageStringLiteral(json, decodedIndex, va);\n                                                }\n                                                break;\n                                            case Il2CppMetadataUsage.kIl2CppMetadataUsageMethodRef:\n                                                if (decodedIndex < il2Cpp.methodSpecs.Length)\n                                                {\n                                                    AddMetadataUsageMethodRef(json, decodedIndex, va);\n                                                }\n                                                break;\n                                        }\n                                        if (il2Cpp.Position != position)\n                                        {\n                                            il2Cpp.Position = position;\n                                        }\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n            else if (il2Cpp.Version > 16 && il2Cpp.Version < 27)\n            {\n                foreach (var i in metadata.metadataUsageDic[Il2CppMetadataUsage.kIl2CppMetadataUsageTypeInfo])\n                {\n                    AddMetadataUsageTypeInfo(json, i.Value, il2Cpp.metadataUsages[i.Key]);\n                }\n                foreach (var i in metadata.metadataUsageDic[Il2CppMetadataUsage.kIl2CppMetadataUsageIl2CppType])\n                {\n                    AddMetadataUsageIl2CppType(json, i.Value, il2Cpp.metadataUsages[i.Key]);\n                }\n                foreach (var i in metadata.metadataUsageDic[Il2CppMetadataUsage.kIl2CppMetadataUsageMethodDef])\n                {\n                    AddMetadataUsageMethodDef(json, i.Value, il2Cpp.metadataUsages[i.Key]);\n                }\n                foreach (var i in metadata.metadataUsageDic[Il2CppMetadataUsage.kIl2CppMetadataUsageFieldInfo])\n                {\n                    AddMetadataUsageFieldInfo(json, i.Value, il2Cpp.metadataUsages[i.Key]);\n                }\n                foreach (var i in metadata.metadataUsageDic[Il2CppMetadataUsage.kIl2CppMetadataUsageStringLiteral])\n                {\n                    AddMetadataUsageStringLiteral(json, i.Value, il2Cpp.metadataUsages[i.Key]);\n                }\n                foreach (var i in metadata.metadataUsageDic[Il2CppMetadataUsage.kIl2CppMetadataUsageMethodRef])\n                {\n                    AddMetadataUsageMethodRef(json, i.Value, il2Cpp.metadataUsages[i.Key]);\n                }\n            }\n            //输出单独的StringLiteral\n            var stringLiterals = json.ScriptString.Select(x => new\n            {\n                value = x.Value,\n                address = $\"0x{x.Address:X}\"\n            }).ToArray();\n            var jsonOptions = new JsonSerializerOptions() { WriteIndented = true, IncludeFields = true };\n            File.WriteAllText(outputDir + \"stringliteral.json\", JsonSerializer.Serialize(stringLiterals, jsonOptions), new UTF8Encoding(false));\n            //写入文件\n            File.WriteAllText(outputDir + \"script.json\", JsonSerializer.Serialize(json, jsonOptions));\n            //il2cpp.h\n            for (int i = 0; i < genericClassList.Count; i++)\n            {\n                var pointer = genericClassList[i];\n                AddGenericClassStruct(pointer);\n            }\n            var headerStruct = new StringBuilder();\n            foreach (var info in structInfoList)\n            {\n                structInfoWithStructName.Add(info.TypeName + \"_o\", info);\n            }\n            foreach (var info in structInfoList)\n            {\n                headerStruct.Append(RecursionStructInfo(info));\n            }\n            var sb = new StringBuilder();\n            sb.Append(HeaderConstants.GenericHeader);\n            switch (il2Cpp.Version)\n            {\n                case 22:\n                    sb.Append(HeaderConstants.HeaderV22);\n                    break;\n                case 23:\n                case 24:\n                    sb.Append(HeaderConstants.HeaderV240);\n                    break;\n                case 24.1:\n                    sb.Append(HeaderConstants.HeaderV241);\n                    break;\n                case 24.2:\n                case 24.3:\n                case 24.4:\n                case 24.5:\n                    sb.Append(HeaderConstants.HeaderV242);\n                    break;\n                case 27:\n                case 27.1:\n                case 27.2:\n                    sb.Append(HeaderConstants.HeaderV27);\n                    break;\n                case 29:\n                case 29.1:\n                case 31:\n                    sb.Append(HeaderConstants.HeaderV29);\n                    break;\n                default:\n                    Console.WriteLine($\"WARNING: This il2cpp version [{il2Cpp.Version}] does not support generating .h files\");\n                    return;\n            }\n            sb.Append(headerStruct);\n            sb.Append(arrayClassHeader);\n            sb.Append(methodInfoHeader);\n            File.WriteAllText(outputDir + \"il2cpp.h\", sb.ToString());\n        }\n\n        private void AddMetadataUsageTypeInfo(ScriptJson json, uint index, ulong address)\n        {\n            var type = il2Cpp.types[index];\n            var typeName = executor.GetTypeName(type, true, false);\n            var scriptMetadata = new ScriptMetadata();\n            json.ScriptMetadata.Add(scriptMetadata);\n            scriptMetadata.Address = il2Cpp.GetRVA(address);\n            scriptMetadata.Name = typeName + \"_TypeInfo\";\n            var signature = GetIl2CppStructName(type);\n            if (signature.EndsWith(\"_array\"))\n            {\n                scriptMetadata.Signature = \"Il2CppClass*\";\n            }\n            else\n            {\n                scriptMetadata.Signature = FixName(signature) + \"_c*\";\n            }\n        }\n\n        private void AddMetadataUsageIl2CppType(ScriptJson json, uint index, ulong address)\n        {\n            var type = il2Cpp.types[index];\n            var typeName = executor.GetTypeName(type, true, false);\n            var scriptMetadata = new ScriptMetadata();\n            json.ScriptMetadata.Add(scriptMetadata);\n            scriptMetadata.Address = il2Cpp.GetRVA(address);\n            scriptMetadata.Name = typeName + \"_var\";\n            scriptMetadata.Signature = \"Il2CppType*\";\n        }\n\n        private void AddMetadataUsageMethodDef(ScriptJson json, uint index, ulong address)\n        {\n            var methodDef = metadata.methodDefs[index];\n            var typeDef = metadata.typeDefs[methodDef.declaringType];\n            var typeName = executor.GetTypeDefName(typeDef, true, true);\n            var methodName = typeName + \".\" + metadata.GetStringFromIndex(methodDef.nameIndex) + \"()\";\n            var scriptMetadataMethod = new ScriptMetadataMethod();\n            json.ScriptMetadataMethod.Add(scriptMetadataMethod);\n            scriptMetadataMethod.Address = il2Cpp.GetRVA(address);\n            scriptMetadataMethod.Name = \"Method$\" + methodName;\n            var imageName = typeDefImageNames[typeDef];\n            var methodPointer = il2Cpp.GetMethodPointer(imageName, methodDef);\n            if (methodPointer > 0)\n            {\n                scriptMetadataMethod.MethodAddress = il2Cpp.GetRVA(methodPointer);\n            }\n        }\n\n        private void AddMetadataUsageFieldInfo(ScriptJson json, uint index, ulong address)\n        {\n            var fieldRef = metadata.fieldRefs[index];\n            var type = il2Cpp.types[fieldRef.typeIndex];\n            var typeDef = GetTypeDefinition(type);\n            var fieldDef = metadata.fieldDefs[typeDef.fieldStart + fieldRef.fieldIndex];\n            var fieldName = executor.GetTypeName(type, true, false) + \".\" + metadata.GetStringFromIndex(fieldDef.nameIndex);\n            var scriptMetadata = new ScriptMetadata();\n            json.ScriptMetadata.Add(scriptMetadata);\n            scriptMetadata.Address = il2Cpp.GetRVA(address);\n            scriptMetadata.Name = \"Field$\" + fieldName;\n        }\n\n        private void AddMetadataUsageStringLiteral(ScriptJson json, uint index, ulong address)\n        {\n            var scriptString = new ScriptString();\n            json.ScriptString.Add(scriptString);\n            scriptString.Address = il2Cpp.GetRVA(address);\n            scriptString.Value = metadata.GetStringLiteralFromIndex(index);\n        }\n\n        private void AddMetadataUsageMethodRef(ScriptJson json, uint index, ulong address)\n        {\n            var methodSpec = il2Cpp.methodSpecs[index];\n            var scriptMetadataMethod = new ScriptMetadataMethod();\n            json.ScriptMetadataMethod.Add(scriptMetadataMethod);\n            scriptMetadataMethod.Address = il2Cpp.GetRVA(address);\n            (var methodSpecTypeName, var methodSpecMethodName) = executor.GetMethodSpecName(methodSpec, true);\n            scriptMetadataMethod.Name = \"Method$\" + methodSpecTypeName + \".\" + methodSpecMethodName + \"()\";\n            if (il2Cpp.methodSpecGenericMethodPointers.ContainsKey(methodSpec))\n            {\n                var genericMethodPointer = il2Cpp.methodSpecGenericMethodPointers[methodSpec];\n                if (genericMethodPointer > 0)\n                {\n                    scriptMetadataMethod.MethodAddress = il2Cpp.GetRVA(genericMethodPointer);\n                }\n            }\n        }\n\n        private static string FixName(string str)\n        {\n            if (keyword.Contains(str))\n            {\n                str = \"_\" + str;\n            }\n            else if (specialKeywords.Contains(str))\n            {\n                str = \"_\" + str + \"_\";\n            }\n\n            if (Regex.IsMatch(str, \"^[0-9]\"))\n            {\n                return \"_\" + str;\n            }\n            else\n            {\n                return Regex.Replace(str, \"[^a-zA-Z0-9_]\", \"_\");\n            }\n        }\n\n        private string ParseType(Il2CppType il2CppType, Il2CppGenericContext context = null)\n        {\n            switch (il2CppType.type)\n            {\n                case Il2CppTypeEnum.IL2CPP_TYPE_VOID:\n                    return \"void\";\n                case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN:\n                    return \"bool\";\n                case Il2CppTypeEnum.IL2CPP_TYPE_CHAR:\n                    return \"uint16_t\"; //Il2CppChar\n                case Il2CppTypeEnum.IL2CPP_TYPE_I1:\n                    return \"int8_t\";\n                case Il2CppTypeEnum.IL2CPP_TYPE_U1:\n                    return \"uint8_t\";\n                case Il2CppTypeEnum.IL2CPP_TYPE_I2:\n                    return \"int16_t\";\n                case Il2CppTypeEnum.IL2CPP_TYPE_U2:\n                    return \"uint16_t\";\n                case Il2CppTypeEnum.IL2CPP_TYPE_I4:\n                    return \"int32_t\";\n                case Il2CppTypeEnum.IL2CPP_TYPE_U4:\n                    return \"uint32_t\";\n                case Il2CppTypeEnum.IL2CPP_TYPE_I8:\n                    return \"int64_t\";\n                case Il2CppTypeEnum.IL2CPP_TYPE_U8:\n                    return \"uint64_t\";\n                case Il2CppTypeEnum.IL2CPP_TYPE_R4:\n                    return \"float\";\n                case Il2CppTypeEnum.IL2CPP_TYPE_R8:\n                    return \"double\";\n                case Il2CppTypeEnum.IL2CPP_TYPE_STRING:\n                    return \"System_String_o*\";\n                case Il2CppTypeEnum.IL2CPP_TYPE_PTR:\n                    {\n                        var oriType = il2Cpp.GetIl2CppType(il2CppType.data.type);\n                        return ParseType(oriType) + \"*\";\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE:\n                    {\n                        var typeDef = executor.GetTypeDefinitionFromIl2CppType(il2CppType);\n                        if (typeDef.IsEnum)\n                        {\n                            return ParseType(il2Cpp.types[typeDef.elementTypeIndex]);\n                        }\n                        return structNameDic[typeDef] + \"_o\";\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_CLASS:\n                    {\n                        var typeDef = executor.GetTypeDefinitionFromIl2CppType(il2CppType);\n                        return structNameDic[typeDef] + \"_o*\";\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_VAR:\n                    {\n                        if (context != null)\n                        {\n                            var genericParameter = executor.GetGenericParameteFromIl2CppType(il2CppType);\n                            var genericInst = il2Cpp.MapVATR<Il2CppGenericInst>(context.class_inst);\n                            var pointers = il2Cpp.MapVATR<ulong>(genericInst.type_argv, genericInst.type_argc);\n                            var pointer = pointers[genericParameter.num];\n                            var type = il2Cpp.GetIl2CppType(pointer);\n                            return ParseType(type);\n                        }\n                        return \"Il2CppObject*\";\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY:\n                    {\n                        var arrayType = il2Cpp.MapVATR<Il2CppArrayType>(il2CppType.data.array);\n                        var elementType = il2Cpp.GetIl2CppType(arrayType.etype);\n                        var elementStructName = GetIl2CppStructName(elementType, context);\n                        var typeStructName = elementStructName + \"_array\";\n                        if (structNameHashSet.Add(typeStructName))\n                        {\n                            ParseArrayClassStruct(elementType, context);\n                        }\n                        return typeStructName + \"*\";\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST:\n                    {\n                        var genericClass = il2Cpp.MapVATR<Il2CppGenericClass>(il2CppType.data.generic_class);\n                        var typeDef = executor.GetGenericClassTypeDefinition(genericClass);\n                        var typeStructName = genericClassStructNameDic[il2CppType.data.generic_class];\n                        if (structNameHashSet.Add(typeStructName))\n                        {\n                            genericClassList.Add(il2CppType.data.generic_class);\n                        }\n                        if (typeDef.IsValueType)\n                        {\n                            if (typeDef.IsEnum)\n                            {\n                                return ParseType(il2Cpp.types[typeDef.elementTypeIndex]);\n                            }\n                            return typeStructName + \"_o\";\n                        }\n                        return typeStructName + \"_o*\";\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_TYPEDBYREF:\n                    return \"Il2CppObject*\";\n                case Il2CppTypeEnum.IL2CPP_TYPE_I:\n                    return \"intptr_t\";\n                case Il2CppTypeEnum.IL2CPP_TYPE_U:\n                    return \"uintptr_t\";\n                case Il2CppTypeEnum.IL2CPP_TYPE_OBJECT:\n                    return \"Il2CppObject*\";\n                case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY:\n                    {\n                        var elementType = il2Cpp.GetIl2CppType(il2CppType.data.type);\n                        var elementStructName = GetIl2CppStructName(elementType, context);\n                        var typeStructName = elementStructName + \"_array\";\n                        if (structNameHashSet.Add(typeStructName))\n                        {\n                            ParseArrayClassStruct(elementType, context);\n                        }\n                        return typeStructName + \"*\";\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_MVAR:\n                    {\n                        if (context != null)\n                        {\n                            var genericParameter = executor.GetGenericParameteFromIl2CppType(il2CppType);\n                            //https://github.com/Perfare/Il2CppDumper/issues/687\n                            if (context.method_inst == 0 && context.class_inst != 0)\n                            {\n                                goto case Il2CppTypeEnum.IL2CPP_TYPE_VAR;\n                            }\n                            var genericInst = il2Cpp.MapVATR<Il2CppGenericInst>(context.method_inst);\n                            var pointers = il2Cpp.MapVATR<ulong>(genericInst.type_argv, genericInst.type_argc);\n                            var pointer = pointers[genericParameter.num];\n                            var type = il2Cpp.GetIl2CppType(pointer);\n                            return ParseType(type);\n                        }\n                        return \"Il2CppObject*\";\n                    }\n                default:\n                    throw new NotSupportedException();\n            }\n        }\n        public static string GetMethodTypeSignature(List<Il2CppTypeEnum> types)\n        {\n            string signature = string.Empty;\n            foreach (Il2CppTypeEnum type in types)\n            {\n                signature += type switch\n                {\n                    Il2CppTypeEnum.IL2CPP_TYPE_VOID => \"v\",\n                    Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN or Il2CppTypeEnum.IL2CPP_TYPE_CHAR or Il2CppTypeEnum.IL2CPP_TYPE_I1 or Il2CppTypeEnum.IL2CPP_TYPE_U1 or Il2CppTypeEnum.IL2CPP_TYPE_I2 or Il2CppTypeEnum.IL2CPP_TYPE_U2 or Il2CppTypeEnum.IL2CPP_TYPE_I4 or Il2CppTypeEnum.IL2CPP_TYPE_U4 => \"i\",\n                    Il2CppTypeEnum.IL2CPP_TYPE_I8 or Il2CppTypeEnum.IL2CPP_TYPE_U8 => \"j\",\n                    Il2CppTypeEnum.IL2CPP_TYPE_R4 => \"f\",\n                    Il2CppTypeEnum.IL2CPP_TYPE_R8 => \"d\",\n                    Il2CppTypeEnum.IL2CPP_TYPE_STRING or Il2CppTypeEnum.IL2CPP_TYPE_PTR or Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE or Il2CppTypeEnum.IL2CPP_TYPE_CLASS or Il2CppTypeEnum.IL2CPP_TYPE_VAR or Il2CppTypeEnum.IL2CPP_TYPE_ARRAY or Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST or Il2CppTypeEnum.IL2CPP_TYPE_TYPEDBYREF or Il2CppTypeEnum.IL2CPP_TYPE_I or Il2CppTypeEnum.IL2CPP_TYPE_U or Il2CppTypeEnum.IL2CPP_TYPE_OBJECT or Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY or Il2CppTypeEnum.IL2CPP_TYPE_MVAR => \"i\",\n                    _ => throw new NotSupportedException(),\n                };\n            }\n            return signature;\n        }\n\n        private void AddStruct(Il2CppTypeDefinition typeDef)\n        {\n            var structInfo = new StructInfo();\n            structInfoList.Add(structInfo);\n            structInfo.TypeName = structNameDic[typeDef];\n            structInfo.IsValueType = typeDef.IsValueType;\n            AddParents(typeDef, structInfo);\n            AddFields(typeDef, structInfo, null);\n            AddVTableMethod(structInfo, typeDef);\n            AddRGCTX(structInfo, typeDef);\n        }\n\n        private void AddGenericClassStruct(ulong pointer)\n        {\n            var genericClass = il2Cpp.MapVATR<Il2CppGenericClass>(pointer);\n            var typeDef = executor.GetGenericClassTypeDefinition(genericClass);\n            var structInfo = new StructInfo();\n            structInfoList.Add(structInfo);\n            structInfo.TypeName = genericClassStructNameDic[pointer];\n            structInfo.IsValueType = typeDef.IsValueType;\n            AddParents(typeDef, structInfo);\n            AddFields(typeDef, structInfo, genericClass.context);\n            AddVTableMethod(structInfo, typeDef);\n        }\n\n        private void AddParents(Il2CppTypeDefinition typeDef, StructInfo structInfo)\n        {\n            if (!typeDef.IsValueType && !typeDef.IsEnum)\n            {\n                if (typeDef.parentIndex >= 0)\n                {\n                    var parent = il2Cpp.types[typeDef.parentIndex];\n                    if (parent.type != Il2CppTypeEnum.IL2CPP_TYPE_OBJECT)\n                    {\n                        structInfo.Parent = GetIl2CppStructName(parent);\n                    }\n                }\n            }\n        }\n\n        private void AddFields(Il2CppTypeDefinition typeDef, StructInfo structInfo, Il2CppGenericContext context)\n        {\n            if (typeDef.field_count > 0)\n            {\n                var fieldEnd = typeDef.fieldStart + typeDef.field_count;\n                var cache = new HashSet<string>(StringComparer.Ordinal);\n                for (var i = typeDef.fieldStart; i < fieldEnd; ++i)\n                {\n                    var fieldDef = metadata.fieldDefs[i];\n                    var fieldType = il2Cpp.types[fieldDef.typeIndex];\n                    if ((fieldType.attrs & FIELD_ATTRIBUTE_LITERAL) != 0)\n                    {\n                        continue;\n                    }\n                    var structFieldInfo = new StructFieldInfo\n                    {\n                        FieldTypeName = ParseType(fieldType, context)\n                    };\n                    var fieldName = FixName(metadata.GetStringFromIndex(fieldDef.nameIndex));\n                    if (!cache.Add(fieldName))\n                    {\n                        fieldName = $\"_{i - typeDef.fieldStart}_{fieldName}\";\n                    }\n                    structFieldInfo.FieldName = fieldName;\n                    structFieldInfo.IsValueType = IsValueType(fieldType, context);\n                    structFieldInfo.IsCustomType = IsCustomType(fieldType, context);\n                    if ((fieldType.attrs & FIELD_ATTRIBUTE_STATIC) != 0)\n                    {\n                        structInfo.StaticFields.Add(structFieldInfo);\n                    }\n                    else\n                    {\n                        structInfo.Fields.Add(structFieldInfo);\n                    }\n                }\n            }\n        }\n\n        private void AddVTableMethod(StructInfo structInfo, Il2CppTypeDefinition typeDef)\n        {\n            var dic = new SortedDictionary<int, Il2CppMethodDefinition>();\n            for (int i = 0; i < typeDef.vtable_count; i++)\n            {\n                var vTableIndex = typeDef.vtableStart + i;\n                var encodedMethodIndex = metadata.vtableMethods[vTableIndex];\n                var usage = Metadata.GetEncodedIndexType(encodedMethodIndex);\n                var index = metadata.GetDecodedMethodIndex(encodedMethodIndex);\n                Il2CppMethodDefinition methodDef;\n                if (usage == 6) //kIl2CppMetadataUsageMethodRef\n                {\n                    var methodSpec = il2Cpp.methodSpecs[index];\n                    methodDef = metadata.methodDefs[methodSpec.methodDefinitionIndex];\n                }\n                else\n                {\n                    methodDef = metadata.methodDefs[index];\n                }\n                if (methodDef.slot != ushort.MaxValue)\n                {\n                    dic[methodDef.slot] = methodDef;\n                }\n            }\n            if (dic.Count > 0)\n            {\n                structInfo.VTableMethod = new StructVTableMethodInfo[dic.Last().Key + 1];\n                foreach (var i in dic)\n                {\n                    var methodInfo = new StructVTableMethodInfo();\n                    structInfo.VTableMethod[i.Key] = methodInfo;\n                    var methodDef = i.Value;\n                    methodInfo.MethodName = $\"{FixName(metadata.GetStringFromIndex(methodDef.nameIndex))}\";\n                }\n            }\n        }\n\n        private void AddRGCTX(StructInfo structInfo, Il2CppTypeDefinition typeDef)\n        {\n            var imageName = typeDefImageNames[typeDef];\n            var collection = executor.GetRGCTXDefinition(imageName, typeDef);\n            if (collection != null)\n            {\n                foreach (var definitionData in collection)\n                {\n                    var structRGCTXInfo = new StructRGCTXInfo();\n                    structInfo.RGCTXs.Add(structRGCTXInfo);\n                    structRGCTXInfo.Type = definitionData.type;\n                    Il2CppRGCTXDefinitionData rgctxDefData;\n                    if (il2Cpp.Version >= 27.2)\n                    {\n                        rgctxDefData = il2Cpp.MapVATR<Il2CppRGCTXDefinitionData>(definitionData._data);\n                    }\n                    else\n                    {\n                        rgctxDefData = definitionData.data;\n                    }\n                    switch (definitionData.type)\n                    {\n                        case Il2CppRGCTXDataType.IL2CPP_RGCTX_DATA_TYPE:\n                            {\n                                var il2CppType = il2Cpp.types[rgctxDefData.typeIndex];\n                                structRGCTXInfo.TypeName = FixName(executor.GetTypeName(il2CppType, true, false));\n                                break;\n                            }\n                        case Il2CppRGCTXDataType.IL2CPP_RGCTX_DATA_CLASS:\n                            {\n                                var il2CppType = il2Cpp.types[rgctxDefData.typeIndex];\n                                structRGCTXInfo.ClassName = FixName(executor.GetTypeName(il2CppType, true, false));\n                                break;\n                            }\n                        case Il2CppRGCTXDataType.IL2CPP_RGCTX_DATA_METHOD:\n                            {\n                                var methodSpec = il2Cpp.methodSpecs[rgctxDefData.methodIndex];\n                                (var methodSpecTypeName, var methodSpecMethodName) = executor.GetMethodSpecName(methodSpec, true);\n                                structRGCTXInfo.MethodName = FixName(methodSpecTypeName + \".\" + methodSpecMethodName);\n                                break;\n                            }\n                    }\n                }\n            }\n        }\n\n        private List<StructRGCTXInfo> GenerateRGCTX(string imageName, Il2CppMethodDefinition methodDef)\n        {\n            var rgctxs = new List<StructRGCTXInfo>();\n            var collection = executor.GetRGCTXDefinition(imageName, methodDef);\n            if (collection != null)\n            {\n                foreach (var definitionData in collection)\n                {\n                    var structRGCTXInfo = new StructRGCTXInfo();\n                    rgctxs.Add(structRGCTXInfo);\n                    structRGCTXInfo.Type = definitionData.type;\n                    Il2CppRGCTXDefinitionData rgctxDefData;\n                    if (il2Cpp.Version >= 27.2)\n                    {\n                        rgctxDefData = il2Cpp.MapVATR<Il2CppRGCTXDefinitionData>(definitionData._data);\n                    }\n                    else\n                    {\n                        rgctxDefData = definitionData.data;\n                    }\n                    switch (definitionData.type)\n                    {\n                        case Il2CppRGCTXDataType.IL2CPP_RGCTX_DATA_TYPE:\n                            {\n                                var il2CppType = il2Cpp.types[rgctxDefData.typeIndex];\n                                structRGCTXInfo.TypeName = FixName(executor.GetTypeName(il2CppType, true, false));\n                                break;\n                            }\n                        case Il2CppRGCTXDataType.IL2CPP_RGCTX_DATA_CLASS:\n                            {\n                                var il2CppType = il2Cpp.types[rgctxDefData.typeIndex];\n                                structRGCTXInfo.ClassName = FixName(executor.GetTypeName(il2CppType, true, false));\n                                break;\n                            }\n                        case Il2CppRGCTXDataType.IL2CPP_RGCTX_DATA_METHOD:\n                            {\n                                var methodSpec = il2Cpp.methodSpecs[rgctxDefData.methodIndex];\n                                (var methodSpecTypeName, var methodSpecMethodName) = executor.GetMethodSpecName(methodSpec, true);\n                                structRGCTXInfo.MethodName = FixName(methodSpecTypeName + \".\" + methodSpecMethodName);\n                                break;\n                            }\n                    }\n                }\n            }\n            return rgctxs;\n        }\n\n        private void ParseArrayClassStruct(Il2CppType il2CppType, Il2CppGenericContext context)\n        {\n            var structName = GetIl2CppStructName(il2CppType, context);\n            arrayClassHeader.Append($\"struct {structName}_array {{\\n\" +\n                $\"\\tIl2CppObject obj;\\n\" +\n                $\"\\tIl2CppArrayBounds *bounds;\\n\" +\n                $\"\\til2cpp_array_size_t max_length;\\n\" +\n                $\"\\t{ParseType(il2CppType, context)} m_Items[65535];\\n\" +\n                $\"}};\\n\");\n        }\n\n        private Il2CppTypeDefinition GetTypeDefinition(Il2CppType il2CppType)\n        {\n            switch (il2CppType.type)\n            {\n                case Il2CppTypeEnum.IL2CPP_TYPE_VOID:\n                case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN:\n                case Il2CppTypeEnum.IL2CPP_TYPE_CHAR:\n                case Il2CppTypeEnum.IL2CPP_TYPE_I1:\n                case Il2CppTypeEnum.IL2CPP_TYPE_U1:\n                case Il2CppTypeEnum.IL2CPP_TYPE_I2:\n                case Il2CppTypeEnum.IL2CPP_TYPE_U2:\n                case Il2CppTypeEnum.IL2CPP_TYPE_I4:\n                case Il2CppTypeEnum.IL2CPP_TYPE_U4:\n                case Il2CppTypeEnum.IL2CPP_TYPE_I8:\n                case Il2CppTypeEnum.IL2CPP_TYPE_U8:\n                case Il2CppTypeEnum.IL2CPP_TYPE_R4:\n                case Il2CppTypeEnum.IL2CPP_TYPE_R8:\n                case Il2CppTypeEnum.IL2CPP_TYPE_STRING:\n                case Il2CppTypeEnum.IL2CPP_TYPE_TYPEDBYREF:\n                case Il2CppTypeEnum.IL2CPP_TYPE_I:\n                case Il2CppTypeEnum.IL2CPP_TYPE_U:\n                case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE:\n                case Il2CppTypeEnum.IL2CPP_TYPE_CLASS:\n                case Il2CppTypeEnum.IL2CPP_TYPE_OBJECT:\n                    return executor.GetTypeDefinitionFromIl2CppType(il2CppType);\n                case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST:\n                    var genericClass = il2Cpp.MapVATR<Il2CppGenericClass>(il2CppType.data.generic_class);\n                    return executor.GetGenericClassTypeDefinition(genericClass);\n                default:\n                    throw new NotSupportedException();\n            }\n        }\n\n        private void CreateStructNameDic(Il2CppTypeDefinition typeDef)\n        {\n            var typeName = executor.GetTypeDefName(typeDef, true, true);\n            var typeStructName = FixName(typeName);\n            var uniqueName = GetUniqueName(typeStructName);\n            structNameDic.Add(typeDef, uniqueName);\n        }\n\n        private string GetUniqueName(string name)\n        {\n            var fixName = name;\n            int i = 1;\n            while (!structNameHashSet.Add(fixName))\n            {\n                fixName = $\"{name}_{i++}\";\n            }\n            return fixName;\n        }\n\n        private string RecursionStructInfo(StructInfo info)\n        {\n            if (!structCache.Add(info))\n            {\n                return string.Empty;\n            }\n\n            var sb = new StringBuilder();\n            var pre = new StringBuilder();\n\n            if (info.Parent != null)\n            {\n                var parentStructName = info.Parent + \"_o\";\n                pre.Append(RecursionStructInfo(structInfoWithStructName[parentStructName]));\n                sb.Append($\"struct {info.TypeName}_Fields : {info.Parent}_Fields {{\\n\");\n                // C style\n                //sb.Append($\"struct {info.TypeName}_Fields {{\\n\");\n                //sb.Append($\"\\t{info.Parent}_Fields _;\\n\");\n            }\n            else\n            {\n                if (il2Cpp is PE && !info.IsValueType)\n                {\n                    if (il2Cpp.Is32Bit)\n                    {\n                        sb.Append($\"struct __declspec(align(4)) {info.TypeName}_Fields {{\\n\");\n                    }\n                    else\n                    {\n                        sb.Append($\"struct __declspec(align(8)) {info.TypeName}_Fields {{\\n\");\n                    }\n                }\n                else\n                {\n                    sb.Append($\"struct {info.TypeName}_Fields {{\\n\");\n                }\n            }\n            foreach (var field in info.Fields)\n            {\n                if (field.IsValueType)\n                {\n                    var fieldInfo = structInfoWithStructName[field.FieldTypeName];\n                    pre.Append(RecursionStructInfo(fieldInfo));\n                }\n                if (field.IsCustomType)\n                {\n                    sb.Append($\"\\tstruct {field.FieldTypeName} {field.FieldName};\\n\");\n                }\n                else\n                {\n                    sb.Append($\"\\t{field.FieldTypeName} {field.FieldName};\\n\");\n                }\n            }\n            sb.Append(\"};\\n\");\n\n            if (info.RGCTXs.Count > 0)\n            {\n                sb.Append($\"struct {info.TypeName}_RGCTXs {{\\n\");\n                for (int i = 0; i < info.RGCTXs.Count; i++)\n                {\n                    var rgctx = info.RGCTXs[i];\n                    switch (rgctx.Type)\n                    {\n                        case Il2CppRGCTXDataType.IL2CPP_RGCTX_DATA_TYPE:\n                            sb.Append($\"\\tIl2CppType* _{i}_{rgctx.TypeName};\\n\");\n                            break;\n                        case Il2CppRGCTXDataType.IL2CPP_RGCTX_DATA_CLASS:\n                            sb.Append($\"\\tIl2CppClass* _{i}_{rgctx.ClassName};\\n\");\n                            break;\n                        case Il2CppRGCTXDataType.IL2CPP_RGCTX_DATA_METHOD:\n                            sb.Append($\"\\tMethodInfo* _{i}_{rgctx.MethodName};\\n\");\n                            break;\n                    }\n                }\n                sb.Append(\"};\\n\");\n            }\n\n            if (info.VTableMethod.Length > 0)\n            {\n                sb.Append($\"struct {info.TypeName}_VTable {{\\n\");\n                for (int i = 0; i < info.VTableMethod.Length; i++)\n                {\n                    sb.Append($\"\\tVirtualInvokeData _{i}_\");\n                    var method = info.VTableMethod[i];\n                    if (method != null)\n                    {\n                        sb.Append(method.MethodName);\n                    }\n                    else\n                    {\n                        sb.Append(\"unknown\");\n                    }\n                    sb.Append(\";\\n\");\n                }\n                sb.Append(\"};\\n\");\n            }\n\n            sb.Append($\"struct {info.TypeName}_c {{\\n\");\n            sb.Append($\"\\tIl2CppClass_1 _1;\\n\");\n            if (info.StaticFields.Count > 0)\n            {\n                sb.Append($\"\\tstruct {info.TypeName}_StaticFields* static_fields;\\n\");\n            }\n            else\n            {\n                sb.Append(\"\\tvoid* static_fields;\\n\");\n            }\n            if (info.RGCTXs.Count > 0)\n            {\n                sb.Append($\"\\t{info.TypeName}_RGCTXs* rgctx_data;\\n\");\n            }\n            else\n            {\n                sb.Append(\"\\tIl2CppRGCTXData* rgctx_data;\\n\");\n            }\n            sb.Append($\"\\tIl2CppClass_2 _2;\\n\");\n            if (info.VTableMethod.Length > 0)\n            {\n                sb.Append($\"\\t{info.TypeName}_VTable vtable;\\n\");\n            }\n            else\n            {\n                sb.Append(\"\\tVirtualInvokeData vtable[32];\\n\");\n            }\n            sb.Append($\"}};\\n\");\n\n            sb.Append($\"struct {info.TypeName}_o {{\\n\");\n            if (!info.IsValueType)\n            {\n                sb.Append($\"\\t{info.TypeName}_c *klass;\\n\");\n                sb.Append($\"\\tvoid *monitor;\\n\");\n            }\n            sb.Append($\"\\t{info.TypeName}_Fields fields;\\n\");\n            sb.Append(\"};\\n\");\n\n            if (info.StaticFields.Count > 0)\n            {\n                sb.Append($\"struct {info.TypeName}_StaticFields {{\\n\");\n                foreach (var field in info.StaticFields)\n                {\n                    if (field.IsValueType)\n                    {\n                        var fieldInfo = structInfoWithStructName[field.FieldTypeName];\n                        pre.Append(RecursionStructInfo(fieldInfo));\n                    }\n                    if (field.IsCustomType)\n                    {\n                        sb.Append($\"\\tstruct {field.FieldTypeName} {field.FieldName};\\n\");\n                    }\n                    else\n                    {\n                        sb.Append($\"\\t{field.FieldTypeName} {field.FieldName};\\n\");\n                    }\n                }\n                sb.Append(\"};\\n\");\n            }\n\n            return pre.Append(sb).ToString();\n        }\n\n        private string GetIl2CppStructName(Il2CppType il2CppType, Il2CppGenericContext context = null)\n        {\n            switch (il2CppType.type)\n            {\n                case Il2CppTypeEnum.IL2CPP_TYPE_VOID:\n                case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN:\n                case Il2CppTypeEnum.IL2CPP_TYPE_CHAR:\n                case Il2CppTypeEnum.IL2CPP_TYPE_I1:\n                case Il2CppTypeEnum.IL2CPP_TYPE_U1:\n                case Il2CppTypeEnum.IL2CPP_TYPE_I2:\n                case Il2CppTypeEnum.IL2CPP_TYPE_U2:\n                case Il2CppTypeEnum.IL2CPP_TYPE_I4:\n                case Il2CppTypeEnum.IL2CPP_TYPE_U4:\n                case Il2CppTypeEnum.IL2CPP_TYPE_I8:\n                case Il2CppTypeEnum.IL2CPP_TYPE_U8:\n                case Il2CppTypeEnum.IL2CPP_TYPE_R4:\n                case Il2CppTypeEnum.IL2CPP_TYPE_R8:\n                case Il2CppTypeEnum.IL2CPP_TYPE_STRING:\n                case Il2CppTypeEnum.IL2CPP_TYPE_TYPEDBYREF:\n                case Il2CppTypeEnum.IL2CPP_TYPE_I:\n                case Il2CppTypeEnum.IL2CPP_TYPE_U:\n                case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE:\n                case Il2CppTypeEnum.IL2CPP_TYPE_CLASS:\n                case Il2CppTypeEnum.IL2CPP_TYPE_OBJECT:\n                    {\n                        var typeDef = executor.GetTypeDefinitionFromIl2CppType(il2CppType);\n                        return structNameDic[typeDef];\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_PTR:\n                    {\n                        var oriType = il2Cpp.GetIl2CppType(il2CppType.data.type);\n                        return GetIl2CppStructName(oriType);\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY:\n                    {\n                        var arrayType = il2Cpp.MapVATR<Il2CppArrayType>(il2CppType.data.array);\n                        var elementType = il2Cpp.GetIl2CppType(arrayType.etype);\n                        var elementStructName = GetIl2CppStructName(elementType, context);\n                        var typeStructName = elementStructName + \"_array\";\n                        if (structNameHashSet.Add(typeStructName))\n                        {\n                            ParseArrayClassStruct(elementType, context);\n                        }\n                        return typeStructName;\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY:\n                    {\n                        var elementType = il2Cpp.GetIl2CppType(il2CppType.data.type);\n                        var elementStructName = GetIl2CppStructName(elementType, context);\n                        var typeStructName = elementStructName + \"_array\";\n                        if (structNameHashSet.Add(typeStructName))\n                        {\n                            ParseArrayClassStruct(elementType, context);\n                        }\n                        return typeStructName;\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST:\n                    {\n                        var typeStructName = genericClassStructNameDic[il2CppType.data.generic_class];\n                        if (structNameHashSet.Add(typeStructName))\n                        {\n                            genericClassList.Add(il2CppType.data.generic_class);\n                        }\n                        return typeStructName;\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_VAR:\n                    {\n                        if (context != null)\n                        {\n                            var genericParameter = executor.GetGenericParameteFromIl2CppType(il2CppType);\n                            var genericInst = il2Cpp.MapVATR<Il2CppGenericInst>(context.class_inst);\n                            var pointers = il2Cpp.MapVATR<ulong>(genericInst.type_argv, genericInst.type_argc);\n                            var pointer = pointers[genericParameter.num];\n                            var type = il2Cpp.GetIl2CppType(pointer);\n                            return GetIl2CppStructName(type);\n                        }\n                        return \"System_Object\";\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_MVAR:\n                    {\n                        if (context != null)\n                        {\n                            var genericParameter = executor.GetGenericParameteFromIl2CppType(il2CppType);\n                            var genericInst = il2Cpp.MapVATR<Il2CppGenericInst>(context.method_inst);\n                            var pointers = il2Cpp.MapVATR<ulong>(genericInst.type_argv, genericInst.type_argc);\n                            var pointer = pointers[genericParameter.num];\n                            var type = il2Cpp.GetIl2CppType(pointer);\n                            return GetIl2CppStructName(type);\n                        }\n                        return \"System_Object\";\n                    }\n                default:\n                    throw new NotSupportedException();\n            }\n        }\n\n        private bool IsValueType(Il2CppType il2CppType, Il2CppGenericContext context)\n        {\n            switch (il2CppType.type)\n            {\n                case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE:\n                    {\n                        var typeDef = executor.GetTypeDefinitionFromIl2CppType(il2CppType);\n                        return !typeDef.IsEnum;\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST:\n                    {\n                        var genericClass = il2Cpp.MapVATR<Il2CppGenericClass>(il2CppType.data.generic_class);\n                        var typeDef = executor.GetGenericClassTypeDefinition(genericClass);\n                        return typeDef.IsValueType && !typeDef.IsEnum;\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_VAR:\n                    {\n                        if (context != null)\n                        {\n                            var genericParameter = executor.GetGenericParameteFromIl2CppType(il2CppType);\n                            var genericInst = il2Cpp.MapVATR<Il2CppGenericInst>(context.class_inst);\n                            var pointers = il2Cpp.MapVATR<ulong>(genericInst.type_argv, genericInst.type_argc);\n                            var pointer = pointers[genericParameter.num];\n                            var type = il2Cpp.GetIl2CppType(pointer);\n                            return IsValueType(type, null);\n                        }\n                        return false;\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_MVAR:\n                    {\n                        if (context != null)\n                        {\n                            var genericParameter = executor.GetGenericParameteFromIl2CppType(il2CppType);\n                            var genericInst = il2Cpp.MapVATR<Il2CppGenericInst>(context.method_inst);\n                            var pointers = il2Cpp.MapVATR<ulong>(genericInst.type_argv, genericInst.type_argc);\n                            var pointer = pointers[genericParameter.num];\n                            var type = il2Cpp.GetIl2CppType(pointer);\n                            return IsValueType(type, null);\n                        }\n                        return false;\n                    }\n                default:\n                    return false;\n            }\n        }\n\n        private bool IsCustomType(Il2CppType il2CppType, Il2CppGenericContext context)\n        {\n            switch (il2CppType.type)\n            {\n                case Il2CppTypeEnum.IL2CPP_TYPE_PTR:\n                    {\n                        var oriType = il2Cpp.GetIl2CppType(il2CppType.data.type);\n                        return IsCustomType(oriType, context);\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_STRING:\n                case Il2CppTypeEnum.IL2CPP_TYPE_CLASS:\n                case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY:\n                case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY:\n                    {\n                        return true;\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE:\n                    {\n                        var typeDef = executor.GetTypeDefinitionFromIl2CppType(il2CppType);\n                        if (typeDef.IsEnum)\n                        {\n                            return IsCustomType(il2Cpp.types[typeDef.elementTypeIndex], context);\n                        }\n                        return true;\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST:\n                    {\n                        var genericClass = il2Cpp.MapVATR<Il2CppGenericClass>(il2CppType.data.generic_class);\n                        var typeDef = executor.GetGenericClassTypeDefinition(genericClass);\n                        if (typeDef.IsEnum)\n                        {\n                            return IsCustomType(il2Cpp.types[typeDef.elementTypeIndex], context);\n                        }\n                        return true;\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_VAR:\n                    {\n                        if (context != null)\n                        {\n                            var genericParameter = executor.GetGenericParameteFromIl2CppType(il2CppType);\n                            var genericInst = il2Cpp.MapVATR<Il2CppGenericInst>(context.class_inst);\n                            var pointers = il2Cpp.MapVATR<ulong>(genericInst.type_argv, genericInst.type_argc);\n                            var pointer = pointers[genericParameter.num];\n                            var type = il2Cpp.GetIl2CppType(pointer);\n                            return IsCustomType(type, null);\n                        }\n                        return false;\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_MVAR:\n                    {\n                        if (context != null)\n                        {\n                            var genericParameter = executor.GetGenericParameteFromIl2CppType(il2CppType);\n                            var genericInst = il2Cpp.MapVATR<Il2CppGenericInst>(context.method_inst);\n                            var pointers = il2Cpp.MapVATR<ulong>(genericInst.type_argv, genericInst.type_argc);\n                            var pointer = pointers[genericParameter.num];\n                            var type = il2Cpp.GetIl2CppType(pointer);\n                            return IsCustomType(type, null);\n                        }\n                        return false;\n                    }\n                default:\n                    return false;\n            }\n        }\n\n        private void GenerateMethodInfo(string methodInfoName, string structTypeName, List<StructRGCTXInfo> rgctxs)\n        {\n            if (rgctxs.Count > 0)\n            {\n                methodInfoHeader.Append($\"struct {methodInfoName}_RGCTXs {{\\n\");\n                for (int i = 0; i < rgctxs.Count; i++)\n                {\n                    var rgctx = rgctxs[i];\n                    switch (rgctx.Type)\n                    {\n                        case Il2CppRGCTXDataType.IL2CPP_RGCTX_DATA_TYPE:\n                            methodInfoHeader.Append($\"\\tIl2CppType* _{i}_{rgctx.TypeName};\\n\");\n                            break;\n                        case Il2CppRGCTXDataType.IL2CPP_RGCTX_DATA_CLASS:\n                            methodInfoHeader.Append($\"\\tIl2CppClass* _{i}_{rgctx.ClassName};\\n\");\n                            break;\n                        case Il2CppRGCTXDataType.IL2CPP_RGCTX_DATA_METHOD:\n                            methodInfoHeader.Append($\"\\tMethodInfo* _{i}_{rgctx.MethodName};\\n\");\n                            break;\n                    }\n                }\n                methodInfoHeader.Append(\"};\\n\");\n            }\n\n            methodInfoHeader.Append($\"struct {methodInfoName} {{\\n\");\n            methodInfoHeader.Append($\"\\tIl2CppMethodPointer methodPointer;\\n\");\n            if (il2Cpp.Version >= 29)\n            {\n                methodInfoHeader.Append($\"\\tIl2CppMethodPointer virtualMethodPointer;\\n\");\n                methodInfoHeader.Append($\"\\tInvokerMethod invoker_method;\\n\");\n            }\n            else\n            {\n                methodInfoHeader.Append($\"\\tvoid* invoker_method;\\n\"); //TODO\n            }\n            methodInfoHeader.Append($\"\\tconst char* name;\\n\");\n            if (il2Cpp.Version <= 24)\n            {\n                methodInfoHeader.Append($\"\\t{structTypeName}_c *declaring_type;\\n\");\n            }\n            else\n            {\n                methodInfoHeader.Append($\"\\t{structTypeName}_c *klass;\\n\");\n            }\n            methodInfoHeader.Append($\"\\tconst Il2CppType *return_type;\\n\");\n            if (il2Cpp.Version >= 29)\n            {\n                methodInfoHeader.Append($\"\\tconst Il2CppType** parameters;\\n\");\n            }\n            else\n            {\n                methodInfoHeader.Append($\"\\tconst void* parameters;\\n\"); //ParameterInfo*\n            }\n            if (rgctxs.Count > 0)\n            {\n                methodInfoHeader.Append($\"\\tconst {methodInfoName}_RGCTXs* rgctx_data;\\n\");\n            }\n            else\n            {\n                methodInfoHeader.Append($\"\\tconst Il2CppRGCTXData* rgctx_data;\\n\");\n            }\n            methodInfoHeader.Append($\"\\tunion\\n\");\n            methodInfoHeader.Append($\"\\t{{\\n\");\n            methodInfoHeader.Append($\"\\t\\tconst void* genericMethod;\\n\");\n            if (il2Cpp.Version >= 27)\n            {\n                methodInfoHeader.Append($\"\\t\\tconst void* genericContainerHandle;\\n\");\n            }\n            else\n            {\n                methodInfoHeader.Append($\"\\t\\tconst void* genericContainer;\\n\");\n            }\n            methodInfoHeader.Append($\"\\t}};\\n\");\n            if (il2Cpp.Version <= 24)\n            {\n                methodInfoHeader.Append($\"\\tint32_t customAttributeIndex;\\n\");\n            }\n            methodInfoHeader.Append($\"\\tuint32_t token;\\n\");\n            methodInfoHeader.Append($\"\\tuint16_t flags;\\n\");\n            methodInfoHeader.Append($\"\\tuint16_t iflags;\\n\");\n            methodInfoHeader.Append($\"\\tuint16_t slot;\\n\");\n            methodInfoHeader.Append($\"\\tuint8_t parameters_count;\\n\");\n            methodInfoHeader.Append($\"\\tuint8_t bitflags;\\n\");\n            methodInfoHeader.Append($\"}};\\n\");\n        }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Outputs/StructInfo.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace Il2CppDumper\n{\n    public class StructInfo\n    {\n        public string TypeName;\n        public bool IsValueType;\n        public string Parent;\n        public List<StructFieldInfo> Fields = new();\n        public List<StructFieldInfo> StaticFields = new();\n        public StructVTableMethodInfo[] VTableMethod = Array.Empty<StructVTableMethodInfo>();\n        public List<StructRGCTXInfo> RGCTXs = new();\n    }\n\n    public class StructFieldInfo\n    {\n        public string FieldTypeName;\n        public string FieldName;\n        public bool IsValueType;\n        public bool IsCustomType;\n    }\n\n    public class StructVTableMethodInfo\n    {\n        public string MethodName;\n    }\n\n    public class StructRGCTXInfo\n    {\n        public Il2CppRGCTXDataType Type;\n        public string TypeName;\n        public string ClassName;\n        public string MethodName;\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Program.cs",
    "content": "﻿using System;\nusing System.IO;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing System.Text.Json;\n\nnamespace Il2CppDumper\n{\n    class Program\n    {\n        private static Config config;\n\n        [STAThread]\n        static void Main(string[] args)\n        {\n            config = JsonSerializer.Deserialize<Config>(File.ReadAllText(AppDomain.CurrentDomain.BaseDirectory + @\"config.json\"));\n            string il2cppPath = null;\n            string metadataPath = null;\n            string outputDir = null;\n\n            if (args.Length == 1)\n            {\n                if (args[0] == \"-h\" || args[0] == \"--help\" || args[0] == \"/?\" || args[0] == \"/h\")\n                {\n                    ShowHelp();\n                    return;\n                }\n            }\n            if (args.Length > 3)\n            {\n                ShowHelp();\n                return;\n            }\n            if (args.Length > 1)\n            {\n                foreach (var arg in args)\n                {\n                    if (File.Exists(arg))\n                    {\n                        var file = File.ReadAllBytes(arg);\n                        if (BitConverter.ToUInt32(file, 0) == 0xFAB11BAF)\n                        {\n                            metadataPath = arg;\n                        }\n                        else\n                        {\n                            il2cppPath = arg;\n                        }\n                    }\n                    else if (Directory.Exists(arg))\n                    {\n                        outputDir = Path.GetFullPath(arg) + Path.DirectorySeparatorChar;\n                    }\n                }\n            }\n            outputDir ??= AppDomain.CurrentDomain.BaseDirectory;\n            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))\n            {\n                if (il2cppPath == null)\n                {\n                    var ofd = new OpenFileDialog\n                    {\n                        Filter = \"Il2Cpp binary file|*.*\"\n                    };\n                    if (ofd.ShowDialog())\n                    {\n                        il2cppPath = ofd.FileName;\n                        ofd.Filter = \"global-metadata|global-metadata.dat\";\n                        if (ofd.ShowDialog())\n                        {\n                            metadataPath = ofd.FileName;\n                        }\n                        else\n                        {\n                            return;\n                        }\n                    }\n                    else\n                    {\n                        return;\n                    }\n                }\n            }\n            if (il2cppPath == null)\n            {\n                ShowHelp();\n                return;\n            }\n            if (metadataPath == null)\n            {\n                Console.WriteLine($\"ERROR: Metadata file not found or encrypted.\");\n            }\n            else\n            {\n                try\n                {\n                    if (Init(il2cppPath, metadataPath, out var metadata, out var il2Cpp))\n                    {\n                        Dump(metadata, il2Cpp, outputDir);\n                    }\n                }\n                catch (Exception e)\n                {\n                    Console.WriteLine(e);\n                }\n            }\n            if (config.RequireAnyKey)\n            {\n                Console.WriteLine(\"Press any key to exit...\");\n                Console.ReadKey(true);\n            }\n        }\n\n        static void ShowHelp()\n        {\n            Console.WriteLine($\"usage: {AppDomain.CurrentDomain.FriendlyName} <executable-file> <global-metadata> <output-directory>\");\n        }\n\n        private static bool Init(string il2cppPath, string metadataPath, out Metadata metadata, out Il2Cpp il2Cpp)\n        {\n            Console.WriteLine(\"Initializing metadata...\");\n            var metadataBytes = File.ReadAllBytes(metadataPath);\n            metadata = new Metadata(new MemoryStream(metadataBytes));\n            Console.WriteLine($\"Metadata Version: {metadata.Version}\");\n\n            Console.WriteLine(\"Initializing il2cpp file...\");\n            var il2cppBytes = File.ReadAllBytes(il2cppPath);\n            var il2cppMagic = BitConverter.ToUInt32(il2cppBytes, 0);\n            var il2CppMemory = new MemoryStream(il2cppBytes);\n            switch (il2cppMagic)\n            {\n                default:\n                    throw new NotSupportedException(\"ERROR: il2cpp file not supported.\");\n                case 0x6D736100:\n                    var web = new WebAssembly(il2CppMemory);\n                    il2Cpp = web.CreateMemory();\n                    break;\n                case 0x304F534E:\n                    var nso = new NSO(il2CppMemory);\n                    il2Cpp = nso.UnCompress();\n                    break;\n                case 0x905A4D: //PE\n                    il2Cpp = new PE(il2CppMemory);\n                    break;\n                case 0x464c457f: //ELF\n                    if (il2cppBytes[4] == 2) //ELF64\n                    {\n                        il2Cpp = new Elf64(il2CppMemory);\n                    }\n                    else\n                    {\n                        il2Cpp = new Elf(il2CppMemory);\n                    }\n                    break;\n                case 0xCAFEBABE: //FAT Mach-O\n                case 0xBEBAFECA:\n                    var machofat = new MachoFat(new MemoryStream(il2cppBytes));\n                    Console.Write(\"Select Platform: \");\n                    for (var i = 0; i < machofat.fats.Length; i++)\n                    {\n                        var fat = machofat.fats[i];\n                        Console.Write(fat.magic == 0xFEEDFACF ? $\"{i + 1}.64bit \" : $\"{i + 1}.32bit \");\n                    }\n                    Console.WriteLine();\n                    var key = Console.ReadKey(true);\n                    var index = int.Parse(key.KeyChar.ToString()) - 1;\n                    var magic = machofat.fats[index % 2].magic;\n                    il2cppBytes = machofat.GetMacho(index % 2);\n                    il2CppMemory = new MemoryStream(il2cppBytes);\n                    if (magic == 0xFEEDFACF)\n                        goto case 0xFEEDFACF;\n                    else\n                        goto case 0xFEEDFACE;\n                case 0xFEEDFACF: // 64bit Mach-O\n                    il2Cpp = new Macho64(il2CppMemory);\n                    break;\n                case 0xFEEDFACE: // 32bit Mach-O\n                    il2Cpp = new Macho(il2CppMemory);\n                    break;\n            }\n            var version = config.ForceIl2CppVersion ? config.ForceVersion : metadata.Version;\n            il2Cpp.SetProperties(version, metadata.metadataUsagesCount);\n            Console.WriteLine($\"Il2Cpp Version: {il2Cpp.Version}\");\n            if (config.ForceDump || il2Cpp.CheckDump())\n            {\n                if (il2Cpp is ElfBase elf)\n                {\n                    Console.WriteLine(\"Detected this may be a dump file.\");\n                    Console.WriteLine(\"Input il2cpp dump address or input 0 to force continue:\");\n                    var DumpAddr = Convert.ToUInt64(Console.ReadLine(), 16);\n                    if (DumpAddr != 0)\n                    {\n                        il2Cpp.ImageBase = DumpAddr;\n                        il2Cpp.IsDumped = true;\n                        if (!config.NoRedirectedPointer)\n                        {\n                            elf.Reload();\n                        }\n                    }\n                }\n                else\n                {\n                    il2Cpp.IsDumped = true;\n                }\n            }\n\n            Console.WriteLine(\"Searching...\");\n            try\n            {\n                var flag = il2Cpp.PlusSearch(metadata.methodDefs.Count(x => x.methodIndex >= 0), metadata.typeDefs.Length, metadata.imageDefs.Length);\n                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))\n                {\n                    if (!flag && il2Cpp is PE)\n                    {\n                        Console.WriteLine(\"Use custom PE loader\");\n                        il2Cpp = PELoader.Load(il2cppPath);\n                        il2Cpp.SetProperties(version, metadata.metadataUsagesCount);\n                        flag = il2Cpp.PlusSearch(metadata.methodDefs.Count(x => x.methodIndex >= 0), metadata.typeDefs.Length, metadata.imageDefs.Length);\n                    }\n                }\n                if (!flag)\n                {\n                    flag = il2Cpp.Search();\n                }\n                if (!flag)\n                {\n                    flag = il2Cpp.SymbolSearch();\n                }\n                if (!flag)\n                {\n                    Console.WriteLine(\"ERROR: Can't use auto mode to process file, try manual mode.\");\n                    Console.Write(\"Input CodeRegistration: \");\n                    var codeRegistration = Convert.ToUInt64(Console.ReadLine(), 16);\n                    Console.Write(\"Input MetadataRegistration: \");\n                    var metadataRegistration = Convert.ToUInt64(Console.ReadLine(), 16);\n                    il2Cpp.Init(codeRegistration, metadataRegistration);\n                }\n                if (il2Cpp.Version >= 27 && il2Cpp.IsDumped)\n                {\n                    var typeDef = metadata.typeDefs[0];\n                    var il2CppType = il2Cpp.types[typeDef.byvalTypeIndex];\n                    metadata.ImageBase = il2CppType.data.typeHandle - metadata.header.typeDefinitionsOffset;\n                }\n            }\n            catch (Exception e)\n            {\n                Console.WriteLine(e);\n                Console.WriteLine(\"ERROR: An error occurred while processing.\");\n                return false;\n            }\n            return true;\n        }\n\n        private static void Dump(Metadata metadata, Il2Cpp il2Cpp, string outputDir)\n        {\n            Console.WriteLine(\"Dumping...\");\n            var executor = new Il2CppExecutor(metadata, il2Cpp);\n            var decompiler = new Il2CppDecompiler(executor);\n            decompiler.Decompile(config, outputDir);\n            Console.WriteLine(\"Done!\");\n            if (config.GenerateStruct)\n            {\n                Console.WriteLine(\"Generate struct...\");\n                var scriptGenerator = new StructGenerator(executor);\n                scriptGenerator.WriteScript(outputDir);\n                Console.WriteLine(\"Done!\");\n            }\n            if (config.GenerateDummyDll)\n            {\n                Console.WriteLine(\"Generate dummy dll...\");\n                DummyAssemblyExporter.Export(executor, outputDir, config.DummyDllAddToken);\n                Console.WriteLine(\"Done!\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Resource1.Designer.cs",
    "content": "﻿//------------------------------------------------------------------------------\n// <auto-generated>\n//     此代码由工具生成。\n//     运行时版本:4.0.30319.42000\n//\n//     对此文件的更改可能会导致不正确的行为，并且如果\n//     重新生成代码，这些更改将会丢失。\n// </auto-generated>\n//------------------------------------------------------------------------------\n\nnamespace Il2CppDumper {\n    using System;\n    \n    \n    /// <summary>\n    ///   一个强类型的资源类，用于查找本地化的字符串等。\n    /// </summary>\n    // 此类是由 StronglyTypedResourceBuilder\n    // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。\n    // 若要添加或移除成员，请编辑 .ResX 文件，然后重新运行 ResGen\n    // (以 /str 作为命令选项)，或重新生成 VS 项目。\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Resources.Tools.StronglyTypedResourceBuilder\", \"17.0.0.0\")]\n    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\n    internal class Resource1 {\n        \n        private static global::System.Resources.ResourceManager resourceMan;\n        \n        private static global::System.Globalization.CultureInfo resourceCulture;\n        \n        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute(\"Microsoft.Performance\", \"CA1811:AvoidUncalledPrivateCode\")]\n        internal Resource1() {\n        }\n        \n        /// <summary>\n        ///   返回此类使用的缓存的 ResourceManager 实例。\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Resources.ResourceManager ResourceManager {\n            get {\n                if (object.ReferenceEquals(resourceMan, null)) {\n                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager(\"Il2CppDumper.Resource1\", typeof(Resource1).Assembly);\n                    resourceMan = temp;\n                }\n                return resourceMan;\n            }\n        }\n        \n        /// <summary>\n        ///   重写当前线程的 CurrentUICulture 属性，对\n        ///   使用此强类型资源类的所有资源查找执行重写。\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Globalization.CultureInfo Culture {\n            get {\n                return resourceCulture;\n            }\n            set {\n                resourceCulture = value;\n            }\n        }\n        \n        /// <summary>\n        ///   查找 System.Byte[] 类型的本地化资源。\n        /// </summary>\n        internal static byte[] Il2CppDummyDll {\n            get {\n                object obj = ResourceManager.GetObject(\"Il2CppDummyDll\", resourceCulture);\n                return ((byte[])(obj));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Resource1.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <assembly alias=\"System.Windows.Forms\" name=\"System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\" />\n  <data name=\"Il2CppDummyDll\" type=\"System.Resources.ResXFileRef, System.Windows.Forms\">\n    <value>Libraries\\Il2CppDummyDll.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </data>\n</root>"
  },
  {
    "path": "Il2CppDumper/Utils/ArmUtils.cs",
    "content": "﻿using System;\n\nnamespace Il2CppDumper\n{\n    static class ArmUtils\n    {\n        public static uint DecodeMov(byte[] asm)\n        {\n            var low = (ushort)(asm[2] + ((asm[3] & 0x70) << 4) + ((asm[1] & 0x04) << 9) + ((asm[0] & 0x0f) << 12));\n            var high = (ushort)(asm[6] + ((asm[7] & 0x70) << 4) + ((asm[5] & 0x04) << 9) + ((asm[4] & 0x0f) << 12));\n            return (uint)((high << 16) + low);\n        }\n\n        public static ulong DecodeAdr(ulong pc, byte[] inst)\n        {\n            var bin = inst.HexToBin();\n            var uint64 = string.Concat(bin.AsSpan(8, 19), bin.AsSpan(1, 2));\n            uint64 = uint64.PadLeft(64, uint64[0]);\n            return pc + Convert.ToUInt64(uint64, 2);\n        }\n\n        public static ulong DecodeAdrp(ulong pc, byte[] inst)\n        {\n            pc &= 0xFFFFFFFFFFFFF000;\n            var bin = inst.HexToBin();\n            var uint64 = string.Concat(bin.AsSpan(8, 19), bin.AsSpan(1, 2), new string('0', 12));\n            uint64 = uint64.PadLeft(64, uint64[0]);\n            return pc + Convert.ToUInt64(uint64, 2);\n        }\n\n        public static ulong DecodeAdd(byte[] inst)\n        {\n            var bin = inst.HexToBin();\n            var uint64 = Convert.ToUInt64(bin.Substring(10, 12), 2);\n            if (bin[9] == '1')\n                uint64 <<= 12;\n            return uint64;\n        }\n\n        public static bool IsAdr(byte[] inst)\n        {\n            var bin = inst.HexToBin();\n            return bin[0] == '0' && bin.Substring(3, 5) == \"10000\";\n        }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Utils/AttributeArgument.cs",
    "content": "﻿namespace Il2CppDumper\n{\n    public class AttributeArgument\n    {\n        public BlobValue Value;\n        public int Index;\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Utils/BlobValue.cs",
    "content": "﻿namespace Il2CppDumper\n{\n    public class BlobValue\n    {\n        public object Value;\n        public Il2CppTypeEnum il2CppTypeEnum;\n        public Il2CppType EnumType;\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Utils/CustomAttributeDataReader.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.IO;\n\nnamespace Il2CppDumper\n{\n    public class CustomAttributeDataReader : BinaryReader\n    {\n        private readonly Il2CppExecutor executor;\n        private readonly Metadata metadata;\n        private long ctorBuffer;\n        private long dataBuffer;\n\n        public uint Count { get; set; }\n\n        public CustomAttributeDataReader(Il2CppExecutor executor, byte[] buff) : base(new MemoryStream(buff))\n        {\n            this.executor = executor;\n            metadata = executor.metadata;\n            Count = this.ReadCompressedUInt32();\n            ctorBuffer = BaseStream.Position;\n            dataBuffer = BaseStream.Position + Count * 4;\n        }\n\n        public string GetStringCustomAttributeData()\n        {\n            BaseStream.Position = ctorBuffer;\n            var ctorIndex = ReadInt32();\n            var methodDef = metadata.methodDefs[ctorIndex];\n            var typeDef = metadata.typeDefs[methodDef.declaringType];\n            ctorBuffer = BaseStream.Position;\n\n            BaseStream.Position = dataBuffer;\n            var argumentCount = this.ReadCompressedUInt32();\n            var fieldCount = this.ReadCompressedUInt32();\n            var propertyCount = this.ReadCompressedUInt32();\n\n            var argList = new List<string>();\n\n            for (var i = 0; i < argumentCount; i++)\n            {\n                argList.Add($\"{AttributeDataToString(ReadAttributeDataValue())}\");\n            }\n            for (var i = 0; i < fieldCount; i++)\n            {\n                var str = AttributeDataToString(ReadAttributeDataValue());\n                (var declaring, var fieldIndex) = ReadCustomAttributeNamedArgumentClassAndIndex(typeDef);\n                var fieldDef = metadata.fieldDefs[declaring.fieldStart + fieldIndex];\n                argList.Add($\"{metadata.GetStringFromIndex(fieldDef.nameIndex)} = {str}\");\n            }\n            for (var i = 0; i < propertyCount; i++)\n            {\n                var str = AttributeDataToString(ReadAttributeDataValue());\n                (var declaring, var propertyIndex) = ReadCustomAttributeNamedArgumentClassAndIndex(typeDef);\n                var propertyDef = metadata.propertyDefs[declaring.propertyStart + propertyIndex];\n                argList.Add($\"{metadata.GetStringFromIndex(propertyDef.nameIndex)} = {str}\");\n            }\n            dataBuffer = BaseStream.Position;\n\n\n            var typeName = metadata.GetStringFromIndex(typeDef.nameIndex).Replace(\"Attribute\", \"\");\n            if (argList.Count > 0)\n            {\n                return $\"[{typeName}({string.Join(\", \", argList)})]\";\n            }\n            else\n            {\n                return $\"[{typeName}]\";\n            }\n        }\n\n        private string AttributeDataToString(BlobValue blobValue)\n        {\n            //TODO enum\n            if (blobValue.Value == null)\n            {\n                return \"null\";\n            }\n            switch (blobValue.il2CppTypeEnum)\n            {\n                case Il2CppTypeEnum.IL2CPP_TYPE_STRING:\n                    return $\"\\\"{blobValue.Value}\\\"\";\n                case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY:\n                    var array = (BlobValue[])blobValue.Value;\n                    var list = new List<string>();\n                    foreach (var item in array)\n                    {\n                        list.Add(AttributeDataToString(item));\n                    }\n                    return $\"new[] {{ {string.Join(\", \", list)} }}\";\n                case Il2CppTypeEnum.IL2CPP_TYPE_IL2CPP_TYPE_INDEX:\n                    var il2CppType = (Il2CppType)blobValue.Value;\n                    return $\"typeof({executor.GetTypeName(il2CppType, false, false)})\";\n                default:\n                    return blobValue.Value.ToString();\n            }\n        }\n\n        public CustomAttributeReaderVisitor VisitCustomAttributeData()\n        {\n            var visitor = new CustomAttributeReaderVisitor();\n\n            BaseStream.Position = ctorBuffer;\n            var ctorIndex = ReadInt32();\n            visitor.CtorIndex = ctorIndex;\n            var methodDef = metadata.methodDefs[ctorIndex];\n            var typeDef = metadata.typeDefs[methodDef.declaringType];\n            ctorBuffer = BaseStream.Position;\n\n            BaseStream.Position = dataBuffer;\n            var argumentCount = this.ReadCompressedUInt32();\n            var fieldCount = this.ReadCompressedUInt32();\n            var propertyCount = this.ReadCompressedUInt32();\n\n            visitor.Arguments = new AttributeArgument[argumentCount];\n            for (var i = 0; i < argumentCount; i++)\n            {\n                var argument = visitor.Arguments[i] = new AttributeArgument();\n                argument.Value = ReadAttributeDataValue();\n                argument.Index = i;\n            }\n            visitor.Fields = new AttributeArgument[fieldCount];\n            for (var i = 0; i < fieldCount; i++)\n            {\n                var field = visitor.Fields[i] = new AttributeArgument();\n                field.Value = ReadAttributeDataValue();\n                (var declaring, var fieldIndex) = ReadCustomAttributeNamedArgumentClassAndIndex(typeDef);\n                field.Index = declaring.fieldStart + fieldIndex;\n            }\n            visitor.Properties = new AttributeArgument[propertyCount];\n            for (var i = 0; i < propertyCount; i++)\n            {\n                var property = visitor.Properties[i] = new AttributeArgument();\n                property.Value = ReadAttributeDataValue();\n                (var declaring, var propertyIndex) = ReadCustomAttributeNamedArgumentClassAndIndex(typeDef);\n                property.Index = declaring.propertyStart + propertyIndex;\n            }\n\n            dataBuffer = BaseStream.Position;\n            return visitor;\n        }\n\n        private BlobValue ReadAttributeDataValue()\n        {\n            var type = executor.ReadEncodedTypeEnum(this, out var enumType);\n            executor.GetConstantValueFromBlob(type, this, out var blobValue);\n            if (enumType != null)\n            {\n                blobValue.EnumType = enumType;\n            }\n            return blobValue;\n        }\n\n        private (Il2CppTypeDefinition, int) ReadCustomAttributeNamedArgumentClassAndIndex(Il2CppTypeDefinition typeDef)\n        {\n            var memberIndex = this.ReadCompressedInt32();\n            if (memberIndex >= 0)\n            {\n                return (typeDef, memberIndex);\n            }\n            memberIndex = -(memberIndex + 1);\n\n            var typeIndex = this.ReadCompressedUInt32();\n            var declaringClass = metadata.typeDefs[typeIndex];\n\n            return (declaringClass, memberIndex);\n        }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Utils/CustomAttributeReaderVisitor.cs",
    "content": "﻿namespace Il2CppDumper\n{\n    public class CustomAttributeReaderVisitor\n    {\n        public int CtorIndex;\n        public AttributeArgument[] Arguments;\n        public AttributeArgument[] Fields;\n        public AttributeArgument[] Properties;\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Utils/DummyAssemblyGenerator.cs",
    "content": "﻿using Mono.Cecil;\nusing Mono.Cecil.Cil;\nusing Mono.Collections.Generic;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\n\nnamespace Il2CppDumper\n{\n    public class DummyAssemblyGenerator\n    {\n        public List<AssemblyDefinition> Assemblies = new();\n\n        private readonly Il2CppExecutor executor;\n        private readonly Metadata metadata;\n        private readonly Il2Cpp il2Cpp;\n        private readonly Dictionary<Il2CppTypeDefinition, TypeDefinition> typeDefinitionDic = new();\n        private readonly Dictionary<Il2CppGenericParameter, GenericParameter> genericParameterDic = new();\n        private readonly MethodDefinition attributeAttribute;\n        private readonly TypeReference stringType;\n        private readonly TypeSystem typeSystem;\n        private readonly Dictionary<int, FieldDefinition> fieldDefinitionDic = new();\n        private readonly Dictionary<int, PropertyDefinition> propertyDefinitionDic = new();\n        private readonly Dictionary<int, MethodDefinition> methodDefinitionDic = new();\n\n        public DummyAssemblyGenerator(Il2CppExecutor il2CppExecutor, bool addToken)\n        {\n            executor = il2CppExecutor;\n            metadata = il2CppExecutor.metadata;\n            il2Cpp = il2CppExecutor.il2Cpp;\n\n            //Il2CppDummyDll\n            var il2CppDummyDll = AssemblyDefinition.ReadAssembly(new MemoryStream(Resource1.Il2CppDummyDll));\n            Assemblies.Add(il2CppDummyDll);\n            var dummyMD = il2CppDummyDll.MainModule;\n            var addressAttribute = dummyMD.Types.First(x => x.Name == \"AddressAttribute\").Methods[0];\n            var fieldOffsetAttribute = dummyMD.Types.First(x => x.Name == \"FieldOffsetAttribute\").Methods[0];\n            attributeAttribute = dummyMD.Types.First(x => x.Name == \"AttributeAttribute\").Methods[0];\n            var metadataOffsetAttribute = dummyMD.Types.First(x => x.Name == \"MetadataOffsetAttribute\").Methods[0];\n            var tokenAttribute = dummyMD.Types.First(x => x.Name == \"TokenAttribute\").Methods[0];\n            stringType = dummyMD.TypeSystem.String;\n            typeSystem = dummyMD.TypeSystem;\n\n            var resolver = new MyAssemblyResolver();\n            var moduleParameters = new ModuleParameters\n            {\n                Kind = ModuleKind.Dll,\n                AssemblyResolver = resolver\n            };\n            resolver.Register(il2CppDummyDll);\n\n            var parameterDefinitionDic = new Dictionary<int, ParameterDefinition>();\n            var eventDefinitionDic = new Dictionary<int, EventDefinition>();\n\n            //创建程序集，同时创建所有类\n            foreach (var imageDef in metadata.imageDefs)\n            {\n                var imageName = metadata.GetStringFromIndex(imageDef.nameIndex);\n                var aname = metadata.assemblyDefs[imageDef.assemblyIndex].aname;\n                var assemblyName = metadata.GetStringFromIndex(aname.nameIndex);\n                Version vers;\n                if (aname.build >= 0)\n                {\n                    vers = new Version(aname.major, aname.minor, aname.build, aname.revision);\n                }\n                else\n                {\n                    //__Generated\n                    vers = new Version(3, 7, 1, 6);\n                }\n                var assemblyNameDef = new AssemblyNameDefinition(assemblyName, vers);\n                /*assemblyNameDef.Culture = metadata.GetStringFromIndex(aname.cultureIndex);\n                assemblyNameDef.PublicKey = Encoding.UTF8.GetBytes(metadata.GetStringFromIndex(aname.publicKeyIndex));\n                assemblyNameDef.HashAlgorithm = (AssemblyHashAlgorithm)aname.hash_alg;\n                assemblyNameDef.Attributes = (AssemblyAttributes)aname.flags;\n                assemblyNameDef.PublicKeyToken = aname.public_key_token;*/\n                var assemblyDefinition = AssemblyDefinition.CreateAssembly(assemblyNameDef, imageName, moduleParameters);\n                resolver.Register(assemblyDefinition);\n                Assemblies.Add(assemblyDefinition);\n                var moduleDefinition = assemblyDefinition.MainModule;\n                moduleDefinition.Types.Clear();//清除自动创建的<Module>类\n                var typeEnd = imageDef.typeStart + imageDef.typeCount;\n                for (var index = imageDef.typeStart; index < typeEnd; ++index)\n                {\n                    var typeDef = metadata.typeDefs[index];\n                    var namespaceName = metadata.GetStringFromIndex(typeDef.namespaceIndex);\n                    var typeName = metadata.GetStringFromIndex(typeDef.nameIndex);\n                    var typeDefinition = new TypeDefinition(namespaceName, typeName, (TypeAttributes)typeDef.flags);\n                    typeDefinitionDic.Add(typeDef, typeDefinition);\n                    if (typeDef.declaringTypeIndex == -1)\n                    {\n                        moduleDefinition.Types.Add(typeDefinition);\n                    }\n                }\n            }\n            foreach (var imageDef in metadata.imageDefs)\n            {\n                var typeEnd = imageDef.typeStart + imageDef.typeCount;\n                for (var index = imageDef.typeStart; index < typeEnd; ++index)\n                {\n                    var typeDef = metadata.typeDefs[index];\n                    var typeDefinition = typeDefinitionDic[typeDef];\n\n                    //nestedtype\n                    for (int i = 0; i < typeDef.nested_type_count; i++)\n                    {\n                        var nestedIndex = metadata.nestedTypeIndices[typeDef.nestedTypesStart + i];\n                        var nestedTypeDef = metadata.typeDefs[nestedIndex];\n                        var nestedTypeDefinition = typeDefinitionDic[nestedTypeDef];\n                        typeDefinition.NestedTypes.Add(nestedTypeDefinition);\n                    }\n                }\n            }\n            //提前处理\n            foreach (var imageDef in metadata.imageDefs)\n            {\n                var typeEnd = imageDef.typeStart + imageDef.typeCount;\n                for (var index = imageDef.typeStart; index < typeEnd; ++index)\n                {\n                    var typeDef = metadata.typeDefs[index];\n                    var typeDefinition = typeDefinitionDic[typeDef];\n\n                    if (addToken)\n                    {\n                        var customTokenAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(tokenAttribute));\n                        customTokenAttribute.Fields.Add(new CustomAttributeNamedArgument(\"Token\", new CustomAttributeArgument(stringType, $\"0x{typeDef.token:X}\")));\n                        typeDefinition.CustomAttributes.Add(customTokenAttribute);\n                    }\n\n                    //genericParameter\n                    if (typeDef.genericContainerIndex >= 0)\n                    {\n                        var genericContainer = metadata.genericContainers[typeDef.genericContainerIndex];\n                        for (int i = 0; i < genericContainer.type_argc; i++)\n                        {\n                            var genericParameterIndex = genericContainer.genericParameterStart + i;\n                            var param = metadata.genericParameters[genericParameterIndex];\n                            var genericParameter = CreateGenericParameter(param, typeDefinition);\n                            typeDefinition.GenericParameters.Add(genericParameter);\n                        }\n                    }\n\n                    //parent\n                    if (typeDef.parentIndex >= 0)\n                    {\n                        var parentType = il2Cpp.types[typeDef.parentIndex];\n                        var parentTypeRef = GetTypeReference(typeDefinition, parentType);\n                        typeDefinition.BaseType = parentTypeRef;\n                    }\n\n                    //interfaces\n                    for (int i = 0; i < typeDef.interfaces_count; i++)\n                    {\n                        var interfaceType = il2Cpp.types[metadata.interfaceIndices[typeDef.interfacesStart + i]];\n                        var interfaceTypeRef = GetTypeReference(typeDefinition, interfaceType);\n                        typeDefinition.Interfaces.Add(new InterfaceImplementation(interfaceTypeRef));\n                    }\n                }\n            }\n            //处理field, method, property等等\n            foreach (var imageDef in metadata.imageDefs)\n            {\n                var imageName = metadata.GetStringFromIndex(imageDef.nameIndex);\n                var typeEnd = imageDef.typeStart + imageDef.typeCount;\n                for (int index = imageDef.typeStart; index < typeEnd; index++)\n                {\n                    var typeDef = metadata.typeDefs[index];\n                    var typeDefinition = typeDefinitionDic[typeDef];\n\n                    //field\n                    var fieldEnd = typeDef.fieldStart + typeDef.field_count;\n                    for (var i = typeDef.fieldStart; i < fieldEnd; ++i)\n                    {\n                        var fieldDef = metadata.fieldDefs[i];\n                        var fieldType = il2Cpp.types[fieldDef.typeIndex];\n                        var fieldName = metadata.GetStringFromIndex(fieldDef.nameIndex);\n                        var fieldTypeRef = GetTypeReference(typeDefinition, fieldType);\n                        var fieldDefinition = new FieldDefinition(fieldName, (FieldAttributes)fieldType.attrs, fieldTypeRef);\n                        typeDefinition.Fields.Add(fieldDefinition);\n                        fieldDefinitionDic.Add(i, fieldDefinition);\n\n                        if (addToken)\n                        {\n                            var customTokenAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(tokenAttribute));\n                            customTokenAttribute.Fields.Add(new CustomAttributeNamedArgument(\"Token\", new CustomAttributeArgument(stringType, $\"0x{fieldDef.token:X}\")));\n                            fieldDefinition.CustomAttributes.Add(customTokenAttribute);\n                        }\n\n                        //fieldDefault\n                        if (metadata.GetFieldDefaultValueFromIndex(i, out var fieldDefault) && fieldDefault.dataIndex != -1)\n                        {\n                            if (executor.TryGetDefaultValue(fieldDefault.typeIndex, fieldDefault.dataIndex, out var value))\n                            {\n                                fieldDefinition.Constant = value;\n                            }\n                            else\n                            {\n                                var customAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(metadataOffsetAttribute));\n                                var offset = new CustomAttributeNamedArgument(\"Offset\", new CustomAttributeArgument(stringType, $\"0x{value:X}\"));\n                                customAttribute.Fields.Add(offset);\n                                fieldDefinition.CustomAttributes.Add(customAttribute);\n                            }\n                        }\n                        //fieldOffset\n                        if (!fieldDefinition.IsLiteral)\n                        {\n                            var fieldOffset = il2Cpp.GetFieldOffsetFromIndex(index, i - typeDef.fieldStart, i, typeDefinition.IsValueType, fieldDefinition.IsStatic);\n                            if (fieldOffset >= 0)\n                            {\n                                var customAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(fieldOffsetAttribute));\n                                var offset = new CustomAttributeNamedArgument(\"Offset\", new CustomAttributeArgument(stringType, $\"0x{fieldOffset:X}\"));\n                                customAttribute.Fields.Add(offset);\n                                fieldDefinition.CustomAttributes.Add(customAttribute);\n                            }\n                        }\n                    }\n                    //method\n                    var methodEnd = typeDef.methodStart + typeDef.method_count;\n                    for (var i = typeDef.methodStart; i < methodEnd; ++i)\n                    {\n                        var methodDef = metadata.methodDefs[i];\n                        var methodName = metadata.GetStringFromIndex(methodDef.nameIndex);\n                        var methodDefinition = new MethodDefinition(methodName, (MethodAttributes)methodDef.flags, typeDefinition.Module.ImportReference(typeSystem.Void))\n                        {\n                            ImplAttributes = (MethodImplAttributes)methodDef.iflags\n                        };\n                        typeDefinition.Methods.Add(methodDefinition);\n                        //genericParameter\n                        if (methodDef.genericContainerIndex >= 0)\n                        {\n                            var genericContainer = metadata.genericContainers[methodDef.genericContainerIndex];\n                            for (int j = 0; j < genericContainer.type_argc; j++)\n                            {\n                                var genericParameterIndex = genericContainer.genericParameterStart + j;\n                                var param = metadata.genericParameters[genericParameterIndex];\n                                var genericParameter = CreateGenericParameter(param, methodDefinition);\n                                methodDefinition.GenericParameters.Add(genericParameter);\n                            }\n                        }\n                        var methodReturnType = il2Cpp.types[methodDef.returnType];\n                        var returnType = GetTypeReferenceWithByRef(methodDefinition, methodReturnType);\n                        methodDefinition.ReturnType = returnType;\n\n                        if (addToken)\n                        {\n                            var customTokenAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(tokenAttribute));\n                            customTokenAttribute.Fields.Add(new CustomAttributeNamedArgument(\"Token\", new CustomAttributeArgument(stringType, $\"0x{methodDef.token:X}\")));\n                            methodDefinition.CustomAttributes.Add(customTokenAttribute);\n                        }\n\n                        if (methodDefinition.HasBody && typeDefinition.BaseType?.FullName != \"System.MulticastDelegate\")\n                        {\n                            var ilprocessor = methodDefinition.Body.GetILProcessor();\n                            if (returnType.FullName == \"System.Void\")\n                            {\n                                ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));\n                            }\n                            else if (returnType.IsValueType)\n                            {\n                                var variable = new VariableDefinition(returnType);\n                                methodDefinition.Body.Variables.Add(variable);\n                                ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloca_S, variable));\n                                ilprocessor.Append(ilprocessor.Create(OpCodes.Initobj, returnType));\n                                ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloc_0));\n                                ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));\n                            }\n                            else\n                            {\n                                ilprocessor.Append(ilprocessor.Create(OpCodes.Ldnull));\n                                ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));\n                            }\n                        }\n                        methodDefinitionDic.Add(i, methodDefinition);\n                        //method parameter\n                        for (var j = 0; j < methodDef.parameterCount; ++j)\n                        {\n                            var parameterDef = metadata.parameterDefs[methodDef.parameterStart + j];\n                            var parameterName = metadata.GetStringFromIndex(parameterDef.nameIndex);\n                            var parameterType = il2Cpp.types[parameterDef.typeIndex];\n                            var parameterTypeRef = GetTypeReferenceWithByRef(methodDefinition, parameterType);\n                            var parameterDefinition = new ParameterDefinition(parameterName, (ParameterAttributes)parameterType.attrs, parameterTypeRef);\n                            methodDefinition.Parameters.Add(parameterDefinition);\n                            parameterDefinitionDic.Add(methodDef.parameterStart + j, parameterDefinition);\n                            //ParameterDefault\n                            if (metadata.GetParameterDefaultValueFromIndex(methodDef.parameterStart + j, out var parameterDefault) && parameterDefault.dataIndex != -1)\n                            {\n                                if (executor.TryGetDefaultValue(parameterDefault.typeIndex, parameterDefault.dataIndex, out var value))\n                                {\n                                    parameterDefinition.Constant = value;\n                                }\n                                else\n                                {\n                                    var customAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(metadataOffsetAttribute));\n                                    var offset = new CustomAttributeNamedArgument(\"Offset\", new CustomAttributeArgument(stringType, $\"0x{value:X}\"));\n                                    customAttribute.Fields.Add(offset);\n                                    parameterDefinition.CustomAttributes.Add(customAttribute);\n                                }\n                            }\n                        }\n                        //methodAddress\n                        if (!methodDefinition.IsAbstract)\n                        {\n                            var methodPointer = il2Cpp.GetMethodPointer(imageName, methodDef);\n                            if (methodPointer > 0)\n                            {\n                                var customAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(addressAttribute));\n                                var fixedMethodPointer = il2Cpp.GetRVA(methodPointer);\n                                var rva = new CustomAttributeNamedArgument(\"RVA\", new CustomAttributeArgument(stringType, $\"0x{fixedMethodPointer:X}\"));\n                                var offset = new CustomAttributeNamedArgument(\"Offset\", new CustomAttributeArgument(stringType, $\"0x{il2Cpp.MapVATR(methodPointer):X}\"));\n                                var va = new CustomAttributeNamedArgument(\"VA\", new CustomAttributeArgument(stringType, $\"0x{methodPointer:X}\"));\n                                customAttribute.Fields.Add(rva);\n                                customAttribute.Fields.Add(offset);\n                                customAttribute.Fields.Add(va);\n                                if (methodDef.slot != ushort.MaxValue)\n                                {\n                                    var slot = new CustomAttributeNamedArgument(\"Slot\", new CustomAttributeArgument(stringType, methodDef.slot.ToString()));\n                                    customAttribute.Fields.Add(slot);\n                                }\n                                methodDefinition.CustomAttributes.Add(customAttribute);\n                            }\n                        }\n                    }\n                    //property\n                    var propertyEnd = typeDef.propertyStart + typeDef.property_count;\n                    for (var i = typeDef.propertyStart; i < propertyEnd; ++i)\n                    {\n                        var propertyDef = metadata.propertyDefs[i];\n                        var propertyName = metadata.GetStringFromIndex(propertyDef.nameIndex);\n                        TypeReference propertyType = null;\n                        MethodDefinition GetMethod = null;\n                        MethodDefinition SetMethod = null;\n                        if (propertyDef.get >= 0)\n                        {\n                            GetMethod = methodDefinitionDic[typeDef.methodStart + propertyDef.get];\n                            propertyType = GetMethod.ReturnType;\n                        }\n                        if (propertyDef.set >= 0)\n                        {\n                            SetMethod = methodDefinitionDic[typeDef.methodStart + propertyDef.set];\n                            propertyType ??= SetMethod.Parameters[0].ParameterType;\n                        }\n                        var propertyDefinition = new PropertyDefinition(propertyName, (PropertyAttributes)propertyDef.attrs, propertyType)\n                        {\n                            GetMethod = GetMethod,\n                            SetMethod = SetMethod\n                        };\n                        typeDefinition.Properties.Add(propertyDefinition);\n                        propertyDefinitionDic.Add(i, propertyDefinition);\n\n                        if (addToken)\n                        {\n                            var customTokenAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(tokenAttribute));\n                            customTokenAttribute.Fields.Add(new CustomAttributeNamedArgument(\"Token\", new CustomAttributeArgument(stringType, $\"0x{propertyDef.token:X}\")));\n                            propertyDefinition.CustomAttributes.Add(customTokenAttribute);\n                        }\n                    }\n                    //event\n                    var eventEnd = typeDef.eventStart + typeDef.event_count;\n                    for (var i = typeDef.eventStart; i < eventEnd; ++i)\n                    {\n                        var eventDef = metadata.eventDefs[i];\n                        var eventName = metadata.GetStringFromIndex(eventDef.nameIndex);\n                        var eventType = il2Cpp.types[eventDef.typeIndex];\n                        var eventTypeRef = GetTypeReference(typeDefinition, eventType);\n                        var eventDefinition = new EventDefinition(eventName, (EventAttributes)eventType.attrs, eventTypeRef);\n                        if (eventDef.add >= 0)\n                            eventDefinition.AddMethod = methodDefinitionDic[typeDef.methodStart + eventDef.add];\n                        if (eventDef.remove >= 0)\n                            eventDefinition.RemoveMethod = methodDefinitionDic[typeDef.methodStart + eventDef.remove];\n                        if (eventDef.raise >= 0)\n                            eventDefinition.InvokeMethod = methodDefinitionDic[typeDef.methodStart + eventDef.raise];\n                        typeDefinition.Events.Add(eventDefinition);\n                        eventDefinitionDic.Add(i, eventDefinition);\n\n                        if (addToken)\n                        {\n                            var customTokenAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(tokenAttribute));\n                            customTokenAttribute.Fields.Add(new CustomAttributeNamedArgument(\"Token\", new CustomAttributeArgument(stringType, $\"0x{eventDef.token:X}\")));\n                            eventDefinition.CustomAttributes.Add(customTokenAttribute);\n                        }\n                    }\n                }\n            }\n            //第三遍，添加CustomAttribute\n            if (il2Cpp.Version > 20)\n            {\n                foreach (var imageDef in metadata.imageDefs)\n                {\n                    var typeEnd = imageDef.typeStart + imageDef.typeCount;\n                    for (int index = imageDef.typeStart; index < typeEnd; index++)\n                    {\n                        var typeDef = metadata.typeDefs[index];\n                        var typeDefinition = typeDefinitionDic[typeDef];\n                        //typeAttribute\n                        CreateCustomAttribute(imageDef, typeDef.customAttributeIndex, typeDef.token, typeDefinition.Module, typeDefinition.CustomAttributes);\n\n                        //field\n                        var fieldEnd = typeDef.fieldStart + typeDef.field_count;\n                        for (var i = typeDef.fieldStart; i < fieldEnd; ++i)\n                        {\n                            var fieldDef = metadata.fieldDefs[i];\n                            var fieldDefinition = fieldDefinitionDic[i];\n                            //fieldAttribute\n                            CreateCustomAttribute(imageDef, fieldDef.customAttributeIndex, fieldDef.token, typeDefinition.Module, fieldDefinition.CustomAttributes);\n                        }\n\n                        //method\n                        var methodEnd = typeDef.methodStart + typeDef.method_count;\n                        for (var i = typeDef.methodStart; i < methodEnd; ++i)\n                        {\n                            var methodDef = metadata.methodDefs[i];\n                            var methodDefinition = methodDefinitionDic[i];\n                            //methodAttribute\n                            CreateCustomAttribute(imageDef, methodDef.customAttributeIndex, methodDef.token, typeDefinition.Module, methodDefinition.CustomAttributes);\n\n                            //method parameter\n                            for (var j = 0; j < methodDef.parameterCount; ++j)\n                            {\n                                var parameterDef = metadata.parameterDefs[methodDef.parameterStart + j];\n                                var parameterDefinition = parameterDefinitionDic[methodDef.parameterStart + j];\n                                //parameterAttribute\n                                CreateCustomAttribute(imageDef, parameterDef.customAttributeIndex, parameterDef.token, typeDefinition.Module, parameterDefinition.CustomAttributes);\n                            }\n                        }\n\n                        //property\n                        var propertyEnd = typeDef.propertyStart + typeDef.property_count;\n                        for (var i = typeDef.propertyStart; i < propertyEnd; ++i)\n                        {\n                            var propertyDef = metadata.propertyDefs[i];\n                            var propertyDefinition = propertyDefinitionDic[i];\n                            //propertyAttribute\n                            CreateCustomAttribute(imageDef, propertyDef.customAttributeIndex, propertyDef.token, typeDefinition.Module, propertyDefinition.CustomAttributes);\n                        }\n\n                        //event\n                        var eventEnd = typeDef.eventStart + typeDef.event_count;\n                        for (var i = typeDef.eventStart; i < eventEnd; ++i)\n                        {\n                            var eventDef = metadata.eventDefs[i];\n                            var eventDefinition = eventDefinitionDic[i];\n                            //eventAttribute\n                            CreateCustomAttribute(imageDef, eventDef.customAttributeIndex, eventDef.token, typeDefinition.Module, eventDefinition.CustomAttributes);\n                        }\n                    }\n                }\n            }\n        }\n\n        private TypeReference GetTypeReferenceWithByRef(MemberReference memberReference, Il2CppType il2CppType)\n        {\n            var typeReference = GetTypeReference(memberReference, il2CppType);\n            if (il2CppType.byref == 1)\n            {\n                return new ByReferenceType(typeReference);\n            }\n            else\n            {\n                return typeReference;\n            }\n        }\n\n        private TypeReference GetTypeReference(MemberReference memberReference, Il2CppType il2CppType)\n        {\n            var moduleDefinition = memberReference.Module;\n            switch (il2CppType.type)\n            {\n                case Il2CppTypeEnum.IL2CPP_TYPE_OBJECT:\n                    return moduleDefinition.ImportReference(typeSystem.Object);\n                case Il2CppTypeEnum.IL2CPP_TYPE_VOID:\n                    return moduleDefinition.ImportReference(typeSystem.Void);\n                case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN:\n                    return moduleDefinition.ImportReference(typeSystem.Boolean);\n                case Il2CppTypeEnum.IL2CPP_TYPE_CHAR:\n                    return moduleDefinition.ImportReference(typeSystem.Char);\n                case Il2CppTypeEnum.IL2CPP_TYPE_I1:\n                    return moduleDefinition.ImportReference(typeSystem.SByte);\n                case Il2CppTypeEnum.IL2CPP_TYPE_U1:\n                    return moduleDefinition.ImportReference(typeSystem.Byte);\n                case Il2CppTypeEnum.IL2CPP_TYPE_I2:\n                    return moduleDefinition.ImportReference(typeSystem.Int16);\n                case Il2CppTypeEnum.IL2CPP_TYPE_U2:\n                    return moduleDefinition.ImportReference(typeSystem.UInt16);\n                case Il2CppTypeEnum.IL2CPP_TYPE_I4:\n                    return moduleDefinition.ImportReference(typeSystem.Int32);\n                case Il2CppTypeEnum.IL2CPP_TYPE_U4:\n                    return moduleDefinition.ImportReference(typeSystem.UInt32);\n                case Il2CppTypeEnum.IL2CPP_TYPE_I:\n                    return moduleDefinition.ImportReference(typeSystem.IntPtr);\n                case Il2CppTypeEnum.IL2CPP_TYPE_U:\n                    return moduleDefinition.ImportReference(typeSystem.UIntPtr);\n                case Il2CppTypeEnum.IL2CPP_TYPE_I8:\n                    return moduleDefinition.ImportReference(typeSystem.Int64);\n                case Il2CppTypeEnum.IL2CPP_TYPE_U8:\n                    return moduleDefinition.ImportReference(typeSystem.UInt64);\n                case Il2CppTypeEnum.IL2CPP_TYPE_R4:\n                    return moduleDefinition.ImportReference(typeSystem.Single);\n                case Il2CppTypeEnum.IL2CPP_TYPE_R8:\n                    return moduleDefinition.ImportReference(typeSystem.Double);\n                case Il2CppTypeEnum.IL2CPP_TYPE_STRING:\n                    return moduleDefinition.ImportReference(typeSystem.String);\n                case Il2CppTypeEnum.IL2CPP_TYPE_TYPEDBYREF:\n                    return moduleDefinition.ImportReference(typeSystem.TypedReference);\n                case Il2CppTypeEnum.IL2CPP_TYPE_CLASS:\n                case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE:\n                    {\n                        var typeDef = executor.GetTypeDefinitionFromIl2CppType(il2CppType);\n                        var typeDefinition = typeDefinitionDic[typeDef];\n                        return moduleDefinition.ImportReference(typeDefinition);\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY:\n                    {\n                        var arrayType = il2Cpp.MapVATR<Il2CppArrayType>(il2CppType.data.array);\n                        var oriType = il2Cpp.GetIl2CppType(arrayType.etype);\n                        return new ArrayType(GetTypeReference(memberReference, oriType), arrayType.rank);\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST:\n                    {\n                        var genericClass = il2Cpp.MapVATR<Il2CppGenericClass>(il2CppType.data.generic_class);\n                        var typeDef = executor.GetGenericClassTypeDefinition(genericClass);\n                        var typeDefinition = typeDefinitionDic[typeDef];\n                        var genericInstanceType = new GenericInstanceType(moduleDefinition.ImportReference(typeDefinition));\n                        var genericInst = il2Cpp.MapVATR<Il2CppGenericInst>(genericClass.context.class_inst);\n                        var pointers = il2Cpp.MapVATR<ulong>(genericInst.type_argv, genericInst.type_argc);\n                        foreach (var pointer in pointers)\n                        {\n                            var oriType = il2Cpp.GetIl2CppType(pointer);\n                            genericInstanceType.GenericArguments.Add(GetTypeReference(memberReference, oriType));\n                        }\n                        return genericInstanceType;\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY:\n                    {\n                        var oriType = il2Cpp.GetIl2CppType(il2CppType.data.type);\n                        return new ArrayType(GetTypeReference(memberReference, oriType));\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_VAR:\n                    {\n                        if (memberReference is MethodDefinition methodDefinition)\n                        {\n                            return CreateGenericParameter(executor.GetGenericParameteFromIl2CppType(il2CppType), methodDefinition.DeclaringType);\n                        }\n                        var typeDefinition = (TypeDefinition)memberReference;\n                        return CreateGenericParameter(executor.GetGenericParameteFromIl2CppType(il2CppType), typeDefinition);\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_MVAR:\n                    {\n                        var methodDefinition = (MethodDefinition)memberReference;\n                        return CreateGenericParameter(executor.GetGenericParameteFromIl2CppType(il2CppType), methodDefinition);\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_PTR:\n                    {\n                        var oriType = il2Cpp.GetIl2CppType(il2CppType.data.type);\n                        return new PointerType(GetTypeReference(memberReference, oriType));\n                    }\n                default:\n                    throw new NotSupportedException();\n            }\n        }\n\n        private void CreateCustomAttribute(Il2CppImageDefinition imageDef, int customAttributeIndex, uint token, ModuleDefinition moduleDefinition, Collection<CustomAttribute> customAttributes)\n        {\n            var attributeIndex = metadata.GetCustomAttributeIndex(imageDef, customAttributeIndex, token);\n            if (attributeIndex >= 0)\n            {\n                try\n                {\n                    if (il2Cpp.Version < 29)\n                    {\n                        var attributeTypeRange = metadata.attributeTypeRanges[attributeIndex];\n                        for (int i = 0; i < attributeTypeRange.count; i++)\n                        {\n                            var attributeTypeIndex = metadata.attributeTypes[attributeTypeRange.start + i];\n                            var attributeType = il2Cpp.types[attributeTypeIndex];\n                            var typeDef = executor.GetTypeDefinitionFromIl2CppType(attributeType);\n                            var typeDefinition = typeDefinitionDic[typeDef];\n                            if (!TryRestoreCustomAttribute(typeDefinition, moduleDefinition, customAttributes))\n                            {\n                                var methodPointer = executor.customAttributeGenerators[attributeIndex];\n                                var fixedMethodPointer = il2Cpp.GetRVA(methodPointer);\n                                var customAttribute = new CustomAttribute(moduleDefinition.ImportReference(attributeAttribute));\n                                var name = new CustomAttributeNamedArgument(\"Name\", new CustomAttributeArgument(stringType, typeDefinition.Name));\n                                var rva = new CustomAttributeNamedArgument(\"RVA\", new CustomAttributeArgument(stringType, $\"0x{fixedMethodPointer:X}\"));\n                                var offset = new CustomAttributeNamedArgument(\"Offset\", new CustomAttributeArgument(stringType, $\"0x{il2Cpp.MapVATR(methodPointer):X}\"));\n                                customAttribute.Fields.Add(name);\n                                customAttribute.Fields.Add(rva);\n                                customAttribute.Fields.Add(offset);\n                                customAttributes.Add(customAttribute);\n                            }\n                        }\n                    }\n                    else\n                    {\n                        var startRange = metadata.attributeDataRanges[attributeIndex];\n                        var endRange = metadata.attributeDataRanges[attributeIndex + 1];\n                        metadata.Position = metadata.header.attributeDataOffset + startRange.startOffset;\n                        var buff = metadata.ReadBytes((int)(endRange.startOffset - startRange.startOffset));\n                        var reader = new CustomAttributeDataReader(executor, buff);\n                        if (reader.Count != 0)\n                        {\n                            for (var i = 0; i < reader.Count; i++)\n                            {\n                                var visitor = reader.VisitCustomAttributeData();\n                                var methodDefinition = methodDefinitionDic[visitor.CtorIndex];\n                                var customAttribute = new CustomAttribute(moduleDefinition.ImportReference(methodDefinition));\n                                foreach (var argument in visitor.Arguments)\n                                {\n                                    var parameterDefinition = methodDefinition.Parameters[argument.Index];\n                                    var customAttributeArgument = CreateCustomAttributeArgument(parameterDefinition.ParameterType, argument.Value, methodDefinition);\n                                    customAttribute.ConstructorArguments.Add(customAttributeArgument);\n                                }\n                                foreach (var field in visitor.Fields)\n                                {\n                                    var fieldDefinition = fieldDefinitionDic[field.Index];\n                                    var customAttributeArgument = CreateCustomAttributeArgument(fieldDefinition.FieldType, field.Value, fieldDefinition);\n                                    var customAttributeNamedArgument = new CustomAttributeNamedArgument(fieldDefinition.Name, customAttributeArgument);\n                                    customAttribute.Fields.Add(customAttributeNamedArgument);\n                                }\n                                foreach (var property in visitor.Properties)\n                                {\n                                    var propertyDefinition = propertyDefinitionDic[property.Index];\n                                    var customAttributeArgument = CreateCustomAttributeArgument(propertyDefinition.PropertyType, property.Value, propertyDefinition);\n                                    var customAttributeNamedArgument = new CustomAttributeNamedArgument(propertyDefinition.Name, customAttributeArgument);\n                                    customAttribute.Properties.Add(customAttributeNamedArgument);\n                                }\n                                customAttributes.Add(customAttribute);\n                            }\n                        }\n                    }\n                }\n                catch\n                {\n                    Console.WriteLine($\"ERROR: Error while restoring attributeIndex {attributeIndex}\");\n                }\n            }\n        }\n\n        private static bool TryRestoreCustomAttribute(TypeDefinition attributeType, ModuleDefinition moduleDefinition, Collection<CustomAttribute> customAttributes)\n        {\n            if (attributeType.Methods.Count == 1 && attributeType.Name != \"CompilerGeneratedAttribute\")\n            {\n                var methodDefinition = attributeType.Methods[0];\n                if (methodDefinition.Name == \".ctor\" && methodDefinition.Parameters.Count == 0)\n                {\n                    var customAttribute = new CustomAttribute(moduleDefinition.ImportReference(methodDefinition));\n                    customAttributes.Add(customAttribute);\n                    return true;\n                }\n            }\n            return false;\n        }\n\n        private GenericParameter CreateGenericParameter(Il2CppGenericParameter param, IGenericParameterProvider iGenericParameterProvider)\n        {\n            if (!genericParameterDic.TryGetValue(param, out var genericParameter))\n            {\n                var genericName = metadata.GetStringFromIndex(param.nameIndex);\n                genericParameter = new GenericParameter(genericName, iGenericParameterProvider)\n                {\n                    Attributes = (GenericParameterAttributes)param.flags\n                };\n                genericParameterDic.Add(param, genericParameter);\n                for (int i = 0; i < param.constraintsCount; ++i)\n                {\n                    var il2CppType = il2Cpp.types[metadata.constraintIndices[param.constraintsStart + i]];\n                    genericParameter.Constraints.Add(new GenericParameterConstraint(GetTypeReference((MemberReference)iGenericParameterProvider, il2CppType)));\n                }\n            }\n            return genericParameter;\n        }\n\n        private CustomAttributeArgument CreateCustomAttributeArgument(TypeReference typeReference, BlobValue blobValue, MemberReference memberReference)\n        {\n            var val = blobValue.Value;\n            if (typeReference.FullName == \"System.Object\")\n            {\n                if (blobValue.il2CppTypeEnum == Il2CppTypeEnum.IL2CPP_TYPE_IL2CPP_TYPE_INDEX)\n                {\n                    val = new CustomAttributeArgument(memberReference.Module.ImportReference(typeof(Type)), GetTypeReference(memberReference, (Il2CppType)val));\n                }\n                else\n                {\n                    val = new CustomAttributeArgument(GetBlobValueTypeReference(blobValue, memberReference), val);\n                }\n            }\n            else if (val == null)\n            {\n                return new CustomAttributeArgument(typeReference, val);\n            }\n            else if (typeReference is ArrayType arrayType)\n            {\n                var arrayVal = (BlobValue[])val;\n                var array = new CustomAttributeArgument[arrayVal.Length];\n                var elementType = arrayType.ElementType;\n                for (int i = 0; i < arrayVal.Length; i++)\n                {\n                    array[i] = CreateCustomAttributeArgument(elementType, arrayVal[i], memberReference);\n                }\n                val = array;\n            }\n            else if (typeReference.FullName == \"System.Type\")\n            {\n                val = GetTypeReference(memberReference, (Il2CppType)val);\n            }\n            return new CustomAttributeArgument(typeReference, val);\n        }\n\n        private TypeReference GetBlobValueTypeReference(BlobValue blobValue, MemberReference memberReference)\n        {\n            if (blobValue.EnumType != null)\n            {\n                return GetTypeReference(memberReference, blobValue.EnumType);\n            }\n            var il2CppType = new Il2CppType\n            {\n                type = blobValue.il2CppTypeEnum\n            };\n            return GetTypeReference(memberReference, il2CppType);\n        }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Utils/FileDialogNative.cs",
    "content": "﻿using System;\nusing System.Runtime.InteropServices;\n\nnamespace Il2CppDumper\n{\n    static class FileDialogNative\n    {\n        [ComImport]\n        [ClassInterface(ClassInterfaceType.None)]\n        [TypeLibType(TypeLibTypeFlags.FCanCreate)]\n        [Guid(CLSIDGuid.FileOpenDialog)]\n        internal class FileOpenDialogRCW\n        { }\n\n        internal class IIDGuid\n        {\n            private IIDGuid() { } // Avoid FxCop violation AvoidUninstantiatedInternalClasses\n            // IID GUID strings for relevant COM interfaces\n            internal const string IModalWindow = \"b4db1657-70d7-485e-8e3e-6fcb5a5c1802\";\n            internal const string IFileDialog = \"42f85136-db7e-439c-85f1-e4075d135fc8\";\n            internal const string IFileOpenDialog = \"d57c7288-d4ad-4768-be02-9d969532d960\";\n            internal const string IFileSaveDialog = \"84bccd23-5fde-4cdb-aea4-af64b83d78ab\";\n            internal const string IFileDialogEvents = \"973510DB-7D7F-452B-8975-74A85828D354\";\n            internal const string IShellItem = \"43826D1E-E718-42EE-BC55-A1E261C37BFE\";\n            internal const string IShellItemArray = \"B63EA76D-1F85-456F-A19C-48159EFA858B\";\n        }\n\n        internal class CLSIDGuid\n        {\n            private CLSIDGuid() { } // Avoid FxCop violation AvoidUninstantiatedInternalClasses\n            internal const string FileOpenDialog = \"DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7\";\n            internal const string FileSaveDialog = \"C0B4E2F3-BA21-4773-8DBA-335EC946EB8B\";\n        }\n\n        [ComImport()]\n        [Guid(IIDGuid.IFileDialog)]\n        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]\n        internal interface IFileDialog\n        {\n            [PreserveSig]\n            int Show([In] IntPtr parent);\n\n            void SetFileTypes([In] uint cFileTypes, [In][MarshalAs(UnmanagedType.LPArray)] COMDLG_FILTERSPEC[] rgFilterSpec);\n\n            void SetFileTypeIndex([In] uint iFileType);\n\n            void GetFileTypeIndex(out uint piFileType);\n\n            void Advise([In, MarshalAs(UnmanagedType.Interface)] IFileDialogEvents pfde, out uint pdwCookie);\n\n            void Unadvise([In] uint dwCookie);\n\n            void SetOptions([In] FOS fos);\n\n            void GetOptions(out FOS pfos);\n\n            void SetDefaultFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);\n\n            void SetFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);\n\n            void GetFolder([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);\n\n            void GetCurrentSelection([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);\n\n            void SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] string pszName);\n\n            void GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName);\n\n            void SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle);\n\n            void SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText);\n\n            void SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel);\n\n            void GetResult([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);\n\n            void AddPlace([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, int alignment);\n\n            void SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);\n\n            void Close([MarshalAs(UnmanagedType.Error)] int hr);\n\n            void SetClientGuid([In] ref Guid guid);\n\n            void ClearClientData();\n\n            void SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter);\n        }\n\n        [ComImport,\n        Guid(IIDGuid.IFileDialogEvents),\n        InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]\n        internal interface IFileDialogEvents\n        {\n            // NOTE: some of these callbacks are cancelable - returning S_FALSE means that \n            // the dialog should not proceed (e.g. with closing, changing folder); to \n            // support this, we need to use the PreserveSig attribute to enable us to return\n            // the proper HRESULT\n            [PreserveSig]\n            int OnFileOk([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd);\n\n            [PreserveSig]\n            int OnFolderChanging([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd, [In, MarshalAs(UnmanagedType.Interface)] IShellItem psiFolder);\n\n            void OnFolderChange([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd);\n\n            void OnSelectionChange([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd);\n\n            void OnShareViolation([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd, [In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, out FDE_SHAREVIOLATION_RESPONSE pResponse);\n\n            void OnTypeChange([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd);\n\n            void OnOverwrite([In, MarshalAs(UnmanagedType.Interface)] IFileDialog pfd, [In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, out FDE_OVERWRITE_RESPONSE pResponse);\n        }\n\n        [ComImport,\n        Guid(IIDGuid.IShellItem),\n        InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]\n        internal interface IShellItem\n        {\n            void BindToHandler([In, MarshalAs(UnmanagedType.Interface)] IntPtr pbc, [In] ref Guid bhid, [In] ref Guid riid, out IntPtr ppv);\n\n            void GetParent([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);\n\n            void GetDisplayName([In] SIGDN sigdnName, [MarshalAs(UnmanagedType.LPWStr)] out string ppszName);\n\n            void GetAttributes([In] uint sfgaoMask, out uint psfgaoAttribs);\n\n            void Compare([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, [In] uint hint, out int piOrder);\n        }\n\n        internal enum SIGDN : uint\n        {\n            SIGDN_NORMALDISPLAY = 0x00000000,           // SHGDN_NORMAL\n            SIGDN_PARENTRELATIVEPARSING = 0x80018001,   // SHGDN_INFOLDER | SHGDN_FORPARSING\n            SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000,  // SHGDN_FORPARSING\n            SIGDN_PARENTRELATIVEEDITING = 0x80031001,   // SHGDN_INFOLDER | SHGDN_FOREDITING\n            SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000,  // SHGDN_FORPARSING | SHGDN_FORADDRESSBAR\n            SIGDN_FILESYSPATH = 0x80058000,             // SHGDN_FORPARSING\n            SIGDN_URL = 0x80068000,                     // SHGDN_FORPARSING\n            SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8007c001,     // SHGDN_INFOLDER | SHGDN_FORPARSING | SHGDN_FORADDRESSBAR\n            SIGDN_PARENTRELATIVE = 0x80080001           // SHGDN_INFOLDER\n        }\n\n        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)]\n        internal struct COMDLG_FILTERSPEC\n        {\n            [MarshalAs(UnmanagedType.LPWStr)]\n            internal string pszName;\n            [MarshalAs(UnmanagedType.LPWStr)]\n            internal string pszSpec;\n        }\n\n        [Flags]\n        internal enum FOS : uint\n        {\n            FOS_OVERWRITEPROMPT = 0x00000002,\n            FOS_STRICTFILETYPES = 0x00000004,\n            FOS_NOCHANGEDIR = 0x00000008,\n            FOS_PICKFOLDERS = 0x00000020,\n            FOS_FORCEFILESYSTEM = 0x00000040, // Ensure that items returned are filesystem items.\n            FOS_ALLNONSTORAGEITEMS = 0x00000080, // Allow choosing items that have no storage.\n            FOS_NOVALIDATE = 0x00000100,\n            FOS_ALLOWMULTISELECT = 0x00000200,\n            FOS_PATHMUSTEXIST = 0x00000800,\n            FOS_FILEMUSTEXIST = 0x00001000,\n            FOS_CREATEPROMPT = 0x00002000,\n            FOS_SHAREAWARE = 0x00004000,\n            FOS_NOREADONLYRETURN = 0x00008000,\n            FOS_NOTESTFILECREATE = 0x00010000,\n            FOS_HIDEMRUPLACES = 0x00020000,\n            FOS_HIDEPINNEDPLACES = 0x00040000,\n            FOS_NODEREFERENCELINKS = 0x00100000,\n            FOS_DONTADDTORECENT = 0x02000000,\n            FOS_FORCESHOWHIDDEN = 0x10000000,\n            FOS_DEFAULTNOMINIMODE = 0x20000000\n        }\n\n        internal enum FDE_SHAREVIOLATION_RESPONSE\n        {\n            FDESVR_DEFAULT = 0x00000000,\n            FDESVR_ACCEPT = 0x00000001,\n            FDESVR_REFUSE = 0x00000002\n        }\n\n        internal enum FDE_OVERWRITE_RESPONSE\n        {\n            FDEOR_DEFAULT = 0x00000000,\n            FDEOR_ACCEPT = 0x00000001,\n            FDEOR_REFUSE = 0x00000002\n        }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Utils/Il2CppExecutor.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\n\nnamespace Il2CppDumper\n{\n    public class Il2CppExecutor\n    {\n        public Metadata metadata;\n        public Il2Cpp il2Cpp;\n        private static readonly Dictionary<int, string> TypeString = new()\n        {\n            {1,\"void\"},\n            {2,\"bool\"},\n            {3,\"char\"},\n            {4,\"sbyte\"},\n            {5,\"byte\"},\n            {6,\"short\"},\n            {7,\"ushort\"},\n            {8,\"int\"},\n            {9,\"uint\"},\n            {10,\"long\"},\n            {11,\"ulong\"},\n            {12,\"float\"},\n            {13,\"double\"},\n            {14,\"string\"},\n            {22,\"TypedReference\"},\n            {24,\"IntPtr\"},\n            {25,\"UIntPtr\"},\n            {28,\"object\"},\n        };\n        public ulong[] customAttributeGenerators;\n\n        public Il2CppExecutor(Metadata metadata, Il2Cpp il2Cpp)\n        {\n            this.metadata = metadata;\n            this.il2Cpp = il2Cpp;\n\n            if (il2Cpp.Version >= 27 && il2Cpp.Version < 29)\n            {\n                customAttributeGenerators = new ulong[metadata.imageDefs.Sum(x => x.customAttributeCount)];\n                foreach (var imageDef in metadata.imageDefs)\n                {\n                    var imageDefName = metadata.GetStringFromIndex(imageDef.nameIndex);\n                    var codeGenModule = il2Cpp.codeGenModules[imageDefName];\n                    if (imageDef.customAttributeCount > 0)\n                    {\n                        var pointers = il2Cpp.ReadClassArray<ulong>(il2Cpp.MapVATR(codeGenModule.customAttributeCacheGenerator), imageDef.customAttributeCount);\n                        pointers.CopyTo(customAttributeGenerators, imageDef.customAttributeStart);\n                    }\n                }\n            }\n            else if (il2Cpp.Version < 27)\n            {\n                customAttributeGenerators = il2Cpp.customAttributeGenerators;\n            }\n        }\n\n        public string GetTypeName(Il2CppType il2CppType, bool addNamespace, bool is_nested)\n        {\n            switch (il2CppType.type)\n            {\n                case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY:\n                    {\n                        var arrayType = il2Cpp.MapVATR<Il2CppArrayType>(il2CppType.data.array);\n                        var elementType = il2Cpp.GetIl2CppType(arrayType.etype);\n                        return $\"{GetTypeName(elementType, addNamespace, false)}[{new string(',', arrayType.rank - 1)}]\";\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY:\n                    {\n                        var elementType = il2Cpp.GetIl2CppType(il2CppType.data.type);\n                        return $\"{GetTypeName(elementType, addNamespace, false)}[]\";\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_PTR:\n                    {\n                        var oriType = il2Cpp.GetIl2CppType(il2CppType.data.type);\n                        return $\"{GetTypeName(oriType, addNamespace, false)}*\";\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_VAR:\n                case Il2CppTypeEnum.IL2CPP_TYPE_MVAR:\n                    {\n                        var param = GetGenericParameteFromIl2CppType(il2CppType);\n                        return metadata.GetStringFromIndex(param.nameIndex);\n                    }\n                case Il2CppTypeEnum.IL2CPP_TYPE_CLASS:\n                case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE:\n                case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST:\n                    {\n                        string str = string.Empty;\n                        Il2CppTypeDefinition typeDef;\n                        Il2CppGenericClass genericClass = null;\n                        if (il2CppType.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST)\n                        {\n                            genericClass = il2Cpp.MapVATR<Il2CppGenericClass>(il2CppType.data.generic_class);\n                            typeDef = GetGenericClassTypeDefinition(genericClass);\n                        }\n                        else\n                        {\n                            typeDef = GetTypeDefinitionFromIl2CppType(il2CppType);\n                        }\n                        if (typeDef.declaringTypeIndex != -1)\n                        {\n                            str += GetTypeName(il2Cpp.types[typeDef.declaringTypeIndex], addNamespace, true);\n                            str += '.';\n                        }\n                        else if (addNamespace)\n                        {\n                            var @namespace = metadata.GetStringFromIndex(typeDef.namespaceIndex);\n                            if (@namespace != \"\")\n                            {\n                                str += @namespace + \".\";\n                            }\n                        }\n\n                        var typeName = metadata.GetStringFromIndex(typeDef.nameIndex);\n                        var index = typeName.IndexOf(\"`\");\n                        if (index != -1)\n                        {\n                            str += typeName[..index];\n                        }\n                        else\n                        {\n                            str += typeName;\n                        }\n\n                        if (is_nested)\n                            return str;\n\n                        if (genericClass != null)\n                        {\n                            var genericInst = il2Cpp.MapVATR<Il2CppGenericInst>(genericClass.context.class_inst);\n                            str += GetGenericInstParams(genericInst);\n                        }\n                        else if (typeDef.genericContainerIndex >= 0)\n                        {\n                            var genericContainer = metadata.genericContainers[typeDef.genericContainerIndex];\n                            str += GetGenericContainerParams(genericContainer);\n                        }\n\n                        return str;\n                    }\n                default:\n                    return TypeString[(int)il2CppType.type];\n            }\n        }\n\n        public string GetTypeDefName(Il2CppTypeDefinition typeDef, bool addNamespace, bool genericParameter)\n        {\n            var prefix = string.Empty;\n            if (typeDef.declaringTypeIndex != -1)\n            {\n                prefix = GetTypeName(il2Cpp.types[typeDef.declaringTypeIndex], addNamespace, true) + \".\";\n            }\n            else if (addNamespace)\n            {\n                var @namespace = metadata.GetStringFromIndex(typeDef.namespaceIndex);\n                if (@namespace != \"\")\n                {\n                    prefix = @namespace + \".\";\n                }\n            }\n            var typeName = metadata.GetStringFromIndex(typeDef.nameIndex);\n            if (typeDef.genericContainerIndex >= 0)\n            {\n                var index = typeName.IndexOf(\"`\");\n                if (index != -1)\n                {\n                    typeName = typeName[..index];\n                }\n                if (genericParameter)\n                {\n                    var genericContainer = metadata.genericContainers[typeDef.genericContainerIndex];\n                    typeName += GetGenericContainerParams(genericContainer);\n                }\n            }\n            return prefix + typeName;\n        }\n\n        public string GetGenericInstParams(Il2CppGenericInst genericInst)\n        {\n            var genericParameterNames = new List<string>();\n            var pointers = il2Cpp.MapVATR<ulong>(genericInst.type_argv, genericInst.type_argc);\n            for (int i = 0; i < genericInst.type_argc; i++)\n            {\n                var il2CppType = il2Cpp.GetIl2CppType(pointers[i]);\n                genericParameterNames.Add(GetTypeName(il2CppType, false, false));\n            }\n            return $\"<{string.Join(\", \", genericParameterNames)}>\";\n        }\n\n        public string GetGenericContainerParams(Il2CppGenericContainer genericContainer)\n        {\n            var genericParameterNames = new List<string>();\n            for (int i = 0; i < genericContainer.type_argc; i++)\n            {\n                var genericParameterIndex = genericContainer.genericParameterStart + i;\n                var genericParameter = metadata.genericParameters[genericParameterIndex];\n                genericParameterNames.Add(metadata.GetStringFromIndex(genericParameter.nameIndex));\n            }\n            return $\"<{string.Join(\", \", genericParameterNames)}>\";\n        }\n\n        public (string, string) GetMethodSpecName(Il2CppMethodSpec methodSpec, bool addNamespace = false)\n        {\n            var methodDef = metadata.methodDefs[methodSpec.methodDefinitionIndex];\n            var typeDef = metadata.typeDefs[methodDef.declaringType];\n            var typeName = GetTypeDefName(typeDef, addNamespace, false);\n            if (methodSpec.classIndexIndex != -1)\n            {\n                var classInst = il2Cpp.genericInsts[methodSpec.classIndexIndex];\n                typeName += GetGenericInstParams(classInst);\n            }\n            var methodName = metadata.GetStringFromIndex(methodDef.nameIndex);\n            if (methodSpec.methodIndexIndex != -1)\n            {\n                var methodInst = il2Cpp.genericInsts[methodSpec.methodIndexIndex];\n                methodName += GetGenericInstParams(methodInst);\n            }\n            return (typeName, methodName);\n        }\n\n        public Il2CppGenericContext GetMethodSpecGenericContext(Il2CppMethodSpec methodSpec)\n        {\n            var classInstPointer = 0ul;\n            var methodInstPointer = 0ul;\n            if (methodSpec.classIndexIndex != -1)\n            {\n                classInstPointer = il2Cpp.genericInstPointers[methodSpec.classIndexIndex];\n            }\n            if (methodSpec.methodIndexIndex != -1)\n            {\n                methodInstPointer = il2Cpp.genericInstPointers[methodSpec.methodIndexIndex];\n            }\n            return new Il2CppGenericContext { class_inst = classInstPointer, method_inst = methodInstPointer };\n        }\n\n        public Il2CppRGCTXDefinition[] GetRGCTXDefinition(string imageName, Il2CppTypeDefinition typeDef)\n        {\n            Il2CppRGCTXDefinition[] collection = null;\n            if (il2Cpp.Version >= 24.2)\n            {\n                il2Cpp.rgctxsDictionary[imageName].TryGetValue(typeDef.token, out collection);\n            }\n            else\n            {\n                if (typeDef.rgctxCount > 0)\n                {\n                    collection = new Il2CppRGCTXDefinition[typeDef.rgctxCount];\n                    Array.Copy(metadata.rgctxEntries, typeDef.rgctxStartIndex, collection, 0, typeDef.rgctxCount);\n                }\n            }\n            return collection;\n        }\n\n        public Il2CppRGCTXDefinition[] GetRGCTXDefinition(string imageName, Il2CppMethodDefinition methodDef)\n        {\n            Il2CppRGCTXDefinition[] collection = null;\n            if (il2Cpp.Version >= 24.2)\n            {\n                il2Cpp.rgctxsDictionary[imageName].TryGetValue(methodDef.token, out collection);\n            }\n            else\n            {\n                if (methodDef.rgctxCount > 0)\n                {\n                    collection = new Il2CppRGCTXDefinition[methodDef.rgctxCount];\n                    Array.Copy(metadata.rgctxEntries, methodDef.rgctxStartIndex, collection, 0, methodDef.rgctxCount);\n                }\n            }\n            return collection;\n        }\n\n        public Il2CppTypeDefinition GetGenericClassTypeDefinition(Il2CppGenericClass genericClass)\n        {\n            if (il2Cpp.Version >= 27)\n            {\n                var il2CppType = il2Cpp.GetIl2CppType(genericClass.type);\n                if (il2CppType == null)\n                {\n                    return null;\n                }\n                return GetTypeDefinitionFromIl2CppType(il2CppType);\n            }\n            if (genericClass.typeDefinitionIndex == 4294967295 || genericClass.typeDefinitionIndex == -1)\n            {\n                return null;\n            }\n            return metadata.typeDefs[genericClass.typeDefinitionIndex];\n        }\n\n        public Il2CppTypeDefinition GetTypeDefinitionFromIl2CppType(Il2CppType il2CppType)\n        {\n            if (il2Cpp.Version >= 27 && il2Cpp.IsDumped)\n            {\n                var offset = il2CppType.data.typeHandle - metadata.ImageBase - metadata.header.typeDefinitionsOffset;\n                var index = offset / (ulong)metadata.SizeOf(typeof(Il2CppTypeDefinition));\n                return metadata.typeDefs[index];\n            }\n            else\n            {\n                return metadata.typeDefs[il2CppType.data.klassIndex];\n            }\n        }\n\n        public Il2CppGenericParameter GetGenericParameteFromIl2CppType(Il2CppType il2CppType)\n        {\n            if (il2Cpp.Version >= 27 && il2Cpp.IsDumped)\n            {\n                var offset = il2CppType.data.genericParameterHandle - metadata.ImageBase - metadata.header.genericParametersOffset;\n                var index = offset / (ulong)metadata.SizeOf(typeof(Il2CppGenericParameter));\n                return metadata.genericParameters[index];\n            }\n            else\n            {\n                return metadata.genericParameters[il2CppType.data.genericParameterIndex];\n            }\n        }\n\n        public SectionHelper GetSectionHelper()\n        {\n            return il2Cpp.GetSectionHelper(metadata.methodDefs.Count(x => x.methodIndex >= 0), metadata.typeDefs.Length, metadata.imageDefs.Length);\n        }\n\n        public bool TryGetDefaultValue(int typeIndex, int dataIndex, out object value)\n        {\n            var pointer = metadata.GetDefaultValueFromIndex(dataIndex);\n            var defaultValueType = il2Cpp.types[typeIndex];\n            metadata.Position = pointer;\n            if (GetConstantValueFromBlob(defaultValueType.type, metadata.Reader, out var blobValue))\n            {\n                value = blobValue.Value;\n                return true;\n            }\n            else\n            {\n                value = pointer;\n                return false;\n            }\n        }\n\n        public bool GetConstantValueFromBlob(Il2CppTypeEnum type, BinaryReader reader, out BlobValue value)\n        {\n            value = new BlobValue\n            {\n                il2CppTypeEnum = type\n            };\n            switch (type)\n            {\n                case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN:\n                    value.Value = reader.ReadBoolean();\n                    return true;\n                case Il2CppTypeEnum.IL2CPP_TYPE_U1:\n                    value.Value = reader.ReadByte();\n                    return true;\n                case Il2CppTypeEnum.IL2CPP_TYPE_I1:\n                    value.Value = reader.ReadSByte();\n                    return true;\n                case Il2CppTypeEnum.IL2CPP_TYPE_CHAR:\n                    value.Value = BitConverter.ToChar(reader.ReadBytes(2), 0);\n                    return true;\n                case Il2CppTypeEnum.IL2CPP_TYPE_U2:\n                    value.Value = reader.ReadUInt16();\n                    return true;\n                case Il2CppTypeEnum.IL2CPP_TYPE_I2:\n                    value.Value = reader.ReadInt16();\n                    return true;\n                case Il2CppTypeEnum.IL2CPP_TYPE_U4:\n                    if (il2Cpp.Version >= 29)\n                    {\n                        value.Value = reader.ReadCompressedUInt32();\n                    }\n                    else\n                    {\n                        value.Value = reader.ReadUInt32();\n                    }\n                    return true;\n                case Il2CppTypeEnum.IL2CPP_TYPE_I4:\n                    if (il2Cpp.Version >= 29)\n                    {\n                        value.Value = reader.ReadCompressedInt32();\n                    }\n                    else\n                    {\n                        value.Value = reader.ReadInt32();\n                    }\n                    return true;\n                case Il2CppTypeEnum.IL2CPP_TYPE_U8:\n                    value.Value = reader.ReadUInt64();\n                    return true;\n                case Il2CppTypeEnum.IL2CPP_TYPE_I8:\n                    value.Value = reader.ReadInt64();\n                    return true;\n                case Il2CppTypeEnum.IL2CPP_TYPE_R4:\n                    value.Value = reader.ReadSingle();\n                    return true;\n                case Il2CppTypeEnum.IL2CPP_TYPE_R8:\n                    value.Value = reader.ReadDouble();\n                    return true;\n                case Il2CppTypeEnum.IL2CPP_TYPE_STRING:\n                    int length;\n                    if (il2Cpp.Version >= 29)\n                    {\n                        length = reader.ReadCompressedInt32();\n                        if (length == -1)\n                        {\n                            value.Value = null;\n                        }\n                        else\n                        {\n                            value.Value = Encoding.UTF8.GetString(reader.ReadBytes(length));\n                        }\n                    }\n                    else\n                    {\n                        length = reader.ReadInt32();\n                        value.Value = reader.ReadString(length);\n                    }\n                    return true;\n                case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY:\n                    var arrayLen = reader.ReadCompressedInt32();\n                    if (arrayLen == -1)\n                    {\n                        value.Value = null;\n                    }\n                    else\n                    {\n                        var array = new BlobValue[arrayLen];\n                        var arrayElementType = ReadEncodedTypeEnum(reader, out var enumType);\n                        var arrayElementsAreDifferent = reader.ReadByte();\n                        for (int i = 0; i < arrayLen; i++)\n                        {\n                            var elementType = arrayElementType;\n                            if (arrayElementsAreDifferent == 1)\n                            {\n                                elementType = ReadEncodedTypeEnum(reader, out enumType);\n                            }\n                            GetConstantValueFromBlob(elementType, reader, out var data);\n                            data.il2CppTypeEnum = elementType;\n                            data.EnumType = enumType;\n                            array[i] = data;\n                        }\n                        value.Value = array;\n                    }\n                    return true;\n                case Il2CppTypeEnum.IL2CPP_TYPE_IL2CPP_TYPE_INDEX:\n                    var typeIndex = reader.ReadCompressedInt32();\n                    if (typeIndex == -1)\n                    {\n                        value.Value = null;\n                    }\n                    else\n                    {\n                        value.Value = il2Cpp.types[typeIndex];\n                    }\n                    return true;\n                default:\n                    value = null;\n                    return false;\n            }\n        }\n\n        public Il2CppTypeEnum ReadEncodedTypeEnum(BinaryReader reader, out Il2CppType enumType)\n        {\n            enumType = null;\n            var type = (Il2CppTypeEnum)reader.ReadByte();\n            if (type == Il2CppTypeEnum.IL2CPP_TYPE_ENUM)\n            {\n                var enumTypeIndex = reader.ReadCompressedInt32();\n                enumType = il2Cpp.types[enumTypeIndex];\n                var typeDef = GetTypeDefinitionFromIl2CppType(enumType);\n                type = il2Cpp.types[typeDef.elementTypeIndex].type;\n            }\n            return type;\n        }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Utils/MyAssemblyResolver.cs",
    "content": "﻿using Mono.Cecil;\n\nnamespace Il2CppDumper\n{\n    public class MyAssemblyResolver : DefaultAssemblyResolver\n    {\n        public void Register(AssemblyDefinition assembly)\n        {\n            RegisterAssembly(assembly);\n        }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Utils/OpenFileDialog.cs",
    "content": "﻿using System;\nusing static Il2CppDumper.FileDialogNative;\n\nnamespace Il2CppDumper\n{\n    public class OpenFileDialog\n    {\n        public string Title { get; set; }\n        public string Filter { get; set; }\n        public string FileName { get; set; }\n\n        public bool ShowDialog()\n        {\n            var dialog = (IFileDialog)(new FileOpenDialogRCW());\n            dialog.GetOptions(out var options);\n            options |= FOS.FOS_FORCEFILESYSTEM | FOS.FOS_NOVALIDATE | FOS.FOS_DONTADDTORECENT;\n            dialog.SetOptions(options);\n            if (!string.IsNullOrEmpty(Title))\n            {\n                dialog.SetTitle(Title);\n            }\n            if (!string.IsNullOrEmpty(Filter))\n            {\n                string[] filterElements = Filter.Split(new char[] { '|' });\n                COMDLG_FILTERSPEC[] filter = new COMDLG_FILTERSPEC[filterElements.Length / 2];\n                for (int x = 0; x < filterElements.Length; x += 2)\n                {\n                    filter[x / 2].pszName = filterElements[x];\n                    filter[x / 2].pszSpec = filterElements[x + 1];\n                }\n                dialog.SetFileTypes((uint)filter.Length, filter);\n            }\n            if (dialog.Show(IntPtr.Zero) == 0)\n            {\n                dialog.GetResult(out var shellItem);\n                shellItem.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out var ppszName);\n                FileName = ppszName;\n                return true;\n            }\n            else\n            {\n                return false;\n            }\n        }\n    }\n}"
  },
  {
    "path": "Il2CppDumper/Utils/PELoader.cs",
    "content": "﻿using System;\nusing System.ComponentModel;\nusing System.IO;\nusing System.Runtime.InteropServices;\nusing System.Text;\n\nnamespace Il2CppDumper\n{\n    public class PELoader\n    {\n        [DllImport(\"kernel32.dll\", SetLastError = true, CharSet = CharSet.Unicode)]\n        private extern static IntPtr LoadLibrary(string path);\n\n        public static PE Load(string fileName)\n        {\n            var buff = File.ReadAllBytes(fileName);\n            using var reader = new BinaryStream(new MemoryStream(buff));\n            var dosHeader = reader.ReadClass<DosHeader>();\n            if (dosHeader.Magic != 0x5A4D)\n            {\n                throw new InvalidDataException(\"ERROR: Invalid PE file\");\n            }\n            reader.Position = dosHeader.Lfanew;\n            if (reader.ReadUInt32() != 0x4550u) //Signature\n            {\n                throw new InvalidDataException(\"ERROR: Invalid PE file\");\n            }\n            var fileHeader = reader.ReadClass<FileHeader>();\n            if (fileHeader.Machine == 0x14c && Environment.Is64BitProcess) //64bit process can't load 32bit dll\n            {\n                throw new InvalidOperationException(\"The file is a 32-bit file, please try to load it with Il2CppDumper-x86.exe\");\n            }\n            if (fileHeader.Machine == 0x8664 && !Environment.Is64BitProcess) //32bit process can't load 64bit dll\n            {\n                throw new InvalidOperationException(\"The file is a 64-bit file, please try to load it with Il2CppDumper.exe\");\n            }\n            var pos = reader.Position;\n            reader.Position = pos + fileHeader.SizeOfOptionalHeader;\n            var sections = reader.ReadClassArray<SectionHeader>(fileHeader.NumberOfSections);\n            var last = sections[^1];\n            var size = last.VirtualAddress + last.VirtualSize;\n            var peBuff = new byte[size];\n            var handle = LoadLibrary(fileName);\n            if (handle == IntPtr.Zero)\n            {\n                throw new Win32Exception(Marshal.GetLastWin32Error());\n            }\n            foreach (var section in sections)\n            {\n                switch (section.Characteristics)\n                {\n                    case 0x60000020:\n                    case 0x40000040:\n                    case 0xC0000040:\n                        Marshal.Copy(new IntPtr(handle.ToInt64() + section.VirtualAddress), peBuff, (int)section.VirtualAddress, (int)section.VirtualSize);\n                        break;\n                }\n            }\n            var peMemory = new MemoryStream(peBuff);\n            var writer = new BinaryWriter(peMemory, Encoding.UTF8, true);\n            var headerSize = reader.Position;\n            reader.Position = 0;\n            var buff2 = reader.ReadBytes((int)headerSize);\n            writer.Write(buff2);\n            writer.Flush();\n            writer.Close();\n            peMemory.Position = 0;\n            var pe = new PE(peMemory);\n            pe.LoadFromMemory((ulong)handle.ToInt64());\n            return pe;\n        }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Utils/SearchSection.cs",
    "content": "﻿namespace Il2CppDumper\n{\n    public enum SearchSectionType\n    {\n        Exec,\n        Data,\n        Bss\n    }\n\n    public class SearchSection\n    {\n        public ulong offset;\n        public ulong offsetEnd;\n        public ulong address;\n        public ulong addressEnd;\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/Utils/SectionHelper.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Il2CppDumper\n{\n    public class SectionHelper\n    {\n        private List<SearchSection> exec;\n        private List<SearchSection> data;\n        private List<SearchSection> bss;\n        private readonly Il2Cpp il2Cpp;\n        private readonly int methodCount;\n        private readonly int typeDefinitionsCount;\n        private readonly long metadataUsagesCount;\n        private readonly int imageCount;\n        private bool pointerInExec;\n\n        public List<SearchSection> Exec => exec;\n        public List<SearchSection> Data => data;\n        public List<SearchSection> Bss => bss;\n\n        public SectionHelper(Il2Cpp il2Cpp, int methodCount, int typeDefinitionsCount, long metadataUsagesCount, int imageCount)\n        {\n            this.il2Cpp = il2Cpp;\n            this.methodCount = methodCount;\n            this.typeDefinitionsCount = typeDefinitionsCount;\n            this.metadataUsagesCount = metadataUsagesCount;\n            this.imageCount = imageCount;\n        }\n\n        public void SetSection(SearchSectionType type, Elf32_Phdr[] sections)\n        {\n            var secs = new List<SearchSection>();\n            foreach (var section in sections)\n            {\n                if (section != null)\n                {\n                    secs.Add(new SearchSection\n                    {\n                        offset = section.p_offset,\n                        offsetEnd = section.p_offset + section.p_filesz,\n                        address = section.p_vaddr,\n                        addressEnd = section.p_vaddr + section.p_memsz\n                    });\n                }\n            }\n            SetSection(type, secs);\n        }\n\n        public void SetSection(SearchSectionType type, Elf64_Phdr[] sections)\n        {\n            var secs = new List<SearchSection>();\n            foreach (var section in sections)\n            {\n                if (section != null)\n                {\n                    secs.Add(new SearchSection\n                    {\n                        offset = section.p_offset,\n                        offsetEnd = section.p_offset + section.p_filesz,\n                        address = section.p_vaddr,\n                        addressEnd = section.p_vaddr + section.p_memsz\n                    });\n                }\n            }\n            SetSection(type, secs);\n        }\n\n        public void SetSection(SearchSectionType type, MachoSection[] sections)\n        {\n            var secs = new List<SearchSection>();\n            foreach (var section in sections)\n            {\n                if (section != null)\n                {\n                    secs.Add(new SearchSection\n                    {\n                        offset = section.offset,\n                        offsetEnd = section.offset + section.size,\n                        address = section.addr,\n                        addressEnd = section.addr + section.size\n                    });\n                }\n            }\n            SetSection(type, secs);\n        }\n\n        public void SetSection(SearchSectionType type, MachoSection64Bit[] sections)\n        {\n            var secs = new List<SearchSection>();\n            foreach (var section in sections)\n            {\n                if (section != null)\n                {\n                    secs.Add(new SearchSection\n                    {\n                        offset = section.offset,\n                        offsetEnd = section.offset + section.size,\n                        address = section.addr,\n                        addressEnd = section.addr + section.size\n                    });\n                }\n            }\n            SetSection(type, secs);\n        }\n\n        public void SetSection(SearchSectionType type, ulong imageBase, SectionHeader[] sections)\n        {\n            var secs = new List<SearchSection>();\n            foreach (var section in sections)\n            {\n                if (section != null)\n                {\n                    secs.Add(new SearchSection\n                    {\n                        offset = section.PointerToRawData,\n                        offsetEnd = section.PointerToRawData + section.SizeOfRawData,\n                        address = section.VirtualAddress + imageBase,\n                        addressEnd = section.VirtualAddress + section.VirtualSize + imageBase\n                    });\n                }\n            }\n            SetSection(type, secs);\n        }\n\n        public void SetSection(SearchSectionType type, params NSOSegmentHeader[] sections)\n        {\n            var secs = new List<SearchSection>();\n            foreach (var section in sections)\n            {\n                if (section != null)\n                {\n                    secs.Add(new SearchSection\n                    {\n                        offset = section.FileOffset,\n                        offsetEnd = section.FileOffset + section.DecompressedSize,\n                        address = section.MemoryOffset,\n                        addressEnd = section.MemoryOffset + section.DecompressedSize\n                    });\n                }\n            }\n            SetSection(type, secs);\n        }\n\n        public void SetSection(SearchSectionType type, params SearchSection[] secs)\n        {\n            SetSection(type, secs.ToList());\n        }\n\n        private void SetSection(SearchSectionType type, List<SearchSection> secs)\n        {\n            switch (type)\n            {\n                case SearchSectionType.Exec:\n                    exec = secs;\n                    break;\n                case SearchSectionType.Data:\n                    data = secs;\n                    break;\n                case SearchSectionType.Bss:\n                    bss = secs;\n                    break;\n            }\n        }\n\n        public ulong FindCodeRegistration()\n        {\n            if (il2Cpp.Version >= 24.2)\n            {\n                ulong codeRegistration;\n                if (il2Cpp is ElfBase)\n                {\n                    codeRegistration = FindCodeRegistrationExec();\n                    if (codeRegistration == 0)\n                    {\n                        codeRegistration = FindCodeRegistrationData();\n                    }\n                    else\n                    {\n                        pointerInExec = true;\n                    }\n                }\n                else\n                {\n                    codeRegistration = FindCodeRegistrationData();\n                    if (codeRegistration == 0)\n                    {\n                        codeRegistration = FindCodeRegistrationExec();\n                        pointerInExec = true;\n                    }\n                }\n                return codeRegistration;\n            }\n            return FindCodeRegistrationOld();\n        }\n\n        public ulong FindMetadataRegistration()\n        {\n            if (il2Cpp.Version < 19)\n            {\n                return 0;\n            }\n            if (il2Cpp.Version >= 27)\n            {\n                return FindMetadataRegistrationV21();\n            }\n            return FindMetadataRegistrationOld();\n        }\n\n        private ulong FindCodeRegistrationOld()\n        {\n            foreach (var section in data)\n            {\n                il2Cpp.Position = section.offset;\n                while (il2Cpp.Position < section.offsetEnd)\n                {\n                    var addr = il2Cpp.Position;\n                    if (il2Cpp.ReadIntPtr() == methodCount)\n                    {\n                        try\n                        {\n                            var pointer = il2Cpp.MapVATR(il2Cpp.ReadUIntPtr());\n                            if (CheckPointerRangeDataRa(pointer))\n                            {\n                                var pointers = il2Cpp.ReadClassArray<ulong>(pointer, methodCount);\n                                if (CheckPointerRangeExecVa(pointers))\n                                {\n                                    return addr - section.offset + section.address;\n                                }\n                            }\n                        }\n                        catch\n                        {\n                            // ignored\n                        }\n                    }\n                    il2Cpp.Position = addr + il2Cpp.PointerSize;\n                }\n            }\n\n            return 0ul;\n        }\n\n        private ulong FindMetadataRegistrationOld()\n        {\n            foreach (var section in data)\n            {\n                il2Cpp.Position = section.offset;\n                var end = Math.Min(section.offsetEnd, il2Cpp.Length) - il2Cpp.PointerSize;\n                while (il2Cpp.Position < end)\n                {\n                    var addr = il2Cpp.Position;\n                    if (il2Cpp.ReadIntPtr() == typeDefinitionsCount)\n                    {\n                        try\n                        {\n                            il2Cpp.Position += il2Cpp.PointerSize * 2;\n                            var pointer = il2Cpp.MapVATR(il2Cpp.ReadUIntPtr());\n                            if (CheckPointerRangeDataRa(pointer))\n                            {\n                                var pointers = il2Cpp.ReadClassArray<ulong>(pointer, metadataUsagesCount);\n                                if (CheckPointerRangeBssVa(pointers))\n                                {\n                                    return addr - il2Cpp.PointerSize * 12 - section.offset + section.address;\n                                }\n                            }\n                        }\n                        catch\n                        {\n                            // ignored\n                        }\n                    }\n                    il2Cpp.Position = addr + il2Cpp.PointerSize;\n                }\n            }\n\n            return 0ul;\n        }\n\n        private ulong FindMetadataRegistrationV21()\n        {\n            foreach (var section in data)\n            {\n                il2Cpp.Position = section.offset;\n                var end = Math.Min(section.offsetEnd, il2Cpp.Length) - il2Cpp.PointerSize;\n                while (il2Cpp.Position < end)\n                {\n                    var addr = il2Cpp.Position;\n                    if (il2Cpp.ReadIntPtr() == typeDefinitionsCount)\n                    {\n                        il2Cpp.Position += il2Cpp.PointerSize;\n                        if (il2Cpp.ReadIntPtr() == typeDefinitionsCount)\n                        {\n                            try\n                            {\n                                var pointer = il2Cpp.MapVATR(il2Cpp.ReadUIntPtr());\n                                if (CheckPointerRangeDataRa(pointer))\n                                {\n                                    var pointers = il2Cpp.ReadClassArray<ulong>(pointer, typeDefinitionsCount);\n                                    bool flag;\n                                    if (pointerInExec)\n                                    {\n                                        flag = CheckPointerRangeExecVa(pointers);\n                                    }\n                                    else\n                                    {\n                                        flag = CheckPointerRangeDataVa(pointers);\n                                    }\n                                    if (flag)\n                                    {\n                                        return addr - il2Cpp.PointerSize * 10 - section.offset + section.address;\n                                    }\n                                }\n                            }\n                            catch\n                            {\n                                // ignored\n                            }\n                        }\n                    }\n                    il2Cpp.Position = addr + il2Cpp.PointerSize;\n                }\n            }\n\n            return 0ul;\n        }\n\n        private bool CheckPointerRangeDataRa(ulong pointer)\n        {\n            return data.Any(x => pointer >= x.offset && pointer <= x.offsetEnd);\n        }\n\n        private bool CheckPointerRangeExecVa(ulong[] pointers)\n        {\n            return pointers.All(x => exec.Any(y => x >= y.address && x <= y.addressEnd));\n        }\n\n        private bool CheckPointerRangeDataVa(ulong[] pointers)\n        {\n            return pointers.All(x => data.Any(y => x >= y.address && x <= y.addressEnd));\n        }\n\n        private bool CheckPointerRangeBssVa(ulong[] pointers)\n        {\n            return pointers.All(x => bss.Any(y => x >= y.address && x <= y.addressEnd));\n        }\n\n        private static readonly byte[] featureBytes = { 0x6D, 0x73, 0x63, 0x6F, 0x72, 0x6C, 0x69, 0x62, 0x2E, 0x64, 0x6C, 0x6C, 0x00 }; //mscorlib.dll\n\n        private ulong FindCodeRegistrationData()\n        {\n            return FindCodeRegistration2019(data);\n        }\n\n        private ulong FindCodeRegistrationExec()\n        {\n            return FindCodeRegistration2019(exec);\n        }\n\n        private ulong FindCodeRegistration2019(List<SearchSection> secs)\n        {\n            foreach (var sec in secs)\n            {\n                il2Cpp.Position = sec.offset;\n                var buff = il2Cpp.ReadBytes((int)(sec.offsetEnd - sec.offset));\n                foreach (var index in buff.Search(featureBytes))\n                {\n                    var dllva = (ulong)index + sec.address;\n                    foreach (var refva in FindReference(dllva))\n                    {\n                        foreach (var refva2 in FindReference(refva))\n                        {\n                            if (il2Cpp.Version >= 27)\n                            {\n                                for (int i = imageCount - 1; i >= 0; i--)\n                                {\n                                    foreach (var refva3 in FindReference(refva2 - (ulong)i * il2Cpp.PointerSize))\n                                    {\n                                        il2Cpp.Position = il2Cpp.MapVATR(refva3 - il2Cpp.PointerSize);\n                                        if (il2Cpp.ReadIntPtr() == imageCount)\n                                        {\n                                            if (il2Cpp.Version >= 29)\n                                            {\n                                                return refva3 - il2Cpp.PointerSize * 14;\n                                            }\n                                            return refva3 - il2Cpp.PointerSize * 13;\n                                        }\n                                    }\n                                }\n                            }\n                            else\n                            {\n                                for (int i = 0; i < imageCount; i++)\n                                {\n                                    foreach (var refva3 in FindReference(refva2 - (ulong)i * il2Cpp.PointerSize))\n                                    {\n                                        return refva3 - il2Cpp.PointerSize * 13;\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n            return 0ul;\n        }\n\n        private IEnumerable<ulong> FindReference(ulong addr)\n        {\n            foreach (var dataSec in data)\n            {\n                var position = dataSec.offset;\n                var end = Math.Min(dataSec.offsetEnd, il2Cpp.Length) - il2Cpp.PointerSize;\n                while (position < end)\n                {\n                    il2Cpp.Position = position;\n                    if (il2Cpp.ReadUIntPtr() == addr)\n                    {\n                        yield return position - dataSec.offset + dataSec.address;\n                    }\n                    position += il2Cpp.PointerSize;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Il2CppDumper/config.json",
    "content": "{\n  \"DumpMethod\": true,\n  \"DumpField\": true,\n  \"DumpProperty\": true,\n  \"DumpAttribute\": true,\n  \"DumpFieldOffset\": true,\n  \"DumpMethodOffset\": true,\n  \"DumpTypeDefIndex\": true,\n  \"GenerateDummyDll\": true,\n  \"GenerateStruct\": true,\n  \"DummyDllAddToken\": true,\n  \"RequireAnyKey\": true,\n  \"ForceIl2CppVersion\": false,\n  \"ForceVersion\": 16,\n  \"ForceDump\": false,\n  \"NoRedirectedPointer\": false\n}"
  },
  {
    "path": "Il2CppDumper/ghidra.py",
    "content": "# -*- coding: utf-8 -*-\nimport json\n\nprocessFields = [\n\t\"ScriptMethod\",\n\t\"ScriptString\",\n\t\"ScriptMetadata\",\n\t\"ScriptMetadataMethod\",\n\t\"Addresses\",\n]\n\nfunctionManager = currentProgram.getFunctionManager()\nbaseAddress = currentProgram.getImageBase()\nUSER_DEFINED = ghidra.program.model.symbol.SourceType.USER_DEFINED\n\ndef get_addr(addr):\n\treturn baseAddress.add(addr)\n\ndef set_name(addr, name):\n\tname = name.replace(' ', '-')\n\tcreateLabel(addr, name, True, USER_DEFINED)\n\ndef make_function(start):\n\tfunc = getFunctionAt(start)\n\tif func is None:\n\t\tcreateFunction(start, None)\n\nf = askFile(\"script.json from Il2cppdumper\", \"Open\")\ndata = json.loads(open(f.absolutePath, 'rb').read().decode('utf-8'))\n\nif \"ScriptMethod\" in data and \"ScriptMethod\" in processFields:\n\tscriptMethods = data[\"ScriptMethod\"]\n\tmonitor.initialize(len(scriptMethods))\n\tmonitor.setMessage(\"Methods\")\n\tfor scriptMethod in scriptMethods:\n\t\taddr = get_addr(scriptMethod[\"Address\"])\n\t\tname = scriptMethod[\"Name\"].encode(\"utf-8\")\n\t\tset_name(addr, name)\n\t\tmonitor.incrementProgress(1)\n\nif \"ScriptString\" in data and \"ScriptString\" in processFields:\n\tindex = 1\n\tscriptStrings = data[\"ScriptString\"]\n\tmonitor.initialize(len(scriptStrings))\n\tmonitor.setMessage(\"Strings\")\n\tfor scriptString in scriptStrings:\n\t\taddr = get_addr(scriptString[\"Address\"])\n\t\tvalue = scriptString[\"Value\"].encode(\"utf-8\")\n\t\tname = \"StringLiteral_\" + str(index)\n\t\tcreateLabel(addr, name, True, USER_DEFINED)\n\t\tsetEOLComment(addr, value)\n\t\tindex += 1\n\t\tmonitor.incrementProgress(1)\n\nif \"ScriptMetadata\" in data and \"ScriptMetadata\" in processFields:\n\tscriptMetadatas = data[\"ScriptMetadata\"]\n\tmonitor.initialize(len(scriptMetadatas))\n\tmonitor.setMessage(\"Metadata\")\n\tfor scriptMetadata in scriptMetadatas:\n\t\taddr = get_addr(scriptMetadata[\"Address\"])\n\t\tname = scriptMetadata[\"Name\"].encode(\"utf-8\")\n\t\tset_name(addr, name)\n\t\tsetEOLComment(addr, name)\n\t\tmonitor.incrementProgress(1)\n\nif \"ScriptMetadataMethod\" in data and \"ScriptMetadataMethod\" in processFields:\n\tscriptMetadataMethods = data[\"ScriptMetadataMethod\"]\n\tmonitor.initialize(len(scriptMetadataMethods))\n\tmonitor.setMessage(\"Metadata Methods\")\n\tfor scriptMetadataMethod in scriptMetadataMethods:\n\t\taddr = get_addr(scriptMetadataMethod[\"Address\"])\n\t\tname = scriptMetadataMethod[\"Name\"].encode(\"utf-8\")\n\t\tmethodAddr = get_addr(scriptMetadataMethod[\"MethodAddress\"])\n\t\tset_name(addr, name)\n\t\tsetEOLComment(addr, name)\n\t\tmonitor.incrementProgress(1)\n\nif \"Addresses\" in data and \"Addresses\" in processFields:\n\taddresses = data[\"Addresses\"]\n\tmonitor.initialize(len(addresses))\n\tmonitor.setMessage(\"Addresses\")\n\tfor index in range(len(addresses) - 1):\n\t\tstart = get_addr(addresses[index])\n\t\tmake_function(start)\n\t\tmonitor.incrementProgress(1)\n\nprint 'Script finished!'\n"
  },
  {
    "path": "Il2CppDumper/ghidra_wasm.py",
    "content": "# -*- coding: utf-8 -*-\nimport json\n\nfrom wasm import WasmLoader\nfrom wasm.analysis import WasmAnalysis\nfrom ghidra.util.task import ConsoleTaskMonitor\n\nmonitor = ConsoleTaskMonitor()\nWasmLoader.loadElementsToTable(currentProgram, WasmAnalysis.getState(currentProgram).module, 0, 0, 0, monitor)\n\nrunScript(\"analyze_dyncalls.py\")\n\nprocessFields = [\n\t\"ScriptMethod\",\n\t\"ScriptString\",\n\t\"ScriptMetadata\",\n\t\"ScriptMetadataMethod\",\n\t\"Addresses\",\n]\n\nfunctionManager = currentProgram.getFunctionManager()\nprogspace = currentProgram.addressFactory.getAddressSpace(\"ram\")\nUSER_DEFINED = ghidra.program.model.symbol.SourceType.USER_DEFINED\n\ndef get_addr(addr):\n\treturn progspace.getAddress(addr)\n\ndef set_name(addr, name):\n\tname = name.replace(' ', '-')\n\tcreateLabel(addr, name, True, USER_DEFINED)\n\ndef make_function(start):\n\tfunc = getFunctionAt(start)\n\tif func is None:\n\t\tcreateFunction(start, None)\n\nf = askFile(\"script.json from Il2cppdumper\", \"Open\")\ndata = json.loads(open(f.absolutePath, 'rb').read().decode('utf-8'))\n\n\nif \"ScriptMethod\" in data and \"ScriptMethod\" in processFields:\n\tscriptMethods = data[\"ScriptMethod\"]\n\tdynCallNamespace =  currentProgram.symbolTable.getNamespace(\"dynCall\", None)\n\tmonitor.initialize(len(scriptMethods))\n\tmonitor.setMessage(\"Methods\")\n\tfor scriptMethod in scriptMethods:\n\t\toffset = scriptMethod[\"Address\"]\n\t\tsig = scriptMethod[\"TypeSignature\"]\n\t\tsymbolName = \"func_%s_%d\" % (sig, offset)\n\t\tsymbol = currentProgram.symbolTable.getSymbols(symbolName, dynCallNamespace)\n\t\tif len(symbol) > 0:\n\t\t\taddr = symbol[0].address\n\t\t\tname = scriptMethod[\"Name\"].encode(\"utf-8\")\n\t\t\tset_name(addr, name)\n\t\telse:\n\t\t\tprint \"Warning at %s:\" % scriptMethod[\"Name\"]\n\t\t\tprint \"Symbol %s not found!\" % symbolName\n\t\tmonitor.incrementProgress(1)\n\nif \"ScriptString\" in data and \"ScriptString\" in processFields:\n\tindex = 1\n\tscriptStrings = data[\"ScriptString\"]\n\tmonitor.initialize(len(scriptStrings))\n\tmonitor.setMessage(\"Strings\")\n\tfor scriptString in scriptStrings:\n\t\taddr = get_addr(scriptString[\"Address\"])\n\t\tvalue = scriptString[\"Value\"].encode(\"utf-8\")\n\t\tname = \"StringLiteral_\" + str(index)\n\t\tcreateLabel(addr, name, True, USER_DEFINED)\n\t\tsetEOLComment(addr, value)\n\t\tindex += 1\n\t\tmonitor.incrementProgress(1)\n\nif \"ScriptMetadata\" in data and \"ScriptMetadata\" in processFields:\n\tscriptMetadatas = data[\"ScriptMetadata\"]\n\tmonitor.initialize(len(scriptMetadatas))\n\tmonitor.setMessage(\"Metadata\")\n\tfor scriptMetadata in scriptMetadatas:\n\t\taddr = get_addr(scriptMetadata[\"Address\"])\n\t\tname = scriptMetadata[\"Name\"].encode(\"utf-8\")\n\t\tset_name(addr, name)\n\t\tsetEOLComment(addr, name)\n\t\tmonitor.incrementProgress(1)\n\nif \"ScriptMetadataMethod\" in data and \"ScriptMetadataMethod\" in processFields:\n\tscriptMetadataMethods = data[\"ScriptMetadataMethod\"]\n\tmonitor.initialize(len(scriptMetadataMethods))\n\tmonitor.setMessage(\"Metadata Methods\")\n\tfor scriptMetadataMethod in scriptMetadataMethods:\n\t\taddr = get_addr(scriptMetadataMethod[\"Address\"])\n\t\tname = scriptMetadataMethod[\"Name\"].encode(\"utf-8\")\n\t\tmethodAddr = get_addr(scriptMetadataMethod[\"MethodAddress\"])\n\t\tset_name(addr, name)\n\t\tsetEOLComment(addr, name)\n\t\tmonitor.incrementProgress(1)\n\nif \"Addresses\" in data and \"Addresses\" in processFields:\n\tpass\n\nprint 'Script finished!'\n"
  },
  {
    "path": "Il2CppDumper/ghidra_with_struct.py",
    "content": "# -*- coding: utf-8 -*-\nimport json\n\nfrom ghidra.app.util.cparser.C import CParserUtils\nfrom ghidra.app.cmd.function import ApplyFunctionSignatureCmd\n\nprocessFields = [\n\t\"ScriptMethod\",\n\t\"ScriptString\",\n\t\"ScriptMetadata\",\n\t\"ScriptMetadataMethod\",\n\t\"Addresses\",\n]\n\nfunctionManager = currentProgram.getFunctionManager()\nbaseAddress = currentProgram.getImageBase()\nUSER_DEFINED = ghidra.program.model.symbol.SourceType.USER_DEFINED\n\ndef get_addr(addr):\n\treturn baseAddress.add(addr)\n\ndef set_name(addr, name):\n    try:\n        name = name.replace(' ', '-')\n        createLabel(addr, name, True, USER_DEFINED)\n    except:\n        print(\"set_name() Failed.\")\n\ndef set_type(addr, type):\n\t# Requires types (il2cpp.h) to be imported first\n\tnewType = type.replace(\"*\",\" *\").replace(\"  \",\" \").strip()\n\tdataTypes = getDataTypes(newType)\n\taddrType = None\n\tif len(dataTypes) == 0:\n\t\tif newType == newType[:-2] + \" *\":\n\t\t\tbaseType = newType[:-2]\n\t\t\tdataTypes = getDataTypes(baseType)\n\t\t\tif len(dataTypes) == 1:\n\t\t\t\tdtm = currentProgram.getDataTypeManager()\n\t\t\t\tpointerType = dtm.getPointer(dataTypes[0])\n\t\t\t\taddrType = dtm.addDataType(pointerType, None)\n\telif len(dataTypes) > 1:\n\t\tprint(\"Conflicting data types found for type \" + type + \"(parsed as '\" + newType + \"')\")\n\t\treturn\n\telse:\n\t\taddrType = dataTypes[0]\n\tif addrType is None:\n\t\tprint(\"Could not identify type \" + type + \"(parsed as '\" + newType + \"')\")\n\telse:\n\t    try:\n\t        createData(addr, addrType)\n\t    except ghidra.program.model.util.CodeUnitInsertionException:\n\t        print(\"Warning: unable to set type (CodeUnitInsertionException)\")\n\t    \n\ndef make_function(start):\n\tfunc = getFunctionAt(start)\n\tif func is None:\n\t\ttry:\n\t\t\tcreateFunction(start, None)\n\t\texcept:\n\t\t\tprint(\"Warning: Unable to create function\")\n\ndef set_sig(addr, name, sig):\n\ttry: \n\t\ttypeSig = CParserUtils.parseSignature(None, currentProgram, sig, False)\n\texcept ghidra.app.util.cparser.C.ParseException:\n\t\tprint(\"Warning: Unable to parse\")\n\t\tprint(sig)\n\t\tprint(\"Attempting to modify...\")\n\t\t# try to fix by renaming the parameters\n\t\ttry:\n\t\t\tnewSig = sig.replace(\", \",\"ext, \").replace(\"\\)\",\"ext\\)\")\n\t\t\ttypeSig = CParserUtils.parseSignature(None, currentProgram, newSig, False)\n\t\texcept:\n\t\t\tprint(\"Warning: also unable to parse\")\n\t\t\tprint(newSig)\n\t\t\tprint(\"Skipping.\")\n\t\t\treturn\n\tif typeSig is not None:\n\t\ttry:\n            \t\ttypeSig.setName(name)\n            \t\tApplyFunctionSignatureCmd(addr, typeSig, USER_DEFINED, False, True).applyTo(currentProgram)\n\t\texcept:\n\t\t\tprint(\"Warning: unable to set Signature. ApplyFunctionSignatureCmd() Failed.\")\n\nf = askFile(\"script.json from Il2cppdumper\", \"Open\")\ndata = json.loads(open(f.absolutePath, 'rb').read().decode('utf-8'))\n\nif \"ScriptMethod\" in data and \"ScriptMethod\" in processFields:\n\tscriptMethods = data[\"ScriptMethod\"]\n\tmonitor.initialize(len(scriptMethods))\n\tmonitor.setMessage(\"Methods\")\n\tfor scriptMethod in scriptMethods:\n\t\taddr = get_addr(scriptMethod[\"Address\"])\n\t\tname = scriptMethod[\"Name\"].encode(\"utf-8\")\n\t\tset_name(addr, name)\n\t\tmonitor.incrementProgress(1)\n\nif \"ScriptString\" in data and \"ScriptString\" in processFields:\n\tindex = 1\n\tscriptStrings = data[\"ScriptString\"]\n\tmonitor.initialize(len(scriptStrings))\n\tmonitor.setMessage(\"Strings\")\n\tfor scriptString in scriptStrings:\n\t\taddr = get_addr(scriptString[\"Address\"])\n\t\tvalue = scriptString[\"Value\"].encode(\"utf-8\")\n\t\tname = \"StringLiteral_\" + str(index)\n\t\tcreateLabel(addr, name, True, USER_DEFINED)\n\t\tsetEOLComment(addr, value)\n\t\tindex += 1\n\t\tmonitor.incrementProgress(1)\n\nif \"ScriptMetadata\" in data and \"ScriptMetadata\" in processFields:\n\tscriptMetadatas = data[\"ScriptMetadata\"]\n\tmonitor.initialize(len(scriptMetadatas))\n\tmonitor.setMessage(\"Metadata\")\n\tfor scriptMetadata in scriptMetadatas:\n\t\taddr = get_addr(scriptMetadata[\"Address\"])\n\t\tname = scriptMetadata[\"Name\"].encode(\"utf-8\")\n\t\tset_name(addr, name)\n\t\tsetEOLComment(addr, name)\n\t\tmonitor.incrementProgress(1)\n\t\tif scriptMetadata[\"Signature\"]:\n\t\t\tset_type(addr, scriptMetadata[\"Signature\"].encode(\"utf-8\"))\n\nif \"ScriptMetadataMethod\" in data and \"ScriptMetadataMethod\" in processFields:\n\tscriptMetadataMethods = data[\"ScriptMetadataMethod\"]\n\tmonitor.initialize(len(scriptMetadataMethods))\n\tmonitor.setMessage(\"Metadata Methods\")\n\tfor scriptMetadataMethod in scriptMetadataMethods:\n\t\taddr = get_addr(scriptMetadataMethod[\"Address\"])\n\t\tname = scriptMetadataMethod[\"Name\"].encode(\"utf-8\")\n\t\tmethodAddr = get_addr(scriptMetadataMethod[\"MethodAddress\"])\n\t\tset_name(addr, name)\n\t\tsetEOLComment(addr, name)\n\t\tmonitor.incrementProgress(1)\n\nif \"Addresses\" in data and \"Addresses\" in processFields:\n\taddresses = data[\"Addresses\"]\n\tmonitor.initialize(len(addresses))\n\tmonitor.setMessage(\"Addresses\")\n\tfor index in range(len(addresses) - 1):\n\t\tstart = get_addr(addresses[index])\n\t\tmake_function(start)\n\t\tmonitor.incrementProgress(1)\n\nif \"ScriptMethod\" in data and \"ScriptMethod\" in processFields:\n\tscriptMethods = data[\"ScriptMethod\"]\n\tfor scriptMethod in scriptMethods:\n\t\taddr = get_addr(scriptMethod[\"Address\"])\n\t\tsig = scriptMethod[\"Signature\"][:-1].encode(\"utf-8\")\n\t\tname = scriptMethod[\"Name\"].encode(\"utf-8\")\n\t\tset_sig(addr, name, sig)\n\nprint 'Script finished!'\n"
  },
  {
    "path": "Il2CppDumper/hopper-py3.py",
    "content": "import codecs\nimport json\n\ndef deserializeJSON(script_file):\n    if script_file is not None:\n        f = codecs.open(script_file, \"r\",\"utf-8\")\n\n        # Reading from file\n        data = json.loads(f.read())\n        f.close()\n\n        return data\n\ndef changeAddressNames(script):\n    for i in script['ScriptMethod']:\n        addr = i['Address']\n        name = i['Name']\n        #sig = i['Signature']\n        #typesig = i['TypeSignature']\n\n        #print(addr, name)\n        doc.setNameAtAddress(addr, name)\n\n    return\n\ndef main():\n    script_file = doc.askFile('Select script.py', None, None)\n    script = deserializeJSON(script_file)\n    changeAddressNames(script)\n\ndoc = Document.getCurrentDocument()\nmain()\n"
  },
  {
    "path": "Il2CppDumper/ida.py",
    "content": "# -*- coding: utf-8 -*-\nimport json\n\nprocessFields = [\n\t\"ScriptMethod\",\n\t\"ScriptString\",\n\t\"ScriptMetadata\",\n\t\"ScriptMetadataMethod\",\n\t\"Addresses\",\n]\n\nimageBase = idaapi.get_imagebase()\n\ndef get_addr(addr):\n\treturn imageBase + addr\n\ndef set_name(addr, name):\n\tret = idc.set_name(addr, name, SN_NOWARN | SN_NOCHECK)\n\tif ret == 0:\n\t\tnew_name = name + '_' + str(addr)\n\t\tret = idc.set_name(addr, new_name, SN_NOWARN | SN_NOCHECK)\n\ndef make_function(start, end):\n\tnext_func = idc.get_next_func(start)\n\tif next_func < end:\n\t\tend = next_func\n\tif idc.get_func_attr(start, FUNCATTR_START) == start:\n\t\tida_funcs.del_func(start)\n\tida_funcs.add_func(start, end)\n\npath = idaapi.ask_file(False, '*.json', 'script.json from Il2cppdumper')\ndata = json.loads(open(path, 'rb').read().decode('utf-8'))\n\nif \"Addresses\" in data and \"Addresses\" in processFields:\n\taddresses = data[\"Addresses\"]\n\tfor index in range(len(addresses) - 1):\n\t\tstart = get_addr(addresses[index])\n\t\tend = get_addr(addresses[index + 1])\n\t\tmake_function(start, end)\n\nif \"ScriptMethod\" in data and \"ScriptMethod\" in processFields:\n\tscriptMethods = data[\"ScriptMethod\"]\n\tfor scriptMethod in scriptMethods:\n\t\taddr = get_addr(scriptMethod[\"Address\"])\n\t\tname = scriptMethod[\"Name\"].encode(\"utf-8\")\n\t\tset_name(addr, name)\n\nif \"ScriptString\" in data and \"ScriptString\" in processFields:\n\tindex = 1\n\tscriptStrings = data[\"ScriptString\"]\n\tfor scriptString in scriptStrings:\n\t\taddr = get_addr(scriptString[\"Address\"])\n\t\tvalue = scriptString[\"Value\"].encode(\"utf-8\")\n\t\tname = \"StringLiteral_\" + str(index)\n\t\tidc.set_name(addr, name, SN_NOWARN)\n\t\tidc.set_cmt(addr, value, 1)\n\t\tindex += 1\n\nif \"ScriptMetadata\" in data and \"ScriptMetadata\" in processFields:\n\tscriptMetadatas = data[\"ScriptMetadata\"]\n\tfor scriptMetadata in scriptMetadatas:\n\t\taddr = get_addr(scriptMetadata[\"Address\"])\n\t\tname = scriptMetadata[\"Name\"].encode(\"utf-8\")\n\t\tset_name(addr, name)\n\t\tidc.set_cmt(addr, name, 1)\n\nif \"ScriptMetadataMethod\" in data and \"ScriptMetadataMethod\" in processFields:\n\tscriptMetadataMethods = data[\"ScriptMetadataMethod\"]\n\tfor scriptMetadataMethod in scriptMetadataMethods:\n\t\taddr = get_addr(scriptMetadataMethod[\"Address\"])\n\t\tname = scriptMetadataMethod[\"Name\"].encode(\"utf-8\")\n\t\tmethodAddr = get_addr(scriptMetadataMethod[\"MethodAddress\"])\n\t\tset_name(addr, name)\n\t\tidc.set_cmt(addr, name, 1)\n\t\tidc.set_cmt(addr, '{0:X}'.format(methodAddr), 0)\n\nprint 'Script finished!'\n\n"
  },
  {
    "path": "Il2CppDumper/ida_py3.py",
    "content": "# -*- coding: utf-8 -*-\nimport json\n\nprocessFields = [\n\t\"ScriptMethod\",\n\t\"ScriptString\",\n\t\"ScriptMetadata\",\n\t\"ScriptMetadataMethod\",\n\t\"Addresses\",\n]\n\nimageBase = idaapi.get_imagebase()\n\ndef get_addr(addr):\n\treturn imageBase + addr\n\ndef set_name(addr, name):\n\tret = idc.set_name(addr, name, SN_NOWARN | SN_NOCHECK)\n\tif ret == 0:\n\t\tnew_name = name + '_' + str(addr)\n\t\tret = idc.set_name(addr, new_name, SN_NOWARN | SN_NOCHECK)\n\ndef make_function(start, end):\n\tnext_func = idc.get_next_func(start)\n\tif next_func < end:\n\t\tend = next_func\n\tif idc.get_func_attr(start, FUNCATTR_START) == start:\n\t\tida_funcs.del_func(start)\n\tida_funcs.add_func(start, end)\n\npath = idaapi.ask_file(False, '*.json', 'script.json from Il2cppdumper')\ndata = json.loads(open(path, 'rb').read().decode('utf-8'))\n\nif \"Addresses\" in data and \"Addresses\" in processFields:\n\taddresses = data[\"Addresses\"]\n\tfor index in range(len(addresses) - 1):\n\t\tstart = get_addr(addresses[index])\n\t\tend = get_addr(addresses[index + 1])\n\t\tmake_function(start, end)\n\nif \"ScriptMethod\" in data and \"ScriptMethod\" in processFields:\n\tscriptMethods = data[\"ScriptMethod\"]\n\tfor scriptMethod in scriptMethods:\n\t\taddr = get_addr(scriptMethod[\"Address\"])\n\t\tname = scriptMethod[\"Name\"]\n\t\tset_name(addr, name)\n\nif \"ScriptString\" in data and \"ScriptString\" in processFields:\n\tindex = 1\n\tscriptStrings = data[\"ScriptString\"]\n\tfor scriptString in scriptStrings:\n\t\taddr = get_addr(scriptString[\"Address\"])\n\t\tvalue = scriptString[\"Value\"]\n\t\tname = \"StringLiteral_\" + str(index)\n\t\tidc.set_name(addr, name, SN_NOWARN)\n\t\tidc.set_cmt(addr, value, 1)\n\t\tindex += 1\n\nif \"ScriptMetadata\" in data and \"ScriptMetadata\" in processFields:\n\tscriptMetadatas = data[\"ScriptMetadata\"]\n\tfor scriptMetadata in scriptMetadatas:\n\t\taddr = get_addr(scriptMetadata[\"Address\"])\n\t\tname = scriptMetadata[\"Name\"]\n\t\tset_name(addr, name)\n\t\tidc.set_cmt(addr, name, 1)\n\nif \"ScriptMetadataMethod\" in data and \"ScriptMetadataMethod\" in processFields:\n\tscriptMetadataMethods = data[\"ScriptMetadataMethod\"]\n\tfor scriptMetadataMethod in scriptMetadataMethods:\n\t\taddr = get_addr(scriptMetadataMethod[\"Address\"])\n\t\tname = scriptMetadataMethod[\"Name\"]\n\t\tmethodAddr = get_addr(scriptMetadataMethod[\"MethodAddress\"])\n\t\tset_name(addr, name)\n\t\tidc.set_cmt(addr, name, 1)\n\t\tidc.set_cmt(addr, '{0:X}'.format(methodAddr), 0)\n\nprint('Script finished!')\n\n"
  },
  {
    "path": "Il2CppDumper/ida_with_struct.py",
    "content": "# -*- coding: utf-8 -*-\nimport json\n\nprocessFields = [\n\t\"ScriptMethod\",\n\t\"ScriptString\",\n\t\"ScriptMetadata\",\n\t\"ScriptMetadataMethod\",\n\t\"Addresses\",\n]\n\nimageBase = idaapi.get_imagebase()\n\ndef get_addr(addr):\n\treturn imageBase + addr\n\ndef set_name(addr, name):\n\tret = idc.set_name(addr, name, SN_NOWARN | SN_NOCHECK)\n\tif ret == 0:\n\t\tnew_name = name + '_' + str(addr)\n\t\tret = idc.set_name(addr, new_name, SN_NOWARN | SN_NOCHECK)\n\ndef make_function(start, end):\n\tnext_func = idc.get_next_func(start)\n\tif next_func < end:\n\t\tend = next_func\n\tif idc.get_func_attr(start, FUNCATTR_START) == start:\n\t\tida_funcs.del_func(start)\n\tida_funcs.add_func(start, end)\n\npath = idaapi.ask_file(False, '*.json', 'script.json from Il2cppdumper')\nhpath = idaapi.ask_file(False, '*.h', 'il2cpp.h from Il2cppdumper')\nparse_decls(open(hpath, 'rb').read(), 0)\ndata = json.loads(open(path, 'rb').read().decode('utf-8'))\n\nif \"Addresses\" in data and \"Addresses\" in processFields:\n\taddresses = data[\"Addresses\"]\n\tfor index in range(len(addresses) - 1):\n\t\tstart = get_addr(addresses[index])\n\t\tend = get_addr(addresses[index + 1])\n\t\tmake_function(start, end)\n\nif \"ScriptMethod\" in data and \"ScriptMethod\" in processFields:\n\tscriptMethods = data[\"ScriptMethod\"]\n\tfor scriptMethod in scriptMethods:\n\t\taddr = get_addr(scriptMethod[\"Address\"])\n\t\tname = scriptMethod[\"Name\"].encode(\"utf-8\")\n\t\tset_name(addr, name)\n\t\tsignature = scriptMethod[\"Signature\"].encode(\"utf-8\")\n\t\tif apply_type(addr, parse_decl(signature, 0), 1) == False:\n\t\t\tprint \"apply_type failed:\", hex(addr), signature\n\nif \"ScriptString\" in data and \"ScriptString\" in processFields:\n\tindex = 1\n\tscriptStrings = data[\"ScriptString\"]\n\tfor scriptString in scriptStrings:\n\t\taddr = get_addr(scriptString[\"Address\"])\n\t\tvalue = scriptString[\"Value\"].encode(\"utf-8\")\n\t\tname = \"StringLiteral_\" + str(index)\n\t\tidc.set_name(addr, name, SN_NOWARN)\n\t\tidc.set_cmt(addr, value, 1)\n\t\tindex += 1\n\nif \"ScriptMetadata\" in data and \"ScriptMetadata\" in processFields:\n\tscriptMetadatas = data[\"ScriptMetadata\"]\n\tfor scriptMetadata in scriptMetadatas:\n\t\taddr = get_addr(scriptMetadata[\"Address\"])\n\t\tname = scriptMetadata[\"Name\"].encode(\"utf-8\")\n\t\tset_name(addr, name)\n\t\tidc.set_cmt(addr, name, 1)\n\t\tif scriptMetadata[\"Signature\"] is not None:\n\t\t\tsignature = scriptMetadata[\"Signature\"].encode(\"utf-8\")\n\t\t\tif apply_type(addr, parse_decl(signature, 0), 1) == False:\n\t\t\t\tprint \"apply_type failed:\", hex(addr), signature\n\nif \"ScriptMetadataMethod\" in data and \"ScriptMetadataMethod\" in processFields:\n\tscriptMetadataMethods = data[\"ScriptMetadataMethod\"]\n\tfor scriptMetadataMethod in scriptMetadataMethods:\n\t\taddr = get_addr(scriptMetadataMethod[\"Address\"])\n\t\tname = scriptMetadataMethod[\"Name\"].encode(\"utf-8\")\n\t\tmethodAddr = get_addr(scriptMetadataMethod[\"MethodAddress\"])\n\t\tset_name(addr, name)\n\t\tidc.set_cmt(addr, name, 1)\n\t\tidc.set_cmt(addr, '{0:X}'.format(methodAddr), 0)\n\nprint 'Script finished!'\n\n"
  },
  {
    "path": "Il2CppDumper/ida_with_struct_py3.py",
    "content": "# -*- coding: utf-8 -*-\nimport json\n\nprocessFields = [\n\t\"ScriptMethod\",\n\t\"ScriptString\",\n\t\"ScriptMetadata\",\n\t\"ScriptMetadataMethod\",\n\t\"Addresses\",\n]\n\nimageBase = idaapi.get_imagebase()\n\ndef get_addr(addr):\n\treturn imageBase + addr\n\ndef set_name(addr, name):\n\tret = idc.set_name(addr, name, SN_NOWARN | SN_NOCHECK)\n\tif ret == 0:\n\t\tnew_name = name + '_' + str(addr)\n\t\tret = idc.set_name(addr, new_name, SN_NOWARN | SN_NOCHECK)\n\ndef make_function(start, end):\n\tnext_func = idc.get_next_func(start)\n\tif next_func < end:\n\t\tend = next_func\n\tif idc.get_func_attr(start, FUNCATTR_START) == start:\n\t\tida_funcs.del_func(start)\n\tida_funcs.add_func(start, end)\n\npath = idaapi.ask_file(False, '*.json', 'script.json from Il2cppdumper')\nhpath = idaapi.ask_file(False, '*.h', 'il2cpp.h from Il2cppdumper')\nparse_decls(open(hpath, 'r').read(), 0)\ndata = json.loads(open(path, 'rb').read().decode('utf-8'))\n\nif \"Addresses\" in data and \"Addresses\" in processFields:\n\taddresses = data[\"Addresses\"]\n\tfor index in range(len(addresses) - 1):\n\t\tstart = get_addr(addresses[index])\n\t\tend = get_addr(addresses[index + 1])\n\t\tmake_function(start, end)\n\nif \"ScriptMethod\" in data and \"ScriptMethod\" in processFields:\n\tscriptMethods = data[\"ScriptMethod\"]\n\tfor scriptMethod in scriptMethods:\n\t\taddr = get_addr(scriptMethod[\"Address\"])\n\t\tname = scriptMethod[\"Name\"]\n\t\tset_name(addr, name)\n\t\tsignature = scriptMethod[\"Signature\"]\n\t\tif apply_type(addr, parse_decl(signature, 0), 1) == False:\n\t\t\tprint(\"apply_type failed:\", hex(addr), signature)\n\nif \"ScriptString\" in data and \"ScriptString\" in processFields:\n\tindex = 1\n\tscriptStrings = data[\"ScriptString\"]\n\tfor scriptString in scriptStrings:\n\t\taddr = get_addr(scriptString[\"Address\"])\n\t\tvalue = scriptString[\"Value\"]\n\t\tname = \"StringLiteral_\" + str(index)\n\t\tidc.set_name(addr, name, SN_NOWARN)\n\t\tidc.set_cmt(addr, value, 1)\n\t\tindex += 1\n\nif \"ScriptMetadata\" in data and \"ScriptMetadata\" in processFields:\n\tscriptMetadatas = data[\"ScriptMetadata\"]\n\tfor scriptMetadata in scriptMetadatas:\n\t\taddr = get_addr(scriptMetadata[\"Address\"])\n\t\tname = scriptMetadata[\"Name\"]\n\t\tset_name(addr, name)\n\t\tidc.set_cmt(addr, name, 1)\n\t\tif scriptMetadata[\"Signature\"] is not None:\n\t\t\tsignature = scriptMetadata[\"Signature\"]\n\t\t\tif apply_type(addr, parse_decl(signature, 0), 1) == False:\n\t\t\t\tprint(\"apply_type failed:\", hex(addr), signature)\n\nif \"ScriptMetadataMethod\" in data and \"ScriptMetadataMethod\" in processFields:\n\tscriptMetadataMethods = data[\"ScriptMetadataMethod\"]\n\tfor scriptMetadataMethod in scriptMetadataMethods:\n\t\taddr = get_addr(scriptMetadataMethod[\"Address\"])\n\t\tname = scriptMetadataMethod[\"Name\"]\n\t\tmethodAddr = get_addr(scriptMetadataMethod[\"MethodAddress\"])\n\t\tset_name(addr, name)\n\t\tidc.set_cmt(addr, name, 1)\n\t\tidc.set_cmt(addr, '{0:X}'.format(methodAddr), 0)\n\nprint('Script finished!')\n\n"
  },
  {
    "path": "Il2CppDumper/il2cpp_header_to_binja.py",
    "content": "import re\n\ndata = open(\"./il2cpp.h\").read()\n\nbuiltin = [\"void\", \"intptr_t\", \"uint32_t\", \"uint16_t\", \"int32_t\", \"uint8_t\", \"bool\",\n           \"int64_t\", \"uint64_t\", \"double\", \"int16_t\", \"int8_t\", \"float\", \"uintptr_t\",\n           \"const\", \"union\", \"{\", \"};\", \"il2cpp_array_size_t\", \"il2cpp_array_lower_bound_t\",\n           \"struct\", \"Il2CppMethodPointer\"]\nstructs = []\nnotfound = []\nheader = \"\"\n\nfor line in data.splitlines():\n    if line.startswith(\"struct\") or line.startswith(\"union\"):\n        struct = line.split()[1]\n        if struct.endswith(\";\"):\n            struct = struct[:-1]\n        structs.append(struct)\n    if line.startswith(\"\\t\"):\n        struct = line[1:].split()[0]\n        if struct == \"struct\":\n            struct = line[1:].split()[1]\n        if struct.endswith(\"*\"):\n            struct = struct[:-1]\n        if struct.endswith(\"*\"):\n            struct = struct[:-1]\n        if struct in builtin:\n            continue\n        if struct not in structs and struct not in notfound:\n            notfound.append(struct)\nfor struct in notfound:\n    header += f\"struct {struct};\" + \"\\n\"\nto_replace = re.findall(\"struct (.*) {\\n};\", data)\nfor item in to_replace:\n    data = data.replace(\"struct \"+item+\" {\\n};\", \"\")\n    data = data.replace(\"\\t\"+item.split()[0]+\" \", \"\\tvoid *\")\n    data = data.replace(\"\\t struct \"+item.split()[0]+\" \", \"\\t void *\")\n    data = re.sub(r\": (\\w+) {\", r\"{\\n\\t\\1 super;\", data)\nwith open(\"./il2cpp_binja.h\", \"w\") as f:\n    f.write(header)\n    f.write(data)\n"
  },
  {
    "path": "Il2CppDumper/il2cpp_header_to_ghidra.py",
    "content": "﻿import re\n\nheader = \"typedef unsigned __int8 uint8_t;\\n\" \\\n         \"typedef unsigned __int16 uint16_t;\\n\" \\\n         \"typedef unsigned __int32 uint32_t;\\n\" \\\n         \"typedef unsigned __int64 uint64_t;\\n\" \\\n         \"typedef __int8 int8_t;\\n\" \\\n         \"typedef __int16 int16_t;\\n\" \\\n         \"typedef __int32 int32_t;\\n\" \\\n         \"typedef __int64 int64_t;\\n\" \\\n         \"typedef __int64 intptr_t;\\n\" \\\n         \"typedef __int64 uintptr_t;\\n\" \\\n         \"typedef unsigned __int64 size_t;\\n\" \\\n         \"typedef _Bool bool;\\n\"\n\n\ndef main():\n    fixed_header_data = \"\"\n    with open(\"il2cpp.h\", 'r') as f:\n        print(\"il2cpp.h opened...\")\n        original_header_data = f.read()\n        print(\"il2cpp.h read...\")\n        fixed_header_data = re.sub(r\": (\\w+) {\", r\"{\\n \\1 super;\", original_header_data)\n        print(\"il2cpp.h data fixed...\")\n    print(\"il2cpp.h closed.\")\n    with open(\"il2cpp_ghidra.h\", 'w') as f:\n        print(\"il2cpp_ghidra.h opened...\")\n        f.write(header)\n        print(\"header written...\")\n        f.write(fixed_header_data)\n        print(\"fixed data written...\")\n    print(\"il2cpp_ghidra.h closed.\")\n\n\nif __name__ == '__main__':\n    print(\"Script started...\")\n    main()\n"
  },
  {
    "path": "Il2CppDumper.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.1.32228.430\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Il2CppDumper\", \"Il2CppDumper\\Il2CppDumper.csproj\", \"{2087F99A-A655-41C1-84BB-54798AEA4080}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{2087F99A-A655-41C1-84BB-54798AEA4080}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{2087F99A-A655-41C1-84BB-54798AEA4080}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{2087F99A-A655-41C1-84BB-54798AEA4080}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{2087F99A-A655-41C1-84BB-54798AEA4080}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {E570C2EE-9A67-4FA2-A564-FB23AD4800C9}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2016 Perfare\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Il2CppDumper\n\n[![Build status](https://ci.appveyor.com/api/projects/status/anhqw33vcpmp8ofa?svg=true)](https://ci.appveyor.com/project/Perfare/il2cppdumper/branch/master/artifacts)\n\n中文说明请戳[这里](README.zh-CN.md)\n\nUnity il2cpp reverse engineer\n\n## Features\n\n* Complete DLL restore (except code), can be used to extract `MonoBehaviour` and `MonoScript`\n* Supports ELF, ELF64, Mach-O, PE, NSO and WASM format\n* Supports Unity 5.3 - 2022.2\n* Supports generate IDA, Ghidra and Binary Ninja scripts to help them better analyze il2cpp files\n* Supports generate structures header file\n* Supports Android memory dumped `libil2cpp.so` file to bypass protection\n* Support bypassing simple PE protection\n\n## Usage\n\nRun `Il2CppDumper.exe` and choose the il2cpp executable file and `global-metadata.dat` file, then enter the information as prompted\n\nThe program will then generate all the output files in current working directory\n\n### Command-line\n\n```\nIl2CppDumper.exe <executable-file> <global-metadata> <output-directory>\n```\n\n### Outputs\n\n#### DummyDll\n\nFolder, containing all restored dll files\n\nUse [dnSpy](https://github.com/0xd4d/dnSpy), [ILSpy](https://github.com/icsharpcode/ILSpy) or other .Net decompiler tools to view\n\nCan be used to extract Unity `MonoBehaviour` and `MonoScript`, for [UtinyRipper](https://github.com/mafaca/UtinyRipper), [UABE](https://7daystodie.com/forums/showthread.php?22675-Unity-Assets-Bundle-Extractor)\n\n#### ida.py\n\nFor IDA\n\n#### ida_with_struct.py\n\nFor IDA, read il2cpp.h file and apply structure information in IDA\n\n#### il2cpp.h\n\nstructure information header file\n\n#### ghidra.py\n\nFor Ghidra\n\n#### Il2CppBinaryNinja\n\nFor BinaryNinja\n\n#### ghidra_wasm.py\n\nFor Ghidra, work with [ghidra-wasm-plugin](https://github.com/nneonneo/ghidra-wasm-plugin)\n\n#### script.json\n\nFor ida.py, ghidra.py and Il2CppBinaryNinja\n\n#### stringliteral.json\n\nContains all stringLiteral information\n\n### Configuration\n\nAll the configuration options are located in `config.json`\n\nAvailable options:\n\n* `DumpMethod`, `DumpField`, `DumpProperty`, `DumpAttribute`, `DumpFieldOffset`, `DumpMethodOffset`, `DumpTypeDefIndex`\n  * Whether to output these information to dump.cs\n\n* `GenerateDummyDll`, `GenerateScript`\n  * Whether to generate these things\n\n* `DummyDllAddToken`\n  * Whether to add token in DummyDll\n\n* `RequireAnyKey`\n  * Whether to press any key to exit at the end\n\n* `ForceIl2CppVersion`, `ForceVersion`\n  * If `ForceIl2CppVersion` is `true`, the program will use the version number specified in `ForceVersion` to choose parser for il2cpp binaries (does not affect the choice of metadata parser). This may be useful on some older il2cpp version (e.g. the program may need to use v16 parser on il2cpp v20 (Android) binaries in order to work properly)\n\n* `ForceDump`\n  * Force files to be treated as dumped\n\n* `NoRedirectedPointer`\n  * Treat pointers in dumped files as unredirected, This option needs to be `true` for files dumped from some devices\n\n## Common errors\n\n#### `ERROR: Metadata file supplied is not valid metadata file.`  \n\nMake sure you choose the correct file. Sometimes games may obfuscate this file for content protection purposes and so on. Deobfuscating of such files is beyond the scope of this program, so please **DO NOT** file an issue regarding to deobfuscating.\n\nIf your file is `libil2cpp.so` and you have a rooted Android phone, you can try my other project [Zygisk-Il2CppDumper](https://github.com/Perfare/Zygisk-Il2CppDumper), it can bypass this protection.\n\n#### `ERROR: Can't use auto mode to process file, try manual mode.`\n\nPlease note that the executable file for the PC platform is `GameAssembly.dll` or `*Assembly.dll`\n\nYou can open a new issue and upload the file, I will try to solve.\n\n#### `ERROR: This file may be protected.`\n\nIl2CppDumper detected that the executable file has been protected, use `GameGuardian` to dump `libil2cpp.so` from the game memory, then use Il2CppDumper to load and follow the prompts, can bypass most protections.\n\nIf you have a rooted Android phone, you can try my other project [Zygisk-Il2CppDumper](https://github.com/Perfare/Zygisk-Il2CppDumper), it can bypass almost all protections.\n\n## Credits\n\n- Jumboperson - [Il2CppDumper](https://github.com/Jumboperson/Il2CppDumper)\n"
  },
  {
    "path": "README.zh-CN.md",
    "content": "# Il2CppDumper\n\n[![Build status](https://ci.appveyor.com/api/projects/status/anhqw33vcpmp8ofa?svg=true)](https://ci.appveyor.com/project/Perfare/il2cppdumper/branch/master/artifacts)\n\nUnity il2cpp逆向工程\n\n## 功能\n\n* 还原DLL文件（不包含代码），可用于提取`MonoBehaviour`和`MonoScript`\n* 支持ELF, ELF64, Mach-O, PE, NSO和WASM格式\n* 支持Unity 5.3 - 2022.2\n* 生成IDA和Ghidra的脚本，帮助IDA和Ghidra更好的分析il2cpp文件\n* 生成结构体头文件\n* 支持从内存dump的`libil2cpp.so`文件以绕过保护\n* 支持绕过简单的PE保护\n\n## 使用说明\n\n直接运行Il2CppDumper.exe并依次选择il2cpp的可执行文件和global-metadata.dat文件，然后根据提示输入相应信息。\n\n程序运行完成后将在当前运行目录下生成输出文件\n\n### 命令行\n\n```\nIl2CppDumper.exe <executable-file> <global-metadata> <output-directory>\n```\n\n### 输出文件\n\n#### DummyDll\n\n文件夹，包含所有还原的DLL文件\n\n使用[dnSpy](https://github.com/0xd4d/dnSpy)，[ILSpy](https://github.com/icsharpcode/ILSpy)或者其他.Net反编译工具即可查看具体信息\n\n可用于提取Unity的`MonoBehaviour`和`MonoScript`，适用于[UtinyRipper](https://github.com/mafaca/UtinyRipper)或者[UABE](https://7daystodie.com/forums/showthread.php?22675-Unity-Assets-Bundle-Extractor)等\n\n#### ida.py\n\n用于IDA\n\n#### ida_with_struct.py\n\n用于IDA, 读取il2cpp.h文件并在IDA中应用结构信息\n\n#### il2cpp.h\n\n包含结构体的头文件\n\n#### ghidra.py\n\n用于Ghidra\n\n#### Il2CppBinaryNinja\n\n用于BinaryNinja\n\n#### ghidra_wasm.py\n\n用于Ghidra, 和[ghidra-wasm-plugin](https://github.com/nneonneo/ghidra-wasm-plugin)一起工作\n\n#### script.json\n\n用于IDA和Ghidra脚本\n\n#### stringliteral.json\n\n包含所有stringLiteral信息\n\n### 关于config.json\n\n* `DumpMethod`，`DumpField`，`DumpProperty`，`DumpAttribute`，`DumpFieldOffset`, `DumpMethodOffset`, `DumpTypeDefIndex`\n  * 是否在dump.cs输出相应的内容\n\n* `GenerateDummyDll`，`GenerateScript`\n  * 是否生成这些内容\n\n* `DummyDllAddToken`\n  * 是否在DummyDll中添加token\n\n* `RequireAnyKey`\n  * 在程序结束时是否需要按键退出\n\n* `ForceIl2CppVersion`，`ForceVersion`  \n  * 当ForceIl2CppVersion为`true`时，程序将根据ForceVersion指定的版本读取il2cpp的可执行文件（Metadata仍然使用header里的版本），在部分低版本的il2cpp中可能会用到（比如安卓20版本下，你可能需要设置ForceVersion为16程序才能正常工作）\n\n* `ForceDump`\n  * 强制将文件视为dump文件\n\n* `NoRedirectedPointer`\n  * 将dump文件中的指针视为未重定向的, 从某些设备dump出的文件需要设置该项为`true`\n\n## 常见问题\n\n#### `ERROR: Metadata file supplied is not valid metadata file.`\n\nglobal-metadata.dat已被加密。关于解密的问题请去相关破解论坛寻求帮助，请不要在issues提问！\n\n如果你的文件是`libil2cpp.so`并且你拥有一台已root的安卓手机，你可以尝试我的另一个项目[Zygisk-Il2CppDumper](https://github.com/Perfare/Zygisk-Il2CppDumper)，它能够无视global-metadata.dat加密\n\n#### `ERROR: Can't use auto mode to process file, try manual mode.`\n\n请注意PC平台的可执行文件是`GameAssembly.dll`或者`*Assembly.dll`\n\n你可以打开一个新的issue，并上传文件，我会尝试解决\n\n#### `ERROR: This file may be protected.`\n\nIl2CppDumper检测到可执行文件已被保护，使用`GameGuardian`从游戏内存中dump `libil2cpp.so`，然后使用Il2CppDumper载入按提示操作，可绕过大部分保护\n\n如果你拥有一台已root的安卓手机，你可以尝试我的另一个项目[Zygisk-Il2CppDumper](https://github.com/Perfare/Zygisk-Il2CppDumper)，它能够绕过几乎所有保护\n\n## 感谢\n\n- Jumboperson - [Il2CppDumper](https://github.com/Jumboperson/Il2CppDumper)\n"
  }
]