首页
论坛
课程
招聘
[翻译]使用Frida框架hook安卓native方法(适合新手)
2020-5-26 18:43 13020

[翻译]使用Frida框架hook安卓native方法(适合新手)

2020-5-26 18:43
13020

使用Frida框架hook安卓native方法(适合新手)

之前一篇文章中,我们介绍了如何在安卓app中添加C/C++代码。本文将以上文的app为示例,hook其中用C编写的Jniint函数。

 

这篇文章中有一些你可能感兴趣的Frida代码示例。

 

本文适合刚入门的新手,目的是介绍如何使用Frida hook方法,尤其是native方法。我们将详细介绍整个流程中的每个步骤。如果你想下载本文的APK示例,链接在

 

在本教程中,我们会处理Java方法和C函数。我不会刻意区分这些术语,因为它们意思是一样的。

 

第一步是检测APK是否包含共享库。简单的方法是解压APK。别忘了APK是实际app的打包,所以可以像解压压缩包一样提取APK内容。选择你常用的解压程序解压APK。

 

解压后的文件结构应该类似于:

├── AndroidManifest.xml
├── classes2.dex
├── classes.dex
├── lib
│   ├── arm64-v8a
│   │   └── libnative-lib.so
│   ├── armeabi-v7a
│   │   └── libnative-lib.so
│   ├── x86
│   │   └── libnative-lib.so
│   └── x86_64
│       └── libnative-lib.so
├── [...more here...]

lib文件夹下,我们看到了针对不同架构的库的编译版本。选择适配设备的,我们选的是x86。我们需要分析该共享对象内部的函数,命令为nm --demangle --dynamic libnative-lib.so。结果如下:

$ nm --demangle --dynamic libnative-lib.so 
00002000 A __bss_start
         U __cxa_atexit
         U __cxa_finalize
00002000 A _edata
00002000 A _end
00000630 T Java_com_erev0s_jniapp_MainActivity_Jniint
000005d0 T Jniint
         U rand
         U srand
         U __stack_chk_fail
         U time

我们首先注意到了两个函数:Java_com_erev0s_jniapp_MainActivity_JniintJniint。如果你想了解关于这两个函数的更多信息,请阅读另一篇文章的相关部分。我们要做的是改变APK的执行流程,让Jniint返回我们自定义的值。

 

方法有二:

  1. Hook Java层,即劫持Java JNI调用,此方法可以不用处理C代码;
  2. 深入native层在Jniint函数上做手脚。

一般来说,方法一比较容易,但是有时候方法二操作会更方便。这完全取决于app本身和你的目的。两种方法我们都会尝试,并且对其步骤做评价。

配置测试环境

本教程中所使用的,以及我在进行常规安卓安全测试中所使用的,都是Genymotion。Genymotion是一个非常不错的模拟器,非常轻巧,也可集成到Android Studio中。在测试环境中,挑选的设备/模拟器一定要有root访问权限。其实root对于执行hook而言也不是必须的(有其他替代方法),但本文中的教程需要root权限。Genymotion默认情况下具有root访问权限。

安装Frida

此步骤非常简单,只需Python环境并且运行两个命令。第一个命令是pip install frida-tools,用以安装基本组件,第二个命令是pip install frida,用以安装一些在使用Frida过程中有用的Python bindings(Python bindings的作用是允许用Python调用其他语言的方法)。

在设备上运行frida-server

首先下载最新版本的frida-server,链接在。搜索frida-server并选择设备对应的安卓架构,Genymotion对应的是x86。下载完成后,解压并重命名一个好记的名字,比如frida-server。接下来将其传至设备上并运行。往设备上传文件需要adb。如果目录下没有adb,你需要下载adb。你可以在adb目录下运行,也可以将目录路径添加至环境变量。部分教程在

 

现在adb就绪,并且已经将设备连接至电脑,或者配置好了模拟器。执行命令adb push path/to/your/frida-server /tmp。该命令会将电脑上的frida-server文件传到设备的/tmp目录下。

 

最后,在设备上运行frida-server。步骤是:先打开adb shell,进入/tmp目录,然后执行chmod +x frida-server使其可执行,最后执行./frida-server,并且不要关闭命令行窗口。

 

