破解微軟智慧手環

wyzsk發表於2020-08-19
作者: 暗羽 · 2016/04/22 11:07

翻譯自:http://www.b0n0n.com/2016/04/20/ms-jailbreak/

0x00 簡介


這學期我得到了一個微軟智慧手環作為專案研究目標。最初的專案目標並不是太難:只是去理解客戶端的通訊方式。因此我決定尋求樂趣,我決定嘗試pwn掉它。在這裡我想要感謝遠在OSIRIS實驗室的朋友給我提供的支援,我的伴侶也一直默默支援著我。當然,需要感謝的還有我的導師,mongo,他啟發了我,教會了我很多,對此我表示由衷地感謝。

0x01 行為分析


首先,我們分析一下這種智慧手環的一些基本行為,例如它如何升級韌體,上傳使用者狀態等。幸運的是,這個客戶端只是一個windows二進位制檔案,因此我們可以很容易的構建好逆向環境。這個Windows客戶端檔案可以在這裡下載。由於客戶端是用C#編寫的,我們可以使用一些例如ILSpy,JustDecompile,dnSpy以及dotPeek之類的工具很容易的對它進行除錯和反編譯。

在對客戶端進行逆向後,我發現客戶端會從雲端下載FirmwareUpdate.bin檔案並將其存放在這個目錄:

#!bash
c:/Users/IEUser/AppData/Local/Microsoft/CargoDevice/u_9e35ffc6-2859-4332-b89c-9110db164d9c/d_ffff1300ffffffff1830454e06000e30/FirmwareUpdate

現在我知道了韌體會從哪裡進行更新,下一步要做的就是獲取用於更新的韌體。因為我的裝置已經是最新韌體了,無法正常獲取更新韌體,所以我需要找到另外一種方法來獲取韌體。或許我可以試著欺騙伺服器?

p1

我使用Burp修改了請求資訊中的版本號,之後它成功的欺騙了伺服器,開始下載FirmwareUpdate.bin檔案。得到這個檔案後我就可以繼續做一些有趣的事情。首先,我們需要分析更新韌體FirmwareUpdate.bin。

#!bash
[email protected] ~/MS_band $ binwalk FirmwareUpdate.bin

DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
29668 0x73E4 LZMA compressed data, properties: 0xA2, dictionary size: 2097152 bytes, uncompressed size: 1966105 bytes
30069 0x7575 CRC32 polynomial table, little endian
244521 0x3BB29 SHA256 hash constants, little endian
853728 0xD06E0 LZMA compressed data, properties: 0xA2, dictionary size: 2097152 bytes, uncompressed size: 1966105 bytes
939669 0xE5695 CRC32 polynomial table, little endian

根據binwalk顯示的資訊,我在網上沒有找到類似格式的有用資訊。因此我決定對FirmwareUpdate.bin進行逆向然後猜測二進位制檔案中不同的部分。我注意到 FirmwareUpdate.bin的大小是0x16D67E位元,這個值儲存在檔案頭的0x13偏移位置:

