Skip to content

[Question] Exception while parsing global-metadata.dat of protected game + semi-guide for protected il2cpp.so #415

Description

@quangvnm

Hello,

First of all, thank you very much for your effort, I have used your util till now to dump and made several game wiki by analyzing game mechanism. It works great. Recently, I have some trouble to crack on one protected game that I detailed below.

  • Il2CppDumper version: v6.4.19

  • Target Unity version:

Metadata Version Il2Cpp Version Change il2cpp version to
24.2 24.2 24.3
  • Describe the issue:

The first time I tried to use Il2CppDumper on this game, it told me that il2cpp is protected. So I fired up root mode over adb and dump the binary directly (I think this should obtain the same results as with GG):

# grep -C3 il2cpp.so /proc/<game-id>/maps
735abf1000-735acf1000 r--p 00000000 b3:18 2285                           /system/lib64/libc.so
735acf1000-735acf2000 ---p 00000000 00:00 0                              [anon:thread stack guard page]
735acf2000-735adee000 rw-p 00000000 00:00 0                              [stack:20137]
735adee000-735e183000 r--p 00000000 fd:00 1060248                        /data/app/com.xxx/lib/arm64/libil2cpp.so
735e183000-735e184000 ---p 00000000 00:00 0                              [anon:thread stack guard page]
735e184000-735e185000 ---p 00000000 00:00 0 
735e185000-735e288000 rw-p 00000000 00:00 0                              [stack:20133]
--
7499496000-7499497000 ---p 00000000 00:00 0                              [anon:thread stack guard page]
7499497000-7499498000 ---p 00000000 00:00 0 
7499498000-7499593000 rw-p 00000000 00:00 0                              [stack:20053]
7499593000-7499f6a000 r-xp 00000000 fd:00 1060248                        /data/app/com.xxx/lib/arm64/libil2cpp.so
7499f6a000-749bc82000 r-xp 009d7000 fd:00 1060248                        /data/app/com.xxx/lib/arm64/libil2cpp.so
749bc82000-749c529000 r-xp 026ef000 fd:00 1060248                        /data/app/com.xxx/lib/arm64/libil2cpp.so
749c529000-749c538000 ---p 00000000 00:00 0 
749c538000-749c938000 rw-p 02f95000 fd:00 1060248                        /data/app/com.xxx/lib/arm64/libil2cpp.so
749c938000-749cbbb000 rw-p 00000000 00:00 0                              [anon:.bss]
749cbc4000-749cbd4000 rw-s 00000000 00:01 293721                         /dev/ashmem/shared_memory/168F74D06DBD03DD0ACF9AF489CA4D41 (deleted)

The first il2cpp.so (from 0x735adee000 to 735e183000) should be the original (unpacked) file. I dumped that memory region and compare with the original and my assumption is correct.
The second il2cpp.so spans over several region (from 0x7499593000 to 0x749cbc4000, .bss included) is the unpacked file. I dumped that region with

# dd if=/proc/<game-id>/mem of=/sdcard/libil2cpp.so bs=4096 skip=122262931 count=13873

and verify with IDA that the executable segment is much more readable compare to some bogus data from the first file.


The second il2cpp.so doesn't contain Section Header Table(SHT) though 😢

$ readelf -S libil2cpp.so
There are 8 section headers, starting at offset 0x3394770:
readelf: Warning: Section 0 has an out of range sh_link value of 2605427684
readelf: Warning: Section 0 has an out of range sh_info value of 116
readelf: Warning: Section 1 has an out of range sh_link value of 2605428576
readelf: Warning: Section 2 has an out of range sh_link value of 2605428640
readelf: Warning: Section 3 has an out of range sh_link value of 2605428704
readelf: Warning: Section 3 has an out of range sh_info value of 116
readelf: Warning: Section 4 has an out of range sh_link value of 2605428768
readelf: Warning: Section 5 has an out of range sh_link value of 2605428832
readelf: Warning: Section 5 has an out of range sh_info value of 116
readelf: Warning: Section 6 has an out of range sh_link value of 2605429392
readelf: Warning: Section 7 has an out of range sh_link value of 2601189312
readelf: Error: Reading 500817395640 bytes extends past end of file for string table

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
readelf: Warning: [ 0]: Expected link to another section in info fieldreadelf: Warning: Size of section 0 is larger than the entire file!
  [ 0] <no-strings>      00000074: <unkn  000000749b4babcc  749b4babd4
       000000749b4babdc  000000749b4b5e44 XILOGCxxxxxop      2605427684   116     500821634028
