frida

1.基本理解

frida是一个优秀的跨系统、跨平台的开源注入框架,既能hook java层,也能hook native层,而且安装简单便捷。不过局限性是手机要root权限。
动态注入与hook都会修改目标程序的运行行为,但它们最大的区别在于:使用hook框架对程序hook后,会修改原方法或函数的指针,让其转去执行hook的方法,而动态注入则通过进程读写技术将一段代码或程序写到目标程序的内存空间,然后修改目标程序的指令指针,让加载代码得以执行。

2.基本流程

frida安装网上有安装教程
本文主要叙述python+js式hook;

import frida
import sys

# hook逻辑脚本;有时候会单独写个js脚本,然后文件读取(最好别有汉字);
jscode=open('file.js').read()

#连接usb设备
redv = frida.get_usb_device()    
# 注入进程,attach传入进程名称(字符串)或者进程号(整数)
session = frida.attach("进程名称")
script = session.create_script(jscode)


# 接收脚本信息的回调函数
# message是一个对象,type属性为send则表示send函数发送的信息,其内容在payload里
# 下面这个on_message函数可以做固定用法,一般无需改动,当然也可直接打印message看看里边的内容
def on_message(message, data):
    if message['type'] == 'send':
        print("[*]{0}".format(message['payload']))
    elif :
        print(message)
# 应该是设置message事件的回调函数
script.on('message', on_message)
# 加载hook脚本
script.load()
#卸载脚本,如果只想运行一次就修改参数可能需要卸载脚本
#定义一个全局变量判断是否得到自己想要的结果;global定义
#script.unload()
# 保持主线程不结束(也可以使用time.sleep循环)
sys.stdin.read()


上面的脚本一般不需要变动,真正需要改动的在file.js里面;

#因为hookjava方法;外层要进行封装;
Java.perform(function(){
	#里面写包名.类名
    var tblives= Java.use('com.taobao.taolive.room.ui.chat.ChatController');
	#写方法名;function里面输入参数也可以不写用arguments传入
	#方法体里面才是真正需要改动的东西;每当程序执行这个方法,就会被frida勾住,执行下面的程序块
	#
    tblives.setupChatTopMessage.implementation=function(a,b) {
        #js里面打印,python获取不到
        console.log(" start hook");
        console.log(" a:",a);
        console.log(" b:",b);
        #send方法也是输出,但是会经过回调函数到python脚本里面,可以对结果进行调用
        send(a)
        
		#下面相当于还是执行的原方法的逻辑,没做改动
        var abc = this.setupChatTopMessage(a,b);
        return abc;

        }
        
    })
;

2.1 hook java方法汇总

2.1.1 hook 重载函数使用overload

var   tblives= Java.use('com.taobao.taolive.room.ui.chat.ChatTopMessage');  
#这个是构造函数的重载
tblives.$init.overload("int","java.lang.String","java.lang.String","com.taobao.taolive.sdk.adapter.message.TLiveMsg").implementation=function(a,b,c,d) {}

2.1.2 hook构造函数用$init

代码见上

2.1.3 hook 内部类用$

#类里面又定义了一个类
var inInnerClass = Java.use('ese.xposedtest.MainActivity$inInnerClass');

2.1.4 hook 生成对象使用$new

const JavaString = Java.use('java.lang.String');
var exampleString1 = JavaString.$new('Hello World, this is an example string in Java.');
console.log('[+] exampleString1: ' + exampleString1);

2.1.5 hook 静态变量(属性)用反射的方法

在这里插入代码片

3. 进阶教学

主要是对frida的应用

3.1 打印动态加载的插件

Java.perform(function(){
		#加载jar/apk/dex
        var dexclassLoader = Java.use("dalvik.system.DexClassLoader");
        dexclassLoader.$init.implementation = function(dexPath,optimizedDirectory,librarySearchPath,parent) {
            #dex路径
            console.log("dexPath:" + dexPath);
            #输出优化后的dex文件
            console.log("optimizedDirectory:" + optimizedDirectory);
            #动态库路径
            console.log("librarySearchPath:" + librarySearchPath);
            #制定父类加载器
            console.log("parent:" + parent);

            this.$init(dexPath, optimizedDirectory, librarySearchPath, parent);
        }
        console.log("down!");

});

3.2打印native方法在so的位置偏移


var ishook_libart = false;

