frida学习及使用

2023-10-26

安装frida

Frida框架简介
Frida是一款基于Python + JavaScript的Hook与调试框架。
Firda是一款易用的跨平Hook工具,Java层到Native层的Hook无所不能,是一种动态 
的插桩工具,可以插入代码到原生 App 的内存空间中,动态的去监视和修改行为,
原生平台包括Win、Mac、Linux、Android、iOS全平台。

环境配置步骤:
1.安装Python环境 3.7

2.安装frida模块
	打开Py输入命令:
		pip install frida
		pip install frida-tools
		pip uninstall frida
		pip uninstall frida-tools
		pip install frida==15.1.27
		pip install frida-tools==10.6.2

google pixels 3a
frida=16.1.3
frida-tools=12.2.1

3.frida-server下载地址:
	查看版本信息:frida --version
	https://github.com/frida/frida/releases
	下载安装frida server 版本和类型对应,框架和设备对应

4.安装PyCharm 

5.启动frida-server

6.端口转发
	adb forward tcp:27042 tcp:27042

7.测试
	frida-ps -U	
	frida -U -f com.qianyu.fridaapp --no-pause

安装python3.7

在这里插入图片描述

设置环境变量

在这里插入图片描述

安装pycharm和nodejs

创建工程的时候,记得将鼠标所在的两个勾选框选上
在这里插入图片描述
在这里插入图片描述

使用frida

将frida-server push到手机设备中

在这里插入图片描述
在这里插入图片描述

端口转发

在这里插入图片描述

安装apk

使用jadx查看java代码

在这里插入图片描述

运行frida-server

我使用15.1.27版本的frida版本,在安卓手机上会报错。所以我果断升级了frida版本

sargo:/data/local/tmp # ./frida-server-15.1.27-android-arm64
{"type":"error",
"description":"Error: Unable to determine ClassLinker field offsets",
"stack":"Error: Unable to determine ClassLinker field offsets\n    
	at Ye (frida/node_modules/frida-java-bridge/lib/android.js:400:1)\n    
	at frida/node_modules/frida-java-bridge/lib/memoize.js:4:1\n    
	at ze (frida/node_modules/frida-java-bridge/lib/android.js:193:1)\n    
	at Oe (frida/node_modules/frida-java-bridge/lib/android.js:16:1)\n   
	 at _tryInitialize (frida/node_modules/frida-java-bridge/index.js:29:1)\n    
	 at new _ (frida/node_modules/frida-java-bridge/index.js:21:1)\n    
	 at Object.4../lib/android (frida/node_modules/frida-java-bridge/index.js:332:1)\n    
	 at o (frida/node_modules/browser-pack/_prelude.js:1:1)\n    
	 at frida/node_modules/browser-pack/_prelude.js:1:1\n    
	 at Object.22.frida-java-bridge (frida/runtime/java.js:1:1)",
"fileName":"frida/node_modules/frida-java-bridge/lib/android.js","lineNumber":400,"columnNumber":1}

frida源码阅读

在这里插入图片描述

frida hook方法

注意点:

  1. frida和frida-server版本号必须要一致
  2. hook的时候,必须要运行hook的程序,否则报错

Frida Java层hoook

JavaHook.java

# -*- coding: utf-8 -*-

import os
import sys
import frida
import codecs


def message(message, data):
    if message["type"] == 'send':
        print("[*] {0}".format(message['payload']))
    else:
        print(message)


process = frida.get_remote_device().attach('NDKDemo')
if not os.path.isfile('./JavaHook.js'):
    raise TypeError("./JavaHook.js does not exist")
with codecs.open('./JavaHook.js', 'r', 'UTF-8') as file:
    js_code = file.read()
script = process.create_script(js_code)
script.on("message", message)
script.load()
# script.exports.test()
# script.exports.test()
# script.exports.test()
# script.exports.test()
sys.stdin.read()


