MZHeader/macdbg

GitHub: MZHeader/macdbg

macdbg 是一款基于 Textual TUI 封装系统 LLDB 的 macOS 调试器,专为逆向工程师提供多面板可视化调试、syscall/网络追踪和反调试绕过能力。

Stars: 2 | Forks: 0

# macdbg Apple 系统 LLDB 的 Textual TUI。它为你提供运行中进程的多面板视图。包含一个惰性的 syscall 和网络 tracer,能够突破反调试检测,并允许你就地编辑寄存器和内存。 ![主视图](https://static.pigsec.cn/wp-content/uploads/repos/cas/4a/4ae3e3012f17774dbb3ca94e09f79ccfe85d9573c50f9766adb475c296386d4e.png) ## 适用人群 适用于调试 macOS 二进制文件、但不擅长记忆 CLI 命令,并且希望获得更接近 x64dbg 体验的逆向工程师。 ## 环境要求 - 安装了 Xcode Command Line Tools 的 macOS (`xcode-select --install`) —— 这会提供 `/usr/bin/lldb` 和 `/usr/bin/python3`,macdbg 会直接使用这两个程序。 无需进行任何 `pip install`:LLDB 的 Python 绑定来自系统 LLDB(它们不在 PyPI 上),并且 UI 依赖项(textual、rich 及其相关组件)都已经打包在 [`vendor/`](vendor) 目录下,因此克隆下来的仓库是完全自包含的。 ## 安装 ``` git clone https://github.com/MZHeader/macdbg cd macdbg ./macdbg.sh /path/to/your/binary ``` `macdbg.sh` 是入口点:它会将 `PYTHONPATH` 指向系统的 LLDB 绑定 (`lldb -P`) 以及内置的依赖项,然后启动 TUI。请在克隆的目录中运行它。 ## Syscall 和网络 Tracer 觉得手动操作太麻烦?Ctrl+T 会在 libSystem 中的文件、进程和网络入口点上下断点。每次命中都会记录带有解析参数的调用,并且进程会自动继续执行,因此追踪过程不会中断执行。 ![追踪标签页](https://static.pigsec.cn/wp-content/uploads/repos/cas/ad/ad1b327d009c5f899b60bac8b4ec3785c9ce667464a2fa2f69ba49139b2172de.png) ## 反反调试 Ctrl+D 会打开一个包含多个独立绕过选项的菜单,默认全部关闭: ![防御菜单](https://static.pigsec.cn/wp-content/uploads/repos/cas/3e/3ef57f487949cbfcf414fb4a726df3fffee07615739c0d640e01f4eef714d789.png) - **PT_DENY_ATTACH 绕过** 会 hook `ptrace` 并在设置了拒绝标志时返回 `0`,因此内核永远看不到该调用。 - **直接 syscall ptrace 扫描** 用于捕获示例代码在跳过 libc 并直接内联执行 `svc #0x80` 时的相同拒绝行为。 - **Mach 异常端口伪装** 会 hook `task_get_exception_ports` 并返回零端口,因此没有任何迹象表明有程序附加。 - **用于用户断点的硬件断点** 可防止用户断点修改 `__TEXT` 段中的字节,这能够应对序言哈希检查。 - **用于 tracer 断点的硬件断点** 对 tracer 断点执行相同的操作。请在启用 tracer 之前开启此选项。 - **Fork 身份模式** 使 `fork` 返回 `0`,并使 `setsid` 返回一个正的伪造 sid,这样父进程就会在进程内运行子代码路径,且无需调试器重新附加。 - **出站 exec 沙箱** 会 hook `system`、`popen`、`execve`、`execvp`、`posix_spawn` 和 `posix_spawnp`。自动拦截模式会对每个调用返回 `-1`;交互模式则会在每次调用时暂停,并提示你选择允许还是拦截。 ### Fork 绕过功能应对的情况 这是 macOS 的守护进程化机制。父进程退出以看起来像正常终止,而子进程则重新挂载到 launchd 并与控制 TTY 分离,因此附加到父进程的调试器会失去可见性。如果其中任何一个调用失败,示例代码就会中止运行,不会执行 payload。 ``` pid_t pid = fork(); if (pid < 0) { return; } if (pid > 0) { _exit(0); } pid_t sid = setsid(); if (sid < 0) { return; } ``` 编译后的形式会直接检查符号位(`tst x0, #0x80000000` 或 `tbnz x0, #31, `),而不是将其与 `-1` 进行比较。Fork 身份模式让 `fork` 返回 `0`,并让 `setsid` 返回一个正值,从而使这两个分支都能进入 payload 执行块,而不会走向中止路径。 ### Exec 沙箱应对的情况 某些示例代码会通过杀死分析师的环境来增强自身对抗动态分析的能力。一种常见的模式是执行 `killall Terminal`。 ``` system("uname -a"); if (some_check()) { system("killall Terminal"); } decrypt_c2_config(); ``` 自动拦截模式会拦截所有出站的 exec 并返回 `-1`。交互模式对于实际的分析更有用:对于执行环境侦察的 `system("uname -a")`,可以选择允许,以便示例代码看到真实的输出。而对于 `system("killall Terminal")`,则进行拦截并返回 `-1`。示例代码会认为两者都已成功触发,并继续执行进入 payload。 ## 断点脚本 断点标签页会显示 ID、地址、符号、附加命令数、条件以及启用状态。右键点击任何断点行 → **编辑命令**,你将获得一个用于编辑 lldb 命令列表的全屏编辑器。Ctrl+S 保存,Esc 取消。每行一条 lldb 命令,就像你直接使用交互式的 `breakpoint command add` 命令但没有多行提示符时一样。 ![断点命令](https://static.pigsec.cn/wp-content/uploads/repos/cas/af/af8502ba8fc4c36f06225b0d2e921f16f7efd82b2d9367873aaf42c6142bf0a8.png) ## 编辑寄存器和内存 右键点击任意寄存器行并选择 **编辑值**。提示框中会预填充当前值,以便你查看将要覆盖的内容;如果你想全部替换,可以按 Ctrl+U 清空输入框。 ![编辑寄存器](https://static.pigsec.cn/wp-content/uploads/repos/cas/13/13d4f540bd5ab4214fa8e0b985b1da21c20d0bf2453340aef0c51888d3f5699f.png) 右键点击任意内存或堆栈行并选择 **编辑字节**。逻辑相同,输入框会预填充以空格分隔的十六进制格式的当前 16 个字节。 ![编辑内存](https://static.pigsec.cn/wp-content/uploads/repos/cas/8f/8f8713a99fa0dfeeaac310505a0c3425394e3668c228b4ab9fb6057039903d0f.png) ## 命令面板 Ctrl+P 会打开一个覆盖所有 lldb 命令的模糊搜索面板,并将 lldb 自身的帮助文本作为描述显示出来。 ![命令面板](https://static.pigsec.cn/wp-content/uploads/repos/cas/bc/bcc1fda130d8db77c8ad92ffe28e5ddd83c1921cc631760272f5d420b5c26019.png) ![模糊搜索](https://static.pigsec.cn/wp-content/uploads/repos/cas/6e/6e96903dc19ffca477203039e92a216c66c1133c91c227139273aae17b45c212.png) ## 主题 有很多主题可供选择 :) ![主题](https://static.pigsec.cn/wp-content/uploads/repos/cas/cb/cb8e4fe3c5643c6e768c1f067e165ded4a04875b115db6a4cf57e6b458487fdf.png) ## 快捷键 | 按键 | 操作 | |-----|--------| | F2 | 在 pc 处切换断点 | | F5 | 反汇编视图回到 pc(在浏览后使用) | | F6 | 执行直到返回(步出当前栈帧) | | F7 | 单步步入(指令) | | F8 | 单步步过(指令) | | F9 | 继续 | | Enter(在反汇编中) | 在内存面板中跟踪操作数地址 | | `:` | 聚焦控制台命令栏 | | Ctrl+B | 中断运行中的进程 | | Ctrl+D | 防御菜单 | | Ctrl+F | 搜索进程内存(默认为目标作用域;加上 `all:` 前缀可扩展到库) | | Ctrl+G | 聚焦内存跟踪地址输入框 | | Ctrl+K | 清空追踪标签页 | | Ctrl+P | 命令面板 | | Ctrl+T | 切换 tracer | | Ctrl+Y | 切换追踪作用域(严格 / 均衡 / 宽泛 / 关闭) | | Ctrl+C | 退出 | | 右键点击某一行 | 特定面板的上下文菜单 | 无论你在控制台中输入什么,都会被传入 `SBCommandInterpreter.HandleCommand` 进行处理。如果某个命令会触发交互式的 Y/N 提示(如 `run`、`br del`),封装器会在命令到达 lldb 之前自动替你进行答复。 ## 附加功能 - **内存搜索。** 默认仅限目标作用域(二进制文件加上堆和栈)。加上 `all:` 前缀可将其扩大到已加载的库。Ctrl+F Enter 可循环跳转到下一个匹配项。 - **基于单一二进制文件的持久化。** 存储于 `~/.macdbg/.json`。带有条件和命令脚本的断点、注释和书签在你下次打开同一个二进制文件时都会恢复。 - **反汇编注释。** 右键点击反汇编行并选择 **添加注释**。该注释会在不同会话间持久保留,并在反汇编行中呈现为加粗的金黄色 `← note`。 - **跳转箭头指示槽。** 为源地址和目标地址均可见的所有分支提供左侧控制流连线。在当前 pc 处,箭头颜色会根据寄存器值和 CPSR 标志实时评估为**绿色(如果分支将执行)**或**红色(如果不执行)**。 - **函数名称标记。** 在具有 lldb 符号信息的函数边界处显示 `▼ funcname:` 横幅行。 - **内联解引用提示。** `adrp + add` 和 `adrp + ldr` 指令对会获得一条亮蓝色的 `; = 0x… "resolved string"` 或 `; load @ 0x… symbol` 注释,直接在反汇编行中显示该地址实际解析出的内容。 - **在反汇编中跟踪。** 右键点击调用或分支操作数,或寄存器值,选择“在反汇编中跟踪”,即可在不移动 pc 的情况下浏览该地址。按 F5 可瞬间跳回原处。 - **调用栈标签页。** 显示所选线程的完整回溯信息,包含 pc、函数和模块。 - **监视窗口。** 位于内存和堆栈旁边的三个固定的迷你十六进制转储窗口。右键点击任何地址、寄存器值、内存行或字符串 → **在监视窗口 1/2/3 中跟踪** 即可将其固定。单步执行时地址保持不变;只有字节内容会刷新。非常适合用于监视内联解密 stub 逐字节填充堆栈缓冲区明文的过程。监视绑定会针对每个二进制文件持久化保存在 `~/.macdbg/.json` 中。右键点击监视面板可进行长度设置、添加标签和清空控制。
标签:DAST, LLDB, Python, 云资产清单, 动态调试器, 反反调试, 恶意软件分析, 无后门, 网络取证, 逆向工具, 逆向工程