# Fridahook 安卓的一款强大工具,比 xposed 要方便很多,下面就介绍一下 frida 安装到使用的方法。(基于有 python 环境)

  1. # 先安装 pythonfrida 模块,再下载 frida-server 并推到手机里

    • 网上大佬们讲 12 版本和 14 版本比较稳定,我建议安卓 6,712 ,安卓 8 以上用 14 (如有不匹配,还得自己试😂),我用的 14.2.18 ,再安装对应版本的 frida-tools , 可以到 github 上看对应版本

      Github: https://github.com/frida/frida/releases/tag/14.2.18

    pip install frida==14.2.18
    pip install frida-tools==9.2.4
  2. # 然后再根据安卓系统下载 frida-server , 一般真机是 arm 内核,模拟器是 x86 内核,可以用下面的 adb 指令查看

    adb shell getprop ro.product.cpu.abi

    返回:

    arm64-v8a			# 这里可以看到我的是 arm64
    • git 上下载对应的 server

  3. # 把下载的 server 解压,然后用 adb 推送到手机 /data/local/tmp 里,并给执行权限。

    adb push frida-server-14.2.18-android-arm64  /data/local/tmp/frida-server   # 注意一定要解压之后再推送到手机
    adb shell		# 进入 adb 命令行,前提是电脑只连接了一部手机或模拟器,否则需要指定 id
    $ su			# 打开 root 权限
    $ cd /data/local/tmp	# 切换到 tmp 目录下
    $ chmod +x frida-server		# 给 frida-server 添加可执行权限
    $ ./frida-server	# 启动 frida-server 如下图光标闪烁,表示启动成功

    • server 启动后,控制台不要关闭,再打开一个控制台设置端口转发:
    adb forward tcp:27042 tcp:27042
    
  4. # 然后开始写 python 脚本,用来注入 js 脚本,输出 log ,我这里是直接获取手机当前打开的 app 信息,懒得每次自己查询包名, js 代码写在单独文件。

    import frida
    import sys
    # 读取 js 代码
    def get_jscode():
        fn = "jscode.js"
        with open(fn, "r", encoding="utf-8") as f:
            data = f.read()
        return data
    def on_message(message, data):
        # print "回调函数信息:", message
        if message['type'] == 'send':
            print("[*] {0}".format(message['payload']))
        else:
            print(message)
            
    jscode = get_jscode()
    # rdev = frida.get_remote_device ()      # 模拟器
    rdev = frida.get_usb_device()       # 数据线 好像两种都可以
    front_app = rdev.get_frontmost_application()    # 获取当前打开的 app
    try:
        pkg_name = front_app.identifier  # 获取当前 app 包名
        
        # 启动 app 两种方式,运行时用一种就可以。
        # 方式一:spawn 模式,下面用 resume(不加这个函数,可能会卡死)重启 app,可以 hook app 启动阶段的函数(比如 root 检测)
        pid = rdev.spawn([pkg_name])    # 根据 app 包名获取 pid
        session = rdev.attach(pid)		# 添加此 pid 进程
        script = session.create_script(jscode)	# 添加 js 代码
        script.on('message', on_message)	# log 输出
        script.load()		# 加载脚本
        rdev.resume(pid)    # 重启 app, 用来 hook app 启动阶段的函数
        sys.stdin.read()	# 持续输出控制台,不加这句代码,执行一次就结束了
        
        # 方式二:直接 attach (pkg_name),hook app 执行后的代码,不需要重启
        session = rdev.attach(pkg_name)  # 通过包名添加进程,后面代码一样,只是没有重启的函数
        script = session.create_script(jscode)	
        script.on('message', on_message)	
        script.load()		
        sys.stdin.read()
        
    except AttributeError as e:
        print(e)
        print("当前app的pid为空!")
  5. # 编写 js 脚本, hook 的核心代码,首先找到 hook 点,然后修改下面代码即可。

    Java.perform(function () {
        var hook_class = Java.use("com.tencent.news.MainActivity")		// 比如 hook 某新闻的 MainActivity 类
        console.log("success..")
        hook_class.a.implementation = function (str){			// MainActivity 类的 a 函数
            console.log("str", str)		 // 打印 str 的值,也可以用 send (str)
            return this.a(str)			// 如果原函数有 return,这里必须也要调用 this.a (str) 并 return 出去
        }
    })
  6. # 关于不同 java 函数 hook 方式

    • # 一般函数 -- implementation
      var hook_class = Java.use('com.example.Mainclass');
      hook_class.fun.implementation = function (arg) {
          console.log('arg:', arg);
          return this.fun(arg);
      }
    • # 重载函数 -- overload , 重载的函数就是同一个类下面函数名相同,参数不同的函数
      var hook_class = Java.use('com.example.Mainclass');
      hook_class.fun.overload("java.lang.String").implementation = function (arg) {
          console.log('arg:', arg);
          return this.fun(arg);
      }

      overload 里面需要添加参数的类型,按位置对应,下面列出一些常用的类型

      Java 中参数类型frida 脚本中参数类型
      intint
      bytebyte
      floatfloat
      Stringjava.lang.String
      HashMapjava.util.HashMap
      booleanboolean
    • # 构造函数 -- $init , 如果构造函数还有重载还需要再 $init 后面加 overload
      var hook_class = Java.use('com.example.Mainclass');
      hook_class.$init.implementation = function () {
          return this.$init();
      }
      // 构造函数重载
      hook_class.$init.overload().implementation = function () {
          return this.$init();
      }
    • # 构造对象 -- $new
      const hashmap = Java.use("java.util.HashMap");
      var hashobj = hashmap.$new()
      hashobj.put("key","value")
      const javaString = Java.use("java.lang.String");
      var strobj = javaString.$new("我是一个string")
    • # 类中类 -- $hook 内部类的函数
      var hook_class = Java.use('com.example.Mainclass$innerclass');
      hook_class.fun.implementation = function (arg) {
          console.log('arg:', arg);
          return this.fun(arg);
      }
    • # 静态变量 -- value
      var hook_class = Java.use("com.example.Mainclass");
      console.log("hook_class中method的值", hook_class.method.value)
    • # sonative 静态注册函数 -- 关键是使用 IDA 找到关键函数
      // 方法一:通过 intercept 拦截器,根据函数名 hook
      var so_name = "xxxlib.so";    // 要 hook 的 lib.so 文件名
      var func_name = "func_name";          // 要 hook 的函数名
      var func_addr = Module.findExportByName(so_name , func_name);
      console.log("func addr is ---" + func_addr);
      Interceptor.attach(n_addr_func, {
          // 在 hook 函数之前执行的语句
          onEnter: function(args) 
          {
              console.log("hook on enter")
          },
          // 在 hook 函数之后执行的语句
          onLeave:function(retval)
          {
              console.log("hook on leave")
          }
      });
      // 方法二:通过偏移地址 inlinehook
      console.log("so start:")
       		// 如果是 32 位 下面地址需要改成 0x22F0+1
      var address = Module.findBaseAddress("libencrypt.so").add(0x22F0);  
      console.log("func address:", address)
      Interceptor.attach(pointer, {
          onEnter: function (args) {
         		// 根据指针地址获取 string,根据参数的实际类型打印
              console.log("params1", Memory.readCString(args[0]));
          },
          onLeave: function (retval) {
              console.log("here???", retval)
          }
      })
    • # 打印 object 类型的值

      // 目前我就知道这三种,而且也不一定对所有 obj 有效
      >> console.log(obj.toString())
      >> consloe.log(JSON.toJSONString(obj))
      >> for(var i in obj){
          	console.log(obj[i].toString())		// 遍历 obj,打印每一条属性
      		}
  7. # 打开手机 app ,然后运行 python 脚本,就可以进行 hook

    frida只是工具,重点还是要找到hook位置。
    
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

渣渣文 微信支付

微信支付

渣渣文 支付宝

支付宝