首页
社区
课程
招聘
[原创]Apatch内核模块之栈回溯升级版以及遇到的问题
发表于: 2025-8-9 14:50 2410

[原创]Apatch内核模块之栈回溯升级版以及遇到的问题

2025-8-9 14:50
2410

在上一篇文章https://bbs.kanxue.com/thread-287893.htm中通过 hook 了 svc 进行了监控,然后获取目标进程内存,利用 fp 寄存器实现了栈回溯。此时的栈回溯只有内存地址,还需要额外的辅助才能拿到 so 中对应的地址,在这篇文章中可以获取到 so 名称以及 so 的相对偏移。

根据 maps 文件的生成原理,可以在源码中查看到show_map_vma
e32K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4S2J5k6h3k6S2L8X3c8J5L8$3W2V1i4K6u0W2j5$3!0E0i4K6u0r3j5h3&6V1M7X3!0A6k6o6p5K6i4K6u0V1y4g2)9J5k6e0p5H3i4K6u0V1L8s2c8K6i4K6u0r3M7#2)9K6c8Y4u0W2k6Y4y4Q4x3@1c8K6K9r3!0%4i4K6g2X3L8h3q4H3i4K6g2X3N6X3#2S2i4K6t1$3j5h3#2H3i4K6y4n7M7s2u0G2K9X3g2U0N6q4)9K6c8r3k6K6

他是通过struct vm_area_struct *vma 获取到 vm_file,然后使用seq_file_path函数获取到里面的路径字符串,seq_file_path 中调用了seq_path,下面是seq_path 的源码。

从这里看出其中的字符串主要是通过d_path 来取得。

那么根据这个流程我们可以自己实现一个,大概流程如下:

具体实现如下

这里要使用到的mm_struct 和vm_area_struct 结构体在 Apatch 中提供的头文件里没有,我们可以自己编写一个头文件

这个结构体可以从源码中复制过来,要注意对应内核版本,我的手机是 5.10 内核所以用的 5.10 版本。另外,这里可以截断一部分,只需要覆盖到我们需要用的成员偏移,能让编译器找到对应偏移即可。新的效果如下:

使用该内核模块拦截到的是所有的 svc,那么栈回溯中也会回溯所有调用到的。这里发现 dmesg 打出来的日志里有很多系统自身调用 svc 生成的,会干扰到我们查看日志。
此处考虑从 task 结构体中获取 cred 结构体,在 cred 结构体中会保存进程 uid,通过过滤 uid 可以知道是否是普通 app 的进程。

但是在实现的过程中,调用了get_task_cred 获取 cred 结构就会导致内核崩溃,下面是实现源码:

还请各位大佬指点一下

