當前位置:
首頁 > 新聞 > macOS內核調試介紹

macOS內核調試介紹

對於技術大咖來說,調試內核是一件非常有趣且具有挑戰的事情,除非調試過程中發生嚴重的異常,否則在一般情況下,他們是不會輕易放棄的。不過,技術開發商也知道這一點,他們也在想法設法讓內核調試變得越來越難。比如蘋果公司就已經採取了一些措施,讓macOS的內核調試變得越來越難,首先,將有關debug引導參數的文檔信息隱藏在lock和key下,然後將內核調試工具包轉移到Developer Account-only Downloads部分。雖然目前互聯網上有很多關於在macOS上調試內核的文章,但其中很多都已經不實用了,比如有的文章會告訴調試人員,通過設置的NVRAM啟動參數,但這個方法已經不再有效。甚至還有的文章停留在 「現在調試人員應該設置一個有效的調試會話」這樣的層面!在這篇文章中,我盡我所能為大家提供最準確和最新的調試信息,包括正確的調試命令,正確的boot-args參數,當然還有具體的調試示例。

開始在macOS上進行內核調試

調試時,要做的第一件事就是進行調試環境的設置和對測試設備的配置,調試人員需要有一個能進行調試的內核對象(在本文中,我使用的是iMac 2011作為調試器)和一個用於調試的設備(本文使用的是MacBook Pro 2009)。雖然調試人員可以使用我在以下討論的各種方式將兩者連接起來,但在本文的示例中,最好的方法(也是最可靠的)似乎是通過兩者之間的火線介面(firewire)(這是因為我的兩台設備都有firewire埠)而不是USB-C。

硬體部分設置好以後,我們還需要運行一些軟體。理論上調試人員可以調試RELEASE內核,但調試人員不是技術大咖,只是一個初學者時,調試Development內核就會輕鬆得多。默認情況下,macOS里會自帶一個位於/System/Library/ kernel /kernel中的RELEASE融合內核,其中kernel是Mach-O 64-bit executable x86_64。所以,我們可以通過導航到Apple Developer門戶並下載內核調試工具包,來獲得macOS版本的Development內核。令人驚訝的是,蘋果公司只是簡單將該套件置於正常的、免費的Apple開發者賬戶( Apple Developer Account)的lock中,按著我原來的想法,我還以為蘋果公司是將其置於付費的Apple開發者賬戶下載之中。

無論如何,一旦調試人員進入到Apple Developer Portal下載部分,調試人員就將看到如下內容。

這個過程非常的重要,這是因為調試人員會在以上的這個列表中,找到適合於他們的特定macOS版本的內核調試工具包,下載後,裡面包含調試人員將在調試中啟動的內核,如果內核與調試人員的macOS版本不匹配,它將無法啟動,甚至對對調試人員的文件、計算機等造成損害。

為macOS版本找到合適的內核調試工具包(Kernel Debug Kit)

要找到正確的內核調試工具包,調試人員必須知道他們的macOS版本和實際的內部版本號。調試人員可以很容易的看到你正在運行的macOS版本,只要打開蘋果的圖標,按下「關於這台Mac」,然後在窗口中閱讀出現的版本信息,例如「10.13.6版本」。

對於實際的內部版本號,調試人員可以單擊「關於這個Mac」窗口中的「版本」標籤,也可以運行終端命令sw_vers | grep BuildVersion。在本文的示例中,運行sw_vers | grep BuildVersion命令會輸出 「BuildVersion: 17G65」。

Last login: Sun Dec 2 03:58:16 on ttys000

Isabella:~ geosn0w$ sw_vers | grep BuildVersion

BuildVersion: 17G65

Isabella:~ geosn0w$

所以,就本文而言,我正在運行的macOS High Sierra(10.13.6)的版本號為17G65。查看剛剛下載的工具包,我可以立即找到和我的版本適應的工具,這樣我就可以下載包含安裝文件的.DMG文件,文件非常少。

準備調試器以供調試器調試

