dylib Injection
macOS provides several mechanisms for dynamically injecting shared libraries (dylibs) into processes, enabling advanced persistence, hooking, and control over target applications. These techniques are commonly used in red teaming for privilege escalation, data exfiltration, or bypassing security controls. Below are the primary methods for dylib injection and their practical implementation.
LD_PRELOAD: Preloading Libraries at Process Initialization¶
LD_PRELOAD allows specifying a list of shared libraries to load before any other libraries in a process. This is particularly useful for hooking functions like open, malloc, or execve in target applications.
How It Works¶
When a process is launched, the dynamic linker (dyld) loads libraries specified in LD_PRELOAD before resolving dependencies. This enables overriding standard library functions or injecting malicious code.
Example: Hooking open¶
# Compile a dylib that hooks open()
gcc -fPIC -shared -o hook.dylib hook.c
export DYLD_INSERT_LIBRARIES=/path/to/hook.dylib
/Applications/TargetApp.app/Contents/MacOS/TargetApp
hook.c (simplified):
#include <dlfcn.h>
#include <stdio.h>
int open(const char *path, int flags) {
printf("[Hook] Opening %s\n", path);
return (*(int (*)(const char*, int))dlsym(RTLD_NEXT, "open"))(path, flags);
}
Limitations¶
- Sandboxed apps: macOS sandboxing may block
LD_PRELOADfor apps with restricted permissions. - Process lifetime: The dylib is only loaded for the duration of the process.
DYLD_INSERT_LIBRARIES: Inserting Libraries at Runtime¶
DYLD_INSERT_LIBRARIES forces dyld to load specified libraries into a running process. Unlike LD_PRELOAD, this method can inject libraries into already running processes, making it ideal for post-exploitation scenarios.
How It Works¶
This environment variable tells dyld to load the listed dylibs during process initialization. It is often used in conjunction with launchd or osascript to target specific processes.
Example: Injecting into a Running Process¶
# Inject a dylib into a running process (e.g., Finder)
osascript -e 'tell application "Finder" to launch'
DYLD_INSERT_LIBRARIES=/path/to/inject.dylib /usr/bin/killall Finder
inject.dylib (simplified):
#include <stdio.h>
#include <mach-o/dyld.h>
void _dyld_register_func_for_add_image(void *image, const char *path) {
printf("[Injected] %s loaded\n", path);
}
Limitations¶
- Process compatibility: Only works on processes that are not sandboxed or have elevated privileges.
- DYLD_LIBRARY_PATH: May require additional configuration to ensure the dylib is found.
Alternative Techniques: Mach-O Injection and Linker Flags¶
For more advanced scenarios, attackers may modify binary dependencies using tools like install_name_tool to embed dylibs directly into target executables. This approach bypasses environment variables entirely but requires binary modification.
Example: Embedding a Dylib¶
install_name_tool -add_rpath /path/to/libs /path/to/target_binary
install_name_tool -change /usr/lib/libc.dylib /path/to/libs/libc.dylib /path/to/target_binary
This method is often used in malware that requires persistence across reboots.
Key takeaways¶
- LD_PRELOAD is ideal for hooking functions in newly launched processes but is limited by sandboxing.
- DYLD_INSERT_LIBRARIES enables runtime injection into active processes, making it valuable for post-exploitation.
- Binary modification (e.g.,
install_name_tool) offers persistence but requires deeper access to the target application. - Always test in controlled environments and respect system restrictions like SIP (System Integrity Protection).