function hook_libart() {
    if (ishook_libart === true) {
        return;
    }
    var symbols = Module.enumerateSymbolsSync("libart.so");
    var addrGetStringUTFChars = null;
    var addrNewStringUTF = null;
    var addrFindClass = null;
    var addrGetMethodID = null;
    var addrGetStaticMethodID = null;
    var addrGetFieldID = null;
    var addrGetStaticFieldID = null;
    var addrRegisterNatives = null;
    var addrAllocObject = null;
    var addrCallObjectMethod = null;
    var addrGetObjectClass = null;
    var addrReleaseStringUTFChars = null;
    for (var i = 0; i < symbols.length; i++) {
        var symbol = symbols[i];
        if (symbol.name == "_ZN3art3JNI17GetStringUTFCharsEP7_JNIEnvP8_jstringPh") {
            addrGetStringUTFChars = symbol.address;
            console.log("GetStringUTFChars is at ", symbol.address, symbol.name);
        } else if (symbol.name == "_ZN3art3JNI12NewStringUTFEP7_JNIEnvPKc") {
            addrNewStringUTF = symbol.address;
            console.log("NewStringUTF is at ", symbol.address, symbol.name);
        } else if (symbol.name == "_ZN3art3JNI9FindClassEP7_JNIEnvPKc") {
            addrFindClass = symbol.address;
            console.log("FindClass is at ", symbol.address, symbol.name);
        } else if (symbol.name == "_ZN3art3JNI11GetMethodIDEP7_JNIEnvP7_jclassPKcS6_") {
            addrGetMethodID = symbol.address;
            console.log("GetMethodID is at ", symbol.address, symbol.name);
        } else if (symbol.name == "_ZN3art3JNI17GetStaticMethodIDEP7_JNIEnvP7_jclassPKcS6_") {
            addrGetStaticMethodID = symbol.address;
            console.log("GetStaticMethodID is at ", symbol.address, symbol.name);
        } else if (symbol.name == "_ZN3art3JNI10GetFieldIDEP7_JNIEnvP7_jclassPKcS6_") {
            addrGetFieldID = symbol.address;
            console.log("GetFieldID is at ", symbol.address, symbol.name);
        } else if (symbol.name == "_ZN3art3JNI16GetStaticFieldIDEP7_JNIEnvP7_jclassPKcS6_") {
            addrGetStaticFieldID = symbol.address;
            console.log("GetStaticFieldID is at ", symbol.address, symbol.name);
        } else if (symbol.name == "_ZN3art3JNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi") {
            addrRegisterNatives = symbol.address;
            console.log("RegisterNatives is at ", symbol.address, symbol.name);
        } else if (symbol.name.indexOf("_ZN3art3JNI11AllocObjectEP7_JNIEnvP7_jclass") >= 0) {
            addrAllocObject = symbol.address;
            console.log("AllocObject is at ", symbol.address, symbol.name);
        }  else if (symbol.name.indexOf("_ZN3art3JNI16CallObjectMethodEP7_JNIEnvP8_jobjectP10_jmethodIDz") >= 0) {
            addrCallObjectMethod = symbol.address;
            console.log("CallObjectMethod is at ", symbol.address, symbol.name);
        } else if (symbol.name.indexOf("_ZN3art3JNI14GetObjectClassEP7_JNIEnvP8_jobject") >= 0) {
            addrGetObjectClass = symbol.address;
            console.log("GetObjectClass is at ", symbol.address, symbol.name);
        } else if (symbol.name.indexOf("_ZN3art3JNI21ReleaseStringUTFCharsEP7_JNIEnvP8_jstringPKc") >= 0) {
            addrReleaseStringUTFChars = symbol.address;
            console.log("ReleaseStringUTFChars is at ", symbol.address, symbol.name);
        }
    }

    if (addrRegisterNatives != null) {
        Interceptor.attach(addrRegisterNatives, {
            onEnter: function (args) {
                console.log("[RegisterNatives] method_count:", args[3]);
                var env = args[0];
                var java_class = args[1];
                
                var funcAllocObject = new NativeFunction(addrAllocObject, "pointer", ["pointer", "pointer"]);
                var funcGetMethodID = new NativeFunction(addrGetMethodID, "pointer", ["pointer", "pointer", "pointer", "pointer"]);
                var funcCallObjectMethod = new NativeFunction(addrCallObjectMethod, "pointer", ["pointer", "pointer", "pointer"]);
                var funcGetObjectClass = new NativeFunction(addrGetObjectClass, "pointer", ["pointer", "pointer"]);
                var funcGetStringUTFChars = new NativeFunction(addrGetStringUTFChars, "pointer", ["pointer", "pointer", "pointer"]);
                var funcReleaseStringUTFChars = new NativeFunction(addrReleaseStringUTFChars, "void", ["pointer", "pointer", "pointer"]);

                var clz_obj = funcAllocObject(env, java_class);
                var mid_getClass = funcGetMethodID(env, java_class, Memory.allocUtf8String("getClass"), Memory.allocUtf8String("()Ljava/lang/Class;"));
                var clz_obj2 = funcCallObjectMethod(env, clz_obj, mid_getClass);
                var cls = funcGetObjectClass(env, clz_obj2);
                var mid_getName = funcGetMethodID(env, cls, Memory.allocUtf8String("getName"), Memory.allocUtf8String("()Ljava/lang/String;"));
                var name_jstring = funcCallObjectMethod(env, clz_obj2, mid_getName);
                var name_pchar = funcGetStringUTFChars(env, name_jstring, ptr(0));
                var class_name = ptr(name_pchar).readCString();
                funcReleaseStringUTFChars(env, name_jstring, name_pchar);

                //console.log(class_name);

                var methods_ptr = ptr(args[2]);

                var method_count = parseInt(args[3]);
                for (var i = 0; i < method_count; i++) {
                    var name_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3));
                    var sig_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize));
                    var fnPtr_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize * 2));

                    var name = Memory.readCString(name_ptr);
                    var sig = Memory.readCString(sig_ptr);
                    var find_module = Process.findModuleByAddress(fnPtr_ptr);
                    console.log("[RegisterNatives] java_class:", class_name, "name:", name, "sig:", sig, "fnPtr:", fnPtr_ptr, "module_name:", find_module.name, "module_base:", find_module.base, "offset:", ptr(fnPtr_ptr).sub(find_module.base));

                }
            },
            onLeave: function (retval) { }
        });
    }

    ishook_libart = true;
}

