SamboyCoding / Cpp2IL

Work-in-progress tool to reverse unity's IL2CPP toolchain.
MIT License
1.66k stars 192 forks source link

Support dumped il2cpp files from memory (Android) #127

Closed AndroidMaster24 closed 2 years ago

AndroidMaster24 commented 2 years ago

It seems Cpp2IL doesn't have option to input base address. I needed to dump binary and metadata from memory in order to obtain decrypted blocks. I tried to input command but getting an error Cpp2IL.Core.SoftException: Invalid force option configuration ./Cpp2IL --game-path "path to apk file" --force-binary-path "libil2cpp-b6bf7000-bdc3d000.bin" --force-metadata-path "global-metadata.dat-a98f0000-aab42000.bin"

https://anonfiles.com/X4UbGe1by0/dumped_il2cpp_files_zip

Perfare refuse to fix the issue for 32-bit files (See https://github.com/Perfare/Il2CppDumper/issues/552), that's why I open issue here hoping you will support it. 32-bit is not dead yet, many games are still using it

SamboyCoding commented 2 years ago

The only thing you're missing in that is the unity version. Try and see if that works.

AndroidMaster24 commented 2 years ago

Is that correct?

./Cpp2IL --game-path "path to apk file" --force-binary-path "libil2cpp-b6bf7000-bdc3d000.bin" --force-metadata-path "global-metadata.dat-a98f0000-aab42000.bin" --force-unity-version 2020.3.30f1

also tried --force-unity-version "2020.3.30f1"

===Cpp2IL by Samboy063===
A Tool to Reverse Unity's "il2cpp" Build Process.

[Info] [Program] Running on Win32NT
[Warn] [Program] Using force options, I sure hope you know what you're doing!

Unhandled Exception: System.FormatException: The input string was not in a correct format.
   ved System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
   ved System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
   ved System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
   ved System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   ved System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   ved Cpp2IL.Program.GetRuntimeOptionsFromCommandLine(String[] commandLine) i E:\Github\Cpp2IL\Cpp2IL\Program.cs:linje 271
   ved Cpp2IL.Program.Main(String[] args) i E:\Github\Cpp2IL\Cpp2IL\Program.cs:linje 331
SamboyCoding commented 2 years ago

Remove the f1

AndroidMaster24 commented 2 years ago

Alright, the forcing args works now but i'm getting an error regarding binary reader. Since the binary was dumped from memory, I'm pretty sure it is needed to input base address like original Il2CppDumper

[Info] [Program] Running on Win32NT
[Warn] [Program] Using force options, I sure hope you know what you're doing!
[Info] [Library] Initializing Metadata...
[Info] [Library]        Using actual IL2CPP Metadata version 27,1
[Info] [Library] Initialized Metadata in 1626ms
[Info] [Library] Searching Binary for Required Data...

Unhandled Exception: System.ArgumentOutOfRangeException: The length of the stream must not be negative and must be less than 2^31 - 1 - origin.
Parameter name: value
   ved System.IO.MemoryStream.set_Position(Int64 value)
   ved LibCpp2IL.ClassReadingBinaryReader.set_Position(Int64 value) i E:\Github\Cpp2IL\LibCpp2IL\ClassReadingBinaryReader.cs:linje 30
   ved LibCpp2IL.ClassReadingBinaryReader.ReadStringToNull(Int64 offset) i E:\Github\Cpp2IL\LibCpp2IL\ClassReadingBinaryReader.cs:linje 277
   ved LibCpp2IL.ClassReadingBinaryReader.ReadStringToNull(UInt64 offset) i E:\Github\Cpp2IL\LibCpp2IL\ClassReadingBinaryReader.cs:linje 263
   ved LibCpp2IL.Elf.ElfFile..ctor(MemoryStream input, Int64 maxMetadataUsages) i E:\Github\Cpp2IL\LibCpp2IL\Elf\ElfFile.cs:linje 70
   ved LibCpp2IL.LibCpp2IlMain.Initialize(Byte[] binaryBytes, Byte[] metadataBytes, Int32[] unityVersion) i E:\Github\Cpp2IL\LibCpp2IL\LibCpp2IlMain.cs:linje 169
   ved LibCpp2IL.LibCpp2IlMain.LoadFromFile(String pePath, String metadataPath, Int32[] unityVersion) i E:\Github\Cpp2IL\LibCpp2IL\LibCpp2IlMain.cs:linje 248
   ved Cpp2IL.Core.Cpp2IlApi.InitializeLibCpp2Il(String assemblyPath, String metadataPath, Int32[] unityVersion, Boolean allowUserToInputAddresses) i E:\Github\Cpp2IL\Cpp2IL.Core\Cpp2IlApi.cs:linje 182
   ved Cpp2IL.Program.MainWithArgs(Cpp2IlRuntimeArgs runtimeArgs) i E:\Github\Cpp2IL\Cpp2IL\Program.cs:linje 385
   ved Cpp2IL.Program.Main(String[] args) i E:\Github\Cpp2IL\Cpp2IL\Program.cs:linje 333
ChaomengCFX commented 2 years ago

Alright, the forcing args works now but i'm getting an error regarding binary reader. Since the binary was dumped from memory, I'm pretty sure it is needed to input base address like original Il2CppDumper

[Info] [Program] Running on Win32NT
[Warn] [Program] Using force options, I sure hope you know what you're doing!
[Info] [Library] Initializing Metadata...
[Info] [Library]        Using actual IL2CPP Metadata version 27,1
[Info] [Library] Initialized Metadata in 1626ms
[Info] [Library] Searching Binary for Required Data...

Unhandled Exception: System.ArgumentOutOfRangeException: The length of the stream must not be negative and must be less than 2^31 - 1 - origin.
Parameter name: value
   ved System.IO.MemoryStream.set_Position(Int64 value)
   ved LibCpp2IL.ClassReadingBinaryReader.set_Position(Int64 value) i E:\Github\Cpp2IL\LibCpp2IL\ClassReadingBinaryReader.cs:linje 30
   ved LibCpp2IL.ClassReadingBinaryReader.ReadStringToNull(Int64 offset) i E:\Github\Cpp2IL\LibCpp2IL\ClassReadingBinaryReader.cs:linje 277
   ved LibCpp2IL.ClassReadingBinaryReader.ReadStringToNull(UInt64 offset) i E:\Github\Cpp2IL\LibCpp2IL\ClassReadingBinaryReader.cs:linje 263
   ved LibCpp2IL.Elf.ElfFile..ctor(MemoryStream input, Int64 maxMetadataUsages) i E:\Github\Cpp2IL\LibCpp2IL\Elf\ElfFile.cs:linje 70
   ved LibCpp2IL.LibCpp2IlMain.Initialize(Byte[] binaryBytes, Byte[] metadataBytes, Int32[] unityVersion) i E:\Github\Cpp2IL\LibCpp2IL\LibCpp2IlMain.cs:linje 169
   ved LibCpp2IL.LibCpp2IlMain.LoadFromFile(String pePath, String metadataPath, Int32[] unityVersion) i E:\Github\Cpp2IL\LibCpp2IL\LibCpp2IlMain.cs:linje 248
   ved Cpp2IL.Core.Cpp2IlApi.InitializeLibCpp2Il(String assemblyPath, String metadataPath, Int32[] unityVersion, Boolean allowUserToInputAddresses) i E:\Github\Cpp2IL\Cpp2IL.Core\Cpp2IlApi.cs:linje 182
   ved Cpp2IL.Program.MainWithArgs(Cpp2IlRuntimeArgs runtimeArgs) i E:\Github\Cpp2IL\Cpp2IL\Program.cs:linje 385
   ved Cpp2IL.Program.Main(String[] args) i E:\Github\Cpp2IL\Cpp2IL\Program.cs:linje 333

After modifying the constructor of ELF file class, I successfully dumped the il2cpp file from memory (unity 2017.4.39f1, il2cpp version 24, x86, Android)

The main modifications I made are as follows:

Manually set the value of _globalOffsett to the dump position, and set a bool called _isDump to true

In after _globaloffset is assigned, add (You need to modify the access permissions of IElfProgramHeaderEntry's attribute)

            if (_isDump)
            {
                for (int i = 0; i < _elfProgramHeaderEntries!.Count; i++)
                {
                    Position = _elfHeader!.pProgramHeader + (is32Bit ? i * 32u + 4u : i * 56u + 8u);
                    var phdr = _elfProgramHeaderEntries[i];
                    phdr.RawAddress = phdr.VirtualAddress;
                    phdr.VirtualAddress += (ulong)_globalOffset;
                    Position += is32Bit ? 4 : 8;
                    phdr.RawSize = phdr.VirtualSize;
                }
            }

In after dynamicsection is assigned, add

                if (_isDump)
                {
                    for (int i = 0; i < _dynamicSection.Count; i++)
                    {
                        Position = (long)dynamicSegment.RawAddress + (is32Bit ? i * 8 + 4 : i * 16 + 8);
                        var dyn = _dynamicSection[i];
                        switch (dyn.Tag)
                        {
                            case ElfDynamicType.DT_PLTGOT:
                            case ElfDynamicType.DT_HASH:
                            case ElfDynamicType.DT_STRTAB:
                            case ElfDynamicType.DT_SYMTAB:
                            case ElfDynamicType.DT_RELA:
                            case ElfDynamicType.DT_INIT:
                            case ElfDynamicType.DT_FINI:
                            case ElfDynamicType.DT_REL:
                            case ElfDynamicType.DT_JMPREL:
                            case ElfDynamicType.DT_INIT_ARRAY:
                            case ElfDynamicType.DT_FINI_ARRAY:
                                dyn.Value += (ulong)_globalOffset;
                                break;
                        }
                    }
                }

and modified ProcessRelocations

            if (!_isDump)
            {
                LibLogger.VerboseNewline("\tFinding Relocations...");
                start = DateTime.Now;

                ProcessRelocations();

                LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
            }

In fact, because il2cpp files are encrypted, I also made some other modifications. Finally, it worked. I hope it will help you.

SamboyCoding commented 2 years ago

Glad you got it working

AndroidMaster24 commented 2 years ago

@jxr2006 Thanks, i'll see what I can do with this. Do you mind making pull request of this changes?

krulci commented 10 months ago

Alright, the forcing args works now but i'm getting an error regarding binary reader. Since the binary was dumped from memory, I'm pretty sure it is needed to input base address like original Il2CppDumper

[Info] [Program] Running on Win32NT
[Warn] [Program] Using force options, I sure hope you know what you're doing!
[Info] [Library] Initializing Metadata...
[Info] [Library]        Using actual IL2CPP Metadata version 27,1
[Info] [Library] Initialized Metadata in 1626ms
[Info] [Library] Searching Binary for Required Data...

Unhandled Exception: System.ArgumentOutOfRangeException: The length of the stream must not be negative and must be less than 2^31 - 1 - origin.
Parameter name: value
   ved System.IO.MemoryStream.set_Position(Int64 value)
   ved LibCpp2IL.ClassReadingBinaryReader.set_Position(Int64 value) i E:\Github\Cpp2IL\LibCpp2IL\ClassReadingBinaryReader.cs:linje 30
   ved LibCpp2IL.ClassReadingBinaryReader.ReadStringToNull(Int64 offset) i E:\Github\Cpp2IL\LibCpp2IL\ClassReadingBinaryReader.cs:linje 277
   ved LibCpp2IL.ClassReadingBinaryReader.ReadStringToNull(UInt64 offset) i E:\Github\Cpp2IL\LibCpp2IL\ClassReadingBinaryReader.cs:linje 263
   ved LibCpp2IL.Elf.ElfFile..ctor(MemoryStream input, Int64 maxMetadataUsages) i E:\Github\Cpp2IL\LibCpp2IL\Elf\ElfFile.cs:linje 70
   ved LibCpp2IL.LibCpp2IlMain.Initialize(Byte[] binaryBytes, Byte[] metadataBytes, Int32[] unityVersion) i E:\Github\Cpp2IL\LibCpp2IL\LibCpp2IlMain.cs:linje 169
   ved LibCpp2IL.LibCpp2IlMain.LoadFromFile(String pePath, String metadataPath, Int32[] unityVersion) i E:\Github\Cpp2IL\LibCpp2IL\LibCpp2IlMain.cs:linje 248
   ved Cpp2IL.Core.Cpp2IlApi.InitializeLibCpp2Il(String assemblyPath, String metadataPath, Int32[] unityVersion, Boolean allowUserToInputAddresses) i E:\Github\Cpp2IL\Cpp2IL.Core\Cpp2IlApi.cs:linje 182
   ved Cpp2IL.Program.MainWithArgs(Cpp2IlRuntimeArgs runtimeArgs) i E:\Github\Cpp2IL\Cpp2IL\Program.cs:linje 385
   ved Cpp2IL.Program.Main(String[] args) i E:\Github\Cpp2IL\Cpp2IL\Program.cs:linje 333

After modifying the constructor of ELF file class, I successfully dumped the il2cpp file from memory (unity 2017.4.39f1, il2cpp version 24, x86, Android)

The main modifications I made are as follows:

Manually set the value of _globalOffsett to the dump position, and set a bool called _isDump to true

In after _globaloffset is assigned, add (You need to modify the access permissions of IElfProgramHeaderEntry's attribute)

            if (_isDump)
            {
                for (int i = 0; i < _elfProgramHeaderEntries!.Count; i++)
                {
                    Position = _elfHeader!.pProgramHeader + (is32Bit ? i * 32u + 4u : i * 56u + 8u);
                    var phdr = _elfProgramHeaderEntries[i];
                    phdr.RawAddress = phdr.VirtualAddress;
                    phdr.VirtualAddress += (ulong)_globalOffset;
                    Position += is32Bit ? 4 : 8;
                    phdr.RawSize = phdr.VirtualSize;
                }
            }

In after dynamicsection is assigned, add

                if (_isDump)
                {
                    for (int i = 0; i < _dynamicSection.Count; i++)
                    {
                        Position = (long)dynamicSegment.RawAddress + (is32Bit ? i * 8 + 4 : i * 16 + 8);
                        var dyn = _dynamicSection[i];
                        switch (dyn.Tag)
                        {
                            case ElfDynamicType.DT_PLTGOT:
                            case ElfDynamicType.DT_HASH:
                            case ElfDynamicType.DT_STRTAB:
                            case ElfDynamicType.DT_SYMTAB:
                            case ElfDynamicType.DT_RELA:
                            case ElfDynamicType.DT_INIT:
                            case ElfDynamicType.DT_FINI:
                            case ElfDynamicType.DT_REL:
                            case ElfDynamicType.DT_JMPREL:
                            case ElfDynamicType.DT_INIT_ARRAY:
                            case ElfDynamicType.DT_FINI_ARRAY:
                                dyn.Value += (ulong)_globalOffset;
                                break;
                        }
                    }
                }

and modified ProcessRelocations

            if (!_isDump)
            {
                LibLogger.VerboseNewline("\tFinding Relocations...");
                start = DateTime.Now;

                ProcessRelocations();

                LibLogger.VerboseNewline($"OK ({(DateTime.Now - start).TotalMilliseconds} ms)");
            }

In fact, because il2cpp files are encrypted, I also made some other modifications. Finally, it worked. I hope it will help you.

能不能push一下这个到独立的fork?