在調試器(即要調試其內核的設備)上下載調試工具包後,雙擊安裝DMG文件。在DMG文件中,調試人員將找到一個名為KernelDebugKit.pkg的文件,雙擊它並按照安裝嚮導進行操作。安裝完畢,會出現一個詢問調試人員macOS登錄密碼的界面。你可以不理會這個詢問,但請不要將此安裝程序刪掉,調試人員以後還會需要它。

安裝完成後的界面看起來如下:

安裝完成後,調試人員會被導航到/Library/Developer/KDKs。在那裡,調試人員將獲得一個名為KDK_YOUR_VERSION_BUILDNUMBER.kdk的文件夾。在本文的示例中,該文件夾名為KDK_10.13.6_17G65.kdk。打開文件夾,調試人員會在其中找到另一個名為「System」的文件夾。導航到文件夾後,先進入「Library」,然後進入「Kernels」。在該文件夾中,調試人員將找到一些內核二進位文件,一些Xcode調試符號文件(.dSYM)等。一般情況下,調試人員對名為kernel.development的文件感興趣。

將kernel.development複製並粘貼到在RELEASE內核二進位文件中運行的/ System / Library / Kernels /中。此時,調試人員的macOS上應該安裝應該有兩個內核,一個是RELEASE內核,另一個是DEVELOPMENT內核。

禁用調試器上的SIP

為了正確調試,調試人員可能需要在要調試其內核的計算機上禁用SIP(系統完整性保護)。為此,調試人員需在恢復模式下重新啟動計算機。要做到這一點,必須重新啟動設備,當調試人員看到啟動界面打開時,按CMD + R,等待幾秒鐘,使啟動進入恢復模式用戶界面,然後點擊「Terminal」繼續。

在恢復終端中,寫入csrutil disable,然後重新啟動計算機,此時只需正常啟動即可。

設置正確的NVRAM boot-args

由於蘋果公司一直在更新boot-args,因此調試人員在互聯網上找到的設置參數可能已經沒有用了。以下boot-args已經過測試,確定可以在2018年的macOS High Sierra運行。

注意!以下boot-args會假設調試人員直接通過火線介面或利用「Thunderbolt」(雷電)適配器通過火線介面執行操作。

如果調試人員在較舊的Mac上,員直接通過火線介面,那在終端中要運行的命令如下所示。

sudo nvram boot-args="debug=0x8146 kdp_match_name=firewire fwdebug=0x40 pmuflags=1 -v"

如果調試人員是利用「Thunderbolt」(雷電)適配器通過火線介面執行操作,那在終端中要運行的命令如下所示。

sudo nvram boot-args="debug=0x8146 kdp_match_name=firewire fwkdp=0x8000 fwdebug=0x40 pmuflags=1 -v"

區別在於fwkdp=0x8000會告訴OFireWireFamily.kext::AppleFWOHCI_KDP使用非內置firewire thunderbolt適配器進行調試會話。

此時,調試器可以在重新啟動後進行調試,但是讓我先解釋一下啟動參數所代表的具體含義:

·debug=0x8146:代表調試員可以進行調試了,並允許他們按下電源按鈕來觸發NMI, NMI代表不可屏蔽中斷(即CPU不能屏蔽) ,它用於調試器連接;

·kdp_match_name=firewire:允許調試人員通過FireWireKDP進行調試;

·fwkdp=0x8000 :正如我之前解釋的那樣,該參數是告訴kext使用thunderbolt連接到火線介面,如果你是直接使用火線介面,請不要設置該參數;

·fwdebug=0x40:通過啟用AppleFWOHCI_KDP驅動程序,得出更詳細的輸出信息,這對於排除調試過程中的故障很有用;

·muflags=1 :它會禁用看門狗定時器,看門狗定時器(WDT,Watch Dog Timer)是單片機的一個組成部分,它實際上是一個計數器,一般給看門狗一個數字,程序開始運行後看門狗開始倒計數。如果程序運行正常,過一段時間CPU應發出指令讓看門狗複位,重新開始倒計數。如果看門狗減到0就認為程序沒有正常工作,強制整個系統複位。

