ELF: Detect and defeat trivial XOR encryption

This commit is contained in:
Katy Coe
2020-02-08 11:58:09 +01:00
parent b9061e573b
commit 5652e89abe
2 changed files with 41 additions and 2 deletions

View File

@@ -10,6 +10,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text;
namespace Il2CppInspector namespace Il2CppInspector
{ {
@@ -108,6 +109,7 @@ namespace Il2CppInspector
private elf_shdr<TWord>[] section_header_table; private elf_shdr<TWord>[] section_header_table;
private elf_dynamic<TWord>[] dynamic_table; private elf_dynamic<TWord>[] dynamic_table;
private elf_header<TWord> elf_header; private elf_header<TWord> elf_header;
private Dictionary<string, elf_shdr<TWord>> sectionByName = new Dictionary<string, elf_shdr<TWord>>();
public ElfReader(Stream stream) : base(stream) { } public ElfReader(Stream stream) : base(stream) { }
@@ -139,13 +141,22 @@ namespace Il2CppInspector
if ((Elf) elf_header.m_dwFormat != Elf.ELFMAG) if ((Elf) elf_header.m_dwFormat != Elf.ELFMAG)
return false; return false;
// 64-bit not supported // Ensure supported architecture
if ((Elf) elf_header.m_arch != ArchClass) if ((Elf) elf_header.m_arch != ArchClass)
return false; return false;
// Get PHT and SHT
program_header_table = ReadArray<TPHdr>(conv.Long(elf_header.e_phoff), elf_header.e_phnum); program_header_table = ReadArray<TPHdr>(conv.Long(elf_header.e_phoff), elf_header.e_phnum);
section_header_table = ReadArray<elf_shdr<TWord>>(conv.Long(elf_header.e_shoff), elf_header.e_shnum); section_header_table = ReadArray<elf_shdr<TWord>>(conv.Long(elf_header.e_shoff), elf_header.e_shnum);
// Get section name mappings
var pStrtab = section_header_table[elf_header.e_shtrndx].sh_offset;
foreach (var section in section_header_table) {
var name = ReadNullTerminatedString(conv.Long(pStrtab) + section.sh_name);
sectionByName.Add(name, section);
}
// Get dynamic table if it exists
if (getProgramHeader(Elf.PT_DYNAMIC) is TPHdr PT_DYNAMIC) if (getProgramHeader(Elf.PT_DYNAMIC) is TPHdr PT_DYNAMIC)
dynamic_table = ReadArray<elf_dynamic<TWord>>(conv.Long(PT_DYNAMIC.p_offset), (int) (conv.Long(PT_DYNAMIC.p_filesz) / Sizeof(typeof(elf_dynamic<TWord>)))); dynamic_table = ReadArray<elf_dynamic<TWord>>(conv.Long(PT_DYNAMIC.p_offset), (int) (conv.Long(PT_DYNAMIC.p_filesz) / Sizeof(typeof(elf_dynamic<TWord>))));
@@ -187,7 +198,7 @@ namespace Il2CppInspector
if (BaseStream is FileStream) if (BaseStream is FileStream)
throw new InvalidOperationException("Input stream to ElfReader is a file. Please supply a mutable stream source."); throw new InvalidOperationException("Input stream to ElfReader is a file. Please supply a mutable stream source.");
var writer = new BinaryWriter(BaseStream); using var writer = new BinaryWriter(BaseStream, Encoding.Default, true);
var relsz = Sizeof(typeof(TSym)); var relsz = Sizeof(typeof(TSym));
foreach (var rel in rels) { foreach (var rel in rels) {
@@ -236,9 +247,36 @@ namespace Il2CppInspector
} }
Console.WriteLine($"Processed {rels.Count} relocations"); Console.WriteLine($"Processed {rels.Count} relocations");
// Detect and defeat trivial XOR encryption
if (dynamic_table.Any(d => (Elf) conv.Int(d.d_tag) == Elf.DT_INIT)) {
var rodataFirstBytes = ReadArray<byte>(conv.Long(sectionByName[".rodata"].sh_offset), 256);
var xorKey = rodataFirstBytes.GroupBy(b => b).OrderByDescending(f => f.Count()).First().Key;
if (xorKey != 0x00) {
Console.WriteLine($"Performing trivial XOR decryption (key: 0x{xorKey:X2})");
xorSection(".text", xorKey);
xorSection(".rodata", xorKey);
}
}
return true; return true;
} }
private void xorRange(int offset, int length, byte xorValue) {
using var writer = new BinaryWriter(BaseStream, Encoding.Default, true);
var bytes = ReadArray<byte>(offset, length);
bytes = bytes.Select(b => (byte) (b ^ xorValue)).ToArray();
writer.Seek(offset, SeekOrigin.Begin);
writer.Write(bytes);
}
private void xorSection(string sectionName, byte xorValue) {
var section = sectionByName[sectionName];
xorRange(conv.Int(section.sh_offset), conv.Int(section.sh_size), xorValue);
}
public override Dictionary<string, ulong> GetSymbolTable() { public override Dictionary<string, ulong> GetSymbolTable() {
// Three possible symbol tables in ELF files // Three possible symbol tables in ELF files
var pTables = new List<(TWord offset, TWord count, TWord strings)>(); var pTables = new List<(TWord offset, TWord count, TWord strings)>();

View File

@@ -45,6 +45,7 @@ namespace Il2CppInspector
DT_RELA = 7, DT_RELA = 7,
DT_RELASZ = 8, DT_RELASZ = 8,
DT_RELAENT = 9, DT_RELAENT = 9,
DT_INIT = 12,
DT_REL = 17, DT_REL = 17,
DT_RELSZ = 18, DT_RELSZ = 18,
DT_RELENT = 19, DT_RELENT = 19,