mirror of
https://github.com/Perfare/Il2CppDumper.git
synced 2025-01-09 03:07:42 -03:00
初始化提交
This commit is contained in:
parent
8bde61638d
commit
ef9e9de713
14 changed files with 1656 additions and 0 deletions
63
.gitattributes
vendored
Normal file
63
.gitattributes
vendored
Normal file
|
@ -0,0 +1,63 @@
|
|||
###############################################################################
|
||||
# Set default behavior to automatically normalize line endings.
|
||||
###############################################################################
|
||||
* text=auto
|
||||
|
||||
###############################################################################
|
||||
# Set default behavior for command prompt diff.
|
||||
#
|
||||
# This is need for earlier builds of msysgit that does not have it on by
|
||||
# default for csharp files.
|
||||
# Note: This is only used by command line
|
||||
###############################################################################
|
||||
#*.cs diff=csharp
|
||||
|
||||
###############################################################################
|
||||
# Set the merge driver for project and solution files
|
||||
#
|
||||
# Merging from the command prompt will add diff markers to the files if there
|
||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||
# the diff markers are never inserted). Diff markers may cause the following
|
||||
# file extensions to fail to load in VS. An alternative would be to treat
|
||||
# these files as binary and thus will always conflict and require user
|
||||
# intervention with every merge. To do so, just uncomment the entries below
|
||||
###############################################################################
|
||||
#*.sln merge=binary
|
||||
#*.csproj merge=binary
|
||||
#*.vbproj merge=binary
|
||||
#*.vcxproj merge=binary
|
||||
#*.vcproj merge=binary
|
||||
#*.dbproj merge=binary
|
||||
#*.fsproj merge=binary
|
||||
#*.lsproj merge=binary
|
||||
#*.wixproj merge=binary
|
||||
#*.modelproj merge=binary
|
||||
#*.sqlproj merge=binary
|
||||
#*.wwaproj merge=binary
|
||||
|
||||
###############################################################################
|
||||
# behavior for image files
|
||||
#
|
||||
# image files are treated as binary by default.
|
||||
###############################################################################
|
||||
#*.jpg binary
|
||||
#*.png binary
|
||||
#*.gif binary
|
||||
|
||||
###############################################################################
|
||||
# diff behavior for common document formats
|
||||
#
|
||||
# Convert binary document formats to text before diffing them. This feature
|
||||
# is only available from the command line. Turn it on by uncommenting the
|
||||
# entries below.
|
||||
###############################################################################
|
||||
#*.doc diff=astextplain
|
||||
#*.DOC diff=astextplain
|
||||
#*.docx diff=astextplain
|
||||
#*.DOCX diff=astextplain
|
||||
#*.dot diff=astextplain
|
||||
#*.DOT diff=astextplain
|
||||
#*.pdf diff=astextplain
|
||||
#*.PDF diff=astextplain
|
||||
#*.rtf diff=astextplain
|
||||
#*.RTF diff=astextplain
|
242
.gitignore
vendored
Normal file
242
.gitignore
vendored
Normal file
|
@ -0,0 +1,242 @@
|
|||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
[Xx]64/
|
||||
[Xx]86/
|
||||
[Bb]uild/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
|
||||
# Visual Studio 2015 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# DNX
|
||||
project.lock.json
|
||||
artifacts/
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
|
||||
# TODO: Un-comment the next line if you do not want to checkin
|
||||
# your web deploy settings because they may include unencrypted
|
||||
# passwords
|
||||
#*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/packages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/packages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/packages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignoreable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directory
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
[Ss]tyle[Cc]op.*
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
node_modules/
|
||||
orleans.codegen.cs
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# LightSwitch generated files
|
||||
GeneratedArtifacts/
|
||||
ModelManifest.xml
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
22
Il2CppDumper.sln
Normal file
22
Il2CppDumper.sln
Normal file
|
@ -0,0 +1,22 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Il2CppDumper", "Il2CppDumper\Il2CppDumper.csproj", "{379715D4-4B7B-41F2-B78A-8B18D86320E2}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{379715D4-4B7B-41F2-B78A-8B18D86320E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{379715D4-4B7B-41F2-B78A-8B18D86320E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{379715D4-4B7B-41F2-B78A-8B18D86320E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{379715D4-4B7B-41F2-B78A-8B18D86320E2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
20
Il2CppDumper/DefineConstants.cs
Normal file
20
Il2CppDumper/DefineConstants.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
internal static class DefineConstants
|
||||
{
|
||||
public const int FIELD_ATTRIBUTE_PRIVATE = 0x0001;
|
||||
public const int FIELD_ATTRIBUTE_PUBLIC = 0x0006;
|
||||
public const int FIELD_ATTRIBUTE_STATIC = 0x0010;
|
||||
public const int FIELD_ATTRIBUTE_INIT_ONLY = 0x0020;
|
||||
public const int METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK = 0x0007;
|
||||
public const int METHOD_ATTRIBUTE_PRIVATE = 0x0001;
|
||||
public const int METHOD_ATTRIBUTE_PUBLIC = 0x0006;
|
||||
public const int METHOD_ATTRIBUTE_STATIC = 0x0010;
|
||||
public const int METHOD_ATTRIBUTE_VIRTUAL = 0x0040;
|
||||
public const int TYPE_ATTRIBUTE_VISIBILITY_MASK = 0x00000007;
|
||||
public const int TYPE_ATTRIBUTE_PUBLIC = 0x00000001;
|
||||
public const int TYPE_ATTRIBUTE_INTERFACE = 0x00000020;
|
||||
public const int TYPE_ATTRIBUTE_ABSTRACT = 0x00000080;
|
||||
public const int TYPE_ATTRIBUTE_SEALED = 0x00000100;
|
||||
public const int TYPE_ATTRIBUTE_SERIALIZABLE = 0x00002000;
|
||||
public const int PARAM_ATTRIBUTE_OUT = 0x0002;
|
||||
public const int PARAM_ATTRIBUTE_OPTIONAL = 0x0010;
|
||||
}
|
130
Il2CppDumper/Elf.cs
Normal file
130
Il2CppDumper/Elf.cs
Normal file
|
@ -0,0 +1,130 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Il2CppDumper
|
||||
{
|
||||
class Elf : MyBinaryReader
|
||||
{
|
||||
public elf_header elf_header;
|
||||
public Dictionary<string, elf_32_shdr> sectionWithName;
|
||||
List<elf_32_shdr> sections;
|
||||
|
||||
public Elf(Stream stream) : base(stream)
|
||||
{
|
||||
elf_header = new elf_header();
|
||||
elf_header.m_dwFormat = ReadUInt32();
|
||||
if (elf_header.m_dwFormat != 0x464c457f)
|
||||
{
|
||||
throw new Exception("ERROR: il2cpp lib provided is not a valid ELF file.");
|
||||
}
|
||||
elf_header.m_arch = ReadByte();
|
||||
elf_header.m_endian = ReadByte();
|
||||
elf_header.m_version = ReadByte();
|
||||
elf_header.m_osabi = ReadByte();
|
||||
elf_header.m_osabi_ver = ReadByte();
|
||||
elf_header.e_pad = ReadBytes(7);
|
||||
elf_header.e_type = ReadUInt16();
|
||||
elf_header.e_machine = ReadUInt16();
|
||||
elf_header.e_version = ReadUInt32();
|
||||
if (elf_header.m_arch == 1)//32
|
||||
{
|
||||
elf_header.e_entry = ReadUInt32();
|
||||
elf_header.e_phoff = ReadUInt32();
|
||||
elf_header.e_shoff = ReadUInt32();
|
||||
elf_header.e_flags = ReadUInt32();
|
||||
elf_header.e_ehsize = ReadUInt16();
|
||||
elf_header.e_phentsize = ReadUInt16();
|
||||
elf_header.e_phnum = ReadUInt16();
|
||||
elf_header.e_shentsize = ReadUInt16();
|
||||
elf_header.e_shnum = ReadUInt16();
|
||||
elf_header.e_shtrndx = ReadUInt16();
|
||||
}
|
||||
else//64
|
||||
{
|
||||
elf_header.e_entry = ReadUInt64();
|
||||
elf_header.e_phoff = ReadUInt64();
|
||||
elf_header.e_shoff = ReadUInt64();
|
||||
elf_header.e_flags = ReadUInt32();
|
||||
elf_header.e_ehsize = ReadUInt16();
|
||||
elf_header.e_phentsize = ReadUInt16();
|
||||
elf_header.e_phnum = ReadUInt16();
|
||||
elf_header.e_shentsize = ReadUInt16();
|
||||
elf_header.e_shnum = ReadUInt16();
|
||||
elf_header.e_shtrndx = ReadUInt16();
|
||||
}
|
||||
GetSectionWithName();
|
||||
}
|
||||
|
||||
private void GetSectionWithName()
|
||||
{
|
||||
try
|
||||
{
|
||||
var section_name_block_off = (int)elf_header.e_shoff + (elf_header.e_shentsize * elf_header.e_shtrndx);
|
||||
if (elf_header.m_arch == 1)//32
|
||||
{
|
||||
Position = section_name_block_off + 2 * 4 + 4 + 4;
|
||||
section_name_block_off = ReadInt32();
|
||||
}
|
||||
else//Hmm...
|
||||
{
|
||||
Position = section_name_block_off + 2 * 4 + 8 + 8;
|
||||
section_name_block_off = ReadInt32();
|
||||
}
|
||||
var sectionWithNametmp = new Dictionary<string, elf_32_shdr>();
|
||||
var sectionstmp = new List<elf_32_shdr>();
|
||||
for (int i = 0; i < elf_header.e_shnum; i++)
|
||||
{
|
||||
var section = GetSection(i);
|
||||
sectionWithNametmp.Add(ReadStringToNull(section_name_block_off + section.sh_name), section);
|
||||
sectionstmp.Add(section);
|
||||
}
|
||||
sectionWithName = sectionWithNametmp;
|
||||
sections = sectionstmp;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine("ERROR: Unable to get section.");
|
||||
}
|
||||
}
|
||||
|
||||
private elf_32_shdr GetSection(int iSection)
|
||||
{
|
||||
return ReadClass<elf_32_shdr>((int)elf_header.e_shoff + (elf_header.e_shentsize * iSection));
|
||||
}
|
||||
|
||||
public uint MapVATR(uint uiAddr)
|
||||
{
|
||||
if (sections == null)
|
||||
return uiAddr;
|
||||
elf_32_shdr pFirstSec = sections[0];
|
||||
if (uiAddr < pFirstSec.sh_addr)
|
||||
return 0;
|
||||
for (int i = 1; i < elf_header.e_shnum; ++i)
|
||||
{
|
||||
elf_32_shdr pSection = sections[i];
|
||||
if (pSection.sh_addr > uiAddr)
|
||||
{
|
||||
elf_32_shdr pRetSec = sections[i - 1];
|
||||
uint uiResOffset = uiAddr - pRetSec.sh_addr;
|
||||
return pRetSec.sh_offset + uiResOffset;
|
||||
}
|
||||
}
|
||||
elf_32_shdr pRetSec2 = sections[elf_header.e_shnum - 1];
|
||||
uint uiResOffset2 = uiAddr - pRetSec2.sh_addr;
|
||||
return pRetSec2.sh_offset + uiResOffset2;
|
||||
}
|
||||
|
||||
public T MapVATR<T>(uint uiAddr) where T : new()
|
||||
{
|
||||
return ReadClass<T>(MapVATR(uiAddr));
|
||||
}
|
||||
|
||||
public T[] MapVATR<T>(uint uiAddr, int count) where T : new()
|
||||
{
|
||||
return ReadClassArray<T>(MapVATR(uiAddr), count);
|
||||
}
|
||||
}
|
||||
}
|
71
Il2CppDumper/ElfClass.cs
Normal file
71
Il2CppDumper/ElfClass.cs
Normal file
|
@ -0,0 +1,71 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Il2CppDumper
|
||||
{
|
||||
class elf_header
|
||||
{
|
||||
// 0x7f followed by ELF in ascii
|
||||
public uint m_dwFormat;
|
||||
|
||||
// 1 - 32 bit
|
||||
// 2 - 64 bit
|
||||
public byte m_arch;
|
||||
|
||||
// 1 - little endian
|
||||
// 2 - big endian
|
||||
public byte m_endian;
|
||||
|
||||
// 1 is original elf format
|
||||
public byte m_version;
|
||||
|
||||
// set based on OS, refer to OSABI enum
|
||||
public byte m_osabi;
|
||||
|
||||
// refer to elf documentation
|
||||
public byte m_osabi_ver;
|
||||
|
||||
// unused
|
||||
public byte[] e_pad;//byte[7]
|
||||
|
||||
// 1 - relocatable
|
||||
// 2 - executable
|
||||
// 3 - shared
|
||||
// 4 - core
|
||||
public ushort e_type;
|
||||
|
||||
// refer to isa enum
|
||||
public ushort e_machine;
|
||||
|
||||
public uint e_version;
|
||||
|
||||
//全部定义为64位
|
||||
public ulong e_entry;
|
||||
public ulong e_phoff;
|
||||
public ulong e_shoff;
|
||||
public uint e_flags;
|
||||
public ushort e_ehsize;
|
||||
public ushort e_phentsize;
|
||||
public ushort e_phnum;
|
||||
public ushort e_shentsize;
|
||||
public ushort e_shnum;
|
||||
public ushort e_shtrndx;
|
||||
}
|
||||
|
||||
class elf_32_shdr
|
||||
{
|
||||
public uint sh_name;
|
||||
public uint sh_type;
|
||||
public uint sh_flags;
|
||||
public uint sh_addr;
|
||||
public uint sh_offset;
|
||||
public uint sh_size;
|
||||
public uint sh_link;
|
||||
public uint sh_info;
|
||||
public uint sh_addralign;
|
||||
public uint sh_entsize;
|
||||
}
|
||||
}
|
118
Il2CppDumper/Il2Cpp.cs
Normal file
118
Il2CppDumper/Il2Cpp.cs
Normal file
|
@ -0,0 +1,118 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Il2CppDumper
|
||||
{
|
||||
class Il2Cpp : Elf
|
||||
{
|
||||
Il2CppMetadataRegistration pMetadataRegistration;
|
||||
public Il2CppCodeRegistration pCodeRegistration;
|
||||
|
||||
public Il2Cpp(Stream stream) : base(stream)
|
||||
{
|
||||
if (!Auto())
|
||||
{
|
||||
throw new Exception("ERROR: Unable to process file automatically, try to use manual mode.");
|
||||
}
|
||||
}
|
||||
|
||||
public Il2Cpp(Stream stream, uint codeRegistration, uint metadataRegistration) : base(stream)
|
||||
{
|
||||
Init(codeRegistration, metadataRegistration);
|
||||
}
|
||||
|
||||
private void Init(uint codeRegistration, uint metadataRegistration)
|
||||
{
|
||||
pCodeRegistration = MapVATR<Il2CppCodeRegistration>(codeRegistration);
|
||||
pMetadataRegistration = MapVATR<Il2CppMetadataRegistration>(metadataRegistration);
|
||||
pCodeRegistration.methodPointers = MapVATR<uint>(pCodeRegistration.pmethodPointers, (int)pCodeRegistration.methodPointersCount);
|
||||
pMetadataRegistration.fieldOffsets = MapVATR<int>(pMetadataRegistration.pfieldOffsets, pMetadataRegistration.fieldOffsetsCount);
|
||||
var types = MapVATR<uint>(pMetadataRegistration.ptypes, pMetadataRegistration.typesCount);
|
||||
pMetadataRegistration.types = new Il2CppType[pMetadataRegistration.typesCount];
|
||||
for (int i = 0; i < pMetadataRegistration.typesCount; ++i)
|
||||
{
|
||||
pMetadataRegistration.types[i] = MapVATR<Il2CppType>(types[i]);
|
||||
pMetadataRegistration.types[i].Init();
|
||||
}
|
||||
}
|
||||
|
||||
public Il2CppType GetTypeFromTypeIndex(int idx)
|
||||
{
|
||||
return pMetadataRegistration.types[idx];
|
||||
}
|
||||
|
||||
public int GetFieldOffsetFromIndex(int typeIndex, int fieldIndexInType)
|
||||
{
|
||||
var ptr = pMetadataRegistration.fieldOffsets[typeIndex];
|
||||
Position = ptr + 4 * fieldIndexInType;
|
||||
return ReadInt32();
|
||||
}
|
||||
|
||||
public bool Auto()
|
||||
{
|
||||
if (sectionWithName != null)
|
||||
{
|
||||
var bytes = new byte[] { 0x1c, 0x0, 0x9f, 0xe5, 0x1c, 0x10, 0x9f, 0xe5, 0x1c, 0x20, 0x9f, 0xe5 };
|
||||
//判断必要的section是否都在
|
||||
if (sectionWithName.ContainsKey(".got") && sectionWithName.ContainsKey(".init_array") && sectionWithName.ContainsKey(".dynamic"))
|
||||
{
|
||||
var dynamic = sectionWithName[".dynamic"];
|
||||
var got = sectionWithName[".got"];
|
||||
//从.dynamic获取_GLOBAL_OFFSET_TABLE_
|
||||
uint _GLOBAL_OFFSET_TABLE_ = 0;
|
||||
Position = dynamic.sh_offset;
|
||||
var dynamicend = dynamic.sh_offset + dynamic.sh_size;
|
||||
var gotend = got.sh_offset + got.sh_size;
|
||||
while (Position < dynamicend)
|
||||
{
|
||||
var tag = ReadInt32();
|
||||
if (tag == 3)
|
||||
{
|
||||
var tmp = ReadUInt32();
|
||||
if (tmp >= got.sh_offset && tmp <= gotend)
|
||||
{
|
||||
_GLOBAL_OFFSET_TABLE_ = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Position += 4;
|
||||
}
|
||||
//从.init_array获取函数
|
||||
var init_array = sectionWithName[".init_array"];
|
||||
var addrs = ReadClassArray<uint>(init_array.sh_offset, (int)init_array.sh_size / 4);
|
||||
foreach (var i in addrs)
|
||||
{
|
||||
if (i != 0)
|
||||
{
|
||||
Position = i;
|
||||
var buff = ReadBytes(12);
|
||||
if (bytes.SequenceEqual(buff))
|
||||
{
|
||||
Position = i + 0x2c;
|
||||
var subaddr = ReadUInt32() + _GLOBAL_OFFSET_TABLE_;
|
||||
Position = subaddr + 0x28;
|
||||
var codeRegistration = ReadUInt32() + _GLOBAL_OFFSET_TABLE_;
|
||||
Console.WriteLine("CodeRegistration : {0:x}", codeRegistration);
|
||||
Position = subaddr + 0x2C;
|
||||
var ptr = ReadUInt32() + _GLOBAL_OFFSET_TABLE_;
|
||||
Position = MapVATR(ptr);
|
||||
var metadataRegistration = ReadUInt32();
|
||||
Console.WriteLine("MetadataRegistration : {0:x}", metadataRegistration);
|
||||
Init(codeRegistration, metadataRegistration);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("ERROR: The necessary section is missing.");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
208
Il2CppDumper/Il2CppClass.cs
Normal file
208
Il2CppDumper/Il2CppClass.cs
Normal file
|
@ -0,0 +1,208 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Il2CppDumper
|
||||
{
|
||||
public class Il2CppCodeRegistration
|
||||
{
|
||||
public uint methodPointersCount;
|
||||
public uint pmethodPointers;
|
||||
public uint delegateWrappersFromNativeToManagedCount;
|
||||
public uint delegateWrappersFromNativeToManaged; // note the double indirection to handle different calling conventions
|
||||
public uint delegateWrappersFromManagedToNativeCount;
|
||||
public uint delegateWrappersFromManagedToNative;
|
||||
public uint marshalingFunctionsCount;
|
||||
public uint marshalingFunctions;
|
||||
public uint ccwMarshalingFunctionsCount;
|
||||
public uint ccwMarshalingFunctions;
|
||||
public uint genericMethodPointersCount;
|
||||
public uint genericMethodPointers;
|
||||
public uint invokerPointersCount;
|
||||
public uint invokerPointers;
|
||||
public int customAttributeCount;
|
||||
public uint customAttributeGenerators;
|
||||
public int guidCount;
|
||||
public uint guids; // Il2CppGuid
|
||||
|
||||
public uint[] methodPointers
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
}
|
||||
|
||||
class Il2CppMetadataRegistration
|
||||
{
|
||||
public int genericClassesCount;
|
||||
public uint genericClasses;
|
||||
public int genericInstsCount;
|
||||
public uint genericInsts;
|
||||
public int genericMethodTableCount;
|
||||
public uint genericMethodTable; // Il2CppGenericMethodFunctionsDefinitions
|
||||
public int typesCount;
|
||||
public uint ptypes;
|
||||
public int methodSpecsCount;
|
||||
public uint methodSpecs;
|
||||
|
||||
public int fieldOffsetsCount;
|
||||
public uint pfieldOffsets;
|
||||
|
||||
public int typeDefinitionsSizesCount;
|
||||
public uint typeDefinitionsSizes;
|
||||
public uint metadataUsagesCount;
|
||||
public uint metadataUsages;
|
||||
|
||||
public int[] fieldOffsets
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public Il2CppType[] types
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Il2CppTypeEnum
|
||||
{
|
||||
IL2CPP_TYPE_END = 0x00, /* End of List */
|
||||
IL2CPP_TYPE_VOID = 0x01,
|
||||
IL2CPP_TYPE_BOOLEAN = 0x02,
|
||||
IL2CPP_TYPE_CHAR = 0x03,
|
||||
IL2CPP_TYPE_I1 = 0x04,
|
||||
IL2CPP_TYPE_U1 = 0x05,
|
||||
IL2CPP_TYPE_I2 = 0x06,
|
||||
IL2CPP_TYPE_U2 = 0x07,
|
||||
IL2CPP_TYPE_I4 = 0x08,
|
||||
IL2CPP_TYPE_U4 = 0x09,
|
||||
IL2CPP_TYPE_I8 = 0x0a,
|
||||
IL2CPP_TYPE_U8 = 0x0b,
|
||||
IL2CPP_TYPE_R4 = 0x0c,
|
||||
IL2CPP_TYPE_R8 = 0x0d,
|
||||
IL2CPP_TYPE_STRING = 0x0e,
|
||||
IL2CPP_TYPE_PTR = 0x0f, /* arg: <type> token */
|
||||
IL2CPP_TYPE_BYREF = 0x10, /* arg: <type> token */
|
||||
IL2CPP_TYPE_VALUETYPE = 0x11, /* arg: <type> token */
|
||||
IL2CPP_TYPE_CLASS = 0x12, /* arg: <type> token */
|
||||
IL2CPP_TYPE_VAR = 0x13, /* Generic parameter in a generic type definition, represented as number (compressed unsigned integer) number */
|
||||
IL2CPP_TYPE_ARRAY = 0x14, /* type, rank, boundsCount, bound1, loCount, lo1 */
|
||||
IL2CPP_TYPE_GENERICINST = 0x15, /* <type> <type-arg-count> <type-1> \x{2026} <type-n> */
|
||||
IL2CPP_TYPE_TYPEDBYREF = 0x16,
|
||||
IL2CPP_TYPE_I = 0x18,
|
||||
IL2CPP_TYPE_U = 0x19,
|
||||
IL2CPP_TYPE_FNPTR = 0x1b, /* arg: full method signature */
|
||||
IL2CPP_TYPE_OBJECT = 0x1c,
|
||||
IL2CPP_TYPE_SZARRAY = 0x1d, /* 0-based one-dim-array */
|
||||
IL2CPP_TYPE_MVAR = 0x1e, /* Generic parameter in a generic method definition, represented as number (compressed unsigned integer) */
|
||||
IL2CPP_TYPE_CMOD_REQD = 0x1f, /* arg: typedef or typeref token */
|
||||
IL2CPP_TYPE_CMOD_OPT = 0x20, /* optional arg: typedef or typref token */
|
||||
IL2CPP_TYPE_INTERNAL = 0x21, /* CLR internal type */
|
||||
|
||||
IL2CPP_TYPE_MODIFIER = 0x40, /* Or with the following types */
|
||||
IL2CPP_TYPE_SENTINEL = 0x41, /* Sentinel for varargs method signature */
|
||||
IL2CPP_TYPE_PINNED = 0x45, /* Local var that points to pinned object */
|
||||
|
||||
IL2CPP_TYPE_ENUM = 0x55 /* an enumeration */
|
||||
}
|
||||
|
||||
public class Il2CppType
|
||||
{
|
||||
public uint datapoint;
|
||||
public Anonymous data { get; set; }
|
||||
public uint bits;
|
||||
public uint attrs { get; set; }
|
||||
public Il2CppTypeEnum type { get; set; }
|
||||
public uint num_mods { get; set; }
|
||||
public uint byref { get; set; }
|
||||
public uint pinned { get; set; }
|
||||
|
||||
public void Init()
|
||||
{
|
||||
var str = System.Convert.ToString(bits, 2);
|
||||
if (str.Length != 32)
|
||||
{
|
||||
str = new string(Enumerable.Repeat('0', 32 - str.Length).Concat(str.ToCharArray()).ToArray());
|
||||
}
|
||||
attrs = Convert.ToUInt32(str.Substring(16, 16), 2);
|
||||
type = (Il2CppTypeEnum)Convert.ToInt32(str.Substring(8, 8), 2);
|
||||
num_mods = Convert.ToUInt32(str.Substring(2, 6), 2);
|
||||
byref = Convert.ToUInt32(str.Substring(1, 1), 2);
|
||||
pinned = Convert.ToUInt32(str.Substring(0, 1), 2);
|
||||
data = new Anonymous() { dummy = datapoint };
|
||||
}
|
||||
|
||||
public class Anonymous
|
||||
{
|
||||
public uint dummy;
|
||||
public int klassIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)dummy;
|
||||
}
|
||||
}
|
||||
public uint type
|
||||
{
|
||||
get
|
||||
{
|
||||
return dummy;
|
||||
}
|
||||
}
|
||||
public uint array
|
||||
{
|
||||
get
|
||||
{
|
||||
return dummy;
|
||||
}
|
||||
}
|
||||
public int genericParameterIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)dummy;
|
||||
}
|
||||
}
|
||||
public uint generic_class
|
||||
{
|
||||
get
|
||||
{
|
||||
return dummy;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Il2CppGenericClass
|
||||
{
|
||||
public int typeDefinitionIndex; /* the generic type definition */
|
||||
public Il2CppGenericContext context; /* a context that contains the type instantiation doesn't contain any method instantiation */
|
||||
public uint cached_class; /* if present, the Il2CppClass corresponding to the instantiation. */
|
||||
}
|
||||
|
||||
public class Il2CppGenericContext
|
||||
{
|
||||
/* The instantiation corresponding to the class generic parameters */
|
||||
public uint class_inst;
|
||||
/* The instantiation corresponding to the method generic parameters */
|
||||
public uint method_inst;
|
||||
}
|
||||
|
||||
|
||||
public class Il2CppGenericInst
|
||||
{
|
||||
public uint type_argc;
|
||||
public uint type_argv;
|
||||
}
|
||||
|
||||
public class Il2CppArrayType
|
||||
{
|
||||
public uint etype;
|
||||
public byte rank;
|
||||
public byte numsizes;
|
||||
public byte numlobounds;
|
||||
public uint sizes;
|
||||
public uint lobounds;
|
||||
}
|
||||
}
|
63
Il2CppDumper/Il2CppDumper.csproj
Normal file
63
Il2CppDumper/Il2CppDumper.csproj
Normal file
|
@ -0,0 +1,63 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{379715D4-4B7B-41F2-B78A-8B18D86320E2}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Il2CppDumper</RootNamespace>
|
||||
<AssemblyName>Il2CppDumper</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="DefineConstants.cs" />
|
||||
<Compile Include="Elf.cs" />
|
||||
<Compile Include="ElfClass.cs" />
|
||||
<Compile Include="Il2Cpp.cs" />
|
||||
<Compile Include="Il2CppClass.cs" />
|
||||
<Compile Include="Metadata.cs" />
|
||||
<Compile Include="MetadataClass.cs" />
|
||||
<Compile Include="MyBinaryReader.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
85
Il2CppDumper/Metadata.cs
Normal file
85
Il2CppDumper/Metadata.cs
Normal file
|
@ -0,0 +1,85 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Il2CppDumper
|
||||
{
|
||||
class Metadata : MyBinaryReader
|
||||
{
|
||||
Il2CppGlobalMetadataHeader pMetadataHdr;
|
||||
public int uiImageCount;
|
||||
public int uiNumTypes;
|
||||
public Il2CppImageDefinition[] imageDefs;
|
||||
public Il2CppTypeDefinition[] typeDefs;
|
||||
public Il2CppMethodDefinition[] methodDefs;
|
||||
public Il2CppParameterDefinition[] parameterDefs;
|
||||
public Il2CppFieldDefinition[] fieldDefs;
|
||||
public Il2CppFieldDefaultValue[] fieldDefaultValues;
|
||||
|
||||
public Metadata(Stream stream) : base(stream)
|
||||
{
|
||||
pMetadataHdr = ReadClass<Il2CppGlobalMetadataHeader>();
|
||||
if (pMetadataHdr.sanity != 0xFAB11BAF)
|
||||
{
|
||||
throw new Exception("ERROR: Metadata file supplied is not valid metadata file.");
|
||||
}
|
||||
if (pMetadataHdr.version != 21 && pMetadataHdr.version != 22)
|
||||
{
|
||||
throw new Exception($"ERROR: Metadata file supplied is not a supported version[{pMetadataHdr.version}].");
|
||||
}
|
||||
uiImageCount = pMetadataHdr.imagesCount / MySizeOf(typeof(Il2CppImageDefinition));
|
||||
uiNumTypes = pMetadataHdr.typeDefinitionsCount / MySizeOf(typeof(Il2CppTypeDefinition));
|
||||
imageDefs = ReadClassArray<Il2CppImageDefinition>(pMetadataHdr.imagesOffset, uiImageCount);
|
||||
//GetTypeDefFromIndex
|
||||
typeDefs = ReadClassArray<Il2CppTypeDefinition>(pMetadataHdr.typeDefinitionsOffset, uiNumTypes);
|
||||
//GetMethodDefinition
|
||||
methodDefs = ReadClassArray<Il2CppMethodDefinition>(pMetadataHdr.methodsOffset, pMetadataHdr.methodsCount / MySizeOf(typeof(Il2CppMethodDefinition)));
|
||||
//GetParameterFromIndex
|
||||
parameterDefs = ReadClassArray<Il2CppParameterDefinition>(pMetadataHdr.parametersOffset, pMetadataHdr.parametersCount / MySizeOf(typeof(Il2CppParameterDefinition)));
|
||||
//GetFieldDefFromIndex
|
||||
fieldDefs = ReadClassArray<Il2CppFieldDefinition>(pMetadataHdr.fieldsOffset, pMetadataHdr.fieldsCount / MySizeOf(typeof(Il2CppFieldDefinition)));
|
||||
//GetFieldDefaultFromIndex
|
||||
fieldDefaultValues = ReadClassArray<Il2CppFieldDefaultValue>(pMetadataHdr.fieldDefaultValuesOffset, pMetadataHdr.fieldDefaultValuesCount / MySizeOf(typeof(Il2CppFieldDefaultValue)));
|
||||
}
|
||||
|
||||
public Il2CppFieldDefaultValue GetFieldDefaultFromIndex(int idx)
|
||||
{
|
||||
return fieldDefaultValues.FirstOrDefault(x => x.fieldIndex == idx);
|
||||
}
|
||||
|
||||
public int GetDefaultValueFromIndex(int idx)
|
||||
{
|
||||
return pMetadataHdr.fieldAndParameterDefaultValueDataOffset + idx;
|
||||
}
|
||||
|
||||
public string GetString(int idx)
|
||||
{
|
||||
return ReadStringToNull(pMetadataHdr.stringOffset + idx);
|
||||
}
|
||||
|
||||
private int MySizeOf(Type type)
|
||||
{
|
||||
int size = 0;
|
||||
foreach (var i in type.GetFields())
|
||||
{
|
||||
if (i.FieldType == typeof(int))
|
||||
{
|
||||
size += 4;
|
||||
}
|
||||
else if (i.FieldType == typeof(uint))
|
||||
{
|
||||
size += 4;
|
||||
}
|
||||
else if (i.FieldType == typeof(short))
|
||||
{
|
||||
size += 2;
|
||||
}
|
||||
else if (i.FieldType == typeof(ushort))
|
||||
{
|
||||
size += 2;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
}
|
||||
}
|
180
Il2CppDumper/MetadataClass.cs
Normal file
180
Il2CppDumper/MetadataClass.cs
Normal file
|
@ -0,0 +1,180 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Il2CppDumper
|
||||
{
|
||||
class Il2CppGlobalMetadataHeader
|
||||
{
|
||||
public uint sanity;
|
||||
public int version;
|
||||
public int stringLiteralOffset; // string data for managed code
|
||||
public int stringLiteralCount;
|
||||
public int stringLiteralDataOffset;
|
||||
public int stringLiteralDataCount;
|
||||
public int stringOffset; // string data for metadata
|
||||
public int stringCount;
|
||||
public int eventsOffset; // Il2CppEventDefinition
|
||||
public int eventsCount;
|
||||
public int propertiesOffset; // Il2CppPropertyDefinition
|
||||
public int propertiesCount;
|
||||
public int methodsOffset; // Il2CppMethodDefinition
|
||||
public int methodsCount;
|
||||
public int parameterDefaultValuesOffset; // Il2CppParameterDefaultValue
|
||||
public int parameterDefaultValuesCount;
|
||||
public int fieldDefaultValuesOffset; // Il2CppFieldDefaultValue
|
||||
public int fieldDefaultValuesCount;
|
||||
public int fieldAndParameterDefaultValueDataOffset; // uint8_t
|
||||
public int fieldAndParameterDefaultValueDataCount;
|
||||
public int fieldMarshaledSizesOffset; // Il2CppFieldMarshaledSize
|
||||
public int fieldMarshaledSizesCount;
|
||||
public int parametersOffset; // Il2CppParameterDefinition
|
||||
public int parametersCount;
|
||||
public int fieldsOffset; // Il2CppFieldDefinition
|
||||
public int fieldsCount;
|
||||
public int genericParametersOffset; // Il2CppGenericParameter
|
||||
public int genericParametersCount;
|
||||
public int genericParameterConstraintsOffset; // TypeIndex
|
||||
public int genericParameterConstraintsCount;
|
||||
public int genericContainersOffset; // Il2CppGenericContainer
|
||||
public int genericContainersCount;
|
||||
public int nestedTypesOffset; // TypeDefinitionIndex
|
||||
public int nestedTypesCount;
|
||||
public int interfacesOffset; // TypeIndex
|
||||
public int interfacesCount;
|
||||
public int vtableMethodsOffset; // EncodedMethodIndex
|
||||
public int vtableMethodsCount;
|
||||
public int interfaceOffsetsOffset; // Il2CppInterfaceOffsetPair
|
||||
public int interfaceOffsetsCount;
|
||||
public int typeDefinitionsOffset; // Il2CppTypeDefinition
|
||||
public int typeDefinitionsCount;
|
||||
public int rgctxEntriesOffset; // Il2CppRGCTXDefinition
|
||||
public int rgctxEntriesCount;
|
||||
public int imagesOffset; // Il2CppImageDefinition
|
||||
public int imagesCount;
|
||||
public int assembliesOffset; // Il2CppAssemblyDefinition
|
||||
public int assembliesCount;
|
||||
public int metadataUsageListsOffset; // Il2CppMetadataUsageList
|
||||
public int metadataUsageListsCount;
|
||||
public int metadataUsagePairsOffset; // Il2CppMetadataUsagePair
|
||||
public int metadataUsagePairsCount;
|
||||
public int fieldRefsOffset; // Il2CppFieldRef
|
||||
public int fieldRefsCount;
|
||||
public int referencedAssembliesOffset; // int
|
||||
public int referencedAssembliesCount;
|
||||
public int attributesInfoOffset; // Il2CppCustomAttributeTypeRange
|
||||
public int attributesInfoCount;
|
||||
public int attributeTypesOffset; // TypeIndex
|
||||
public int attributeTypesCount;
|
||||
}
|
||||
|
||||
class Il2CppImageDefinition
|
||||
{
|
||||
public int nameIndex;
|
||||
public int assemblyIndex;
|
||||
|
||||
public int typeStart;
|
||||
public uint typeCount;
|
||||
|
||||
public int entryPointIndex;
|
||||
public uint token;
|
||||
}
|
||||
|
||||
public class Il2CppTypeDefinition
|
||||
{
|
||||
public int nameIndex;
|
||||
public int namespaceIndex;
|
||||
public int customAttributeIndex;
|
||||
public int byvalTypeIndex;
|
||||
public int byrefTypeIndex;
|
||||
|
||||
public int declaringTypeIndex;
|
||||
public int parentIndex;
|
||||
public int elementTypeIndex; // we can probably remove this one. Only used for enums
|
||||
|
||||
public int rgctxStartIndex;
|
||||
public int rgctxCount;
|
||||
|
||||
public int genericContainerIndex;
|
||||
|
||||
public int delegateWrapperFromManagedToNativeIndex;
|
||||
public int marshalingFunctionsIndex;
|
||||
public int ccwFunctionIndex;
|
||||
public int guidIndex;
|
||||
|
||||
public uint flags;
|
||||
|
||||
public int fieldStart;
|
||||
public int methodStart;
|
||||
public int eventStart;
|
||||
public int propertyStart;
|
||||
public int nestedTypesStart;
|
||||
public int interfacesStart;
|
||||
public int vtableStart;
|
||||
public int interfaceOffsetsStart;
|
||||
|
||||
public ushort method_count;
|
||||
public ushort property_count;
|
||||
public ushort field_count;
|
||||
public ushort event_count;
|
||||
public ushort nested_type_count;
|
||||
public ushort vtable_count;
|
||||
public ushort interfaces_count;
|
||||
public ushort interface_offsets_count;
|
||||
|
||||
// bitfield to portably encode boolean values as single bits
|
||||
// 01 - valuetype;
|
||||
// 02 - enumtype;
|
||||
// 03 - has_finalize;
|
||||
// 04 - has_cctor;
|
||||
// 05 - is_blittable;
|
||||
// 06 - is_import;
|
||||
// 07-10 - One of nine possible PackingSize values (0, 1, 2, 4, 8, 16, 32, 64, or 128)
|
||||
public uint bitfield;
|
||||
public uint token;
|
||||
}
|
||||
|
||||
public class Il2CppMethodDefinition
|
||||
{
|
||||
public int nameIndex;
|
||||
public int declaringType;
|
||||
public int returnType;
|
||||
public int parameterStart;
|
||||
public int customAttributeIndex;
|
||||
public int genericContainerIndex;
|
||||
public int methodIndex;
|
||||
public int invokerIndex;
|
||||
public int delegateWrapperIndex;
|
||||
public int rgctxStartIndex;
|
||||
public int rgctxCount;
|
||||
public uint token;
|
||||
public ushort flags;
|
||||
public ushort iflags;
|
||||
public ushort slot;
|
||||
public ushort parameterCount;
|
||||
}
|
||||
|
||||
public class Il2CppParameterDefinition
|
||||
{
|
||||
public int nameIndex;
|
||||
public uint token;
|
||||
public int customAttributeIndex;
|
||||
public int typeIndex;
|
||||
}
|
||||
|
||||
public class Il2CppFieldDefinition
|
||||
{
|
||||
public int nameIndex;
|
||||
public int typeIndex;
|
||||
public int customAttributeIndex;
|
||||
public uint token;
|
||||
}
|
||||
|
||||
public class Il2CppFieldDefaultValue
|
||||
{
|
||||
public int fieldIndex;
|
||||
public int typeIndex;
|
||||
public int dataIndex;
|
||||
}
|
||||
}
|
139
Il2CppDumper/MyBinaryReader.cs
Normal file
139
Il2CppDumper/MyBinaryReader.cs
Normal file
|
@ -0,0 +1,139 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Il2CppDumper
|
||||
{
|
||||
class MyBinaryReader : BinaryReader
|
||||
{
|
||||
public MyBinaryReader(Stream stream) : base(stream) { }
|
||||
|
||||
public long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return BaseStream.Position;
|
||||
}
|
||||
set
|
||||
{
|
||||
BaseStream.Position = value;
|
||||
}
|
||||
}
|
||||
|
||||
public T ReadClass<T>(long addr) where T : new()
|
||||
{
|
||||
BaseStream.Position = addr;
|
||||
return ReadClass<T>();
|
||||
}
|
||||
|
||||
public T ReadClass<T>() where T : new()
|
||||
{
|
||||
var type = typeof(T);
|
||||
if (type.IsPrimitive)
|
||||
{
|
||||
if (type == typeof(int))
|
||||
{
|
||||
return (T)(object)ReadInt32();
|
||||
}
|
||||
else if (type == typeof(uint))
|
||||
{
|
||||
return (T)(object)ReadUInt32();
|
||||
}
|
||||
else
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
T t = new T();
|
||||
foreach (var i in t.GetType().GetFields())
|
||||
{
|
||||
if (i.FieldType == typeof(int))
|
||||
{
|
||||
i.SetValue(t, ReadInt32());
|
||||
}
|
||||
else if (i.FieldType == typeof(uint))
|
||||
{
|
||||
i.SetValue(t, ReadUInt32());
|
||||
}
|
||||
else if (i.FieldType == typeof(short))
|
||||
{
|
||||
i.SetValue(t, ReadInt16());
|
||||
}
|
||||
else if (i.FieldType == typeof(ushort))
|
||||
{
|
||||
i.SetValue(t, ReadUInt16());
|
||||
}
|
||||
else if (i.FieldType == typeof(byte))
|
||||
{
|
||||
i.SetValue(t, ReadByte());
|
||||
}
|
||||
else
|
||||
{
|
||||
var mi = GetType().GetMethod("ReadClass", Type.EmptyTypes);
|
||||
var mi2 = mi.MakeGenericMethod(i.FieldType);
|
||||
var o = mi2.Invoke(this, null);
|
||||
i.SetValue(t, o);
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
public T[] ReadClassArray<T>(long addr, int count) where T : new()
|
||||
{
|
||||
BaseStream.Position = addr;
|
||||
var type = typeof(T);
|
||||
if (type.IsPrimitive)
|
||||
{
|
||||
if (type == typeof(int))
|
||||
{
|
||||
int[] t = new int[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
t[i] = ReadInt32();
|
||||
}
|
||||
return t as T[];
|
||||
}
|
||||
else if (type == typeof(uint))
|
||||
{
|
||||
uint[] t = new uint[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
t[i] = ReadUInt32();
|
||||
}
|
||||
return t as T[];
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
T[] t = new T[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
t[i] = ReadClass<T>();
|
||||
}
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
public string ReadStringToNull(long addr)
|
||||
{
|
||||
BaseStream.Position = addr;
|
||||
string result = "";
|
||||
char c;
|
||||
for (int i = 0; i < base.BaseStream.Length; i++)
|
||||
{
|
||||
if ((c = (char)base.ReadByte()) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
result += c.ToString();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
279
Il2CppDumper/Program.cs
Normal file
279
Il2CppDumper/Program.cs
Normal file
|
@ -0,0 +1,279 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Il2CppDumper
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static Metadata metadata;
|
||||
static Il2Cpp il2cpp;
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Select Mode: 1. Manual 2.Auto");
|
||||
var key = Console.ReadKey(true);
|
||||
try
|
||||
{
|
||||
if (key.KeyChar == '2')
|
||||
{
|
||||
metadata = new Metadata(new MemoryStream(File.ReadAllBytes("global-metadata.dat")));
|
||||
il2cpp = new Il2Cpp(new MemoryStream(File.ReadAllBytes("libil2cpp.so")));
|
||||
}
|
||||
else if (key.KeyChar == '1')
|
||||
{
|
||||
Console.Write("Input CodeRegistration(R0): ");
|
||||
var codeRegistration = Convert.ToUInt32(Console.ReadLine(), 16);
|
||||
Console.Write("Input MetadataRegistration(R1): ");
|
||||
var metadataRegistration = Convert.ToUInt32(Console.ReadLine(), 16);
|
||||
metadata = new Metadata(new MemoryStream(File.ReadAllBytes("global-metadata.dat")));
|
||||
il2cpp = new Il2Cpp(new MemoryStream(File.ReadAllBytes("libil2cpp.so")), codeRegistration, metadataRegistration);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
var writer = new StreamWriter(new FileStream("dump.cs", FileMode.Create));
|
||||
Console.WriteLine("Dumping...");
|
||||
//dump_image();
|
||||
for (int imageIndex = 0; imageIndex < metadata.uiImageCount; imageIndex++)
|
||||
{
|
||||
var imageDef = metadata.imageDefs[imageIndex];
|
||||
writer.Write($"// Image {imageIndex}: {metadata.GetString(imageDef.nameIndex)} - {imageDef.typeStart}\n");
|
||||
}
|
||||
for (int idx = 0; idx < metadata.uiNumTypes; ++idx)
|
||||
{
|
||||
//dump_class(i);
|
||||
var typeDef = metadata.typeDefs[idx];
|
||||
writer.Write($"// Namespace: {metadata.GetString(typeDef.namespaceIndex)}\n");
|
||||
if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_SERIALIZABLE) != 0)
|
||||
writer.Write("[Serializable]\n");
|
||||
if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_VISIBILITY_MASK) == DefineConstants.TYPE_ATTRIBUTE_PUBLIC)
|
||||
writer.Write("public ");
|
||||
if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_ABSTRACT) != 0)
|
||||
writer.Write("abstract ");
|
||||
if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_SEALED) != 0)
|
||||
writer.Write("sealed ");
|
||||
if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_INTERFACE) != 0)
|
||||
writer.Write("interface ");
|
||||
else
|
||||
writer.Write("class ");
|
||||
writer.Write($"{metadata.GetString(typeDef.nameIndex)} // TypeDefIndex: {idx}\n{{\n");
|
||||
writer.Write("\t// Fields\n");
|
||||
var fieldEnd = typeDef.fieldStart + typeDef.field_count;
|
||||
for (int i = typeDef.fieldStart; i < fieldEnd; ++i)
|
||||
{
|
||||
//dump_field(i, idx, i - typeDef.fieldStart);
|
||||
var pField = metadata.fieldDefs[i];
|
||||
var pType = il2cpp.GetTypeFromTypeIndex(pField.typeIndex);
|
||||
var pDefault = metadata.GetFieldDefaultFromIndex(i);
|
||||
writer.Write("\t");
|
||||
if ((pType.attrs & DefineConstants.FIELD_ATTRIBUTE_PRIVATE) == DefineConstants.FIELD_ATTRIBUTE_PRIVATE)
|
||||
writer.Write("private ");
|
||||
if ((pType.attrs & DefineConstants.FIELD_ATTRIBUTE_PUBLIC) == DefineConstants.FIELD_ATTRIBUTE_PUBLIC)
|
||||
writer.Write("public ");
|
||||
if ((pType.attrs & DefineConstants.FIELD_ATTRIBUTE_STATIC) != 0)
|
||||
writer.Write("static ");
|
||||
if ((pType.attrs & DefineConstants.FIELD_ATTRIBUTE_INIT_ONLY) != 0)
|
||||
writer.Write("readonly ");
|
||||
writer.Write($"{get_type_name(pType)} {metadata.GetString(pField.nameIndex)}");
|
||||
if (pDefault != null && pDefault.dataIndex != -1)
|
||||
{
|
||||
var pointer = metadata.GetDefaultValueFromIndex(pDefault.dataIndex);
|
||||
Il2CppType pTypeToUse = il2cpp.GetTypeFromTypeIndex(pDefault.typeIndex);
|
||||
if (pointer > 0)
|
||||
{
|
||||
metadata.Position = pointer;
|
||||
object multi = null;
|
||||
switch (pTypeToUse.type)
|
||||
{
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN:
|
||||
multi = metadata.ReadBoolean();
|
||||
break;
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_U1:
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_I1:
|
||||
multi = metadata.ReadByte();
|
||||
break;
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_CHAR:
|
||||
multi = metadata.ReadChar();
|
||||
break;
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_U2:
|
||||
multi = metadata.ReadUInt16();
|
||||
break;
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_I2:
|
||||
multi = metadata.ReadInt16();
|
||||
break;
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_U4:
|
||||
multi = metadata.ReadUInt32();
|
||||
break;
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_I4:
|
||||
multi = metadata.ReadInt32();
|
||||
break;
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_U8:
|
||||
multi = metadata.ReadUInt64();
|
||||
break;
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_I8:
|
||||
multi = metadata.ReadInt64();
|
||||
break;
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_R4:
|
||||
multi = metadata.ReadSingle();
|
||||
break;
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_R8:
|
||||
multi = metadata.ReadDouble();
|
||||
break;
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_STRING:
|
||||
var uiLen = metadata.ReadInt32();
|
||||
multi = Encoding.UTF8.GetString(metadata.ReadBytes(uiLen));
|
||||
break;
|
||||
}
|
||||
if (multi is string)
|
||||
writer.Write($" = \"{multi}\"");
|
||||
else if (multi != null)
|
||||
writer.Write($" = {multi}");
|
||||
}
|
||||
}
|
||||
writer.Write("; // 0x{0:x}\n", il2cpp.GetFieldOffsetFromIndex(idx, i - typeDef.fieldStart));
|
||||
}
|
||||
writer.Write("\t// Methods\n");
|
||||
var methodEnd = typeDef.methodStart + typeDef.method_count;
|
||||
for (int i = typeDef.methodStart; i < methodEnd; ++i)
|
||||
{
|
||||
//dump_method(i);
|
||||
var methodDef = metadata.methodDefs[i];
|
||||
writer.Write("\t");
|
||||
Il2CppType pReturnType = il2cpp.GetTypeFromTypeIndex(methodDef.returnType);
|
||||
if ((methodDef.flags & DefineConstants.METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == DefineConstants.METHOD_ATTRIBUTE_PRIVATE)
|
||||
writer.Write("private ");
|
||||
if ((methodDef.flags & DefineConstants.METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == DefineConstants.METHOD_ATTRIBUTE_PUBLIC)
|
||||
writer.Write("public ");
|
||||
if ((methodDef.flags & DefineConstants.METHOD_ATTRIBUTE_VIRTUAL) != 0)
|
||||
writer.Write("virtual ");
|
||||
if ((methodDef.flags & DefineConstants.METHOD_ATTRIBUTE_STATIC) != 0)
|
||||
writer.Write("static ");
|
||||
|
||||
writer.Write($"{get_type_name(pReturnType)} {metadata.GetString(methodDef.nameIndex)}(");
|
||||
for (int j = 0; j < methodDef.parameterCount; ++j)
|
||||
{
|
||||
Il2CppParameterDefinition pParam = metadata.parameterDefs[methodDef.parameterStart + j];
|
||||
string szParamName = metadata.GetString(pParam.nameIndex);
|
||||
Il2CppType pType = il2cpp.GetTypeFromTypeIndex(pParam.typeIndex);
|
||||
string szTypeName = get_type_name(pType);
|
||||
if ((pType.attrs & DefineConstants.PARAM_ATTRIBUTE_OPTIONAL) != 0)
|
||||
writer.Write("optional ");
|
||||
if ((pType.attrs & DefineConstants.PARAM_ATTRIBUTE_OUT) != 0)
|
||||
writer.Write("out ");
|
||||
if (j != methodDef.parameterCount - 1)
|
||||
{
|
||||
writer.Write($"{szTypeName} {szParamName}, ");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write($"{szTypeName} {szParamName}");
|
||||
}
|
||||
}
|
||||
if (methodDef.methodIndex >= 0)
|
||||
writer.Write("); // {0:x} - {1}\n", il2cpp.pCodeRegistration.methodPointers[methodDef.methodIndex], methodDef.methodIndex);
|
||||
else
|
||||
writer.Write("); // 0 - -1\n");
|
||||
}
|
||||
writer.Write("}\n");
|
||||
}
|
||||
writer.Close();
|
||||
Console.WriteLine("Done !");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e.Message);
|
||||
}
|
||||
Console.WriteLine("Press any key to exit...");
|
||||
Console.ReadKey(true);
|
||||
}
|
||||
|
||||
private static string get_type_name(Il2CppType pType)
|
||||
{
|
||||
string ret;
|
||||
if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_CLASS || pType.type == Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE)
|
||||
{
|
||||
Il2CppTypeDefinition klass = metadata.typeDefs[pType.data.klassIndex];
|
||||
ret = metadata.GetString(klass.nameIndex);
|
||||
}
|
||||
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST)
|
||||
{
|
||||
Il2CppGenericClass generic_class = il2cpp.MapVATR<Il2CppGenericClass>(pType.data.generic_class);
|
||||
Il2CppTypeDefinition pMainDef = metadata.typeDefs[generic_class.typeDefinitionIndex];
|
||||
ret = metadata.GetString(pMainDef.nameIndex);
|
||||
var typeNames = new List<string>();
|
||||
Il2CppGenericInst pInst = il2cpp.MapVATR<Il2CppGenericInst>(generic_class.context.class_inst);
|
||||
var pointers = il2cpp.MapVATR<uint>(pInst.type_argv, (int)pInst.type_argc);
|
||||
for (int i = 0; i < pInst.type_argc; ++i)
|
||||
{
|
||||
var pOriType = il2cpp.MapVATR<Il2CppType>(pointers[i]);
|
||||
pOriType.Init();
|
||||
typeNames.Add(get_type_name(pOriType));
|
||||
}
|
||||
ret += $"<{string.Join(", ", typeNames)}>";
|
||||
}
|
||||
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_ARRAY)
|
||||
{
|
||||
Il2CppArrayType arrayType = il2cpp.MapVATR<Il2CppArrayType>(pType.data.array);
|
||||
var type = il2cpp.MapVATR<Il2CppType>(arrayType.etype);
|
||||
type.Init();
|
||||
ret = $"{get_type_name(type)}[]";
|
||||
}
|
||||
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY)
|
||||
{
|
||||
var type = il2cpp.MapVATR<Il2CppType>(pType.data.type);
|
||||
type.Init();
|
||||
ret = $"{get_type_name(type)}[]";
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((int)pType.type >= szTypeString.Length)
|
||||
ret = "unknow";
|
||||
else
|
||||
ret = szTypeString[(int)pType.type];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static string[] szTypeString =
|
||||
{
|
||||
"END",
|
||||
"void",
|
||||
"bool",
|
||||
"char",
|
||||
"sbyte",
|
||||
"byte",
|
||||
"short",
|
||||
"ushort",
|
||||
"int",
|
||||
"uint",
|
||||
"long",
|
||||
"ulong",
|
||||
"float",
|
||||
"double",
|
||||
"string",
|
||||
"PTR",//eg. void*
|
||||
"BYREF",
|
||||
"VALUETYPE",
|
||||
"CLASS",
|
||||
"T",
|
||||
"ARRAY",
|
||||
"GENERICINST",
|
||||
"TYPEDBYREF",
|
||||
"None",
|
||||
"IntPtr",
|
||||
"UIntPtr",
|
||||
"None",
|
||||
"FNPTR",
|
||||
"object",
|
||||
"SZARRAY",
|
||||
"T",
|
||||
"CMOD_REQD",
|
||||
"CMOD_OPT",
|
||||
"INTERNAL",
|
||||
};
|
||||
}
|
||||
}
|
36
Il2CppDumper/Properties/AssemblyInfo.cs
Normal file
36
Il2CppDumper/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// 有关程序集的一般信息由以下
|
||||
// 控制。更改这些特性值可修改
|
||||
// 与程序集关联的信息。
|
||||
[assembly: AssemblyTitle("Il2CppDumper")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Il2CppDumper")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
//将 ComVisible 设置为 false 将使此程序集中的类型
|
||||
//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
|
||||
//请将此类型的 ComVisible 特性设置为 true。
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
|
||||
[assembly: Guid("379715d4-4b7b-41f2-b78a-8b18d86320e2")]
|
||||
|
||||
// 程序集的版本信息由下列四个值组成:
|
||||
//
|
||||
// 主版本
|
||||
// 次版本
|
||||
// 生成号
|
||||
// 修订号
|
||||
//
|
||||
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
|
||||
// 方法是按如下所示使用“*”: :
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
Loading…
Reference in a new issue