·-v :這個參數雖然最簡單的,但它會命令計算機啟動時要顯示詳細設備信息,而不是像平常那樣只顯示蘋果的徽標和啟動進度條。不僅在調試人員進行調試時,對於故障排除非常有用,而且在Bootloop(無限重啟)時也很有用。

除了本文要設置的這些引導參數之外,macOS還支持更多在/osfmk/kern/debug.h中定義的參數,具體的參數我已在下面列出,這些參數來自xnu-4570.41.2。

.../* Debug boot-args */#define DB_HALT 0x1//#define DB_PRT 0x2 -- obsolete#define DB_NMI 0x4

#define DB_KPRT 0x8

#define DB_KDB 0x10

#define DB_ARP 0x40

#define DB_KDP_BP_DIS 0x80//#define DB_LOG_PI_SCRN 0x100 -- obsolete#define DB_KDP_GETC_ENA 0x200#define DB_KERN_DUMP_ON_PANIC 0x400 /* Trigger core dump on panic*/#define DB_KERN_DUMP_ON_NMI 0x800 /* Trigger core dump on NMI */#define DB_DBG_POST_CORE 0x1000 /*Wait in debugger after NMI core */#define DB_PANICLOG_DUMP 0x2000 /* Send paniclog on panic,not core*/#define DB_REBOOT_POST_CORE 0x4000 /* Attempt to reboot after

* post-panic crashdump/paniclog

* dump.

*/#define DB_NMI_BTN_ENA 0x8000 /* Enable button to directly trigger NMI */#define DB_PRT_KDEBUG 0x10000 /* kprintf KDEBUG traces */#define DB_DISABLE_LOCAL_CORE 0x20000 /* ignore local kernel core dump support */#define DB_DISABLE_GZIP_CORE 0x40000 /* don"t gzip kernel core dumps */#define DB_DISABLE_CROSS_PANIC 0x80000 /* x86 only - don"t trigger cross panics. Only

* necessary to enable x86 kernel debugging on

* configs with a dev-fused co-processor running

* release bridgeOS.

*/#define DB_REBOOT_ALWAYS 0x100000 /* Don"t wait for debugger connection */...

準備調試器設備

現在既然調試器準備好了,我們就要準備配置運行調試器的設備。為此,我使用了另一台運行El Capitan的macOS設備,但這並不重要。還記得我們在調試器上安裝的內核調試工具包嗎?我們也需要在調試器設備上安裝它。不同之處在於我們不會移動內核,也不會在調試器上設置任何引導參數。我們只是要用到內核而已,因為我們將使用lldb來執行調試。如果調試人員熟悉GDB,則不必擔心,這裡有一個GDB -> LLDB命令表。

注意:即使內核調試工具包沒有運行與調試器相同的macOS版本,調試人員應該在調試器上安裝相同的macOS內核調試工具包,因為我們不會在調試器上啟動任何內核。

安裝工具包後,就可以調試內核了。

調試內核

首先,重新啟動調試器。此時,調試人員將看到它是在文本模式控制台被啟動的,該控制台會輸出詳細的啟動信息。等到屏幕上顯示「DSMOS出現!」,然後按一下電源按鈕,注意不要按住它不放。在調試器上,調試人員將看到它正在等待連接。

在調試器設備上的連接過程

打開終端窗口並啟動fwkdp -v,這是FireWire KDP工具,它將偵聽火線介面並將數據重定向到本地主機,這樣調試人員就可以將KDP目標設置為localhost或127.0.0.1,

MacBook-Pro-van-Mac:~ mac$ fwkdp -vFireWire KDP Tool (v1.6)Matched on device 0x00002403

Created plugin interface 0x7f9e50c03548 with result 0x00000000

Created device interface 0x7f9e50c0d508 with result 0x00000000

Opened device interface 0x7f9e50c0d508 with result 0x00000000

Added callback dispatcher with result 0x00000000

Created pseudo address space 0x7f9e50c0d778 at 0xf0430000

Address space enabled.

