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方法地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值