Dylib Injection - Exploiting macOS Applications
This document is still a draft. Please note that there might be mistakes or inaccuracies.
Table of Contents
- Table of Contents
- Introduction
- Prerequisites
- Step 1: Identify Target Application
- Step 2: Create the Dylib
- Step 3: Inject the Dylib
- Step 4: Test the Injection
- Step 5: Cleanup
- Conclusion
Introduction
Dylib injection is a technique used to modify or extend the behavior of macOS applications by injecting dynamic libraries (dylibs
) into their address space. This can be a powerful tool for reverse engineering, debugging, or even security research. In this guide, we’ll walk through the process of injecting a dylib
into a macOS
application.
We will explore two different techniques for injecting a dynamically linked library (dylib
) into an application:
DYLD_INSERT_LIBRARIES Injection
DYLIB Hijacking
We will ultimately leverage this to run in the application’s context, which will provide us rights that we didn’t necessarily have before.
Prerequisites
Before we begin, make sure you have the following:
macOS
development environment.- Knowledge of
C/C++
programming. Xcode
or a compatible development environment.- The target
macOS
application for injection.
Step 1: Identify Target Application
Identify the macOS
application you want to inject a dylib into. You’ll need the full path to the application binary (e.g., /Applications/TargetApp.app/Contents/MacOS/TargetApp
).
Step 2: Create the Dylib
Create a new Xcode
project for a Command Line Tool
Write your dylib code in C/C++
Let’s make a short dynamic library that we can inject into a target application. The library will print to the standard output and generate a log message as well.
DYLD_INSERT_LIBRARIES Injection in macOS
The DYLD_INSERT_LIBRARIES
injection technique is a very old and classic technique on macOS. It’s similar to the LD_PRELOAD1
method.
DYLD_INSERT_LIBRARIES
is an environment variable that instructs the dyld dynamic library loader to load any dylib
before the main application starts. The loaded dylib
will run in the context of the application we are targeting.
1
2
3
4
5
6
7
8
9
#include <stdio.h>
#include <syslog.h>
__attribute__((constructor))
static void myconstructor(int argc, const char **argv)
{
printf("[+] dylib constructor called from %s\n", argv[0]);
syslog(LOG_ERR, "[+] dylib constructor called from %s\n", argv[0]);
}
The __attribute__((constructor))
is a GCC
specific syntax that instructs the compiler to treat the next function as a constructor. When the dynamic loader loads the compiled binary, it will run the function specified under the constructor.
Use gcc
to compile the dynamic library. The -dynamiclib
option will compile the file as a dylib
instead of a Mach-O
executable. The -o
option specifies the name of the output file.
1
gcc -dynamiclib example.c -o example.dylib
Let’s create a simple “Hello World” application in C
, compile it with gcc
, run it, and inject the dynamic library into this application.
1
2
3
4
5
6
#include <stdio.h>
int main()
{
printf("Hello, World!\n");
return 0;
}
1
2
./hello
DYLD_INSERT_LIBRARIES=example.dylib ./hello
1
2
3
DYLD_INSERT_LIBRARIES=example.dylib ./hello
[+] dylib constructor called from ./hello
Hello, World!
Monitor log output using the log
command
1
2
3
4
5
log stream --style syslog --predicate 'eventMessage CONTAINS[c] "constructor"'
Filtering the log data using "composedMessage CONTAINS[c] "constructor""
Timestamp (process)[PID]
2021-01-15 08:35:14.505743-0600 localhost MachOView[94732]: (example.dylib) [+] dylib constructor called from /Applications/MachOView.app/Contents/MacOS/MachOView
This command logs all event messages containing the “constructor” word in the message body. We’re using the stream option to view logs from the system continuously,
--style
to specify the formatting, and--predicate
is a filter we apply to the stream.
DYLIB Hijacking
A second way of injecting code into a macOS application is by performing dylib hijacking or a dylib proxying attack.
The idea behind this attack is very similar to DLL hijacking1 on Windows. It works by leveraging situations in which we can inject our own dylib when the dynamic loader (dyld) loads the application’s shared libraries.
There are two main scenarios in which we can conduct dylib hijacking
Build the dylib, ensuring it’s a dynamic library (.dylib
)
Step 3: Inject the Dylib
- Open Terminal and navigate to the directory where the dylib and target application are located.
Use the
DYLD_INSERT_LIBRARIES
environment variable to inject the dylib into the target application. ReplaceTargetApp
andYourDylib.dylib
with the actual names:1
DYLD_INSERT_LIBRARIES=./YourDylib.dylib /Applications/TargetApp.app/Contents/MacOS/TargetApp
- The target application will launch with your dylib injected.
Step 4: Test the Injection
- Monitor the application for any behavior changes or logs generated by your dylib.
- Test your code thoroughly to ensure it interacts with the target application as intended.
Step 5: Cleanup
- After testing, remember to remove the dylib injection by closing the target application.
To revert, simply close the application and remove the dylib from the environment variable:
1
DYLD_INSERT_LIBRARIES= /Applications/TargetApp.app/Contents/MacOS/TargetApp
Conclusion
Dylib injection is a powerful technique for manipulating macOS applications. However, use it responsibly and only for legitimate purposes like debugging and reverse engineering. Be aware that some applications may have security mechanisms in place to prevent injection.
Remember that unauthorized dylib injection into proprietary applications may violate their terms of service or even legal regulations, so always use this knowledge ethically and within the bounds of the law.