# frida使用非标准端口
# /data/local/tmp # ./fs_12.7.22_arm64 -l 127.0.0.1:31928  默认端口: 27046
# process = frida.get_device_manager().add_remote_device('127.0.0.1:31928').attach('FridaApp')
# if not os.path.isfile('./JavaHook.js'):
#     raise TypeError("./JavaHook.js does not exist")
# with codecs.open('./JavaHook.js', 'r', 'UTF-8') as file:
#     js_code = file.read()
# script = process.create_script(js_code)
# script.on("message", message)
# script.load()
# sys.stdin.read()

JavaHook.js

// HOOK普通方法、静态方法
function Test01(){
    let loginActivity = Java.use('com.yijincc.ndkdemo.LoginActivity');
    loginActivity.login.implementation = function () {
        console.log("=============login===============");
        console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
        console.log(arguments[0]);
        console.log(arguments[1]);
        this.login(arguments[0],arguments[1]);
    }
}

// HOOK构造方法、重载方法
function Test02(){
    let intent = Java.use('android.content.Intent');
    intent.$init.overload('android.content.Context', 'java.lang.Class').implementation = function () {
       console.log("=============intent===============");
       console.log(arguments[0]);
       console.log(arguments[1]);
       this.$init(arguments[0],arguments[1]);
    }
}

// HOOK内部类
function Test03(){
    let loginActivity$1 = Java.use('com.yijincc.ndkdemo.LoginActivity$1');
    loginActivity$1.onClick.implementation = function () {
        console.log("=============onClick===============");
        console.log(arguments[0]);
        this.onClick(arguments[0]);
    }
}

// 主动调用构造方法
function Test04(){
    let money = Java.use('com.yijincc.fridaapp.Money');
    let obj = money.$new(1000,'RMB');
    console.log(obj.getInfo());
}

// 操作对象里面的成员变量
function Test05(){
    let money = Java.use('com.yijincc.fridaapp.Money');
    let obj = money.$new(10000,'RMB');
    console.log(obj.name.value);
    console.log(obj.num.value);

    console.log('===============================');

    obj.name.value = 'RMB';
    obj.num.value = 10000000;
    console.log(obj.name.value);
    console.log(obj.num.value);
}

// 主动调用普通方法
function Test06(){
    let money = Java.use('com.yijincc.fridaapp.Money');
    let obj = money.$new(2000,'RMB');
    console.log(obj.getInfo());
}

// 获取当前类已有的实例实现主动调用普通方法
function Test07(){
    Java.choose('com.yijincc.ndkdemo.MainActivity',{
        onMatch: function(obj){ // 枚举时调用
                console.log(obj);
                console.log(obj.name.value);
                console.log(obj.age.value);
                console.log(obj.sex.value);
                console.log(obj.rand('B',99))
            }, onComplete: function(){ // 枚举完成后调用
                console.log("end");
            }
        });
}

// 主动调用静态方法
function Test08(){
    let mainActivity = Java.use('com.yijincc.ndkdemo.MainActivity');
    console.log(mainActivity.isRel(444,444));
}

// HOOK打印堆栈信息
// function Test09(){
//     let money = Java.use('com.yijincc.fridaapp.Money');
//     money.getInfo.implementation = function () {
//         console.log("=============getInfo===============");
//         console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
//         return this.getInfo();
//     }
// }

// HOOK指定类的所有方法
function Test10(){
    let money = Java.use('com.yijincc.ndkdemo.MainActivity');
    let methods = money.class.getDeclaredMethods();
    for(let j = 0; j < methods.length; j++){
        let methodName = methods[j].getName();
        console.log(methodName);
        for(let k = 0; k < money[methodName].overloads.length; k++){
            money[methodName].overloads[k].implementation = function(){
                console.log('==========='+methodName+'===========');
                for(let i = 0; i < arguments.length; i++){
                    console.log(arguments[i]);
                }
                console.log('===========end===========');
                return this[methodName].apply(this, arguments);
            }
        }
    }
}

