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.
216 lines (215 loc) • 9.36 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports._Il2CppMethod = void 0;
const decorator_cache_getter_1 = require("decorator-cache-getter");
const accessor_1 = require("../../utils/accessor");
const console_1 = require("../../utils/console");
const api_1 = require("../api");
const decorators_1 = require("../decorators");
const native_struct_1 = require("../native-struct");
const variables_1 = require("../variables");
const utils_1 = require("../utils");
const class_1 = require("./class");
const object_1 = require("./object");
const type_1 = require("./type");
const parameter_1 = require("./parameter");
let _Il2CppMethod = class _Il2CppMethod extends native_struct_1.NativeStruct {
get actualPointer() {
return api_1.Api._methodGetPointer(this.handle);
}
get class() {
return new class_1._Il2CppClass(api_1.Api._methodGetClass(this.handle));
}
get isGeneric() {
return api_1.Api._methodIsGeneric(this.handle);
}
get isInflated() {
return api_1.Api._methodIsInflated(this.handle);
}
get isInstance() {
return api_1.Api._methodIsInstance(this.handle);
}
get name() {
return api_1.Api._methodGetName(this.handle);
}
get parameterCount() {
return api_1.Api._methodGetParamCount(this.handle);
}
get parameters() {
const iterator = Memory.alloc(Process.pointerSize);
const accessor = new accessor_1.Accessor();
let handle;
let parameter;
while (!(handle = api_1.Api._methodGetParameters(this.handle, iterator)).isNull()) {
parameter = new parameter_1._Il2CppParameter(handle);
accessor[parameter.name] = parameter;
}
return accessor;
}
get relativePointerAsString() {
return `0x${this.actualPointer.sub(variables_1.library.base).toString(16).padStart(8, "0")}`;
}
get returnType() {
return new type_1._Il2CppType(api_1.Api._methodGetReturnType(this.handle));
}
get nativeFunction() {
const parametersTypesAliasesForFrida = Array(this.parameterCount).fill("pointer");
if (this.isInstance || variables_1.unityVersion.isLegacy) {
parametersTypesAliasesForFrida.push("pointer");
}
if (this.isInflated) {
parametersTypesAliasesForFrida.push("pointer");
}
return new NativeFunction(this.actualPointer, this.returnType.aliasForFrida, parametersTypesAliasesForFrida);
}
set implementation(callback) {
Interceptor.revert(this.actualPointer);
if (callback == null)
return;
if (this.actualPointer.isNull()) {
console_1.raise(`Can't replace method ${this.name} from ${this.class.type.name}: pointer is NULL.`);
}
const parametersTypesAliasesForFrida = [];
if (this.isInstance) {
parametersTypesAliasesForFrida.push(this.class.type.aliasForFrida);
}
for (const parameterInfo of this.parameters) {
parametersTypesAliasesForFrida.push(parameterInfo.type.aliasForFrida);
}
const methodInfo = this;
const replaceCallback = function (...invocationArguments) {
const instance = methodInfo.isInstance ? new object_1._Il2CppObject(invocationArguments[0]) : null;
const startIndex = +methodInfo.isInstance | +variables_1.unityVersion.isLegacy;
const args = methodInfo.parameters[accessor_1.filterAndMap](() => true, parameter => parameter.asHeld(invocationArguments, startIndex));
return callback.call(this, instance, args);
};
const nativeCallback = new NativeCallback(replaceCallback, this.returnType.aliasForFrida, parametersTypesAliasesForFrida);
Interceptor.replace(this.actualPointer, nativeCallback);
Interceptor.flush();
}
get parametersTypesAliasesForFrida() {
const parametersTypesAliasesForFrida = new Array(this.parameterCount).fill("pointer");
if (this.isInstance || variables_1.unityVersion.isLegacy) {
parametersTypesAliasesForFrida.push("pointer");
}
if (this.isInflated) {
parametersTypesAliasesForFrida.push("pointer");
}
return parametersTypesAliasesForFrida;
}
invoke(...parameters) {
return this._invoke(NULL, ...parameters);
}
intercept({ onEnter, onLeave }) {
if (this.actualPointer.isNull()) {
console_1.raise(`Can't intercept method ${this.name} from ${this.class.type.name}: pointer is NULL.`);
}
const interceptorCallbacks = {};
if (onEnter != undefined) {
const methodInfo = this;
interceptorCallbacks.onEnter = function (invocationArguments) {
const instance = methodInfo.isInstance ? new object_1._Il2CppObject(invocationArguments[0]) : null;
const startIndex = +methodInfo.isInstance | +variables_1.unityVersion.isLegacy;
const args = methodInfo.parameters[accessor_1.filterAndMap](() => true, parameter => parameter.asHeld(invocationArguments, startIndex));
onEnter.call(this, instance, args);
};
}
if (onLeave != undefined) {
const methodInfo = this;
interceptorCallbacks.onLeave = function (invocationReturnValue) {
onLeave.call(this, {
valueHandle: invocationReturnValue.add(0),
get value() {
return utils_1.readRawValue(invocationReturnValue, methodInfo.returnType);
},
set value(v) {
invocationReturnValue.replace(utils_1.allocRawValue(v, methodInfo.returnType));
}
});
};
}
return Interceptor.attach(this.actualPointer, interceptorCallbacks);
}
trace() {
if (this.actualPointer.isNull()) {
console_1.warn(`Can't trace method ${this.name} from ${this.class.type.name}: pointer is NULL.`);
}
try {
Interceptor.attach(this.actualPointer, () => console_1.inform(`${this.relativePointerAsString} ${this.name}`));
}
catch (e) {
console_1.warn(`Can't trace method ${this.name} from ${this.class.type.name}: ${e.message}.`);
}
}
asHeld(holder) {
const invoke = this._invoke.bind(this, holder);
return {
invoke(...parameters) {
return invoke(...parameters);
}
};
}
_invoke(instance, ...parameters) {
if (this.parameterCount != parameters.length) {
console_1.raise(`This method takes ${this.parameterCount} parameters, but ${parameters.length} were supplied.`);
}
const allocatedParameters = Array.from(this.parameters).map((parameter, i) => utils_1.allocRawValue(parameters[i], parameter.type));
if (this.isInstance || variables_1.unityVersion.isLegacy)
allocatedParameters.unshift(instance);
if (this.isInflated)
allocatedParameters.push(this.handle);
return utils_1.readRawValue(this.nativeFunction(...allocatedParameters), this.returnType);
}
};
__decorate([
decorator_cache_getter_1.cache
], _Il2CppMethod.prototype, "actualPointer", null);
__decorate([
decorator_cache_getter_1.cache
], _Il2CppMethod.prototype, "class", null);
__decorate([
decorator_cache_getter_1.cache
], _Il2CppMethod.prototype, "isGeneric", null);
__decorate([
decorator_cache_getter_1.cache
], _Il2CppMethod.prototype, "isInflated", null);
__decorate([
decorator_cache_getter_1.cache
], _Il2CppMethod.prototype, "isInstance", null);
__decorate([
decorator_cache_getter_1.cache
], _Il2CppMethod.prototype, "name", null);
__decorate([
decorator_cache_getter_1.cache
], _Il2CppMethod.prototype, "parameterCount", null);
__decorate([
decorator_cache_getter_1.cache
], _Il2CppMethod.prototype, "parameters", null);
__decorate([
decorator_cache_getter_1.cache
], _Il2CppMethod.prototype, "relativePointerAsString", null);
__decorate([
decorator_cache_getter_1.cache
], _Il2CppMethod.prototype, "returnType", null);
__decorate([
decorator_cache_getter_1.cache
], _Il2CppMethod.prototype, "nativeFunction", null);
__decorate([
decorator_cache_getter_1.cache
], _Il2CppMethod.prototype, "parametersTypesAliasesForFrida", null);
__decorate([
decorators_1.shouldBeInstance(false)
], _Il2CppMethod.prototype, "invoke", null);
__decorate([
decorators_1.shouldBeInstance(true)
], _Il2CppMethod.prototype, "asHeld", null);
_Il2CppMethod = __decorate([
decorators_1.nonNullHandle
], _Il2CppMethod);
exports._Il2CppMethod = _Il2CppMethod;