2018-12-02 05:51:05.453 fwkdp[5663:60796] CFSocketSetAddress listen failure: 102

Created KDP socket listener 0x7f9e50c0d940 with result 0

KDP Proxy and CoreDump-Receive dual mode active.

Use "localhost" as the KDP target in gdb.

Ready.

現在,在不關閉此窗口的情況下,打開另一個終端窗口並啟動lldb調試器,方法是將調試器上安裝的kernel.development文件作為內核調試工具包的一部分傳遞給它。請記住,內核可以在/Library/Developer/KDKs/中找到。在那裡,調試人員將會找到一個名為KDK_YOUR_VERSION_BUILDNUMBER.kdk的文件夾。在本文的示例中,該文件夾名為KDK_10.13.6_17G65.kdk,而我所需要的完整內核路徑

在本文的示例中,新終端窗口中的命令是xcrun lldb /Library/Developer/KDKs/KDK_10.13.6_17G65.kdk/System/Library/ kernel /kernel.development。

Last login: Sun Dec 2 10:37:51 on ttys000

MacBook-Pro-van-Mac:~ mac$ xcrun lldb /Library/Developer/KDKs/KDK_10.13.6_17G65.kdk/System/Library/Kernels/kernel.development

(lldb) target create "/Library/Developer/KDKs/KDK_10.13.6_17G65.kdk/System/Library/Kernels/kernel.development"

warning: "kernel" contains a debug script. To run this script in this debug session:

command script import "/Library/Developer/KDKs/KDK_10.13.6_17G65.kdk/System/Library/Kernels/kernel.development.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.13.6_17G65.kdk/System/Library/Kernels/kernel.development" (x86_64).

如上所示,lldb表示「內核」所包含的調試腳本。在現在打開的lldb窗口中,運行settings set target.load-script-from-symbol-file true來運行腳本。

Last login: Sun Dec 2 10:37:51 on ttys000MacBook-Pro-van-Mac:~ mac$ xcrun lldb /Library/Developer/KDKs/KDK_10.13.6_17G65.kdk/System/Library/Kernels/kernel.development(lldb) target create "/Library/Developer/KDKs/KDK_10.13.6_17G65.kdk/System/Library/Kernels/kernel.development"warning: "kernel" contains a debug script. To run this script in this debug session:command script import "/Library/Developer/KDKs/KDK_10.13.6_17G65.kdk/System/Library/Kernels/kernel.development.dSYM/Contents/Resources/DWARF/../Python/kernel.py"To run all discovered debug scripts in this session: settings set target.load-script-from-symbol-file trueCurrent executable set to "/Library/Developer/KDKs/KDK_10.13.6_17G65.kdk/System/Library/Kernels/kernel.development" (x86_64).(lldb) settings set target.load-script-from-symbol-file trueLoading kernel debugging from /Library/Developer/KDKs/KDK_10.13.6_17G65.kdk/System/Library/Kernels/kernel.development.dSYM/Contents/Resources/DWARF/../Python/kernel.pyLLDB version lldb-360.1.70settings set target.process.python-os-plugin-path "/Library/Developer/KDKs/KDK_10.13.6_17G65.kdk/System/Library/Kernels/kernel.development.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_deccommand script import "/Library/Developer/KDKs/KDK_10.13.6_17G65.kdk/System/Library/Kernels/kernel.development.dSYM/Contents/Resources/DWARF/../Python/lldbmacros/xnu.py"xnu debug macros loaded successfully. Run showlldbtypesummaries to enable type summaries.settings set target.process.optimization-warnings false(lldb)

現在,我們終於可以通過編寫kdp-remote localhost將lldb連接到 動態內核(live kernel)了。如果一切正常,內核應該已經連接成功,且應該出現以下這樣的輸出內容。一開始,許多文本會湧入調試人員的lldb窗口,不過過一會,內核進入休息狀態。

