HN
Today

macOS code injection for fun and no profit (2024)

This detailed technical guide explores macOS code injection using Mach APIs, driven by the author's desire for a Live++ equivalent on Apple's platform. It meticulously walks through attaching to processes, manipulating memory, and injecting new functions with trampolines. The article is a popular read for those interested in low-level macOS development and understanding how tools like debuggers or hot-reloading systems function.

14
Score
0
Comments
#4
Highest Rank
4h
on Front Page
First Seen
Mar 7, 7:00 PM
Last Seen
Mar 7, 10:00 PM
Rank Over Time
4578

The Lowdown

The author, inspired by the C/C++ hot-reloading capabilities of Live++ on Windows, embarked on a vacation project to understand the mechanics of code injection on macOS. Since Live++ lacks a macOS version, this exploration serves as a practical, step-by-step guide to achieve similar low-level process manipulation for 'fun and no profit', demonstrating core principles used by debuggers and other system tools.

  • Setup and Entitlements: The guide begins with setting up a CMake project and configuring macOS entitlements via codesign to grant the injection program debugger-like capabilities.
  • Process Attachment: It details how to attach to a running process using its PID and the Mach API task_for_pid(), which provides a task control port for further interaction. The example cleverly uses a data.txt file to share runtime addresses and PID, bypassing ASLR complexities.
  • Process Control: Instructions are provided for suspending and resuming a target process's threads using task_suspend() and task_resume() to ensure atomic memory operations.
  • Memory Manipulation: The core functionalities of reading and writing to a remote process's memory are explained with vm_read_overwrite() and vm_write(), demonstrated by altering an integer variable in the target program.
  • Code Injection via Trampolines: The most advanced section covers injecting an entirely new function. This involves allocating executable memory in the target process using vm_allocate() and vm_protect(), then writing the new function's machine code. The key technique, trampolines, is introduced to redirect calls from an existing function (foo()) to the newly injected one (bar()).
  • Architecture-Specific Trampolines: The guide provides assembly details for both x86_64 and ARM64 architectures for creating these jump instructions, noting the use of fpatchable-function-entry compiler flags to reserve space for the trampoline by adding NOPs.

While not production-ready, this detailed walkthrough provides a solid foundation for understanding the intricate processes behind code injection and hot-reloading. It demystifies how debuggers, live-coding solutions, and even certain malware/antivirus programs interact with and modify running applications at a fundamental level on macOS.