// 枚举已加载的所有类与枚举类的所有方法
function Test11(){
    let classes = Java.enumerateLoadedClassesSync();
    for(let i = 0; i < classes.length; i++){
        if(classes[i].indexOf("com.") !== -1){
            console.log("clazz:"+classes[i]);
            let clazz = Java.use(classes[i]);
            let methods = clazz.class.getDeclaredMethods();
            for(let j = 0; j < methods.length; j++){
                console.log("method:"+methods[j]);
            }
        }
    }
}

// hook动态加载dex文件
function Test12(){
    // Java.enumerateLoadedClasses({
    //     onMatch: function (name, handle) {
    //         if (name.indexOf("com.example") >= 0) {
    //             console.log(name);
    //             let class6 = Java.use(name);
    //             class6.check.implementation = function () {
    //                 console.log("check:", this);
    //                 return true;
    //             };
    //         }
    //     }, onComplete: function () {}
    // });

    Java.enumerateClassLoaders({
        onMatch: function (loader) {
            try {
                if (loader.findClass("com.example.androiddemo.Dynamic.DynamicCheck")) {
                    console.log(loader);
                    Java.classFactory.loader = loader;      //切换classloader
                }
            } catch (error) {}
        }, onComplete: function () {}
    });
    let DynamicCheck = Java.use("com.example.androiddemo.Dynamic.DynamicCheck");
    console.log(DynamicCheck);
    DynamicCheck.check.implementation = function () {
        console.log("DynamicCheck.check");
        return true;
    }
}

// 动态加载dex文件
function Test13(){
    // jar -cvf dex.jar com/example/androiddemo/StringUtils.class
    // dx --dex --output=dex.dex dex.jar
    let dex= Java.openClassFile("/data/local/tmp/dex.dex");
    dex.load();
    let stringUtils = Java.use("com.example.androiddemo.StringUtils");
    console.log(stringUtils.tohexString("1234567890"));
}

rpc.exports = {
    test:function () {
        Java.choose('com.yijincc.ndkdemo.MainActivity',{
        onMatch: function(obj){ // 枚举时调用
                console.log(obj);
                console.log(obj.name.value);
                console.log(obj.age.value);
                console.log(obj.sex.value);
                console.log(obj.rand('B',99))
            }, onComplete: function(){ // 枚举完成后调用
                console.log("============end============");
            }
        });
    }
}

Java.perform(function () {
    Test01();
    // Test02(); // 重载方法
    // Test03(); // 内部类
    // Test04()  // 主动调用构造方法,创建一个对象
    // Test07();
    // Test08();
    // Test10(); // 打印所有的方法
    // Test11();
    //Test13();
});

Frida native层hook 一

通过IDA找到要hook的native函数(静态)
在这里插入图片描述base64魔改
在这里插入图片描述## NativeHook.py

# -*- coding: utf-8 -*-

import os
import sys
import frida
import codecs


def message(message, data):
    if message["type"] == 'send':
        print("[*] {0}".format(message['payload']))
    else:
        print(message)


process = frida.get_remote_device().attach('NDKDemo')
if not os.path.isfile('./NativeHook.js'):
    raise TypeError("./NativeHook.js does not exist")
with codecs.open('./NativeHook.js', 'r', 'UTF-8') as file:
    js_code = file.read()
script = process.create_script(js_code)
script.on("message", message)
script.load()
sys.stdin.read()


# frida使用非标准端口
# /data/local/tmp # ./fs_12.7.22_arm64 -l 127.0.0.1:31928  默认端口: 27046
# process = frida.get_device_manager().add_remote_device('127.0.0.1:31928').attach('Android_crackme')
# if not os.path.isfile('./NativeHook.js'):
#     raise TypeError("./NativeHook.js does not exist")
# with codecs.open('./NativeHook.js', 'r', 'UTF-8') as file:
#     js_code = file.read()
# script = process.create_script(js_code) # 创建脚本
# script.on("message", message)
# script.load()
# sys.stdin.read()

NativeHook.js

