一、Frida框架简介

  • Frida是一款基于Python + JavaScript 的hook框架,本质是一种动态插桩技术。可以用于Android、Windows、iOS等各大平台,其执行脚本基于Python或者Node.js写成,而注入代码用JavaScript写成,所以有必要了解一些这些语言的语法。本文主要讲述了Android上Frida框架的使用。

    二、Android Frida环境搭建

  • 使用Frida需要Python 3环境,在Windows上目前预编译的版本需要Python3.7,暂时不支持Python 3.8。关于Python的安装这里就不再赘述。同时你还需要安装好pip。然后就可以安装frida了,使用如下的命令:

    1. pip3 install frida frida-tools
  • 除此之外,我们还需要下载Frida的Server端,可以从Github上下载:https://github.com/frida/frida/releases。这里我们选择Android的版本,arm是32位而arm64是64位,还有x86和x86_64版本提供,根据自己手机的类型下载。

image.png

  • 下载解压之后要将Server端推送到手机上,和IDA的Debug Server类似,我们将其推送至/data/local/tmp/目录:

    1. adb push frida-server-12.8.11-android-arm64 /data/local/tmp/
  • 类似地,为其赋予执行权限,并使用root身份启动它。

    cd /data/local/tmp/
    su
    chmod +x frida-server-12.8.11-android-arm64
    ./frida-server-12.8.11-android-arm64
    
  • 如果不想使用命令行工具,也可以尝试一下我自己封装的FridaHooker,它提供了一种利用图形化界面管理frida的方法,会为你自动识别手机的类型并为你安装和启动frida,地址为:https://github.com/wrlu/FridaHookerimage.png

  • 启动后,在电脑上执行命令,以连接到USB上的frida server:

    frida-ps -Ua
    
  • 如果能成功显示出进程列表,那么就证明启动成功。如果显示不出,说明是Server端没有启动,如果只能显示出两三个进程,说明没有以root身份启动Server端。不过有时候会显示出Windows的进程列表,这种情况最好使用下面的Python绑定方法使用frida。

image.png

  • 同时这里还支持连接远程frida server,可以使用如下命令:
    frida-ps -H
    

三、Frida Hook Android Java代码

  • Frida注入控制程序使用Python写成,可以使用任何你喜欢的IDE,这里不再叙述。示例代码如下:

    import sys
    import frida
    js_file_name = 'Hook.js'
    process_name = 'com.xxx.xxx'
    # 自定义回调函数
    def on_message(message, data):
      if message['type'] == 'send':
          print("[*] {0}".format(message['payload']))
      else:
          print(message)
    def get_js_code():
      js_file = open(js_file_name, 'r')
      return js_file.read()
    if __name__ == '__main__':
      # 附加到进程并得到进程对象
      process = frida.get_usb_device().attach(process_name)
      # 指定JavaScript脚本
      script = process.create_script(get_js_code())
      # 加载JavaScript脚本
      script.on('message', on_message)
      script.load()
      # 读取返回输入
      sys.stdin.read()
    
  • 该脚本首先获取了USB设备,也就是我们连接的手机。然后附加到了我们指定的进程上,这里是com.xxx.xxx,所以在执行脚本之前要先在手机上启动好欲hook的目标程序。然后加载了JavaScript脚本并获取了其返回的内容。JavaScript脚本中将实现具体的Hook功能,内容如下:

    Java.perform(function () {
      var LogUtil = Java.use('com.xxx.xxx.xxx.LogUtil');
      LogUtil.isDebug.implementation = function () {
          send('Hooking isDebug method');
          return true;
     }
    });
    

这里是要Hook一个Java方法,首先使用Java.use找到Java的类,然后调用方法的implementation来实现Hook,提供一个回调函数,这个函数将覆盖原有的函数。本例中是将该方法的返回值强制修改为true,这样就完成了Hook。

  • 有时候Hook会超时,所以可以把上述代码放在以下的代码块里,但是不是必须的:

    setImmediate(function() { ... });
    
  • frida允许你一次性Hook多个进程,也可以一次性注入多个脚本,所以假如有m个进程,n个脚本,每次就可以执行m * n个注入任务。但是要注意的是如果注入的进程或脚本过多,可能会导致手机崩溃。这里有我的一个示例代码,提供了较为完善的脚本加载和注入功能,源代码详见:https://github.com/wrlu/Frida-Hook-Android

    四、Frida Hook Android Native方法

  • 到以上内容显示出Frida的优势只是不需要重启手机,比较方便。但是Frida还可以完成Xposed不能完成的任务,那就是来Hook Native方法,也就是so动态库中的C/C++方法。示例代码如下:

    Interceptor.attach(Module.findExportByName("libc.so" , "open"), {
      onEnter: function(args) {
          log("open() called!")
      },
      onLeave:function(retval){
    
      }
    });
    
  • 这里面和Java层Hook有些类似,使用Interceptor.attach来附加到动态库,使用Module.findExportByName来找到要Hook的函数,第一个参数是模块名称,第二个参数就是函数名。里面的代码和Java层Hook比较相似。

    五、Frida CLI

  • 就像Scapy这样的框架一样,Frida也是可以通过CLI访问的,要完成上面Python脚本的内容,可以用以下的命令代替:

    frida -U -l [JavaScript脚本] [进程名]
    frida -H [主机名:端口] -l [JavaScript脚本]
    # e.g.
    frida -U -l ./hook.js com.huawei.xxx
    frida -H 192.168.3.2:27042 -l ./hook.js com.huawei.xxx
    

六、使用Python连接远程frida server

  • frida使用的是TCP协议进行连接,也支持连接远程的frida server,在Python中有一个get_remote_device()方法,后来发现这个函数默认连接的是127.0.0.1:27042,而且不能更改。后来才发现应该用如下的方法:

    host = '192.168.3.2:27042'
    manager = frida.get_device_manager()
    remote_device = manager.add_remote_device(host)
    remote_device.get_process(process_name)
    remote_process = remote_device.attach(process_name)
    
  • 在我编写的SecMobile的项目中,使用了这种方法,配合frp代理工具实现了集成管理frida受控端的功能。但是感觉可能没啥卵用,只有集成化测试的时候有用,自己用意义不大。

image.png

七、常见错误

  • NotSupportedError错误:remote_write PTRACE_POKEDATA head failed: 5
  • NotSupportedError错误:MagiskHide相关
    • 在Magisk Manager中禁用MagiskHide即可
  • InvalidArgumentError错误:设备未连接

  • 本文介绍了Frida在Android Hook上的应用,实际上Frida还可以Hook其他系统的代码,有时间会再撰写文章进行讲解。