📋 文章大綱
什麼是 Mac EFI 密碼鎖定?
當 Mac 電腦被開機 BIOS (EFI) 密碼鎖住時,如果不知道密碼要強制解開,需要使用特定方法。本文將深入探討 Mac EFI 韌體密碼的運作原理、SCBO 解鎖文件的神秘機制,以及完整的逆向工程分析。
Mac EFI 密碼解鎖方法總覽
依年份分類的解鎖方式
2011年以前的 Mac:可使用清 PRAM 方式 (command+option+p+r)
2011~2017 的 Mac:則可以用下面方法破解:
- 暴力破解法:Mac EFI Password 由於沒有密碼輸入限制,可用模擬 USB 鍵盤的 Teensy 或密碼破解硬體暴力破解。時效很長,成功率低。
- 物理改寫法:直接吹下或用檢測頭物理改寫 Mac EFI BIOS EEPROM,搜索 $SVS (0x24 0x53 0x56 0x53)。將 FF 填入十六進位值寫滿。ROM 中以「$SVS」開頭的每個區塊都要這樣清除寫入。

圖片出自:GitHub Gist
官方解鎖流程
官方解法是:如果要強制解開,請準備發票、購買證明到維修中心,維修工程師會協助解開。
維修工程師會透過特殊按法取得 33 位交換碼與序號資料,送給蘋果 GSX 維修系統。GSX 系統會回傳 SCBO 檔案,將此 324 byte SCBO 檔案拷入外接硬碟並選擇其開機,即可重設 Mac EFI password。
這方法其實同於一般 PC 解密碼機制,可參考 BIOS-PW.org,不過 Mac 做的比較複雜。
SCBO 解鎖文件是什麼?
本文討論的是 2016 年時就有黑產服務方不用銷售證明可做到官方解鎖服務的現象。
核心問題:Apple EFI Recovery Password 算法被攻破了嗎?是技術上的漏洞還是流程上的漏洞?
以下翻譯原文 MacReversing – Apple EFI firmware passwords and the SCBO myth,參考翻譯
取得 33 位交換碼
首先你要取得被上鎖機器的 33 位交換碼,要照下面操作:

SCBO 文件如何生成
正規來講,授權維修中心發送給蘋果支持部門就能得到 SCBO 文件,但你必須提供一些關鍵信息。
要獲得這些信息,你必須在出現韌體密碼提示屏幕時,同時按下 SHIFT+CONTROL+OPTION+COMMAND+S,從而得到一個字符串。這就是蘋果支持部門所要求提供的字符串,同時,它跟我們在 SCBO 文件裡面看到的字符串一模一樣。
前面數字是機器序列號,而後面的十六位數字是每次設置、刪除或修改固件密碼時現場生成的一個數值(nonce)。
SCBO 文件結構分析
SCBO 樣本文件:SCBO_original.zip
(SHA256(SCBO_original)=fad3ea1c8ffa710c243957cc834ac1427af0ea19503d9fc7839626f6cac4398b)

上面為解鎖檔案全部內容:
- 前四個字節為字符串 ‘SCBO’,這是一個 Magic Number(0x4F424353)
- 在幾個字節之後,可以看到另一個字符串,前面是機器序號
- 序號後數據暫時都是未知數
- 檔案總長度為 324 bytes
能否修改 SCBO 文件重用?
能不能通過修改和重復利用同一個樣本 SCBO 文件來重置任意其他 Mac 的固件密碼呢?
答案是否定的。如果我們在測試 Mac 上建立一個固件密碼,必須生成所需要的字符串,然後對 SCBO 進行相應的修改。計算機將處理該文件並重新設置系統,但密碼不會重置。
這為我們提供了另一個信息:這個 SCBO 的內容會進行某種完整性檢驗。如果沒有這種檢驗的話,任何人都可以修改 SCBO 內容。
🔑 OSSLab 關鍵發現
這些 SCBO 解鎖檔案是利用流程漏洞取得:
- SCBO 檔案非單純 hash 換算破解,其密鑰是由 RSA 2048 簽章產生,最終可對 Apple 保護的 BIOS 區作 EFI password 區域做擦除
- 上面機制無明顯漏洞
- 判定此為流程上的漏洞而非技術上的漏洞
EFI 韌體逆向工程分析
提取 EFI 二進制代碼
首先,我們需要提取出所有 EFI 二進制代碼,這有兩種途徑:
- 從存有 EFI 內容的 Flash 芯片轉儲中提取
- 從 EFI 更新文件中發現的 SCAP 文件中提取
MAC 韌體庫,如果你需要早期的 EFI 更新,或想驗證自己的 EFI 閃存是否遭到修改的話,可以輕鬆從這裡下載所需的更新。
利用 UEFITool,你可以輕鬆地從轉儲和 SCAP 中提取內容(如果需要大量提取所有文件的話,最好使用 UEFIExtract 工具代替)。如果需要從 NVRAM 分區提取內容,則必須使用 UEFITool 的 new_engine 分支。
尋找逆向突破口
本文的目標 Mac 是一個 MacBookPro8.2 系統,並且所有文件都是從 MBP81_0047_2CB_LOCKED.scap 這個固件更新文件中提取的。
開始的時候,最好的線索自然是 SCBO 文件的魔法值了,因為它必然會在代碼中的某個地方進行相應的檢查。對付這種類型的任務,最好的工具是 bgrep。我們想要查找的字節是 5343424F,即「SCBO」的魔法值。
只有一個符合要求,即一個 DXE 階段的二進制文件,其 GUID 為 9EBA2D25-BBE3-4AC2-A2C6-C87F44A1278C。請注意,在 (U)EFI 的世界裡是沒有文件名這一說的,所有的東西都是通過一個 128 位的 GUID 來引用的。

