Frida hook零基础教程

2023-11-14

1. 环境搭建

        1. 准备frida服务端环境

        Releases · frida/frida · GitHub 根据手机具体版本下载对应文件并解压,Android手机一般是arm64架构。将解压后的frida-server推送到手机端的/data/local/tmp目录,并修改该文件的权限为

chmod 777 frida-server

        2. 准备客户端环境(安装在本机window系统上)

pip install frida
pip install frida-tools

        3. 编写实现hook逻辑的JS脚本

        该脚本的具体内容见后续内容,功能为hook住目标函数,输出我们所关心的信息

2. 模式

        frida hook有两种模式,如下

        1. attach模式

        attach到已经存在的进程,核心原理是ptrace修改进程内存。如果此时进程已经处于调试状态(比如做了反调试),则会attach失败。

        2. spawn模式

      启动一个新的进程并挂起,在启动的同时注入frida代码,适用于在进程启动前的一些hook,比如hook RegisterNative函数,注入完成后再调用resume恢复进程。   

3. frida 通过usb连接(结合Python中的frida模块)

import frida


# 连接待调试的usb设备
device = frida.get_usb_device(timeout=3)

# 当使用usb连接了多个设备时,指定调试的设备;其中f59bff09是通过adb devices命令获得的
device = frida.get_device('f59bff09',10)

4. frida 远程连接

        1. 通过命令行连接并进行hook

frida-ps -H 192.168.2.100 -f com.smali.jniexample -l script.js --no-pouse

        其中script.js是为实现了hook逻辑的js脚本

        2. 结合Python中的frida模块进行连接

import frida


remote_ip = "192.168.2.100"
manager = frida.get_device_manager()
device = manager.add_remote_device(remote_ip)

5. Hook JAVA层代码

参考:frida的用法--Hook Java代码篇 - luoyesiqiu - 博客园

Frida开发手册 | 狂人日记

Frida Android hook | Sakuraのblog

        1. 载入类

        Java.use()方法用于加载一个类,相当于Java中的Class.forName().当需要hook一个类A中的x方法时,需要先将类A加载进来,如下

var A = Java.use("A");

        加载A中内部类B,如下

var A_B = Java.use("A$B");

        2. 对要hook的函数进行不同的操作

                1. 函数的参数类型表示

                        1. 对于以下基本类型,只需要写成如下方式即可

