]> Chaos Git - misc/apocalypse.git/commitdiff
Dump this in a repo master
authorchaoskagami <chaos.kagami@gmail.com>
Wed, 24 Aug 2016 03:01:51 +0000 (23:01 -0400)
committerchaoskagami <chaos.kagami@gmail.com>
Wed, 24 Aug 2016 03:01:51 +0000 (23:01 -0400)
README.md [new file with mode: 0644]
b.sh [new file with mode: 0755]
config.c [new file with mode: 0644]
config.h [new file with mode: 0644]
gettime_speedhack.c [new file with mode: 0644]
info_window.c [new file with mode: 0644]

diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..70a6879
--- /dev/null
+++ b/README.md
@@ -0,0 +1,10 @@
+apocalypse
+------------
+
+This is a very shitty gettimeofday/clock_gettime based speedhack that works on *some* games.
+
+It's also very old and not maintained, but might serve as a good example of:
+
+ * How to hook functions via LD_PRELOAD
+
+ * How NOT to document code properly
diff --git a/b.sh b/b.sh
new file mode 100755 (executable)
index 0000000..1b0a29e
--- /dev/null
+++ b/b.sh
@@ -0,0 +1,3 @@
+gcc -ldl -m64 -fPIC -shared `pkg-config --cflags --libs sdl2` -lGL -o apocalypse64.so gettime_speedhack.c info_window.c config.c
+gcc -ldl -m32 -fPIC -shared `pkg-config --cflags --libs sdl2` -lGL -o apocalypse32.so gettime_speedhack.c info_window.c config.c
+cp *.so ~/.preloads/
diff --git a/config.c b/config.c
new file mode 100644 (file)
index 0000000..d742d30
--- /dev/null
+++ b/config.c
@@ -0,0 +1,126 @@
+#define DEFINED_ENABLES_HERE
+
+#include <dlfcn.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <unistd.h>
+#include <stdint.h>
+
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <time.h>
+
+#include "config.h"
+
+int ENABLE_TIME_HACKS = 0;
+int ENABLE_GETTIMEOFDAY_HOOK = 0;
+int ENABLE_CLOCK_GETTIME_HOOK = 0;
+
+// Is this Isaac: AB or RB?
+int IS_TBOI = 0;
+
+double SLOW_FACTOR = 1.0;
+
+int HAS_LOADED_CONFIG = 0;
+
+struct stat info;
+
+void read_cfg() {
+       FILE* f = fopen("apocalypse.conf", "r");
+       if (!f) {
+               // Doesn't exist, so write the example.
+               fprintf(stderr, "[HOOK] No config file found, writing one out to 'apocalypse.conf'\n");
+               f = fopen("apocalypse.conf", "w");
+               fprintf(f,
+                       "#================================\n"
+                       "# Apocalypse tool config file\n"
+                       "#================================\n\n"
+                       "# Enable time hacks. Required for slowdown\n"
+                       "# and speedup, as well.\n"
+                       "time_hacks=0\n"
+                       "# Enable gettimeofday-based time hack.\n"
+                       "gettimeofday=0\n"
+                       "# Enable clock_gettime-based time hack.\n"
+                       "clock_gettime=0\n"
+                       "# Slow factor with time hack.\n"
+                       "slow_factor=1.0\n\n"
+                       "#================================\n"
+                       "# Game-specific stuff\n"
+                       "#================================\n\n"
+                       "# Binding of isaac hooks\n"
+                       "isaac=0\n"
+               );
+               fclose(f);
+               f = fopen("apocalypse.conf", "r");
+       }
+
+       stat("apocalypse.conf", &info);
+
+       char* line = NULL;
+       size_t len = 0;
+       int read = 0;
+
+       while ((read = getline(&line, &len, f)) != -1) {
+               // Line less than three characters? Next.
+               if (strlen(line) < 3)
+                       continue;
+
+               // Line is \n? Next.
+               if (line[0] == '\n')
+                       continue;
+
+               // First character is #? Next.
+               if (line[0] == '#')
+                       continue;
+
+               char *prop, *value;
+
+               prop = line;
+
+               int i;
+               for(i=0; i < strlen(line); i++) {
+                       if (line[i] == '=') {
+                               line[i] = '\0';
+                               value = &line[i+1];
+                       }
+               }
+
+               if ( !strcmp(prop, "time_hacks") ) {
+                       sscanf(value, "%d", & ENABLE_TIME_HACKS);
+                       fprintf(stderr, "[HOOK] time_hacks: %d\n", ENABLE_CLOCK_GETTIME_HOOK);
+               }
+               else if ( !strcmp(prop, "gettimeofday") ) {
+                       sscanf(value, "%d", & ENABLE_GETTIMEOFDAY_HOOK);
+                       fprintf(stderr, "[HOOK] gettimeofday: %d\n", ENABLE_GETTIMEOFDAY_HOOK);
+               }
+               else if ( !strcmp(prop, "clock_gettime") ) {
+                       sscanf(value, "%d", & ENABLE_CLOCK_GETTIME_HOOK);
+                       fprintf(stderr, "[HOOK] clock_gettime: %d\n", ENABLE_CLOCK_GETTIME_HOOK);
+               }
+               else if ( !strcmp(prop, "slow_factor") ) {
+                       sscanf(value, "%lf", & SLOW_FACTOR);
+                       fprintf(stderr, "[HOOK] slow factor: %lf\n", SLOW_FACTOR);
+               }
+       }
+
+       fprintf(stderr, "[HOOK] Read 'apocalypse.conf'. Settings loaded.\n");
+
+       fclose(f);
+
+       HAS_LOADED_CONFIG = 1;
+}
+
+int check_cfg_mod() {
+       struct stat new;
+       stat("apocalypse.conf", &new);
+       if (new.st_mtim.tv_sec != info.st_mtim.tv_sec || new.st_mtim.tv_nsec != info.st_mtim.tv_nsec) {
+               // File was modified. Reload.
+               read_cfg();
+               memcpy(&info, &new, sizeof(struct stat));
+               return 1;
+       }
+       return 0;
+}
diff --git a/config.h b/config.h
new file mode 100644 (file)
index 0000000..44203b5
--- /dev/null
+++ b/config.h
@@ -0,0 +1,31 @@
+#define _GNU_SOURCE
+#include <dlfcn.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <unistd.h>
+#include <stdint.h>
+
+#include <sys/time.h>
+#include <time.h>
+
+#include <GL/gl.h>
+#include <GL/glx.h>
+
+#ifndef DEFINED_ENABLES_HERE
+extern int ENABLE_TIME_HACKS;
+extern int ENABLE_GETTIMEOFDAY_HOOK;
+extern int ENABLE_CLOCK_GETTIME_HOOK;
+
+extern int HAS_LOADED_CONFIG;
+
+extern int IS_TBOI;
+
+extern double SLOW_FACTOR;
+
+#endif
+
+void read_cfg();
+int check_cfg_mod(); // Returns 1 if reloaded.
diff --git a/gettime_speedhack.c b/gettime_speedhack.c
new file mode 100644 (file)
index 0000000..f155d42
--- /dev/null
@@ -0,0 +1,160 @@
+#include "config.h"
+
+typedef int (*gettimeofday_t)(struct timeval *tv, struct timezone *tz);
+typedef int (*clock_gettime_t)(clockid_t clk_id, struct timespec *tp);
+
+gettimeofday_t gettimeofday_REAL = NULL;
+clock_gettime_t clock_gettime_REAL = NULL;
+
+uint64_t time_div = 1;
+uint64_t time_mul = 1;
+double time_speedhack = 1.0f;
+
+int initd_hack = 0;
+struct timeval  gtod_time;
+struct timeval  gtod_base;
+struct timespec clkgt_m_time;
+/* CLOCK_REALTIME
+   CLOCK_REALTIME_COARSE
+   CLOCK_MONOTONIC
+   CLOCK_MONOTONIC_COARSE
+   CLOCK_BOOTTIME
+   CLOCK_PROCESS_CPUTIME_ID
+   CLOCK_THREAD_CPUTIME_ID */
+struct timespec clkgt_m_base;
+
+int mode_to_int(int mode) {
+       switch(mode) {
+               case CLOCK_REALTIME:
+                       return 0;
+               case CLOCK_REALTIME_COARSE:
+                       return 1;
+               case CLOCK_MONOTONIC:
+                       return 2;
+               case CLOCK_MONOTONIC_COARSE:
+                       return 3;
+               case CLOCK_BOOTTIME:
+                       return 4;
+               case CLOCK_PROCESS_CPUTIME_ID:
+                       return 5;
+               case CLOCK_THREAD_CPUTIME_ID:
+                       return 6;
+               default:
+                       return -1;
+       }
+}
+
+int int_to_mode(int mode) {
+       switch(mode) {
+               case 0:
+                       return CLOCK_REALTIME;
+               case 1:
+                       return CLOCK_REALTIME_COARSE;
+               case 2:
+                       return CLOCK_MONOTONIC;
+               case 3:
+                       return CLOCK_MONOTONIC_COARSE;
+               case 4:
+                       return CLOCK_BOOTTIME;
+               case 5:
+                       return CLOCK_PROCESS_CPUTIME_ID;
+               case 6:
+                       return CLOCK_THREAD_CPUTIME_ID;
+       }
+}
+
+// Init state.
+void clock_hack_init() {
+       check_cfg_mod();
+
+       gettimeofday_REAL = dlsym(RTLD_NEXT, "gettimeofday");
+       clock_gettime_REAL = dlsym(RTLD_NEXT, "clock_gettime");
+
+       if (gettimeofday_REAL(&gtod_time, NULL)) {
+               fprintf(stderr, "[HOOK] !!! SANITY ERROR !!! - real gettimeofday cannot be used, aborting\n");
+               exit(-1);
+       }
+
+       gtod_base.tv_sec  = gtod_time.tv_sec;
+       gtod_base.tv_usec = gtod_time.tv_usec;
+
+       if (clock_gettime_REAL(CLOCK_MONOTONIC, &clkgt_m_time)) {
+               fprintf(stderr, "[HOOK] !!! SANITY ERROR !!! - real gettimeofday cannot be used, aborting\n");
+               exit(-1);
+       }
+
+       clkgt_m_base.tv_sec  = clkgt_m_time.tv_sec;
+       clkgt_m_base.tv_nsec = clkgt_m_time.tv_nsec;
+
+       if (!ENABLE_TIME_HACKS)
+               fprintf(stderr, "[HOOK] Speedhack is disabled.\n", time_speedhack);
+       else
+               fprintf(stderr, "[HOOK] Speedhack is applied. Time factor is %lf.\n", time_speedhack);
+
+       initd_hack = 1;
+}
+
+// Transform time based on fraction.
+void xform_timeval(struct timeval *tv, struct timeval *orig) {
+       // What is this? Well, on init we save the initial point. From there,
+       // time moves at half-speed. So if I run a game at 2:00 PM, it's not back in 1990.
+
+       // PROBLEM - Time changes. We add a different value for the 'base'.
+       tv->tv_sec  = gtod_base.tv_sec  + ((tv->tv_sec  - orig->tv_sec)  * SLOW_FACTOR);
+       tv->tv_usec = gtod_base.tv_usec + ((tv->tv_usec - orig->tv_usec) * SLOW_FACTOR);
+
+}
+
+void xform_timespec(struct timespec *tv, struct timespec *orig) {
+       tv->tv_sec  = clkgt_m_base.tv_sec  + ((tv->tv_sec  - orig->tv_sec)  * SLOW_FACTOR);
+       tv->tv_nsec = clkgt_m_base.tv_nsec + ((tv->tv_nsec - orig->tv_nsec) * SLOW_FACTOR);
+}
+
+int done_gt_print = 0;
+
+// Fake gettimeofday.
+int gettimeofday(struct timeval *tv, struct timezone *tz) {
+       if (!initd_hack) clock_hack_init();
+
+       int r = gettimeofday_REAL(tv, NULL);
+       if (ENABLE_TIME_HACKS && ENABLE_GETTIMEOFDAY_HOOK)
+               xform_timeval(tv, &gtod_time);
+
+       if (check_cfg_mod()) {
+               gtod_base.tv_sec  = tv->tv_sec;
+               gtod_base.tv_usec = tv->tv_usec;
+       }
+
+       if (tv != NULL && tv->tv_sec % 5 == 0) {
+               if (!done_gt_print) printf("[gettimeofday]  %llu\t%llu\n", tv->tv_sec, tv->tv_usec);
+               done_gt_print = 1;
+       } else
+               done_gt_print = 0;
+
+       return r;
+}
+
+int done_clkgt_print = 0;
+
+// Fake clock_gettime.
+int clock_gettime(clockid_t clk_id, struct timespec *tp) {
+       if (!initd_hack) clock_hack_init();
+
+       int r = clock_gettime_REAL(clk_id, tp);
+       if (ENABLE_TIME_HACKS && ENABLE_CLOCK_GETTIME_HOOK)
+               xform_timespec(tp, &clkgt_m_time);
+
+       if (check_cfg_mod()) {
+               clkgt_m_base.tv_sec  = tp->tv_sec;
+               clkgt_m_base.tv_nsec = tp->tv_nsec;
+       }
+
+       if (tp != NULL && tp->tv_sec % 5 == 0) {
+               mode_to_int(clk_id);
+               if (!done_clkgt_print) printf("[clock_gettime] %llu\t%llu\n", tp->tv_sec, tp->tv_nsec);
+               done_clkgt_print = 1;
+       } else
+               done_clkgt_print = 0;
+
+       return r;
+}
diff --git a/info_window.c b/info_window.c
new file mode 100644 (file)
index 0000000..93eb31e
--- /dev/null
@@ -0,0 +1,83 @@
+#include "config.h"
+
+// Types.
+typedef __GLXextFuncPtr (*glXGetProcAddressARB_t) (const GLubyte*);
+typedef __GLXextFuncPtr (*glXSwapBuffers_t)(Display* dpy, GLXDrawable drawable);
+typedef GLXContext (*glXCreateContext_t)(Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct);
+
+// Function hooks.
+static glXSwapBuffers_t       glXSwapBuffers_REAL       = NULL;
+static glXGetProcAddressARB_t glXGetProcAddressARB_REAL = NULL;
+static glXCreateContext_t     glXCreateContext_REAL     = NULL;
+
+void pre_hook()  {
+/*     char speed[64];
+       speed[0] = '\0';
+       if (ENABLE_TIME_HACKS)
+               snprintf(speed, 64, "speedhack: %02lfx", SLOW_FACTOR);
+       uint8_t* buf = string_to_buf(speed);
+       glDrawPixels(8*strlen(speed), 8, GL_RGBA, GL_UNSIGNED_BYTE, buf);
+       free(buf); */
+}
+
+void post_hook() {}
+
+GLXContext   hook_context;
+Display*     hook_display;
+XVisualInfo* hook_visinfo;
+
+// glXSwapBuffers hook.
+void glXSwapBuffers_fake(Display* dpy, GLXDrawable drawable) {
+       pre_hook();
+       glXSwapBuffers_REAL(dpy, drawable);
+       post_hook();
+}
+
+// glXCreateContext hook.
+GLXContext glXCreateContext_fake( Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct ) {
+       hook_context = glXCreateContext_REAL(dpy, vis, shareList, direct);
+       hook_display = dpy;
+       hook_visinfo = vis;
+
+       fprintf(stderr, "[HOOK] Obtained GL context pointers successfully.\n");
+
+       return hook_context;
+}
+
+// Same-ish thing, thin shim.
+__GLXextFuncPtr glXGetProcAddress (const GLubyte* procName) {
+       return glXGetProcAddressARB(procName);
+}
+
+// glXGetProcAddressARB
+__GLXextFuncPtr glXGetProcAddressARB (const GLubyte* procName)
+{
+       __GLXextFuncPtr result;
+
+       // Fetch pointer of actual glXGetProcAddressARB() function
+       if(!glXGetProcAddressARB_REAL) {
+               char* errorstr;
+               fprintf(stderr, "[HOOK] Overrided glXGetProcAddress.\n");
+               glXGetProcAddressARB_REAL = (glXGetProcAddressARB_t) dlsym(RTLD_NEXT, "glXGetProcAddressARB");
+               if((errorstr = dlerror())) {
+                       fprintf(stderr, "dlsym fail: %s\n", errorstr);
+                       exit(1);
+               }
+       }
+
+       // Return our own function pointers for things.
+       if (!strcmp( (const char*) procName, "glXSwapBuffers" )) {
+               fprintf(stderr, "[HOOK] Hooked glXSwapBuffers pointer.\n");
+
+               glXSwapBuffers_REAL = (glXSwapBuffers_t) glXGetProcAddressARB_REAL(procName);
+               return (__GLXextFuncPtr) glXSwapBuffers_fake;
+       } else if (!strcmp( (const char*) procName, "glXCreateContext" )) {
+               fprintf(stderr, "[HOOK] Hooked glXCreateContext pointer.\n");
+
+               glXCreateContext_REAL = (glXCreateContext_t) glXGetProcAddressARB_REAL(procName);
+               return (__GLXextFuncPtr) glXCreateContext_fake;
+       }
+
+       // Return default function pointer
+       return glXGetProcAddressARB_REAL(procName);
+}