// HOOK导出函数
function Test01(){
    // 用于在指定的模块中查找导出函数的地址
    let funGetFlag = Module.findExportByName("libnative-lib.so", "Java_com_yijincc_ndkdemo_LoginActivity_login");
    send("native: " + funGetFlag); // 基地址
    Interceptor.attach(funGetFlag, {
        onEnter: function(args){
            send("============getFlag===============");
            send(args[0]);
            send(args[1]);
        },
        onLeave: function(retval){
            send("============result===============");
            send(retval);
            // 获取JNIEnv*
            let env = Java.vm.tryGetEnv();
            // 将jstring 转换 const char*
            let str=env.getStringUtfChars(retval,0);
            send(str.readCString());
        }
    });
}

// HOOK未导出函数
function Test02(){
    // 绝对地址=so模块起始地址(基地址)+偏移地址
    let baseAddr = Module.findBaseAddress("libnative-lib.so");
    send("baseAddr:"+baseAddr);
    // 指令集 分为ARM指令、thumb指令
    // ARM指令地址不变  thumb指令地址+1 sub_ 开头的函数 这种函数只能使用这种方式来进行
    Interceptor.attach(baseAddr.add(0x15F08), {
        onEnter: function(args){
            send("============encrypt===============");
            send(args[0]);
            send(args[1]);
            send(args[2]);
            console.log(hexdump(args[2], {
                offset: 0,
                length: 16,
                header: true,
                ansi: false
            }));
            // 获取JNIEnv*
            let env = Java.vm.tryGetEnv();
            // 将jstring 转换 const char*
            let str=env.getStringUtfChars(args[2],0);
            send(str.readCString());
        },
        onLeave: function(retval){
            send("============result===============");
            send(retval);
            // 获取JNIEnv*
            let env = Java.vm.tryGetEnv();
            // 将jstring 转换 const char*
            let str=env.getStringUtfChars(retval,0);
            send(str.readCString());
        }
    });
}

// HOOK枚举导入函数信息
function Test03(){
    send("Test03")
    let imports = Module.enumerateImportsSync("libnative-lib.so");
    send(imports)
    for(let i=0;i<imports.length;i++){
        // if(imports[i].name.indexOf('raise') !== -1){
            send(imports[i]);
        // }
    }
}

// HOOK枚举导出函数信息
function Test04(){
    send("Test04-start")
    send(device)
    let exports = Module.enumerateExportsSync("libnative-lib.so");
    send(exports)
    for(let i=0;i<exports.length;i++){
        if(exports[i].name.indexOf('Java_') !== -1){
            send("name:"+exports[i].name+"  address:"+exports[i].address);
        }
    }
    send("Test04-end")
}

// 遍历模块列表信息
function Test05(){
    Process.enumerateModules({
        onMatch: function(exp){
            send(exp)
            if(exp.name.indexOf('libnative-lib.so') !== -1){
                send('enumerateModules find');
                send(exp);
                return 'stop';
            }
        },
        onComplete: function(){
            send('enumerateModules stop');
        }
    });
}

// 读写内存数据
function Test06(){
    let mem_addr=Memory.alloc(20);
    //Memory.writeInt(mem_addr,0x1234567890abcdef);
    Memory.writeLong(mem_addr,0x1234567890abcdef);
    // console.log(hexdump(mem_addr));
    console.log(hexdump(mem_addr, {
        offset: 0,
        length: 20,
        header: true,
        ansi: true
    }));
}

// 使用frida api读写文件
function Test07(){
    let file = new File("/data/data/com.yijincc.ndkdemo/yijincc.txt", "w");
    file.write("hello world!!!\\n");
    file.flush();
    file.close();
}