00000000 5F C3 01 09 00 00 00 00 00 00 00 00 00 00 00 21 00 00 00 7E D6 16 00 C3 23 1E 43 00 C0 65 01 00 00 00 00 01 00 01 C0 65 01 01 00 00 _..............!...~....#.C..e.........e....
0000002C B0 0E 00 02 C0 65 B1 0F 00 68 03 00 00 42 00 CD B4 0F 00 02 73 01 00 2B 00 CF 27 11 00 30 10 00 00 2C 00 FF 37 11 00 30 0C 00 00 2D .....e...h...B......s..+..'..0...,..7..0...-
00000058 00 2F 44 11 00 30 04 00 00 2E 00 5F 48 11 00 30 10 00 00 2F 00 8F 58 11 00 30 04 00 00 30 00 BF 5C 11 00 30 08 00 00 31 00 EF 64 11 ./D..0....._H..0.../..X..0...0..\..0...1..d.
00000084 00 30 04 00 00 32 00 1F 69 11 00 30 24 00 00 33 00 4F 8D 11 00 30 04 00 00 34 00 7F 91 11 00 30 04 00 00 6C 00 AF 95 11 00 30 04 00 .0...2..i..0$..3.O...0...4.....0...l.....0..
000000B0 00 2A 00 DF 99 11 00 6A 06 00 00 29 00 49 A0 11 00 00 03 00 00 46 00 49 A3 11 00 40 0A 00 00 36 00 89 AD 11 00 80 28 00 00 3F 00 09 .*.....j...).I.......F.I...@...6......(..?..
000000DC D6 11 00 40 EF 00 00 41 00 49 C5 12 00 97 B6 00 00 28 00 E0 7B 13 00 D8 15 00 00 49 00 B8 91 13 00 4E 2C 00 00 4A 00 06 BE 13 00 40 ...@...A.I.......(..{......I.....N,..J.....@
00000108 2C 00 00 4E 00 46 EA 13 00 2C 30 00 00 4C 00 72 1A 14 00 10 2F 00 00 4F 00 82 49 14 00 E2 2D 00 00 50 00 64 77 14 00 E6 2D 00 00 4B ,..N.F...,0..L.r..../..O..I...-..P.dw...-..K
00000134 00 4A A5 14 00 06 2F 00 00 4D 00 50 D4 14 00 BA 2C 00 00 24 00 0A 01 15 00 0D 66 00 00 25 00 17 67 15 00 FB 95 00 00 6D 00 12 FD 15 .J..../..M.P....,..$......f..%..g......m....
00000160 00 6C D9 00 00 9F 84 42 00 03 00 0A 00 E8 0C 00 00 00 30 00 00 00 00 01 00 15 05 FF 1F 64 07 C4 91 00 02 FF 1F FF FF FF FF FF FF FF .l.....B..........0..........d..............
0000018C FF 00 00 09 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ............................................
000001B8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ............................................

因為binwalk顯示的資訊中有CRC32多項式表,我決定尋找4位元的CRC校驗值,它應該是在頭資訊中用於完整性檢查。在檔案頭中,你可以在0x17偏移處看到4個位元組的“隨機”資料:0x431E23C3。將這四個位元組替換成'\0'後計算其他資料的CRC值,我們得到了完全相同的結果:

#!bash
Found at offset dec=23 hex=00000017
CRC=431E23C3

看起來這個二進位制檔案使用了CRC校驗值檢查了FirmwareUpdate.bin的檔案完整性。下一步我將嘗試將修改過的韌體推送到手環。我修改了儲存在FirmwareUpdate.bin中的版本號作為測試,看看這個手環是否會接受任意修改過的FirmwareUpdate.bin韌體。如果手環接受了修改的韌體,版本號作為測試值可以很容易的檢驗效果。

0001EC6C 00 4D 69 63 72 6F 73 6F 66 74 20 43 6F 72 70 6F 72 61 74 69 6F 6E 00 00 00 31 30 2E 33 2E 33 33 30 34 2E 30 00 25 75 00 00 30 37 32 .Microsoft Corporation...10.3.3304.0.%u..072
0001EC98 37 00 00 00 00 20 4C 45 00 9F 38 02 00 80 C3 C9 01 0B 2A 02 00 39 39 02 00 FF F7 E8 FE 06 20 28 70 60 68 C5 F8 05 00 01 E0 09 20 28 7.... LE..8.......*..99....... (p`h....... (

不幸的是,我發現手環在進行更新時會檢查韌體有沒有被篡改或者損壞。我需要繞過這個問題,於是我使用了Dnspy設定斷點,並且在客戶端傳送資訊給手環之前對其進行修改。

#!csharp
 private bool PushFirmwareUpdateToDeviceInternal(FirmwareUpdateInfo updateInfo, CancellationToken cancellationToken, KdkFWUpdateProgress progressTracker)
 {
     bool result = false;
     this.CheckIfUpdateValidForDevice(updateInfo.FirmwareVersion);
     Logger.Log(LogLevel.Info, "Verified that the firmware update is valid for the device", new object[0]);
     cancellationToken.ThrowIfCancellationRequested();
     string text = Path.Combine("FirmwareUpdate", "FirmwareUpdate.bin");
     if (this.storageProvider.FileExists(text))
     {
         int.Parse(updateInfo.SizeInBytes);
         this.UploadDeviceFirmware(text, progressTracker);
     }
     string value = this.FirmwareVersions.ApplicationVersion.ToString();
     if (updateInfo.FirmwareVersion.Equals(value))
     {
         result = true;
         Logger.Log(LogLevel.Info, "Verified that the firmware update is successfully installed on the device", new object[0]);
     }
     return result;
 }

上面的C#函式用於將韌體更新傳送到手環

然而在完成這個過程後,我沒有在手環的螢幕上看到韌體安裝的畫面,這意味著它失敗了。似乎他們還有其他的機制用於檢驗韌體完整性。這意味著我不得不繼續對更新韌體進行逆向,根據binwalk顯示的資訊,似乎有一部分程式碼被識別為LZMA資料。現在的問題是我不知道檔案的載入地址。在閱讀了一些關於嵌入式ARM裝置的逆向資料後,我幸運地找到了一個表,其中包含了正確的載入地址0x05c8bf。

#!bash
000d2230 00 bf c8 05 00 11 c9 05 00 4f c9 05 00 8d c9 05 |.........O......|
000d2240 00 93 c9 05 00 99 c9 05 00 f1 c9 05 00 51 ca 05 |.............Q..|
000d2250 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000d2260 00 01 00 00 00 14 00 00 00 00 00 00 00 02 00 00 |................|
000d2270 00 04 00 00 00 00 00 00 00 03 00 00 00 06 00 00 |................|

最終,我使用IDA處理這個二進位制檔案。透過搜尋CRC位置(偏移量) 0x17,我發現了關鍵的CRC校驗函式,並且透過交叉引用我發現了IntegrityCheck函式,以及其他一些檢查函式。整個完整性檢驗程式如下:

1.檢查主CRC

p2

2.檢查塊CRC

p3

3.檢查更新韌體版本號是否高於當前版本

p4

因此我要做的就是將版本號修改為比我當前手環高的數值,然後重新計算塊CRC校驗值,以及主CRC校驗值。

為了方便,我針對這種韌體的二進位制格式寫了一個解析器:

#!bash
Offset: 0x00000000 Magic number: 0xC35F
Offset: 0x00000002 Unkown byte: 0x1
Offset: 0x00000003 Unkown flag: 0x00000009 (looks like GPIO port output speed)
Offset: 0x00000007 Zero padding
Offset: 0x0000000F Total number of sections: 0x00000021
Offset: 0x00000013 Firmware size: 0x0016D67E
Offset: 0x00000017 CRC of whole firmware: 0x431E23C3
Section table:
Offset 0x0000001B section type 0xC000:
 Section offset 0x00000165, size 0x00010000 [ends at 0x00010165]
 Offset: 0x00000004 Version number: 0x000A0003.0x00000CE8 (shown as 10.3.3304)
 Offset: 0x00000010 Section size: 0x00010000
 Offset: 0x00000018 Section CRC: 0x91C40764
Offset 0x00000025 section type 0xC001:
 Section offset 0x00010165, size 0x000EB000 [ends at 0x000FB165]
 Offset: 0x00000004 Version number: 0x000A0003.0x00000CE8 (shown as 10.3.3304)
 Offset: 0x00000010 Section size: 0x000EB000
 Offset: 0x00000018 Section CRC: 0xE46EFF7D
...

接下來,我寫了一個補丁用於修改版本號,以及搜尋修改我想要修改的字串。

#!python
def Patch(filename):
    f = open(filename, 'r+')
    Patched = f.read()

    Patched = VersionNumPatch(Patched, "10.6.3304")

    text1 = TextPad("No new texts, check back in a few.")    #patch the empty text string
    text2 = TextPad("pwned by ------------- mongo&b0n0n")
    Patched = SearchPatch(Patched, text1, text2)

    Patched = CalSectCrc(Patched) # recalculate the section CRCs
    Patched = CalMainCrc(Patched) # recalculate the main CRC

    with open('FirmwareUpdate.Patch', 'w+') as f:
    f.write(Patched)

Patch("FirmwareUpdate.bin")

你可以在我的github上獲取所有程式碼。

在對韌體進行完修改後,我使用了上面一樣的方法將其更新到裝置中。

p5

裝置接收到檔案後,它會檢查檔案的完整性,如果檔案透過所有檢查,你會看到這樣的安裝畫面:

p6

安裝完成後手環會重啟,然後你可以檢查版本號以及其他修改過的地方:

p7

p8

你可以修改將其中的任意程式碼和資料修改為你想要的。

我還沒有購買微軟手環二代,所以我不知道這種方法是否適用於二代的手環。當然們如果你有興趣可以自己進行嘗試。

以上,如果您在文章中發現有任何錯誤,歡迎指正。

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章