271  static void
272  show_map_vma(struct seq_file *m, struct vm_area_struct *vma)
273  {
274     struct mm_struct *mm = vma->vm_mm;
275     struct file *file = vma->vm_file;
276     vm_flags_t flags = vma->vm_flags;
277     unsigned long ino = 0;
278     unsigned long long pgoff = 0;
279     unsigned long start, end;
280     dev_t dev = 0;
281     const char *name = NULL;
282 
283     if (file) {
284         struct inode *inode = file_inode(vma->vm_file);
285         dev = inode->i_sb->s_dev;
286         ino = inode->i_ino;
287         pgoff = ((loff_t)vma->vm_pgoff) << PAGE_SHIFT;
288     }
289 
290     start = vma->vm_start;
291     end = vma->vm_end;
292     show_vma_header_prefix(m, start, end, flags, pgoff, dev, ino);
293 
294     /*
295      * Print the dentry name for named mappings, and a
296      * special [heap] marker for the heap:
297      */
298     if (file) {
299         seq_pad(m, ' ');
300         seq_file_path(m, file, "\n");
301         goto done;
302     }
303 
304     if (vma->vm_ops && vma->vm_ops->name) {
305         name = vma->vm_ops->name(vma);
306         if (name)
307             goto done;
308     }
309 
310     name = arch_vma_name(vma);
311     if (!name) {
312         struct anon_vma_name *anon_name;
313 
314         if (!mm) {
315             name = "[vdso]";
316             goto done;
317         }
318 
319         if (vma->vm_start <= mm->brk &&
320             vma->vm_end >= mm->start_brk) {
321             name = "[heap]";
322             goto done;
323         }
324 
325         if (is_stack(vma)) {
326             name = "[stack]";
327             goto done;
328         }
329 
330         anon_name = anon_vma_name(vma);
331         if (anon_name) {
332             seq_pad(m, ' ');
333             seq_printf(m, "[anon:%s]", anon_name->name);
334         }
335     }
336 
337  done:
338     if (name) {
339         seq_pad(m, ' ');
340         seq_puts(m, name);
341     }
342     seq_putc(m, '\n');
343  }
271  static void
272  show_map_vma(struct seq_file *m, struct vm_area_struct *vma)
273  {
274     struct mm_struct *mm = vma->vm_mm;
275     struct file *file = vma->vm_file;
276     vm_flags_t flags = vma->vm_flags;
277     unsigned long ino = 0;
278     unsigned long long pgoff = 0;
279     unsigned long start, end;
280     dev_t dev = 0;
281     const char *name = NULL;
282 
283     if (file) {
284         struct inode *inode = file_inode(vma->vm_file);
285         dev = inode->i_sb->s_dev;
286         ino = inode->i_ino;
287         pgoff = ((loff_t)vma->vm_pgoff) << PAGE_SHIFT;
288     }
289 
290     start = vma->vm_start;
291     end = vma->vm_end;
292     show_vma_header_prefix(m, start, end, flags, pgoff, dev, ino);
293 
294     /*
295      * Print the dentry name for named mappings, and a
296      * special [heap] marker for the heap:
297      */
298     if (file) {
299         seq_pad(m, ' ');
300         seq_file_path(m, file, "\n");
301         goto done;
302     }
303 
304     if (vma->vm_ops && vma->vm_ops->name) {
305         name = vma->vm_ops->name(vma);
306         if (name)
307             goto done;
308     }
309 
310     name = arch_vma_name(vma);
311     if (!name) {
312         struct anon_vma_name *anon_name;
313 
314         if (!mm) {
315             name = "[vdso]";
316             goto done;
317         }
318 
319         if (vma->vm_start <= mm->brk &&
320             vma->vm_end >= mm->start_brk) {
321             name = "[heap]";
322             goto done;
323         }
324 
325         if (is_stack(vma)) {
326             name = "[stack]";
327             goto done;
328         }
329 
330         anon_name = anon_vma_name(vma);
331         if (anon_name) {
332             seq_pad(m, ' ');
333             seq_printf(m, "[anon:%s]", anon_name->name);
334         }
335     }
336 
337  done:
338     if (name) {
339         seq_pad(m, ' ');
340         seq_puts(m, name);
341     }
342     seq_putc(m, '\n');
343  }
459  int seq_path(struct seq_file *m, const struct path *path, const char *esc)
460  {
461     char *buf;
462     size_t size = seq_get_buf(m, &buf);
463     int res = -1;
464 
465     if (size) {
466         char *p = d_path(path, buf, size);
467         if (!IS_ERR(p)) {
468             char *end = mangle_path(buf, p, esc);
469             if (end)
470                 res = end - buf;
471         }
472     }
473     seq_commit(m, res);
474 
475     return res;
476  }
477  EXPORT_SYMBOL(seq_path);
459  int seq_path(struct seq_file *m, const struct path *path, const char *esc)
460  {
461     char *buf;
462     size_t size = seq_get_buf(m, &buf);
463     int res = -1;
464 
465     if (size) {
466         char *p = d_path(path, buf, size);
467         if (!IS_ERR(p)) {
468             char *end = mangle_path(buf, p, esc);
469             if (end)
470                 res = end - buf;
471         }
472     }
473     seq_commit(m, res);
474 
475     return res;
476  }
477  EXPORT_SYMBOL(seq_path);
task_struct->mm_struct->vm_area_struct->vm_file
d_path(vm_file)
task_struct->mm_struct->vm_area_struct->vm_file
d_path(vm_file)
typedef char *(*d_path)(const struct path *path, char *buf, int buflen);
d_path d_path_func;
 
struct mm_struct{
    struct vm_area_struct *mmap;
};
 
void show_vma(struct task_struct *task, pid_t pid, unsigned long addr){
    struct mm_struct *mm;
    struct vm_area_struct *vma;
 
    mm = get_task_mm_func(task);
    // pr_info(">>> VMA list for PID %d:\n", pid);
    for (vma = mm->mmap; vma; vma = vma->vm_next) {
        if(vma->vm_start <= addr && vma->vm_end >= addr){
            char path[256] = {0};
            if (vma->vm_file) {
                char *tmp = d_path_func(&vma->vm_file->f_path, path, sizeof(path));
                char *path = strrchr(tmp, '/');
                if(path){
                    path++;
                    pr_info("VMA: %s+0x%lx pid: %d\n",
                         path, addr - vma->vm_start, pid);
                }else{
                    pr_info("VMA: %s+0x%lx pid: %d\n",
                         tmp, addr - vma->vm_start, pid);
                }
            }
        }
    }
    mmput_func(mm);
}
 