(lldb) kdp-remote localhostVersion: Darwin Kernel Version 17.7.0: Wed Oct 10 23:06:14 PDT 2018; root:xnu-4570.71.13~1/DEVELOPMENT_X86_64; UUID=1718D865-98B4-3F6E-97CF-42BF0D02ADD7; stext=0xffffff802e800000Kernel UUID: 1718D865-98B4-3F6E-97CF-42BF0D02ADD7Load Address: 0xffffff802e800000Kernel slid 0x2e600000 in memory.Loaded kernel file /Library/Developer/KDKs/KDK_10.13.6_17G3025.kdk/System/Library/Kernels/kernel.developmentLoading 152 kext modules warning: Can"t find binary/dSYM for com.apple.kec.Libm (BC3F7DA4-03EA-30F7-B44A-62C249D51C10).warning: Can"t find binary/dSYM for com.apple.kec.corecrypto (B081B8C1-1DFF-342F-8DF2-C3AA925ECA3A).warning: Can"t find binary/dSYM for com.apple.kec.pthread (E64F7A49-CBF0-3251-9F02-3655E3B3DD31).warning: Can"t find binary/dSYM for com.apple.iokit.IOACPIFamily (95DA39BB-7C39-3742-A2E5-86C555E21D67)[...].Target arch: x86_64.. done.Target arch: x86_64Instantiating threads completely from saved state in memory.Process 1 stopped* thread #2: tid = 0x0066, 0xffffff802e97a8d3 kernel.development`DebuggerWithContext [inlined] current_cpu_datap at cpu_data.h:401, name = "0xffffff80486a2338", queue = "0x0", stop reason = signal SIGSTOP frame #0: 0xffffff802e97a8d3 kernel.development`DebuggerWithContext [inlined] current_cpu_datap at cpu_data.h:401 [opt]

現在我們就連接到動態內核了,不過你可以看到此時進程已停止,這意味著內核已凍結,這就是為什麼啟動過程會在調試人員離開的位置停止。不過現在調試器已連接,我們只需做到一點就可以安全地繼續啟動進程到正常的macOS桌面。要做到這一點,我們只需解凍該過程,輸入「c」 即可,然後按Enter鍵直到啟動繼續(更多文本會出現在調試器屏幕上)。

(lldb) cProcess 1 resumingProcess 1 stopped* thread #2: tid = 0x0066, 0xffffff802e97a8d3 kernel.development`DebuggerWithContext [inlined] current_cpu_datap at cpu_data.h:401, name = "0xffffff80486a2338", queue = "0x0", stop reason = EXC_BREAKPOINT (code=3, subcode=0x0) frame #0: 0xffffff802e97a8d3 kernel.development`DebuggerWithContext [inlined] current_cpu_datap at cpu_data.h:401 [opt](lldb) c

一旦調試器完全在macOS中啟動,調試人員就可以在桌面上進行任何調試了。要運行調試器命令,調試人員必須再次觸發NMI,然後按一下電源按鈕。調試器屏幕將凍結,但調試器的lldb屏幕將處於運行狀態,此時調試人員可以在動態內核上讀/寫寄存器,讀/寫內存,反彙編地址,反彙編函數等。要將其解凍,請再次鍵入「c」 並在lldb屏幕上按一下Enter鍵。

內核調試示例

示例1:使用lldb讀取所有寄存器並將「AAAAAAAA」寫入其中一個寄存器

要讀取所有寄存器,按下電源按鈕並在打開的lldb窗口中輸入register read --all來觸發NMI:

(lldb) register read --allGeneral Purpose Registers: rax = 0xffffff802f40ba40 kernel.development`processor_master rbx = 0x0000000000000000 rcx = 0xffffff802f40ba40 kernel.development`processor_master rdx = 0x0000000000000000 rdi = 0x0000000000000004 rsi = 0xffffff7fb1483ff4 rbp = 0xffffff817e8ccd50 rsp = 0xffffff817e8ccd10 r8 = 0x0000000000000000 r9 = 0x0000000000000001 r10 = 0x00000000000004d1 r11 = 0x00000000000004d0 r12 = 0x0000000000000000 r13 = 0x0000000000000000 r14 = 0x0000000000000000 r15 = 0xffffff7fb1483ff4 rip = 0xffffff802e97a8d3 kernel.development`DebuggerWithContext + 403 [inlined] current_cpu_datap at cpu.c:220 kernel.development`DebuggerWithContext + 403 [inlined] current_processor at debug.c:463 kernel.development`DebuggerWithContext + 403 [inlined] DebuggerTrapWithState + 46 at debug.c:537 kernel.development`DebuggerWithContext + 357 at debug.c:537 rflags = 0x0000000000000046 cs = 0x0000000000000008 fs = 0x0000000000000000 gs = 0x0000000000000000 Floating Point Registers: fcw = 0x0000 fsw = 0x0000 ftw = 0x00 fop = 0x0000 ip = 0x00000000 cs = 0x0000 dp = 0x00000000 ds = 0x0000 mxcsr = 0x00000000 mxcsrmask = 0x00000000 stmm0 = stmm1 = stmm2 = stmm3 = stmm4 = stmm5 = stmm6 = stmm7 = xmm0 = xmm1 = xmm2 = xmm3 = xmm4 = xmm5 = xmm6 = xmm7 = xmm8 = xmm9 = xmm10 = xmm11 = xmm12 = xmm13 = xmm14 = xmm15 = Exception State Registers:3 registers were unavailable.(lldb)

現在讓我們對其中一個寄存器進行寫入,注意不要在未設置為0x0000000000000000的寄存器中寫入,因為調試人員將覆蓋某些內容,找一個空的進行寫入。在本文的示例中,R13是空的(r13 = 0x0000000000000000),所以我可以其中寫入來證明我的觀點。為了向寄存器寫入一個AAAs字元串,我可以將它的值替換為0x414141414141414141,其中0x41是ASCII字元「A」的十六進位表示。要覆蓋寄存器,我可以使用register write r13 0x4141414141414141命令。果然,如果我們再次讀取寄存器,就會發現已經覆蓋了。

(lldb) register write R13 0x4141414141414141(lldb) register read --allGeneral Purpose Registers: rax = 0xffffff802f40ba40 kernel.development`processor_master rbx = 0x0000000000000000 rcx = 0xffffff802f40ba40 kernel.development`processor_master rdx = 0x0000000000000000 rdi = 0x0000000000000004 rsi = 0xffffff7fb1483ff4 rbp = 0xffffff817e8ccd50 rsp = 0xffffff817e8ccd10 r8 = 0x0000000000000000 r9 = 0x0000000000000001 r10 = 0x00000000000004d1 r11 = 0x00000000000004d0 r12 = 0x0000000000000000 r13 = 0x4141414141414141

注意:當調試人員想要讀取單個寄存器時,他們不必輸入register read --all,調試人員可以簡單地用register read [register] 指定寄存器,例如register read r13。

示例2:在運行uname -a時更改內核版本和名稱

是時候在內核做一些真正的內存讀寫了,調試人員可能知道,終端中的uname -a命令會列出了內核的名稱、版本、版本號和構建日期,那我們如何將其更改為我們想要的內容呢?

首先,我們不知道內核存儲名稱、版本、版本號和構建日期信息的位置,因此我們要首先找到信息的存儲位置。為此,我們可以使用任何反彙編程序,如IDA Pro,Hopper Disassembler,Jtool,Binary Ninja等。

我在本文的示例中使用的是IDA Pro,要做的就是載入內核。在IDA Pro中開發文件,並讓IDA分析它。由於內核太大,分析可能需要一段時間,所以請耐心等待。當IDA完成時,輸出應該或多或少看起來像以下這樣。調試人員會知道IDA何時完成,因為它會在左下角顯示「AU: idle」。

現在,我們必須找到位置字元串。。我們知道,當在終端中執行uname -a命令時,內核名是Darwin,所以為了在IDA中查找位置字元串,我們要到頂部欄 - >查看 - >打開子視圖 - >字元串。這樣,我們將看到一個新的字元串窗口,如果調試人員在其中按CTRL + F,搜索框將顯示在底部,搜索Darwin,整個字元串都會顯示出來。