下面我們把這個二進制代碼加載到反彙編器中,嘗試了解其中到底發生了什麼:

這意味著,我們在這個問題上找到了一個好的切入點,下面要進一步了解這個函數的去向何方,以及它是如何被調用的。
SCBO 文件使用流程
重設 EFI 密碼步驟
照上面方法回傳給黑服務得到 SCBO 文件時,要照下面流程重設 EFI 密碼:
- 格式化外接硬碟為 GUID 分區和 MacOS 擴展格式。將它命名為 Firmware 或任意名稱
- 將名為「SCBO」的二進制文件拖拽到桌面
- 在終端執行下列命令:
cp ~/Desktop/SCBO /Volumes/Firmware/.SCBO
- 在終端執行以下命令:
cp ~/Desktop/SCBO /Volumes/Firmware/._SCBO
- 彈出閃存驅動器
- 關閉電腦
- 把閃存驅動器插入到計算機
- 啟動電腦,同時按住 Option 鍵
- 你應該看到鎖形符號,一會兒後,電腦應重新啟動,顯示啟動管理器
這給了我們一條重要的線索,我們應該去尋找具有文件系統訪問權限的代碼,然後去讀取這兩個文件之一。

逆向工具推薦
逆向 (U)EFI 的二進制文件是很煩人的事情,因為每個外部函數是函數指針,所以反彙編輸出不是很簡明易懂。為此,我們可以藉助於 Snare 創建的 ida-efiutils,它是一組腳本,可以通過重命名函數指針、偏移量和結構來改善反彙編輸出。
另外還有 EFISwissKnife 插件,可以完成更多的任務,如給已知的函數提供原型和文檔註釋,生成統計數據,以及從已安裝和使用的協議中提取信息並保存到數據庫中。
下圖為無任何插件幫助下 IDA 對 start() 函數的反彙編輸出結果:

運行 EFISwissKnife 後的結果:

從上面可以看到,它識別了兩種被調用到的 (U)EFI 引導服務:SetWatchdogTimer 和 LocateProtocol,同時,也對 LocateProtocol 使用的 GUID 給出了相應的註釋。

SCBO 文件處理機制
由於逆向工程的藝術成分較多,科學成分較少,我會首先告訴你發生了什麼,然後進一步介紹它是如何發生的。
首先,此 EFI 二進制文件安裝時,會有一個事件通知。USB 閃存驅動器插入時,會觸發該通知,並調用一個回調函數。
這個回調函數的任務之一,是嘗試從閃存中讀取 SCBO 文件,並驗證它的格式是否正確(例如檢查幻數等)。如果 SCBO 的內容看起來沒有問題,然後將通過 GUID 5D62B28D-6ED2-40B4-A560-6CD79B93D366 設置一個新的 EFI NVRAM 變量 「.SCBO_0000」。
事件通知代碼可以在 start() 函數中找到:

在這段代碼中,最有趣的當屬 CreateEvent 服務的第三個參數,即 notifyfunction。當事件觸發時,就會執行這個回調函數。

文件系統操作分析
現在讓我們開始考察回調函數的代碼。它試圖通過 GUID 為 75FAB4B4-6AC1-429A-A000-6B0B95E71CA1 的代碼來定位一個新協議。

這個函數內部,我們找到了一些文件方面的操作:

上面的代碼負責打開 USB 閃存驅動器卷,以便能夠讀取其中的內容。