hook_libart();

在这里插入图片描述

3.3send 和console

console.log()只是打印在控制台;
send()方法会经过回调到脚本可以进行调用;
但是有时候send()参数会返回结果很奇怪,解决办法如下

send(arguments[1]);
send(arguments[1].toString());
[*]{'$handle': '0x203d2a', '$weakRef': 41}
[*]{"nick":"难以释怀的浅时光","identify":{"APASS_USER":"0","fanLevel":"3","VIP_USER":"1"},"userid":"1016207621"}

参考文献:
hook基本流程
hook方法

native方法地址

03-20
### 关于 Frida 动态 Instrumentation 工具的使用说明 #### 什么是 FridaFrida 是一种强大的动态 instrumentation 工具,允许开发者通过注入 JavaScript 脚本的方式对运行中的应用程序进行分析、修改和调试。它支持多种平台(如 Windows、macOS、Linux、Android 和 iOS),并提供了灵活的 API 来实现各种功能。 --- #### 基础环境搭建 为了成功使用 Frida,需完成以下准备工作: 1. **安装 Frida** 可以通过 Python 的 pip 包管理器来安装 Frida: ```bash pip install frida-tools ``` 2. **部署 Frida Server** 在目标设备上启动 Frida Server 并确保其版本与本地使用的 Frida 工具相匹配[^1]。可以通过以下命令验证版本一致性: ```bash frida --version ``` 如果发现版本不一致,则需要下载对应版本的 Frida Server 并替换旧版。 3. **连接目标设备** 对于 Android 设备,可通过 USB 或网络方式连接至主机,并确认 ADB 正常工作: ```bash adb devices ``` --- #### 基本操作流程 以下是使用 Frida 进行动态 instrumentation 的基本步骤: 1. **枚举已安装的应用程序** 使用 `frida-ps` 列出当前设备上的可交互进程列表: ```bash frida-ps -U ``` 2. **附加到指定进程** 将 Frida 附着到某个正在运行的目标应用中: ```bash frida-trace -U com.example.app ``` 3. **编写 Hook 脚本** 创建一个 `.js` 文件定义所需的拦截逻辑。例如,下面是一个简单的函数钩子示例: ```javascript Interceptor.attach(Module.findExportByName(null, "function_name"), { onEnter: function(args) { console.log("Function called with argument:", args[0].toInt32()); }, onLeave: function(retval) { console.log("Return value is:", retval.toInt32()); } }); ``` 4. **执行脚本** 加载上述脚本文件并与目标进程绑定: ```bash frida -U -n com.example.app -l script.js --no-pause ``` --- #### 高级特性扩展 除了基础功能外,Frida 提供了许多高级选项满足更复杂的需求: - **自定义 Hook** 当预设模板无法完全适配需求时,可以手动构建特定场景下的 hook 函数[^2]。这通常涉及深入理解目标方法签名及其调用上下文。 - **集成其他框架** r2frida 结合 Radare2 实现更加全面的过程监控能力[^3]。借助此组合方案,研究者不仅限于单一维度的数据采集,还能同步获得内存映射视图以及控制流图表等辅助信息。 --- #### 注意事项 - 确认所选架构类型(armeabi-v7a/x86/arm64-v8a)以便加载恰当的 so 库实例。 - 若遇到权限不足的情况,请尝试授予 root 访问权给测试账户或者切换为非侵入模式操作。 ```python import frida device = frida.get_usb_device() pid = device.spawn(["com.example.app"]) session = device.attach(pid) with open('script.js', 'r') as f: jscode = f.read() script = session.create_script(jscode) script.load() device.resume(pid) input("Press Enter to stop...") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值