frida学习及使用

文章目录

  • 安装frida
    • 安装python3.7
    • 设置环境变量
    • 安装pycharm和nodejs
  • 使用frida
    • 将frida-server push到手机设备中
    • 端口转发
    • 安装apk
    • 使用jadx查看java代码
    • 运行frida-server
  • frida源码阅读
  • frida hook方法
    • Frida Java层hoook
      • JavaHook.java
      • JavaHook.js
    • Frida native层hook 一
    • NativeHook.js

安装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();
})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/56513.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深度学习——划分自定义数据集

深度学习——划分自定义数据集 以人脸表情数据集raf_db为例&#xff0c;初始目录如下&#xff1a; 需要经过处理后返回 train_images, train_label, val_images, val_label 定义 read_split_data(root: str, val_rate: float 0.2) 方法来解决&#xff0c;代码如下&#xff1a…

局域网内电脑ping不通(防火墙惹的祸)

明明是同一网段&#xff08;同一局域网&#xff09;的电脑&#xff0c;却ping不通&#xff0c;这种情况大概率就是防火墙惹得祸了。除了把防火墙关掉&#xff0c;我们还可以采取如下解决方案。 解决方案&#xff1a; 1. 打开&#xff1a;控制面板\系统和安全\Windows Defende…

matlab多线程,parfor循环进度,matlab互斥锁

一. 内容简介 matlab多线程&#xff0c;parfor循环进度&#xff0c;matlab互斥锁 二. 软件环境 2.1 matlab 2022b 2.2代码链接 https://gitee.com/JJW_1601897441/csdn 三.主要流程 3.1 matlab多线程 有好几种&#xff0c;最简单的&#xff0c;最好理解的就是parfor&am…

面试热题(无重复字符的最长子串)

无重复字符的最长子串 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 输入: s "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc"&#xff0c;所以其长度为 3。 解法一&#xff1a; public int lengthOfLonge…

css 动画之旋转视差

序&#xff1a;网上看到的一个例子&#xff0c;做一下 效果图&#xff1a; 代码&#xff1a; <style>.content{width: 300px;height: 300px;margin: 139px auto;display: grid;grid-template-columns: repeat(3,1fr);grid-template-rows: repeat(3,1fr);grid-template:…

4年测试工程师,常用功能测试点总结,“我“不再走弯路...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 输入框测试 1、字…

MySQL的JSON操作

官网地址 1. MySQL json介绍 As of MySQL 5.7.8, MySQL supports a native JSON data type defined by RFC 7159 that enables efficient access to data in JSON (JavaScript Object Notation) documents. Automatic validation of JSON documents stored in JSON columns. …

【消息中间件】原生PHP对接Uni H5、APP、微信小程序实时通讯消息服务

文章目录 视频演示效果前言一、分析二、全局注入MQTT连接1.引入库2.写入全局连接代码 二、PHP环境建立总结 视频演示效果 【uniapp】实现买定离手小游戏 前言 Mqtt不同环境问题太多&#xff0c;新手可以看下 《【MQTT】Esp32数据上传采集&#xff1a;最新mqtt插件&#xff08;支…

PHP: 开发入门macOS系统下的安装和配置

安装Homebrew 安装 ~~友情提示&#xff1a;这个命令对网络有要求&#xff0c;可能需要翻墙或者用你的手机热点试试&#xff0c;或者把DNS换成&#xff08;114.114.114.114 和 8.8.8.8&#xff09; /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebr…

【【胎教级51单片机智能小车设计】】

胎教级51单片机智能小车设计 从现在开始开一个新坑 称为创意工坊 主要更新一些有意思的设计 第一次手把手更新51单片机智能小车 胎教级教学人人都会 单片机实现的功能是通过蓝牙APP 控制小车前后左右移动 先讲明白这个小车 后续再在这个小车上更新其他的设计 成品图 第一步…

分库分表之基于Shardingjdbc+docker+mysql主从架构实现读写分离(一)

说明&#xff1a;请先自行安装好docker再来看本篇文章&#xff0c;本篇文章主要实现通过使用docker部署mysql实现读写分离&#xff0c;并连接数据库测试。第二篇将实现使用Shardingjdbc实现springboot的读写分离实现。 基于Docker去创建Mysql的主从架构 #创建主从数据库文件夹…

Rocky(centos) jar 注册成服务,能开机自启动

概述 涉及&#xff1a;1&#xff09;sh 无法直接运行java命令&#xff0c;可以软连&#xff0c;此处是直接路径 2&#xff09;sh脚本报一堆空格换行错误&#xff1a;需将转成unix标准格式&#xff1b; #切换到上传的脚本路径 dos2unix 脚本文件名.sh 2&#xff09;SELINUX …

如何使用STAR原则优化项目管理?

介绍STAR原则 1.1 STAR原则的定义 STAR原则是一个行为面试技术&#xff0c;即Situation&#xff08;情境&#xff09;、Task&#xff08;任务&#xff09;、Action&#xff08;行动&#xff09;和Result&#xff08;结果&#xff09;。这种原则被广泛应用在职业面试中&#x…

PROFINet转Modbus协议转换网关Profinet数据通讯模块

产品概述 你是否曾经遇到过不同网络协议之间的沟通问题&#xff1f;捷米特JM-RTU-PN为你解决这个难题&#xff01; 捷米特JM-RTU-PN是一款数据通讯模块&#xff0c;能够实现PROFINet网络与Modbus网络之间的数据传输。它可以将RS485网络连接到PROFINet网络&#xff0c;并支持不…

【iOS】—— UIKit相关问题

文章目录 UIKit常用的UIKit组件懒加载的优势 CALayer和UIView区别关系 UITableViewUITableView遵循的两个delegate以及必须实现的方法上述四个必须实现方法执行顺序其他方法的执行顺序&#xff1a; UICollectionView和UITableView的区别UICollectionViewFlowLayout和UICollecti…

mysql进阶-用户的创建_修改_删除

1. 使用mysql单次查询 [rootVM-4-6-centos /]# mysql -h localhost -P 3306 -p mytest -e "select * from book1"; Enter password: ------------------------------------------- | id | category_id | book_name | num | ----------------------------…

第七章 图论

第七章 图论 一、数据结构定义 图的邻接矩阵存储法#define MaxVertexNum 100 // 节点数目的最大值// 无边权&#xff0c;只用0或1表示边是否存在 bool graph[MaxVertexNum][MaxVertexNum];// 有边权 int graph[MaxVertexNum][MaxVertexNum];图的邻接表存储法 把所有节点存储为…

Java版工程行业管理系统源码-专业的工程管理软件- 工程项目各模块及其功能点清单 em

&#xfeff; Java版工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离 功能清单如下&#xff1a; 首页 工作台&#xff1a;待办工作、消息通知、预警信息&#xff0c;点击可进入相应的列表 项目进度图表&#xff1a;选择&#xff08;总体或单个&…

UNITY随记(八) SHADER实现立方体CUBE显示边框,描边

Shader "Vitens/CubeOutline"{Properties{_Color("Color", color) (1,1,1,1)_Width("Width", range(0,0.5)) 0.1}SubShader{Tags { "Queue""Transparent" }Pass {//如果要显示背面的线框&#xff0c;取消下面两个注释即可…

【etcd】docker 启动单点 etcd

etcd: v3.5.9 etcd-browser: rustyx/etcdv3-browser:latest 本文档主要描述用 docker 部署单点的 etcd&#xff0c; 用 etcd-browser 来查看注册到 etcd 的 key 默认配置启动 docker run -d --name ai-etcd --networkhost --restart always \-v $PWD/etcd.conf.yml:/opt/bitn…