FRIDA 实用手册

简介: # FRIDA 实用手册 本文目的是作为工具类文章,收集整理了一些 FRIDA 的使用技巧和用例,方便同学们在开发使用过程中开袋即食。 frida 的基础教程可以直接参看[官网说明](https://www.frida.re/docs/examples/android/)。

FRIDA 实用手册

本文目的是作为工具类文章,收集整理了一些 FRIDA 的使用技巧和用例,方便同学们在开发使用过程中开袋即食。

frida 的基础教程可以直接参看官网说明

Python 部分

JS 中文支持

使用 codecs.open(scriptpath, "r", "utf-8") 打开文件读取 js 即可。

获取指定 UID 设备

device = frida.get_device_manager().get_device("094fdb0a0b0df7f8")

获取远程设备

mgr = frida.get_device_manager()
device = mgr.add_remote_device("30.137.25.128:13355")

启动调试进程

pid = device.spawn([packename])
process = device.attach(pid)
script = process.create_script(jscode)
script.on('message', on_message)
script.load()
device.resume(pid)

python 与 js 交互的官方示例

from __future__ import print_function
import frida
import sys

session = frida.attach("hello")
script = session.create_script("""
Interceptor.attach(ptr("%s"), {
    onEnter: function(args) {
        send(args[0].toString());
        var op = recv('input', function(value) {
            args[0] = ptr(value.payload);
        });
        op.wait();
    }
});
""" % int(sys.argv[1], 16))
def on_message(message, data):
    print(message)
    val = int(message['payload'], 16)
    script.post({'type': 'input', 'payload': str(val * 2)})
script.on('message', on_message)
script.load()
sys.stdin.read()

从 bytecode 加载脚本

# -*- coding: utf-8 -*-
from __future__ import print_function

import frida


system_session = frida.attach(0)
bytecode = system_session.compile_script(name="bytecode-example", source="""\
'use strict';
rpc.exports = {
  listThreads: function () {
    return Process.enumerateThreadsSync();
  }
};
""")

session = frida.attach("Twitter")
script = session.create_script_from_bytes(bytecode)
script.load()
api = script.exports
# 这里的 list_threads 是 listThreads 驼峰命名法自动转换后的结果,由 rpc exports 功能导出给 python 调用
print("api.list_threads() =>", api.list_threads())   

JS 部分

hook Android 短信发送 SendDataMessage

function hook_sms() {
    var SmsManager = Java.use('android.telephony.SmsManager');
    SmsManager.sendDataMessage.implementation = function (
        destinationAddress, scAddress, destinationPort, data, sentIntent, deliveryIntent) {
        console.log("sendDataMessage destinationAddress: " + destinationAddress + " port: " + destinationPort);
        showStacks();
        this.sendDataMessage(destinationAddress, scAddress, destinationPort, data, sentIntent, deliveryIntent);
    }
}

定时执行函数

  1. setTimeout 延迟执行一次
setTimeout(funcA, 15000);
  1. setInterval 间隔循环执行
var id_ = setInterval(funcB, 15000);
clearInterval(id_);    // 终止

bin array 转字符串

function bin2String(array) {
    if (null == array) {
        return "null";
    }
    var result = "";
    try {
        var String_java = Java.use('java.lang.String');
        result = String_java.$new(array);
    }
    catch (e) {
        dmLogout("== use bin2String_2 ==");
        result = bin2String_2(array);
    }

    return result;
}

function bin2String_2(array) {
    var result = "";
    try {
        var tmp = 0;
        for (var i = 0; i < array.length; i++) {
            tmp = parseInt(array[i]);
            if ( tmp == 0xc0
                || (tmp < 32 && tmp != 10)
                || tmp > 126 )  {
                return result;
            }  // 不是可见字符就返回了, 换行符除外
            result += String.fromCharCode(parseInt(array[i].toString(2), 2));
        }
    }
    catch (e) {
        console.log(e);
    }
    return result;
}

自己封装输出函数加入线程ID 和时间