d_path_func = (typeof(d_path))kallsyms_lookup_name("d_path");
typedef char *(*d_path)(const struct path *path, char *buf, int buflen);
d_path d_path_func;
 
struct mm_struct{
    struct vm_area_struct *mmap;
};
 
void show_vma(struct task_struct *task, pid_t pid, unsigned long addr){
    struct mm_struct *mm;
    struct vm_area_struct *vma;
 
    mm = get_task_mm_func(task);
    // pr_info(">>> VMA list for PID %d:\n", pid);
    for (vma = mm->mmap; vma; vma = vma->vm_next) {
        if(vma->vm_start <= addr && vma->vm_end >= addr){
            char path[256] = {0};
            if (vma->vm_file) {
                char *tmp = d_path_func(&vma->vm_file->f_path, path, sizeof(path));
                char *path = strrchr(tmp, '/');
                if(path){
                    path++;
                    pr_info("VMA: %s+0x%lx pid: %d\n",
                         path, addr - vma->vm_start, pid);
                }else{
                    pr_info("VMA: %s+0x%lx pid: %d\n",
                         tmp, addr - vma->vm_start, pid);
                }
            }
        }
    }
    mmput_func(mm);
}
 

[培训]科锐软件逆向54期预科班、正式班开始火爆招生报名啦!!!

收藏
免费 54
支持
分享
最新回复 (31)
雪    币: 2
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2025-8-9 17:28
0
雪    币: 160
活跃值: (1416)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2025-8-9 19:35
0
雪    币: 281
活跃值: (758)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
广西风险等级
2025-8-10 07:27
0
雪    币: 103
活跃值: (600)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
在内核空间搜索回溯就不太有效率吧,尤其是想要实现dladdr和函数符号定位。
保留基本的pc和lr就行,剩下的按照运行时so加载基址反查结合内存dump静态分析更好。毕竟很多壳都不用bl和blr,你获取的栈桢可能是很多层之前的调用入口了,中间不知道b/br了几次
2025-8-10 20:48
0
雪    币: 103
活跃值: (600)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
uid过滤的话,你可以在模块里内建一张idr表,里面插入需要监测的uid键。至于uid的获取可以参考下current_uid()宏的实现,好像需要rcu_deference保护
2025-8-10 20:54
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
7
感谢分享
2025-8-11 17:22
0
雪    币: 23
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
1
2025-8-12 09:12
0
雪    币: 1578
活跃值: (975)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
9
dadadasda uid过滤的话,你可以在模块里内建一张idr表,里面插入需要监测的uid键。至于uid的获取可以参考下current_uid()宏的实现,好像需要rcu_deference保护
OK,谢谢大佬
2025-8-12 09:37
0
雪    币: 371
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10
666
2025-8-12 17:41
0
雪    币: 1126
活跃值: (5455)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
11

..

最后于 2025-8-15 11:17 被三一米田编辑 ,原因:
2025-8-15 09:46
0
雪    币: 240
活跃值: (1930)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
我记得Apatch里提供了专门的api可以直接获取uid
2025-8-16 11:20
0
雪    币: 764
活跃值: (2662)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
1
2025-8-18 23:08
0
雪    币: 1
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
14
666
2025-8-19 09:10
0
雪    币: 589
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
15
666
2025-8-19 14:49
0
雪    币: 200
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
16
孤恒666
2025-9-2 15:20
0
雪    币: 78
活跃值: (2049)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
17
666
2025-9-4 14:36
0
雪    币: 7
活跃值: (664)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
666
2025-9-15 01:01
0
雪    币: 166
活跃值: (358)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
感谢分享
2025-9-19 17:24
0
雪    币: 105
活跃值: (1947)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
6666
2025-9-21 10:37
0
雪    币: 10
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
21
666
2025-9-23 16:14
0
雪    币: 527
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
22
66
666
2025-9-24 16:05
0
雪    币: 38
活跃值: (2594)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
优秀的!
2025-9-28 14:48
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
24
66666
2025-10-9 15:41
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
25
777777
2025-10-10 02:31
0
游客
登录 | 注册 方可回帖
返回