Skip to content

Instantly share code, notes, and snippets.

@jakobrs
Last active July 3, 2021 08:42
Show Gist options
  • Save jakobrs/5c694c5b97fd054c071216bbf9f16f73 to your computer and use it in GitHub Desktop.
Save jakobrs/5c694c5b97fd054c071216bbf9f16f73 to your computer and use it in GitHub Desktop.
fake dlopen_from and dlsym_from on macOS
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);
}
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