Skip to content

Commit c980c1b

Browse files
committed
Switch to PLT hooking
1 parent 0955d93 commit c980c1b

File tree

3 files changed

+854
-80
lines changed

3 files changed

+854
-80
lines changed

doorstop.c

Lines changed: 37 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <stdlib.h>
77
#include <stdint.h>
88
#include <libgen.h>
9+
#include "plthook.h"
910

1011
#define TRUE 1
1112
#define FALSE 0
@@ -14,56 +15,19 @@
1415
#if __linux__
1516
// rely on GNU for now (which we need anyway for LD_PRELOAD trick)
1617
extern char *program_invocation_name;
17-
void *(*real_dlsym)(void *, const char *) = NULL;
18-
int (*real_fclose)(FILE*) = NULL;
19-
20-
// Some crazy hackery here to get LD_PRELOAD hackery work with dlsym hooking
21-
// Taken from https://stackoverflow.com/questions/15599026/how-can-i-intercept-dlsym-calls-using-ld-preload
22-
extern void *_dl_sym(void *, const char *, void *);
2318

2419
#define PATH_MAX 4096 // Maximum on Linux
25-
#define real_dlsym real_dlsym
26-
#define real_fclose real_fclose
27-
#define dlsym_proxy dlsym
28-
#define fclose_proxy fclose
2920
#define program_path(app_path) realpath(program_invocation_name, app_path)
30-
#define DYLD_INTERPOSE(_replacment, _replacee)
31-
#define INIT_DLSYM \
32-
{ \
33-
if (real_dlsym == NULL) \
34-
real_dlsym = _dl_sym(RTLD_NEXT, "dlsym", dlsym_proxy); \
35-
if (!strcmp(name, "dlsym")) \
36-
return (void *)dlsym_proxy; \
37-
}
38-
#define INIT_FCLOSE \
39-
{ \
40-
if (real_fclose == NULL) \
41-
real_fclose = real_dlsym(RTLD_NEXT, "fclose"); \
42-
}
4321

4422
#elif __APPLE__
4523
#include <mach-o/dyld.h>
46-
#include "plthook.h"
4724

4825
#define PATH_MAX 1024 // Maximum on macOS
49-
#define real_dlsym dlsym
50-
#define real_fclose fclose
51-
#define dlsym_proxy dlsym_proxy
52-
#define fclose_proxy fclose_proxy
5326
#define program_path(app_path) \
5427
{ \
5528
uint32_t bufsize = PATH_MAX; \
5629
_NSGetExecutablePath(app_path, &bufsize); \
5730
}
58-
#define DYLD_INTERPOSE(_replacment, _replacee) \
59-
__attribute__((used)) static struct \
60-
{ \
61-
const void *replacment; \
62-
const void *replacee; \
63-
} _interpose_##_replacee \
64-
__attribute__((section("__DATA,__interpose"))) = {(const void *)(unsigned long)&_replacment, (const void *)(unsigned long)&_replacee};
65-
#define INIT_DLSYM
66-
#define INIT_FCLOSE
6731
#endif
6832

6933
void *(*r_mono_jit_init_version)(const char *root_domain_name, const char *runtime_version);
@@ -91,7 +55,7 @@ char *(*r_mono_assembly_getrootdir)();
9155

9256
void doorstop_init_mono_functions(void *handle)
9357
{
94-
#define LOAD_METHOD(m) r_##m = real_dlsym(handle, #m)
58+
#define LOAD_METHOD(m) r_##m = dlsym(handle, #m)
9559

9660
LOAD_METHOD(mono_jit_init_version);
9761
LOAD_METHOD(mono_domain_assembly_open);
@@ -216,64 +180,58 @@ void *jit_init_hook(const char *root_domain_name, const char *runtime_version)
216180
return domain;
217181
}
218182

