重點結論(給趕時間的讀者)
- 功能鎖可以被繞過:付費才能啟用的高階功能,其「鑰匙」是用公開公式從探頭序號計算出來的,鑰匙本身並不保密。
- 一個對外接口沒有安裝防護:同一台設備上的任何應用程式,都可以透過
ThirdPartyManageActivity借用 SonoiQ 儲存影像,病人資料有外洩風險。 - 與醫院系統的加密連線沒有驗證對方身份:加密有開啟,但「對方是否真的是醫院伺服器」的檢查被關閉了。
- 出廠密碼直接寫死在程式碼中:管理員帳號 Admin 的密碼是 12345678,使用已過時的無鹽 MD5 方式儲存。
- 正面評價:資料備份功能已關閉(病歷不會自動流出設備);在本次檢查範圍內,未發現木馬或間諜行為。
注意:以上結論全部來自「靜態分析」(閱讀程式碼後推理),沒有連接任何設備做動態驗證。部分結論標示了信心等級,請以「推論」的態度閱讀。
閱讀指南:這份報告如何使用
- 不需要任何背景知識:每個專業術語在第一次出現時,都會就地附上「人話」解釋。詳細技術資料收在灰色區塊中,可以完全跳過。
- 用比喻理解硬體:灰色虛線框「比喻」區塊,用日常事物解釋硬體概念。
- 安全發現有顏色標籤:紅色 = 高風險(應優先處理)、黃色 = 中風險(應該處理)、綠色 = 低風險(知道即可)。每張卡片都附「如何修復」與「信心等級」。
- 第六部分是術語詞典,但主要術語在正文中已經就地解釋過,詞典是輔助查詢。
SonoiQ 是什麼?
1.1 先從超聲波本身講起
你可能在醫院見過這樣的畫面:醫生手持一個像滑鼠大小的「探頭」,在病人皮膚上滑動,旁邊螢幕立刻出現黑白影像。這就是超聲波檢查(也稱為超音波檢查)。
超聲波 = 用「人類聽不見的高頻聲音」來「觀看」人體內部。探頭發出聲波,聲波碰到內臟會反彈回來,探頭接收「回聲」,電腦再把回聲繪製成影像。原理與蝙蝠在夜間飛行相同,蝙蝠用回聲「看見」物體,醫生用超聲波「看見」內臟。
超聲波檢查之所以普及,是因為它不使用輻射(不像 X 光或電腦斷層),對孕婦與胎兒也相對安全,因此產科檢查幾乎都以超聲波為主。
傳統的超聲波主機,體積相當於一台推車。SonoiQ 做的事情相同,但縮小成一支探頭 + 一部 Android 平板或手機:探頭負責發出與接收聲波,平板負責顯示影像與操作介面。
1.2 SonoiQ App 是什麼
SonoiQ(本報告研究的版本 2.2.15,程式識別碼 com.SonoiQ.uhandprobe)是安裝在 Android 設備上的應用程式。它負責:
- 透過 USB 線或 Wi-Fi 連接探頭;
- 顯示即時超聲影像(黑白結構影像、彩色血流影像等);
- 提供測量工具(例如量度腫塊尺寸)、撰寫報告、儲存影像;
- 內建 人工智慧(AI)輔助功能,可自動辨識膀胱、心臟、甲狀腺等器官(請注意:是「輔助」,不能取代醫生判斷,詳見發現五);
- 支援 語音控制,醫生雙手忙碌時,可以用口頭指令操作(例如「凍結畫面」)。語音辨識使用離線引擎 Vosk,不需要網路,中文與英文都支援;
- 程式碼中包含與醫院系統對接的功能,使用名為 DICOM 的行業標準(DICOM 是醫療影像在醫院之間傳送的「通用語言」,等同醫療界的 PDF 格式)。
這個 App 不是只賣一個品牌。我們發現程式碼中預設了 18 個 OEM 身份編號(OEM = 代工貼牌:由一家工廠製造核心,其他品牌貼上自己的名稱銷售,類似手機界的「公版機」)。原始品牌是 Youkey,其他編號對應 ESAOTE、BD、SonoStar 等貼牌客戶。
1.3 什麼是「APK」?
APK 是 Android 應用程式的「行李箱」格式。一個 App 的所有內容,程式碼、圖片、聲音、甚至探頭韌體(硬體內部的程式),全部壓縮在一個以 .apk 結尾的檔案中。本報告研究的 APK 大小為 299 MB(約等於三部高畫質電影的檔案量),解壓縮後有 2,182 個檔案。
我們做了什麼?(逆向工程=解剖)
2.1 什麼是逆向工程
軟體出廠時,原始程式碼會先被轉換成「機器讀得懂、人類看不懂」的形式(稱為「編譯」)。逆向工程是使用專門工具,把這種形式「還原」回接近人類可讀的程式碼,再研究其運作原理。
本次研究是「離線靜態分析」:只分析使用者自己持有的 APK 檔案,沒有連接任何設備、沒有入侵任何系統、沒有修改任何市售產品。換句話說,就像拆解自己買回來的電器,這是本次報告的工作範圍。任何超出此範圍的用途,都不在本報告的內容之列。範圍細節記錄在專案的 scope.md 檔案中。
2.2 靜態分析與動態分析的分別
資安研究通常分兩種做法,本報告只做第一種:
- 靜態分析(本次採用):像讀食譜一樣閱讀程式碼,不執行它。優點是安全、不需設備;限制是只能推論「程式碼看起來會做什麼」,無法證明「實際運行時一定如此」。
- 動態分析(本次未做):把程式真的跑起來,觀察它實際的行為(例如真的攔截它送出的網路封包)。需要實體設備,屬於後續工作。
因此,本報告中的每個結論都標示了「信心等級」,高代表程式碼證據非常直接,中代表有推論成分,並註明哪些部分需要動態驗證。
2.3 使用的工具
| 工具 | 功能 | 白話比喻 |
|---|---|---|
| jadx | 將程式碼還原成 Java 語言 | 解凍機,把急凍蛋糕解凍 |
| apktool | 將 APK 完全解包(含資源與圖片) | 開箱工具,把所有物品逐件取出 |
| radare2 / rabin2 | 分析最深層的機器碼 | 顯微鏡,觀察肉眼看不到的細節 |
| strings / xxd | 在檔案中搜尋文字線索、檢視原始資料 | 放大鏡與濾網 |
2.4 解剖流程(六個步驟)
登記樣本
記錄檔案指紋(SHA-256,一條 64 字元的唯一驗證碼),確保整個研究過程對象一致。
盤點資產
解壓縮並列出全部 2,182 個檔案:28 個引擎程式、77 個探頭型號資料、13 個 AI 模型……
還原程式碼
jadx 還原出 6,025 個 Java 檔案(其中約 1,050 個是廠商自行撰寫,其餘是公開工具庫);中層格式 smali 有 11,997 個。
追蹤資料流向
從「探頭讀取影像」開始,一路追蹤到「畫面顯示」,畫出完整的資料路線圖。
解碼授權系統
研究它如何鎖住「需要付費購買的功能」,找出鎖的構造與繞過條件。
安全檢查
以十六項檢查清單逐項檢視:加密、密碼、外部接口……逐項評分。
App 內部結構 — 六層全景
整個系統可以想像成一棟「六層樓」。從底層(硬體)到頂層(你看到的畫面):
3.1 每一層的白話解釋
第 1 層:探頭硬體
探頭內部有兩顆關鍵晶片,其中最重要的是 FPGA:
FPGA = 一顆「可以重新接線」的萬能電路晶片。一般晶片出廠時功能就已固定;FPGA 則可以在每次開機時載入一份「接線圖」,改變自己的功能。SonoiQ 使用的是 Efinix Trion T55F324 型號,我們在韌體檔案的「出生證明」(明文註解)中找到它的完整身份,還包括專案代號 YK2100。
「波束形成」= 用數學方法控制 16 或 32 個微小發聲單元(壓電陣元)的發聲時間差,讓聲波像探照燈一樣聚焦到想觀察的方向。這是超聲波成像的核心技術,沒有它,就無法把聲波「瞄準」到身體深處。
第 2 層:連接方式與 FPGA 的「貨架」
App 支援七種連接方式(有線 USB、無線 Wi-Fi、模擬模式等)。我們逆向出 USB 通訊的完整地圖:影像資料存放在 FPGA 內三個固定地址(0x20000、0x40000、0x60000),App 定時到這些地址「取貨」。
USB VID 0x04B4 = Cypress Semiconductor(USB 晶片製造商),資料通道為 EP6 bulk,FIFO 緩衝 2,048 字節。三個貨架位:B 影像 @0x20000、H.264 編碼流 @0x40000、T/M 影像 @0x60000。B 幀單次讀取量為 131,072 字節(128 KB);幀首字節為負值時代表影像左右相反,需要反轉處理。Wi-Fi 探頭使用 UDP 端口 8081 通訊,指令封包以 0xFE 開頭、0xFF 結尾,而檢查結果顯示,封包沒有任何防錯驗證碼(詳見第五部分 S-16)。
第 3 層:原生引擎
「原生引擎」是指用更底層語言(C/C++)撰寫的高效能程式(副檔名 .so,等同 Windows 的 .dll)。其中最重要的是名為 libdoppler 的檔案(15.4 MB):
第 4 層:訊息泵
底層引擎與上層介面之間,靠一條「對講機頻道」溝通。我們把這條頻道的原始機器碼完整還原,確認了便條的格式:
底層會產生一疊「便條」,上層每秒輪流查看有沒有新便條。每張便條固定 16 字節,記錄三個數字:what(發生什麼事,32 位元)、arg1(第一個相關數值,32 位元)、arg2(第二個相關數值,64 位元)。例如「影像已就緒」「按鍵被按下」等事件,都會以這種便條形式傳遞(此處僅為格式說明,非實際事件代碼)。
這個發現的實用價值:將來可以使用 Frida 工具(一種動態攔截工具),在 App 運行時即時讀取這些便條,觀察底層引擎實際在傳遞什麼訊息。
第 5 層:業務核心
這一層由 Java 撰寫,像一間「辦公室」:名為 Ultrasys 的總指揮協調一切;另有十六類 AI 輔助功能(膀胱、心臟射血分數、肺部 B 線、甲狀腺、多囊卵巢、乳腺、皮膚、靜脈曲張、頸動脈等)。病人資料存放在三個 SQLite 資料庫中(SQLite 是一種輕量級資料庫格式,等同 App 內建的「檔案櫃」)。
第 6 層:畫面
開機後首先看到登入畫面。我們發現出廠預設密碼是「Admin / 12345678」,且密碼以過時的無鹽 MD5 方式儲存,詳細說明見第五部分 S-09。
五個重要發現
功能鎖的「鑰匙配方」寫在門牌上
超聲設備業界有個常見的商業模式:硬體完全相同,軟體功能分級販售。SonoiQ 將「Color 彩色血流」、「PW 血流測速」、「DICOM 醫院對接」等功能,以授權碼鎖定;授權碼存放在探頭硬體內部的一顆小晶片(EEPROM,斷電後仍會記住資料的記憶體)中。
我們把這套鎖的構造完全拆解。驗證流程是:
① 讀取探頭序號(SN)→ ② 將序號代入一個 hash 公式(hash=單向指紋計算,見詞典)→ ③ 得到一組數字 → ④ 與 EEPROM 中儲存的授權碼比對 → ⑤ 相同則開放功能,不同則鎖住。
關鍵問題在於:程式一共使用了六種 hash 公式,全部是數十年來公開的教科書算法,DJB2(對應 B 模式)、BKDR(Color)、FNV(PW)、BP(DICOM)、JS(人/獸醫)、DEK(使用時間)。我們甚至以反組譯確認了公式的實際參數(例如 DJB2 的起始值 5381)。
也就是說:任何取得探頭序號的人,用十行程式碼就能自行計算出正確的授權碼。
S 系列探頭授權儲存於 EEPROM 位址表:B @28288、PW @28240、Color @28256、DICOM @28224、人/獸醫 @28308、OEM 品牌 ID @28312;R 系列則儲存於 SD 卡區塊 2–12。反組譯證據:DJB2 起始值 0x1505(=5381)、每步乘以 33;FNV 使用乘法加 XOR;BKDR 使用乘法加加法。繞過條件:HSUsbProbeCh16.VerifyAuth() 硬編碼回傳 true;GetOEMAuth(255) 一律放行;序號前兩字節為零且授權碼為零時,自動寫入完整授權。
隱藏功能比說明書多得多
- 租賃模式:程式碼包含「使用時間/次數授權」,類似影印機租賃,探頭可以按使用量計費(使用第四種公式 DEK;檢查點在最深層引擎中,是否真的啟動需動態驗證)。
- 獸醫七級:不只是「人用/獸用」兩種,實際支援 0–6 共七個獸醫等級。
- RF 原始資料採集:可取得未加工的「生肉級」回聲資料(單幀最多約 2 MB),研究與工程用途。
- FPGA 現場升級:將新韌體檔案放入指定資料夾,App 下次啟動時自動更新探頭「腦筋」。
- 一探頭多機:支援多台設備同時觀看同一探頭(教學用途)。
- 模擬模式:沒有探頭也能示範操作(畫面播放模擬資料)。
- 第三方嵌入:其他 App 可以呼叫超聲功能(存在安全問題,見第五部分 S-14)。
一支探頭家族:77 個型號+13 個 AI 模型
一個壓縮檔(PID03.zip,檔案大小 140.8 MB)裝著 77 個探頭型號的完整參數,凸陣(腹部)、線陣(血管/甲狀腺)、相位陣列(心臟)、腔內探頭(婦科)……每個型號都有一份約二十萬字節的「出生證明」,描述其發聲特性與成像參數。
同一壓縮檔內還有 13 個 AI 模型檔案(解壓縮後合計約 165 MB)。檔名帶有耐人尋味的線索:例如疑似訓練樣本數量(n7000)與輸入尺寸(256x192)。請注意:這些是從檔名推測的線索,並非訓練資料的證明。其中包含一個「乳腺影像分割」模型(23.9 MB)。
此外,程式支援 40 種以上的檢查模式,包括眼科、前列腺、睪丸、經顱(檢測腦部血流)等並非每台設備都有的模式。
硬體身份完整曝光
| 問題 | 答案 | 證據 |
|---|---|---|
| FPGA 是哪家廠商? | Efinix Trion T55F324 | 韌體檔案的明文註解 |
| Wi-Fi 晶片? | TI CC3220R / CC3235S | 韌體+啟動向量表 |
| USB 晶片? | Cypress(VID 0x04B4) | 程式碼常數 |
| 真正的品牌? | Youkey(專案代號 YK2100) | FPGA 專案路徑+OEM 清單 |
| 殘留的開發路徑? | D:\Project\FPGA\YK2100_FPGA_T55_new | RBF 檔案註解殘留 |
最後一列的 Windows 路徑,是工程師在打包韌體時不小心留在檔案中的痕跡,這類「指紋」在逆向工程中很有價值,可用於確認開發環境與內部專案命名。
十六類 AI 輔助功能由真實模型驅動
| 模型 | 大小 | 用途(EF=射血分數,心臟每次搏動的泵血比例;B 線=肺部積液跡象;PCOS=多囊卵巢症候群) |
|---|---|---|
| ResUNet_Bladder | 23.9 MB | 膀胱自動量測體積 |
| breast_lite | 23.9 MB | 乳腺影像分割 |
| Carotid v&l | 17.7 MB | 頸動脈自動定位 |
| skin_segment | 17.5 MB | 皮膚層分割 |
| cardiac_ef | 13.8 MB | 心臟射血分數計算 |
| lung_bline | 13.4 MB | 肺部 B 線檢測 |
| ob_hc/thyroid/varicosity/pcos 等 | 每個 4.6–7.9 MB | 產科頭圍、甲狀腺、靜脈曲張、多囊卵巢 |
安全報告卡 — 十六項檢查結果
我們以十六項清單逐項檢查,以下是最重要的五項(完整十六項見技術文件)。每張卡片包含:觀察到的證據、影響、修復建議、信心等級。
信心等級說明:「高」代表程式碼證據直接明確;「中」代表包含推論成分;未經動態驗證的部分會明確標示。
對外接口沒有防護:任何 App 都能借用 SonoiQ 存取影像與病人資料
觀察到的證據:App 有一個對外開放的「接待處」(技術上稱為 exported Activity:意即「允許其他應用程式啟動」的活動介面,名稱是 ThirdPartyManageActivity)。同一台設備上的任何應用程式都可以啟動它,無需任何身份驗證。
影響(推論):惡意 App 可以將假病人資料寫入病歷資料庫;可以指定一個資料夾,讓超聲影像與 PDF 報告自動複製過去(包含病人姓名等私隱資料);甚至可以強制 App 崩潰。
com.Com.handprobe.ThirdPartyManageActivity(manifest 中 exported=true,無權限保護)· 輸入參數:PATIENTID/NAME/GENDER/AGE/SAVEIMG_PATH/EXPORT_MODE · 輸出方式:將影像 PNG+PDF 複製到指定路徑,或經 IMG_PATH 回傳絕對路徑。
功能授權鎖可被完整繞過
觀察到的證據:授權碼=以公開 hash 公式(DJB2/BKDR/FNV/BP/JS/DEK)對探頭序號計算;寫入通道(USB 廠商專用指令 24)沒有簽章、沒有加密;另存在多個繞過條件(ch16 型號驗證硬編碼放行、OEM 萬能碼 255、序號歸零時自動授權)。
影響(推論):有能力接觸硬體的人,可自行計算並寫入授權碼,解鎖全部高階功能(Color/PW/DICOM)。這屬於商業模式風險,廠商依賴功能分級收費,但這把鎖本身沒有保密性。
與醫院系統的連線:有加密,但沒有「驗明正身」
觀察到的證據:App 具備「醫院資訊系統(HIS)對接」功能。檢查發現其加密連線的身份驗證被完全關閉,程式不會檢查「對方是否真的是醫院伺服器」。簽名使用 SHA-1+Base64(Base64 只是編碼方式,不是加密;SHA-1 已被證實存在碰撞攻擊而過時),且簽名使用的時間戳是寫死的(不是即時時間)。
影響(推論):在不安全的網路(例如開放 Wi-Fi)中,攻擊者可以偽裝成醫院伺服器,攔截醫院帳號密碼。
HttpProtocol_hle:checkServerTrusted() 空實作+hostnameVerifier 恆回傳 true+SHA-1+Base64+硬編碼時間戳。
出廠密碼寫死在程式碼中
觀察到的證據:登入畫面的出廠帳戶是 Admin/12345678,直接寫在程式碼中;密碼以「無鹽 MD5」儲存(「無鹽」=沒有加入隨機調味料,相同密碼會產生相同指紋,容易以預先計算好的對照表反查);另有一個空密碼的「緊急」帳戶。
影響(推論):任何能實體接觸設備的人,都可以用已知的預設密碼登入。好消息是:App 已關閉資料備份(allowBackup=false),病歷不會被 Android 系統自動備份出去。
探頭無線通訊沒有防錯機制
觀察到的證據:Wi-Fi 探頭的通訊協定中,檢查函數是「空殼」,收到的資料沒有驗證碼(checksum;checksum 是附加在資料後方的一小段檢查值,用於偵測資料是否在傳輸中損壞或被竄改)。
影響(待動態驗證):靜態分析只能證明「沒有防錯機制」,不能證明可以遠端注入指令或竄改影像。要判斷實際影響,需要動態測試:探頭 Wi-Fi 的有效範圍(通常很近)、封包注入的可行性、影像完整性對醫療安全的影響。
5.1 正面觀察(本次檢查範圍內)
- 本次靜態檢查範圍內,未發現木馬或間諜行為(沒有暗中上傳資料、沒有遠端控制後門)。
- 資料備份預設關閉(病歷不會自動流出設備)。
- 程式碼未經過惡意混淆或加殼(透明度高,易於稽核)。
- 程式碼包含本地 AI 推論能力(影像可在設備內處理,不需上傳雲端),但「實際是否會連網」屬於動態行為,靜態分析無法完全證明。