当前位置: 首页 > news >正文

使用 AndroidNativeEmu 调用 JNI 函数

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

AndroidNativeEmu

AndroidNativeEmu 专为 Android 原生代码调试和模拟设计,特别关注 JNI 调用和 Android 环境。相比之下,Unicorn 是通用的多平台 CPU 模拟器,适用于更广泛的原生代码分析。

项目地址:https://github.com/AeonLucid/AndroidNativeEmu

支持的功能:

  • elf 文件解析及 so 加载

  • 栈支持

  • 内存管理

  • 文件系统

  • JNI 支持

  • 常见 syacall 模拟支持

但是,暂时不支持 arm64。

系统调用

AndroidNativeEmu 系统调用的模拟实现都在 cpu/intertupt_handler.py,根据不同的 intno 调用具体的 handler

word/media/image1.png

目前已经实现的系统调用可以在 syscall_hooks.py 看到

word/media/image2.png

JNIEnv

对应 JNI 接口的模拟实现在 src/androidemu/java/jni_env.py,通过 write_function_table 方法模拟实现 JNI 函数表

word/media/image3.png

jni 函数代码是通过 keystone 来生成的,具体代码在:src/androidemu/hooker.py

word/media/image4.png

so 加载过程中,对 so 中导入符号的 Hook,具体代码在:src/androidemu/native/hooks.py

AndroidNativeEmu 默认已经实现的外部函数

word/media/image5.png

native_method 装饰器

native_method 装饰器用于在 AndroidNativeEmu 中将 Python 函数标记为模拟的 JNI 原生方法,允许函数在模拟器中执行并与 Android 的原生方法交互。

假设我们有一个 C++ 函数 strlen,我们想在模拟器中模拟它:

from androidemu.emulator import Emulator
from androidemu.java.helpers.native_method import native_method

# 初始化模拟器
emulator = Emulator()

# 使用 native_method 装饰器标记 Python 函数为模拟的本地方法
@native_method
def strlen(mu, address):
    content = memory_helpers.read_utf8(mu, address)
    length = len(content)
    return length

# 在 strlen 符号上安装钩子,执行自定义逻辑
emulator.modules.add_symbol_hook('strlen',emulator.hooker.write_function(strlen) + 1)

当使用 native_method 装饰器标记 Python 方法时,框架会自动处理方法参数和返回值的类型转换。

androidemu 维护了一个类型映射表,将常见的 JNI 类型与 Python 数据类型进行对应。具体实现在 native_translate_arg 方法中。

word/media/image6.png

在方法调用返回时,会自动判断返回值是否 JNI 类型并进行查表和类型转换返回真实的值,否则直接返回寄存器中的值。

word/media/image7.png

examples

通过以下命令将项目安装到当前 python 环境中:

pip install /path/to/AndroidNativeEmu

在 examples 目录下是 AndroidNativeEmu 的示例代码

word/media/image8.png

example.py

import logging
import sys

from unicorn import UC_HOOK_CODE
from unicorn.arm_const import *

from androidemu.emulator import Emulator

# 配置日志记录
logging.basicConfig(
    stream=sys.stdout,  # 输出到标准输出
    level=logging.DEBUG,  # 日志级别为调试(DEBUG)
    format="%(asctime)s %(levelname)7s %(name)34s | %(message)s"  # 日志格式
)

# 创建日志记录器
logger = logging.getLogger(__name__)

# 初始化模拟器,启用浮点指令集
emulator = Emulator(vfp_inst_set=True)

# 加载 libc.so,禁用初始化(do_init=False)
emulator.load_library("example_binaries/32/libc.so", do_init=False)

# 加载 libnative-lib.so
lib_module = emulator.load_library("example_binaries/32/libnative-lib.so", do_init=False)

# 显示加载的模块信息
logger.info("Loaded modules:")
# 遍历所有已加载的模块并打印其基地址和文件名
for module in emulator.modules:
    logger.info("[0x%x] %s" % (module.base, module.filename))

# 定义调试钩子函数,跟踪代码执行
def hook_code(uc, address, size, user_data):
    # 读取当前地址的指令
    instruction = uc.mem_read(address, size)
    
    # 将指令转换为十六进制格式的字符串
    instruction_str = ''.join('{:02x} '.format(x) for x in instruction)
    
    # 打印出当前的指令地址、大小和指令内容
    print('# Tracing instruction at 0x%x, instruction size = 0x%x, instruction = %s' % (address, size, instruction_str))

# 将调试钩子添加到模拟器
emulator.uc.hook_add(UC_HOOK_CODE, hook_code)

# 调用 "libnative-lib.so" 中的 "_Z4testv" 方法
emulator.call_symbol(lib_module, '_Z4testv')

# 或者通过地址调用
emulator.call_native(lib_module.base+0x000007C4+1) 
 
# 输出返回的字符串长度("strlen" 返回值存在于 R0 寄存器中)
print("String length is: %i" % emulator.uc.reg_read(UC_ARM_REG_R0))

相关文章:

  • k8s学习记录:环境搭建(基于Kubeadmin)
  • 从入门到精通Rust:资源库整理
  • 【YOLOv11改进- 主干网络】YOLOv11+RepViT: 从ViT的角度重新审视Mobile的CNN助力YOLOv11有效涨点;
  • 解决Spring Boot中Druid连接池“discard long time none received connection“警告
  • DeepSeek R1的崛起与挑战:技术创新 与 普通人的反思
  • HTML之JavaScript DOM编程获取元素的方式
  • 制造业革命:数字化转型从哪里开始?
  • 【大模型系列】使用docker安装向量数据库Milvus问题备忘
  • Docker 与 Serverless(无服务器架构)
  • 玩客云OneCloud部署Zerotier虚拟局域网
  • 跨平台公式兼容性大模型提示词模板(飞书 + CSDN + Microsoft Word)
  • C++ 编程语言简介
  • P56 auto类型
  • ThinkPHP:配置Redis并使用
  • Python常用的函数和功能
  • HTML之JavaScript DOM操作元素(1)
  • Day1 初识AndroidAudio
  • 蓝桥杯试题:小明的彩灯(差分 前缀和)
  • 綫性與非綫性泛函分析與應用_1.例題(下)-半母本
  • MySQL 数据库关联查询全解析:一对一、一对多、多对多
  • 人民日报钟声:国际社会应共同维护科学溯源的正确方向
  • 王受文已任中华全国工商业联合会领导班子成员
  • 金砖国家外长会晤落幕,外交部:发出了反对单边霸凌行径的“金砖声音”
  • 看见“看得见的手”,看见住房与土地——读《央地之间》
  • 香港警务处高级助理处长叶云龙升任警务处副处长(行动)
  • 四川一国企“80后”掌门人为报领导“知遇之恩”,盲目决策致数亿损失