macOS Apps - Inspecting, debugging and Fuzzing
学习和实践 AWS 黑客技术:HackTricks 培训 AWS 红队专家 (ARTE) 学习和实践 GCP 黑客技术:HackTricks 培训 GCP 红队专家 (GRTE)
静态分析
otool & objdump & nm
jtool2 & Disarm
您可以从这里下载 disarm。
您可以在这里下载 jtool2或使用 brew
安装它。
jtool 已被 disarm 取代
代码签名 / ldid
Codesign
可以在 macOS 中找到,而 ldid
可以在 iOS 中找到
SuspiciousPackage
SuspiciousPackage 是一个有用的工具,可以检查 .pkg 文件(安装程序),并在安装之前查看其内容。
这些安装程序通常具有 preinstall
和 postinstall
bash 脚本,恶意软件作者通常利用这些脚本来 持久化 恶意软件。
hdiutil
此工具允许 挂载 Apple 磁盘映像 (.dmg) 文件,以便在运行任何内容之前进行检查:
It will be mounted in /Volumes
Packed binaries
检查高熵
检查字符串(几乎没有可理解的字符串,已打包)
MacOS 的 UPX 打包器生成一个名为 "__XHDR" 的部分
Static Objective-C analysis
Metadata
注意,用 Objective-C 编写的程序在编译成 Mach-O binaries 时 保留 其类声明。这样的类声明 包括:
定义的接口
接口方法
接口实例变量
定义的协议
注意,这些名称可能会被混淆,以使二进制文件的逆向工程更加困难。
Function calling
当在使用 Objective-C 的二进制文件中调用一个函数时,编译后的代码不会直接调用该函数,而是会调用 objc_msgSend
。这将调用最终的函数:
该函数期望的参数是:
第一个参数 (self) 是“指向 接收消息的类实例的指针”。更简单地说,它是正在调用该方法的对象。如果该方法是类方法,则这是类对象的一个实例(整体),而对于实例方法,self 将指向类的一个实例化对象。
第二个参数 (op) 是“处理消息的方法选择器”。同样,更简单地说,这只是 方法的名称。
剩余的参数是方法所需的任何 值(op)。
请参见如何在 ARM64 中 轻松获取此信息,使用 lldb
:
x64:
Argument | Register | (for) objc_msgSend |
1st argument | rdi | self: 正在调用该方法的对象 |
2nd argument | rsi | op: 方法的名称 |
3rd argument | rdx | 方法的第一个参数 |
4th argument | rcx | 方法的第二个参数 |
5th argument | r8 | 方法的第三个参数 |
6th argument | r9 | 方法的第四个参数 |
7th+ argument | rsp+ (在栈上) | 方法的第五个及以上参数 |
Dump ObjectiveC metadata
Dynadump
Dynadump 是一个用于类转储 Objective-C 二进制文件的工具。GitHub 指定了 dylibs,但这也适用于可执行文件。
在撰写时,这是目前效果最好的。
常规工具
class-dump
class-dump 是一个原始工具,用于生成 ObjetiveC 格式代码中的类、类别和协议的声明。
它很旧且未维护,因此可能无法正常工作。
ICDump
iCDump 是一个现代的跨平台 Objective-C 类转储工具。与现有工具相比,iCDump 可以独立于 Apple 生态系统运行,并且它提供了 Python 绑定。
静态 Swift 分析
对于 Swift 二进制文件,由于与 Objective-C 的兼容性,有时可以使用 class-dump 提取声明,但并不总是如此。
使用 jtool -l
或 otool -l
命令行,可以找到多个以 __swift5
前缀开头的部分:
您可以在此博客文章中找到有关这些部分存储的信息。
此外,Swift 二进制文件可能具有符号(例如,库需要存储符号,以便可以调用其函数)。符号通常以丑陋的方式包含有关函数名称和属性的信息,因此它们非常有用,并且有“去混淆器”可以获取原始名称:
动态分析
请注意,为了调试二进制文件,需要禁用 SIP(csrutil disable
或 csrutil enable --without debug
),或者将二进制文件复制到临时文件夹并移除签名(codesign --remove-signature <binary-path>
),或者允许调试该二进制文件(您可以使用这个脚本)。
请注意,为了在 macOS 上插桩系统二进制文件(例如 cloudconfigurationd
),必须禁用 SIP(仅移除签名是无效的)。
APIs
macOS 暴露了一些有趣的 API,提供有关进程的信息:
proc_info
:这是主要的 API,提供有关每个进程的大量信息。您需要以 root 身份获取其他进程的信息,但不需要特殊的权限或 mach 端口。libsysmon.dylib
:它允许通过 XPC 暴露的函数获取有关进程的信息,但需要具有com.apple.sysmond.client
权限。
Stackshot & microstackshots
Stackshotting 是一种用于捕获进程状态的技术,包括所有运行线程的调用栈。这对于调试、性能分析和理解系统在特定时间点的行为特别有用。在 iOS 和 macOS 上,可以使用多种工具和方法进行 stackshotting,例如工具 sample
和 spindump
。
Sysdiagnose
该工具(/usr/bini/ysdiagnose
)基本上从您的计算机收集大量信息,执行数十个不同的命令,例如 ps
、zprint
...
它必须以 root 身份运行,守护进程 /usr/libexec/sysdiagnosed
具有非常有趣的权限,例如 com.apple.system-task-ports
和 get-task-allow
。
其 plist 位于 /System/Library/LaunchDaemons/com.apple.sysdiagnose.plist
,声明了 3 个 MachServices:
com.apple.sysdiagnose.CacheDelete
:删除 /var/rmp 中的旧档案com.apple.sysdiagnose.kernel.ipc
:特殊端口 23(内核)com.apple.sysdiagnose.service.xpc
:通过Libsysdiagnose
Obj-C 类的用户模式接口。可以在字典中传递三个参数(compress
、display
、run
)
统一日志
MacOS 生成大量日志,这在运行应用程序时尝试理解它在做什么时非常有用。
此外,有一些日志将包含标签 <private>
以隐藏某些用户或计算机的可识别信息。然而,可以安装证书以披露此信息。请按照这里的说明进行操作。
Hopper
左侧面板
在 Hopper 的左侧面板中,可以看到二进制文件的符号(标签)、过程和函数的列表(Proc)以及字符串(Str)。这些并不是所有字符串,而是定义在 Mac-O 文件的多个部分中的字符串(如 cstring 或 objc_methname
)。
中间面板
在中间面板中,您可以看到反汇编代码。您可以查看原始反汇编、图形、反编译和二进制,通过单击相应的图标:
右键单击代码对象,您可以查看对/来自该对象的引用,甚至可以更改其名称(这在反编译的伪代码中无效):
此外,在中间下方,您可以编写 Python 命令。
右侧面板
在右侧面板中,您可以看到有趣的信息,例如导航历史(以便您知道如何到达当前状态)、调用图,您可以看到所有调用此函数的函数和所有此函数调用的函数,以及局部变量信息。
dtrace
它允许用户以极低的级别访问应用程序,并提供了一种方法,让用户能够跟踪 程序,甚至更改其执行流程。Dtrace 使用探针,这些探针分布在内核中,位于系统调用的开始和结束位置。
DTrace 使用 dtrace_probe_create
函数为每个系统调用创建一个探针。这些探针可以在每个系统调用的入口和出口点触发。与 DTrace 的交互通过 /dev/dtrace 进行,该接口仅对 root 用户可用。
要在不完全禁用 SIP 保护的情况下启用 Dtrace,您可以在恢复模式下执行:csrutil enable --without dtrace
您还可以使用您编译的 dtrace
或 dtruss
二进制文件。
dtrace 的可用探针可以通过以下方式获取:
探针名称由四个部分组成:提供者、模块、函数和名称(fbt:mach_kernel:ptrace:entry
)。如果您没有指定名称的某个部分,Dtrace 将将该部分应用为通配符。
要配置 DTrace 以激活探针并指定触发时要执行的操作,我们需要使用 D 语言。
更详细的解释和更多示例可以在 https://illumos.org/books/dtrace/chp-intro.html 找到。
示例
运行 man -k dtrace
列出 可用的 DTrace 脚本。示例:sudo dtruss -n binary
脚本
dtruss
kdebug
它是一个内核跟踪工具。文档代码可以在 /usr/share/misc/trace.codes
中找到。
像 latency
、sc_usage
、fs_usage
和 trace
这样的工具在内部使用它。
要与 kdebug
进行接口,使用 sysctl
通过 kern.kdebug
命名空间,使用的 MIB 可以在 sys/sysctl.h
中找到,相关函数在 bsd/kern/kdebug.c
中实现。
与 kdebug 进行交互的自定义客户端通常遵循以下步骤:
使用 KERN_KDSETREMOVE 移除现有设置
使用 KERN_KDSETBUF 和 KERN_KDSETUP 设置跟踪
使用 KERN_KDGETBUF 获取缓冲区条目数量
使用 KERN_KDPINDEX 从跟踪中获取自己的客户端
使用 KERN_KDENABLE 启用跟踪
调用 KERN_KDREADTR 读取缓冲区
要将每个线程与其进程匹配,调用 KERN_KDTHRMAP。
为了获取这些信息,可以使用 Apple 工具 trace
或自定义工具 kDebugView (kdv)。
注意,Kdebug 一次只能为一个客户提供服务。 因此,只有一个 k-debug 驱动的工具可以同时执行。
ktrace
ktrace_*
API 来自 libktrace.dylib
,它封装了 Kdebug
的 API。然后,客户端只需调用 ktrace_session_create
和 ktrace_events_[single/class]
来设置特定代码的回调,然后使用 ktrace_start
启动它。
即使在 SIP 激活 的情况下也可以使用这个。
您可以使用实用程序 ktrace
作为客户端:
Or tailspin
.
kperf
这用于进行内核级别的性能分析,并使用 Kdebug
调用构建。
基本上,检查全局变量 kernel_debug_active
,如果设置了它,则调用 kperf_kdebug_handler
,并传入 Kdebug
代码和调用的内核帧地址。如果 Kdebug
代码与所选的匹配,则获取配置为位图的“操作”(请查看 osfmk/kperf/action.h
以获取选项)。
Kperf 还有一个 sysctl MIB 表: (作为 root) sysctl kperf
。这些代码可以在 osfmk/kperf/kperfbsd.c
中找到。
此外,Kperf 的一部分功能位于 kpc
中,它提供有关机器性能计数器的信息。
ProcessMonitor
ProcessMonitor 是一个非常有用的工具,用于检查进程相关的操作(例如,监视一个进程正在创建哪些新进程)。
SpriteTree
SpriteTree 是一个打印进程之间关系的工具。
您需要使用类似 sudo eslogger fork exec rename create > cap.json
的命令监视您的 Mac(启动此终端需要 FDA)。然后,您可以在此工具中加载 json 以查看所有关系:
FileMonitor
FileMonitor 允许监视文件事件(例如创建、修改和删除),提供有关这些事件的详细信息。
Crescendo
Crescendo 是一个 GUI 工具,外观和感觉与 Windows 用户可能熟悉的 Microsoft Sysinternal 的 Procmon 相似。此工具允许开始和停止各种事件类型的记录,允许按文件、进程、网络等类别过滤这些事件,并提供以 json 格式保存记录事件的功能。
Apple Instruments
Apple Instruments 是 Xcode 开发工具的一部分 – 用于监视应用程序性能、识别内存泄漏和跟踪文件系统活动。
fs_usage
允许跟踪进程执行的操作:
TaskExplorer
Taskexplorer 是一个有用的工具,可以查看二进制文件使用的 libraries、它正在使用的 files 和 network 连接。 它还会检查二进制进程与 virustotal 的对比,并显示有关该二进制文件的信息。
PT_DENY_ATTACH
在 这篇博客文章 中,你可以找到一个关于如何 调试一个正在运行的守护进程 的示例,该守护进程使用 PT_DENY_ATTACH
来防止调试,即使 SIP 被禁用。
lldb
lldb 是 macOS 二进制 调试 的事实标准工具。
您可以通过在您的主文件夹中创建一个名为 .lldbinit
的文件,并添加以下行来设置 intel 风味:
在 lldb 中,使用 process save-core
转储进程
(lldb) 命令 | 描述 |
run (r) | 开始执行,直到命中断点或进程终止。 |
process launch --stop-at-entry | 从入口点开始执行并停止 |
continue (c) | 继续调试的进程的执行。 |
nexti (n / ni) | 执行下一条指令。此命令将跳过函数调用。 |
stepi (s / si) | 执行下一条指令。与 nexti 命令不同,此命令将进入函数调用。 |
finish (f) | 执行当前函数(“帧”)中的其余指令,返回并停止。 |
control + c | 暂停执行。如果进程已运行 (r) 或继续 (c),这将导致进程在当前执行位置停止。 |
breakpoint (b) |
breakpoint delete <num> |
help | help breakpoint #获取断点命令的帮助 help memory write #获取写入内存的帮助 |
reg | |
x/s <reg/memory address> | 将内存显示为以 null 结尾的字符串。 |
x/i <reg/memory address> | 将内存显示为汇编指令。 |
x/b <reg/memory address> | 将内存显示为字节。 |
print object (po) | 这将打印由参数引用的对象 po $raw
请注意,Apple 的大多数 Objective-C API 或方法返回对象,因此应通过“打印对象”(po)命令显示。如果 po 没有产生有意义的输出,请使用 |
memory | memory read 0x000.... memory read $x0+0xf2a memory write 0x100600000 -s 4 0x41414141 #在该地址写入 AAAA memory write -f s $rip+0x11f+7 "AAAA" #在地址中写入 AAAA |
disassembly | dis #反汇编当前函数 dis -n <funcname> #反汇编函数 dis -n <funcname> -b <basename> #反汇编函数 dis -c 6 #反汇编 6 行 dis -c 0x100003764 -e 0x100003768 # 从一个地址到另一个地址 dis -p -c 4 # 从当前地址开始反汇编 |
parray | parray 3 (char **)$x1 # 检查 x1 寄存器中 3 个组件的数组 |
image dump sections | 打印当前进程内存的映射 |
image dump symtab <library> |
|
调用 objc_sendMsg
函数时,rsi 寄存器保存方法的 名称,以 null 结尾的(“C”)字符串。要通过 lldb 打印名称,请执行:
(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:"
反动态分析
虚拟机检测
命令
sysctl hw.model
在 主机为 MacOS 时返回 "Mac",但在虚拟机中返回不同的内容。一些恶意软件通过玩弄
hw.logicalcpu
和hw.physicalcpu
的值来检测是否为虚拟机。一些恶意软件还可以根据 MAC 地址(00:50:56)检测机器是否为 VMware。
也可以通过简单的代码检查 进程是否正在被调试:
if(P_TRACED == (info.kp_proc.p_flag & P_TRACED)){ //进程正在被调试 }
它还可以调用
ptrace
系统调用,使用PT_DENY_ATTACH
标志。这 防止 调试器附加和跟踪。您可以检查
sysctl
或ptrace
函数是否被 导入(但恶意软件可以动态导入它)正如在这篇文章中所提到的,“击败反调试技术:macOS ptrace 变体”: “消息 Process # exited with status = 45 (0x0000002d) 通常是调试目标使用 PT_DENY_ATTACH 的明显迹象”
核心转储
如果满足以下条件,则会创建核心转储:
kern.coredump
sysctl 设置为 1(默认值)如果进程不是 suid/sgid 或
kern.sugid_coredump
为 1(默认值为 0)AS_CORE
限制允许该操作。可以通过调用ulimit -c 0
来抑制代码转储的创建,并通过ulimit -c unlimited
重新启用它们。
在这些情况下,核心转储根据 kern.corefile
sysctl 生成,并通常存储在 /cores/core/.%P
中。
模糊测试
ReportCrash 分析崩溃的进程并将崩溃报告保存到磁盘。崩溃报告包含可以 帮助开发人员诊断 崩溃原因的信息。
对于在每个用户 launchd 上下文中 运行的应用程序和其他进程,ReportCrash 作为 LaunchAgent 运行,并将崩溃报告保存在用户的 ~/Library/Logs/DiagnosticReports/
中。
对于守护进程、在系统 launchd 上下文中 运行的其他进程 和其他特权进程,ReportCrash 作为 LaunchDaemon 运行,并将崩溃报告保存在系统的 /Library/Logs/DiagnosticReports
中。
如果您担心崩溃报告 被发送到 Apple,可以禁用它们。如果不担心,崩溃报告可以帮助 找出服务器崩溃的原因。
睡眠
在 MacOS 中进行模糊测试时,重要的是不要让 Mac 进入睡眠状态:
systemsetup -setsleep Never
pmset, 系统偏好设置
SSH 断开连接
如果您通过 SSH 连接进行模糊测试,确保会话不会断开是很重要的。因此,请使用以下内容更改 sshd_config 文件:
TCPKeepAlive Yes
ClientAliveInterval 0
ClientAliveCountMax 0
Internal Handlers
查看以下页面 以了解如何找到哪个应用程序负责 处理指定的方案或协议:
macOS File Extension & URL scheme app handlersEnumerating Network Processes
这很有趣,可以找到管理网络数据的进程:
或使用 netstat
或 lsof
Libgmalloc
Fuzzers
适用于CLI工具
它“可以正常工作”与macOS GUI工具。注意一些macOS应用程序有一些特定要求,比如唯一的文件名、正确的扩展名,需要从沙盒中读取文件(~/Library/Containers/com.apple.Safari/Data
)...
一些示例:
更多模糊测试 MacOS 信息
参考文献
学习和实践 AWS 黑客技术:HackTricks 培训 AWS 红队专家 (ARTE) 学习和实践 GCP 黑客技术:HackTricks 培训 GCP 红队专家 (GRTE)
Last updated