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.
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 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
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:"
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/com.apple.ReportCrash.plist sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.ReportCrash.Root.plist #To re-enable crash reporting: launchctl load -w /System/Library/LaunchAgents/com.apple.ReportCrash.plist sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.ReportCrash.Root.plist
When fuzzing on MacOS, it is important to not allow your Mac to go into sleep mode:
systemsetup -setsleep Never
pmset, System Settings
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
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/com.apple.Safari/Data)…
Some examples:
# iBooks litefuzz -l -c "/System/Applications/Books.app/Contents/MacOS/Books FUZZ" -i files/epub -o crashes/ibooks -t /Users/test/Library/Containers/com.apple.iBooksX/Data/tmp -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.app/Contents/MacOS/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