
BIDK API参考手册开发者必备的接口和数据结构详解【免费下载链接】BIDKA low-overhead dynamic binary instrumentation and modification tool for ARM (both AArch32 and AArch64 support) and RISC-V (RV64GC).项目地址: https://gitcode.com/openeuler/BIDK前往项目官网免费下载https://ar.openeuler.org/ar/BIDK是一个针对ARMAArch32/AArch64和RISC-VRV64GC架构的低开销动态二进制插桩和修改工具。本指南将详细介绍BIDK的核心API接口和数据结构帮助开发者快速上手并构建强大的二进制分析插件。 BIDK核心架构概述BIDK采用插件化架构允许开发者在运行时动态修改和分析二进制代码。其核心组件包括动态二进制修改引擎实时重写目标程序的指令流插件支持系统提供丰富的回调机制和API接口代码缓存管理高效管理修改后的代码片段线程感知设计支持多线程环境下的安全操作 核心数据结构详解mambo_context插件上下文结构这是BIDK API中最核心的数据结构封装了所有插件操作所需的上下文信息typedef struct { dbm_thread *thread_data; // 线程相关数据 mambo_cb_idx event_type; // 事件类型 int plugin_id; // 插件ID union { struct code_ctx code; // 代码执行上下文 struct syscall_ctx syscall; // 系统调用上下文 struct vm_ctx vm; // 虚拟内存操作上下文 }; } mambo_context;code_ctx代码执行上下文当处理指令相关事件时使用此结构体struct code_ctx { cc_type fragment_type; // 片段类型基本块/跟踪等 int fragment_id; // 片段ID inst_set inst_type; // 指令集类型 void *read_address; // 原始指令地址 int inst; // 指令编码 mambo_cond cond; // 条件码 void *write_p; // 写入指针 void *data_p; // 数据指针 uint32_t pushed_regs; // 已压栈寄存器 uint32_t available_regs; // 可用寄存器 int plugin_pushed_reg_count; // 插件压栈寄存器计数 char *func_name; // 函数名 bool replace; // 是否替换指令 bool *stop; // 停止扫描标志 };syscall_ctx系统调用上下文处理系统调用事件时使用的数据结构struct syscall_ctx { uintptr_t number; // 系统调用号 uintptr_t *regs; // 寄存器数组指针 bool replace; // 是否替换系统调用 uintptr_t ret; // 返回值 }; 回调机制与事件类型BIDK提供了丰富的事件回调机制允许插件在特定时机介入执行流程事件类型枚举typedef enum { PLUGIN_REG, // 插件注册 PRE_INST_C, // 指令执行前 POST_INST_C, // 指令执行后 PRE_BB_C, // 基本块执行前 POST_BB_C, // 基本块执行后 PRE_FRAGMENT_C, // 代码片段执行前 POST_FRAGMENT_C, // 代码片段执行后 PRE_SYSCALL_C, // 系统调用前 POST_SYSCALL_C, // 系统调用后 PRE_THREAD_C, // 线程创建前 POST_THREAD_C, // 线程结束后 PRE_FN_C, // 函数调用前 POST_FN_C, // 函数调用后 EXIT_C, // 程序退出 VM_OP_C, // 虚拟内存操作 CALLBACK_MAX_IDX } mambo_cb_idx;分支类型枚举typedef enum { BRANCH_NONE (1 0), BRANCH_DIRECT (1 1), // 直接分支 BRANCH_INDIRECT (1 2), // 间接分支 BRANCH_RETURN (1 3), // 返回指令 BRANCH_COND (1 4), // 条件分支 BRANCH_COND_PSR (1 5), // PSR条件分支 BRANCH_COND_CBZ (1 6), // CBZ/CBNZ分支 BRANCH_COND_TBZ (1 7), // TBZ/TBNZ分支仅A64 BRANCH_COND_IT (1 8), // IT块分支仅T32 BRANCH_CALL (1 9), // 调用指令 BRANCH_INTERWORKING (1 10), // 指令集切换分支 BRANCH_TABLE (1 11), // 跳转表分支仅T32 } mambo_branch_type; 核心API函数详解插件注册与管理mambo_register_plugin()- 注册新插件mambo_context *mambo_register_plugin(void);这是插件开发的入口点每个插件必须在初始化时调用此函数。回调注册函数- 注册事件处理器int mambo_register_pre_inst_cb(mambo_context *ctx, mambo_callback cb); int mambo_register_post_inst_cb(mambo_context *ctx, mambo_callback cb); int mambo_register_pre_basic_block_cb(mambo_context *ctx, mambo_callback cb); int mambo_register_post_basic_block_cb(mambo_context *ctx, mambo_callback cb); int mambo_register_pre_syscall_cb(mambo_context *ctx, mambo_callback cb); int mambo_register_post_syscall_cb(mambo_context *ctx, mambo_callback cb);内存管理APImambo_alloc() / mambo_free()- 插件内存分配void *mambo_alloc(mambo_context *ctx, size_t size); void mambo_free(mambo_context *ctx, void *ptr);使用BIDK的内存管理机制分配和释放内存确保线程安全。插件数据存储- 线程本地存储int mambo_set_plugin_data(mambo_context *ctx, void *data); void *mambo_get_plugin_data(mambo_context *ctx); int mambo_set_thread_plugin_data(mambo_context *ctx, void *data); void *mambo_get_thread_plugin_data(mambo_context *ctx);这些函数允许插件存储和检索线程特定的数据。指令操作API指令信息获取- 分析当前指令int mambo_get_inst(mambo_context *ctx); // 获取指令编码 inst_set mambo_get_inst_type(mambo_context *ctx); // 获取指令集类型 int mambo_get_fragment_id(mambo_context *ctx); // 获取片段ID cc_type mambo_get_fragment_type(mambo_context *ctx); // 获取片段类型 int mambo_get_inst_len(mambo_context *ctx); // 获取指令长度内存访问检测- 识别加载/存储指令bool mambo_is_load(mambo_context *ctx); // 是否为加载指令 bool mambo_is_store(mambo_context *ctx); // 是否为存储指令 bool mambo_is_load_or_store(mambo_context *ctx); // 是否为内存访问指令 int mambo_get_ld_st_size(mambo_context *ctx); // 获取内存访问大小分支类型检测- 分析控制流mambo_branch_type mambo_get_branch_type(mambo_context *ctx);这个函数对于构建控制流分析插件至关重要。代码生成API寄存器管理- 临时寄存器分配int mambo_get_scratch_regs(mambo_context *ctx, int count, ...); int mambo_get_scratch_reg(mambo_context *ctx, int *regp); int mambo_free_scratch_regs(mambo_context *ctx, uint32_t regs); int mambo_free_scratch_reg(mambo_context *ctx, int reg);代码发射函数- 生成新指令void emit_push(mambo_context *ctx, uint32_t regs); // 寄存器压栈 void emit_pop(mambo_context *ctx, uint32_t regs); // 寄存器出栈 void emit_set_reg(mambo_context *ctx, enum reg reg, uintptr_t value); // 设置寄存器值 void emit_fcall(mambo_context *ctx, void *function_ptr); // 函数调用 int emit_branch(mambo_context *ctx, void *target); // 无条件分支 int emit_branch_cond(mambo_context *ctx, void *target, mambo_cond cond); // 条件分支系统调用处理系统调用操作- 拦截和修改系统调用int mambo_syscall_get_no(mambo_context *ctx, uintptr_t *no); // 获取系统调用号 void mambo_syscall_get_args(mambo_context *ctx, uintptr_t **args); // 获取参数 int mambo_syscall_bypass(mambo_context *ctx); // 绕过系统调用 int mambo_syscall_get_return(mambo_context *ctx, uintptr_t *ret); // 获取返回值 int mambo_syscall_set_return(mambo_context *ctx, uintptr_t ret); // 设置返回值️ 实用工具函数地址计算与映射mambo_calc_ld_st_addr()- 计算内存访问地址int mambo_calc_ld_st_addr(mambo_context *ctx, enum reg reg);将加载/存储指令的地址计算到指定寄存器中。mambo_add_identity_mapping()- 添加地址映射int mambo_add_identity_mapping(mambo_context *ctx);确保修改后的代码能够正确访问原始代码位置。符号与堆栈跟踪符号信息获取- 地址到符号的映射int get_symbol_info_by_addr(uintptr_t addr, char **sym_name, void **start_addr, char **filename);根据地址获取符号名称、起始地址和文件名信息。堆栈回溯支持- 生成调用栈typedef int (*stack_frame_handler)(void *data, void *addr, char *sym_name, void *symbol_start_addr, char *filename); int get_backtrace(stack_frame_t *fp, stack_frame_handler handler, void *ptr); 插件开发最佳实践1. 插件初始化模式每个BIDK插件都应该遵循标准的初始化模式__attribute__((constructor)) void plugin_init() { mambo_context *ctx mambo_register_plugin(); assert(ctx ! NULL); // 注册回调函数 mambo_register_pre_inst_cb(ctx, pre_inst_handler); mambo_register_post_inst_cb(ctx, post_inst_handler); // 设置插件数据 mambo_set_plugin_data(ctx, global_data); }2. 线程安全数据管理对于多线程插件使用线程本地存储int pre_thread_handler(mambo_context *ctx) { struct thread_data *data mambo_alloc(ctx, sizeof(struct thread_data)); mambo_set_thread_plugin_data(ctx, data); // 初始化线程数据 } int post_thread_handler(mambo_context *ctx) { struct thread_data *data mambo_get_thread_plugin_data(ctx); // 清理线程数据 mambo_free(ctx, data); }3. 高效代码注入使用BIDK的代码生成API实现高效插桩int pre_inst_handler(mambo_context *ctx) { if (mambo_is_load_or_store(ctx)) { // 分配临时寄存器 int reg; mambo_get_scratch_reg(ctx, reg); // 计算内存地址 mambo_calc_ld_st_addr(ctx, reg); // 执行自定义逻辑 emit_fcall(ctx, my_memory_tracer); // 释放寄存器 mambo_free_scratch_reg(ctx, reg); } } 实际应用示例分支计数插件查看 plugins/branch_count.c 了解如何统计不同类型的分支指令struct br_count { uint64_t direct_branch_count; uint64_t indirect_branch_count; uint64_t return_branch_count; }; int branch_count_pre_inst_handler(mambo_context *ctx) { mambo_branch_type type mambo_get_branch_type(ctx); if (type BRANCH_RETURN) { // 处理返回指令 } else if (type BRANCH_DIRECT) { // 处理直接分支 } else if (type BRANCH_INDIRECT) { // 处理间接分支 } }内存跟踪插件查看 plugins/mtrace.c 学习如何跟踪内存访问int mtrace_pre_inst_handler(mambo_context *ctx) { bool is_load mambo_is_load(ctx); bool is_store mambo_is_store(ctx); if (is_load || is_store) { int size mambo_get_ld_st_size(ctx); // 记录内存访问信息 } } 性能优化技巧减少代码缓存压力选择性插桩只在必要时注入代码批量处理合并多个操作减少指令数寄存器重用高效管理临时寄存器条件执行使用条件分支避免不必要的代码执行内存访问优化局部性原理将相关数据放在相邻位置缓存友好减少缓存未命中预取策略提前加载可能用到的数据 进一步学习资源官方API文档api/plugin_support.h - 核心API定义辅助函数库api/helpers.h - 实用工具函数插件示例plugins/ - 丰富的插件实现系统调用支持syscalls.h - 系统调用相关定义 常见问题解答Q: 如何调试BIDK插件A: 使用标准调试工具如gdb并设置断点在插件的回调函数中。确保使用正确的编译标志。Q: 插件会影响程序性能吗A: BIDK设计为低开销但插件的复杂性会影响性能。建议进行性能分析和优化。Q: 支持哪些架构A: BIDK支持ARMAArch32和AArch64以及RISC-VRV64GC架构。Q: 如何处理多线程程序A: BIDK提供线程感知的API使用mambo_set_thread_plugin_data()和mambo_get_thread_plugin_data()管理线程本地数据。通过掌握BIDK的API接口和数据结构您可以构建强大的二进制分析工具实现性能分析、安全检测、动态优化等多种功能。【免费下载链接】BIDKA low-overhead dynamic binary instrumentation and modification tool for ARM (both AArch32 and AArch64 support) and RISC-V (RV64GC).项目地址: https://gitcode.com/openeuler/BIDK创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考