马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
ARM 32 位架构动态注入代码技能文档
1. 配景概述
在某些环境下,我们须要在运行时动态地天生并实行代码,比方 JIT(Just-In-Time Compilation)技能、运行时补丁或二进制重写。本文先容了一种在 ARM 32 位架构下,通过 mmap 分配可实行内存,注入汇编指令,并革新指令缓存以确保代码准确实行的方法。
2. 代码实现
以下代码示例展示了如安在 ARM 32 位架构下动态注入一段汇编代码并实行它。- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/mman.h>
- #include <unistd.h>
- #include <string.h>
- void __flush_icache_range(unsigned long start, unsigned long end);
- typedef int (*func_t)(void);
- int main() {
- // 1. 分配一块可执行内存
- size_t page_size = sysconf(_SC_PAGESIZE);
- void *mem = mmap(NULL, page_size, PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- if (mem == MAP_FAILED) {
- perror("mmap");
- return 1;
- }
- // 2. ARM 32 位汇编指令 (mov r0, #42; bx lr)
- unsigned char code[] = {
- 0x2A, 0x00, 0xA0, 0xE3, // mov r0, #42
- 0x1E, 0xFF, 0x2F, 0xE1 // bx lr
- };
- // 3. 复制代码到分配的内存
- memcpy(mem, code, sizeof(code));
- // 4. 刷新指令缓存
- __flush_icache_range((unsigned long)mem, (unsigned long)mem + sizeof(code));
- // 5. 执行代码
- func_t func = (func_t)mem;
- int result = func();
- printf("JIT 生成代码返回值: %d\n", result);
- // 6. 释放内存
- munmap(mem, page_size);
- return 0;
- }
- // 7. 在内核模块中实现 __flush_icache_range
- void __flush_icache_range(unsigned long start, unsigned long end) {
- //__asm__ __volatile__(
- // "mov r3, #0\n"
- // "mcr p15, 0, r3, c7, c5, 0\n" // Invalidate I-cache
- // "dsb\n"
- // "isb\n"
- // : : "r"(start), "r"(end) : "r3"
- //);
- __builtin___clear_cache((char *)start, (char *)end);
- }
复制代码 3. 代码分析
3.1. 分配可实行内存
- size_t page_size = sysconf(_SC_PAGESIZE);
- void *mem = mmap(NULL, page_size, PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
复制代码
- mmap 用于分配一块内存,答应读、写和实行。
- MAP_ANONYMOUS 使得映射不依靠详细的文件。
- MAP_PRIVATE 确保内存地区私有。
- 如果 mmap 失败,步调打印错误并返回。
3.2. 注入 ARM 32 位汇编指令
- unsigned char code[] = {
- 0x2A, 0x00, 0xA0, 0xE3, // mov r0, #42
- 0x1E, 0xFF, 0x2F, 0xE1 // bx lr
- };
复制代码
- 这段代码实行 mov r0, #42,然后 bx lr 返回。
- 该代码用于返回 42 作为函数的返回值。
3.3. 革新指令缓存
- __flush_icache_range((unsigned long)mem, (unsigned long)mem + sizeof(code));
复制代码
- ARM 处置惩罚器有独立的数据缓存和指令缓存。
- memcpy 仅更新数据缓存,因此须要革新指令缓存确保 CPU 看到最新指令。
- __flush_icache_range 通过 __builtin___clear_cache 或 mcr p15 指令革新缓存。
3.4. 实行代码
- func_t func = (func_t)mem;
- int result = func();
复制代码
- mem 被转换为函数指针。
- 通过 func() 调用动态天生的代码。
3.5. 开释内存
- 利用 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企服之家,中国第一个企服评测及商务社交产业平台。
|