免Root使用Frida的一种简易方案

前言

在Android逆向过程中,除了Xposed,还有一个必不可少的Hook神器,那就是Frida。而且,Firida比Xposed功能更加强大,不仅可以实现Java层Hook,还可以实现native层Hook。但是在使用过程中,只能在Root设备才能实现代码的hook。那么是否有免Root使用Frida的方案呢?

关于免Root使用Frida,业内也有一些方案,大致有以下几种:

  1. 使用Apktool反编译Apk,修改smali文件和manifest文件,实现Firda的加载。
    这种方案原理比较简单,实现起来也不算复杂。这篇英文文档中,对此有非常详细的介绍:
    Using Frida on Android without root
    这种方案的本质就是将frida-gadget.so放到反编译后的apk so目录下,并修改反编译后的smali文件,插入System.loadLibrary("frida-gadget")对应的smali代码,从而实现frida的加载。
  2. 使用开源工具Objection
    源码地址:https://github.com/sensepost/objection
    其原理跟方法1类似,也是使用Apktool反编译apk然后植入代码,只是它将这个流程封装成一个工具,使用起来更方便。
  3. 使用LIEF工具修改原so文件,实现对frida-gadget.so的加载
    LIEF工具的官方文档对此有详细的介绍:https://lief.quarkslab.com/doc/latest/tutorials/09_frida_lief.html
    也可参考本文对应的中文翻译文档:https://bbs.pediy.com/thread-229970.htm
    这种方法的基本原理是,利用LIEF工具将frida-gadget.so与原Apk中的某个so文件链接起来,使得加载原so时,同时也加载了frida-gadget.so文件,从而实现Frida工具。
    这种方法有以下几个缺点:
  • 需要向APK里添加文件
  • 需要程序有至少一个native库
  • 注入进去的库的加载顺序不能控制

使用Xpatch实现免Root的Frida功能

Xpatch是笔者开发的一个免Root加载Xposed插件工具
源码地址:https://github.com/WindySha/Xpatch
Xpatch Apk版本Xposed Tool下载地址:https://xposed-tool-app.oss-cn-beijing.aliyuncs.com/data/xposed_tool_v2.0.2.apk

既然Xpatch可以实现免Root加载Xposed插件,那么,Xpatch应该也可以实现免Root使用Frida。

方法其实也比较简单,只需编写一个专门用于加载frida-gadget.so文件的Xposed插件,然后使用Xpatch处理原Apk文件并安装,最后让经Xpatch处理后的Apk加载该该Xposed插件即可。

下面,详细介绍该Xposed插件的实现方法。

用于加载Frida.so的Xposed模块

为了实现Xposed模块中的Frida.so能被其他进程加载,可以通过以下几个步骤:

  1. 将frida-gadget.so文件内置到Xposed插件Apk的lib目录下;
  2. 获取当前插件Apk文件路径,这里有两种方式可以取到:
  • 通过PackageManager和插件Apk的包名获取Apk的安装路径,代码如下:
apkPath = context.getPackageManager().getApplicationInfo(packageName, 0).sourceDir;

这种方法的前提是,插件已经在设备上安装了。

  • 根据加载插件的classLoader,反射获取classLoader里保存的apk路径
    加载Xposed插件模块的classLoader都是一个BaseDexClassLoader,里面保存了此插件的文件路径,通过反射可以获取到:
Field fieldPathList = getClassLoader().getClass().getSuperclass().getDeclaredField("pathList");
fieldPathList.setAccessible(true);
Object dexPathList = fieldPathList.get(AppUtils.class.getClassLoader());

 Field fieldDexElements = dexPathList.getClass().getDeclaredField("dexElements");
fieldDexElements.setAccessible(true);
Object[] dexElements = (Object[]) fieldDexElements.get(dexPathList);
Object dexElement = dexElements[0];