验证正确配置和操作的方式是,打开另一个命令行窗口,执行frida-ps -U。如果看到结果是一个很长的进程列表,那就说明没问题,否则重新阅读本小节并严格按步骤执行。

 

如果你是按照上一篇文章的步骤执行的,别忘了安装从此处下载APK样本,或者自己编译APK。有多种安装APK的方法,其中之一是运行adb install nameOfApk.apk

基于Frida框架用Java API hook

我们要hook的方法是Jniint,在此之前,请先在查阅Frida的Java API,会对你理解后续的操作有帮助。

 

首先,点击app图标启动app。点击按钮后会弹出一个数字,如下所示:

 

点击按钮弹出数字

 

我们接下来创建一个给Frida使用的JavaScript文件,来hook我们想hook的函数(Jniint)。JavaScript文件内容如下:

Java.perform(function () {
  // we create a javascript wrapper for MainActivity
  var Activity = Java.use('com.erev0s.jniapp.MainActivity');
  // replace the Jniint implementation
  Activity.Jniint.implementation = function () {
    // console.log is used to report information back to us
    console.log("Inside Jniint now...");
    // return this number of our choice
    return 80085
  };
});

代码的意思直接明了,我们首先给MainActivity类创建了一个包装对象,然后替换MainActivity类中的Jniint。保存文件,命名为myhook.js
在设备中打开app时,我们需要在JavaScript文件的目录下打开命令行终端。

 

命令是frida -U -l myhook.js com.erev0s.jniapp

 

-U表示通过USB连接设备,-l表示使用JavaScript文件,最后是指定hook的app。注意此命令要求app已经在设备上运行,它不会自动启动。如果想自动启动app,则需使用命令frida -U -l hookNative.js -f com.erev0s.jniapp --no-pause-f会启动指定的app,--no-pause会在app启动后执行主线程。

 

不论用何种方式,结果是一样的,你会看到类似如下的界面:

 

用Java API hook app

 

如你所见,按下按钮后,结果已更改为我们在JavaScript代码中定义的值。至此,我们已经使用Frida的Java API成功更改了Jniint的返回值。

基于Frida框架直接hook native层代码

在我们需要处理C/C++的函数并且仅更改返回结果无法满足需求的情况下,此方法特别有用。比如找出一个加密函数中的特殊参数(也许是密钥)。步骤与上文一致,唯一的变动是JavaScript文件myhook.js的内容有变化:

Interceptor.attach(Module.getExportByName('libnative-lib.so', 'Jniint'), {
    onEnter: function(args) {
    },
    onLeave: function(retval) {
      // simply replace the value to be returned with 0
      retval.replace(0);
    }
});

此处用的API介绍见该链接,它会在libnative-lib.so中自动搜寻Jniint函数,libnative-lib.so即为我们之前解压APK时看到的库文件的名字。调用retval.replace(0)以替换返回值。

 

以与之前相同的方式执行Frida时,会看到报错!不用担心,这是预期内的,因为我们正在尝试hook Jniint,但是由于还未按下按钮,该函数尚未被加载!因此,Frida告诉我们找不到"Jniint"。按下按钮,调用Jniint,然后就可以了。我们唯一要做的就是再次保存我们的JavaScript文件,Frida将自动重新加载之,现在如果再次按下按钮,我们会得到以下信息:

 

在native层hook app

结论

在本文中,我们详细介绍了两种hook native方法并更改其返回值的方法,并介绍了如何配置环境以及安装所有必需的工具。如果你想深入研究Frida,请查阅官方API文档,因为你会找到几乎所有你所需的内容。建议在一开始练习的时候节奏不要太快,因为可能会遇到一些复杂情况。希望你喜欢这篇文章,并能从中学到一些东西。如有任何问题或评论,请随时与我联系,我将尽力回答。

 

原文链接:https://erev0s.com/blog/how-hook-android-native-methods-frida-noob-friendly/

 

翻译:看雪翻译小组 SpearMint

 

校对:看雪翻译小组 skeep


2021 KCTF 秋季赛 防守篇-征题倒计时(11月14日截止)!

收藏
点赞2
打赏
分享
最新回复 (1)
雪    币: 21
活跃值: 活跃值 (227)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jfztaq 活跃值 2021-5-7 07:00
2