219-
void *dlsym_proxy(void *handle, const char *name)
220-
{
221-
INIT_DLSYM;
222-
183+
void *dlsym_hook(void *handle, const char *name) {
184+
223185
if (!strcmp(name, "mono_jit_init_version"))
224186
{
225187
doorstop_init_mono_functions(handle);
226188
return (void *)jit_init_hook;
227189
}
228190

229-
return real_dlsym(handle, name);
191+
return dlsym(handle, name);
230192
}
231193

232-
int fclose_proxy(FILE *stream)
233-
{
234-
INIT_FCLOSE;
235-
236-
// Some versions of Unity wrongly close stdout, which prevents writing to console
237-
if (stream == stdout)
238-
return 0;
239-
return real_fclose(stream);
194+
int fclose_hook(FILE *stream) {
195+
// Some versions of Unity wrongly close stdout, which prevents writing to console
196+
if (stream == stdout)
197+
return F_OK;
198+
return fclose(stream);
240199
}
241200

242-
#if __APPLE__
243-
// Normal case: hook dlsym and get both handle to mono and hook to jit_init_version
244-
DYLD_INTERPOSE(dlsym_proxy, real_dlsym);
245-
DYLD_INTERPOSE(fclose_proxy, real_fclose);
201+
__attribute__ ((constructor)) void doorstop_setup() {
202+
plthook_t *hook;
246203

247-
/*
248-
On older Unity versions, Mono methods are resolved by the OS's loader directly.
249-
Because of this, there is no dlsym, in which case we need to apply a PLT hook.
250-
*/
204+
if(plthook_open(&hook, NULL) != 0) {
205+
printf("Failed to open current process PLT! Cannot run Doorstop! Error: %s\n", plthook_error());
206+
return;
207+
}
251208

252-
void *find_mono_image()
253-
{
209+
if(plthook_replace(hook, "dlsym", &dlsym_hook, NULL) != 0)
210+
printf("Failed to hook dlsym, ignoring it. Error: %s\n", plthook_error());
211+
212+
if(plthook_replace(hook, "fclose", &fclose_hook, NULL) != 0)
213+
printf("Failed to hook fclose, ignoring it. Error: %s\n", plthook_error());
214+
215+
#if __APPLE__
216+
/*
217+
On older Unity versions, Mono methods are resolved by the OS's loader directly.
218+
Because of this, there is no dlsym, in which case we need to apply a PLT hook.
219+
*/
220+
void *mono_handle = NULL;
254221
uint32_t cnt = _dyld_image_count();
255222
for (uint32_t idx = 0; idx < cnt; idx++)
256223
{
257224
const char *image_name = idx ? _dyld_get_image_name(idx) : NULL;
258-
if (image_name && strstr(image_name, "libmono"))
259-
return dlopen(image_name, RTLD_LAZY | RTLD_NOLOAD);
225+
if (image_name && strstr(image_name, "libmono"))
226+
{
227+
mono_handle = dlopen(image_name, RTLD_LAZY | RTLD_NOLOAD);
228+
break;
229+
}
260230
}
261-
return NULL;
262-
}
263-
264-
__attribute__((constructor)) void doorstop_main()
265-
{
266-
plthook_t *hook;
267231

268-
if(plthook_open(&hook, NULL) != 0)
269-
printf("Failed to open current process PLT! err: %s\n", plthook_error());
270-
271-
if(plthook_replace(hook, "mono_jit_init_version", &jit_init_hook, NULL) == 0)
272-
{
273-
void *mono_handle = find_mono_image();
232+
if(plthook_replace(hook, "mono_jit_init_version", &jit_init_hook, NULL) == 0 && mono_handle)
274233
doorstop_init_mono_functions(mono_handle);
275-
}
276-
234+
#endif
235+
277236
plthook_close(hook);
278-
}
279-
#endif
237+
}

makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ UNAME_S := $(shell uname -s)
66
ifeq ($(UNAME_S), Linux)
77
EXT = so
88
CCFLAGS += -D LINUX
9-
FILES=doorstop.c
9+
FILES=doorstop.c plthook_elf.c
1010
endif
1111
ifeq ($(UNAME_S), Darwin)
1212
EXT = dylib

0 commit comments

Comments
 (0)