利用Frida解密钛备份客户端备份恢复命令

之前介绍过使用Xposed框架、开发Xposed插件来解密钛备份的数据备份和恢复逻辑。这里介绍使用Frida来实现同样功能,相较于Xposed,Frida更加动态和灵活、可以Hook Native层、拥有跨平台特性,另外配置过程也比Xposed简洁。

1 Frida

1.0.1 简介

frida是一款基于python + javascript的hook框架,可运行在android、ios、linux、winosx等各平台,主要使用动态二进制插桩技术。插桩技术是指将额外的代码注入程序中以收集运行时的信息,可分为两种 源代码插桩、二进制插桩 。二进制插桩指额外代码注入到二进制可执行文件中,又可以将其细化为 静态二进制插桩、动态二进制插桩 。静态二进制插桩是在程序执行前插入额外的代码和数据,生成一个永久改变的可执行文件。动态二进制插桩则是在程序运行时实时地插入额外代码和数据,对可执行文件没有任何永久改变。Frida在Android平台上需要配置一个frida-server,二进制动态插桩技术的原理是使用了 ptrace 附加到目标进程上,访问进程的内存、Hook和跟踪以及拦截函数等等。

1.0.2 安装和配置

我们用到的frida框架分为两部分:一部分是运行在系统上的交互工具frida CLI; 另一部分是运行在目标机器上的代码注入工具 frida-server。通过pip安装frida和frida-tools。

pip install frida
pip install frida-tools

执行一下 frida version 命令,确认一下本机的frida环境版本,这个版本需要与frida-server的主版本匹配。本机的frida版本为12,所以frida-server也需要使用主版本位12的版本才行。

frida --version

安装frida-server前需要先读取cpuinfo信息,需要根据cpu版本下载相应的frida-server,前往frida github官方地址下载对应版本。

cpuinfo.png

图1  cpuinfo信息

然后将下载的frida-server推送到指定文件夹,并添加可执行权限。

adb push frida-server /data/local/tmp/
adb shell chmod 777 /data/local/tmp/frida-server

配置完成之后,在adb shell里面将frida-server启动起来,然后执行frida-tools中的命令frida-ps -U,如果可以输出进程列表则表示配置完成。

2 函数拦截

参考之前的文章Android客户端数据备份和恢复,里面说到了在 o.en 的构造函数中的第二个参数就是我们想要的命令。我们直接使用python+js的方式来进行hook操作,注意en有两个构造函数,需要用overload指定你想hook哪一个。完整代码如下所示:

import sys

import frida

package_name = "com.keramidas.TitaniumBackup"


def get_messages_from_js(message, data):
    print(message)


def hook_log_on_command():
    hook_code = """
    Java.perform(function () {
      console.log("[*] Hook command construct function");
      var hclass = Java.use("o.en");
      hclass.$init.overload('o.es$if', 'java.lang.String').implementation = function (a, b) {
        console.log("Hook Start...");
        console.log(arguments[1]);
        return this.$init(a, b);
    }

    });
    """
    return hook_code


def main():
    process = frida.get_device_manager().enumerate_devices()[-1].attach(
        package_name)
    script = process.create_script(hook_log_on_command())
    script.on('message', get_messages_from_js)
    script.load()
    sys.stdin.read()


if __name__ == '__main__':
    main()

跟xposed一样,也可以把所有的命令都完整的打印出来,并且比xposed更方便,不需要安装额外的插件。

frida-taibeifen.png

图2  hook结果