Understanding the Lifecycle of Dynamic Loaders: A Detailed Analysis
Written on
Chapter 1: Introduction to Dyld's Functionality
This installment is the seventh in a series dedicated to debugging Dyld-1122 and examining its source code. We will delve into the logging mechanisms and dyldCache components found within the ProcessConfig, while also deciphering the roles of three specific environment variables: DYLD_PRINT_TO_FILE, DYLD_SHARED_REGION, and DYLD_SHARED_CACHE_DIR.
It's important to note that this analysis might contain inaccuracies as I am still gaining experience in this area. If you spot any errors, please feel free to comment or reach out via my social media channels. Let's dive in!
Working Map
To kick things off, we will decompile Dyld using Hopper with the command:
Copyhopper -e '/usr/lib/dyld'
We are currently analyzing the Memory Manager. In the previous article, I introduced pseudo-code, which we will build upon as we set up the ProcessConfig.
Last time, we began exploring properties of ProcessConfig and concluded with ProcessConfig::Security. Now, we will continue with ProcessConfig::Logging:
The first video titled "Pro Tools Crashes / Won't Open Session (4 ways to fix it!)" offers various solutions for troubleshooting this common issue.
Section 1.1: Logging in Dyld
We will initiate our exploration of ProcessConfig::Logging, focusing on the following code section:
- Start: Logging in dyld-1122.1 — DyldProcessConfig.cpp#L850
- End: pathOverrides in dyld-1122.1 — DyldProcessConfig.cpp#L1530
We can set LLDB breakpoints to monitor the logging procedure:
# Start - dyld`dyld4::ProcessConfig::Logging::Logging
settings set target.env-vars DYLD_IN_CACHE=0
br set -n ProcessConfig -s dyld -R 92
# END - dyld`dyld4::ProcessConfig::ProcessConfig+128
br set -n ProcessConfig -s dyld -R 128
The next installment will pick up right where this one leaves off.
Subsection 1.1.1: Environment Variables and Logging
We will execute ProcessConfig::Logging::Logging. Since we're not running the application with ExclaveKit (an internal Apple tool), we will focus on lines 852-874 of DyldProcessConfig.cpp.
Logging variables will be set according to the Dyld Environment Variables, assuming security.allowEnvVarsPrint has been enabled by AMFI earlier.
Among the variables, two undocumented DEV variables are noteworthy:
- DYLD_PRINT_TO_STDERR=1: Forces output to STDERR for console logs.
- DYLD_PRINT_INTERPOSING=1: Displays information about any interposes that have occurred.
After setting the logging descriptor to STDERR_FILENO (2) and specifying that logging will not use a file output, a condition check determines if DYLD_PRINT_TO_FILE is processed, even for incorrectly signed files.
We then utilize the openLogFile syscall wrapper to manage file paths specified by DYLD_PRINT_TO_FILE=test.txt, using the syscall with three arguments.
The code may behave differently depending on the compilation context, and we will analyze it through assembly-level execution.
Logging Summary
After executing dyld4::ProcessConfig::Logging::Logging without any DEV variables, we observe the ProcessConfig memory related to dyldCache. By default, Dyld employs the Shared Library Cache (SLC), but this can be disabled with DYLD_SHARED_REGION=avoid.
To function correctly, all cached libraries must be situated in their designated filesystem locations. For an overview of the system libraries required when utilizing the avoid option, see the following command:
(lldb) image list
Chapter 2: Exploring DyldCache Configuration
In the second video, "The Late Show with Matty Johns remembers the late Paul Green," the show pays tribute to the late Paul Green, highlighting his contributions and impact.