用VirtualBox调试macOS内核

栏目: 服务器 · 发布时间: 6年前

内容简介:这篇文章会手把手教你如何用 VirtualBox 进行 macOS 内核的源码级调试。虽然这些步骤都是在 VirtualBox上进行的,但在 VMWare 上也是通用的,甚至更简单。如果你还没在 VirtualBox 上安装 macOS 镜像,你可以复用 VMWare 的 vmdk,也可以装个新的。重新安装系统需要 ISO 镜像,下面的命令可以将从如果你用了桥接,可以跳过这部分。

这篇文章会手把手教你如何用 VirtualBox 进行 macOS 内核的源码级调试。虽然这些步骤都是在 VirtualBox上进行的,但在 VMWare 上也是通用的,甚至更简单。

安装 VirtualBox 和 Sierra/High Sierra

如果你还没在 VirtualBox 上安装 macOS 镜像,你可以复用 VMWare 的 vmdk,也可以装个新的。重新安装系统需要 ISO 镜像,下面的命令可以将从 Mac app store 下载的 Sierra 转成 ISO。

macOS Sierra

$ export MAC_OS_IMG_DIR=/Applications/Install\ macOS\ Sierra.app
 
$ hdiutil attach "$MAC_OS_IMG_DIR/Contents/SharedSupport/InstallESD.dmg" -noverify -nobrowse -mountpoint /Volumes/installesd
 
$ hdiutil create -o /tmp/Sierra -size 8g -type SPARSE -layout SPUD -fs HFS+J
 
$ hdiutil attach /tmp/Sierra.sparseimage -noverify -nobrowse -mountpoint /Volumes/install
 
$ asr restore -source /Volumes/installesd/BaseSystem.dmg -target /Volumes/install -noprompt -noverify -erase
 
$ rm /Volumes/OS\ X\ Base\ System/System/Installation/Packages
 
$ cp -rp /Volumes/installesd/Packages /Volumes/OS\ X\ Base\ System/System/Installation/
 
$ cp -rp /Volumes/installesd/BaseSystem.dmg /Volumes/OS\ X\ Base\ System/BaseSystem.dmg
 
$ cp -rp /Volumes/installesd/BaseSystem.chunklist /Volumes/OS\ X\ Base\ System/BaseSystem.chunklist
 
$ hdiutil detach /Volumes/installesd
 
$ hdiutil detach /Volumes/OS\ X\ Base\ System/
 
$ hdiutil resize -sectors min /tmp/Sierra.sparseimage
 
$ hdiutil convert /tmp/Sierra.sparseimage -format UDTO -o /tmp/Sierra
 
$ rm /tmp/Sierra.sparseimage
 
$ mv /tmp/Sierra.cdr ~/Sierra.iso

macOS High Sierra

$ export MAC_OS_IMG_DIR=/Applications/Install\ macOS\ High\ Sierra.app
 
$ hdiutil create -o /tmp/HighSierra.cdr -size 7316m -layout SPUD -fs HFS+J
 
$ hdiutil attach /tmp/HighSierra.cdr.dmg -noverify -nobrowse -mountpoint /Volumes/install_build
 
$ asr restore -source "$MAC_OS_IMG_DIR/Contents/SharedSupport/BaseSystem.dmg" -target /Volumes/install_build -noprompt -noverify -erase
 
# 如果我们不拷贝安装文件,那么安装程序会从网络上下载镜像安装,如果我们拷贝镜像进入,安装时候会使用我们拷贝进入的安装文件,国内貌似只能本地安装
$ cp -rp "$MAC_OS_IMG_DIR/Contents/SharedSupport" /Volumes/OS\ X\ Base\ System/Install\ macOS\ High\ Sierra.app/Contents/
 
$ hdiutil detach /Volumes/OS\ X\ Base\ System
 
$ hdiutil convert /tmp/HighSierra.cdr.dmg -format UDTO -o /tmp/HighSierra.iso
 
$ mv /tmp/HighSierra.iso.cdr ~/HighSierra.iso
 
$ rm -rf /tmp/HighSierra.cdr.dmg

网络设置

如果你用了桥接,可以跳过这部分。

如果用的是 NAT,需要为 KDP 开启端口转发。点击“网络”,选择“高级” -> “端口转发”,将 localhost 41139/UDP 转发到虚拟机的 41139/UDP,就能够访问到虚拟机的 41139 端口了。

