macOS Applications – Testing, Debugging, and Fuzzing (Part 2)

18 March 2024 7 minutes Author: Cyber Witcher

This is the second part of our research, in which we continue to look at various aspects of analyzing, debugging and phasing macOS applications. In this installment, we’ll delve into static and dynamic analysis techniques, and explore the various tools and techniques you can use to investigate applications on macOS.

The second part of the article “MacOS programs – verification, debugging and fuzzing” is a continuation of the first part


ProcessMonitor is a very useful tool for inspecting the process-related actions that a process performs (for example, tracking what new processes a process spawns).


SpriteTree is a tool for printing relationships between processes. You need to monitor your Mac with a command like sudo eslogger fork exec rename create > cap.json (the terminal that runs this is required by the FDA). You can then load the json into this tool to see all the connections:


FileMonitor allows you to track events on a file (such as creation, modification, and deletion), providing detailed information about such events.


Crescendo — is a GUI tool that Windows users may know from Microsoft Sysinternal’s Procmon. This tool allows you to start and stop the recording of different types of events, allows you to filter these events by categories such as file, process, network, etc. and provides functionality to save the recorded events in json format.

Apple tools

Інструменти Apple is part of the Xcode developer tools used to monitor application performance, detect memory leaks, and track file system activity.


Allows you to monitor actions performed by processes:

fs_usage -w -f filesys ls #This tracks filesystem actions of proccess names containing ls
fs_usage -w -f network curl #This tracks network actions


Taskexplorer useful for viewing the libraries used by a binary, the files it uses, and network connections. It also checks binaries on virustotal and shows information about the binary.


In this blog post, you can find an example of how to debug a running daemon that was previously PT_DENY_ATTACH prevented from debugging even when SIP was disabled.


lldb is the actual macOS binary debugging tool.

lldb ./malware.bin
lldb -p 1122
lldb -n malware.bin
lldb -n malware.bin --waitfor

You can install the Intel flavor when creating a .lldbinit file to your home folder with lldb using the following line:

settings set target.x86-disassembly-flavor intel

Inside lldb, create a process dump using process save-coreprocess save-core

print object (po) 

This will print the object referenced by the parameter

po $raw


