Linux底子 -- ARM 32 位架构动态注入代码技能文档

[复制链接]
发表于 2025-10-24 20:02:01 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
ARM 32 位架构动态注入代码技能文档

1. 配景概述

在某些环境下,我们须要在运行时动态地天生并实行代码,比方 JIT(Just-In-Time Compilation)技能、运行时补丁或二进制重写。本文先容了一种在 ARM 32 位架构下,通过 mmap 分配可实行内存,注入汇编指令,并革新指令缓存以确保代码准确实行的方法。
2. 代码实现

以下代码示例展示了如安在 ARM 32 位架构下动态注入一段汇编代码并实行它。
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <sys/mman.h>
  4. #include <unistd.h>
  5. #include <string.h>
  6. void __flush_icache_range(unsigned long start, unsigned long end);
  7. typedef int (*func_t)(void);
  8. int main() {
  9.     // 1. 分配一块可执行内存
  10.     size_t page_size = sysconf(_SC_PAGESIZE);
  11.     void *mem = mmap(NULL, page_size, PROT_READ | PROT_WRITE | PROT_EXEC,
  12.                      MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
  13.     if (mem == MAP_FAILED) {
  14.         perror("mmap");
  15.         return 1;
  16.     }
  17.     // 2. ARM 32 位汇编指令 (mov r0, #42; bx lr)
  18.     unsigned char code[] = {
  19.         0x2A, 0x00, 0xA0, 0xE3,  // mov r0, #42
  20.         0x1E, 0xFF, 0x2F, 0xE1   // bx lr
  21.     };
  22.     // 3. 复制代码到分配的内存
  23.     memcpy(mem, code, sizeof(code));
  24.     // 4. 刷新指令缓存
  25.     __flush_icache_range((unsigned long)mem, (unsigned long)mem + sizeof(code));
  26.     // 5. 执行代码
  27.     func_t func = (func_t)mem;
  28.     int result = func();
  29.     printf("JIT 生成代码返回值: %d\n", result);
  30.     // 6. 释放内存
  31.     munmap(mem, page_size);
  32.     return 0;
  33. }
  34. // 7. 在内核模块中实现 __flush_icache_range
  35. void __flush_icache_range(unsigned long start, unsigned long end) {
  36.     //__asm__ __volatile__(
  37.     //    "mov r3, #0\n"
  38.     //    "mcr p15, 0, r3, c7, c5, 0\n"  // Invalidate I-cache
  39.     //    "dsb\n"
  40.     //    "isb\n"
  41.     //    : : "r"(start), "r"(end) : "r3"
  42.     //);
  43.     __builtin___clear_cache((char *)start, (char *)end);
  44. }
复制代码
3. 代码分析

3.1. 分配可实行内存
  1. size_t page_size = sysconf(_SC_PAGESIZE);
  2. void *mem = mmap(NULL, page_size, PROT_READ | PROT_WRITE | PROT_EXEC,
  3.                  MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
复制代码

  • mmap 用于分配一块内存,答应读、写和实行。
  • MAP_ANONYMOUS 使得映射不依靠详细的文件。
  • MAP_PRIVATE 确保内存地区私有。
  • 如果 mmap 失败,步调打印错误并返回。
3.2. 注入 ARM 32 位汇编指令
  1. unsigned char code[] = {
  2.     0x2A, 0x00, 0xA0, 0xE3,  // mov r0, #42
  3.     0x1E, 0xFF, 0x2F, 0xE1   // bx lr
  4. };
复制代码

  • 这段代码实行 mov r0, #42,然后 bx lr 返回。
  • 该代码用于返回 42 作为函数的返回值。
3.3. 革新指令缓存
  1. __flush_icache_range((unsigned long)mem, (unsigned long)mem + sizeof(code));
复制代码

  • ARM 处置惩罚器有独立的数据缓存和指令缓存。
  • memcpy 仅更新数据缓存,因此须要革新指令缓存确保 CPU 看到最新指令。
  • __flush_icache_range 通过 __builtin___clear_cache 或 mcr p15 指令革新缓存。
3.4. 实行代码
  1. func_t func = (func_t)mem;
  2. int result = func();
复制代码

  • mem 被转换为函数指针。
  • 通过 func() 调用动态天生的代码。
3.5. 开释内存
  1. munmap(mem, page_size);
复制代码

  • 利用 munmap 开释 mmap 分配的内存,克制内存走漏。
4. 指令缓存革新机制

4.1. __flush_icache_range 作用


  • 由于 memcpy 只影响数据缓存,而 CPU 实行指令依靠指令缓存,因此须要革新。
  • 在 ARM 32 位架构上,通常通过 mcr 指令(p15, 0, c7, c5, 0)来无效化 I-cache。
  • __builtin___clear_cache 是 GCC 提供的跨平台缓存革新方法。
4.2. ARM 处置惩罚器的缓存同等性标题


  • 当代 ARM 处置惩罚器利用 Harvard 架构,数据和指令缓存独立。
  • 必须显式革新指令缓存以确保最新指令被实行。
  • 处置惩罚器大概会重排序操纵,因此须要 dsb(数据同步屏蔽)和 isb(指令同步屏蔽)。
5. 实用场景


  • JIT 编译器: 运行时天生代码,进步性能
  • 二进制重写: 在应用步调运行时修改其代码。
  • 安全研究: 比方代码注入、ROP 攻击分析等。
6. 结论


  • 本文先容了 ARM 32 位架构下动态天生并实行代码的方法。
  • 关键步调包罗 mmap 分配可实行内存、memcpy 复制代码、革新指令缓存并实行。
  • 实用于 JIT、补丁、二进制重写等高级应用。
通过以上方法,可以在 ARM 32 位环境下高效、安全地实举措态代码注入。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
继续阅读请点击广告
回复

使用道具 举报

×
登录参与点评抽奖,加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表