| name | macos-app-analysis |
| description | Use this skill whenever analyzing macOS binaries, debugging applications, performing security research on macOS apps, or fuzzing macOS software. Trigger for any macOS binary analysis, reverse engineering, crash investigation, security assessment, or when the user mentions inspecting, debugging, or testing macOS applications. Also use when investigating suspicious macOS binaries, analyzing crash reports, or performing malware analysis on macOS. |
macOS App Analysis
A comprehensive skill for inspecting, debugging, and fuzzing macOS applications and binaries.
Quick Start
analyze-macos-binary.sh /path/to/binary
check-signature.sh /path/to/binary
enumerate-network-procs.sh
setup-fuzzing.sh
Static Analysis
Binary Inspection Tools
otool - Native macOS binary analysis:
otool -L /path/to/binary
otool -tv /path/to/binary
otool -ov /path/to/binary
otool -l /path/to/binary
objdump - GNU binary utilities:
objdump -m --dylibs-used /path/to/binary
objdump -m -h /path/to/binary
objdump -m --syms /path/to/binary
objdump -m --full-contents /path/to/binary
objdump -d /path/to/binary
objdump --disassemble-symbols=_func --x86-asm-syntax=intel /path/to/binary
nm - Symbol listing:
nm -m /path/to/binary
nm --dyldinfo-only /path/to/binary
Disarm (jtool2 successor)
Download from: https://newosxbook.com/tools/disarm.html
export JCOLOR=1
ARCH=arm64e disarm -c -i -I --signature /path/to/binary
ARCH=arm64e disarm -c -l /path/to/binary
ARCH=arm64e disarm -c -L /path/to/binary
ARCH=arm64e disarm -c -S /path/to/binary
ARCH=arm64e disarm -c -d /path/to/binary
disarm -e filesets kernelcache.release.d23
JDEBUG=1 disarm -e filesets kernelcache.release.d23
disarm -r "code signature" /path/to/binary
disarm -e "code signature" /path/to/binary
Code Signing Analysis
codesign (macOS):
codesign -vv -d /path/to/binary 2>&1 | grep -E "Authority|TeamIdentifier"
codesign --verify --verbose /path/to/app.app
codesign -d --entitlements :- /path/to/binary
spctl --assess --verbose /path/to/app.app
codesign -s <cert-name-keychain> /path/to/binary
codesign --remove-signature /path/to/binary
ldid (iOS/macOS):
ldid -h /path/to/binary
ldid -e /path/to/binary
ldid -S /path/to/entitlements.xml /path/to/binary
Package and Disk Image Analysis
SuspiciousPackage - Inspect .pkg installers:
hdiutil - Mount disk images:
hdiutil attach ~/Downloads/file.dmg
hdiutil detach /Volumes/VolumeName
Detecting Packed Binaries
Look for these indicators:
- High entropy in binary sections
- Almost no readable strings
- UPX packer creates
__XHDR section on macOS
otool -l /path/to/binary | grep -A 5 "__XHDR"
strings /path/to/binary | wc -l
Objective-C Analysis
Understanding objc_msgSend
When Objective-C methods are called, they use objc_msgSend:
| Register | Parameter | Description |
|---|
| rdi (x64) / x0 (arm64) | self | Object receiving the message |
| rsi (x64) / x1 (arm64) | op | Method selector (name) |
| rdx (x64) / x2 (arm64) | arg1 | First method argument |
| rcx (x64) / x3 (arm64) | arg2 | Second method argument |
| r8 (x64) / x4 (arm64) | arg3 | Third method argument |
| r9 (x64) / x5 (arm64) | arg4 | Fourth method argument |
| stack | arg5+ | Additional arguments |
Dumping Objective-C Metadata
Dynadump (recommended):
./dynadump dump /path/to/binary
class-dump (legacy):
class-dump /path/to/binary > output.h
iCDump (modern, cross-platform):
import icdump
metadata = icdump.objc.parse("/path/to/binary")
print(metadata.to_decl())
Native tools:
nm --dyldinfo-only /path/to/binary
otool -ov /path/to/binary
objdump --macho --objc-meta-data /path/to/binary
Swift Analysis
Finding Swift Metadata Sections
jtool2 -l /path/to/binary | grep "__swift5"
otool -l /path/to/binary | grep "__swift5"
Common Swift sections:
__swift5_typeref - Type references
__swift5_reflstr - Reflection strings
__swift5_fieldmd - Field metadata
__swift5_capture - Capture descriptors
Demangling Swift Symbols
swift demangle "__T10MyApp10MyClassC10myMethodyyF"
Dynamic Analysis
Prerequisites
Disable SIP (System Integrity Protection):
csrutil disable
csrutil enable --without debug
csrutil enable --without dtrace
Remove binary signature (for debugging):
codesign --remove-signature /path/to/binary
lldb - Primary Debugging Tool
lldb /path/to/binary
lldb -p <pid>
lldb -n /path/to/binary --waitfor
settings set target.x86-disassembly-flavor intel
Common lldb commands:
| Command | Description |
|---|
run / r | Start execution |
process launch --stop-at-entry | Stop at entry point |
continue / c | Continue execution |
nexti / ni | Step over instruction |
stepi / si | Step into instruction |
finish / f | Run to function return |
control+c | Pause execution |
breakpoint set -n main | Set breakpoint on main |
breakpoint set -r '\[NSFileManager .*\]$' | Regex breakpoint |
breakpoint set -r . -s libobjc.A.dylib | All functions in library |
breakpoint delete <num> | Delete breakpoint |
breakpoint list / br l | List breakpoints |
breakpoint enable/disable <num> | Enable/disable breakpoint |
reg read | Read all registers |
reg read $rax | Read specific register |
reg write $rip 0x100035cc0 | Write to register |
x/s <address> | Display as string |
x/i <address> | Display as instruction |
x/b <address> | Display as bytes |
print object / po | Print Objective-C object |
memory read <address> | Read memory |
memory write <address> -s 4 0x41414141 | Write memory |
|
Printing Objective-C method names:
(lldb) x/s $rsi
(lldb) print (char*)$rsi
(lldb) reg read $rsi
DTrace - Dynamic Tracing
dtrace -l | head
sudo dtrace -n 'syscall:::entry {@[execname] = count()}'
sudo dtrace -s script.d <pid>
sudo dtrace -s b.d -c "cat /etc/hosts"
sudo dtruss -c /path/to/binary
sudo dtruss -p <pid>
sudo dtruss -n /path/to/binary
DTrace script example (save as syscalls.d):
syscall::open:entry
{
printf("%s(%s)", probefunc, copyinstr(arg0));
}
syscall::close:entry
{
printf("%s(%d)\n", probefunc, arg0);
}
Kernel Tracing Tools
ktrace (works with SIP enabled):
ktrace trace -s -S -t c -c /path/to/binary | grep "binary("
fs_usage - File system monitoring:
fs_usage -w -f filesys ls
fs_usage -w -f network curl
kdebug - Kernel tracing facility:
- Trace codes:
/usr/share/misc/trace.codes
- Tools:
latency, sc_usage, fs_usage, trace
- Note: Only one kdebug client at a time
Process Monitoring Tools
ProcessMonitor (Objective-See):
TaskExplorer (Objective-See):
FileMonitor (Objective-See):
SpriteTree - Process relationship visualization:
sudo eslogger fork exec rename create > cap.json
Crescendo - Sysinternals-style monitoring:
System Diagnostics
sysdiagnose - Comprehensive system dump:
sudo /usr/bin/sysdiagnose
Stackshots - Process state capture:
sample <pid> <seconds> <outputfile>
spindump <pid>
Unified Logs:
log show --predicate 'process == "AppName"' --last 1h
log stream --predicate 'process == "AppName"'
To reveal <private> data, install disclosure certificate (see: https://superuser.com/questions/1532031/how-to-show-private-data-in-macos-unified-log)
Anti-Debugging Detection
Common Techniques
VM Detection:
sysctl hw.model
sysctl hw.logicalcpu
sysctl hw.physicalcpu
Debugger Detection:
Import Analysis:
otool -L /path/to/binary | grep -E "sysctl|ptrace"
nm /path/to/binary | grep -E "sysctl|ptrace"
Core Dumps
Configuration
sysctl kern.coredump
sysctl kern.sugid_coredump
sysctl kern.corefile
ulimit -c 0
ulimit -c unlimited
Core Dump Locations
- User processes:
/cores/core.%P
- Default pattern:
kern.corefile sysctl
- Check:
ls -la /cores/
Fuzzing
Crash Report Analysis
ReportCrash locations:
- User apps:
~/Library/Logs/DiagnosticReports/
- System daemons:
/Library/Logs/DiagnosticReports/
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
Re-enable:
launchctl load -w /System/Library/LaunchAgents/com.apple.ReportCrash.plist
sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.ReportCrash.Root.plist
Preventing Sleep During Fuzzing
sudo systemsetup -setsleep Never
pmset sleep 0
SSH Session Persistence
Edit /etc/ssh/sshd_config:
TCPKeepAlive yes
ClientAliveInterval 0
ClientAliveCountMax 0
sudo launchctl unload /System/Library/LaunchDaemons/ssh.plist
sudo launchctl load -w /System/Library/LaunchDaemons/ssh.plist
Fuzzing Tools
AFL++ - CLI tools:
afl-fuzz -i input_dir -o output_dir -- /path/to/binary @@
Litefuzz - GUI apps (recommended for macOS):
litefuzz -l -c "/path/to/app.app/Contents/MacOS/AppName FUZZ" \
-i input_dir -o crashes_dir -n 100000 -ez
litefuzz -l -c "/System/Applications/Books.app/Contents/MacOS/Books FUZZ" \
-i files/epub -o crashes/ibooks \
-t ~/Library/Containers/com.apple.iBooksX/Data/tmp \
-x 10 -n 100000 -ez
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
litefuzz -lk -c "smbutil view smb://localhost:4455" \
-a tcp://localhost:4455 -i input/mac-smb-resp -p -n 100000 -z
Memory Error Detection
libgmalloc - Debug malloc:
lldb -o "target create \`which 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"
Network Process Enumeration
dtrace -n 'syscall::recv*:entry { printf("-> %s (pid=%d)", execname, pid); }' >> recv.log
sort -u recv.log > procs.txt
netstat -an | grep LISTEN
lsof -i -P
lsof -i :<port>
Hopper Disassembler
Interface Overview
Left Panel:
- Labels: Binary symbols
- Proc: Procedures and functions
- Str: Strings from binary sections
Middle Panel:
- Raw disassembly
- Control flow graph
- Decompiled pseudocode
- Binary view
- Python console (bottom)
Right Panel:
- Navigation history
- Call graph (callers/callees)
- Local variables
Useful Actions
- Right-click code object → References to/from
- Right-click → Rename symbol
- Use Python console for custom analysis
Best Practices
- Always work on copies - Never modify original binaries
- Document findings - Keep notes on analysis steps and discoveries
- Use multiple tools - Cross-verify findings with different analyzers
- Check entitlements - Review what permissions the binary requests
- Monitor side effects - Watch file, network, and process activity
- Preserve evidence - Save crash reports, logs, and core dumps
- Test in isolated environment - Use VMs or sandboxed environments for suspicious binaries
Common Workflows
Quick Binary Analysis
file /path/to/binary
otool -L /path/to/binary
codesign -vv -d /path/to/binary
nm /path/to/binary | head -50
strings /path/to/binary | grep -iE "ptrace|debug|vmware|virtual"
sudo dtruss -c /path/to/binary
Malware Analysis
codesign --remove-signature /path/to/malware
./analyze-macos-binary.sh /path/to/malware
lldb /path/to/malware
(lldb) process launch --stop-at-entry
(lldb) breakpoint set -n main
(lldb) continue
sudo ProcessMonitor
sudo FileMonitor
sudo dtrace -n 'syscall::recv*:entry { printf("%s (pid=%d)\n", execname, pid); }'
Fuzzing Setup
sudo systemsetup -setsleep Never
mkdir -p fuzz_input
litefuzz -l -c "/path/to/app FUZZ" -i fuzz_input -o crashes -n 1000000 -ez
watch -n 1 'ls -lt crashes/ | head -10'
References