aboutsummaryrefslogtreecommitdiff
path: root/src/hook
diff options
context:
space:
mode:
authorJan200101 <sentrycraft123@gmail.com>2023-01-22 02:56:48 +0100
committerJan200101 <sentrycraft123@gmail.com>2023-08-05 22:15:10 +0200
commitb97db529be365851633a6cc1c9285d930209049d (patch)
tree7a73d6adf71797b9308692a03253d15d3703b5a8 /src/hook
parent045e16665a55e2b7b6dc2e953c91f2125f61e083 (diff)
downloadOFQT-b97db529be365851633a6cc1c9285d930209049d.tar.gz
OFQT-b97db529be365851633a6cc1c9285d930209049d.zip
hook stash: a1af9ba65d57be898e079a98229845f42069c1e6hook
Diffstat (limited to 'src/hook')
-rw-r--r--src/hook/CMakeLists.txt22
-rw-r--r--src/hook/arch.c42
-rw-r--r--src/hook/arch.h9
-rw-r--r--src/hook/hook.c46
-rw-r--r--src/hook/hook.h10
-rw-r--r--src/hook/inject.c412
-rw-r--r--src/hook/inject.h10
-rw-r--r--src/hook/memory.c115
-rw-r--r--src/hook/memory.h13
-rw-r--r--src/hook/module.c179
-rw-r--r--src/hook/module.h20
-rw-r--r--src/hook/payloads/CMakeLists.txt36
-rw-r--r--src/hook/payloads/SysLoadLibrary.c99
13 files changed, 1013 insertions, 0 deletions
diff --git a/src/hook/CMakeLists.txt b/src/hook/CMakeLists.txt
new file mode 100644
index 0000000..79a7186
--- /dev/null
+++ b/src/hook/CMakeLists.txt
@@ -0,0 +1,22 @@
+
+# get all modules first
+
+list(APPEND
+ HOOK_SOURCES
+ ${CMAKE_CURRENT_SOURCE_DIR}/arch.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/arch.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hook.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/hook.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/inject.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/inject.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/memory.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/memory.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/module.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/module.h
+)
+add_subdirectory(payloads)
+
+add_library(hook STATIC ${HOOK_SOURCES})
+target_compile_options(hook PUBLIC ${CFLAGS})
+target_include_directories(hook PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+target_include_directories(hook PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
diff --git a/src/hook/arch.c b/src/hook/arch.c
new file mode 100644
index 0000000..19c37e9
--- /dev/null
+++ b/src/hook/arch.c
@@ -0,0 +1,42 @@
+#include <stdio.h>
+#include <limits.h>
+#include <sys/types.h>
+
+#include "arch.h"
+
+unsigned char getProcessBits(pid_t pid)
+{
+ char exe_path[PATH_MAX];
+ snprintf(exe_path, sizeof(exe_path), "/proc/%i/exe", pid);
+
+ return getElfBits(exe_path);
+}
+
+unsigned char getElfBits(const char* path)
+{
+ if (!path)
+ return 0;
+
+ FILE* fd = fopen(path, "rb");
+ if (!fd)
+ return 0;
+
+ char indent[5];
+ fread(indent, sizeof(*indent), sizeof(indent), fd);
+ fclose(fd);
+
+ if (indent[0] != 0x7f)
+ return 0;
+
+ if (indent[1] != 'E' ||
+ indent[2] != 'L' ||
+ indent[3] != 'F')
+ return 0;
+
+ if (indent[4] == 1)
+ return 32;
+ else if (indent[4] == 2)
+ return 64;
+
+ return 0;
+} \ No newline at end of file
diff --git a/src/hook/arch.h b/src/hook/arch.h
new file mode 100644
index 0000000..8e81ad8
--- /dev/null
+++ b/src/hook/arch.h
@@ -0,0 +1,9 @@
+#ifndef ARCH_H
+#define ARCH_H
+
+#include <sys/types.h>
+
+unsigned char getProcessBits(pid_t pid);
+unsigned char getElfBits(const char* path);
+
+#endif \ No newline at end of file
diff --git a/src/hook/hook.c b/src/hook/hook.c
new file mode 100644
index 0000000..b677a79
--- /dev/null
+++ b/src/hook/hook.c
@@ -0,0 +1,46 @@
+#include <stdio.h>
+#include <sys/syscall.h>
+#include <sys/mman.h>
+#include <string.h>
+
+#include "hook.h"
+#include "inject.h"
+#include "memory.h"
+#include "module.h"
+
+#include "payloads/libSysLoadLibrary_so.h"
+
+// defined in tvn:proc.c
+extern pid_t getPid(const char*);
+
+static void writeToDisk(const char* path, const char* content, const size_t size)
+{
+ FILE* fd = fopen(path, "wb");
+ fwrite(content, sizeof(*content), size, fd);
+ fclose(fd);
+}
+
+int fix_SysLoadLibary()
+{
+ pid_t pid = getPid("loop_forever");
+ printf("%i\n", pid);
+ if (pid != -1)
+ {
+ char* path = "/tmp/SysLoadLibrary.so";
+
+ fprintf(stderr, "[~] writing library to disk\n");
+ writeToDisk(path, libSysLoadLibrary_so, libSysLoadLibrary_so_size);
+
+ //inject_syscall(pid, 1, (void*)21, NULL, NULL, NULL, NULL, NULL);
+
+ fprintf(stderr, "[~] loading library into process\n");
+ int ret = load_library(pid, path);
+ if (!ret)
+ fprintf(stderr, "[*] Success\n");
+ else if (ret == 1)
+ fprintf(stderr, "[!] library already loaded\n");
+ else
+ fprintf(stderr, "[!] could not load libary\n");
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/src/hook/hook.h b/src/hook/hook.h
new file mode 100644
index 0000000..f31cdfd
--- /dev/null
+++ b/src/hook/hook.h
@@ -0,0 +1,10 @@
+#ifndef HOOK_H
+#define HOOK_H
+
+#ifndef HAS_HOOKS
+#error hooks have not been enabled
+#endif
+
+int fix_SysLoadLibary();
+
+#endif \ No newline at end of file
diff --git a/src/hook/inject.c b/src/hook/inject.c
new file mode 100644
index 0000000..34c078c
--- /dev/null
+++ b/src/hook/inject.c
@@ -0,0 +1,412 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+#include <sys/ptrace.h>
+#include <sys/mman.h>
+#include <dlfcn.h>
+#include <unistd.h>
+#include <elf.h>
+
+#include "inject.h"
+#include "memory.h"
+#include "module.h"
+#include "arch.h"
+
+#define Elf64W(type) Elf64_ ## type
+#define Elf32W(type) Elf32_ ## type
+
+#define Elf64Ehdr Elf64W(Ehdr)
+#define Elf32Ehdr Elf32W(Ehdr)
+
+#define Elf64Shdr Elf64W(Shdr)
+#define Elf32Shdr Elf32W(Shdr)
+
+#define Elf64Sym Elf64W(Sym)
+#define Elf32Sym Elf32W(Sym)
+
+static uintptr_t getSymbolOffset(const char* elf_path, const char* symbol_name)
+{
+ unsigned char bits = getElfBits(elf_path);
+
+ FILE* fd = fopen(elf_path, "rb");
+ fseek(fd, 0, SEEK_END);
+ size_t elf_size = (size_t) ftell(fd);
+ rewind(fd);
+
+ char* elf_body = malloc(elf_size);
+ fread(elf_body, 1, elf_size, fd);
+ fclose(fd);
+
+ if (bits == 64)
+ {
+ Elf64Ehdr* header = (Elf64Ehdr*)elf_body;
+
+ Elf64Shdr* section = (Elf64Shdr*)(elf_body + header->e_shoff);
+ Elf64Shdr* symtab_section = NULL;
+ for (uintptr_t i = 0; i <= header->e_shnum; i++)
+ {
+ if (i == header->e_shnum)
+ return 0;
+
+ if (section[i].sh_type == SHT_SYMTAB)
+ {
+ symtab_section = section+i;
+ break;
+ }
+ }
+
+ Elf64Sym* symtab = (Elf64Sym*)(elf_body + symtab_section->sh_offset);
+ size_t symbol_num = symtab_section->sh_size / symtab_section->sh_entsize;
+ char *symbol_names = (char *)(elf_body + section[symtab_section->sh_link].sh_offset);
+
+ for (size_t j = 0; j < symbol_num; ++j)
+ {
+ char* name = symbol_names + symtab[j].st_name;
+ size_t symbol_name_len = strlen(symbol_name);
+ if (strncmp(name, symbol_name, symbol_name_len))
+ continue;
+ if (name[symbol_name_len] != '\0' && name[symbol_name_len] != '@')
+ continue;
+
+ if (symtab[j].st_value > 0)
+ {
+ uintptr_t value = symtab[j].st_value;
+ free(elf_body);
+ return value;
+ }
+ }
+ }
+ else if (bits == 32)
+ {
+ Elf32Ehdr* header = (Elf32Ehdr*)elf_body;
+
+ Elf32Shdr* section = (Elf32Shdr*)(elf_body + header->e_shoff);
+ Elf32Shdr* symtab_section = NULL;
+ for (uintptr_t i = 0; i <= header->e_shnum; i++)
+ {
+ if (i == header->e_shnum)
+ return 0;
+
+ if (section[i].sh_type == SHT_SYMTAB)
+ {
+ symtab_section = section+i;
+ break;
+ }
+ }
+
+ Elf32Sym* symtab = (Elf32Sym*)(elf_body + symtab_section->sh_offset);
+ size_t symbol_num = symtab_section->sh_size / symtab_section->sh_entsize;
+ char *symbol_names = (char *)(elf_body + section[symtab_section->sh_link].sh_offset);
+
+ for (size_t j = 0; j < symbol_num; ++j)
+ {
+ char* name = symbol_names + symtab[j].st_name;
+ size_t symbol_name_len = strlen(symbol_name);
+ if (strncmp(name, symbol_name, symbol_name_len))
+ continue;
+ if (name[symbol_name_len] != '\0' && name[symbol_name_len] != '@')
+ continue;
+
+ if (symtab[j].st_value > 0)
+ {
+ uintptr_t value = symtab[j].st_value;
+ free(elf_body);
+ return value;
+ }
+ }
+ }
+
+ free(elf_body);
+
+ return 0;
+}
+
+void* inject_syscall(
+ pid_t pid,
+ uintptr_t syscall_n,
+ void* arg0,
+ void* arg1,
+ void* arg2,
+ void* arg3,
+ void* arg4,
+ void* arg5
+){
+ void* ret = (void*)-1;
+ int status;
+ struct user_regs_struct old_regs, regs;
+ void* injection_addr = (void*)-1;
+
+ //This buffer is our payload, which will run a syscall properly on x86/x64
+ unsigned char injection_buf[] =
+ {
+ 0xff, 0xff, // placerholder
+ /* these nops are here because
+ * we're going to write memory using
+ * ptrace, and it always writes the size
+ * of a word, which means we have to make
+ * sure the buffer is long enough
+ */
+ 0x90, //nop
+ 0x90, //nop
+ 0x90, //nop
+ 0x90, //nop
+ 0x90, //nop
+ 0x90 //nop
+ };
+
+ unsigned char bits = getProcessBits(pid);
+ if (bits == 64)
+ {
+ //syscall
+ injection_buf[0] = 0x0f;
+ injection_buf[1] = 0x05;
+ }
+ else if (bits == 32)
+ {
+ //int80 (syscall)
+ injection_buf[0] = 0xcd;
+ injection_buf[1] = 0x80;
+ }
+ else
+ {
+ return NULL;
+ }
+
+ //As ptrace will always write a uintptr_t, let's make sure we're using proper buffers
+ uintptr_t old_data;
+ uintptr_t injection_buffer;
+ memcpy(&injection_buffer, injection_buf, sizeof(injection_buffer));
+
+ //Attach to process using 'PTRACE_ATTACH'
+ ptrace(PTRACE_ATTACH, pid, NULL, NULL);
+ wait(&status);
+
+ /* Get the current registers using 'PTRACE_GETREGS' so that
+ * we can restore the execution later
+ * and also modify the bytes of EIP/RIP
+ */
+
+ ptrace(PTRACE_GETREGS, pid, NULL, &old_regs);
+ regs = old_regs;
+
+ //Now, let's set up the registers that will be injected into the tracee
+
+#if defined(__i386__)
+ regs.eax = (uintptr_t)syscall_n;
+ regs.ebx = (uintptr_t)arg0;
+ regs.ecx = (uintptr_t)arg1;
+ regs.edx = (uintptr_t)arg2;
+ regs.esi = (uintptr_t)arg3;
+ regs.edi = (uintptr_t)arg4;
+ regs.ebp = (uintptr_t)arg5;
+ injection_addr = (void*)regs.eip;
+#elif defined(__x86_64__)
+ if (bits == 64)
+ {
+ regs.rax = (uintptr_t)syscall_n;
+ regs.rdi = (uintptr_t)arg0;
+ regs.rsi = (uintptr_t)arg1;
+ regs.rdx = (uintptr_t)arg2;
+ regs.r10 = (uintptr_t)arg3;
+ regs.r8 = (uintptr_t)arg4;
+ regs.r9 = (uintptr_t)arg5;
+ injection_addr = (void*)regs.rip;
+ }
+ else if (bits == 32)
+ {
+ regs.rax = (uintptr_t)syscall_n;
+ regs.rbx = (uintptr_t)arg0;
+ regs.rcx = (uintptr_t)arg1;
+ regs.rdx = (uintptr_t)arg2;
+ regs.rsi = (uintptr_t)arg3;
+ regs.rdi = (uintptr_t)arg4;
+ regs.rbp = (uintptr_t)arg5;
+ injection_addr = (void*)regs.rip;
+ }
+#endif
+
+ //Let's store the buffer at EIP/RIP that we're going to modify into 'old_data' using 'PTRACE_PEEKDATA'
+ old_data = (uintptr_t)ptrace(PTRACE_PEEKDATA, pid, injection_addr, NULL);
+
+ //Let's write our payload into the EIP/RIP of the target process using 'PTRACE_POKEDATA'
+ ptrace(PTRACE_POKEDATA, pid, injection_addr, injection_buffer);
+
+ //Let's inject our modified registers into the target process using 'PTRACE_SETREGS'
+ ptrace(PTRACE_SETREGS, pid, NULL, &regs);
+
+ //Let's run a single step in the target process (execute one assembly instruction)
+ ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL);
+ waitpid(pid, &status, WSTOPPED); //Wait for the instruction to run
+
+ //Let's get the registers after the syscall to store the return value
+ ptrace(PTRACE_GETREGS, pid, NULL, &regs);
+#if defined(__i386__)
+ ret = (void*)regs.eax;
+#elif defined(__x86_64__)
+ ret = (void*)regs.rax;
+#endif
+
+ long long ret_int = (long long)ret;
+
+ if (ret_int < 0)
+ fprintf(stderr, "syscall error: %s\n", strerror((int)-ret_int));
+
+ //Let's write the old data at EIP/RIP
+ ptrace(PTRACE_POKEDATA, pid, (void*)injection_addr, old_data);
+
+ //Let's restore the old registers to continue the normal execution
+ ptrace(PTRACE_SETREGS, pid, NULL, &old_regs);
+ ptrace(PTRACE_DETACH, pid, NULL, NULL); //Detach and continue the execution
+
+ return ret;
+}
+
+
+/**
+ * Return values:
+ * 1 already loaded
+ * 2 arch error
+ */
+int load_library(pid_t pid, char* lib_path)
+{
+ /* Let's get the address of the 'libc_dlopen_mode' of the target process
+ * and store it on 'dlopen_ex' by loading the LIBC of the target process
+ * on here and then getting the offset of its own '__libc_dlopen_mode'.
+ * Then we sum this offset to the base of the external LIBC module
+ */
+ struct module_s lib_mod = getModule(pid, lib_path);
+ if (lib_mod.size)
+ return 1;
+
+ struct module_s libc_ex = getModule(pid, "/libc.so");
+ uintptr_t offset = getSymbolOffset(libc_ex.path, "__libc_dlopen_mode");
+
+ // fallback
+ if (!offset)
+ offset = getSymbolOffset(libc_ex.path, "dlopen");
+
+ fprintf(stderr, "%li\n", offset);
+
+ //Get the external '__libc_dlopen_mode' by summing the offset to the libc_ex.base
+ void* dlopen_ex = (void*)((uintptr_t)libc_ex.base + offset);
+
+ freeModule(&libc_ex);
+
+ //--- Now let's go to the injection part
+
+ int status;
+ struct user_regs_struct old_regs, regs;
+ unsigned char inj_buf_x64[] =
+ {
+ /* On 'x64', we dont have to pass anything to the stack, as we're only
+ * using 2 parameters, which will be stored on RDI (library path address) and
+ * RSI (flags, in this case RTLD_LAZY).
+ * This means we just have to call the __libc_dlopen_mode function, which
+ * will be on RAX.
+ */
+
+ 0xFF, 0xD0, //call rax
+ 0xCC, //int3 (SIGTRAP)
+ };
+
+ unsigned char inj_buf_x86[] =
+ {
+ /* We have to pass the parameters to the stack (in reversed order)
+ * The register 'ebx' will store the library path address and the
+ * register 'ecx' will store the flag (RTLD_LAZY)
+ * After pushing the parameters to the stack, we will call EAX, which
+ * will store the address of '__libc_dlopen_mode'
+ */
+ 0x51, //push ecx
+ 0x53, //push ebx
+ 0xFF, 0xD0, //call eax
+ 0xCC, //int3 (SIGTRAP)
+ };
+
+ unsigned char* inj_buf = NULL;
+ size_t sizeof_inj_buf = 0;
+
+ unsigned char bits = getProcessBits(pid);
+ if (bits == 64)
+ {
+ inj_buf = inj_buf_x64;
+ sizeof_inj_buf = sizeof(inj_buf_x64);
+ }
+ else if (bits == 32)
+ {
+ inj_buf = inj_buf_x86;
+ sizeof_inj_buf = sizeof(inj_buf_x86);
+ }
+ else
+ {
+ fprintf(stderr, "Could not figure out what injection buffer to use\n");
+ return 2;
+ }
+
+ //Let's allocate memory for the payload and the library path
+ size_t lib_path_len = strlen(lib_path) + 1;
+ size_t inj_size = sizeof_inj_buf + lib_path_len;
+ void* inj_addr = allocate_memory(pid, inj_size, PROT_EXEC | PROT_READ | PROT_WRITE);
+ void* path_addr = (void*)((uintptr_t)inj_addr + sizeof_inj_buf);
+
+ //Write the memory to our allocated address
+ write_memory(pid, inj_addr, inj_buf, sizeof_inj_buf);
+ write_memory(pid, path_addr, (void*)lib_path, lib_path_len);
+
+ //Attach to the target process
+ ptrace(PTRACE_ATTACH, pid, NULL, NULL);
+ wait(&status);
+
+ //Get the current registers to restore later
+ ptrace(PTRACE_GETREGS, pid, NULL, &old_regs);
+ regs = old_regs;
+
+ //Let's setup the registers according to our payload
+# if defined(__i386__)
+ regs.eax = (long)dlopen_ex;
+ regs.ebx = (long)path_addr;
+ regs.ecx = (long)RTLD_LAZY;
+ regs.eip = (long)inj_addr; //The execution will continue from 'inj_addr' (EIP)
+# elif defined(__x86_64__)
+ if (bits == 64)
+ {
+ regs.rax = (uintptr_t)dlopen_ex;
+ regs.rdi = (uintptr_t)path_addr;
+ regs.rsi = (uintptr_t)RTLD_LAZY;
+ regs.rip = (uintptr_t)inj_addr; //The execution will continue from 'inj_addr' (RIP)
+ }
+ else if (bits == 32)
+ {
+ regs.rax = (uintptr_t)dlopen_ex;
+ regs.rbx = (uintptr_t)path_addr;
+ regs.rcx = (uintptr_t)RTLD_LAZY;
+ regs.rip = (uintptr_t)inj_addr; //The execution will continue from 'inj_addr' (RIP)
+ }
+# endif
+
+ //Inject the modified registers to the target process
+ ptrace(PTRACE_SETREGS, pid, NULL, &regs);
+
+ //Continue the execution
+ ptrace(PTRACE_CONT, pid, NULL, NULL);
+
+ //Wait for the int3 (SIGTRAP) breakpoint
+ waitpid(pid, &status, WSTOPPED);
+
+ //Set back the old registers
+ ptrace(PTRACE_SETREGS, pid, NULL, &old_regs);
+
+ //Detach from the process and continue the execution
+ ptrace(PTRACE_DETACH, pid, NULL, NULL);
+
+ //Deallocate the memory we allocated for the injection buffer and the library path
+ deallocate_memory(pid, inj_addr, inj_size);
+
+ return 0;
+}
+
+
+
diff --git a/src/hook/inject.h b/src/hook/inject.h
new file mode 100644
index 0000000..e82c445
--- /dev/null
+++ b/src/hook/inject.h
@@ -0,0 +1,10 @@
+#ifndef INJECT_H
+#define INJECT_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+void* inject_syscall(pid_t pid, uintptr_t syscall_n, void*, void*, void*, void*, void*, void*);
+int load_library(pid_t pid, char* lib_path);
+
+#endif \ No newline at end of file
diff --git a/src/hook/memory.c b/src/hook/memory.c
new file mode 100644
index 0000000..eedf728
--- /dev/null
+++ b/src/hook/memory.c
@@ -0,0 +1,115 @@
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/uio.h>
+#include <sys/syscall.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+#include "memory.h"
+#include "inject.h"
+#include "arch.h"
+
+#define mmap_x64 9
+#define munmap_x64 11
+#define mmap2_x86 192
+#define munmap_x86 91
+
+void read_memory(pid_t pid, void* src, void* dst, size_t size)
+{
+ /*
+ pid = target process id
+ src = address to read from on the target process
+ dst = address to write to on the caller process
+ size = size of the buffer that will be read
+ */
+
+ struct iovec iosrc;
+ struct iovec iodst;
+ iodst.iov_base = dst;
+ iodst.iov_len = size;
+ iosrc.iov_base = src;
+ iosrc.iov_len = size;
+
+ if (process_vm_readv(pid, &iodst, 1, &iosrc, 1, 0) == -1)
+ fprintf(stderr, "process_vm_readv: %s\n", strerror(errno));
+}
+
+void write_memory(pid_t pid, void* dst, void* src, size_t size)
+{
+ /*
+ pid = target process id
+ dst = address to write to on the target process
+ src = address to read from on the caller process
+ size = size of the buffer that will be read
+ */
+
+ struct iovec iosrc;
+ struct iovec iodst;
+ iosrc.iov_base = src;
+ iosrc.iov_len = size;
+ iodst.iov_base = dst;
+ iodst.iov_len = size;
+
+ if(process_vm_writev(pid, &iosrc, 1, &iodst, 1, 0) == -1)
+ fprintf(stderr, "process_vm_writev: %s\n", strerror(errno));
+}
+
+void* allocate_memory(pid_t pid, size_t size, int protection)
+{
+ //mmap template:
+ //void *mmap (void *__addr, size_t __len, int __prot, int __flags, int __fd, __off_t __offset);
+
+ void* ret = (void*)-1;
+
+ unsigned char bits = getProcessBits(pid);
+
+ if (bits == 32)
+ {
+ ret = inject_syscall(
+ pid,
+ mmap2_x86,
+ //arguments
+ (void*)0,
+ (void*)size,
+ (void*)(uintptr_t)protection,
+ (void*)(MAP_ANON | MAP_PRIVATE),
+ (void*)-1,
+ (void*)0
+ );
+ }
+ else if (bits == 64)
+ {
+ ret = inject_syscall(
+ pid,
+ mmap_x64,
+ //arguments
+ (void*)0,
+ (void*)size,
+ (void*)(uintptr_t)protection,
+ (void*)(MAP_ANON | MAP_PRIVATE),
+ (void*)-1,
+ (void*)0
+ );
+ }
+
+ return ret;
+}
+
+void deallocate_memory(pid_t pid, void* src, size_t size)
+{
+ unsigned char bits = getProcessBits(pid);
+ if (bits == 64)
+ inject_syscall(pid, munmap_x64, src, (void*)size, NULL, NULL, NULL, NULL);
+ else if (bits == 32)
+ inject_syscall(pid, munmap_x86, src, (void*)size, NULL, NULL, NULL, NULL);
+}
+
+void* protect_memory(pid_t pid, void* src, size_t size, int protection)
+{
+ //mprotect template
+ //int mprotect (void *__addr, size_t __len, int __prot);
+ return inject_syscall(pid, __NR_mprotect, src, (void*)size, (void*)(uintptr_t)protection, NULL, NULL, NULL);
+}
diff --git a/src/hook/memory.h b/src/hook/memory.h
new file mode 100644
index 0000000..cf1f74c
--- /dev/null
+++ b/src/hook/memory.h
@@ -0,0 +1,13 @@
+#ifndef MEMORY_H
+#define MEMORY_H
+
+#include <sys/types.h>
+
+void read_memory(pid_t pid, void* src, void* dst, size_t size);
+void write_memory(pid_t pid, void* dst, void* src, size_t size);
+
+void* allocate_memory(pid_t pid, size_t size, int protection);
+void deallocate_memory(pid_t pid, void* src, size_t size);
+void* protect_memory(pid_t pid, void* src, size_t size, int protection);
+
+#endif \ No newline at end of file
diff --git a/src/hook/module.c b/src/hook/module.c
new file mode 100644
index 0000000..41be1ee
--- /dev/null
+++ b/src/hook/module.c
@@ -0,0 +1,179 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include "module.h"
+#include "arch.h"
+
+#define fprintf(...)
+
+#define NOTFOUND (size_t)(-1)
+#define PROCMAPS_LINE_MAX_LENGTH (PATH_MAX + 100)
+
+static void* strtoptr(pid_t pid, const char* nptr, char** endptr, int base)
+{
+ unsigned char bits = getProcessBits(pid);
+ if (bits == 64)
+ return (void*)strtoull(nptr, endptr, base);
+ else if (bits == 32)
+ return (void*)strtoul(nptr, endptr, base);
+
+ return NULL;
+
+}
+static size_t find(const char* a, const char* b, uintptr_t offset)
+{
+ const char* pos = a + offset;
+
+ while (*pos && strncmp(pos, b, strlen(b)))
+ ++pos;
+
+ if (!*pos)
+ return NOTFOUND;
+
+ return (size_t)(pos - a);
+}
+
+static size_t rfind(const char* a, const char* b, size_t offset)
+{
+ const char* pos = a + (strlen(a) - strlen(b) - offset);
+
+ while (a <= pos && strncmp(pos, b, strlen(b)))
+ --pos;
+
+ if (pos < a)
+ return NOTFOUND;
+
+ return (size_t)(pos - a);
+}
+
+static char* substr(const char* str, size_t pos, size_t len)
+{
+ str = str + pos;
+
+ if (len == NOTFOUND)
+ len = strlen(str);
+
+ char* buf = malloc(len+1);
+ strncpy(buf, str, len);
+ buf[len] = '\0';
+
+ return buf;
+}
+
+struct module_s getModule(pid_t pid, const char* module_name)
+{
+ struct module_s mod = {0};
+
+ char maps_file_path[PATH_MAX];
+ snprintf(maps_file_path, sizeof(maps_file_path), "/proc/%i/maps", pid);
+ fprintf(stderr, "Maps file path: %s\n", maps_file_path);
+
+
+ FILE* maps_file_fs = fopen(maps_file_path, "rb");
+ if (!maps_file_fs) return mod;
+
+ char maps_file[PROCMAPS_LINE_MAX_LENGTH];
+ while( !feof(maps_file_fs) ){
+ if (fgets(maps_file, sizeof(maps_file), maps_file_fs) == NULL){
+ fprintf(stderr,"fgets failed, %s\n",strerror(errno));
+ return mod;
+ }
+ size_t module_path_pos = 0;
+ size_t module_path_end = 0;
+
+ //Get the first slash in the line of the module name
+ module_path_pos = find(maps_file, module_name, 0);
+ if (module_path_pos == NOTFOUND)
+ continue;
+
+ module_path_pos = find(maps_file, "/", 0);
+
+ //Get the end of the line of the module name
+ module_path_end = find(maps_file, "\n", module_path_pos);
+
+ if(module_path_pos == NOTFOUND || module_path_end == NOTFOUND) continue;
+
+ //Module path substring
+ char* module_path_str = substr(maps_file, module_path_pos, module_path_end - module_path_pos);
+
+ fprintf(stderr, "Module path string: %s\n", module_path_str);
+
+ //--- Module name
+
+ char* module_name_str = substr(module_path_str,
+ rfind(module_path_str, "/", 0) + 1, //Substring from the last '/' to the end of the string
+ NOTFOUND
+ );
+
+ fprintf(stderr, "Module name: %s\n", module_name_str);
+
+ //--- Base Address
+
+ size_t base_address_pos = rfind(maps_file, "\n", module_path_pos) + 1;
+ size_t base_address_end = find(maps_file, "-", base_address_pos);
+ if(base_address_pos == NOTFOUND || base_address_end == NOTFOUND) continue;
+ char* base_address_str = substr(maps_file, base_address_pos, base_address_end - base_address_pos);
+ void* base_address = (void*)strtoptr(pid, base_address_str, NULL, 16);;
+ if (!base_address) return mod;
+
+ fprintf(stderr, "Base Address: %p\n", base_address);
+
+ //--- End Address
+ size_t end_address_pos;
+ size_t end_address_end;
+ char* end_address_str;
+ void* end_address;
+
+ //Get end address pos
+ end_address_pos = rfind(maps_file, module_path_str, 0);
+ end_address_pos = rfind(maps_file, "\n", end_address_pos) + 1;
+ end_address_pos = find(maps_file, "-", end_address_pos) + 1;
+
+ //Find first space from end_address_pos
+ end_address_end = find(maps_file, " ", end_address_pos);
+
+ if(end_address_pos == NOTFOUND || end_address_end == NOTFOUND) continue;
+
+ //End address substring
+ end_address_str = substr(maps_file, end_address_pos, end_address_end - end_address_pos);
+ end_address = (void*)strtoptr(pid, end_address_str, NULL, 16);
+ free(end_address_str);
+
+ fprintf(stderr, "End Address: %p\n", end_address);
+
+ //--- Module size
+
+ uintptr_t module_size = (uintptr_t)end_address - (uintptr_t)base_address;
+ fprintf(stderr, "End Address: %li\n", module_size);
+
+ mod.name = module_name_str;
+ mod.path = module_path_str;
+ mod.base = base_address;
+ mod.size = module_size;
+ mod.end = end_address;
+
+ break;
+ }
+
+ //--- Module Path
+
+
+ //---
+
+ //Now we put all the information we got into the mod structure
+
+
+ fclose(maps_file_fs);
+
+ return mod;
+}
+
+void freeModule(struct module_s* mod)
+{
+ free(mod->name);
+ free(mod->path);
+}
diff --git a/src/hook/module.h b/src/hook/module.h
new file mode 100644
index 0000000..7fb83e1
--- /dev/null
+++ b/src/hook/module.h
@@ -0,0 +1,20 @@
+#ifndef MODULE_H
+#define MODULE_H
+
+#include <sys/types.h>
+#include <stdint.h>
+
+struct module_s
+{
+ char* name;
+ char* path;
+ void* base;
+ void* end;
+ uintptr_t size;
+ void* handle; //this will not be used for now, only internally with dlopen
+};
+
+struct module_s getModule(pid_t pid, const char* module_name);
+void freeModule(struct module_s* mod);
+
+#endif \ No newline at end of file
diff --git a/src/hook/payloads/CMakeLists.txt b/src/hook/payloads/CMakeLists.txt
new file mode 100644
index 0000000..fe3968e
--- /dev/null
+++ b/src/hook/payloads/CMakeLists.txt
@@ -0,0 +1,36 @@
+
+list(APPEND
+ modules
+ SysLoadLibrary
+)
+
+foreach(module ${modules})
+ set(module_name "${module}")
+ add_library(${module} SHARED "${module}.c")
+ # OF is 32 bit, so we need to be too
+ set_target_properties(${module} PROPERTIES COMPILE_OPTIONS "-m32" LINK_FLAGS "-m32")
+
+
+ list(APPEND
+ module_embed_output
+ ${CMAKE_CURRENT_BINARY_DIR}/lib${module_name}_so.c
+ ${CMAKE_CURRENT_BINARY_DIR}/lib${module_name}_so.h
+ )
+ # embed
+ add_custom_command(
+ OUTPUT ${module_embed_output}
+ COMMAND ${CMAKE_COMMAND}
+ "-Dbin_in=$<TARGET_FILE:${module}>"
+ -P ${CMAKE_SOURCE_DIR}/cmake/FileEmbed.cmake
+ DEPENDS ${module}
+ )
+ add_library(${module_name}_embed OBJECT ${module_embed_output})
+ list(APPEND
+ HOOK_SOURCES
+ $<TARGET_OBJECTS:${module_name}_embed>
+ )
+
+ set(module_embed_output "")
+endforeach()
+
+set(HOOK_SOURCES ${HOOK_SOURCES} PARENT_SCOPE)
diff --git a/src/hook/payloads/SysLoadLibrary.c b/src/hook/payloads/SysLoadLibrary.c
new file mode 100644
index 0000000..314426d
--- /dev/null
+++ b/src/hook/payloads/SysLoadLibrary.c
@@ -0,0 +1,99 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <dlfcn.h>
+
+#define _DEBUG 1
+#define Q_IsAbsolutePath V_IsAbsolutePath
+#define Assert(f) assert(f)
+#define CommandLine CommandLine_Tier0
+#define Msg printf
+#define V_strcpy_safe strcpy
+#define Q_snprintf snprintf
+#define _getcwd getcwd
+
+typedef void* HMODULE;
+typedef int Sys_Flags;
+typedef void* CSysModule;
+
+static bool (*V_IsAbsolutePath)(const char *pPath) = NULL;
+static HMODULE (*Sys_LoadLibrary)(const char *pLibraryName, Sys_Flags flags) = NULL;
+static char* (*CommandLine__ParmValue)(const char* param) = NULL;
+
+CSysModule *Sys_LoadModule_replacement( const char *pModuleName, Sys_Flags flags /* = SYS_NOFLAGS (0) */ )
+{
+ // If using the Steam filesystem, either the DLL must be a minimum footprint
+ // file in the depot (MFP) or a filesystem GetLocalCopy() call must be made
+ // prior to the call to this routine.
+ char szCwd[1024];
+ HMODULE hDLL = NULL;
+
+ if ( !Q_IsAbsolutePath( pModuleName ) )
+ {
+ char szAbsoluteModuleName[1024];
+
+ // check if the sourcemod provides the library
+ const char *pGameDir = CommandLine__ParmValue("-game");
+ if ( pGameDir )
+ {
+ V_strcpy_safe( szCwd, pGameDir );
+ if (szCwd[strlen(szCwd) - 1] == '/' || szCwd[strlen(szCwd) - 1] == '\\' )
+ {
+ szCwd[strlen(szCwd) - 1] = 0;
+ }
+
+ Q_snprintf( szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s/bin/%s", szCwd, pModuleName );
+
+ hDLL = Sys_LoadLibrary( szAbsoluteModuleName, flags );
+ }
+
+ // if the lib was not in the mod check the base game
+ if (!hDLL)
+ {
+ // full path wasn't passed in, using the current working dir
+ Assert( _getcwd( szCwd, sizeof( szCwd ) ) );
+
+ if (szCwd[strlen(szCwd) - 1] == '/' || szCwd[strlen(szCwd) - 1] == '\\' )
+ {
+ szCwd[strlen(szCwd) - 1] = 0;
+ }
+
+ size_t cCwd = strlen( szCwd );
+ if ( strstr( pModuleName, "bin/") == pModuleName || ( szCwd[ cCwd - 1 ] == 'n' && szCwd[ cCwd - 2 ] == 'i' && szCwd[ cCwd - 3 ] == 'b' ) )
+ {
+ // don't make bin/bin path
+ Q_snprintf( szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s/%s", szCwd, pModuleName );
+ }
+ else
+ {
+ Q_snprintf( szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s/bin/%s", szCwd, pModuleName );
+ }
+ hDLL = Sys_LoadLibrary( szAbsoluteModuleName, flags );
+ }
+ }
+
+ if ( !hDLL )
+ {
+ // full path failed, let LoadLibrary() try to search the PATH now
+ hDLL = Sys_LoadLibrary( pModuleName, flags );
+#if defined( _DEBUG )
+ if ( !hDLL )
+ {
+ // So you can see what the error is in the debugger...
+ Msg( "Failed to load %s: %s\n", pModuleName, dlerror() );
+ }
+#endif // DEBUG
+ }
+
+ return hDLL;
+}
+
+
+void __attribute__((constructor)) lib_entry()
+{
+ //It prints "Injected!" once the library gets loaded.
+ fprintf(stderr, "Injected!\n");
+}