文章目录
- 一、准备 mmap 函数的参数
- 二、mmap 函数远程调用
一、准备 mmap 函数的参数
上一篇博客 【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 远程调用 目标进程中 libc.so 动态库中的 mmap 函数 一 | mmap 函数简介 ) 中介绍了 mmap 函数 ;
mmap 函数的函数原型如下 :
代码语言:javascript复制<sys/mman.h>
void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);
int munmap(void* start,size_t length);
mmap 函数参数含义 :
void* start
: 如果为 0 就是让系统自动分配 , 如果不为 0 , 则由用户指定分配的地址 ;size_t length
: 申请分配内存的大小 ;int prot
: 内存保护标志 , 如PROT_READ | PROT_WRITE | PROT_EXEC
, 表示 可读 | 可写 | 可执行 ;int flags
: 映射对象类型标志位标志位 , 如MAP_ANONYMOUS | MAP_PRIVATE
, 表示 匿名 | 私有 ;int fd
: 文件描述符 ; 没有设置为 0 ;off_t offset
: 被映射对象的起点偏移量 , 一般设置 0 ;
将 mmap 的参数放到 parameters
数组中 , 之后要将该地址传递给远程进程的 ESP 寄存器 , 用于指定
long parameters[10];
/* 下面是远程调用 mmap 函数分配栈内存信息 */
/* call mmap 调用 mmap 函数传入的参数 */
parameters[0] = 0; // addr 地址让系统分配 , 也可以指定内存地址
parameters[1] = 0x4000; // size 分配的内存大小 0x4000 字节 , 也就是 16KB , mmap 函数的参数胡
parameters[2] = PROT_READ | PROT_WRITE | PROT_EXEC; // prot 可读 | 可写 | 可执行
parameters[3] = MAP_ANONYMOUS | MAP_PRIVATE; // flags 匿名 | 私有
parameters[4] = 0; //fd 文件描述符
parameters[5] = 0; //offset 偏移量
二、mmap 函数远程调用
由于远程调用涉及到寄存器的操作 , 因此 arm 架构 与 x86 架构的 远程调用是不同的 , 本次开发的是 x86 架构下的远程调用 ;
首先 , 将 mmap 函数执行的参数 , 写出到远程进程的内存中 , 调用 ptrace_writedata
方法 , 写出内存数据 ;
/* 设置 ESP 栈指针寄存器 */
regs->esp -= (num_params) * sizeof(long);
/* 将 long* params 参数写出到 pid 对应的远程进程中 , 然后将写出后数据的首地址 ,
设置到 pid_t pid 进程号对应的远程进程的 ESP 寄存器中 ,
设置的数据长度 4 字节 */
ptrace_writedata(pid, (uint8_t*)(void*)regs->esp, (uint8_t*)params, (num_params) * sizeof(long));
此外还要在栈中设置一个 0 地址 , 为了保证远程进程执行完毕后 , 自动访问 0 地址 , 导致崩溃 , 这样调试程序就可以收回控制权 ; 参考 【Android 逆向】Android 进程注入工具开发 ( EIP 寄存器指向 dlopen 函数 | ESP 寄存器指向栈内存 | 调试程序收回目标进程控制权 ) 博客 ;
代码语言:javascript复制 /* 设置一个 0 地址 */
long tmp_addr = 0x00;
/* 设置 0 地址的作用是 保证 远程进程 访问该 0 地址 导致崩溃 , 调试工具收回进程控制权 */
regs->esp -= sizeof(long);
ptrace_writedata(pid, (uint8_t*)(regs->esp), (uint8_t*)&tmp_addr, sizeof(tmp_addr));
然后 , 设置 远程进程 的 EIP 寄存器 , 指定执行哪个函数 , 这个 函数地址 是在 【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 获取 远程 目标进程 中的 /system/lib/libc.so 动态库中的 mmap 函数地址 ) 博客中获取的 mmap 函数地址 ;
代码语言:javascript复制 /* 设置 EIP 寄存器值 , 存储 CPU 下一条将要执行的指令 */
regs->eip = addr;
/* 设置 pid 远程进程的寄存器值 */
if (ptrace_setregs(pid, regs) == -1
|| ptrace_continue(pid) == -1) {
printf("errorn");
return -1;
}
最后 , 调用 ptrace_continue
方法 , 执行该 mmap 函数 ;
ptrace_continue(pid)
mmap 函数远程调用 完整代码 :
代码语言:javascript复制#elif defined(__i386__)
long ptrace_call(pid_t pid, uint32_t addr, long* params, uint32_t num_params, struct user_regs_struct* regs)
{
/* 参数说明 : */
if (num_params > 0 && (params != NULL)) {
/* 设置 ESP 栈指针寄存器 */
regs->esp -= (num_params) * sizeof(long);
/* 将 long* params 参数写出到 pid 对应的远程进程中 , 然后将写出后数据的首地址 ,
设置到 pid_t pid 进程号对应的远程进程的 ESP 寄存器中 ,
设置的数据长度 4 字节 */
ptrace_writedata(pid, (uint8_t*)(void*)regs->esp, (uint8_t*)params, (num_params) * sizeof(long));
}
/* 设置一个 0 地址 */
long tmp_addr = 0x00;
/* 设置 0 地址的作用是 保证 远程进程 访问该 0 地址 导致崩溃 , 调试工具收回进程控制权 */
regs->esp -= sizeof(long);
ptrace_writedata(pid, (uint8_t*)(regs->esp), (uint8_t*)&tmp_addr, sizeof(tmp_addr));
/* 设置 EIP 寄存器值 , 存储 CPU 下一条将要执行的指令 */
regs->eip = addr;
/* 设置 pid 远程进程的寄存器值 */
if (ptrace_setregs(pid, regs) == -1
|| ptrace_continue(pid) == -1) {
printf("errorn");
return -1;
}
/* 等待远程调用执行完毕 */
int stat = 0;
waitpid(pid, &stat, WUNTRACED);
while (stat != 0xb7f) {
if (ptrace_continue(pid) == -1) {
printf("errorn");
return -1;
}
waitpid(pid, &stat, WUNTRACED);
}
return 0;
}