function getFormatDate() {
    var date = new Date();
    var month = date.getMonth() + 1;
    var strDate = date.getDate();
    if (month >= 1 && month <= 9) {
        month = "0" + month;
    }
    if (strDate >= 0 && strDate <= 9) {
        strDate = "0" + strDate;
    }
    var currentDate = date.getFullYear() + "-" + month + "-" + strDate
            + " " + date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds();
    return currentDate;
}

function dmLogout(str) {
    var threadid = Process.getCurrentThreadId();
    console.log("["+threadid+"][" + getFormatDate() + "]" + str);
}

打印 Android Java 层堆栈

var showStacks = function () {
    Java.perform(function () {
        dmLogout(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));  // 打印堆栈
    });
}

TracerPid fgets 反调试

var anti_fgets = function () {
    dmLogout("anti_fgets");
    var fgetsPtr = Module.findExportByName("libc.so", "fgets");
    var fgets = new NativeFunction(fgetsPtr, 'pointer', ['pointer', 'int', 'pointer']);
    Interceptor.replace(fgetsPtr, new NativeCallback(function (buffer, size, fp) {
        var retval = fgets(buffer, size, fp);
        var bufstr = Memory.readUtf8String(buffer);
        if (bufstr.indexOf("TracerPid:") > -1) {
            Memory.writeUtf8String(buffer, "TracerPid:\t0");
            // dmLogout("tracerpid replaced: " + Memory.readUtf8String(buffer));
        }
        return retval;
    }, 'pointer', ['pointer', 'int', 'pointer']));
};

反调试时读取 LR 寄存器溯源

var anti_antiDebug = function() {
    var funcPtr = null;

     funcPtr = Module.findExportByName("xxxx.so", "p57F7418DCD0C22CD8909F9B22F0991D3");

    dmLogout("anti_antiDebug " + funcPtr);
    Interceptor.replace(funcPtr, new NativeCallback(function (pathPtr, flags) {
        dmLogout("anti ddddddddddddddebug LR: " + this.context.lr);
        return 0;
    }, 'int', ['int', 'int']));
};

hook JNI API NewStringUTF

function hook_native_newString() {
    var env = Java.vm.getEnv();
    var handlePointer = Memory.readPointer(env.handle);
    dmLogout("env handle: " + handlePointer);
    var NewStringUTFPtr = Memory.readPointer(handlePointer.add(0x29C));
    dmLogout("NewStringUTFPtr addr: " + NewStringUTFPtr);
    Interceptor.attach(NewStringUTFPtr, {
        onEnter: function (args) {
            ...
        }
    });
}

hook JNI API GetStringUTFChars

function hook_native_GetStringUTFChars() {
    var env = Java.vm.getEnv();
    var handlePointer = Memory.readPointer(env.handle);
    dmLogout("env handle: " + handlePointer);
    var GetStringUTFCharsPtr = Memory.readPointer(handlePointer.add(0x2A4));
    dmLogout("GetStringUTFCharsPtr addr: " + GetStringUTFCharsPtr);
    Interceptor.attach(GetStringUTFCharsPtr, {
        onEnter: function (args) {
            var str = "";
            Java.perform(function () {
                str = Java.cast(args[1], Java.use('java.lang.String'));
            });
            dmLogout("GetStringUTFChars: " + str);
            if (str.indexOf("linkData:") > -1) {    // 设置过滤条件
                dmLogout("========== found linkData LR: " + this.context.lr + "  ==========");
            }
        }
    });
};

hook Android URI 打印堆栈

var hook_uri = function() {
    // coord: (7520,0,19) | addr: Ljava/net/URI;->parseURI(Ljava/lang/String;Z)V | loc: ?
    var uri = Java.use('java.net.URI');
    uri.parseURI.implementation = function (a1, a2) {
        a1 = a1.replace("xxxx.com", "yyyy.com");

        dmLogout("uri: " + a1);
        showStacks();
        return this.parseURI(a1, a2);
    }
}

hook KXmlSerializer 拼装内容

function hook_xml() {
    var xmlSerializer = Java.use('org.kxml2.io.KXmlSerializer');    // org.xmlpull.v1.XmlSerializer
    xmlSerializer.text.overload('java.lang.String').implementation = function (text) {
        dmLogout("xtext: " + text);
        if ("GPRS" == text) {
            dmLogout("======>>> found GPRS");
            showStacks();
        }
        return this.text(text);
    }
}

