aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--cmake/FileEmbed.cmake12
-rw-r--r--src/CMakeLists.txt8
-rw-r--r--src/cli/commands.c33
-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
-rw-r--r--src/proc.c71
-rw-r--r--src/proc.h8
-rw-r--r--src/steam.c154
-rw-r--r--src/steam.h2
-rw-r--r--src/threading/CMakeLists.txt2
22 files changed, 1198 insertions, 107 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 51ef549..524f1cb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.12)
+cmake_minimum_required(VERSION 3.14)
if(CMAKE_POLICY_DEFAULT_CMP0017 OR CMAKE_POLICY_DEFAULT_CMP0020)
# touch these to remove warnings
diff --git a/cmake/FileEmbed.cmake b/cmake/FileEmbed.cmake
new file mode 100644
index 0000000..27e963e
--- /dev/null
+++ b/cmake/FileEmbed.cmake
@@ -0,0 +1,12 @@
+get_filename_component(bin_name ${bin_in} NAME)
+string(REGEX REPLACE "\\.| |-" "_" bin_name ${bin_name})
+
+set(c_out ${bin_name}.c)
+set(h_out ${bin_name}.h)
+
+file(READ ${bin_in} filedata HEX)
+
+string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," filedata ${filedata})
+
+file(WRITE ${c_out} "#include <stdlib.h>\nconst unsigned char ${bin_name}[] = {${filedata}};\nconst size_t ${bin_name}_size = sizeof(${bin_name});\n")
+file(WRITE ${h_out} "extern const char ${bin_name}[];\nextern const size_t ${bin_name}_size;\n")
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f3d8a13..0dda750 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -23,12 +23,19 @@ list(APPEND
${CMAKE_CURRENT_SOURCE_DIR}/fs.h
${CMAKE_CURRENT_SOURCE_DIR}/net.c
${CMAKE_CURRENT_SOURCE_DIR}/net.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/proc.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/proc.h
${CMAKE_CURRENT_SOURCE_DIR}/steam.c
${CMAKE_CURRENT_SOURCE_DIR}/steam.h
${CMAKE_CURRENT_SOURCE_DIR}/toast.c
${CMAKE_CURRENT_SOURCE_DIR}/toast.h
)
+if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ add_compile_definitions(HAS_HOOKS)
+ add_subdirectory(hook)
+endif()
+
add_library(tvn STATIC ${CORE_SOURCES})
target_compile_options(tvn PUBLIC ${CFLAGS})
@@ -39,6 +46,7 @@ target_link_libraries(tvn LINK_PUBLIC ${LIBCURL_LIBRARIES})
target_link_libraries(tvn LINK_PUBLIC ${JSONC_LIBRARIES})
target_link_libraries(tvn LINK_PUBLIC md5)
target_link_libraries(tvn LINK_PUBLIC vdf)
+target_link_libraries(tvn LINK_PUBLIC hook)
if (WIN32)
target_link_libraries(tvn LINK_PUBLIC shlwapi)
diff --git a/src/cli/commands.c b/src/cli/commands.c
index 08b7ed4..7146eb4 100644
--- a/src/cli/commands.c
+++ b/src/cli/commands.c
@@ -4,15 +4,23 @@
#include "steam.h"
#include "toast.h"
+#include "proc.h"
#include "commands.h"
#include "updater.h"
+#ifdef HAS_HOOKS
+#include "hook.h"
+#endif
+
#define ARRAY_LEN(arr) sizeof(arr) / sizeof(arr[0])
static int install(int, char**);
static int update(int, char**);
static int run(int, char**);
+#ifdef HAS_HOOKS
+static int hook(int, char**);
+#endif
static int version(int, char**);
static int info(int, char**);
@@ -22,6 +30,9 @@ const struct Command commands[] = {
{ .name = "install", .func = install, .description = "Install OpenFortress"},
{ .name = "update", .func = update, .description = "Update an existing install"},
{ .name = "run", .func = run, .description = "Run OpenFortress"},
+#ifdef HAS_HOOKS
+ { .name = "hook", .func = hook, .description = "Hook into OpenFortress to fix things"},
+#endif
{ .name = "version", .func = version, .description = "Display the OFCL version"},
{ .name = "info", .func = info, .description = "Show info about the current setup"},
};
@@ -210,17 +221,17 @@ static int run(int c, char** v)
if (!strcmp(v[arg_index]+2, "direct"))
{
-
+
launch_func = runOpenFortressDirect;
}
else if (!strcmp(v[arg_index]+2, "naive"))
{
-
+
launch_func = runOpenFortressNaive;
}
else if (!strcmp(v[arg_index]+2, "steam"))
{
-
+
launch_func = runOpenFortressSteam;
}
else
@@ -264,6 +275,22 @@ static int run(int c, char** v)
return exit_val;
}
+#ifdef HAS_HOOKS
+static int hook(int c, char** v)
+{
+ if (getPid("hl2_linux") == -1)
+ {
+ //puts("OpenFortress is not running");
+ //return 1;
+ }
+
+ //puts("trying to fix Sys_LoadLibary");
+ fix_SysLoadLibary();
+
+ return 0;
+}
+#endif
+
static int version(int c, char** v)
{
puts(VERSION);
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");
+}
diff --git a/src/proc.c b/src/proc.c
new file mode 100644
index 0000000..2d74a1f
--- /dev/null
+++ b/src/proc.c
@@ -0,0 +1,71 @@
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <stdio.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#include <tlhelp32.h>
+#endif
+
+#include "proc.h"
+
+pid_t getPid(const char* process_name)
+{
+#if defined(__linux__) || defined(__FreeBSD__)
+
+#ifdef __FreeBSD__
+ // on FreeBSD /proc is not mounted by default
+ if (!isDir("/proc"))
+ return -1;
+#endif
+
+ pid_t pid;
+ char buf[PATH_MAX];
+ struct dirent* ent;
+ DIR* proc = opendir("/proc");
+ FILE* stat;
+
+ if (proc)
+ {
+ while ((ent = readdir(proc)) != NULL)
+ {
+ long lpid = atol(ent->d_name);
+ if (!lpid) continue;
+
+ snprintf(buf, sizeof(buf), "/proc/%ld/stat", lpid);
+ stat = fopen(buf, "r");
+
+ if (stat && (fscanf(stat, "%i (%[^)])", &pid, buf)) == 2)
+ {
+ if (!strcmp(buf, process_name))
+ {
+ fclose(stat);
+ closedir(proc);
+ return pid;
+ }
+ fclose(stat);
+ }
+ }
+
+ closedir(proc);
+ }
+
+#elif _WIN32
+ HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ PROCESSENTRY32 pe32 = {0};
+ pe32.dwSize = sizeof(PROCESSENTRY32);
+ Process32First(hSnap,&pe32);
+
+ while(Process32Next(hSnap,&pe32))
+ {
+ if (!strcmp(pe32.szExeFile, process_name))
+ return (long)pe32.th32ProcessID;
+ }
+#else
+ #error No Implementation
+#endif
+ return -1;
+}
diff --git a/src/proc.h b/src/proc.h
new file mode 100644
index 0000000..5990117
--- /dev/null
+++ b/src/proc.h
@@ -0,0 +1,8 @@
+#ifndef PROC_H
+#define PROC_H
+
+#include <sys/types.h>
+
+pid_t getPid(const char*);
+
+#endif \ No newline at end of file
diff --git a/src/steam.c b/src/steam.c
index 77542e4..6bcf11a 100644
--- a/src/steam.c
+++ b/src/steam.c
@@ -1,16 +1,15 @@
#include <stdlib.h>
#include <string.h>
#include <limits.h>
-#include <unistd.h>
-#include <dirent.h>
#include <stdio.h>
+#include <unistd.h>
#include "vdf.h"
+#include "proc.h"
#include "steam.h"
-#ifdef _WIN32
-#include <windows.h>
-#include <tlhelp32.h>
+#ifdef HAS_HOOKS
+#include "hook.h"
#endif
/**
@@ -181,122 +180,75 @@ char* getSourceSDK2013MpDir(void)
* function to fetch the PID of a running Steam process.
* If none were found returns -1
*/
-long getSteamPID(void)
+pid_t getSteamPID(void)
{
-#if defined(__linux__) || defined(__FreeBSD__)
-
-#ifdef __FreeBSD__
- // on FreeBSD /proc is not mounted by default
- if (!isDir("/proc"))
- return -1;
-#endif
-
- long pid;
- char buf[PATH_MAX];
- struct dirent* ent;
- DIR* proc = opendir("/proc");
- FILE* stat;
-
- if (proc)
- {
- while ((ent = readdir(proc)) != NULL)
- {
- long lpid = atol(ent->d_name);
- if (!lpid) continue;
-
- snprintf(buf, sizeof(buf), "/proc/%ld/stat", lpid);
- stat = fopen(buf, "r");
-
- if (stat && (fscanf(stat, "%li (%[^)])", &pid, buf)) == 2)
- {
- if (!strcmp(buf, STEAM_PROC))
- {
- fclose(stat);
- closedir(proc);
- return pid;
- }
- fclose(stat);
- }
- }
-
- closedir(proc);
- }
-
-#elif _WIN32
- HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
- PROCESSENTRY32 pe32 = {0};
- pe32.dwSize = sizeof(PROCESSENTRY32);
- Process32First(hSnap,&pe32);
-
- while(Process32Next(hSnap,&pe32))
- {
- if (!strcmp(pe32.szExeFile, STEAM_PROC))
- return (long)pe32.th32ProcessID;
- }
-#else
- #error No Implementation
-#endif
- return -1;
+ return getPid(STEAM_PROC);
}
int runOpenFortressDirect(char** args, size_t arg_count)
{
- int in_fork = 0;
-#if defined(__linux__) || defined(__FreeBSD__)
- // fork so we don't have to stay alive for the game
- if (fork()) return 0;
- in_fork = 1;
-#endif
- char* game = getSourceSDK2013MpDir();
- if (!game)
- {
- if (in_fork) exit(0);
- else return 0;
- }
+ pid_t pid;
- char* of_dir = getOpenFortressDir();
- if (!of_dir)
+ if ((pid = fork()))
{
- free(game);
- if (in_fork) exit(0);
- else return 0;
+ // parent
+#ifdef HAS_HOOKS
+ //fix_SysLoadLibary(pid);
+#endif
+ return 0;
}
+ else
+ {
+ // child
+ char* game = getSourceSDK2013MpDir();
+ if (!game)
+ {
+ exit(1);
+ }
- game = realloc(game, strlen(game) + strlen(OS_PATH_SEP) + strlen(HL2_EXE) + 1);
- strcat(game, OS_PATH_SEP);
- strcat(game, HL2_EXE);
+ char* of_dir = getOpenFortressDir();
+ if (!of_dir)
+ {
+ free(game);
+ exit(1);
+ }
+
+ game = realloc(game, strlen(game) + strlen(OS_PATH_SEP) + strlen(HL2_EXE) + 1);
+ strcat(game, OS_PATH_SEP);
+ strcat(game, HL2_EXE);
#if defined(__linux__) || defined(__FreeBSD__)
- // we need to be in the steam environment to get the right locales
- setenv("SteamEnv", "1", 1);
+ // we need to be in the steam environment to get the right locales
+ setenv("SteamEnv", "1", 1);
#endif
- char** argv = malloc(sizeof(char*) * (arg_count + 6));
+ char** argv = malloc(sizeof(char*) * (arg_count + 6));
#ifdef _WIN32
- size_t of_dir_len = strlen(of_dir);
- of_dir = realloc(of_dir, of_dir_len + 3);
- memmove(of_dir+1, of_dir, of_dir_len);
- of_dir[0] = '"';
- of_dir[of_dir_len+1] = '"';
- of_dir[of_dir_len+2] = '\0';
+ size_t of_dir_len = strlen(of_dir);
+ of_dir = realloc(of_dir, of_dir_len + 3);
+ memmove(of_dir+1, of_dir, of_dir_len);
+ of_dir[0] = '"';
+ of_dir[of_dir_len+1] = '"';
+ of_dir[of_dir_len+2] = '\0';
#endif
- argv[0] = game;
- argv[1] = "-game";
- argv[2] = of_dir;
- argv[3] = "-secure";
- argv[4] = "-steam";
- for (size_t i = 0; i < arg_count; ++i)
- argv[5+i] = args[i];
- argv[5+arg_count] = NULL;
+ argv[0] = game;
+ argv[1] = "-game";
+ argv[2] = of_dir;
+ argv[3] = "-secure";
+ argv[4] = "-steam";
+ for (size_t i = 0; i < arg_count; ++i)
+ argv[5+i] = args[i];
+ argv[5+arg_count] = NULL;
- execv(game, argv);
+ execv(game, argv);
- free(game);
- free(of_dir);
+ free(game);
+ free(of_dir);
- exit(0);
+ exit(0);
+ }
}
int runOpenFortressNaive(char** args, size_t arg_count)
diff --git a/src/steam.h b/src/steam.h
index 27345a9..8fa7a0f 100644
--- a/src/steam.h
+++ b/src/steam.h
@@ -55,7 +55,7 @@ char* getSourcemodDir(void);
char* getOpenFortressDir(void);
char* getAppInstallDir(const char* appid);
char* getSourceSDK2013MpDir(void);
-long getSteamPID(void);
+pid_t getSteamPID(void);
int runOpenFortressDirect(char**, size_t);
int runOpenFortressNaive(char**, size_t);
diff --git a/src/threading/CMakeLists.txt b/src/threading/CMakeLists.txt
index b2bd203..cb0c20d 100644
--- a/src/threading/CMakeLists.txt
+++ b/src/threading/CMakeLists.txt
@@ -2,7 +2,7 @@ set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
list(APPEND
- THREADING_SOURCES
+ THREADING_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/cpu.c
${CMAKE_CURRENT_SOURCE_DIR}/cpu.h
${CMAKE_CURRENT_SOURCE_DIR}/pool.c