雙擊字元串,調試人員將被重定向到一個名為_version的常量。所以現在我們知道了,常量就是所謂的「version」,這也是我們要尋找的字元串。調試人員可能傾向於從IDA反彙編中複製常量的地址,但這是不對的,因為內核使用KASLR或內核地址空間布局隨機化,因此地址將不相同。但調試人員其實是不需要知道地址的,他們可以在調試器設備上用lldb輕鬆搞定。

此時得到的就是「version」常量的地址,它實際上非常簡單。按下電源按鈕觸發NMI(如果繼續該過程)並寫入print &(version)。

(lldb) print &(version)(const char (*)[101]) $8 = 0xffffff802f0f68f0(lldb)

在本文的示例中,const char version 位於地址0xffffff802f0f68f0。果然,當我列出字元數組時,它會顯示如下內容。

(lldb) print version(const char [101]) $9 = { [0] = "D" [1] = "a" [2] = "r" [3] = "w" [4] = "i" [5] = "n" [6] = " " [7] = "K" [8] = "e" [9] = "r" [10] = "n" [11] = "e" [12] = "l" [13] = " " [14] = "V" [15] = "e" [16] = "r" [17] = "s" [18] = "i" [19] = "o" [20] = "n" [21] = " " [22] = "1" [23] = "7" [24] = "." [25] = "7" [26] = "." [27] = "0" [28] = ":" [29] = " " [30] = "W" [31] = "e" [32] = "d" [33] = " " [34] = "O" [35] = "c" [36] = "t" [37] = " " [38] = "1" [39] = "0" [40] = " " [41] = "2" [42] = "3" [43] = ":" [44] = "0" [45] = "6" [46] = ":" [47] = "1" [48] = "4" [49] = " " [50] = "P" [51] = "D" [52] = "T" [53] = " " [54] = "2" [55] = "0" [56] = "1" [57] = "8" [58] = ";" [59] = " " [60] = "r" [61] = "o" [62] = "o" [63] = "t" [64] = ":" [65] = "x" [66] = "n" [67] = "u" [68] = "-" [69] = "4" [70] = "5" [71] = "7" [72] = "0" [73] = "." [74] = "7" [75] = "1" [76] = "." [77] = "1" [78] = "3" [79] = "~" [80] = "1" [81] = "/" [82] = "D" [83] = "E" [84] = "V" [85] = "E" [86] = "L" [87] = "O" [88] = "P" [89] = "M" [90] = "E" [91] = "N" [92] = "T" [93] = "_" [94] = "X" [95] = "8" [96] = "6" [97] = "_" [98] = "6" [99] = "4" [100] = ""}(lldb)

實際上,使用x 命令,我就可以將內存內容轉儲到該地址。

(lldb) x 0xffffff802f0f68f00xffffff802f0f68f0: 44 61 72 77 69 6e 20 4b 65 72 6e 65 6c 20 56 65 Darwin Kernel Ve0xffffff802f0f6900: 72 73 69 6f 6e 20 31 37 2e 37 2e 30 3a 20 57 65 rsion 17.7.0: We(lldb)

它看起來像是對0xffffff802f0f6900的繼續,於是我決定繼續轉儲。

(lldb) x 0xffffff802f0f69000xffffff802f0f6900: 65 72 73 69 6f 6e 20 36 39 2e 30 30 20 57 65 65 rsion 17.7.0: We0xffffff802f0f6910: 64 20 4f 63 74 20 31 30 20 32 33 3a 30 36 3a 31 d Oct 10 23:06:1(lldb)

此時,就可以看到44 61 72 77 69 6e了,這是Darwin這個詞的十六進位表示。如果我把它改成十六進位中的「GeoSn0w」,基本上可以改變內核名稱,所有的版本均是如此。

所以,我需要一個Text to Hex轉換器(一個非常好的文本字元轉換16進位小工具,它支持文本轉換16進位,也支持16進位轉換文本),這個工具可以從網上下載到。但需要注意的是,我們如果要寫入更長的字元串,就要先覆蓋一些原先的內容。注意,寫入的字元串不要超過現有字元串中的字元限制。