dnsChanger = {

"affiliate" = "";

"blacklist_dns" = ();

Note that most Apple Objective-C APIs or methods return objects, so they should be displayed using the “print object” (po) command. If po does not give a significant result, use x/b


read memory 0x000… read memory $x0+0xf2a write memory 0x100600000 -s 4 0x41414141 #Write AAAA to this address write memory -fs $rip+0x11f+7 “AAAA” #Write AAAA in the address


dis #Disas current function

dis -n <funcname> #Disas func

dis -n <funcname> -b <basename> #Disas func dis -c 6 #Disas 6 lines

dis -c 0x100003764 -e 0x100003768 # Від одного додавання до іншого dis -p -c 4 # Почати розбирання поточної адреси


parray 3 (char **)$x1 # Check an array of 3 components in x1 reg

When objc_sendMsg is called, the rsi register stores the method name as a null-terminated string (“C”). To print the title via lldb, do:

(lldb) x/s $rsi: 0x1000f1576: "startMiningWithPort:password:coreCount:slowMemory:currency:"

(lldb) print (char*)$rsi: (char *) $1 = 0x00000001000f1576 "startMiningWithPort:password:coreCount:slowMemory:currency:"

(lldb) reg read $rsi: rsi = 0x00000001000f1576 "startMiningWithPort:password:coreCount:slowMemory:currency:"

Antidynamic analysis

Detection of VM
  • The sysctl hw.model command returns “Mac” if the host is MacOS , but something else when it’s a virtual machine.

  • By playing with the values of hw.logicalcpu and hw.physicalcpu, some malware tries to determine whether it is a virtual machine.

  • Some malware can also determine if a machine is VMware based on the MAC address (00:50:56).

  • You can also find out if a process is debugging using simple code, for example:

  • if(P_TRACED == (info.kp_proc.p_flag & P_TRACED)){ //process being debugged }

  • It can also call the ptrace system call with the PT_DENY_ATTACH flag. This prevents the debugger from attaching and tracing.

  • You can check if the sysctla function is imported or (but malware can import it dynamically) ptrace

  • As noted in this writeup, “Overcoming Debug Defenses: ptrace macOS Variants”: “The message Process # exited with status = 45 (0x0000002d) is usually an indication that the debug target is using PT_DENY_ATTACH”


ReportCrash analyzes crash processes and saves a crash report to disk. A crash report contains information that can help the developer diagnose the cause of the crash. For programs and other processes running in the per-user launchd context, ReportCrash runs as LaunchAgent and stores crash reports for the user. ~/Library/Logs/DiagnosticReports/ For daemons, other processes running in the system launchd context, and other privileged processes, ReportCrash runs as LaunchDaemon and saves crashes. reports in system/Library/Logs/DiagnosticReports

If you’re concerned about sending crash reports to Apple, you can turn them off. If not, the crash reports can be useful in finding the cause of the server crash.

#To disable crash reporting:
launchctl unload -w /System/Library/LaunchAgents/
sudo launchctl unload -w /System/Library/LaunchDaemons/

#To re-enable crash reporting:
launchctl load -w /System/Library/LaunchAgents/
sudo launchctl load -w /System/Library/LaunchDaemons/


When fuzzing on MacOS, it is important to not allow your Mac to go into sleep mode:

Disable SSH

If you’re working over an SSH connection, it’s important to make sure the session isn’t running today. So modify the sshd_config file with:

  • TCPKeepAlive Yes

  • ClientAliveInterval 0

  • ClientAliveCountMax 0

sudo launchctl unload /System/Library/LaunchDaemons/ssh.plist
sudo launchctl load -w /System/Library/LaunchDaemons/ssh.plist

Enumeration of network processes

It is interesting to find processes that manage network data:

dtrace -n 'syscall::recv*:entry { printf("-> %s (pid=%d)", execname, pid); }' >> recv.log
#wait some time
sort -u recv.log > procs.txt
cat procs.txt

Or use netstat or bolsoflsof


lldb -o "target create `which some-binary`" -o "settings set target.env-vars DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib" -o "run arg1 arg2" -o "bt" -o "reg read" -o "dis -s \$pc-32 -c 24 -m -F intel" -o "quit"


  • AFL++ Works for CLI tools

  • Litefuzz It “just works” with macOS GUI tools. Note that some macOS applications have certain requirements, such as unique filenames, correct extension, needing to read files from the sandbox ( ~/Library/Containers/…

Some examples:

# iBooks
litefuzz -l -c "/System/Applications/ FUZZ" -i files/epub -o crashes/ibooks -t /Users/test/Library/Containers/ -x 10 -n 100000 -ez

# -l : Local
# -c : cmdline with FUZZ word (if not stdin is used)
# -i : input directory or file
# -o : Dir to output crashes
# -t : Dir to output runtime fuzzing artifacts
# -x : Tmeout for the run (default is 1)
# -n : Num of fuzzing iterations (default is 1)
# -e : enable second round fuzzing where any crashes found are reused as inputs
# -z : enable malloc debug helpers

# Font Book
litefuzz -l -c "/System/Applications/Font Book FUZZ" -i input/fonts -o crashes/font-book -x 2 -n 500000 -ez

# smbutil (using pcap capture)
litefuzz -lk -c "smbutil view smb://localhost:4455" -a tcp://localhost:4455 -i input/mac-smb-resp -p -n 100000 -z

# screensharingd (using pcap capture)
litefuzz -s -a tcp://localhost:5900 -i input/screenshared-session --reportcrash screensharingd -p -n 100000
Other related articles
Found an error?
If you find an error, take a screenshot and send it to the bot.