[翻譯]如何將鍵盤改造成為貪吃蛇遊戲(全)
gjden發表於2016-04-14
如何將鍵盤改造成為貪吃蛇遊戲(硬體分析篇)
作者:spritesmods
翻譯:gjden(from the adlab)
譯註:本文不完全是按照作者原文翻譯,其中加入了我自己的理解和截圖。個人感覺這邊文章非常好,當然有點囉嗦,增加了翻譯量。目前還沒有翻譯完,就分上下篇吧,請大家先看這個翻譯好的上篇,下篇有空了再翻譯給大家,不足和錯誤之處歡迎指正,也請高手出來一起討論,互相學習。
一、簡介
儘管白天裡我的本職工作是做軟體開發,但晚上我卻是一個喜歡hack各種電子玩意兒的駭客。那意味著我幾乎整天都坐在電腦旁敲程式碼、除錯….你可以想象鍵盤就是我選擇征服一切的武器:為了讓我的程式能夠按照預期執行,我通常樂意一直不停的敲著鍵盤。
當然,大部分的鍵盤的生命是有限的,(儘管我固執的認為我所使用的IBM Model M是不朽的)。終於,有天我發現我工作鍵盤的shift鍵不能工作了,這是使得我的email看起來很不方便並且導致寫程式碼時變得更加惱怒。因此我需要一個新鍵盤,老鍵盤是英式的橡膠圓頂鍵盤,因而這也是一次好機會來更換一個好一點的鍵盤,比如一個機械鍵盤。
因此我便在網上搜尋一箇中意的鍵盤,我想要Cherry Brown 的機械按鍵,因為我是不會和選擇聲音大的Cherry Blues鍵盤的人做朋友。無數字鍵的鍵盤對於我來說更好,這會減少我手與軌跡球之間的距離。
滿足我所有要求的最便宜的鍵盤便是Coolermaster Quickfire Rapid-I(譯註:看來人家有錢啊,這還便宜,酷冷至尊的鍵盤7百多元)。這個鍵盤是一款帶有LED光的無數字鍵的遊戲鍵盤,對於我來說可以省去不少麻煩:僅僅是他的遊戲屬性便不會出現鍵盤衝突(譯註:鍵盤衝突是當多個鍵同時按下時其中一些按鍵不能響應,一般遊戲玩家應該都不陌生,無衝突的鍵盤是最好的)並且將按鍵點選率提高到了一個非常驚人的水平,還有就是每一個按鍵背面都包含有一個白色的LED燈。
LED背光是一個有趣的功能,鍵盤用它來實現了照明模式:你既能夠設定固定的點亮模式,也可以設定為按鍵模式(你每次按鍵時點亮,然後燈光漸漸變暗)。
拿到鍵盤後我帶著它去上班,到第二天,我將新鍵盤給同事看,他們都知道我有一個撕毀保修條的嗜好(意思應該是大家都知道他喜歡hack硬體)。因此,其中一個同事開玩笑的說:”你已經擁有這個鍵盤24個小時了,這玩意有一堆LEDs燈和箭頭鍵.很遺憾你還差一條蛇在這上面跑。”開始我也只是笑笑,但之後我就不停的想,Coolermaster(著名的鍵盤廠商)的傢伙不是已經自豪的宣佈這個鍵盤裡有個ARM Cortex的CPU. 或許有可能.....。
二、硬體分析
因此,如果我要實現這件事情,我首先需要研究一下硬體。他們說在裡面有一個ARM, 但難道只是用來驅動鍵盤和LEDs嗎?那麼我需要開啟鍵盤來確認一下。
首先,我發現如此優雅的鍵盤為什麼這麼重的原因:這按鍵之下的白色板實際上是金屬做成的。
這是裸鍵盤的背部,可用看出PCB連線著按鍵和LEDs燈。注意為了防止按鍵衝突,每一個鍵都含有一個二極體。
這是PCB上的一個特寫區域,這裡有一個控制器晶片(黑色正方形)。在左下部有微型的USB插座。在它的上方挨著主處理器的是電源調節器。處理器周圍都是用來驅動LED燈的電晶體,還有一個i2c的EEPROM,可能用於儲存燈光設定的。
控制器是HT32F1755,由臺灣公司Holtek(盛群半導體)製造。這是一個帶有127k flash和32k RAM的72MHz ARM Cortex-M3。
很奇怪這麼快速的微處理器現如今便宜到被用來放在鍵盤上,其比某些插在其上的USB裝置的控制器還要快。
這個控制器有幾個不錯的額外特性。其擁有一個通用的SWD/JTAG-port可以用來除錯執行在控制器中的程式,這隻需要幾條線和一個JTAG偵錯程式就可以。其次,如果你想讀寫FLASH的話,鍵盤有一個基於bootloader的ROM,只需要拉下一個GPIO重置晶片即可,然後使用一個windows程式你便可以透過USB讀寫FLASH,但是讀寫FLASH可能會導致FLASH資料遭到破壞。
晶片也包含有安全保護機制。最明顯的是”安全位(security bit)”,它會阻止駭客從flash中獲取資料,如果其訪問來自於第三方(比如USB bootloader和JTAG)而不是flash內部的話會立刻關閉flash。
好吧,安全位被設計來阻止了我要做的第一件事情:我需要fash資料來確定鍵盤工作的原理然後為其加入貪吃蛇功能。如果安全位被設定,我將不能使用SWD埠來獲取韌體。然而安全被設定了嗎?只有一種方法來確認…
首先,我需要找到一種容易實現的方法來獲取JTAG/SWD埠。幸運的是,PCB板上有幾個沒有填充的標頭。呼叫USB ROM bootloader的GPIO也以同樣的方式被匯出。
譯者注:可以清楚的看到有幾個孔,上面五個孔是SWD除錯接頭,下面兩個孔是bootloader的接頭。下圖是HT32F1755的控制器的引腳圖。
透過對PCB的分析我可以準確的找到SWD介面和Bootloader的介面。如圖:
從圖中我們可以看出SWD引腳,然後直接按引腳連結線路找到對應的口就行了,如果找不到,可以直接到引腳上進行連線。
這是我的裝置,紅色板是FT2232 JTAG board.它不能適配SWD,但是有一個單電阻攻擊的方法來使其適配。
譯者注:OpenOCD中存在一個配置檔案swd-resistor-hack.cfg,只需要其中的配置就可以。
我使用OpenOCD來和他建立連線,之後做一些配置就可以dump Flash了.
可以看到dump出來的全是無效資料,看來控制器的安全位被設定了。
先翻譯到此,下一篇抽空翻譯後給大家呈上
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
如何將鍵盤改造成為貪吃蛇遊戲(韌體逆向與遊戲程式碼的加入)
三、韌體更新程式分析
另外一種獲取flash的方法是利用軟體更新。幸運的是Coolermaster提供了韌體更新功能,更新修改了一些bug,加入了閃光模式。你可以從官網上下載最新版本
http://gaming.coolermaster.com/en/products/keyboards/rapid-i/
官網上有兩個版本:EU和US版本。這是因為這兩個版本之間的硬體有一點不同:EU版本有額外的按鍵,因而韌體也會不同。
韌體更新程式以某種方式將韌體嵌入了其中。再動手之前,我猜這兩個版本鍵盤的UI和更新功能應該是相同的,甚至處理更新的程式碼也應該差不多,意思是說,所有的不同應該在兩個韌體執行體中。為了驗證的我的想法,我對比分析了兩個不同更新檔案,其差別都集中在檔案末尾的一個16k的資料塊兒上。
接下來就是將這段資料分離出來,從內容上看的確應該與韌體相關的內容,比如檔案開始帶有我所下載的韌體版本號”1.1.7”(最新版本為1.2.2). 這是一個USB鍵盤,因此在韌體中應該會有USB描述字串之類的東西存在其中,並且是以UTF-16方式儲存的字串,字串中包含有裝置名和裝置廠商的配置資訊。但是從我開啟的檔案來說確什麼也沒有發現,所有韌體要麼是加密過的,要麼是做過壓縮。
我們具體來看看是怎麼回事,如下圖,我們可以注意到兩個特點,一個是不斷重複的'A5 CA 88 A5',沒有壓縮資料會這樣重複出現資料。另外一個是大量的A5出現在了檔案中。因此我們猜測這個檔案可能是使用了簡單的異或方式進行加密,並且異或金鑰為單位元組A5.
接下來就直接將解密的檔案拖入反彙編器,確實反彙編出來了可以閱讀的arm程式碼,但似乎韌體仍有問題,有的跳轉跳到了可讀程式碼之外,這些跳轉到的位置都是一些不可讀的arm程式碼。總而言之,目前還不具備直接從韌體上加入貪吃蛇程式碼。
對於可執行檔案還有另外一件事情要做,就是需要監控USB資料包,我們需要執行更新程式,使用一個USB嗅探器(USBPcap)來做。在觀察了捕獲的包後,我發現韌體更新時會將資料傳送給USB 的端點3,並且透過端點4來接收這些包。其中一個包實際上會將鍵盤切換到韌體模式,更新包格式如下:
• Byte 1-2: Command/subcommand, tells keyboard what to do
• Byte 3-4: CRC16 of entire packet
• Byte 5-8: 32-bit 'from'-address for command
• Byte 9-12: 32-bit 'to'-address for command
• Byte 13-63: Data
這些包具體是如何起作用呢,在韌體更新時,我分析並且推測出如下功能:
Cmd Addr Data
1:2 0x2800-0x2808 (kb->pc) "1.1.5" <- Read version
4:1 0 (Device re-enumerates) <- Enter flash mode
0:8 0x2800-0x2808 - <- Erase version
0:8 0x2c00-0x6ad4 - <- Erase firmware
1:1 0x2c00-0x6ad4 Multiple, uploads fw <- Write fw
1:0 0x2c00-0x6ad4 Multiple, uploads fw <- Verify fw?
1:1 0x2800-0x2808 (pc->kb) "1.1.7" <- Write new version
4:0 1 (Device re-enumerates) <- Exit flash mode
這裡有一些我們感興趣的東西。擦除和寫入一個新的韌體版本號,與擦除和更新韌體程式本身,更新程式傳送的是同一個命令,但是操作的區域不同:分別是以0x2800和0x2c00開始。從這裡我可以推斷出韌體版本儲存在flash的一個獨立獨立扇區裡,簡而言之,韌體不需要實現一個完全不同的命令來管理韌體版本號。
但是,等一下,同樣一個0x2800地址被用來讀取韌體版本號資訊。韌體版本事實上不會超出flash的預設資料長度,但是版本號讀命令實際上和一般的flash讀命令沒有任何區別的,因此,這對於我來說是非常有用的:透過執行包含整個flash區域的讀命令,我應該就能夠獲取flash中的所有資料內容(包含程式)。
譯者注:從如下地址空間佈局圖上可以看出128k的flash位於0x0000 0000-0x0002 0000,64kb SRAM空間為0x2000 0000-0x2000 1000。因而讀寫韌體的地址都在地址空間的前128k的空間中。
我透過usblib寫了一個小程式來做這件事,程式本身沒有什麼問題,但是我卻沒有得到我想要的資料:除了韌體版本區的資料外,讀取到的其他內容都為0。我的推斷(讀取版本號命令即是讀取flash命令)應該是沒有問題,比如說,當我逐個增加地址時,我應該能夠一個位元組一個位元組的讀以致獲得所有的資料。看起來好像還有其他問題使得我去讀取失敗。好吧,我以為能夠很容易的更新我已經解密後韌體的想法泡湯了。之後我在可讀的反彙編程式碼中找到一些蛛絲馬跡。
在一些搜尋之後,我發現一些關鍵的程式碼,這段程式碼每被呼叫一次,就能從flash中讀取一個位元組。其中基本檢查條件是如果一個位元組是從一個允許的區域(0x2800-0x2c00)去讀,那麼它會跳出這段程式碼併傳送一個位元組,如果不是,那就用0來替代。
用NOP程式碼來替換掉最後一行,意味著一個位元組的修改。並且在重加密和修正偏移之後,我已經讓韌體發生了改變,我沒有看到任何CRC校驗,但也可能錯過一個其他方式的校驗而被拒絕更新。然而,也有可能仍會接受更新但是會搞死我的鍵盤。
接下來啟動更新程式執行更新,沒有異常發生:看起來韌體更新,至少來說,是不會自我校驗的。過了一會兒,我算是鬆了口氣:鍵盤在韌體更新後被再次點亮了。但是新韌體真的起作用了嗎?我再次執行了我的程式並dump資料來看:
在執行dump後的映象檔案後,透過反彙編器我可以確認這是一個完整flash dump.沒有奇怪的程式碼出現,也沒有跳轉到無效程式碼,完全是我所期望的未加密韌體資料。我似乎已經實現了鍵盤的韌體備份!如此,除了能夠逆向韌體的所有功能外,也意味著如果我在開發貪吃蛇時如果犯了一個錯誤使得鍵盤變成板磚,那麼我可以使用ROM的bootloader來將原始韌體刷回去使其恢復工作狀態。也意味著我的JTAG/SWD 工具可以派上用場:在大量的微處理器擦除之後我可以重存備份,我能夠禁用保護位以致可以再次單步除錯flash程式碼。
四、寫一個基於Linux的韌體更新程式
在我寫貪吃蛇之前,我還必須解決最後一個問題:我需要一種乾淨的方式來上傳已經修改過的韌體。當我用ROM USB Bootloader時,協助程式是一個基於windows視窗的工具,不適合作為攻擊工具釋出。但是如果做成基於linux的韌體更新工具,那麼便不會出現這樣的問題。我不必釋出一個Coolermaster 版權的程式碼,我可以讓人們獲取我做的韌體更新和解密程式。
為了確保韌體不會存在其他額外的加密,我透過比較我已經解密的韌體程式和我捕獲的USB包來做推斷:檢查韌體dump檔案表明出錯位的確不同,比較兩者,我懷疑控制器自身做了一些異或並且可能在將韌體燒錄到flash中之前做了一些位元組的重佈局。
當然,我一直盯著這個不同的位元組區直到我發現了這個問題。就像我處理韌體加密時一樣。我都已經將程式碼反彙編了,為什麼不能找到呢。的確,我在反彙編程式碼中找到了。
基本上來說,有一個計數器用來記住傳送到鍵盤中的韌體包的數量。如果計數在10到100之間,韌體將會處理被損壞的韌體並且呼叫函式來修復他。
修復過程也不難,就是和一個52位元組的秘鑰進行異或。
我快速的用C寫了一個加密和解密的函式來模擬這個過程。並將其加入到之前的程式碼中。
現在也可以解密韌體更新程式為要寫入flash的資料。生成一個檔案並將其傳送給flash.
五、加入貪吃蛇程式。
隨著之前工作完成,是時候編寫貪吃蛇了。首先,我必須在flash和RAM中找到一個無用的儲存區來儲存我自己的程式碼和資料。這並不難:可以很容易的找到一個不少於64k的空閒flash和28k的RAM。為了修改鍵盤功能,我修改原始韌體中的變數:比如PEM值和RAM中按下的鍵值陣列。透過使用JTAG/SWD找到RAM的這種變數並不難。我在韌體中加入一些HOOK使得我的程式碼能夠執行。比如原始韌體有一個功能是當按鍵被按下時呼叫,如果我對這個動作感興趣,那就可以重定向到我自己函式執行,之後再呼叫原函式執行。
以下是我加入的Hook函式表。
在這些攻擊完成了後,我最終可以在鍵盤上玩貪吃蛇遊戲了。
下面張圖是我新增的貪吃蛇的方向控制。
六、擴充套件
韌體中還有一些東西我做了改善,首先,允許鍵盤這樣更新有一個安全問題。當Coolermasters韌體更新自身時,會有一個視窗通知韌體更新操作,比如我的程式執行linux下預設是root許可權的使用者,攻擊者會在使用者不知情的情況下很容易的重新刷入韌體。比如在韌體中刷入鍵盤記錄器或者進行類似於BadUSB的攻擊。為了防止這種情況發生,我在我的韌體中加入一個物理條件來開啟flash模式。具體來說,你需要在按下組合鍵fn+f後10秒鐘的時候才能進行韌體更新。否則,更新會失敗。
另外,就是關於按鍵效果自定義和遊戲自定義問題目前還沒有,但是我想很多人想要寫入自定義效果但是並不想拆開他們的鍵盤透過bootloader來修復損壞的韌體。我發現鍵盤的USB功能是被禁用了的,因此我決定重用這個功能:在我的韌體程式中,透過一定的cmd包可以用來覆蓋掉韌體中設定的LED訊號值。我還寫了一個PC上的demo來模擬(這個模擬程式作者好像沒有提供)。
七、總結
在Rapid-I(這次hack的工具包)中,預設韌體並不是一成不變的,你可以用keyboad做比Coolermaster考慮得更多的事情。採用同樣hack攻擊技術,你除了用來玩兒貪吃蛇遊戲,任何程式設計師理論上來說可以讓自己想象任何東西執行在鍵盤上。我甚至希望是它變得更安全謝:加入物理組合鍵開啟更新的功能防止惡意攻擊鍵盤。
一般來說,我一般寫的程式碼都是開源的:韌體分割和更新工具使用是請遵循GPLv3協議,貪吃蛇程式和其它程式碼請遵循Beer-Ware協議。因為版權法律原因我不得不清除所有Coolermaster的所有程式碼和二進位制程式。但是你可以透過到官方下載更新程式來提取和重建。這次hack,僅僅使用USB鍵盤作為測試,因為我的鍵盤就是這個版本。
原始碼可以在附件下載。
作者:spritesmods
翻譯:gjden(from the adlab)
譯註:本文不完全是按照作者原文翻譯,其中加入了我自己的理解和截圖。個人感覺這邊文章非常好,當然有點囉嗦,增加了翻譯量。目前還沒有翻譯完,就分上下篇吧,請大家先看這個翻譯好的上篇,下篇有空了再翻譯給大家,不足和錯誤之處歡迎指正,也請高手出來一起討論,互相學習。
一、簡介
儘管白天裡我的本職工作是做軟體開發,但晚上我卻是一個喜歡hack各種電子玩意兒的駭客。那意味著我幾乎整天都坐在電腦旁敲程式碼、除錯….你可以想象鍵盤就是我選擇征服一切的武器:為了讓我的程式能夠按照預期執行,我通常樂意一直不停的敲著鍵盤。
當然,大部分的鍵盤的生命是有限的,(儘管我固執的認為我所使用的IBM Model M是不朽的)。終於,有天我發現我工作鍵盤的shift鍵不能工作了,這是使得我的email看起來很不方便並且導致寫程式碼時變得更加惱怒。因此我需要一個新鍵盤,老鍵盤是英式的橡膠圓頂鍵盤,因而這也是一次好機會來更換一個好一點的鍵盤,比如一個機械鍵盤。
因此我便在網上搜尋一箇中意的鍵盤,我想要Cherry Brown 的機械按鍵,因為我是不會和選擇聲音大的Cherry Blues鍵盤的人做朋友。無數字鍵的鍵盤對於我來說更好,這會減少我手與軌跡球之間的距離。
滿足我所有要求的最便宜的鍵盤便是Coolermaster Quickfire Rapid-I(譯註:看來人家有錢啊,這還便宜,酷冷至尊的鍵盤7百多元)。這個鍵盤是一款帶有LED光的無數字鍵的遊戲鍵盤,對於我來說可以省去不少麻煩:僅僅是他的遊戲屬性便不會出現鍵盤衝突(譯註:鍵盤衝突是當多個鍵同時按下時其中一些按鍵不能響應,一般遊戲玩家應該都不陌生,無衝突的鍵盤是最好的)並且將按鍵點選率提高到了一個非常驚人的水平,還有就是每一個按鍵背面都包含有一個白色的LED燈。
LED背光是一個有趣的功能,鍵盤用它來實現了照明模式:你既能夠設定固定的點亮模式,也可以設定為按鍵模式(你每次按鍵時點亮,然後燈光漸漸變暗)。
拿到鍵盤後我帶著它去上班,到第二天,我將新鍵盤給同事看,他們都知道我有一個撕毀保修條的嗜好(意思應該是大家都知道他喜歡hack硬體)。因此,其中一個同事開玩笑的說:”你已經擁有這個鍵盤24個小時了,這玩意有一堆LEDs燈和箭頭鍵.很遺憾你還差一條蛇在這上面跑。”開始我也只是笑笑,但之後我就不停的想,Coolermaster(著名的鍵盤廠商)的傢伙不是已經自豪的宣佈這個鍵盤裡有個ARM Cortex的CPU. 或許有可能.....。
二、硬體分析
因此,如果我要實現這件事情,我首先需要研究一下硬體。他們說在裡面有一個ARM, 但難道只是用來驅動鍵盤和LEDs嗎?那麼我需要開啟鍵盤來確認一下。
首先,我發現如此優雅的鍵盤為什麼這麼重的原因:這按鍵之下的白色板實際上是金屬做成的。
這是裸鍵盤的背部,可用看出PCB連線著按鍵和LEDs燈。注意為了防止按鍵衝突,每一個鍵都含有一個二極體。
這是PCB上的一個特寫區域,這裡有一個控制器晶片(黑色正方形)。在左下部有微型的USB插座。在它的上方挨著主處理器的是電源調節器。處理器周圍都是用來驅動LED燈的電晶體,還有一個i2c的EEPROM,可能用於儲存燈光設定的。
控制器是HT32F1755,由臺灣公司Holtek(盛群半導體)製造。這是一個帶有127k flash和32k RAM的72MHz ARM Cortex-M3。
很奇怪這麼快速的微處理器現如今便宜到被用來放在鍵盤上,其比某些插在其上的USB裝置的控制器還要快。
這個控制器有幾個不錯的額外特性。其擁有一個通用的SWD/JTAG-port可以用來除錯執行在控制器中的程式,這隻需要幾條線和一個JTAG偵錯程式就可以。其次,如果你想讀寫FLASH的話,鍵盤有一個基於bootloader的ROM,只需要拉下一個GPIO重置晶片即可,然後使用一個windows程式你便可以透過USB讀寫FLASH,但是讀寫FLASH可能會導致FLASH資料遭到破壞。
晶片也包含有安全保護機制。最明顯的是”安全位(security bit)”,它會阻止駭客從flash中獲取資料,如果其訪問來自於第三方(比如USB bootloader和JTAG)而不是flash內部的話會立刻關閉flash。
好吧,安全位被設計來阻止了我要做的第一件事情:我需要fash資料來確定鍵盤工作的原理然後為其加入貪吃蛇功能。如果安全位被設定,我將不能使用SWD埠來獲取韌體。然而安全被設定了嗎?只有一種方法來確認…
首先,我需要找到一種容易實現的方法來獲取JTAG/SWD埠。幸運的是,PCB板上有幾個沒有填充的標頭。呼叫USB ROM bootloader的GPIO也以同樣的方式被匯出。
譯者注:可以清楚的看到有幾個孔,上面五個孔是SWD除錯接頭,下面兩個孔是bootloader的接頭。下圖是HT32F1755的控制器的引腳圖。
透過對PCB的分析我可以準確的找到SWD介面和Bootloader的介面。如圖:
從圖中我們可以看出SWD引腳,然後直接按引腳連結線路找到對應的口就行了,如果找不到,可以直接到引腳上進行連線。
這是我的裝置,紅色板是FT2232 JTAG board.它不能適配SWD,但是有一個單電阻攻擊的方法來使其適配。
譯者注:OpenOCD中存在一個配置檔案swd-resistor-hack.cfg,只需要其中的配置就可以。
我使用OpenOCD來和他建立連線,之後做一些配置就可以dump Flash了.
可以看到dump出來的全是無效資料,看來控制器的安全位被設定了。
先翻譯到此,下一篇抽空翻譯後給大家呈上
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
如何將鍵盤改造成為貪吃蛇遊戲(韌體逆向與遊戲程式碼的加入)
三、韌體更新程式分析
另外一種獲取flash的方法是利用軟體更新。幸運的是Coolermaster提供了韌體更新功能,更新修改了一些bug,加入了閃光模式。你可以從官網上下載最新版本
http://gaming.coolermaster.com/en/products/keyboards/rapid-i/
官網上有兩個版本:EU和US版本。這是因為這兩個版本之間的硬體有一點不同:EU版本有額外的按鍵,因而韌體也會不同。
韌體更新程式以某種方式將韌體嵌入了其中。再動手之前,我猜這兩個版本鍵盤的UI和更新功能應該是相同的,甚至處理更新的程式碼也應該差不多,意思是說,所有的不同應該在兩個韌體執行體中。為了驗證的我的想法,我對比分析了兩個不同更新檔案,其差別都集中在檔案末尾的一個16k的資料塊兒上。
接下來就是將這段資料分離出來,從內容上看的確應該與韌體相關的內容,比如檔案開始帶有我所下載的韌體版本號”1.1.7”(最新版本為1.2.2). 這是一個USB鍵盤,因此在韌體中應該會有USB描述字串之類的東西存在其中,並且是以UTF-16方式儲存的字串,字串中包含有裝置名和裝置廠商的配置資訊。但是從我開啟的檔案來說確什麼也沒有發現,所有韌體要麼是加密過的,要麼是做過壓縮。
我們具體來看看是怎麼回事,如下圖,我們可以注意到兩個特點,一個是不斷重複的'A5 CA 88 A5',沒有壓縮資料會這樣重複出現資料。另外一個是大量的A5出現在了檔案中。因此我們猜測這個檔案可能是使用了簡單的異或方式進行加密,並且異或金鑰為單位元組A5.
接下來就直接將解密的檔案拖入反彙編器,確實反彙編出來了可以閱讀的arm程式碼,但似乎韌體仍有問題,有的跳轉跳到了可讀程式碼之外,這些跳轉到的位置都是一些不可讀的arm程式碼。總而言之,目前還不具備直接從韌體上加入貪吃蛇程式碼。
對於可執行檔案還有另外一件事情要做,就是需要監控USB資料包,我們需要執行更新程式,使用一個USB嗅探器(USBPcap)來做。在觀察了捕獲的包後,我發現韌體更新時會將資料傳送給USB 的端點3,並且透過端點4來接收這些包。其中一個包實際上會將鍵盤切換到韌體模式,更新包格式如下:
• Byte 1-2: Command/subcommand, tells keyboard what to do
• Byte 3-4: CRC16 of entire packet
• Byte 5-8: 32-bit 'from'-address for command
• Byte 9-12: 32-bit 'to'-address for command
• Byte 13-63: Data
這些包具體是如何起作用呢,在韌體更新時,我分析並且推測出如下功能:
Cmd Addr Data
1:2 0x2800-0x2808 (kb->pc) "1.1.5" <- Read version
4:1 0 (Device re-enumerates) <- Enter flash mode
0:8 0x2800-0x2808 - <- Erase version
0:8 0x2c00-0x6ad4 - <- Erase firmware
1:1 0x2c00-0x6ad4 Multiple, uploads fw <- Write fw
1:0 0x2c00-0x6ad4 Multiple, uploads fw <- Verify fw?
1:1 0x2800-0x2808 (pc->kb) "1.1.7" <- Write new version
4:0 1 (Device re-enumerates) <- Exit flash mode
這裡有一些我們感興趣的東西。擦除和寫入一個新的韌體版本號,與擦除和更新韌體程式本身,更新程式傳送的是同一個命令,但是操作的區域不同:分別是以0x2800和0x2c00開始。從這裡我可以推斷出韌體版本儲存在flash的一個獨立獨立扇區裡,簡而言之,韌體不需要實現一個完全不同的命令來管理韌體版本號。
但是,等一下,同樣一個0x2800地址被用來讀取韌體版本號資訊。韌體版本事實上不會超出flash的預設資料長度,但是版本號讀命令實際上和一般的flash讀命令沒有任何區別的,因此,這對於我來說是非常有用的:透過執行包含整個flash區域的讀命令,我應該就能夠獲取flash中的所有資料內容(包含程式)。
譯者注:從如下地址空間佈局圖上可以看出128k的flash位於0x0000 0000-0x0002 0000,64kb SRAM空間為0x2000 0000-0x2000 1000。因而讀寫韌體的地址都在地址空間的前128k的空間中。
我透過usblib寫了一個小程式來做這件事,程式本身沒有什麼問題,但是我卻沒有得到我想要的資料:除了韌體版本區的資料外,讀取到的其他內容都為0。我的推斷(讀取版本號命令即是讀取flash命令)應該是沒有問題,比如說,當我逐個增加地址時,我應該能夠一個位元組一個位元組的讀以致獲得所有的資料。看起來好像還有其他問題使得我去讀取失敗。好吧,我以為能夠很容易的更新我已經解密後韌體的想法泡湯了。之後我在可讀的反彙編程式碼中找到一些蛛絲馬跡。
在一些搜尋之後,我發現一些關鍵的程式碼,這段程式碼每被呼叫一次,就能從flash中讀取一個位元組。其中基本檢查條件是如果一個位元組是從一個允許的區域(0x2800-0x2c00)去讀,那麼它會跳出這段程式碼併傳送一個位元組,如果不是,那就用0來替代。
用NOP程式碼來替換掉最後一行,意味著一個位元組的修改。並且在重加密和修正偏移之後,我已經讓韌體發生了改變,我沒有看到任何CRC校驗,但也可能錯過一個其他方式的校驗而被拒絕更新。然而,也有可能仍會接受更新但是會搞死我的鍵盤。
接下來啟動更新程式執行更新,沒有異常發生:看起來韌體更新,至少來說,是不會自我校驗的。過了一會兒,我算是鬆了口氣:鍵盤在韌體更新後被再次點亮了。但是新韌體真的起作用了嗎?我再次執行了我的程式並dump資料來看:
在執行dump後的映象檔案後,透過反彙編器我可以確認這是一個完整flash dump.沒有奇怪的程式碼出現,也沒有跳轉到無效程式碼,完全是我所期望的未加密韌體資料。我似乎已經實現了鍵盤的韌體備份!如此,除了能夠逆向韌體的所有功能外,也意味著如果我在開發貪吃蛇時如果犯了一個錯誤使得鍵盤變成板磚,那麼我可以使用ROM的bootloader來將原始韌體刷回去使其恢復工作狀態。也意味著我的JTAG/SWD 工具可以派上用場:在大量的微處理器擦除之後我可以重存備份,我能夠禁用保護位以致可以再次單步除錯flash程式碼。
四、寫一個基於Linux的韌體更新程式
在我寫貪吃蛇之前,我還必須解決最後一個問題:我需要一種乾淨的方式來上傳已經修改過的韌體。當我用ROM USB Bootloader時,協助程式是一個基於windows視窗的工具,不適合作為攻擊工具釋出。但是如果做成基於linux的韌體更新工具,那麼便不會出現這樣的問題。我不必釋出一個Coolermaster 版權的程式碼,我可以讓人們獲取我做的韌體更新和解密程式。
為了確保韌體不會存在其他額外的加密,我透過比較我已經解密的韌體程式和我捕獲的USB包來做推斷:檢查韌體dump檔案表明出錯位的確不同,比較兩者,我懷疑控制器自身做了一些異或並且可能在將韌體燒錄到flash中之前做了一些位元組的重佈局。
當然,我一直盯著這個不同的位元組區直到我發現了這個問題。就像我處理韌體加密時一樣。我都已經將程式碼反彙編了,為什麼不能找到呢。的確,我在反彙編程式碼中找到了。
基本上來說,有一個計數器用來記住傳送到鍵盤中的韌體包的數量。如果計數在10到100之間,韌體將會處理被損壞的韌體並且呼叫函式來修復他。
修復過程也不難,就是和一個52位元組的秘鑰進行異或。
我快速的用C寫了一個加密和解密的函式來模擬這個過程。並將其加入到之前的程式碼中。
現在也可以解密韌體更新程式為要寫入flash的資料。生成一個檔案並將其傳送給flash.
五、加入貪吃蛇程式。
隨著之前工作完成,是時候編寫貪吃蛇了。首先,我必須在flash和RAM中找到一個無用的儲存區來儲存我自己的程式碼和資料。這並不難:可以很容易的找到一個不少於64k的空閒flash和28k的RAM。為了修改鍵盤功能,我修改原始韌體中的變數:比如PEM值和RAM中按下的鍵值陣列。透過使用JTAG/SWD找到RAM的這種變數並不難。我在韌體中加入一些HOOK使得我的程式碼能夠執行。比如原始韌體有一個功能是當按鍵被按下時呼叫,如果我對這個動作感興趣,那就可以重定向到我自己函式執行,之後再呼叫原函式執行。
以下是我加入的Hook函式表。
在這些攻擊完成了後,我最終可以在鍵盤上玩貪吃蛇遊戲了。
下面張圖是我新增的貪吃蛇的方向控制。
六、擴充套件
韌體中還有一些東西我做了改善,首先,允許鍵盤這樣更新有一個安全問題。當Coolermasters韌體更新自身時,會有一個視窗通知韌體更新操作,比如我的程式執行linux下預設是root許可權的使用者,攻擊者會在使用者不知情的情況下很容易的重新刷入韌體。比如在韌體中刷入鍵盤記錄器或者進行類似於BadUSB的攻擊。為了防止這種情況發生,我在我的韌體中加入一個物理條件來開啟flash模式。具體來說,你需要在按下組合鍵fn+f後10秒鐘的時候才能進行韌體更新。否則,更新會失敗。
另外,就是關於按鍵效果自定義和遊戲自定義問題目前還沒有,但是我想很多人想要寫入自定義效果但是並不想拆開他們的鍵盤透過bootloader來修復損壞的韌體。我發現鍵盤的USB功能是被禁用了的,因此我決定重用這個功能:在我的韌體程式中,透過一定的cmd包可以用來覆蓋掉韌體中設定的LED訊號值。我還寫了一個PC上的demo來模擬(這個模擬程式作者好像沒有提供)。
七、總結
在Rapid-I(這次hack的工具包)中,預設韌體並不是一成不變的,你可以用keyboad做比Coolermaster考慮得更多的事情。採用同樣hack攻擊技術,你除了用來玩兒貪吃蛇遊戲,任何程式設計師理論上來說可以讓自己想象任何東西執行在鍵盤上。我甚至希望是它變得更安全謝:加入物理組合鍵開啟更新的功能防止惡意攻擊鍵盤。
一般來說,我一般寫的程式碼都是開源的:韌體分割和更新工具使用是請遵循GPLv3協議,貪吃蛇程式和其它程式碼請遵循Beer-Ware協議。因為版權法律原因我不得不清除所有Coolermaster的所有程式碼和二進位制程式。但是你可以透過到官方下載更新程式來提取和重建。這次hack,僅僅使用USB鍵盤作為測試,因為我的鍵盤就是這個版本。
原始碼可以在附件下載。
相關文章
- [譯] RxJS 遊戲之貪吃蛇2019-02-26JS遊戲
- Python:遊戲:貪吃蛇2019-02-27Python遊戲
- jQuery 實現貪吃蛇遊戲2017-03-04jQuery遊戲
- 貪吃蛇js2020-10-26JS
- 04 貪吃蛇2024-04-14
- Shell寫的貪吃蛇遊戲(轉)2007-08-11遊戲
- js貪吃蛇遊戲程式碼例項2017-04-17JS遊戲
- canvas貪吃蛇遊戲程式碼例項2017-02-17Canvas遊戲
- Java實現貪吃蛇2021-03-03Java
- 貪吃蛇c原始碼2020-12-15原始碼
- 貪吃蛇源程式 (轉)2007-12-12
- javascript貪吃蛇小遊戲程式碼例項2017-04-12JavaScript遊戲
- html畫布製作貪吃蛇小遊戲2017-10-29HTML遊戲
- H5遊戲開發:貪吃蛇2017-09-28H5遊戲開發
- 無法執行的貪吃蛇遊戲程式碼,求大神幫忙改動!2016-01-12遊戲
- 開發Windows貪吃蛇遊戲——(一)前期準備2020-12-20Windows遊戲
- C語言小遊戲------貪吃蛇----小白專用2020-10-06C語言遊戲
- 手把手教你寫Android 貪吃蛇 遊戲2018-02-09Android遊戲
- Ubuntu下C語言實現貪吃蛇遊戲2017-12-18UbuntuC語言遊戲
- Python3 貪吃蛇2018-07-23Python
- python實現貪吃蛇2021-11-15Python
- C#貪吃蛇(WPF版)2016-04-11C#
- 如何用Python寫一個貪吃蛇AI2016-03-20PythonAI
- GUI 基於Swing製作貪吃蛇小遊戲2020-11-25GUI遊戲
- 【Python】 Python小遊戲-貪吃蛇大冒險2022-02-21Python遊戲
- canvas實現的貪吃蛇遊戲程式碼例項2017-02-17Canvas遊戲
- 基於51微控制器的貪吃蛇遊戲2018-01-05遊戲
- 一個貪吃蛇小遊戲(17行程式碼)2012-12-05遊戲行程
- js+jquery實現貪吃蛇經典小遊戲2024-11-24JSjQuery遊戲
- OpenGL實現貪吃蛇程式碼2020-12-25
- C語言貪吃蛇原始碼2018-06-23C語言原始碼
- [原生JS][程式導向]貪吃蛇2017-07-16JS
- 初試javascript :貪吃蛇啊 (轉)2007-08-16JavaScript
- 閒得無聊寫的一個貪吃蛇小遊戲~2017-09-26遊戲
- C語言實現桌面貪吃蛇2020-12-19C語言
- Python實現貪吃蛇大作戰2023-12-17Python
- JavaScript-開發一個簡單的貪吃蛇小遊戲2019-03-25JavaScript遊戲
- (完整原始碼)貪吃蛇小遊戲——HTML+CSS+JavaScript實現2019-01-05原始碼遊戲HTMLCSSJavaScript