显存调整到最大

用VirtualBox调试macOS内核

取消软盘

用VirtualBox调试macOS内核

内存设置

内存至少4GB

用VirtualBox调试macOS内核

CPU设置

CPU至少2颗核心

用VirtualBox调试macOS内核

3D加速

开启3D加速,提高性能

用VirtualBox调试macOS内核

完成这一步,就可以安装系统了。

用VirtualBox调试macOS内核

点击磁盘工具

用VirtualBox调试macOS内核

显示出的界面如下

用VirtualBox调试macOS内核

选择下面的"VBOX HARDDISK Media",然后选择"抹掉",如下图:

用VirtualBox调试macOS内核

用VirtualBox调试macOS内核

之后关闭窗口,返回上层窗口,选择" 重新安装 macOS "。进入真正系统安装流程。

用VirtualBox调试macOS内核

用VirtualBox调试macOS内核

用VirtualBox调试macOS内核

用VirtualBox调试macOS内核

用VirtualBox调试macOS内核

安装完成后,从虚拟机中移除安装镜像

用VirtualBox调试macOS内核

重启之后进入如下界面

用VirtualBox调试macOS内核

我们需要安装启动引导

用VirtualBox调试macOS内核

上述执行的命令如下:

fs1:
 
cd "macOS Install Data"
 
cd "Locked Files"
 
cd "Boot Files"
 
boot.efi

稍后会出现如下界面:

用VirtualBox调试macOS内核

等待完成操作,就完成了引导部分的安装。重启之后,就是常规操作了。

用VirtualBox调试macOS内核

用VirtualBox调试macOS内核

安装 XCode

在你的主机上安装 XCode,通过 App store 安装最简单。 可以直接打开 XCode,也可以执行 sudo xcodebuild -license accept 接受 XCode license。

安装内核调试组件(KDK)

根据我们要调试的 macOS 版本从 Apple 开发者中心安装 KDK ,这里我的是10.12 build 16A323.

KDK 的安装目录是 /Library/Developer/KDKs ,提供的内核版本、符号、内核扩展都有 RELEASE、DEVELOPMENT、DEBUG 三种版本。不同之处在于 DEVELOPMENT 和 DEBUG 版比 RELEASE 版多了些断言和错误检查,DEBUG 版的最丰富。

注意:被调试的系统不需要安装 KDK。

修改 nvram boot-args

为了能够调试虚拟机,需要设置虚拟机上 nvram 中的 debug 项。除了 debug 的值外其他值也能被我们所用。下面是一些因垂斯挺的选项:

  • -v:以 verbose 模式启动系统。
  • kcsuffix:填写后缀以指定启动的内核。
  • pmuflags:貌似大家都推荐把这项值设为1。然而 Apple’s Kernel Programming Guide 已经明确指出管理电源的看门狗定时器“只在台式机、笔记本的 G4 版本和台式机的 G5 版本及之前有作用”,其他的看门狗定时器“只在 OS X Server 中启用”。所以,虽然设置了也不影响,但这个选项真没什么卵用。
  • debug:允许远程内核调试。 Apple docs 里有列出可用的标志。我常用的是 DB_LOG_PI_SCRN | DB_ARP | DB_NMI 。另外, control + option + command + shift + escape 可以触发不可屏蔽中断(NMI),继而引发调试器中断,超级方便。这对组合键跟 host key 的组合键冲突的时候用起来很难受,所以我把 host key 重新绑定成 command + right 了。

修改 nvram

在 VMware 里,可用这样修改 nvram:

$ sudo nvram boot-args="-v debug=0x144"

在 virtualbox 里没那么简单,因为一重启修改的值就没了。还好从 virtualbox 手册的 3.13.2 看到了希望:

不能在运行的虚拟机内部操作 EFI 变量了(如:在Mac OS X 虚拟机里运行 nvram 来设置“boot-args”不管用了)。不过,可以通过给虚拟机发送附加数据”VBoxInternal2/EfiBootArgs” 来设置“boot-args”。…

因此,我们需要关闭虚拟机,在主机上运行命令:

$ VBoxManage list vms # 列出下条命令使用的 UUID
"macOS 10.12.0" {9ad936f8-9360-44a6-ba3e-c4d92b4243e8}
 
