在il2cpp手游的逆向分析过程中,frida-il2cpp-bridge是一个十分强大的工具,项目地址:https://github.com/vfsfitvnm/frida-il2cpp-bridge 本文主要记录在windows下的环境配置及该工具使用。
1.Node.js安装配置
下载node.js 安装包进行安装(一路确定即可,新版本会自动添加环境变量),官网地址:Node.js 中文网
cmd 命令能正确输出即安装成功
2.Frida 的安装配置
frida的使用网上有很多详细资料,这里就不再进行说明
3.frida-il2cpp-bridge使用方法一:源码编译
首先,直接在github上下载frida-il2cpp-bridge源码,文件结构如图所示:
编译命令:tsc -w 注意,利用powershell会报错,需要使用cmd
此时,如图所示会报一堆错误,不需要管,因为index.js已经编译出来了,且能正常使用
4.frida-il2cpp-bridge使用方法二:模块引用,利用frida-compile编译
在空文件下运行命令: npm i frida-il2cpp-bridge 进行模块安装
新建 index.ts 文件(该文件进行引用frida-il2cpp-bridge模块)
修改package.json文件配置编译命令
{
"main": "index.ts",
"scripts": {
"prepare": "npm run build",
"watch": "frida-compile index.ts -w -o hook.js"
},
"dependencies": {
"frida-il2cpp-bridge": "^0.8.5"
}
}
运行编译命令:npm run watch
此时,在同级目录下生成编译后的文件hook.js
在index.ts内引用frida-il2cpp-bridge
import "frida-il2cpp-bridge"
至此frida-il2cpp-bridge已经接入完成。
5.frida-il2cpp-bridge的简单使用
我这边使用源码编译进行例子讲解(两种方法只有引用方式区别,代码都是一样的)
以下内容来自项目frida-il2cpp-bridge的wiki,也可前往自行查看:https://github.com/vfsfitvnm/frida-il2cpp-bridge/wiki/Snippets#initialization
5.1 frida附加当前应用程序,并注入js文件
frida -FU -l ./dist/index.js
5.2 dumpcs文件
在il2cpp手游的逆向过程中,dump.cs文件可以极大程度提高逆向效率,通常我们可以使用Il2cppdumper项目(https://github.com/Perfare/Il2CppDumper)进行dump,但是遇到一些so受保护,或者global-metadata.dat文件被加密的情况,可以进行内存dump,而frida-il2cpp-bridge便封装了内存dump功能,使用也十分简单。
Il2Cpp.perform(() => {
// 以默认文件名保存在默认路径 /<default_path>/<default_name>.cs
Il2Cpp.dump();
});
ctrl+s进行保存后,js文件会自动编译完成,frida进行重载,此时控制台输出可以清楚看到已经成功dump出cs文件
5.3 获取Image,Class,Method 等信息
// 获取Assembly-CSharp.dll
const Assembly = Il2Cpp.domain.assembly("Assembly-CSharp").image
// 获取CarSelector类
const CarSelector = Assembly.class("CarSelector")
// 获取CarSelector下的IsCarUnlocked方法
const IsCarUnlocked = CarSelector.method("IsCarUnlocked")
5.4 hook函数进行逻辑修改
// dump.cs 中的函数原型 System.Boolean IsCarUnlocked(); // 0x0207595c
CarSelector.method("IsCarUnlocked").implementation = function (): boolean {
// 利用invoke回调原函数,获取原始返回值
const ret = this.method("IsCarUnlocked").invoke();
// 对原始返回值进行打印,ok是模块中封装的打印函数,也可以直接使用consloe.log
console.log("ret:"+ret);
// 修改返回值
return true;
}
5.5 跟踪器的使用
使用跟踪器可以更快速定位到关键代码,frida-il2cpp-bridge支持对单个或多个类,方法进行跟踪,官方示例如下:
Il2Cpp.perform(() => {
const SystemString = Il2Cpp.corlib.class("System.String");
// it traces method calls and returns
Il2Cpp.trace()
.classes(SystemString)
.filterMethods(method => method.isStatic && method.returnType.equals(SystemString.type) && !method.isExternal)
.and()
.attach();
// detailed trace, it traces method calls and returns and it reports every parameter
Il2Cpp.trace(true)
.assemblies(Il2Cpp.corlib.assembly)
.filterClasses(klass => klass.namespace == "System")
.filterParameters(param => param.type.equals(SystemString) && param.name == "msg")
.and()
.assemblies(Il2Cpp.corlib.assembly)
.filterMethods(method => method.name.toLowerCase().includes("begin"))
.and()
.attach();
});
利用跟踪器对 CarSelector 进行简单分析
// 对CarSelector类进行跟踪,trace(true)时打印参数
Il2Cpp.trace(true)
.classes(CarSelector)
.and()
.attach()
//0x02074ae0 ┌─CarSelector::Awake(this = Cars (CarSelector))
//0x02074ae0 └─CarSelector::Awake
// 对Assembly-CSharp.dll 下的类名包含Selector的类进行跟踪
Il2Cpp.trace(true)
.assemblies(Il2Cpp.domain.assembly("Assembly-CSharp"))
.filterClasses(klass=>klass.name.indexOf("Selector")!=-1)
.and()
.attach()
结语
以上只是对frida-il2cpp-bridge的简单使用,该工具的功能十分强大,需要在实际开发中自行运用!