readelf: Warning: Size of section 1 is larger than the entire file!
  [ 1] <no-strings>      00000074: <unkn  000000749b4baf48  749b4baf50
       000000749b4baf58  000000749b4baf70 XxMSLOTCxxxxxop      2605428576   116     500821634920
readelf: Warning: Size of section 2 is larger than the entire file!
  [ 2] <no-strings>      00000074: <unkn  000000749b4baf88  749b4baf90
       000000749b4baf98  000000749b4bafb0 LOGTCxxxxxop      2605428640   116     500821634984
readelf: Warning: [ 3]: Expected link to another section in info fieldreadelf: Warning: Size of section 3 is larger than the entire file!
  [ 3] <no-strings>      00000074: <unkn  000000749b4bafc8  749b4bafd0
       000000749b4bafd8  000000749b4baff0 ILOGTCxxxxxop      2605428704   116     500821635048
readelf: Warning: Size of section 4 is larger than the entire file!
  [ 4] <no-strings>      00000074: <unkn  000000749b4bb008  749b4bb010
       000000749b4bb018  000000749b4bb030 xxxxxxop      2605428768   116     500821635112
readelf: Warning: [ 5]: Expected link to another section in info fieldreadelf: Warning: Size of section 5 is larger than the entire file!
  [ 5] <no-strings>      00000074: <unkn  000000749b4bb048  749b4bb050
       000000749b4bb058  000000749b4bb070 Ixxxxxxop      2605428832   116     500821635176
readelf: Warning: Size of section 6 is larger than the entire file!
  [ 6] <no-strings>      00000074: <unkn  000000749b4b5aac  749b4b5b38
       000000749b4bb088  000000749b0aff90 Lxxxxxxop      2605429392   116     500817395592
readelf: Warning: Size of section 7 is larger than the entire file!
  [ 7] <no-strings>      00000074: <unkn  000000749b0affa8  749b0affb0
       000000749b0affb8  000000749b0affd0 SLOGTCxxxxxxDop      2601189312   116     500817395656
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  p (processor specific)
readelf: Error: no .dynamic section in the dynamic segment

When I tried Il2CppDumper, it failed because it couldn't find the .text section and reports that this unpacked binary is a dump file. As the Section Header Table is optional in runtime, maybe the unpacker wipes that region or doesn't include it in final unpacked file. Time to rebuild that SHT.

I used another tool to rebuild that table, including various fixes: https://github.com/maiyao1988/elf-dump-fix

$ ./sofix libil2cpp.so 0 unpacked_libil2cpp.so

The tool isn't perfect and it made some assumptions, especially, it couldn't guess the ".text" section, because it couldn't find out the ARM_EXIDX section

$ readelf -lSW unpacked_libil2cpp.so
There are 16 section headers, starting at offset 0x362808e:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .dynsym           DYNSYM          00000000000048b0 0048b0 00e7c0 18   A  2   1  8
  [ 2] .dynstr           STRTAB          0000000000013070 013070 019cbe 00   A  0   0  1
  [ 3] .hash             HASH            00000000000001f0 0001f0 0046bc 04   A  1   0  8
  [ 4] .rela.dyn         RELA            000000000002e0e0 02e0e0 9a45c8 18   A  1   0  8
  [ 5] .rela.plt         RELA            00000000009d26a8 9d26a8 0031c8 18   A  1   6  8
  [ 6] .plt              PROGBITS        00000000009d5870 9d5870 002150 00  AX  0   0 16
  [ 7]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 8]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 9] .fini_array       FINI_ARRAY      0000000002fa5840 2fa5840 000010 00  WA  0   0  8
  [10] .init_array       INIT_ARRAY      0000000002fa57f8 2fa57f8 000000 00  WA  0   0  8
  [11] .dynamic          DYNAMIC         000000000315ee58 315ee58 0001e0 10  WA  2   0  8
  [12] .got              PROGBITS        000000000315f038 315f038 0bbfc8 00  WA  0   0  8
  [13] .data             PROGBITS        000000000321b000 321b000 40cf30 00  WA  0   0  8
  [14]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [15] .shstrtab         STRTAB          0000000000000000 3628000 00008e 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  p (processor specific)

