基于文件内部指针拦截maps读写
- 目前想拦截
maps中的加载记录最好的方式就是进行io重定向 但是进行重定向需要处理的函数太多了 还需要防止app通过fd反查文件路径是否是maps - 这里提供一个思路 我在
app内实现确实可行-基于文件内部指针 - 有一个弊端是会影响效率
- 并且不是比较通用
- 提供一个思路 并不是很有效的解决方案
- 首先知道 在
int fd = syscall(__NR_openat, AT_FDCWD, "/proc/self/maps", O_RDONLY);打开一个文件的情况下 文件内部的指针 是在文件的开始 等待读取 - 这个时候 调用
syscall(__NR_read, fd, &byte, 1)将会读取一个字节到byte中 内部指针往后移动一位 下次调用循环往复 直到读取到文件结尾
- 那么我们就可以拦截文件的读取
read在每次传递进来的fd中 事先读取一整行 判断是否有我们的模块加载记录信息, 当存在我们的加载记录 则直接返回 因为我们主动调用了read文件内部指针往后移到了下一行 那么这行记录将不会被app读取到,当不存在 我们把文件内部指针往回移动读取的字节长度 并且设置一个计数器因为每次调用read读取的是一个字节 我们事先读取了一整行 接下去的那么多字节长度的次数内 都是我们已经判断过的字符串 所以不需要再进行判断, 在指定次数内 不再进入判断逻辑 - 这样一来 当遇到注入的内存段 文件指针跳转到下一行 当没有注入内存段 文件指针回移 不影响其运行
- 下面提供代码以进行测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | LOGE("开始读取maps");int fd = syscall(__NR_openat, AT_FDCWD, "/proc/self/maps", O_RDONLY); // 使用系统调用打开文件if (fd == -1) { LOGE("Failed to open maps file");}char buf[BUF_SIZE];char byte;int bytesRead;int i = 0;while ((bytesRead = syscall(__NR_read, fd, &byte, 1)) > 0) { // 逐字节读取文件内容 buf[i++] = byte; if (byte == '\n') { buf[i] = '\0'; // 在行末添加字符串终止符 LOGE("%s", buf); i = 0; // 重置缓冲区索引 }}if (bytesRead == -1) { LOGE("Error while reading file"); close(fd);}close(fd); |
- 上面的代码读取maps的每一行 进行输出 下面尝试拦截libart.so的加载记录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #define BUF_SIZE 1024static int count = 0;int checkFd(int fd) { if (count == 0) { char buf[BUF_SIZE] = {0}; char byte; int i = 0; while (syscall(__NR_read, fd, &byte, 1) > 0) { // 逐字节读取文件内容 buf[i++] = byte; if (byte == '\n') { buf[i] = '\0'; // 在行末添加字符串终止符 if (strstr(buf, "libart.so")) { // 读取到指定内容 字节返回fd return fd; } else { // 回移文件指针 off_t current_pos = lseek(fd, 0, SEEK_CUR); syscall(__NR_lseek, fd, current_pos - i, SEEK_SET); count = i; return fd; } } } } count--; return fd;} |
- 我们只需要对
read的fd额外套一层函数调用即可 bytesRead = syscall(__NR_read, checkFd(fd), &byte, 1)- 那么再次运行将不会读取到
libart.so内存段 - 因为每一行都额外增加了读取操作 会比较影响性能
- 这里提供的思路不仅仅是读取