frida脚本,自动化寻址JNI方法

版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/

1. 通过 ArtMethod 结构体找到 jni 方法在内存中的地址,并把寻址方法通过 rpc.exports 暴露给 Python 脚本调用

jni_addr.js

let entry_point_from_jni_offset = -1;/*** 找到 entry_point_from_jni_ 在 ArtMethod 结构体中的偏移量(根据 Android 版本不同可能会变化)** @returns {number} 返回 entry_point_from_jni_ 的偏移量,若未找到返回 -1*/
function get_jni_offset() {// 如果偏移量已经计算过(不为 -1),直接返回已保存的偏移量if (entry_point_from_jni_offset !== -1) {return entry_point_from_jni_offset;}// 获取 getUidForName JNI 方法的内存地址,该方法位于 "libandroid_runtime.so" 中let native_addr = Module.findExportByName("libandroid_runtime.so", "_Z32android_os_Process_getUidForNameP7_JNIEnvP8_jobjectP8_jstring");// console.log("native_addr:",native_addr);// 目标类名 "android.os.Process"let className = "android.os.Process";// 使用 Java.use 获取该类的 Java 类对象,并访问其 Class 对象let clazz = Java.use(className).class;// 获取该类的所有声明的方法let methods = clazz.getDeclaredMethods();// 遍历类中的所有方法for (let i = 0; i < methods.length; i++) {// 获取方法的字符串表示形式(如方法的完整签名)let methodName = methods[i].toString();// 获取方法的修饰符,flags 是该方法的访问标志(修饰符),如 public、private、static、native 等let flags = methods[i].getModifiers();// 通过与 256 位运算判断方法是否为 native 方法(256 代表 native 修饰符)if (flags & 256) {// 如果方法名中包含 "getUidForName",说明找到了目标方法if (methodName.indexOf("getUidForName") != -1) {// 获取该方法的 ArtMethod 对象(ArtMethod 是方法的内部表示,包含了方法的很多底层信息)let art_method = methods[i].getArtMethod();// 遍历从 ArtMethod 开始的内存地址,以找到与 native_addr 相等的 JNI 函数地址for (let j = 0; j < 30; j = j + 1) {// 读取 ArtMethod 的内存偏移位置,尝试获取 JNI 函数地址let jni_native_addr = Memory.readPointer(ptr(art_method + j));// 比较 JNI 函数地址是否与我们查找到的 native_addr 相等if (native_addr.equals(jni_native_addr)) {// 找到正确的偏移量,将其保存并返回entry_point_from_jni_offset = j;return j;}}}}}// 如果未找到 JNI 方法对应的偏移量,返回 -1return -1;
}/*** 遍历类中的 native 方法,打印 JNI 函数的地址、所属模块,以及模块中的偏移量。** 调用示例:get_jni_method_addr("lte.NCall")** @param className 类名*/
function get_jni_method_addr(className) {Java.perform(function () {// 获取指定类的 Class 对象let obj = Java.use(className);let clazz = obj.class;// 获取当前系统的 JNI 偏移量let jni_offset = get_jni_offset();// 获取该类中的所有声明的方法let methods = clazz.getDeclaredMethods();// 遍历类中的所有方法for (let i = 0; i < methods.length; i++) {// 将方法转为字符串形式(完整的描述,包括修饰符、返回类型、参数等)let methodName = methods[i].toString();// 获取方法的修饰符,flags 代表访问权限和其他属性(如 native 修饰符)let flags = methods[i].getModifiers();// 检查该方法是否为 native 方法(通过与 256 位运算判断,256 代表 native 修饰符)if (flags & 256) {// 获取该方法的 ArtMethod 对象,ArtMethod 是方法在 ART 虚拟机中的内部表示let art_method = methods[i].getArtMethod();// 通过 ArtMethod 的内存地址 + jni_offset = JNI 函数地址let native_addr = Memory.readPointer(ptr(art_method + jni_offset));// 根据 JNI 函数地址中找到所在的模块,并计算该函数在模块中的偏移量let module;let offset;// 打印方法名console.log("methodName->", methodName);try {// 通过函数地址找到所属的模块module = Process.getModuleByAddress(native_addr);// 计算函数在模块中的偏移量(函数地址减去模块基地址)offset = native_addr - module.base;// 打印模块名称及偏移量,偏移量以十六进制格式显示,并且字母大写console.log("Func.offset==", module.name, "0x" + offset.toString(16).toUpperCase());} catch (err) {}// 打印该方法的 JNI 函数地址console.log("Func.getArtMethod->native_addr:", native_addr.toString().toUpperCase());// console.log("Func.flags->", flags);}}})
}// 暴露给 Python 调用(注意:exports中函数名需要全部小写,而且不能有下划线,不然会找不到方法)
rpc.exports.getjnimethodaddr = get_jni_method_addr

2. 在 python 脚本中加载 jni_addr.js 并调用 get_jni_method_addr 方法打印指定类中所有 native 方法的内存地址

jni_addr.py

import fridadef read_frida_js_source(script):with open(script, "r", encoding='utf-8') as f:return f.read()def on_message(message, data):print(f"消息: {message['type']}, 数据: {message['payload']}")def main():class_name = "com.cyrus.example.MainActivity"device = frida.get_device_manager().add_remote_device("127.0.0.1:1234")pid = device.get_frontmost_application().pidsession: frida.core.Session = device.attach(pid)script = session.create_script(read_frida_js_source("jni_addr.js"))script.on('message', on_message)script.load()script.exports.getjnimethodaddr(class_name)# 退出session.detach()if __name__ == "__main__":main()

运行python脚本,执行结果如下

methodName-> public final native java.lang.String com.cyrus.example.MainActivity.getNativeString()
Func.offset== libnative-lib.so 0x24F10
Func.getArtMethod->native_addr: 0X77518B6F10

具体原理可以参考这篇文章【使用 Frida 定位 JNI 方法内存地址】

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【PnP】详细公式推导,使用DLT直接线性变换法求解相机外参

文章目录 &#x1f680;PnP1️⃣ 求解不考虑尺度的解2️⃣ 恢复解的尺度3️⃣ 另一种解法 &#x1f680;PnP PnP(Perspective-n-Point)是求解3D到2D点相机外参的算法。PnP算法有DLT直接线性变换、P3P三对点估计位姿、EPnP(Efficient PnP)、BA(Bundle Adjustment)光速法平差。这…

数据库基础介绍

前言&#xff1a; 在当今信息化、数字化的时代&#xff0c;数据库是支撑一切信息系统的核心基础设施。无论是金融机构的账户管理、电商平台的商品库存&#xff0c;还是社交媒体的用户信息&#xff0c;数据库都在背后扮演着关键角色数据库不仅用于存储和管理数据&#xff0c;更…

[Ansible实践笔记]自动化运维工具Ansible(一):初探ansibleansible的点对点模式

文章目录 Ansible介绍核心组件任务执行方式 实验前的准备更新拓展安装包仓库在ansible主机上配置ip与主机名的对应关系生成密钥对将公钥发送到被管理端&#xff0c;实现免密登录测试一下是否实现免密登录 常用工具ansibleansible—docansible—playbook 主要配置文件 Ansible 模…

倪师学习笔记-天纪-易经八卦

一、简介 卦代表事情&#xff0c;爻代表时机&#xff0c;三爻为一卦八卦对应的天相&#xff0c;六十四卦对应人间事 二、八卦性 1、乾 天父亲向下看&#xff0c;无所求&#xff0c;雄心万丈始终如一&#xff0c;贞&#xff0c;坚心&#xff0c;专心至刚&#xff0c;天威&am…

Hash表算法

哈希表 理论知识&#xff08;本文来自于代码随想录摘抄&#xff09;什么是哈希常见的三种哈希结数组&#xff1a;set:map:其他常用方法或者技巧&#xff08;自己总结的&#xff09; 练习题和讲解有效的字母移位词349. 两个数组的交集1. 两数之和454. 四数相加 II15. 三数之和 总…

如何选择适合自己的 Python IDE

集成开发环境&#xff08;IDE&#xff09;是指提供广泛软件开发能力的软件应用程序。IDE 通常包括源代码编辑器、构建自动化工具和调试器。大多数现代 IDE 都配备了智能代码补全功能。在本文中&#xff0c;你将发现目前市场上最好的 Python IDE。 什么是 IDE&#xff1f; IDE…

为什么架构设计禁止IP直连?

什么是IP直连&#xff1f; IP直连指应用程序直接在代码中硬编码IP地址&#xff0c;比如&#xff0c;连接mysql数据库的数据库链接&#xff0c;如下的定义方式&#xff0c;就属于IP直连。 这种写法在开发环境中很常见&#xff0c;但是&#xff0c;在正式生产环境中&#xff0c;…

Linux shell编程学习笔记87:blkid命令——获取块设备信息

0 引言 在进行系统安全检测时&#xff0c;我们需要收集块设备的信息&#xff0c;这些可以通过blkid命令来获取。 1 blkid命令的安装 blkid命令是基于libblkid库的命令行工具&#xff0c;可以在大多数Linux发行版中使用。 如果你的Linux系统中没有安装blkid命令&#xff0c;…

Nginx处理并发连接

Nginx以其高效处理并发连接的能力而闻名&#xff0c;这主要归功于其事件驱动的架构和异步非阻塞I/O操作。 是Nginx处理并发连接的关键机制&#xff1a; 1. 事件驱动架构 Nginx采用事件驱动架构&#xff0c;这意味着它使用事件通知机制来响应网络事件&#xff0c;如新连接、读…

构建生产级的 RAG 系统

对 RAG 应用程序进行原型设计很容易&#xff0c;但要使其高性能、健壮且可扩展到大型知识语料库却很困难。 本指南包含各种提示和技巧&#xff0c;以提高 RAG 工作流程的性能。我们首先概述一些通用技术 - 它们按照简单到复杂的顺序进行排列。然后&#xff0c;我们将更深入地研…

【python实操】python小程序之测试报告

引言 python小程序之测试报告 文章目录 引言一、测试报告1.1 概念1.1.1 使用Pytest和Allure生成测试报告1.1.2 使用unittest和HTMLTestRunner生成测试报告1.1.3 总结 1.2 题目1.3 代码1.3 代码解释 二、思考 一、测试报告 1.1 概念 python生成测试报告&#xff0c;常用的方法包…

ELK之路第一步——Elasticsearch集群的搭建以及踩坑记录

elasticSearch集群 前言一、架构二、下载三、虚拟机相关设置3.1 创建es用户3.2 为建es用户赋权sudo3.3 更换es目录所属用户 四、Elasticsearch配置文件修改4.1 修改elasticsearch.yml4.2 修改jvm.options4.3 修改jdk路径 五、启动六、启动报错七、设置密码八、可视化界面cerebr…

支持向量机SVM简述

支持向量机SVM 1、概述 SVM全称是supported vector machine&#xff08;支持向量机&#xff09;&#xff0c;即寻找到一个超平面使样本分成两类&#xff0c;并且间隔最大。 SVM 模型有3种&#xff1a; 线性可分支持向量机&#xff1a;适用于训练数据线性可分。线性支持向量…

Ubuntu22.04环境搭建MQTT服务器

官网&#xff1a; https://mosquitto.org 1.引入库 sudo apt-add-repository ppa:mosquitto-dev/mosquitto-ppa2.升级安装工具 sudo apt-get update 3.安装 sudo apt-get install mosquitto 4.安装客户端 sudo apt-get install mosquitto-clients5.添加修改配置文件 进…

【使用Flask构建RESTful API】从零开始开发简单的Web服务!

使用Flask构建RESTful API&#xff1a;从零开始开发简单的Web服务 引言 随着Web应用程序的广泛使用&#xff0c;RESTful API已成为现代Web服务的核心技术之一。通过RESTful API&#xff0c;我们可以轻松地创建、读取、更新和删除&#xff08;CRUD&#xff09;数据&#xff0c…

力扣21 : 合并两个有序链表

链表style 描述&#xff1a; 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例&#xff1a; 节点大小相同时&#xff0c;l1的节点在前 何解&#xff1f; 1&#xff0c;遍历两个链表&#xff0c;挨个比较节点大小 同时遍…

Python应用指南:利用高德地图API实现路径规划

高德路径规划API是一套基于HTTP协议的接口服务&#xff0c;旨在为开发者提供便捷的路径规划解决方案。该API支持多种出行方式&#xff0c;包括步行、公交和驾车&#xff0c;能够满足不同场景下的路径查询需求。通过调用这些API&#xff0c;用户可以获得从起点到终点的最优路径建…

Flink CDC系列之:理解学习Kubernetes模式

Flink CDC系列之&#xff1a;理解学习Kubernetes模式 准备会话模式启动会话集群设置 Flink CDC提交 Flink CDC Job Kubernetes 是一种流行的容器编排系统&#xff0c;用于自动化计算机应用程序的部署、扩展和管理。Flink 的原生 Kubernetes 集成允许您直接在正在运行的 Kuberne…

SOEM(EtherCAT)主站API梳理

1. 适配器管理 ec_adaptert * ec_find_adapters(void); 功能&#xff1a;查找并返回系统中所有可用的EtherCAT适配器的列表。返回值&#xff1a;指向适配器列表的指针。如果没有找到适配器&#xff0c;则返回NULL。void ec_free_adapters(ec_adaptert * adapter); 功能&#x…

Taro React-Native Android apk 打包

一、打包 react native 之打包 Android的apk - 创客未来 - 博客园 react native 打包成Android 的apk安装包有两种方式&#xff0c;第一种方式是利用 Android studio 打包这里就不接介绍了。第二种是利用 react native 自身项目打包 1、生成签名 再一个空文件夹打开CMD&…