UNPKG

frida-il2cpp-bridge-my

Version:

(my:Support IOS)Frida module to dump, manipulate and hijack any IL2CPP application at runtime with a high level of abstraction.

310 lines (309 loc) 13.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.dump = exports.allocRawValue = exports.readRawValue = exports.writeFieldValue = exports.readFieldValue = exports.getOrNull = void 0; const console_1 = require("../utils/console"); const variables_1 = require("./variables"); const array_1 = require("./structs/array"); const object_1 = require("./structs/object"); const string_1 = require("./structs/string"); const value_type_1 = require("./structs/value-type"); const type_enum_1 = require("./structs/type-enum"); function getOrNull(handle, Class) { return handle.isNull() ? null : new Class(handle); } exports.getOrNull = getOrNull; function isCoherent(value, type) { switch (type.typeEnum) { case type_enum_1._Il2CppTypeEnum.VOID: return value == undefined; case type_enum_1._Il2CppTypeEnum.BOOLEAN: return typeof value == "boolean"; case type_enum_1._Il2CppTypeEnum.I1: case type_enum_1._Il2CppTypeEnum.U1: case type_enum_1._Il2CppTypeEnum.I2: case type_enum_1._Il2CppTypeEnum.U2: case type_enum_1._Il2CppTypeEnum.I4: case type_enum_1._Il2CppTypeEnum.U4: case type_enum_1._Il2CppTypeEnum.CHAR: case type_enum_1._Il2CppTypeEnum.R4: case type_enum_1._Il2CppTypeEnum.R8: return typeof value == "number"; case type_enum_1._Il2CppTypeEnum.I8: return typeof value == "number" || value instanceof Int64; case type_enum_1._Il2CppTypeEnum.U8: return typeof value == "number" || value instanceof UInt64; case type_enum_1._Il2CppTypeEnum.I: case type_enum_1._Il2CppTypeEnum.U: case type_enum_1._Il2CppTypeEnum.PTR: return value instanceof NativePointer; case type_enum_1._Il2CppTypeEnum.VALUETYPE: if (type.class.isEnum) return typeof value == "number"; return value instanceof value_type_1._Il2CppValueType; case type_enum_1._Il2CppTypeEnum.CLASS: case type_enum_1._Il2CppTypeEnum.GENERICINST: case type_enum_1._Il2CppTypeEnum.OBJECT: return value instanceof object_1._Il2CppObject; case type_enum_1._Il2CppTypeEnum.STRING: return value instanceof string_1._Il2CppString; case type_enum_1._Il2CppTypeEnum.SZARRAY: return value instanceof array_1._Il2CppArray; default: console_1.raise(`isCoherent: "${type.name}" (${type_enum_1._Il2CppTypeEnum[type.typeEnum]}) has not been handled yet. Please file an issue!`); } } function readFieldValue(pointer, type) { if (pointer.isNull()) { return undefined; } switch (type.typeEnum) { case type_enum_1._Il2CppTypeEnum.VOID: return undefined; case type_enum_1._Il2CppTypeEnum.BOOLEAN: return !!pointer.readS8(); case type_enum_1._Il2CppTypeEnum.I1: return pointer.readS8(); case type_enum_1._Il2CppTypeEnum.U1: return pointer.readU8(); case type_enum_1._Il2CppTypeEnum.I2: return pointer.readS16(); case type_enum_1._Il2CppTypeEnum.U2: return pointer.readU16(); case type_enum_1._Il2CppTypeEnum.I4: return pointer.readS32(); case type_enum_1._Il2CppTypeEnum.U4: return pointer.readU32(); case type_enum_1._Il2CppTypeEnum.CHAR: return pointer.readU16(); case type_enum_1._Il2CppTypeEnum.I8: return pointer.readS64(); case type_enum_1._Il2CppTypeEnum.U8: return pointer.readU64(); case type_enum_1._Il2CppTypeEnum.R4: return pointer.readFloat(); case type_enum_1._Il2CppTypeEnum.R8: return pointer.readDouble(); case type_enum_1._Il2CppTypeEnum.I: case type_enum_1._Il2CppTypeEnum.U: case type_enum_1._Il2CppTypeEnum.PTR: return pointer.readPointer(); case type_enum_1._Il2CppTypeEnum.VALUETYPE: return type.class.isEnum ? pointer.readS32() : new value_type_1._Il2CppValueType(pointer, type.class); case type_enum_1._Il2CppTypeEnum.CLASS: case type_enum_1._Il2CppTypeEnum.GENERICINST: case type_enum_1._Il2CppTypeEnum.OBJECT: return new object_1._Il2CppObject(pointer.readPointer()); case type_enum_1._Il2CppTypeEnum.STRING: return new string_1._Il2CppString(pointer.readPointer()); case type_enum_1._Il2CppTypeEnum.SZARRAY: return new array_1._Il2CppArray(pointer.readPointer()); default: console_1.raise(`readFieldValue: "${type.name}" (${type_enum_1._Il2CppTypeEnum[type.typeEnum]}) has not been handled yet. Please file an issue!`); } } exports.readFieldValue = readFieldValue; function writeFieldValue(pointer, value, type) { if (!isCoherent(value, type)) { console_1.raise(`A "${type.name}" is required, but a "${Object.getPrototypeOf(value).constructor.name}" was supplied.`); } switch (type.typeEnum) { case type_enum_1._Il2CppTypeEnum.VOID: pointer.writePointer(NULL); break; case type_enum_1._Il2CppTypeEnum.BOOLEAN: { pointer.writeU8(+value); break; } case type_enum_1._Il2CppTypeEnum.I1: pointer.writeS8(value); break; case type_enum_1._Il2CppTypeEnum.U1: pointer.writeU8(value); break; case type_enum_1._Il2CppTypeEnum.I2: pointer.writeS16(value); break; case type_enum_1._Il2CppTypeEnum.U2: pointer.writeU16(value); break; case type_enum_1._Il2CppTypeEnum.I4: pointer.writeS32(value); break; case type_enum_1._Il2CppTypeEnum.U4: pointer.writeU32(value); break; case type_enum_1._Il2CppTypeEnum.CHAR: pointer.writeU16(value); break; case type_enum_1._Il2CppTypeEnum.I8: { const v = value instanceof Int64 ? value.toNumber() : value; pointer.writeS64(v); break; } case type_enum_1._Il2CppTypeEnum.U8: { const v = value instanceof UInt64 ? value.toNumber() : value; pointer.writeS64(v); break; } case type_enum_1._Il2CppTypeEnum.R4: pointer.writeFloat(value); break; case type_enum_1._Il2CppTypeEnum.R8: pointer.writeDouble(value); break; case type_enum_1._Il2CppTypeEnum.I: case type_enum_1._Il2CppTypeEnum.U: case type_enum_1._Il2CppTypeEnum.PTR: pointer.writePointer(value); break; case type_enum_1._Il2CppTypeEnum.VALUETYPE: if (type.class.isEnum) pointer.writeS32(value); else pointer.writePointer(value.handle); break; case type_enum_1._Il2CppTypeEnum.STRING: pointer.writePointer(value.handle); break; case type_enum_1._Il2CppTypeEnum.CLASS: case type_enum_1._Il2CppTypeEnum.OBJECT: case type_enum_1._Il2CppTypeEnum.GENERICINST: pointer.writePointer(value.handle); break; case type_enum_1._Il2CppTypeEnum.SZARRAY: pointer.writePointer(value.handle); break; default: console_1.raise(`writeFieldValue: "${type.name}" (${type_enum_1._Il2CppTypeEnum[type.typeEnum]}) has not been handled yet. Please file an issue!`); } } exports.writeFieldValue = writeFieldValue; function readRawValue(pointer, type) { if (pointer == undefined) { return; } switch (type.typeEnum) { case type_enum_1._Il2CppTypeEnum.VOID: return; case type_enum_1._Il2CppTypeEnum.BOOLEAN: return !!+pointer; case type_enum_1._Il2CppTypeEnum.I1: return +pointer; case type_enum_1._Il2CppTypeEnum.U1: return +pointer; case type_enum_1._Il2CppTypeEnum.I2: return +pointer; case type_enum_1._Il2CppTypeEnum.U2: return +pointer; case type_enum_1._Il2CppTypeEnum.I4: return +pointer; case type_enum_1._Il2CppTypeEnum.U4: return +pointer; case type_enum_1._Il2CppTypeEnum.CHAR: return +pointer; case type_enum_1._Il2CppTypeEnum.I8: return int64(pointer.toString()); case type_enum_1._Il2CppTypeEnum.U8: return int64(pointer.toString()); case type_enum_1._Il2CppTypeEnum.R4: return pointer.readFloat(); case type_enum_1._Il2CppTypeEnum.R8: return pointer.readDouble(); case type_enum_1._Il2CppTypeEnum.I: case type_enum_1._Il2CppTypeEnum.U: case type_enum_1._Il2CppTypeEnum.PTR: return pointer.isNull() ? NULL : pointer.readPointer(); case type_enum_1._Il2CppTypeEnum.VALUETYPE: return type.class.isEnum ? +pointer : new value_type_1._Il2CppValueType(pointer, type.class); case type_enum_1._Il2CppTypeEnum.STRING: return pointer.isNull() ? undefined : new string_1._Il2CppString(pointer); case type_enum_1._Il2CppTypeEnum.CLASS: case type_enum_1._Il2CppTypeEnum.GENERICINST: case type_enum_1._Il2CppTypeEnum.OBJECT: return new object_1._Il2CppObject(pointer); case type_enum_1._Il2CppTypeEnum.SZARRAY: return new array_1._Il2CppArray(pointer); default: console_1.raise(`readRawValue: "${type.name}" (${type_enum_1._Il2CppTypeEnum[type.typeEnum]}) has not been handled yet. Please file an issue!`); } } exports.readRawValue = readRawValue; function allocRawValue(value, type) { if (!isCoherent(value, type)) { console_1.raise(`A "${type.name}" is required, but a "${Object.getPrototypeOf(value).constructor.name}" was supplied.`); } switch (type.typeEnum) { case type_enum_1._Il2CppTypeEnum.VOID: return NULL; case type_enum_1._Il2CppTypeEnum.BOOLEAN: return ptr(+value); case type_enum_1._Il2CppTypeEnum.I1: return ptr(value); case type_enum_1._Il2CppTypeEnum.U1: return ptr(value); case type_enum_1._Il2CppTypeEnum.I2: return ptr(value); case type_enum_1._Il2CppTypeEnum.U2: return ptr(value); case type_enum_1._Il2CppTypeEnum.I4: return ptr(value); case type_enum_1._Il2CppTypeEnum.U4: return ptr(value); case type_enum_1._Il2CppTypeEnum.CHAR: return ptr(value); case type_enum_1._Il2CppTypeEnum.I8: { const v = value instanceof Int64 ? value.toNumber() : value; return ptr(v); } case type_enum_1._Il2CppTypeEnum.U8: { const v = value instanceof UInt64 ? value.toNumber() : value; return ptr(v); } case type_enum_1._Il2CppTypeEnum.R4: return Memory.alloc(4).writeFloat(value); case type_enum_1._Il2CppTypeEnum.R8: return Memory.alloc(8).writeDouble(value); case type_enum_1._Il2CppTypeEnum.PTR: case type_enum_1._Il2CppTypeEnum.I: case type_enum_1._Il2CppTypeEnum.U: return value; case type_enum_1._Il2CppTypeEnum.VALUETYPE: return type.class.isEnum ? ptr(value) : value.handle; case type_enum_1._Il2CppTypeEnum.STRING: return value.handle; case type_enum_1._Il2CppTypeEnum.CLASS: case type_enum_1._Il2CppTypeEnum.OBJECT: case type_enum_1._Il2CppTypeEnum.GENERICINST: return value.handle; case type_enum_1._Il2CppTypeEnum.SZARRAY: return value.handle; default: console_1.raise(`allocRawValue: "${type.name}" (${type_enum_1._Il2CppTypeEnum[type.typeEnum]}) has not been handled yet. Please file an issue!`); } } exports.allocRawValue = allocRawValue; function dump(filePath) { if (variables_1.domain == undefined) { console_1.raise("Not yet initialized!"); } if (filePath == undefined) { const coreModuleName = "UnityEngine.CoreModule" in variables_1.domain.assemblies ? "UnityEngine.CoreModule" : "UnityEngine"; const applicationMethods = variables_1.domain.assemblies[coreModuleName].image.classes["UnityEngine.Application"].methods; const persistentDataPath = applicationMethods.get_persistentDataPath.invoke().content; const getIdentifierName = "get_identifier" in applicationMethods ? "get_identifier" : "get_bundleIdentifier"; const identifier = applicationMethods[getIdentifierName].invoke().content; const version = applicationMethods.get_version.invoke().content; filePath = `${persistentDataPath}/${identifier}_${version}.cs`; } const file = new File(filePath, "w"); for (const assembly of variables_1.domain.assemblies) { console_1.inform(`Dumping ${assembly.name}...`); for (const klass of assembly.image.classes) { file.write(klass.toString()); } } file.flush(); file.close(); console_1.ok(`Dump saved to ${filePath}.`); } exports.dump = dump;