// 基于主动调用libc.so里面的函数实现文件的读写操作
function Test08(){
    let addr_fopen = Module.findExportByName("libc.so", "fopen");
    send("1")
    let addr_fputs = Module.findExportByName("libc.so", "fputs");
    send("2")
    let addr_fclose = Module.findExportByName("libc.so", "fclose");
    send("3")

    let fopen = new NativeFunction(addr_fopen, "pointer", ["pointer", "pointer"]);
    send("4")
    let fputs = new NativeFunction(addr_fputs, "int", ["pointer", "pointer"]);
    send("5")
    let fclose = new NativeFunction(addr_fclose, "int", ["pointer"]);
    send("6")

    let filename = Memory.allocUtf8String("/data/data/com.yijincc.ndkdemo/yijincc.txt");
    send("7")
    let open_mode = Memory.allocUtf8String("w");
    send("8")
    let file = fopen(filename, open_mode);
    send("9")

    let buffer = Memory.allocUtf8String("hello world!!!\\n");
    send("10")
    let result = fputs(buffer, file);
    send("11")
    send("fputs:" + result);
    fclose(file);
}

Java.perform(function () {
    // Test01();
    // Test02();
    // Test03();
    // Test04();
    // Test05();
    // Test06();
    // Test07();
    Test08();
})
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

frida学习及使用 的相关文章

  • 受益终生的十大经典管理学定律

    1 彼得原理 每个组织都是由各种不同的职位 等级或阶层的排列所组成 每个人都隶属于其中的某个等级 彼得原理是美国学者劳斯 彼得在对组织中人员晋升的相关现象研究后 得出一个结论 在各种组织中 雇员总是趋向于晋升到其不称职的地位 彼得原理有时也
  • 汉明码详细讲解

    汉明码 是R Hamming与1940年于贝尔实验室提出的 1 奇偶校验码 奇偶校验码 假设传输信息位为K n 1位 表示为a1 an 1 加上一位奇偶校验位 冗余位 a0 构成一个n位的码字a0 an 1 在接收端校验时 可按照关系式 s

