Android 逆向Android 进程注入工具开发 ( 注入代码分析 | 获取 远程 目标进程 中的 /system/lib/libc.so 动态库中的 mmap 函数地址 )
Posted 韩曙亮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 逆向Android 进程注入工具开发 ( 注入代码分析 | 获取 远程 目标进程 中的 /system/lib/libc.so 动态库中的 mmap 函数地址 )相关的知识,希望对你有一定的参考价值。
文章目录
一、获取 远程 目标进程 中的 /system/lib/libc.so 动态库中的 mmap 函数地址
获取 远程 目标进程 中的 /system/lib/libc.so 动态库中的 mmap 函数地址流程 :
① 获取 本地进程 /system/lib/libc.so 动态库 地址 ;
② 获取 远程进程 /system/lib/libc.so 动态库 地址 ;
③ 计算 本地进程 与 远程进程 的 /system/lib/libc.so 动态库 地址 偏移量 ;
④ 获取 本地进程 mmap 函数地址 ;
⑤ 根据 本地进程 mmap 函数地址 + 本地进程 与 远程进程 的 /system/lib/libc.so 动态库 地址 偏移量 , 计算出 远程进程 /system/lib/libc.so 动态库 的 mmap 函数地址 ;
二、从 /proc/pid/maps 文件中获取 指定 进程 中的 /system/lib/libc.so 动态库地址
查看 /proc/2223/maps 进程对应的内存信息 :
其中涉及到 /system/lib/libc.so
动态库的地址的行 :
b758c000-b758f000 r--p 000e6000 08:02 848 /system/lib/libc.so
首先 , 要获取到 maps 文件地址 ,
- 获取本进程的 maps 文件地址 , 直接使用
"/proc/self/maps"
字符串作为地址 ; - 获取远程进程 maps 文件地址 , 需要
"/proc/%d/maps", pid
将 pid 拼接到 “/proc/%d/maps” 字符串中 ;
char filename[32]; // maps 文件路径
/* 获取 maps 文件路径 */
if (pid < 0) {
/* self process 本进程 */
snprintf(filename, sizeof(filename), "/proc/self/maps");
}
else {
/* 远程进程 */
snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
}
然后 , 使用只读方式 , 打开文件 ;
FILE* fp; // 文件描述符
/* 打开 maps 文件 */
fp = fopen(filename, "r");
最后 , 解析文件中的内容 , 按照 b758c000-b758f000 r--p 000e6000 08:02 848 /system/lib/libc.so
格式解析即可 ;
- 逐行遍历文件 ,
fgets(line, sizeof(line), fp)
; - 读取一行之后 , 查看该行是否包含
"/system/lib/libc.so"
字符串子串 ,strstr(line, module_name)
; - 如果包含 , 则根据
-
字符 , 将其分割成字符串数组 ,pch = strtok(line, "-")
; - 该数组的第一个字符串就是地址值对应的字符串 ,
- 将字符串地址转为 int 类型地址 , 该地址就是 远程 目标进程 中的 /system/lib/libc.so 动态库地址 ;
addr = strtoul(pch, NULL, 16)
解析文件代码如下 :
if (fp != NULL) {
/* 逐行遍历 maps 文件 */
while (fgets(line, sizeof(line), fp)) {
/* 下面是数据行示例 */
/* b758c000-b758f000 r--p 000e6000 08:02 848 /system/lib/libc.so */
/* 找到查找的 module_name 行 , 如果 module_name 是 line 的子串 ,
返回 module_name 首次出现的地址 */
if (strstr(line, module_name)) {
/* 按照 - 字符 , 分割字符串 , 返回第一个字符串 */
pch = strtok(line, "-");
/* 将 "b758c000" 字符串转为 b758c000 整型 */
addr = strtoul(pch, NULL, 16);
if (addr == 0x8000)
addr = 0;
break;
}
}
/* 关闭文件 */
fclose(fp);
}
从 /proc/pid/maps 文件中获取 指定 进程 中的 /system/lib/libc.so 动态库地址代码 :
/* 从 /proc/pid/maps 文件中获取 */
void* get_module_base(pid_t pid, const char* module_name)
{
FILE* fp;
long addr = 0;
char* pch; // 字符串
char filename[32];
char line[1024];
/* 获取 maps 文件路径 */
if (pid < 0) {
/* self process 本进程 */
snprintf(filename, sizeof(filename), "/proc/self/maps");
}
else {
/* 远程进程 */
snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
}
/* 打开 maps 文件 */
fp = fopen(filename, "r");
if (fp != NULL) {
/* 逐行遍历 maps 文件 */
while (fgets(line, sizeof(line), fp)) {
/* 下面是数据行示例 */
/* b758c000-b758f000 r--p 000e6000 08:02 848 /system/lib/libc.so */
/* 找到查找的 module_name 行 , 如果 module_name 是 line 的子串 ,
返回 module_name 首次出现的地址 */
if (strstr(line, module_name)) {
/* 按照 - 字符 , 分割字符串 , 返回第一个字符串 */
pch = strtok(line, "-");
/* 将 "b758c000" 字符串转为 b758c000 整型 */
addr = strtoul(pch, NULL, 16);
if (addr == 0x8000)
addr = 0;
break;
}
}
/* 关闭文件 */
fclose(fp);
}
/* 返回指定的 module_name 动态库地址 */
return (void*)addr;
}
三、获取 本地进程 中的 /system/lib/libc.so 动态库的 mmap 函数地址
获取本地进程的函数地址 , 函数名就是函数地址 ; (void*)mmap
就是 mmap 函数对应的函数指针 ;
/* 获取 目标进程中的 /system/lib/libc.so 动态库中的 mmap 函数地址
(void*)mmap 是本进程中 mmap 函数的地址
计算出 本进程 与 远程目标进程 libc.so 的偏移量
使用本进程的 mmap 函数地址 + 偏移量 , 就可以得到目标进程 mmap 函数地址*/
mmap_addr = get_remote_addr(target_pid, libc_path, (void*)mmap);
四、获取 远程进程 中的 /system/lib/libc.so 动态库的 mmap 函数地址
分别调用 get_module_base
方法 , 获取本地进程 和 特定 PID 进程号对应的远程目标进程 的 /system/lib/libc.so
动态库 首地址 , 计算出这两个首地址之间的偏移量 (uint32_t)remote_handle - (uint32_t)local_handle
;
本进程的 mmap 函数的地址是已知的 , 直接使用 (void*)mmap
就可以获取 ;
使用 本进程的 mmap 函数地址 + 偏移量 , 就可以得到目标进程 mmap 函数地址 ;
char* ret_addr = (char*)((uint32_t)local_addr + (uint32_t)remote_handle - (uint32_t)local_handle)
完整代码示例 :
/* 获取 target_pid 进程的 module_name 动态库中的 local_addr 函数地址 */
void* get_remote_addr(pid_t target_pid, const char* module_name, void* local_addr)
{
void* local_handle, * remote_handle;
/* 获取本进程 module_name 动态库地址 */
local_handle = get_module_base(-1, module_name);
/* 获取远程目标进程 module_name 动态库地址 */
remote_handle = get_module_base(target_pid, module_name);
char* ret_addr = (char*)((uint32_t)local_addr + (uint32_t)remote_handle - (uint32_t)local_handle);
LOGW("[+] get_remote_addr[%s]: local[%p], remote[%p], ret_addr[%p], local_addr[%p]\\n", module_name, local_handle, remote_handle, ret_addr, local_addr);
#if defined(__i386__)
if (!strcmp(module_name, libc_path)) {
//ret_addr += 2;
}
#endif
return ret_addr;
}
以上是关于Android 逆向Android 进程注入工具开发 ( 注入代码分析 | 获取 远程 目标进程 中的 /system/lib/libc.so 动态库中的 mmap 函数地址 )的主要内容,如果未能解决你的问题,请参考以下文章
Android 逆向Android 进程注入工具开发 ( 编译注入工具 | 编译结果文件说明 | 注入过程说明 )
Android 逆向Android 进程注入工具开发 ( 远程调用总结 | 远程调用注意事项 )
Android 逆向Android 进程注入工具开发 ( SO 进程注入环境及 root 权限获取 | 进程注入时序分析 )
Android 逆向Android 进程注入工具开发 ( 注入代码分析 | 调试进程 ATTACH 附着目标进程 | 读取目标函数寄存器值并存档 )
Android 逆向Android 进程注入工具开发 ( 远程调用 | x86 架构的返回值获取 | arm 架构远程调用 )
Android 逆向Android 进程注入工具开发 ( 注入代码分析 | 远程调用 目标进程中 libc.so 动态库中的 mmap 函数 三 | 等待远程函数执行完毕 | 寄存器获取返回值 )(代