Elf file type is DYN (Shared object file)
Entry point 0x0
There are 7 program headers, starting at offset 64

Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x2f957f8 0x2f957f8 R E 0x10000
  LOAD           0x2fa57f8 0x0000000002fa57f8 0x0000000002fa57f8 0x682738 0x682738 RW  0x10000
  DYNAMIC        0x315ee58 0x000000000315ee58 0x000000000315ee58 0x0001e0 0x0001e0 RW  0x8
  NOTE           0x0001c8 0x00000000000001c8 0x00000000000001c8 0x000024 0x000024 R   0x4
  NOTE           0x2f95760 0x0000000002f95760 0x0000000002f95760 0x000098 0x000098 R   0x4
  GNU_EH_FRAME   0x2979680 0x0000000002979680 0x0000000002979680 0x10fcb4 0x10fcb4 R   0x4
  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10

 Section to Segment mapping:
  Segment Sections...
   00     .dynsym .dynstr .hash .rela.dyn .rela.plt .plt 
   01     .fini_array .init_array .dynamic .got .data 
   02     .dynamic 
   03     
   04     
   05     
   06     

Every executable needs at least two section: .text and .data, so we need to fill this. Based on the execution flags/bits on memory maps and/or the Program Headers. I patch the binary to include the .text section and finally:

$ readelf -lhSW unpacked_libil2cpp.so
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           AArch64
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          64 (bytes into file)
  Start of section headers:          56787086 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         7
  Size of section headers:           64 (bytes)
  Number of section headers:         16
  Section header string table index: 15

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .dynsym           DYNSYM          00000000000048b0 0048b0 00e7c0 18   A  2   1  8
  [ 2] .dynstr           STRTAB          0000000000013070 013070 019cbe 00   A  0   0  1
  [ 3] .hash             HASH            00000000000001f0 0001f0 0046bc 04   A  1   0  8
  [ 4] .rela.dyn         RELA            000000000002e0e0 02e0e0 9a45c8 18   A  1   0  8
  [ 5] .rela.plt         RELA            00000000009d26a8 9d26a8 0031c8 18   A  1   6  8
  [ 6] .plt              PROGBITS        00000000009d5870 9d5870 002150 00  AX  0   0 16
  [ 7] .text             PROGBITS        00000000009d79c0 9d79c0 25bd640 00  AX  0   0  0
  [ 8]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 9] .fini_array       FINI_ARRAY      0000000002fa5840 2fa5840 000010 00  WA  0   0  8
  [10] .init_array       INIT_ARRAY      0000000002fa57f8 2fa57f8 000000 00  WA  0   0  8
  [11] .dynamic          DYNAMIC         000000000315ee58 315ee58 0001e0 10  WA  2   0  8
  [12] .got              PROGBITS        000000000315f038 315f038 0bbfc8 00  WA  0   0  8
  [13] .data             PROGBITS        000000000321b000 321b000 40cf30 00  WA  0   0  8
  [14]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [15] .shstrtab         STRTAB          0000000000000000 3628000 00008e 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  p (processor specific)

Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x2f957f8 0x2f957f8 R E 0x10000
  LOAD           0x2fa57f8 0x0000000002fa57f8 0x0000000002fa57f8 0x682738 0x682738 RW  0x10000
  DYNAMIC        0x315ee58 0x000000000315ee58 0x000000000315ee58 0x0001e0 0x0001e0 RW  0x8
  NOTE           0x0001c8 0x00000000000001c8 0x00000000000001c8 0x000024 0x000024 R   0x4
  NOTE           0x2f95760 0x0000000002f95760 0x0000000002f95760 0x000098 0x000098 R   0x4
  GNU_EH_FRAME   0x2979680 0x0000000002979680 0x0000000002979680 0x10fcb4 0x10fcb4 R   0x4
  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10

 Section to Segment mapping:
  Segment Sections...
   00     .dynsym .dynstr .hash .rela.dyn .rela.plt .plt .text 
   01     .fini_array .init_array .dynamic .got .data 
   02     .dynamic 
   03     
   04     
   05     
   06     

There are still some missing section but I think it is enough to launch the IDA and Il2CppDumper.


But I'm currently blocked on parsing global-metadata.dat. There are lots of Out of Bound exceptions, the dump.cs has some class and methods but it isn't exploitable:

Initializing metadata...
Metadata Version: 24.2
Initializing il2cpp file...
Applying relocations...
Il2Cpp Version: 24.2
Searching...
Change il2cpp version to: 24.3
CodeRegistration : 3158650
MetadataRegistration : 3158cd0
Dumping...
ERROR: Some errors in dumping
...
<TRUNCATED>
...
ERROR: Some errors in dumping
Done!
Generate script...
System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at Il2CppDumper.Il2CppExecutor.GetTypeDefName(Il2CppTypeDefinition typeDef, Boolean addNamespace, Boolean genericParameter) in C:\projects\il2cppdumper\Il2CppDumper\Utils\Il2CppExecutor.cs:line 146
   at Il2CppDumper.ScriptGenerator.CreateStructNameDic(Il2CppTypeDefinition typeDef) in C:\projects\il2cppdumper\Il2CppDumper\Outputs\ScriptGenerator.cs:line 710
   at Il2CppDumper.ScriptGenerator.WriteScript(String outputDir) in C:\projects\il2cppdumper\Il2CppDumper\Outputs\ScriptGenerator.cs:line 48
   at Il2CppDumper.Program.Dump(Metadata metadata, Il2Cpp il2Cpp, String outputDir) in C:\projects\il2cppdumper\Il2CppDumper\Program.cs:line 241
   at Il2CppDumper.Program.Main(String[] args) in C:\projects\il2cppdumper\Il2CppDumper\Program.cs:line 96

The files dump.cs:

//...
// Image 50: LitJson.dll - 8009
// Image 51: ACTk.Examples.Genuine.Runtime.dll - 8034
// Image 52: ACTk.Examples.Runtime.dll - 8038
// Image 53: Assembly-CSharp-firstpass.dll - 8051
// Image 54: Assembly-CSharp.dll - 8253

// Namespace: 
internal class nvitationInboxUI // TypeDefIndex: 0
{}

// Namespace: 
internal sealed class Locale // TypeDefIndex: 1
{
	// Methods

	// RVA: 0x202A860 Offset: 0x202A860 VA: 0x202A860
	public static string (string msg) { }

/*System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at Il2CppDumper.Il2Cpp.GetMethodPointer(String imageName, Il2CppMethodDefinition methodDef) in C:\projects\il2cppdumper\Il2CppDumper\Il2Cpp\Il2Cpp.cs:line 242
   at Il2CppDumper.Il2CppDecompiler.Decompile(Config config, String outputDir) in C:\projects\il2cppdumper\Il2CppDumper\Outputs\Il2CppDecompiler.cs:line 245*/
}

// Namespace: 
internal class <Module> // TypeDefIndex: 1670
{}

// Namespace: System.Configuration
public abstract class ConfigurationSection : ConfigurationElement // TypeDefIndex: 1671
{
	// Methods

	// RVA: 0x26EC2D8 Offset: 0x26EC2D8 VA: 0x26EC2D8 Slot: 13
	protected internal virtual void DeserializeSection(XmlReader reader) { }

	// RVA: 0x26EC318 Offset: 0x26EC318 VA: 0x26EC318 Slot: 7
	protected internal override bool IsModified() { }

	// RVA: 0x26EC358 Offset: 0x26EC358 VA: 0x26EC358 Slot: 10
	abstract extern void ResetModified() { }

	// RVA: 0x26EC398 Offset: 0x26EC398 VA: 0x26EC398 Slot: 14
	protected internal virtual string SerializeSection(ConfigurationElement parentElement, string name, ConfigurationSaveMode saveMode) { }

	// RVA: 0x26EBFD8 Offset: 0x26EBFD8 VA: 0x26EBFD8 Slot: 4
	protected internal virtual /*System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at Il2CppDumper.Il2CppExecutor.GetTypeName(Il2CppType il2CppType, Boolean addNamespace, Boolean is_nested) in C:\projects\il2cppdumper\Il2CppDumper\Utils\Il2CppExecutor.cs:line 58
   at Il2CppDumper.Il2CppDecompiler.Decompile(Config config, String outputDir) in C:\projects\il2cppdumper\Il2CppDumper\Outputs\Il2CppDecompiler.cs:line 276*/
}
/*System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at Il2CppDumper.Il2CppDecompiler.Decompile(Config config, String outputDir) in C:\projects\il2cppdumper\Il2CppDumper\Outputs\Il2CppDecompiler.cs:line 73*/
}
//...

Based on my diagnostic, lots of method/class names aren't obfuscated in global-metadata.dat, so maybe game devs didn't use an obfuscator. But while trying to debug Il2CppDumper (with VSCode + .NET SDK) with these files, I got that the offset for several names, pointers, .. is wrong in global-metadata.dat, in a sense that it points to something out of metadata file or bogus data, what make me wonder is that some Definition got decoded correctly (pointer to correct names, addresses ..). So I got stuck and don't know if this is due to a change of global-metadat.dat format from Unity team or some kind of game protector?

Or maybe I made some mistake in my assumptions?

I guess if this is some custom game protector, that will be a won't fix, but if you have some insights on this, I'm glad if you can advise me how to rebuild that global-metadata.dat?

  • Upload executable file and global-metadata.dat:

files.zip

Thank you very much,

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions