【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 远程调用 目标进程中 libc.so 动态库中的 mmap 函数 二 | 准备参数 | 远程调用 mmap 函数 )

简介: 【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 远程调用 目标进程中 libc.so 动态库中的 mmap 函数 二 | 准备参数 | 远程调用 mmap 函数 )

文章目录

一、准备 mmap 函数的参数

二、mmap 函数远程调用





一、准备 mmap 函数的参数


上一篇博客 【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 远程调用 目标进程中 libc.so 动态库中的 mmap 函数 一 | mmap 函数简介 ) 中介绍了 mmap 函数 ;


mmap 函数的函数原型如下 :


<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 寄存器指向栈内存 | 调试程序收回目标进程控制权 ) 博客 ;


/* 设置一个 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 函数地址 ;


/* 设置 EIP 寄存器值 , 存储 CPU 下一条将要执行的指令 */
  regs->eip = addr;
  /* 设置 pid 远程进程的寄存器值 */
  if (ptrace_setregs(pid, regs) == -1
  || ptrace_continue(pid) == -1) {
  printf("error\n");
  return -1;
  }


最后 , 调用 ptrace_continue 方法 , 执行该 mmap 函数 ;


ptrace_continue(pid)



mmap 函数远程调用 完整代码 :


#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("error\n");
  return -1;
  }
  /* 等待远程调用执行完毕 */
  int stat = 0;
  waitpid(pid, &stat, WUNTRACED);
  while (stat != 0xb7f) {
  if (ptrace_continue(pid) == -1) {
    printf("error\n");
    return -1;
  }
  waitpid(pid, &stat, WUNTRACED);
  }
  return 0;
}



相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
目录
相关文章
|
Linux Android开发
测试程序之提供ioctl函数应用操作GPIO适用于Linux/Android
测试程序之提供ioctl函数应用操作GPIO适用于Linux/Android
785 0
|
消息中间件 网络协议 Python
工具人逆袭!掌握Python IPC,让你的进程从此告别单打独斗
【9月更文挑战第9天】你是否曾遇到多个Python程序像孤岛般无法通信,导致数据孤立、任务难协同的问题?掌握进程间通信(IPC)技术,可助你打破这一僵局。IPC是不同进程间传递数据或信号的机制,在Python中常用的方法有管道、消息队列、共享内存及套接字等。其中,管道适用于父子或兄弟进程间简单数据传递;套接字则不仅限于本地,还能在网络间实现复杂的数据交换。通过学习IPC,你将能设计更健壮灵活的系统架构,成为真正的编程高手。
284 3
|
Java 调度 Android开发
Android经典实战之Kotlin的delay函数和Java中的Thread.sleep有什么不同?
本文介绍了 Kotlin 中的 `delay` 函数与 Java 中 `Thread.sleep` 方法的区别。两者均可暂停代码执行,但 `delay` 适用于协程,非阻塞且高效;`Thread.sleep` 则阻塞当前线程。理解这些差异有助于提高程序效率与可读性。
572 1
|
安全 Android开发 Kotlin
Android经典面试题之Kotlin中常见作用域函数
**Kotlin作用域函数概览**: `let`, `run`, `with`, `apply`, `also`. `let`安全调用并返回结果; `run`在上下文中执行代码并返回结果; `with`执行代码块,返回结果; `apply`配置对象后返回自身; `also`附加操作后返回自身
513 8
|
Android开发 Kotlin
Android面试题之kotlin中怎么限制一个函数参数的取值范围和取值类型等
在Kotlin中,限制函数参数可通过类型系统、泛型、条件检查、数据类、密封类和注解实现。例如,使用枚举限制参数为特定值,泛型约束确保参数为Number子类,条件检查如`require`确保参数在特定范围内,数据类封装可添加验证,密封类限制为一组预定义值,注解结合第三方库如Bean Validation进行校验。
634 6
|
Android开发
Android构建系统:Android.mk(2)函数详解
Android构建系统:Android.mk(2)函数详解
472 1
|
消息中间件 网络协议 Python
工具人逆袭!掌握Python IPC,让你的进程从此告别单打独斗
【8月更文挑战第3天】你是否苦恼于Python程序间的“信息孤岛”现象?进程间通信(IPC)技术能助你打破壁垒。IPC是使不同进程共享数据或信号的方法。因全局解释器锁(GIL),多进程配合IPC成为高效处理数据的选择。Python提供管道、消息队列、共享内存等多种IPC手段。例如,管道适合简单父子或兄弟进程通信;套接字不仅限于网络通信,还能实现本地进程间复杂数据交换。掌握IPC,让你的进程协同作战,构建更强大灵活的系统。
280 0
|
Android开发
Android Makefile中inherit-product函数和include的区别
Android Makefile中inherit-product函数和include的区别
532 0
|
Linux 数据库 Perl
【YashanDB 知识库】如何避免 yasdb 进程被 Linux OOM Killer 杀掉
本文来自YashanDB官网,探讨Linux系统中OOM Killer对数据库服务器的影响及解决方法。当内存接近耗尽时,OOM Killer会杀死占用最多内存的进程,这可能导致数据库主进程被误杀。为避免此问题,可采取两种方法:一是在OS层面关闭OOM Killer,通过修改`/etc/sysctl.conf`文件并重启生效;二是豁免数据库进程,由数据库实例用户借助`sudo`权限调整`oom_score_adj`值。这些措施有助于保护数据库进程免受系统内存管理机制的影响。

热门文章

最新文章