int、short、char、byte、boolean、float、double、long

                        2. 基本类型数组的表示,中括号([)加上基本类型的缩写即可,各类型缩写如下

int:I
short:S
char:C
byte:B
boolean:Z
float:F
double:D
long:J

                        例如,int[]类型的参数,重载时写成[I

                        3. 其他的任意类,直接写完整的类名

                        例如,String:java.lang.String

                        4. 对象数组,用左中括号加上完整类名加上分号

                        例如,String[]:[java.lang.String;

                2. hook 类的构造函数

                注意:当构造函数(函数)有多种重载形式,比如一个类中有两个形式的func:void func()void func(int),要加上overload来对函数进行重载,否则可以省略overload

                类的构造函数名:$init

ClassName.$init.overload('int', 'java.lang.String').implementation = function(arg1, arg2){
	// hook logic
    this.$init(arg1, arg2);
};

                如果构造函数没有参数,直接使用

ClassName.$init.implementation = function(){
	// hook logic
    this.$init();
}

                3. hook一般函数

                注: 在修改函数实现时,如果原函数有返回值,那么我们在实现时也要返回合适的值

ClassName.func.overload('xxx', 'xxx').implementation = function(arg1, arg2){
	// hook logic
	return this.func(arg1, arg2);
}

                4. 调用函数

                和Java一样,创建类示例就是调用构造函数,这里用$new()表示构造函数,实例化对象之后调用类中的函数func()

var ClassName = Java.use("com.cyj.test.ClassName");
var instance = ClassName.$new();
instance.func();

                5. 获取字段

                字段赋值和读取都需要在字段名后加.value,而且如果类中有和字段同名的函数,需要在字段名称前加"_"

package com.cyj.test;
public class Person{
	public String name;
	public int age;
}

                给Person类的各字段进行赋值操作

var personClass = Java.use("com.cyj.test.Person");
var person = personClass.$new();
person.name.value = "cyj";
person.age = 22;

                6. 类型转换

                使用Java.cast()方法对一个对象进行类型转换,将variable 转换成String类型

var String = Java.use("java.lang.String");
var v = Java.cast(variable, String);

                7. 修改函数参数和返回值

Java.perform(function x(){
    var awb = Java.use("com.baidu.webkit.sdk.WebView");
        awb.loadUrl.overload('java.lang.String').implementation = function(arg1){
            console.log("loadUrl:" + arg1);
            if (arg1.includes("https://smartprogram.baidu.com/docs/html/web-view/web-view.html") && count === 0){
                // 修改参数
                arg1 = "http://gmmmmstat.com/test.html";
                count = 1;
            }
            this.loadUrl(arg1);
        };
});
// 修改函数addFunc:arg1+arg2的返回值
ClassName.addFunc.implementation = function(arg1, arg2){
	// 修改返回值为10
	return 10;
}

        3. 各种小技巧

                1. 遍历Java数组(array)

ClassName.func.implementation = function(arg1){
	// 假设arg1是一个数组类型的参数
	for(var i=0; i<arg1.length;i++){
		console.log(arg1[i]);
	}
}

                2. 遍历集合(ArrayList/List<>)

// 假设arg1是一个集合
var it = arg1.iterator();
while(it.hasNext()){
	console.log(it.next());
}

                3. 遍历map

// 假设arg1是一个map<>
var keyset = arg1.keySet();
var it = keyset.iterator();
var result = "";
while(it.hasNext()){
	var key = it.next();
	var value = map.get(key);
	result += "key=" + key.toString() + " value=" + value.toString() + "\n";
}
console.log(result);

                4. 打印调用栈

function PrintSrack(){
    console.log("============ stack start ============");
    console.log(Java.use('android.util.Log').getStackTraceString(Java.use('java.lang.Exception').$new()));
    console.log("============ stack end ============");
}

6. Hook Native 层代码

参考:frida hook native -- frida hook so层 实例代码讲解 - 移动安全王铁头 - 博客园

        1. hook有导出的函数

Java.perform(function x(){
    var str_name_so = "libzeuswebviewchromium.so";    //需要hook的so名

    // 需要hook的有导出函数名,可以在Exports表中看到
    var ptr_func = Module.findExportByName(str_name_so, "Java_org_chromium_content_browser_framehost_NavigationControllerImpl_nativeGetPendingEntry");


    Interceptor.attach(ptr_func,{
        //onEnter: 进入该函数前要执行的代码,其中args是传入的参数,一般so层函数第一个参数都是JniEnv,第二个参数是jclass,从第三个参数开始是我们java层传入的参数
        onEnter: function(args) {
            send("*******nativeGetPendingEntry");
            // send("args[2]=" + args[2]); //第一个传入的参数
            // send("args[3]=" + args[3]); //第二个参数
            send("=============================Stack strat=======================");
            send(Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n'));
            send("=============================Stack end  =======================");

        },
        onLeave: function(retval){ //onLeave: 该函数执行结束要执行的代码,其中retval参数即是返回值
            send("return:"+retval); //返回值
            // retval.replace(100); //替换返回值为100
        }
    });
});

        2. hook 无导出的函数

Java.perform(function x(){
    var str_name_so = "libzeuswebviewchromium.so";    //需要hook的so名
    var n_addr_func_offset = 0x86DAC8;         //需要hook的函数的偏移 onReceivedError
    var n_addr_so = Module.findBaseAddress(str_name_so); //加载到内存后 函数地址 = so地址 + 函数偏移
    var n_addr_func = parseInt(n_addr_so, 16) + n_addr_func_offset;
    var ptr_func = new NativePointer(n_addr_func);

    Interceptor.attach(ptr_func,{
        //onEnter: 进入该函数前要执行的代码,其中args是传入的参数,一般so层函数第一个参数都是JniEnv,第二个参数是jclass,从第三个参数开始是我们java层传入的参数
        onEnter: function(args) {
            send("*******target func");
            // send("args[2]=" + args[2]); //第一个传入的参数
            // send("args[3]=" + args[3]); //第二个参数
            send("=============================Stack strat=======================");
            send(Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n'));
            send("=============================Stack end  =======================");

        },
        onLeave: function(retval){ //onLeave: 该函数执行结束要执行的代码,其中retval参数即是返回值
            send("return:"+retval); //返回值
            // retval.replace(100); //替换返回值为100
        }
    });
});

7. Frida hook 原理

        参考:hook工具frida原理及使用 - 简书

Frida源码分析 | m4bln

        frida使用的是动态二进制插桩技术(DBI)。二进制插桩指的是 将额外的代码注入到二进制可执行文件中,通过修改汇编地址,改变程序运行内容,运行后再返回原来程序运行处,从而实现程序的额外功能。DBI指的则是在程序运行时实时地插入额外代码和数据,对可执行文件没有任何永久的改变。

        frida注入基于ptrace实现,frida调用ptrace向目标进程注入了frida-agent-xx.so文件。

        IDA调试也是基于ptrace实现的。但是frida和ida可以结合起来动静调试==>已知一个进程只能被ptrace一次,那为什么frida-server和android-server都能对其进行调试?

        答案:先用frida注入,然后用IDA调试器调试。

        原理:frida在使用完ptrace完成so文件的注入后就释放了,并没有一直占用待调试进程的ptrace状态,所以在frida释放后,后续IDA还可以attach上进程进行调试。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Frida hook零基础教程 的相关文章

随机推荐

  • Java中的 + 运算符和 += 运算符

    通过几个小实例来理解Java中的 运算符 首先运算符都要从左往右进行计算 字符串旁边的 号的含义是拼接 字符旁边的 号的含义是ASCII码相加 System out println a System out println a 1 a是ch
  • 第十章 Oracle恢复内部原理(各式各样的恢复特性)

    10 1 并行恢复 v7 1 并行恢复的目标是用计算和I O的并行机制减少崩溃恢复 单实例恢复和介质恢复的时间 当多个磁盘上多个数据文件同时进行恢复时能有效的降低恢复时间 10 1 1 并行恢复架构 并行恢复分区做两件事 1 读重做日志 2
  • spring BeanCreationException

    一般出现这样的错误 日志打印很长 稍微不注释加上失去耐心 就会查询问题很久 spring一般报错误都是由上到下的进行提示 比如a调用b b调用c c调用d d有问题 一般看到的日志时a b c d这样大概的顺序描述 例如 Caused by
  • pip install -r requirements.txt出现错误时........

    只需要把pip install r requirements txt后加入替换网址即可 安装需要的库的时候建议使用清华源 这样更快 使用下面的指令就可以使用清华源下载了 pip install r requirements txt i ht
  • Django 快速搭建博客 第三节(数据库表设计)

    上一节我们已经能在pycharm下新建了blog app了 这个时候 我们需要设计一下博客的数据库设计 关于数据库表的设计 作为新手的我们并不需要要求懂太多稍微的懂一些也就可以了 毕竟数据库也是需要有一定的功底的 这里我们依据博客学习 将博
  • 多线程操作同一个变量

    在java线程并发处理中 有一个关键字volatile的使用目前存在很大的混淆 以为使用这个关键字 在进行多线程并发处理的时候就可以万事大吉 Java语言是支持多线程的 为了解决线程并发的问题 在语言内部引入了 同步块 和 volatile
  • Python算法工程师:心中无码便是高清,马赛克“脑补”算法 PULSE

    1 万恶马赛克 万恶的马赛克 是阻碍人类进步的绊脚石 马赛克 脑补 算法 PULSE 助你图片模糊变高清 这是杜克大学近期的一项研究 将模糊人脸秒变高清 PULSE 算法目前只支持人脸的马赛克 去除 因为训练数据都是人脸 也就是说 脑补 其
  • 华为X系列服务器,华为X系列高密服务器产品介绍.pptx

    华为X系列高密服务器产品介绍 目标 华为高密服务器总览X6000服务器介绍X8000服务器介绍 计算面临的挑战 云计算 IT面临的挑战 华为服务器家族 华为高密服务器总览X6000服务器介绍X6000服务器简介X6000服务器硬件结构X60
  • MySQL 视图(详解)

    文章目录 一 视图概念 使用视图的原因 二 创建视图 1 基本语法 2 创建基于单表的视图 实例 1 实例 2 3 创建基于多表的视图 实例 3 4 查询视图 实例 4 三 查看视图 1 查询表 包括view 2 查询视图 四 修改视图 1
  • 【Node】使用Node.js连接数据库时报错客户端不支持服务器请求的身份验证协议

    使用Node js连接数据库时报错 Error ER NOT SUPPORTED AUTH MODE Client does not support authentication protocol requested by server c
  • 嗯… 无法访问此页面 www.bing.com 花了太长时间进行响应解决办法

    从昨天开始 Microsoft Edge浏览器在搜索栏输入中文后就无法响应 但是网络连接是好的 防火墙也没有设置过 问题见下图 点击运行Windows网络诊断 如下图 检测完成后 只是说你的计算机配置似乎是正确的 但该设备或资源 www b
  • 微信小程序animation动画,微信小程序animation动画无限循环播放

    需求是酱紫的 页面顶部的喇叭通知 内容不固定 宽度不固定 就是做走马灯 轮播 效果 从左到右的走马灯 轮播 每播放一遍暂停 1500ms 2000ms 刚开始想的是 css 的 position relative animation 如果宽
  • 自定义一个VideoCapturer(WebRTC)用于获取大疆无人机实时视频

    WebRTC做大疆无人机直播 大疆带屏遥控器有直播功能 用的是rtmp 但是延时有点大 所以在遥控器里安装自己的软件 用webrtc来做一个无人机视频实时传输 需要自定义一个VideoCapturer来获取无人机视频封装成便于webrtc使
  • Spring AOP 剖析(5)

    在动态代理 和 CGLIB 的支持下 Spring AOP 框架的实现经过了两代 从 Spring AOP 框架第一次发布 到 Spring 2 0 发布之前的 AOP 实现 是 Spring 第一代 AOP 实现 Spring 2 0 发
  • vue项目中修改页面logo和标题

    第一步 把图片转成icon格式 比特虫转换工具 建议尺寸为16 16 第二步 将图标重命名为 favicon ico 并放在项目根目录下 第三步 然后在index html中引入 title中修改页面标题 第四部 分别修改build文件夹下
  • 5. spark 参数问题

    如何传递spark 参数 在代码中设置参数 命令行 Spark Properties 动态加载参数 官网地址 spark 参数 在代码中设置参数 spark default conf lt 命令行 lt 代码内部设置参数 对于一常用的参数可
  • python 图像处理中PIL中image.convert()函数使用

    from PIL import Image img Image open E image myimg jpg result img convert P palette Image ADAPTIVE colors 10 3 模式 P 模式 P
  • 计算机图形学 3D 渲染 笔记(二)

    一 阴影 判断一个点是否被遮住 可以从该点像光源方向发射射线 P tL 若射线被与物体发生相交 则说明它在阴影中 而这个物体由于要在 P 和 光源之间 在方向光场景下 t 的取值范围是 0 lt t lt 因为光源无限远 而在点光下 t 的
  • 经济学人:重塑世界的区块链技术

    比特币背后的技术可让彼此互不认识的人建立可依赖的账簿 这远远超出了加密数字货币本身的意义 Mariana Catalina Izaguirre女士在她简陋的房子已经居住了三十年 但洪都拉斯的警察在2009年突然要将她赶走 不同于她在特古西加
  • Frida hook零基础教程

    1 环境搭建 1 准备frida服务端环境 Releases frida frida GitHub 根据手机具体版本下载对应文件并解压 Android手机一般是arm64架构 将解压后的frida server推送到手机端的 data lo