我們可以觀察到,EFI_FILE_PROTOCOL 已經提供了讀寫文件系統上的文件所需的基本功能。
SCBO 讀取流程
先前討論的反彙編代碼,會先試圖打開根卷,如果成功的話,就會使用返回的句柄嘗試從 USB 閃存驅動器卷打開「.SCBO」文件。如果打開了該文件,它就會使用 EFI_FILE_PROTOCOL 的 GetInfo 函數查看該文件的大小,然後分配相應內存,最終將其內容讀入分配的緩衝區中。

該文件分兩步讀取,先讀入前面的 12 個字節,這實際上是 SCBO 頭部的大小。如果頭部內容無誤的話,則繼續讀取其餘的內容。

該 SCBO 文件支持多個數據單元,這意味著可能允許單個 USB 閃存驅動器重置多個 MAC 的密碼。這對於一個必須重置許多台 Mac 的系統管理員來說非常有用。
序列號和 Nonce 驗證
如果 SCBO 內容讀取成功,接下來就會調用來自另一個協議的函數,該協議將驗證該 Mac 的序列號和當前 nonce 是否與該 SCBO 文件中的內容相匹配。記住,每次修改固件密碼時,nonce 都會改變。

如果序列號和 nonce 值通過了檢查,將在 EFI NVRAM 中新建一個名為「.SCBO_0000」的變量,如果在 SCBO 文件中沒有更多數據單元要處理的話,系統就會重置。新變量保存了 SCBO 文件中除 12 字節的頭部之外的所有數據,也即總長度為 312 字節。


固件密碼功能實現原理
EFI 密碼存儲機制
EFI 變量包含的固件密碼信息是「CBF2CC32」。該密碼是利用 SHA256 以 MAC(Message Authentication Code)來存放的,其中包含可變的回合數。
暴力破解固件密碼方法不適應於長度超過四位數的密碼,因為回合數越高,就越不可能在可接受的時間內破解出來。下面的結構就是描述該變量的內容的:

給定該結構後,暴力破解工具只需要通過 IOKit 檢索這些信息就可以開始破解過程了,直到密碼與當前哈希匹配為止。對於四位數密碼來說,這個過程只需要一兩分鐘的時間。
Main() 函數分析

Main() 函數非常簡單:首先,將表指針 BootServices 和 RunTimeServices 存放在本地變量中,然後調用一個函數,最後安裝協議。