$ VBoxManage setextradata 9ad936f8-9360-44a6-ba3e-c4d92b4243e8 VBoxInternal2/EfiBootArgs "-v debug=0x144"

如果想个性化定制部分信息,可以执行如下命令修改参数,主要是屏幕,CPU等的属性信息, 不是必须

$ VBoxManage list vms # 列出下条命令使用的 UUID
"macOS High Sierra" {c509e9db-80ac-4a8e-bf57-bdd6d1b7b741}
 
$ VBoxManage modifyvm c509e9db-80ac-4a8e-bf57-bdd6d1b7b741 --cpuidset 00000001 000306a9 04100800 7fbae3ff bfebfbff
 
$ VBoxManage setextradata c509e9db-80ac-4a8e-bf57-bdd6d1b7b741 "VBoxInternal/Devices/efi/0/Config/DmiSystemProduct" "MacBookPro11,3"
 
$ VBoxManage setextradata c509e9db-80ac-4a8e-bf57-bdd6d1b7b741 "VBoxInternal/Devices/efi/0/Config/DmiSystemVersion" "1.0"
 
$ VBoxManage setextradata c509e9db-80ac-4a8e-bf57-bdd6d1b7b741 "VBoxInternal/Devices/efi/0/Config/DmiBoardProduct" "Mac-2BD1B31983FE1663"
 
$ VBoxManage setextradata c509e9db-80ac-4a8e-bf57-bdd6d1b7b741 "VBoxInternal/Devices/smc/0/Config/DeviceKey" "ourhardworkbythesewordsguardedpleasedontsteal(c)AppleComputerInc"
 
$ VBoxManage setextradata c509e9db-80ac-4a8e-bf57-bdd6d1b7b741 "VBoxInternal/Devices/smc/0/Config/GetKeyFromRealSMC" 1
 

交换内核

前面我提到可以指定 kcsuffix 选项以调试不同版本的内核。内核文件在虚拟机的 /System/Library/Kernels 目录,然而这个目录受“系统完整性保护”机制保护(SIP)。所以要想使用 KDK 或者自己编译的内核,必须启动进入 recovery,把目标内核拷进 /System/Library/Kernels 目录,使 kextcache 失效,然后重新启动。

启动进入 recovery

在 VMware 里, cmd + R 就能进入 recovery 模式。virtualbox 要多几步。

启动虚拟机时,按住 F12 ,然后选择 Boot Manager -> EFI Internal Shell ,就会看到 EFI Shell 的欢迎界面。输入命令进入 recovery:

FS2:\com.apple.recovery.boot\boot.efi

进入 recovery 的界面,打开终端,操作目标内核,并将 kextcache 设置为无效。

# mv /path/to/kernels/kernel.development /System/Library/Kernels
# kextcache -invalidate /Volumes/Macintosh\ HD
# reboot

如果需要禁用 SIP,在重启之前执行:

# csrutil disable
Successfully disabled System Integrity Protection. Please restart the machine for the changes to take effect.

源码调试

下载要调试的版本的 XNU 源码。调试时,LLDB 会去 /Library/Caches/com.apple.xbs/Sources/xnu/xnu-... 目录寻找内核源码,所以可以把下载的源码放这个目录,也可以建一个符号链接指向源码目录。还有个方法是 设置 LLDB 的 target.source-map 变量:

lldb> settings set target.source-map /Library/Caches/com.apple.xbs/Sources/xnu/xnu-3789.1.32 /Users/kedy/Downloads/xnu-3789.1.32

早一些的 macOS 版本比如 Yosemite 就只能把源码放在 /SourceCache/xnu/ 里。

安装 LLDB

终于到调试器了。下面会举例用的是 RELEASE 内核。

为了在 Sierra KDK 里用 XNU LLDB 宏,执行 pip install macholib 安装 macholib 模块。粘贴执行加载内核文件时提示我们要执行的命令。(如下)

触发 NMI 后(或者等待设置了 DB_HALT 的调试器暂停启动进程时),执行 kdp-remote <ip> 连接到调试进程(若使用的是 NAT 端口转发,ip 是 localhost)。(如下)

$ lldb /Library/Developer/KDKs/KDK_10.11.2_15C50.kdk/System/Library/Kernels/kernel
(lldb) target create "/Library/Developer/KDKs/KDK_10.11.2_15C50.kdk/System/Library/Kernels/kernel"
warning: 'kernel' contains a debug script. To run this script in this debug session:
 
