Jche
qwqqqqqq

Unity3D + Frida + Hook

2022-03-04 frida hook

Unity3D + Frida +Hook

首先,unity3d是一款游戏引擎,主要开发语言是c#

unity3d编译后代码文件有两种运行模式:

1.c#字节码模式,代码位于Assembly-CSharp.dll直接用dnspy反编译

2.AOT预编译模式,代码位于il2cpp.so

这里我们主要来研究il2cpp.so的逆向,该文件是一个可执行文件,其代码是游戏的C#字节码编译成的原生汇编代码。AOT编译主要是为了优化性能,但同时也增加了逆向难度。

il2cpp机制将C#中所有的类型信息保存到global-metadata.dat的文件,通过解析global-metadata文件,可以获得C#代码中的类型、方法、字段等等信息。

il2cppdumper的使用

1. 安装

我们可以使用il2cppdumper来获取这些信息,这是一个开源工具,可以在github上下载

https://github.com/Perfare/Il2CppDumper

点击右侧releases下面的版本下载即可

il2cppdumper-vxxx.zip

2.获取libil2cpp.so和global -metadata.dat

将你要逆向的apk(xxx.apk)改为(xxx.zip),解压进入目录,拿到libil2cpp.so与global-metadata.dat,目录为

1
2
\\lib\\armeabi-v7a\\libil2cpp.so
\\assets\\bin\\Data\\Managed\\Metadata\\global-metadata.dat

*执行Il2CppDumper.exe*

1.回到Il2CppDumper.exe所在的目录,创建input目录和output目录。

2.将libil2cpp.soglobal-metadata.dat拷贝到input目录中。

3.创建一个il2cpp_decompilation.bat文件。

image-20220407204800636

il2cpp_decompilation.bat文件内容如下:

1
..\\Il2CppDumper.exe libil2cpp.so global-metadata.dat ..\\output

双击执行il2cpp_decompilation.bat 页面会弹出一个cmd窗口然后显示一些done就是成功了

4.进入output目录可以看到生成了相关的cs文件和il2cpp.h文件

image-20220407204745752

查看反编译后的文件

1.dump.cs

这个文件会把C#dll代码的类、方法、字段列出来。

image-20220407204733890

2.il2cpp.h

生成的cpp的头文件,从头文件里我们也可以看到相关的数据结构。

参考:https://blog.csdn.net/linxinfa/article/details/116572369

导出修复il2cpp.so符号的脚本

Il2CppDumper生成的文件中,其中有一个script.py脚本,在IDA中File-Script file选择script.py运行即可,会重命名methodName,添加stringLiteral注释和MakeFunction。

但是使用il2cppdumper中并没有生成script.py的脚本,经过查找资料和推测,是使用ida.py来调用script.json

所以恢复符号的步骤是:

打开 IDA 中的 File- Script file,依次选择 Il2CppDumper 安装目录下的 ida_with_struct_py3.py ,和使用命令导出的 script.json文件,再选择il2cpp.h。

恢复符号后部分函数会变成这样

image-20220407204720853

frida使用

frida是一款基于python + javascript 的hook框架可运行在android、ios、linux、windows等平台 主要使用动态二进制插桩技术。

●动态二进制插桩[Dynamic Binary Instrumentation(DBI)]:在程序运行时实时地插入额外代码和数据,对可执行文件没有任何永久改变。

你能用DBI做些什么呢 (1)访问进程的内存 (2)在应用程序运行时覆盖一些功能 (3)从导入的类中调用函数 (4)在堆上查找对象实例并使用这些对象实例 (5)Hook,跟踪和拦截函数等等

frida框架分为两部分:

  1. 一部分是运行在系统上的交互工具frida CLI。
  2. 另一部分是运行在目标机器上的代码注入工具 frida-serve。

一、Window 安装

1
2
pip install frida
pip install frida-tools

二、安卓安装adb 连接后输入以下命令查看CPU型号getprop ro.product.cpu.abi