經過精心設計,我的十六進位字元串如下所示。

47 65 6f 53 6e 30 77 20 4b 65 72 6e 65 6c 20 56 = "GeoSn0w Kernel V"65 72 73 69 6f 6e 20 36 39 2e 30 30 20 57 65 65 = "ersion 69.00 Wee"

不過現在,我們還不能把它寫成這樣的兩個地址。因為我們必須在所有字元前面加上「0x」,最終的結果如下。

0x47 0x65 0x6f 0x53 0x6e 0x30 0x77 0x20 0x4b 0x65 0x72 0x6e 0x65 0x6c 0x20 0x56 = "GeoSn0w Kernel V"0x65 0x72 0x73 0x69 0x6f 0x6e 0x20 0x36 0x39 0x2e 0x30 0x30 0x20 0x57 0x65 0x65 = "ersion 69.00 Wee"

現在我們可以將位元組寫入內存,讓我們從第一個地址開始。在本文的示例中,命令看起來像這樣:

(lldb) memory write 0xffffff802f0f68f0 0x47 0x65 0x6f 0x53 0x6e 0x30 0x77 0x20 0x4b 0x65 0x72 0x6e 0x65 0x6c 0x20 0x56(lldb) x 0xffffff802f0f68f00xffffff802f0f68f0: 47 65 6f 53 6e 30 77 20 4b 65 72 6e 65 6c 20 56 GeoSn0w Kernel V0xffffff802f0f6900: 72 73 69 6f 6e 20 31 37 2e 37 2e 30 3a 20 57 65 rsion 17.7.0: We(lldb)

以下就是在0xffffff802f0f6900地址中,寫入字元串後的結果。

(lldb) memory write 0xffffff802f0f6900 0x65 0x72 0x73 0x69 0x6f 0x6e 0x20 0x36 0x39 0x2e 0x30 0x30 0x20 0x57 0x65 0x65(lldb) x 0xffffff802f0f69000xffffff802f0f6900: 65 72 73 69 6f 6e 20 36 39 2e 30 30 20 57 65 65 ersion 69.00 Wee0xffffff802f0f6910: 64 20 4f 63 74 20 31 30 20 32 33 3a 30 36 3a 31 d Oct 10 23:06:1(lldb)

現在讓我們在調試器上解凍內核:

(lldb) cProcess 1 resuming(lldb) Loading 1 kext modules warning: Can"t find binary/dSYM for com.apple.driver.AppleXsanScheme (79D5E92F-789E-3C37-BE0E-7D1EAD697DD9). done.Unloading 1 kext modules . done.Unloading 1 kext modules . done.(lldb)

在調試器終端運行uname -a命令:

此時,調試人員會看到顯示出來的字元串。

Last login: Sun Dec 2 07:12:19 on ttys000Isabella:~ geosn0w$ uname -aDarwin Isabella.local 17.7.0 GeoSn0w Kernel Version 69.00 Weed Oct 10 23:06:14 PDT 2018; root:xnu-4570.71.13~1/DEVELOPMENT_X86_64 x86_64Isabella:~ geosn0w$

以上就是我在macOS上進行內核調試的示例結果,希望調試人員喜歡它。不要忘記,在完成調試之後,調試人員應該再次將boot-args設置為stock,以便啟動正常的RELEASE內核。調試人員可以在調試器的終端上運行sudo nvram boot-args=""命令,然後進入/System/Library/ kernel /刪除kernel.development文件。

Isabella:~ geosn0w$ sudo nvram boot-args=""Password:Isabella:~ geosn0w$

現在在終端中輸入以下兩個命令,讓kextcache無效:

sudo touch /Library/Extensions

sudo touch /System/Library/Extensions

然後重新啟動,此時計算機將啟動正常的RELEASE內核。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 嘶吼RoarTalk 的精彩文章:

淺析紅藍對抗中攻擊方基礎設施的日誌聚合和監控
在Microsoft Edge中實現DOM樹

TAG:嘶吼RoarTalk |