Exploiting macOS dynamic-linker and process-injection primitives during authorized engagements - DYLD_INSERT_LIBRARIES injection, @rpath/missing-dylib hijacking with re-export proxy libraries, dyld interposing and fishhook symbol rebinding, Objective-C method swizzling, and Mach task-port thread hijacking (task_for_pid) including arm64e PAC handling - using otool, codesign, install_name_tool, gcc/clang, and lldb, with EndpointSecurity detection notes.
Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.
Quelldateien prüfen
Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Ein direkter Befehl überspringt den Prüf-Prompt. Prüfen Sie die Quelle, bevor Sie ihn ausführen.
Exploiting macOS dynamic-linker and process-injection primitives during authorized engagements - DYLD_INSERT_LIBRARIES injection, @rpath/missing-dylib hijacking with re-export proxy libraries, dyld interposing and fishhook symbol rebinding, Objective-C method swizzling, and Mach task-port thread hijacking (task_for_pid) including arm64e PAC handling - using otool, codesign, install_name_tool, gcc/clang, and lldb, with EndpointSecurity detection notes.
Exploiting macOS Dyld Hijacking & Process Injection
When to Use
You want to run code inside another process on macOS to steal secrets (passwords, messages), inherit its TCC/entitlements, or hook its functions.
A target binary loads libraries via @rpath/DYLD_INSERT_LIBRARIES without library validation, or you hold a task port (task_for_pid) for a get-task-allow process.
You need to choose between load-time injection (dyld) and runtime injection (thread hijack / fishhook) based on the target's protections.
Critical: Techniques Most Often Missed
DYLD_INSERT_LIBRARIES — the simplest primitive; a dylib __attribute__((constructor)) runs before main. Blocked on hardened/platform binaries, so check restrictions first.
How to CONFIRM: sudo log stream --style syslog --predicate 'eventMessage CONTAINS[c] "[+] dylib"' shows your constructor logging when loaded.
@rpath / missing-dylib hijack — find a dylib the app expects but doesn't ship, and that it loads without checking the signature (com.apple.security.cs.disable-library-validation).
How to CONFIRM: one @rpath candidate path doesn't exist on disk; dropping your dylib there and running the binary logs your constructor.
Re-export proxy dylib — keep the app working by re-exporting the legit library's symbols from your malicious one, matching current/compatibility versions.
How to CONFIRM: otool -l /tmp/lib.dylib | grep REEXPORT -A2 shows the absolute re-export path; the app runs normally and your code executes.
fishhook symbol rebinding (runtime) — already inside a process, hook an imported C function by rewriting its import slot; only affects calls that go through an import pointer.
How to CONFIRM: hooked close()/etc. logs each call. NOTE: on arm64e targets check __AUTH_CONST.__auth_got and temporarily make __DATA_CONST writable.
Thread hijack via task port — with a task port you can't thread_create_running (mitigated); instead task_threads() → thread_suspend() → set x0..x7/pc → resume. On arm64e you must sign pc with PAC (ptrauth_sign_unauthenticated) or chain existing gadgets.
How to CONFIRM: target executes your function (e.g., via threadexec); EndpointSecurity emits ES_EVENT_TYPE_NOTIFY_REMOTE_THREAD_CREATE.
Load-time, env: target allows DYLD_* (no hardened runtime / has allow-dyld-environment-variables, not a platform binary).
Load-time, disk: a missing/@rpath dylib + disable-library-validation → hijack on disk (survives relaunch; great for TCC theft).
Runtime, in-proc: you already execute inside the process → interpose (__DATA,__interpose), dyld_dynamic_interpose, fishhook, or ObjC swizzling.
Runtime, remote: you hold the task port of a get-task-allow/unprotected process → thread hijack.
Step 3: Exploit (concrete commands)
# (a) Interpose a libc function via __interpose section, injected with DYLD_INSERT_LIBRARIES# gcc -dynamiclib interpose.c -o interpose.dylib (DYLD_INTERPOSE(my_printf, printf))
DYLD_INSERT_LIBRARIES=./interpose.dylib ./hello
DYLD_PRINT_INTERPOSING=1 DYLD_INSERT_LIBRARIES=./interpose.dylib ./hello # debug interposing# (b) ObjC method_setImplementation to sniff a secret (store original first)# gcc -dynamiclib -framework Foundation sniff.m -o sniff.dylib# constructor: real = method_setImplementation(class_getInstanceMethod(cls,@selector(setPassword:keyFileURL:)), fake)log stream --style syslog --predicate 'eventMessage CONTAINS[c] "Password"'# (c) Persisting dylib injection in an app bundle via Info.plist LSEnvironment, then re-register# <key>LSEnvironment</key><dict><key>DYLD_INSERT_LIBRARIES</key><string>/Applications/App.app/Contents/malicious.dylib</string></dict>
/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -f /Applications/Application.app
# (d) Inspect a remote process before thread hijack
lldb -p <pid> # confirm get-task-allow / debuggability
Step 4: Persist / escalate / pivot
Inherit TCC/entitlements: code running inside a TCC-granted or entitled app gains its camera/FDA/etc. access with no prompt (e.g., the CVE-2023-26818 Telegram camera-TCC bypass via dylib hijack).
Persist the hijack: a dylib dropped at the hijacked @rpath location reloads every launch; bundle LSEnvironment + lsregister survives too. NOTE: on newer macOS, stripping a previously-run app's signature stops it launching, so prefer hijack over re-sign.
Deepen with remote R/W: after thread hijack, build read/write primitives (property_getName for read, _xpc_int64_set_value for write), set up Mach-port channels, and xpc_shmem shared memory — wrapped by threadexec for full control, then transfer Mach ports / fileports to pivot.
Key Concepts
Concept
Description
dyld
The dynamic linker; resolves @rpath/@loader_path/@executable_path and honors DYLD_* env vars (restricted on hardened/platform binaries).
DYLD_INSERT_LIBRARIES
Loads attacker dylib before main; constructor runs first. Blocked by hardened runtime / library validation / platform-binary status.
@rpath hijack
App loads a dylib from a search path; if a higher-priority path is missing/writable and signature isn't checked, swap it.
Re-export proxy
-reexport_library + install_name_tool -change so the malicious dylib forwards real symbols and the app still works.
Interposing
__DATA,__interpose tuples (or dyld_dynamic_interpose) replace functions between the process and loaded libs (not the shared cache).
fishhook
Runtime symbol rebinding of imported functions by rewriting lazy/non-lazy pointer slots; needs __DATA_CONST writable, PAC-aware on arm64e.
ObjC swizzling
method_exchangeImplementations / method_setImplementation swap selector IMPs to intercept Objective-C calls.
Task port / thread hijack
task_for_pid → task_threads → suspend → set registers/pc → resume; thread_set_special_port/mach_reply_port to build Mach-port channels.
PAC (arm64e)
Pointer Authentication signs return addresses/pointers; jumping to attacker memory needs ptrauth_sign_unauthenticated or gadget reuse.
A Developer-ID app with disable-library-validation expects @rpath/lib.dylib at a path that doesn't exist. The tester drops a re-export proxy dylib there; on launch it runs inside the app and uses the app's camera TCC grant (CVE-2023-26818 pattern).
Scenario 2: ObjC swizzle to sniff a password manager
The tester injects sniff.dylib via the app's Info.plistLSEnvironment and lsregister, swizzling setPassword:keyFileURL: with method_setImplementation, logging cleartext passwords to the unified log while calling the original method so nothing breaks.
Scenario 3: Task-port thread hijack with PAC
Holding the task port of a get-task-allow process on Apple Silicon, the tester suspends a thread, sets x0..x7 and a PAC-signed pc, and resumes — building read/write and Mach-port channels via threadexec for full remote control.
Output Format
## macOS Process Injection Finding
**Target**: macOS 14.4 (arm64e) ; App: com.vendor.app (Developer ID, disable-library-validation)
**Primitive**: @rpath dylib hijack with re-export proxy
**Severity**: High
**Finding**: App loads attacker dylib from a missing @rpath path without signature validation
**Evidence**:
- `codesign -d --entitlements :- App.app` -> com.apple.security.cs.disable-library-validation
- `otool -l binary | grep @rpath` -> expects @rpath/lib.dylib ; only lib2/lib.dylib exists
- dropped proxy -> log shows "[+] dylib hijacked"; app runs normally (re-export intact)
**Impact**: Code execution inside the app inheriting its TCC/entitlements (e.g., camera, FDA), enabling data theft.
**Recommendation**:
1. Enable Hardened Runtime + Library Validation; remove `disable-library-validation`/`allow-dyld-environment-variables`.
2. Load dylibs from signed absolute paths; verify loaded-library Team IDs.
3. Ship without `com.apple.security.get-task-allow` to block non-root task-port access.
4. Deploy EndpointSecurity monitoring for GET_TASK / REMOTE_THREAD_CREATE / THREAD_SET_STATE.