Hacking 智能手環
來自專欄安全客
進入現在這個公司第一天上班的那天,有一大堆東西讓我痴狂不已。在這堆東西中其中就包含一個可以自己定製的健康監測手環。從技術角度上來看,能隨時隨地監測健康狀態真是太酷了。
- 很小的尺寸(大約 15mm x 40mm)
- 低功耗藍牙(BLE)
- OLED 顯示屏(96 x 32 像素)
- 可充電電池
- 支持USB 充電
- 加速度感測器
- 振動馬達
- 價格在10 美元左右
在手環外面,除了背部印有「 FCC ID: 2AHFTID115 」,就沒了其他標識。搜索了一下,發現這個設備的名字是 ID115,另外還有些內部構造的圖片。仔細觀察可以看到那塊最大的晶元上寫著 「 N51822 」 ,這表明微控制器單元 (MCU) 很可能是 Nordic 的 nRF51822,一塊支持低功耗藍牙的 32 位 ARM Mo CPU。從理論上來講,這可以編程實現手環現有功能以外的其他事情。
手環拆開前後
在拆卸它之前,我上谷歌搜索到了使用相同晶元類似的手環,不少人成功的拆開了手環。拆開它其實並不容易,黑色的塑料蓋子粘在了灰色的塑料後蓋上。我用電吹風加熱讓膠水軟化,然後用小刀小心翼翼的切開膠水,確保手環不會受到太大的傷害。拆開之後,我確認它確實使用的是 nRF51822。後來,我買了一個看似相似的手環,但是這個手環使用的是德州儀器的 MCU ,這個差異需要的特別注意。nRF51822與圓珠筆大小對比 想辦法和它說話從手冊上了得知,晶元上的串口調試 Serial Wire Debug(SWD) 的兩個引腳可用於編程/調試。這意味著兩件事,如果我們想和它對話:- 我們需要一個 「SWD programmer」 (例如 segger的 J-Link 模擬器)
- 我們需要訪問 SDW 的兩個引腳,即 SDWIO(數據) 和 SWDCLK(時鐘)
幸運的是,板子上有不少裸露的墊片。他們的存在意味著需要進一步的調試/測試/驗證。我想一定是有一個很酷的工程師預留著這些墊片,對於像我這樣的人來說這簡直就是給我們準備的禮物。不是所有的墊片都有標註,我根據我的猜測做了標註。
nRF51822 引腳板子描述SWDIOIO數據引腳SWDCLKCLK時鐘引腳
Open-chip 手術為了能夠訪問 SWD 的兩個引腳,我在板子上給各個接觸墊焊接了很細的線。閃爍下一個目標是嘗試編程實現一些其他事情。為了運行最簡單的程序,我們需要確保:- 我們正確地跟蹤了SWDIO/SWDCLK引腳
- SWD 編程器正常運行,能和計算機交互
- 使用 Nordic』s sdk 交叉編譯Arm 程序
- 能夠把編譯好的程序放到晶元中
- 晶元正確的驅動和引導我們的程序
本案例中 「hello,world」 程序是實現 LDE 發光二極體不間斷的閃爍。即使這樣其實也不簡單,首先板子上沒有 LED 發光二極體。如果我們自己額外添加一個,那就必須搞清楚該接在什麼地方。這增加了問題的另外一個自由度。天下沒有免費的午餐,我只在 P1
和 P2
上連接了兩個 LED,希望能夠在 MCU 上找到對應的引腳。
凌亂的連線
為了能夠使用 J-Link 模擬器,需要從 segger 網站上下載驅動和命令行程序。如果你使用的是 MacOS,那麼你就可以 homebrew 進行安裝。caskroom/drivers/segger-jlink
提供了支持。安裝好之後你就能使用命令行程序 JLinkExe
與 SWD 模擬器進行通信了。隨後,我下載並解壓了 Nordic『s nRF5 SDK(我使用的是version 12.3.0)。在 SDK 中挖掘示例,很明顯我們需要一個知道如何輸出 Arm 程序的編譯器,於是我安裝了gcc-arm-embeded
(同樣可通過 homebrew 安裝)。在 Nordic 的開發者論壇上瀏覽SDK 有關的帖子,發現通常使用的開發板是這個。SDK 預先配置了一些開發包的變數,要實現直接和 MCU 對話,我們需要修改 SDK 中的一些設置。跑馬燈我花了很多時間去了解 nRF5 系統如何讓程序跑起來的,最終搞懂了來龍去脈。在上面的的視頻中可以看到兩個閃爍的 LED。於是,我創建了一個 github 倉庫 ,另外還寫了 Makefiles
。其中一個最大的技巧是找到 nRF51822 的一些變數,例如我的 RAM 只有 16KB。考慮到這些因素,我們需要對鏈接器腳本做些調整。數字 IO正如我所提到的,讓 LED 閃爍還包含著希望和猜測 MCU 的哪個引腳與P1
和 P2
相連,P1
和 P2
連接著 LEDs。最簡單的方法是讓數字 IO 引腳不斷重複升高和降低輸出。讓我驚訝的是,兩個 LED 都被點亮了。更讓我吃驚的是振動馬達也能開啟和關閉。手動進行查找,我確定了以下的映射關係。
nRF51822 引腳板子描述P0.30P1通用數字 IOP0.00P2通用數字 IOP0.01–振動馬達
printf在調試時,與計算機進行對話的能力是非常寶貴的。J-Link 模擬器支持 Real-Time Transfer (RTT)。RTT 晶元與計算機之間發送和接收數據。通過包含頭文件#include "SEGGER_RTT.h"
,並調用函數 SEGGER_RTT_WriteString()
來使用它。在電腦上讀取它需要用到 J-Link 包中的命令行程序 jlinkrttlogger
。OLED另一個極具挑戰性的任務是點亮 OLED 顯示屏。市場上常見的 OLED 顯示屏使用 ssd1306 驅動/控制器,與 MCU 之前串列通信,如 SPI、I2C。我發現在一般的商店很難購買到 96×32 像素的顯示屏,看起來這種解析度並不是常規型號。上谷歌搜索了屏幕上的 「QT1316P01A」,最佳匹配的是一個中國網站。我在全球速賣通找到了最為接近的,但是除了有引腳名稱外沒有任何其他文檔。引腳標誌1C2P2C2N3C1P4C1N5VBAT6NC7VSS8VDD9RES#10SCL11SDA12IREF13VCOMH14VCC來自阿里全球速遞通的 OLED 腳針定義如果上面的表格標註的準確的話,從 SCL、SDA、RES# 引腳可以看出它支持 I2C匯流排。如果我們可以找到 nRF51822 引腳與 OLED 引腳之間的三根合理的連線,那這將是一個好的開端。再來用顯微鏡看看。
# ...
TWI scanerTWI device detected 0x3c真是一個好消息,我們有理由相信顯示屏被真確識別了,它也的確使用 I2C 匯流排。上谷歌搜索發現,0x3c
是這類設備的通用地址。現在,我們可以嘗試發送一些像素到顯示屏上。在這個級別沒有抽象的庫可用。在 ssd1306 的文檔中,我們找到了一些低層級的方法來發送數據到顯示屏。該過程由一些列配置命令組成。其中包括設置屏幕方向、寫入模式、大小。之後,把在屏幕上顯示的數據位元組序列發送到顯示器的圖形顯示數據 RAM(GDDRAM)中。為了得到正確的配置,我看了一下Adafruit』s ssd1306 library,並嘗試枚舉出相似的命令。我在這個項目中花在這裡的時間最多。把所有細節都搞清除是非常耗時的。直到現在仍然還有些行為我無法解析,然而顯示器已經可以正常顯示數據了。繪製了一個硬編碼的點陣圖這是示常式序。
通過這些設置,顯示屏被劃分為包含 96 行的 4 行(頁)。所以每一頁的高度為 8 像素。發送的第一個位元組的數據會被垂直的放在第一列上;第二個位元組的數據會佔據第二行的未知;第三行類似,直到第 96 行。當第一頁寫完,會到第二頁繼續類似的過程。
或者說,這是預期的結果。下面視頻中觀察的結果卻不相同: 首先是一些奇數列被填充,然後是偶數列,最後才是類似的循環過程。調試慢放版的點陣圖顯示我花了很長的時間去弄明白為什麼我在屏幕上看得到無意義的內容,然後又花了些時間調整配置來修復它。最後我放下了自尊,把這個奇怪的渲染邏輯在程序中實現,今天就到此為止吧!Arduino 之旅在我挖掘 Adafruit』s ssd1306 庫時,我希望有一種方法可以在 nRF51822 中 「模擬」 Arduino特定的比特。事實上已經有經驗豐富的大神做了相似的項目,此項目還不止於此,他使用 nRF5 SDK 實現了 Arduino 核心庫。使用這個項目,我們可以打開 Arduino IDE 選擇 nRF5 板,我們可以使用 Arduino 現有的生態開發程序。我 fork 了這個項目,並添加了對我們的這個手環板子的支持。可以在下拉菜單中選擇使用Tools > Board > ID115 Fitness Bracelet(nRF51822)
。
0V
,我們會讀取到 0
;當輸入為 VCC
時,我們會讀取到 1023
;當輸入電壓介於在它之間時也對應著相應的數值。我定期的輸出模擬信號的值,並繪製出了完整的信號結果。震動板和充電對模擬輸入的影響我認為 P0.05
引腳和充電狀態有關。在充電是他的數值會升高,不充電的時候會下降。我懷疑 P0.26
引腳連接著加速度感測器輸出,當我搖動手環時它的數值會飆升。P0.03
和 P0.04
可能也連著著加速度感測器輸出,但是這種行為可能對應著晶元輸入的二階效應。例如,注意在第一張圖中當加速度感測器需要更多的能量時,電池電量(pin5)也會抖動。下面是一個二階效應的例子。代碼可以在sketch上找到。原始數據和繪製腳本在這裡。現在我們又可以在我們的映射表中添上幾行了。nRF51822 引腳板子描述P0.05–模擬輸入-與電池充電相關P0.26–模擬輸入-加速度感測器P0.03–模擬輸入-加速度感測器(可能)P0.04–模擬輸入-加速度感測器(可能)按鈕在最初的固件中,觸控手環屏幕的指定位置可以點亮屏幕。如果我記得沒錯,按住它可以用來計時。這並不是一個實體點擊按鈕,而是某種運行效果不錯的電容感測器。使用相同的方法找到數字輸出,我找到了它與 MCU 連接方式。按鈕代碼可以在這裡找到。nRF51822 引腳板子描述P0.10–數字輸入-內置按鈕低功耗藍牙(BLE)nRF5 的藍牙功是使用一個稱為 SoftDevice 實現的。它是包含在 BLE 的堆棧中的預編譯二進位文件。它應該獨立於應用程序運行。SoftDevice 有相當多的版本,找到正確的版本依賴於 SDK 的版本和晶元的版本。文檔(不幸的是沒有直達鏈接)兼容表中可以查詢到指定晶元版本對應那個 SDK 版本和 SoftDevice 版本。對於我而言,晶元上標有 「QFAAHO」 ,它有 256 KB 快閃記憶體,16KB RAW,與 SoftDevice s130 兼容。我使用的 12.3 版本的 SDK 裡面有一些使用 Software s130 的示常式序。與我們到目前為止刷入的程序相比,這些程序直接被刷入到地址 0x0
。現在我們需要將 SoftDevice 刷入到地址 0x0
, 實際的地址是 0x1b000
。啟動並初始化後,為了說明這一點,我做了一個類似 binky 的例子。但這裡從 SoftDevice 開始,觀察到的行為是一致的,除了我們需要確保 SoftDevice 在之前就被刷寫過。$ make# ...$ make flash-softdevice# ...$ make flash# ...$ make log# ...Hello,world!可以說,在藍牙應用中最簡單的 「Hello World」 程序是把設備變為信標。信標只廣播自己,監聽者的責任是探測到在其範圍中信標並做出反應。這個 SDK 在相同的 ble_app_beacon
下提供了這樣一個示例。它會假定 SoftDevice s130
在之前已近燒寫了。在這裡,我們直接與晶元通信,而不是通過 SDK,這讓事情變得更加困難。此外,還不得不調整 RAM 的大小(正如我從 blinky 示例中學到的那樣),另外一個難以追蹤的問題。事實證明,BLE 堆棧使用一個晶振來執行時間敏感的任務。SDK 示例假定有一個外部晶振。曾經我使用了上千個 printf
來搞清楚這些,需要將配置標誌更改為使用合成時鐘生成器來解決這個問題。信標源碼在這裡可以找到。BLE + Arduino一旦使用 nRF5 SDK 的 BLE 示常式序運行正常,並且了解了 RAM 和晶振陷阱。 我一次又一次的看了 Arduino 的運行環境。sandeepmistry/arduino-BLEPeripheral是做 Aruino-nRF5 項目的那個人的另一個很棒的項目。它提供了在設置 BLE 外圍設備的內部細節的一個不錯的抽象。使用 BLE 點亮藍色的 LED(使用這個 APP)讓我驚訝不已的是,我並沒有 fork 這個庫。Arduino-nRF5 項目的作者花了些時間讓所有的板子都是可配置的,於是需要在下拉菜單 Tools > Low Frenquency Clock > Synthesized
中選擇合適的 SoftDevice 和晶振源。真是了不起,你可以在上面的視頻中看到,我寫了一個開關 LED 的 快速上手的例子。視頻: https://delikely.github.io/2018/05/27/-Hacking-/
下一步此時,在數周的時間裡,我盯著這塊板看了好幾個小時之後,我非常期待能把它重新放回抽屜的後面,並把它放在那裡一段時間。注: 原作者已授權譯文聲明
本文是翻譯文章,文章原作者,文章來源:https://rbaron.net/
原文地址:https://rbaron.net/blog/2018/05/27/Hacking-a-cheap-fitness-tracker-bracelet.html作者:橋的斷想
推薦閱讀:
※各位自學網路安全的朋友們,你們的路線是什麼?
※一些牛逼的編程高手每天的生活是怎樣?
※如何看待阮一峰的博客被人攻擊?
※勒索病毒是網路安全的轉折點還是360的事件營銷?
※如果讓現代的十個頂尖黑客穿越到1981-1990年會怎樣?