随机推荐

  • 【VTK】装配体Assembly的使用

    VTK 装配体Assembly的使用 昨天晚上实现了一个可拖动的坐标轴MovableAxesWidget 今天给他加个使用场景 准备做一个简单的机械臂运动学仿真程序 模型用的HIWIN的机械臂 官网可以下载到模型 hiwin 毕业第一份工作
  • 作为一个程序员,最重要的能力是什么?很多人工作多年后才知道

    我认为程序员只需分三类 天才的程序员 理想的程序员 平庸的程序员 天才在生活中毕竟是少数 今天我们就来聊聊理想的程序员和平庸的程序员有什么区别 理想的程序员与平庸的程序员只有一墙之隔 两者的差距只有6个一点点 而人与人的差距 正是在这日积月
  • 获取下拉框选中的索引值

    selectedIndex 属性可设置或返回下拉列表中被选选项的索引号 var myselect document getElementById id var index myselect selectedIndex if index 1
  • Mission Impossible——《图灵的秘密》读后感

    图灵的秘密 是关于图灵1936年那篇开创性论文的解读 内容很多很难 需要的背景知识包括数理逻辑 lambda演算 以及一些基本的数论 读完的笔记也许都会比原书多 这里想简洁或者宏观性地谈谈几个主角之间的 故事 实际上说争论更准确 初 我目前
  • 机器学习算法(一):逻辑回归模型(Logistic Regression, LR)

    目录 1 LR 1 1 直观表述 1 2 决策边界 Decision Boundary 2 权值求解 2 1 代价函数 似然函数 2 1 1 为什么损失函数不用最小二乘 即逻辑斯蒂回归损失函数为什么使用交叉熵而不是MSE 2 1 2 代价函
  • Linux中安装Redis教程

    1 在CentOS7中新建一个文件夹 然后在这个文件夹中下载 Redis 执行下面的命令 你也可以选择其他的包 如 redis 5 0 10 tar gz 我用这个包安装成功了 wget http download redis io rel
  • Set接口

    Set接口简介 Set接口和List接口一样 同样继承自Collection接口 它与Collection接口中的方法基本一致 并没有对Collection接口进行功能上的扩充 只是比Collection接口更加严格了 与List接口不同的
  • ICMP协议

    参考链接 https www cnblogs com embedded linux p 7068130 html 1 一个新搭建好的网络 往往需要先进行一个简单的测试 来验证网络是否畅通 但是IP协议并不提供可靠传输 如果丢包了 IP协议并
  • nginx基础配置(简单上手)

    全局块 配置影响nginx全局的指令 一般运行nginx服务器的用户组 ngnix进程pid存放路径 日志存放路径 配置文件引入 允许生成woker process数等 events块 配置影响nginx服务器或与用户的网络连接 有每个进程
  • element-ui组件库中Calendar日历组件使用心得(可能用到的常用方法和如何添加监听)

    最近接触到一个需求 做一个值班排班表 拿到低保真之后一直在考虑是如何实现这个排班表 考虑过自己写 也考虑过 fullcalendar vue插件 经过一些评估之后最终选择了项目本身使用的element ui组件库中Calendar日历组件
  • Kafka监控工具,LinkedIn详解

    Kafka监控工具包括以下几种 Kafka Manager 这是一个开源的Kafka集群管理工具 可以监控Kafka集群的健康和性能 并提供可视化的用户界面 Kafka Monitor 这是LinkedIn开发的一个监控工具 可以监控Kaf
  • PPYOLOE

    PP YOLOE是基于PP YOLOv2的单阶段Anchor free模型 超越了多种流行的yolo模型 PP YOLOE有一系列的模型 即s m l x 可以通过width multiplier和depth multiplier配置 PP
  • TDA4VM-LINUX-CSI-9296-9295-camera架构驱动分析和详细使用

    前言 TI在LINUX SDK 8 01版本后才开始支持Linux V4L2接入CSI2 所以在使用前尽量先用RTOS SDK接入CSI2的接口camera 正常工作后开始进行Linux V4L2的开发 LINUX SDK的安装使用 参考另
  • Linux微型服务器(NAS)的搭建

    现在人使用Nas的越来越多 但是对于学生党来说 拥有一个自己的Nas是一件令人兴奋的事情 本篇文章介绍微型Nas 基于神雕开发的海纳思系统 首先 我们选取的是机顶盒改微型nas 我们可以利用mas搭建网页 离线下载 挂青龙脚本 1 1Nas
  • 通过minikube部署kubernetes

    通过minikube部署kubernetes 需要本地验证部署一下knative 需要一个集群 所以先部署一个minikube 记录如下 0 环境准备 安装一个VM VirtualBox 6 0 4版本 1 安装Docker 自己的机器安装
  • 购物车测试用例

    1 界面测试 界面布局 排版是否合理 文字是否显示清晰 不同卖家的商品是否区分明显 页面的tooltips能正常显示 鼠标浮动在购物车按钮 迷你购物车界面显示是否正常 2 功能测试 未登录时 将商品加入购物车 页面跳转到登录页面 登录成功后
  • 开源Linux面板-1Panel

    开源Linux面板 1Panel 1Panel 是一个现代化 开源的 Linux 服务器运维管理面板 1Panel 的功能和优势包括 快速建站 深度集成 Wordpress 和 Halo 域名绑定 SSL 证书配置等一键搞定 高效管理 通过
  • Windows 10 PC 安装 Docker CE

    系统要求 Docker for Windows 支持 64 位版本的 Windows 10 Pro 且必须开启 Hyper V 安装 点击以下链接下载
  • 四数之和——双指针的实践

    一 四数之和 1 1 题目 给定一个包含 n 个整数的数组 nums 和一个目标值 target 判断 nums 中是否存在四个元素 a b c 和 d 使得 a b c d 的值与 target 相等 找出所有满足条件且不重复的四元组 1
  • frida学习及使用

    文章目录 安装frida 安装python3 7 设置环境变量 安装pycharm和nodejs 使用frida 将frida server push到手机设备中 端口转发 安装apk 使用jadx查看java代码 运行frida serv