command script import "/Library/Developer/KDKs/KDK_10.11.2_15C50.kdk/System/Library/Kernels/kernel.dSYM/Contents/Resources/DWARF/../Python/kernel.py"
 
To run all discovered debug scripts in this session:
 
settings set target.load-script-from-symbol-file true
 
Current executable set to '/Library/Developer/KDKs/KDK_10.11.2_15C50.kdk/System/Library/Kernels/kernel' (x86_64).
(lldb) command script import "/Library/Developer/KDKs/KDK_10.11.2_15C50.kdk/System/Library/Kernels/kernel.dSYM/Contents/Resources/DWARF/../Python/kernel.py"
Loading kernel debugging from /Library/Developer/KDKs/KDK_10.11.2_15C50.kdk/System/Library/Kernels/kernel.dSYM/Contents/Resources/DWARF/../Python/kernel.py
LLDB version lldb-370.0.40
Swift-3.1
settings set target.process.python-os-plugin-path "/Library/Developer/KDKs/KDK_10.11.2_15C50.kdk/System/Library/Kernels/kernel.dSYM/Contents/Resources/DWARF/../Python/lldbmacros/core/operating_system.py"
settings set target.trap-handler-names hndl_allintrs hndl_alltraps trap_from_kernel hndl_double_fault hndl_machine_check _fleh_prefabt _ExceptionVectorsBase _ExceptionVectorsTable _fleh_undef _fleh_dataabt _fleh_irq _fleh_decirq _fleh_fiq_generic _fleh_dec
command script import "/Library/Developer/KDKs/KDK_10.11.2_15C50.kdk/System/Library/Kernels/kernel.dSYM/Contents/Resources/DWARF/../Python/lldbmacros/xnu.py"
xnu debug macros loaded successfully. Run showlldbtypesummaries to enable type summaries.
 
 
(lldb) kdp-remote 192.168.149.184
Version: Darwin Kernel Version 15.2.0: Fri Nov 13 19:56:56 PST 2015; root:xnu-3248.20.55~2/RELEASE_X86_64; UUID=17EA3101-D2E4-31BF-BDA9-931F51049F93; stext=0xffffff8007a00000
Kernel UUID: 17EA3101-D2E4-31BF-BDA9-931F51049F93
Load Address: 0xffffff8007a00000
Kernel slid 0x7800000 in memory.
Loaded kernel file /Library/Developer/KDKs/KDK_10.11.2_15C50.kdk/System/Library/Kernels/kernel
Target arch: x86_64
Instantiating threads completely from saved state in memory.
Loading 82 kext modules warning: Can't find binary/dSYM for com.apple.kec.corecrypto (491718F5-B509-31DC-92B5-6BAC95E3F494)
.warning: Can't find binary/dSYM for com.apple.kec.pthread (0888BA0A-49EE-394A-AEB1-1E5C6838A1F2)
 
(omitted...)
 
. done.
kernel was compiled with optimization - stepping may behave oddly; variables may not be available.
Process 1 stopped
* thread #2, name = '0xffffff800db8b000', queue = '0x0', stop reason = signal SIGSTOP
frame #0: 0xffffff8007bd655e kernel`Debugger(message=<unavailable>) at model_dep.c:1020 [opt]
1017
1018 doprnt_hide_pointers = old_doprnt_hide_pointers;
1019 __asm__("int3");
-> 1020 hw_atomic_sub(&debug_mode, 1);
1021 }
1022
1023 char *
(lldb)

瞧,macOS 内核源码调试这就开始了!

参考链接


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Effective C++

Effective C++

[美]Scott Meyers / 侯捷 / 电子工业出版社 / 2006-7 / 58.00元

《Effective C++:改善程序与设计的55个具体做法》(中文版)(第3版)一共组织55个准则,每一条准则描述一个编写出更好的C++的方式。每一个条款的背后都有具体范例支撑。第三版有一半以上的篇幅是崭新内容,包括讨论资源管理和模板(templates)运用的两个新章。为反映出现代设计考虑,对第二版论题做了广泛的修订,包括异常(exceptions)、设计模式(design patterns)......一起来看看 《Effective C++》 这本书的介绍吧!

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具