安裝的這個協議包含有七個函數指針。該函數是由第一個二進制文件調用的,偏移量是 0x18.sub_10000828。
第一列存放使用此協議的 EFI 二進制代碼的 GUID。涉及 EFI 固件密碼驗證的二進制代碼是 2D61B52A-69EF-497D-8317-5574AEC89BE4。
如果設法修改這個函數以使其總是返回零,將其重新封裝到固件轉儲中,刷新固件,這樣,任何固件密碼都能被接受。
新思路:繞過密碼驗證
協議函數 sub_10000704 會檢索變量「CBF2CC32」,根據用戶輸入的密碼生成哈希值,並與該變量中的信息進行比較。常量 SHA1、SHA256 和 SHA512 可以在 818544B5-1B9D-4E7B-8F7D-835AAEAF3B5C 二進制代碼中看到。
如果你有 SPI 刷寫工具,要想刪除 Apple 的 EFI 固件密碼的話,只需轉儲閃存內容,刪除「cbf2cc32」變量(實際上只需要翻轉其名稱中的一個比特即可),然後刷新修改後的固件即可。
實際上,還有另一種方法。偏移「3E6D568B」具有特殊用途,因為如果刪除它,NVRAM 就會被重置為缺省狀態,而該狀態下是沒有設置固件密碼的。
💡 實用建議
這樣,什麼論壇啊,價格讓人蛋疼的 EFI 密碼重置硬件啊,統統都免了:只需一個 SPI 刷寫工具和 SOIC 夾,你就可以搞定一切。
SCBO 變量處理代碼追蹤
靜態分析的挑戰
對於 (U)EFI 的二進制文件來說,進行靜態分析可不是件輕鬆的事情:如果我們要修補代碼並查看運行結果的話,每次刷寫都需要 5 到 8 分鐘。此外,相應的調試器的成本也很貴(如用於 (U)EFI 的 JTAG 調試器),許多都在 6K 美元以上。
EFI DXE 仿真器
利用 Unicorn Engine 框架創建一個 EFI 模擬器和調試程序!EFI 環境是自成一體的——例如沒有連接器和系統調用。
它具有 gdbinit 風格的用戶體驗,並且能夠模擬許多基本命令,例如設置斷點、函數的跟蹤進入及跳出、內存轉儲、修改內存及寄存器等。
SCBO 文件結構詳解
經過一番折騰,在逆向這個函數之後,終於搞懂了 SCBO 的功能。首先,SCBO 的文件結構可以利用下列數據結構來描述:
🔒 重要發現
我們最初搞不明白的那些二進制數據,是一個 2048 位的 RSA 簽名。除非有人找到了蘋果的私有密鑰,否則,根本無法創建 SCBO 密鑰生成器。
那麼,網上的那些視頻,以及有人宣稱他們能夠從網站購買 SCBO 文件是怎麼回事呢?我敢打賭,這是由於某種未知的原因,某些傢伙能夠向蘋果的支持系統提交非法請求,然後將收到的 SCBO 文件出售,以獲取不菲的收入。這些人可能是在蘋果支持中心工作,甚至有可能是蘋果公司的內鬼。
Apple 公鑰分析
處理 SCBO 內容的核心函數是 sub_100021f0。它的首要任務之一是分配一個 0x110(272)字節的緩衝區來保存蘋果公司的公共密鑰。
該固件包含五個不同的 2048 位的公鑰,可以從 EFI 文件 B2CB10B1-714A-4E0C-9ED3-35688B2C99F0 中找到:
每個原始文件的長度是 276 字節,這就是說前 20 個字節都只是頭部信息。我們只需要刪除這些頭部字節,就能獲得 256 個字節的公鑰。
密鑰字節是倒置的。如果想要在自己的工具中使用此公鑰的話,我們必須把這些字節顛倒過來。
序列號與 Nonce 驗證流程
下一步是在物理內存中,從地址 0x0FFFFFF08 處提取序列號。如果你引導一個 Linux 安裝並使用 Chipsec 來讀取物理內存的話,你就能夠讀取 Mac 的獨立編號。
下一步是從變量「BC9772C5」中提取當前 nonce。目的是建立跟 SCBO 中看到的一模一樣的序列號+nonce 字符串。
我們可以利用調試器觀察在調用包含 printf 的函數前後的相應變化:
生成的這個字符串將用來替換 SCBO 緩衝器區中的序列號+nonce 串。簽名驗證代碼將使用從 Mac 獲得的當前值,而非從 SCBO 文件中獲得的值。
SHA256 哈希計算
這樣,我們可以計算 SCBO 前 56 字節內容,field1,field2,以及前述的 SCBO_CONTENTS 結構中的序列號+nonce 的哈希值了。
RSA 簽名驗證
最後一步是驗證 RSA 簽名,以保證序列號+nonce 沒有被篡改。

由於蘋果的公鑰不止一個,所以我們將會看到一個循環結構,這意味著該簽名將針對固件「文件系統」中發現的所有蘋果密鑰進行驗證。如果返回一個有效的結果,那麼該密碼將被刪除,實際上就是從 NVRAM 中清除「cbf2cc32」。
如果參數 DataSize(R9 寄存器,地址 0x100024F8)為零,則該變量就會從 NVRAM 中被刪除。此代碼再一次表明了,EFI 密碼功能確實是通過 NVRAM 變量「CBF2CC32」實現的。
結論與安全建議
技術結論
SCBO 及其格式的神秘面紗已經被徹底揭開了。我們看到,該 SCBO 的功能設計是沒問題、沒有被破解成功的,但是網上在售的貌似有效的 SCBO 文件仍然是一個迷。
🎯 核心結論
我敢打賭,這可能是由內鬼通過蘋果技術支持中心獲得了蘋果系統的訪問權限,但再次聲明,這只有蘋果公司才能查明原因。
自行解鎖建議
如果你忘掉自己的固件密碼,現在可以自己重置它了,只要 SPI Flash 芯片不是較新的 BGA 類型(新的 Mac 電腦當前使用的就是這種類型的芯片,不過通過一種隱秘的調試端口,照樣可以達到同樣的目的!)。
你只需要一個裝置來轉儲閃存芯片,刪除變量,然後刷寫上修改後的版本,或直接刪除變量(我總是喜歡完全轉儲然後重新刷寫閃存的方式)。
安全提醒
當然,這些信息可能被小偷偷用來銷售被盜的 Mac 電腦,但實際上網上已經到處都能獲得相關東西了,不過,本文並沒有透露任何以前未曾揭露的秘密。
我不僅希望你喜歡這篇文章,更希望能通過它激起對 (U)EFI 逆向技術的興趣。當然,由於缺乏相應的調試器,該技術並沒有用戶態或內核逆向技術那樣輕鬆,不過,只要稍微多做一些努力,這些困難仍然是可以解決的。
本文翻譯自 MacReversing,並由 OSSLab 補充實務經驗說明。逆向工程實務太少了,若翻譯質量不夠好請見諒。



















