嘘~ 正在从服务器偷取页面 . . .

基于内部指针拦截


基于文件内部指针拦截maps读写

  • 目前想拦截maps中的加载记录最好的方式就是进行io重定向 但是进行重定向需要处理的函数太多了 还需要防止app通过fd反查文件路径是否是maps
  • 这里提供一个思路 我在app内实现确实可行-基于文件内部指针
  • 有一个弊端是会影响效率
  • 并且不是比较通用
  • 提供一个思路 并不是很有效的解决方案

  1. 首先知道 在int fd = syscall(__NR_openat, AT_FDCWD, "/proc/self/maps", O_RDONLY);打开一个文件的情况下 文件内部的指针 是在文件的开始 等待读取
  2. 这个时候 调用syscall(__NR_read, fd, &byte, 1)将会读取一个字节到byte中 内部指针往后移动一位 下次调用循环往复 直到读取到文件结尾

  • 那么我们就可以拦截文件的读取read在每次传递进来的fd中 事先读取一整行 判断是否有我们的模块加载记录信息, 当存在我们的加载记录 则直接返回 因为我们主动调用了read文件内部指针往后移到了下一行 那么这行记录将不会被app读取到,当不存在 我们把文件内部指针往回移动读取的字节长度 并且设置一个计数器因为每次调用read读取的是一个字节 我们事先读取了一整行 接下去的那么多字节长度的次数内 都是我们已经判断过的字符串 所以不需要再进行判断, 在指定次数内 不再进入判断逻辑
  • 这样一来 当遇到注入的内存段 文件指针跳转到下一行 当没有注入内存段 文件指针回移 不影响其运行
  • 下面提供代码以进行测试
    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的加载记录
    #define BUF_SIZE 1024
    
    static 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;
    }
  • 我们只需要对readfd额外套一层函数调用即可
  • bytesRead = syscall(__NR_read, checkFd(fd), &byte, 1)
  • 那么再次运行将不会读取到libart.so内存段
  • 因为每一行都额外增加了读取操作 会比较影响性能
  • 这里提供的思路不仅仅是读取

文章作者: 林木木
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 林木木 !
评论
  目录