hook Android Log 输出

function hook_log() {
    dmLogout(TAG, "do hook log");
    var Log = Java.use('android.util.Log');
    Log.v.overload('java.lang.String', 'java.lang.String').implementation = function (tag, content) {
        dmLogout(tag + " v", content);
    };
    Log.d.overload('java.lang.String', 'java.lang.String').implementation = function (tag, content) {
        dmLogout(tag + " d", content);
    };
    Log.w.overload('java.lang.String', 'java.lang.String').implementation = function (tag, content) {
        dmLogout(tag + " w", content);
    };
    Log.i.overload('java.lang.String', 'java.lang.String').implementation = function (tag, content) {
        dmLogout(tag + " i", content);
    };
    Log.e.overload('java.lang.String', 'java.lang.String').implementation = function (tag, content) {
        dmLogout(tag + " e", content);
    };
}

native 主动调用

var friendlyFunctionName = new NativeFunction(friendlyFunctionPtr, 'void', ['pointer', 'pointer']);
var returnValue = Memory.alloc(sizeOfLargeObject);
friendlyFunctionName(returnValue, param1);

就先整理这么多,日后再追加。欢迎大佬们追加分享和指正错误。

目录
相关文章
|
存储 算法 数据安全/隐私保护
【密码学】一文读懂白盒AES(Chow方案)(一)
本文主要参考了文献^[1], 代码参考了^[2], 这里感谢文献作者和代码作者,如果有能力的大佬,可以自行查看原文献,个人水平有限,有哪里写的不对的地方,也欢迎读者指正。
4620 0
【密码学】一文读懂白盒AES(Chow方案)(一)
|
Java API Android开发
你有没有想过自己写一个Xposed模块?教程来了~(一)
在互联网上,关于Xposed模块编写的教程可谓是一抓一大把。但由于时间的推移,很多工具和方法都发生了变化(如Eclipse退出安卓编程舞台,AndroidStudio 不断升级导致其一些设置也随之变化等)也正因此,网上的教程往往有一些时限性,比如现如今 provide 这个关键字已经被舍弃了却仍有人在用,还有些说要把jar包放到lib文件夹而非libs文件夹……种种错误或者落伍的教程对新手产生了很大的误导。
605 0
|
Oracle 安全 Java
安卓逆向 -- Unidbg环境搭建篇
安卓逆向 -- Unidbg环境搭建篇
738 3
|
安全 Linux 网络安全
【工具使用】几款优秀的SSH连接客户端软件工具推荐FinalShell、Xshell、MobaXterm、OpenSSH、PUTTY、Terminus、mRemoteNG、Terminals等
【工具使用】几款优秀的SSH连接客户端软件工具推荐FinalShell、Xshell、MobaXterm、OpenSSH、PUTTY、Terminus、mRemoteNG、Terminals等
121080 0
Vue3项目引入 vue-quill 编辑器组件并封装使用
本文介绍了如何在Vue3项目中引入并封装使用`vue-quill`富文本编辑器组件,包括安装配置、父页面实现、子组件设计以及使用方法和效果展示。
2799 0
Vue3项目引入 vue-quill 编辑器组件并封装使用
|
存储 数据安全/隐私保护
App逆向百例|16|某交友App花指令分析
App逆向百例|16|某交友App花指令分析
666 0
|
存储 缓存 JSON
详解HTTP四种请求:POST、GET、DELETE、PUT
【4月更文挑战第3天】
67976 5
详解HTTP四种请求:POST、GET、DELETE、PUT
|
Go C语言 Windows
【教程】使用 IDA Pro + 010 Editor 反编译和修改 so 文件,让你轻松玩转逆向工程!
当我们在做逆向工作时,总会遇到需要查看某个 so 文件的情况,甚至可能需要对其进行一些微小的修改。这时候,我们就需要来点反编译的魔法了。
11422 0
【教程】使用 IDA Pro + 010 Editor 反编译和修改 so 文件,让你轻松玩转逆向工程!
npm install 太慢?解决方法
npm install 太慢?解决方法
10984 0
App逆向百例|18|某A系防护SO跳转修复
App逆向百例|18|某A系防护SO跳转修复
1130 0