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 b87e243dc41bc1972ec1d819ab1aba7907b5890b
parent 7821b701696cd858df9b95561a51631bab117fe1
Author: Tizian Leonhardt <tizianleonhardt@web.de>
Date:   Sat, 23 Jan 2021 20:02:03 +0100

Re-merge comparison

Diffstat:
Mmem_forensics/memcheck-gdb.py | 72+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 69 insertions(+), 3 deletions(-)

diff --git a/mem_forensics/memcheck-gdb.py b/mem_forensics/memcheck-gdb.py @@ -623,8 +623,76 @@ class RkCheckFunctions(gdb.Command): self.fill_altinstr_dict() self.fill_paravirt_dict() + for symbol in self.s.iter_symbols(): + if symbol.entry["st_info"]["type"] == "STT_FUNC": + name = symbol.name + size = symbol.entry["st_size"] + value = symbol.entry["st_value"] + else: + continue + + if name is None or ".cold." in name or ".part." in name or ".constprop." in name: + continue + + self.compare_function(name, size, value) + def compare_function(self, name, size, value): - print("nop") + addr = self.get_v_addr(name) + + if addr is None: + print(f"could not retrieve virtual address address for symbol `{name}`") + return None + + # read in live bytes from start address of the function + 5B (to offset the call to __fentry__) + live_bytes = gdb.execute(f"xbfunc {addr} {size}", to_string=True).split() + objdump = subprocess.check_output(f"objdump -z --disassemble={name} {file_g}", shell=True).split(b"\n")[:-1] + + start = None + for i, s in enumerate(objdump): + if name in s.decode(sys.stdout.encoding): + start = i + break + + objdump = objdump[start+1:] + + end = None + for i, s in enumerate(objdump): + if b'' == s: + end = i + break + + if end is not None: + objdump = objdump[:end] + + # exclude_objdump = [] + # for i, s in enumerate(objdump): + # bytes_start = s.decode(sys.stdout.encoding).find(':') + # if b"<" in s and b">" in s or b"0x" in s or b"ffffff" in s[bytes_start:]: + # exclude_objdump.append(i) + + # exclude_live_bytes = [] + # for i in exclude_objdump: + # bytes = objdump[i].split(b"\t")[1] + # bytes = bytes.strip().split(b" ") + # for j in range(len(bytes)): + # exclude_live_bytes.append(i + j) + + # objdump = [elf_byte for i, elf_byte in enumerate(objdump) if i not in exclude_objdump] + objdump = [line.split(b"\t") for line in objdump] + + # live_bytes = [live_byte for i, live_byte in enumerate(live_bytes) if i not in exclude_live_bytes] + live_bytes = "".join(live_bytes) + + elf_bytes = [line[1].decode(sys.stdout.encoding).strip().replace(' ', '') for line in objdump] + elf_bytes = "".join(elf_bytes) + + int3_chain = ''.join('c' * len(live_bytes)) + if live_bytes == int3_chain: + return None + + if live_bytes != elf_bytes: + print(f"function `{name} compromised, live bytes not equal to ELF bytes") + print(f"expected: {elf_bytes}, live: {live_bytes}") def get_v_addr(self, symbol): try: @@ -713,6 +781,4 @@ class RkCheckFunctions(gdb.Command): i = i + paravirt_patch_site_sz - print(self.paravirt_dict) - RkCheckFunctions()