7.5 KiB
Inspecting, debugging and Fuzzing Mac OS Software
Static Analysis
otool
otool -L /bin/ls #List dynamically linked libraries
otool -tv /bin/ps #Decompile application
SuspiciousPackage
****SuspiciousPackage is a tool useful to inspect .pkg files installers
and see what is inside before installing it.
These installers have preinstall
and postinstall
bash scripts that malware authors usually abuse to persist the malware.
hdiutil
This tool allows to mount Apple disk images **.dmg**
files to inspect them before running anything:
hdiutil attach ~/Downloads/Firefox\ 58.0.2.dmg
It will be mounted in /Volumes
Objective-C
When a function is called in a binary that uses objective-C, the compiled code instead of calling that function, it will call objc_msgSend
. Which will be calling the final function:
The params this function expects are:
- The first parameter
**self**
is "a pointer that points to the instance of the class that is to receive the message". Or more simply put, it’s the object that the method is being invoked upon. If the method is a class method, this will be an instance of the class objectas a whole
, whereas for an instance method, self will point to an instantiated instance of the class as an object. - The second parameter,
**op**
, is "the selector of the method that handles the message". Again, more simply put, this is just the name of the method. - The remaining parameters are any values that are required by the method
op
.
Argument | Register | for objc_msgSend |
---|---|---|
1st argument | rdi | self: object that the method is being invoked upon |
2nd argument | rsi | op: name of the method |
3rd argument | rdx | 1st argument to the method |
4th argument | rcx | 2nd argument to the method |
5th argument | r8 | 3rd argument to the method |
6th argument | r9 | 4th argument to the method |
7th+ argument | rsp+ (on the stack) | 5th+ argument to the method |
Dynamic Analysis
{% hint style="warning" %}
These tools require SIP to be disabled or to copy the binaries to a temporary folder and remove the signature with codesign --remove-signature <binary-path>
{% endhint %}
dtruss
dtruss -c ls #Get syscalls of ls
dtruss -c -p 1000 #get syscalls of PID 1000
ktrace
You can use this one even with SIP activated
ktrace trace -s -S -t c -c ls | grep "ls("
dtrace
It allows users access to applications at an extremely low level and provides a way for users to trace programs and even change their execution flow. Dtrace uses probes which are placed throughout the kernel and are at locations such as the beginning and end of system calls.
The available probes of dtrace can be obtained with:
dtrace -l | head
ID PROVIDER MODULE FUNCTION NAME
1 dtrace BEGIN
2 dtrace END
3 dtrace ERROR
43 profile profile-97
44 profile profile-199
The probe name consists of four parts: the provider, module, function, and name `fbt:mach_kernel:ptrace:entry`
. If you not specifies some part of the name, Dtrace will apply that part as a wildcard.
A more detailed explanation and more examples can be found in https://illumos.org/books/dtrace/chp-intro.html
Examples
- In line
#Count the number of syscalls of each running process
sudo dtrace -n 'syscall:::entry {@[execname] = count()}'
- script
syscall:::entry
/pid == $1/
{
}
#Log every syscall of a PID
sudo dtrace -s script.d 1234
syscall::open:entry
{
printf("%s(%s)", probefunc, copyinstr(arg0));
}
syscall::close:entry
{
printf("%s(%d)\n", probefunc, arg0);
}
#Log files opened and closed by a process
sudo dtrace -s b.d -c "cat /etc/hosts"
syscall:::entry
{
;
}
syscall:::return
{
printf("=%d\n", arg1);
}
#Log sys calls with values
sudo dtrace -s syscalls_info.d -c "cat /etc/hosts"
ProcessMonitor
****ProcessMonitor is a very useful tool to check the process related actions a process is performing for example, monitor which new processes a process is creating
.
fs_usage
Allows to follow 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
Fuzzing
ReportCrash
ReportCrash analyzes crashing processes and saves a crash report to disk. A crash report contains information that can help a developer diagnose the cause of a crash.
For applications and other processes running in the per-user launchd context, ReportCrash runs as a LaunchAgent and saves crash reports in the user's ~/Library/Logs/DiagnosticReports/
For daemons, other processes running in the system launchd context and other privileged processes, ReportCrash runs as a LaunchDaemon and saves crash reports in the system's /Library/Logs/DiagnosticReports
If you are worried about crash reports being sent to Apple you can disable them. If not, crash reports can be useful to figure out how a server crashed.
#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
Sleep
While fuzzing in a MacOS it's important to not allow the Mac to sleep:
- systemsetup -setsleep Never
- pmset, System Preferences
- KeepingYouAwake
SSH Disconnect
If you are fuzzing via a SSH connection it's important to make sure the session isn't going to day. So change 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
Internal Handlers
Checkout this section ****to find out how you can find which app is responsible of handling the specified scheme or protocol.
Enumerating Network Processes
This interesting to find processes that are managing 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 lsof