Android逆向之hook框架frida篇

作者: parkerpeng | 来源:发表于2016-09-19 21:28 被阅读10114次

    前言

    Frida是一款基于python + javascript 的hook框架,通杀android\ios\linux\win\osx等各平台,由于是基于脚本的交互,因此相比xposed和substrace cydia更加便捷,本文重点介绍Frida在android下面的使用。Frida的官网为:http://www.frida.re/

    安装和搭建Frida环境

    首先要保证你的android手机已经root。通过pip安装frida:

    pip install frida

    下载frida-server:

    frida_server的下载地址:https://github.com/frida/frida/releases

    到android手机上并且运行

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

    转发android TCP端口到本地:

    adb forward tcp:27042 tcp:27042
    adb forward tcp:27043 tcp:27043

    测试frida环境,如果出现android手机的进程列表说明搭建成功:

    frida-ps -R
    PID Name


    2700 acceleratord
    2713 adbd
    2798 agnsscontrol
    2799 agnsslog
    2195 akmd09911
    8078 android.process.acore
    31283 android.process.media
    2185 atcmdserver
    4939 chargelogcat
    2796 chr_logd
    22856 com.android.browser
    7912 com.android.contacts
    22417 com.android.gallery3d
    ....

    得到android手机当前最前端Activity所在的进程

    get_front_app.py

    其中get_front_app.py的内容如下:

    import frida
    rdev = frida.get_remote_device()
    front_app = rdev.get_frontmost_application()
    print front_app
    

    枚举android手机所有的进程

    enum_process.py

    enum_process.py内容如下:

    import frida
    rdev = frida.get_remote_device()
    processes = rdev.enumerate_processes()
    for process in processes:
        print process
    

    枚举某个进程加载的所有模块以及模块中的导出函数

    import frida
    rdev = frida.get_remote_device()
    session = rdev.attach("com.tencent.mm")  #如果存在两个一样的进程名可以采用rdev.attach(pid)的方式
    modules = session.enumerate_modules()
    for module in modules:
        print module
        export_funcs = module.enumerate_exports()
        print "\tfunc_name\tRVA"
        for export_func in export_funcs:
            print "\t%s\t%s"%(export_func.name,hex(export_func.relative_address))
    

    hook android的native函数

    import frida
    import sys
    rdev = frida.get_remote_device()
    session = rdev.attach("com.tencent.mm")
    scr = """
    Interceptor.attach(Module.findExportByName("libc.so" , "open"), {
        onEnter: function(args) {
            send("open("+Memory.readCString(args[0])+","+args[1]+")");
        },
        onLeave:function(retval){
        
        }
    });
    """
    script = session.create_script(scr)
    def on_message(message ,data):
        print message
    script.on("message" , on_message)
    script.load()
    sys.stdin.read()
    

    hook android的java层函数

    如下代码为hook微信(测试版本为6.3.13,不同版本由于混淆名字的随机生成的原因或者代码改动导致类名不一样)
    com.tencent.mm.sdk.platformtools.ay类的随机数生成函数,让微信猜拳随机(type=2),而摇色子总是为6点(type=5)

    import frida
    import sys
    rdev = frida.get_remote_device()
    session = rdev.attach("com.tencent.mm")
    
    scr = """
    Java.perform(function () {
    var ay = Java.use("com.tencent.mm.sdk.platformtools.ay");
    ay.pu.implementation = function(){
        var type = arguments[0];
        send("type="+type);
        if (type == 2)
        {
        return this.pu(type);
        }
        else
        {
        return 5;
        }
    };
    
    });
    """
    
    script = session.create_script(scr)
    def on_message(message ,data):
        print message
    script.on("message" , on_message)
    script.load()
    sys.stdin.read()
    

    通过frida向android进程注入dex

    import frida, sys, optparse, re
    def on_message(message, data):
        if message['type'] == 'send':
            print("[*] {0}".format(message['payload']))
        else:
            print(message)
    
    jscode = """
    Java.perform(function () {
        var currentApplication = Java.use("android.app.ActivityThread").currentApplication();
        var context = currentApplication.getApplicationContext();
        var pkgName = context.getPackageName();
        var dexPath = "%s";
        var entryClass = "%s";
        Java.openClassFile(dexPath).load();
        console.log("inject " + dexPath +" to " + pkgName + " successfully!")
        Java.use(entryClass).%s("%s");
        console.log("call entry successfully!")
    });
    """
    
    def checkRequiredArguments(opts, parser):
        missing_options = []
        for option in parser.option_list:
            if re.match(r'^\[REQUIRED\]', option.help) and eval('opts.' + option.dest) == None:
                missing_options.extend(option._long_opts)
        if len(missing_options) > 0:
            parser.error('Missing REQUIRED parameters: ' + str(missing_options))
    
    if __name__ == "__main__":
        usage = "usage: python %prog [options] arg\n\n" \
                "example: python %prog -p com.android.launcher " \
                "-f /data/local/tmp/test.apk " \
                "-e com.parker.test.DexMain/main " \
                "\"hello fridex!\""
        parser = optparse.OptionParser(usage)
        parser.add_option("-p", "--package", dest="pkg", type="string",
                          help="[REQUIRED]package name of the app to be injected.")
        parser.add_option("-f", "--file", dest="dexPath", type="string",
                          help="[REQUIRED]path of the dex")
        parser.add_option("-e", "--entry", dest="entry", type="string",
                          help="[REQUIRED]the entry function Name.")
    
        (options, args) = parser.parse_args()
        checkRequiredArguments(options, parser)
        if len(args) == 0:
            arg = ""
        else:
            arg = args[0]
    
        pkgName = options.pkg
        dexPath = options.dexPath
        entry = options.entry.split("/")
        if len(entry) > 1:
            entryClass = entry[0]
            entryFunction = entry[1]
        else:
            entryClass = entry[0]
            entryFunction = "main"
    
        process = frida.get_usb_device(1).attach(pkgName)
        jscode = jscode%(dexPath, entryClass, entryFunction, arg)
        script = process.create_script(jscode)
        script.on('message', on_message)
        print('[*] Running fridex')
        script.load()
        sys.stdin.read()
    

    通过注入抛出异常代码实现跟踪程序调用栈

    在<<Android 软件安全与逆向分析>>这本书中第八章有介绍通过重打包写入异常代码进行栈跟踪,但是这样比较麻烦,使用frida注入更方便。

    frida的相关资源

    https://github.com/dweinstein/awesome-frida
    http://jaq.alibaba.com/community/art/show?articleid=816
    https://koz.io/using-frida-on-android-without-root/
    http://www.ninoishere.com/frida-learn-by-example/
    https://github.com/TheCjw/Frida-Android-Scripts

    相关文章

      网友评论

      • itzhu:attach 失败 报frida.TransportError: the connection is closed 这个怎么处理啊
        import frida
        rdev = frida.get_remote_device()
        front_app = rdev.get_frontmost_application()
        print front_app

        apps = rdev.enumerate_applications()
        for app in apps: print app

        session = rdev.attach("com.ss.android.article.news")
        前面的命令不会出错,到session就报错了,已经安装了app.有谁碰到的说下解决方案,谢谢大虾门。模拟器是天天模拟器4.4.4的系统 frida-server 用的这个frida-server-10.6.50-android-x86
        itzhu:Application(identifier="com.android.chrome", name="Chrome")
        Application(identifier="com.android.providers.downloads", name="下载管理程序", pid=2033)
        Application(identifier="com.android.musicfx", name="MusicFX")
        Traceback (most recent call last):
        File "H:/ScriptDevelopment/python_work/toutiao.py", line 9, in <module>
        session = rdev.attach("com.ss.android.article.news")
        File "E:\python\lib\site-packages\frida\core.py", line 97, in attach
        return Session(self._impl.attach(self._pid_of(target)))
        frida.TransportError: the connection is closed
      • 三生石的誓言:hi,写得挺好的。顺便咨询下,《通过frida向android进程注入dex》这节中,能否把test.apk分享下,我报了“ error: Missing REQUIRED parameters: ['--package', '--file']”这个错误。多谢~
      • 切忌浮躁:hi,我的系统是4.1.1,so可以hook成功,java死活就是不成功,多简单的代码都报错,https://github.com/frida/frida/issues/250 这个issues,不知道你是否遇到过,或者是我少安装了什么?请教下。
        parkerpeng:@切忌浮躁 用frida时最好用nexus系列手机,其它经过定制rom的手机他们是没有经过测试的。
      • difcareer:这个不错,能hook art 么
        ohyeah521:@difcareer 目前在4.x下兼容性最好,5.0以上各种权限控制,不稳定,各种异常,很烦人

      本文标题:Android逆向之hook框架frida篇

      本文链接:https://www.haomeiwen.com/subject/uklisttx.html