然后去https://github.com/frida/frida/releases中下载对应型号且与电脑安装Frida版本一致的Frida-server版本。这里我下载的是 frida-server-12.10.4-android-arm64.xz

下载完成后将其解压出来,然后重命名为frida-server然后通过adb将其上传到手机adb push .\frida-server /data/local/tmp然后再给其授予777权限。然后在chmod 777 frida-server

转发端口27042

至此,我们在安卓端安装完成。接下来,我们检验是否安装成功,在手机端启动./frida-server然后我们在window上执行Frida-ps -U如下图所示,则表示安装成功

查看进程名:

firda-ps -U

frida插件

idafirida插件能够批量生成hook脚本,在文件当前目录下。

选中一部分函数,然后使用该插件。

image-20220407204652223

https://github.com/P4nda0s/IDAFrida

使用脚本得到的hook函数是这样的

image-20220407204642947

hook脚本

用python封装的hook脚本能重启

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
from os import device_encoding
from ssl import SSLSession
import frida
import sys
device = frida.get_usb_device()
pid = device.spawn(["com.dreamgames.royalmatch"]) #包名
device.resume(pid)
session = device.attach(pid)
script = session.create_script("""
var str_name_so = "libil2cpp.so"; //要hook的so名
var n_addr_func_offset = 0x000000; //要hook的函数在函数里面的偏移

//加载到内存后 函数地址 = so地址 + 函数偏移
var n_addr_so = Module.findBaseAddress(str_name_so);
var n_addr_func = parseInt(n_addr_so, 16) + n_addr_func_offset;

var ptr_func = new NativePointer(n_addr_func);
Interceptor.attach(ptr_func,
{
onEnter: function(args)
{
console.log("hook on enter no exp");
},
onLeave:function(retval)
{
console.log("hook on Leave no exp");
}
});


""")
def on_message(message,data): #js中执行send函数后要回调的函数
print(message)

script.on('message',on_message)
print("1234")
script.load()
sys.stdin.read()
#打印栈调用
console.log(Thread.backtrace(this.context, Backtracer.FUZZY).map(DebugSymbol.fromAddress).join‌('\\\\n')
#打印内存
function print_dump(addr,size){
var buf = Memory.readByteArray(addr,size)
console.log("[function] send[*] " + addr.toString() + " "+ "length: " + size.toString() + "\\\\n[data]")
console.log(hexdump(buf, {
offset: 0,
length: size,
header: false,
ansi: false
}));
console.log("")
}

这里注意函数的参数FUZZY,一般的搜到的调用都是使用Backtracer.ACCURATE,也是默认参数。但这里打印的不完全,所以还是使用FUZZY比较好。

打印调用栈的显示的地址是call和ret的地址,而不是函数的地址。

image-20220407204626677

这也是另一种hook脚本

hook代码写法

https://blog.csdn.net/cyjmosthandsome/article/details/120906998

关于hook代码的写法就放个链接学习,修改return值什么的。

frida端口设置和详细使用

https://q0o0p.top/2021/03/23/hook-frida/

这个博客概括的很全面,转发端口什么都很齐

Author: John Doe

Link: http://example.com/2022/03/04/Unity3D-Frida-Hook/

Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.

< PreviousPost
Unicorn简易使用
NextPost >
演练和使用自己的动态链接库C++
CATALOG
  1. 1. Unity3D + Frida +Hook
    1. 1.1. il2cppdumper的使用
      1. 1.1.1. 1. 安装
    2. 1.2. 2.获取libil2cpp.so和global -metadata.dat
      1. 1.2.1. *执行Il2CppDumper.exe*
      2. 1.2.2. 查看反编译后的文件
    3. 1.3. 导出修复il2cpp.so符号的脚本
    4. 1.4. frida使用
      1. 1.4.1. frida插件
      2. 1.4.2. hook脚本
    5. 1.5. hook代码写法
    6. 1.6. frida端口设置和详细使用