Last active
July 3, 2021 08:42
-
-
Save jakobrs/5c694c5b97fd054c071216bbf9f16f73 to your computer and use it in GitHub Desktop.
fake dlopen_from and dlsym_from on macOS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extern "C" int dyld_func_lookup(const char *, void **); | |
extern "C" void *dlopen_from(const char *file, int mode, void *caller) __attribute__((weak)); | |
/* To get the "caller address", __dyld_dlopen evaluates *(rbp + 0x8), which | |
* means we can set a fake caller address by storing the address of our fake | |
* caller address, minus 8, in rbp. | |
*/ | |
__attribute__((naked)) | |
static void *fake_dlopen_from_10_13(const char *file, int mode, void *caller, | |
void *(*__dyld_dlopen)(const char *, int)) { | |
asm ( | |
"push %rbp\n\t" // Store rbp on the stack (to restore later) | |
"sub $0x10, %rsp\n\t" // Allocate 0x10 bytes on the stack (to store `caller`) | |
"mov %rdx, 8(%rsp)\n\t" // Store `caller` on stack | |
"mov %rsp, %rbp\n\t" // Store address of `caller`, minus 0x8, in rbp | |
"call *%rcx\n\t" // The function call | |
"add $0x10, %rsp\n\t" // Deallocate stack space | |
"pop %rbp\n\t" // Restore rbp | |
"ret\n\t" // Return | |
); | |
} | |
extern "C" void *fake_dlopen_from(const char *file, int mode, void *caller) { | |
if (dlopen_from) { | |
return dlopen_from(file, mode, caller); | |
} | |
void *(*__dyld_dlopen_internal)(const char *file, int mode, void *caller); | |
if (dyld_func_lookup("__dyld_dlopen_internal", (void **)&__dyld_dlopen_internal) == 1) { | |
return __dyld_dlopen_internal(file, mode, caller); | |
} | |
void *(*__dyld_dlopen)(const char *file, int mode); | |
dyld_func_lookup("__dyld_dlsym", (void **)&__dyld_dlopen); | |
return fake_dlopen_from_10_13(file, mode, caller, __dyld_dlopen); | |
} | |
/* This also works */ | |
//__attribute__((alias("_ZL22fake_dlopen_from_10_13PKciPvPFS1_S0_iE"))) | |
//static void *fake_dlsym_from_10_13(void *handle, const char *name, void *caller, | |
// void *(*__dyld_dlsym)(void *, const char *)); | |
__attribute__((naked)) | |
static void *fake_dlsym_from_10_13(void *handle, const char *name, void *caller, | |
void *(*__dyld_dlsym)(void *, const char *)) { | |
/* Identical to fake_dlopen_from_10_13 above */ | |
asm ( | |
"push %rbp\n\t" | |
"sub $0x10, %rsp\n\t" | |
"mov %rdx, 8(%rbp)\n\t" | |
"mov %rsp, %rbp\n\t" | |
"call *%rcx\n\t" | |
"add $0x10, %rsp\n\t" | |
"pop %rbp\n\t" | |
"ret\n\t" | |
); | |
} | |
extern "C" void *fake_dlsym_from(void *handle, const char *name, void *caller) { | |
void *(*__dyld_dlsym_internal)(void *handle, const char *name, void *caller); | |
if (dyld_func_lookup("__dyld_dlsym_internal", (void **)&__dyld_dlsym_internal) == 1) { | |
return __dyld_dlsym_internal(handle, name, caller); | |
} | |
void *(*__dyld_dlsym)(void *handle, const char *name); | |
dyld_func_lookup("__dyld_dlsym", (void **)&__dyld_dlsym); | |
return fake_dlsym_from_10_13(handle, name, caller, __dyld_dlsym); | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extern "C" int dyld_func_lookup(const char *, void **); | |
extern "C" void *dlopen_from(const char *file, int mode, void *caller) __attribute__((weak)); | |
__attribute__((naked)) | |
static void *fake_dlopen_from_10_13(const char *file, int mode, void **rbp, | |
void *(*__dyld_dlopen)(const char *, int)) { | |
asm ( | |
"push %rbp\n\t" // Store rbp on the stack (to restore later) | |
"mov %rdx, %rbp\n\t" // Move rbp argument into rbp | |
"call *%rcx\n\t" // The function call | |
"pop %rbp\n\t" // Restore rbp | |
"ret\n\t" // Return | |
); | |
} | |
extern "C" void *fake_dlopen_from(const char *file, int mode, void *caller) { | |
if (dlopen_from) { | |
return dlopen_from(file, mode, caller); | |
} | |
void *(*__dyld_dlopen_internal)(const char *file, int mode, void *caller); | |
if (dyld_func_lookup("__dyld_dlopen_internal", (void **)&__dyld_dlopen_internal) == 1) { | |
return __dyld_dlopen_internal(file, mode, caller); | |
} | |
void *(*__dyld_dlopen)(const char *file, int mode); | |
dyld_func_lookup("__dyld_dlsym", (void **)&__dyld_dlopen); | |
return fake_dlopen_from_10_13(file, mode, &caller - 1, __dyld_dlopen); | |
} | |
/* This also works */ | |
//__attribute__((alias("_ZL22fake_dlopen_from_10_13PKciPvPFS1_S0_iE"))) | |
//static void *fake_dlsym_from_10_13(void *handle, const char *name, void **rbp, | |
// void *(*__dyld_dlsym)(void *, const char *)); | |
__attribute__((naked)) | |
static void *fake_dlsym_from_10_13(void *handle, const char *name, void **rbp, | |
void *(*__dyld_dlsym)(void *, const char *)) { | |
/* Identical to fake_dlopen_from_10_13 above */ | |
asm ( | |
"push %rbp\n\t" | |
"mov %rdx, %rbp\n\t" | |
"call *%rcx\n\t" | |
"pop %rbp\n\t" | |
"ret\n\t" | |
); | |
} | |
extern "C" void *fake_dlsym_from(void *handle, const char *name, void *caller) { | |
void *(*__dyld_dlsym_internal)(void *handle, const char *name, void *caller); | |
if (dyld_func_lookup("__dyld_dlsym_internal", (void **)&__dyld_dlsym_internal) == 1) { | |
return __dyld_dlsym_internal(handle, name, caller); | |
} | |
void *(*__dyld_dlsym)(void *handle, const char *name); | |
dyld_func_lookup("__dyld_dlsym", (void **)&__dyld_dlsym); | |
return fake_dlsym_from_10_13(handle, name, &caller - 1, __dyld_dlsym); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment