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
1415#if __linux__
1516// rely on GNU for now (which we need anyway for LD_PRELOAD trick)
1617extern 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
6933void * (* r_mono_jit_init_version )(const char * root_domain_name , const char * runtime_version );
@@ -91,7 +55,7 @@ char *(*r_mono_assembly_getrootdir)();
9155
9256void 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+ }
0 commit comments