Field fieldDexFile = dexElement.getClass().getDeclaredField("dexFile");
fieldDexFile.setAccessible(true);
Object dexFile = fieldDexFile.get(dexElement);
String apkPath = ((DexFile) dexFile).getName();

这种方法相对比较麻烦,但是其优点是,插件Apk即使没有安装,也可以取到其被加载时的路径,这样更加灵活。当插件是被内置到Apk中加载时,也可以成功获取到其原路径。

  1. 将插件Apk中的frida-gadget.so文件拷贝到主应用的data/data目录下。
    复制so文件也有两种方法,第一种最简单的方案是使用ZipFile读取Apk压缩包中的so文件流,然后写入到指定的文件目录下。
    另外一种方案是利用Android sdk中的隐藏类NativeLibraryHelper,该类在Android源码中的文件路径为:framework/base/core/java/com/android/internal/content/NativeLibraryHelper.java。其中的copyNativeBinaries就是将Apk中的lib文件复制到指定的文件目录下。其实现原理是在native层遍历ZipFile,并将符合条件的so文件复制出来。由于是native层实现的,其运行效率比java层复制效率高,因此推荐使用。
    下面是Android9.0中copyNativeBinaries方法的源码:
* Copies native binaries to a shared library directory.                                   
 *                                                                                         
 * @param handle APK file to scan for native libraries                                     
 * @param sharedLibraryDir directory for libraries to be copied to                         
 * @return {@link PackageManager#INSTALL_SUCCEEDED} if successful or another               
 *         error code from that class if not                                               
 */                                                                                        
public static int copyNativeBinaries(Handle handle, File sharedLibraryDir, String abi) {   
    for (long apkHandle : handle.apkHandles) {                                             
        int res = nativeCopyNativeBinaries(apkHandle, sharedLibraryDir.getPath(), abi,     
                handle.extractNativeLibs, HAS_NATIVE_BRIDGE, handle.debuggable);           
        if (res != INSTALL_SUCCEEDED) {                                                    
            return res;                                                                    
        }                                                                                  
    }                                                                                      
    return INSTALL_SUCCEEDED;                                                              
}                                                                                          

  1. 调用System.loadLibrary()方法,加载data/data目录下的frida-gadget.so文件。
    so加载成功,便实现了免Root使用Frida。

验证

为了验证该Xposed插件可以实现免Root使用Frida,我们将此插件安装到基于Android6.0.1的Nexus5手机上,并安装Xposed Tool(Xpatch App版本)工具,使用Xposed Tool破解任意一个未加固未防二次打包的应用。然后,在Xposed模块管理中启用此Xposed插件。

我们启动被破解的应用后,发现应用卡在启动界面,这说明,Xposed插件中的frida-gadget.so文件加载成功。
然后将手机连接PC,启动USB调试模式。并在命令行输入:
frida -U gadget -l ../test.js
其中,在test.js中,我们简单地拦截了Activity的onCreate方法和onResume方法,其实现如下:

// test.js
Java.perform(function() {
   var Activity = Java.use("android.app.Activity");
    Activity.onCreate.overload('android.os.Bundle').implementation = function(arg1) {
       console.log("Activity onCreate() got called!  ");
       this.onCreate(arg1);
   }

   Activity.onResume.implementation = function() {
       console.log(" Activity onResume() got called!  ");
       this.onResume();
   }
})

命令行回车后,App成功进入主界面,并在命令行中打印出如下日志:

[Nexus 5::gadget]-> Activity onCreate() got called!  
 Activity onResume() got called! 

成功hook了Activity的onCreate和onResume方法。
这说明test.js中hook代码已生效,免Root环境成功跑通了Frida!!

不足之处

经过测试发现,在部分机型上,部分App上使用frida -U gadget -l ../test.js命令,提示“ Server terminated”或者“Failed to load script: timeout was reached ”,暂时未找到问题原因。

源码

此Xposed插件源码已上传到Github:FridaXposedModule
欢迎Star and Fork。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342