Android Hook工具之Frida 基础使用

在上一篇文章Android Hook工具之Frida 安装配置教程
中讲解了如何安装配置Frida工作环境,这篇文章主要讲解一下Frida的基础使用方式.

在运行以下任何命令之前必须先启动手机中的frida-server

  • 使用frida-trace命令跟踪某个特定的函数:
    frida-trace -U -i [函数名] [程序包名]
    例: 跟踪Chrome中的open函数,先在手机中启动Chrome,否则会跟踪失败,启动后,在终端窗口中输入frida-trace命令
frida-trace -U -i open com.android.chrome
Instrumenting functions...                                              
open: Auto-generated handler at "/Users/wangw/unapk/frida/__handlers__/libc.so/open.js"
Started tracing 1 function. Press Ctrl+C to stop. 

跟踪成功后,会在当前路径下创建以下JavaScript文件(/Users/wangw/unapk/frida/handlers/libc.so/open.js),Frida会将JavaScript文件中的代码注入到进程中并跟踪指定的函数调用,可以修改生成的JavaScript文件实现Hook功能,下面就是自动生成Js文件内容

{
  onEnter: function (log, args, state) {
    log("open(" +
      "path=\"" + Memory.readUtf8String(args[0]) + "\"" +
      ", oflag=" + args[1] +
    ")");
  },

  onLeave: function (log, retval, state) {
  }
}

跟踪成功后就会打印出Chrome调用open函数每一次调用,输出结果类似下面这样:

frida-trace -U -i open com.android.chrome
Instrumenting functions...                                              
open: Auto-generated handler at "/Users/wangw/unapk/frida/__handlers__/libc.so/open.js"
Started tracing 1 function. Press Ctrl+C to stop.                       
           /* TID 0x2252 */
  1312 ms  open(path="/data/user/0/com.android.chrome/code_cache/com.android.opengl.shaders_cache", oflag=0xc2)
  1314 ms  open(path="/data/user/0/com.android.chrome/code_cache/com.android.opengl.shaders_cache", oflag=0xc2)
           /* TID 0x2298 */
  3264 ms  open(path="/data/user/0/com.android.chrome/shared_prefs/com.android.chrome_preferences.xml", oflag=0x241)
  • 强制启动一个应用进程
    frida -U --no-pause -f [应用包名]
    使用-f选项表示强制启动一个应用程序,--no-pause选项表示不中断应用程序的启动,如果不使用这个选项总是会遇到 在强制启动应用程序2秒左右后程序自动退出,
    例: 强制启动Chrome并attach到当前进程
frida -U --no-pause -f com.android.chrome
     ____
    / _  |   Frida 10.6.52 - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at http://www.frida.re/docs/home/
Spawned `com.android.chrome`. Resuming main thread!                     
[HUAWEI EVA-AL10::com.android.chrome]-> 

当attach成功后,就可以开始Hook Java函数和对象了。
关于Friada框架中Java部分的API可以查看官方文档,下面总结几个常用的API。

  • Java.available 返回一个Boolean值,表示当前进程是否加载了 JVM也就是是否运行在Dalvik 或 ART环境中.如果返回false则Java 相关的API则无法调用
[HUAWEI EVA-AL10::com.android.chrome]-> Java.available
true
  • Java.enumerateLoadedClasses(callbacks) 列出已加载的类
[HUAWEI EVA-AL10::com.android.chrome]-> Java.perform(function(){Java.enumerateLo
adedClasses({"onMatch":function(className){ console.log(className) },"onComplete
":function(){console.log(onComplete) }})})
org.chromium.chrome.browser.ntp.ContentSuggestionsNotifier
org.chromium.chrome.browser.snackbar.undo.UndoBarController

所有的代码逻辑都封装在Java.perform(function(){ … })中,逻辑很简单,就是使用Java.enumerateLoadedClassesFridas API 列出所有已加载的类,并将每个类的className输出到控制台,这种使用方式是Frida框架中最常用的,它其实就是一个回调对象模板,

{
  "onMatch":function(arg1, ...){ ... },
  "onComplete":function(){ ... },
}

一旦Frida匹配到你的请求,就会使用一个或多个参数调用onMeth方法,如果匹配完成时就会调用onComplete,

  • Java.use(className) 根据className动态获取一个JavaScript wrapper,获取到后可以调用$new()方法来实例化一个对象,也可以调用$dispose()方法进行释放
Java.perform(function () {
    var Activity = Java.use("android.app.Activity");
    var Exception = Java.use("java.lang.Exception");
    Activity.onResume.implementation = function () {
        throw Exception.$new("Test!");
    };
});
  • Frida框架还支持加载外部脚本代码,而不用直接写到Cli中运行,使用-f选项后面跟着脚本文件路径即可,比如我们将上面的代码保存到一个文件中并命名为Test.js,使用命令运行:
frida -U -l Test.js --no-pause -f com.android.chrome
  • Frida有时候会有超时的提示,为防止这种情况,可以将脚本里面的代码包装在setImmediate函数中或导出为rpc
    例: 将Test.js中的代码修改一下,然后再次运行上面的命令重新部署一下即可。
setImmediate(function() {
    Java.perform(function () {
    var Activity = Java.use("android.app.Activity");
    var Exception = Java.use("java.lang.Exception");
    Activity.onResume.implementation = function () {
        throw Exception.$new("Test!");
    };
});
});

如何Hook一个java方法

  1. 使用Java.use(className)命令获取 JavaScript wrapper
  2. 调用获取到的 JavaScript wrapper对象的方法[JavaScript wrapper对象].[要Hook的方法名].implementation=function(){...}

注1: 如果要Hook的方法有多个重载时,必须使用overload()方法调用,参数必须是完全匹配的,参数类型必须是全类名的也就是全引用名的。
注2: Hook方法中的参数,可以通过arguments数组访问,也可以在implementation函数中声明对应的形参

Android 代码:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.mBtnTest).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View v) {
                helloAndroid();
                test1();
                test2(123);
                test3("str");
                test4("str", true);
            }
        });
    }
    
    private void helloAndroid() {
        System.out.println("helloAndroid()");
    }

    private void test() {
        System.out.println("test1()");
    }

    private void test(int i) {
        System.out.println("test2(int) " + i);
    }

    private void test(String s) {
        System.out.println("test3(String) " + s);
    }

    private void test(String s, boolean b) {
        System.out.println("test4(String, boolean) " + s + ", " + b);
    }
}

JavaScript Hook代码

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

推荐阅读更多精彩内容