首页
社区
课程
招聘
[原创] 基于文件内部指针拦截文件读写
2024-2-20 10:23 14440

[原创] 基于文件内部指针拦截文件读写

2024-2-20 10:23
14440

基于文件内部指针拦截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读取的是一个字节 我们事先读取了一整行 接下去的那么多字节长度的次数内 都是我们已经判断过的字符串 所以不需要再进行判断, 在指定次数内 不再进入判断逻辑
  • 这样一来 当遇到注入的内存段 文件指针跳转到下一行 当没有注入内存段 文件指针回移 不影响其运行
  • 下面提供代码以进行测试
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 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内存段
  • 因为每一行都额外增加了读取操作 会比较影响性能
  • 这里提供的思路不仅仅是读取

[培训]内核驱动高级班,冲击BAT一流互联网大厂工 作,每周日13:00-18:00直播授课

最后于 2024-2-20 10:28 被肉蚌葱鸡编辑 ,原因: 内容编辑
收藏
点赞4
打赏
分享
最新回复 (4)
雪    币: 20
活跃值: (638)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
肉蚌葱鸡 2024-2-21 13:11
2
0
使用seccomp进行拦截svc似乎会导致一些问题 这似乎和在信号处理程序里面再次调用svc有关系
雪    币: 62
活跃值: (572)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
万里星河 2024-2-27 22:36
3
0
肉蚌葱鸡 使用seccomp进行拦截svc似乎会导致一些问题 这似乎和在信号处理程序里面再次调用svc有关系[em_5]
所以需要做个标记以过滤
雪    币: 20
活跃值: (638)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
肉蚌葱鸡 2024-2-28 10:01
4
0
万里星河 所以需要做个标记以过滤
好像是的 死循环是因为系统调用没有增加判断标识
雪    币: 3730
活跃值: (3972)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caolinkai 2024-3-9 13:59
5
0
感谢分享
游客
登录 | 注册 方可回帖
返回