تنهن ڪري، هر شي ظاهر ڪري ٿو (جيئن اسان [پهريون حصو] ()) ۾ قائم ڪيو آهي ته PIN ڪوڊ PSoC جي فليش کوٽائي ۾ ذخيرو ٿيل آهي. تنهن ڪري، اسان کي انهن فليش جي کوٽائي کي پڙهڻ جي ضرورت آهي. ضروري ڪم جي سامهون:
microcontroller سان "ڪميونيڪيشن" جو ڪنٽرول وٺو؛
چيڪ ڪرڻ جو هڪ طريقو ڳوليو ته ڇا هي "مواصلات" ٻاهران پڙهڻ کان محفوظ آهي؛
تحفظ کان پاسو ڪرڻ جو رستو ڳوليو.
اتي ٻه جڳھون آھن جتي صحيح پن ڪوڊ ڳولڻ جو احساس ٿئي ٿو:
اندروني فليش ياداشت؛
SRAM، جتي پن ڪوڊ محفوظ ڪري سگھجي ٿو ان کي صارف پاران داخل ڪيل پن ڪوڊ سان موازنہ ڪرڻ لاءِ.
اڳتي ڏسندي، مان نوٽ ڪندس ته مان اڃا تائين اندروني PSoC فليش ڊرائيو جو ڊمپ کڻڻ ۾ ڪامياب ٿي چڪو آهيان - هارڊويئر حملي کي استعمال ڪندي ان جي حفاظتي نظام کي پاسو ڪندي "ڪولڊ بوٽ ٽريڪنگ" - ISSP پروٽوڪول جي غير دستاويزي صلاحيتن کي رد ڪرڻ کان پوءِ. هن مون کي سڌو سنئون اصل پن ڪوڊ ڊمپ ڪرڻ جي اجازت ڏني.
$ ./psoc.py
syncing: KO OK
[...]
PIN: 1 2 3 4 5 6 7 8 9
سڀني ويڪٽرن جي ڊيگهه ساڳي آهي: 22 بٽ. HSSP دستاويزن ۾ ISSP تي ڪجهه اضافي معلومات آهي: “هڪ ISSP ویکٹر ڪجهه به نه آهي ٿورو تسلسل جيڪو هدايتن جي هڪ سيٽ جي نمائندگي ڪري ٿو.”
5.2. Demystifying Vectors
اچو ته سمجهون ته هتي ڇا ٿي رهيو آهي. شروعات ۾، مون سمجهيو ته اهي ساڳيا ویکٹر M8C هدايتن جا خام نسخا هئا، پر هن مفروضي کي جانچڻ کان پوءِ، مون دريافت ڪيو ته آپريشن جا اپڪوڊس نه ٿا ملن.
پوءِ مون مٿي ڏنل ویکٹر کي گوگل ڪيو ۽ ڀر ۾ آيو هي هڪ مطالعو جتي ليکڪ، جيتوڻيڪ هو تفصيل ۾ نه ٿو وڃي، ڪجهه مفيد مشورا ڏئي ٿو: ”هر هدايت ٽن بِٽن سان شروع ٿئي ٿي جيڪي چار يادگيرين مان هڪ سان ملن ٿيون (ريم کان پڙهو، رام ڏانهن لکو، رجسٽر پڙهو، رجسٽر لکو). پوءِ اتي 8 ايڊريس بِٽ آھن، ان کان پوءِ 8 ڊيٽا بِٽ (پڙھڻ يا لکڻ) ۽ آخر ۾ ٽي اسٽاپ بِٽ.
پوءِ مان سپروائيزري روم (SROM) سيڪشن مان ڪجھ تمام مفيد معلومات گڏ ڪرڻ جي قابل ٿيس. ٽيڪنيڪل دستياب. SROM PSoC ۾ هڪ هارڊ ڪوڊ ٿيل ROM آهي جيڪو يوٽيلٽي فنڪشن مهيا ڪري ٿو (ساڳئي طريقي سان Syscall) پروگرام ڪوڊ لاءِ يوزر اسپيس ۾ هلندڙ:
00h:SWBootReset
01h: ReadBlock
02h: WriteBlock
03h: EraseBlock
06h: ٽيبل ريڊ
07h: چيڪ سم
08h: Calibrate0
09h: Calibrate1
ویکٹر جي نالن کي SROM افعال سان ڀيٽڻ سان، اسان مختلف عملن کي نقشي ڪري سگھون ٿا جيڪي ھن پروٽوڪول جي مدد سان متوقع SROM پيرا ميٽرز سان. انهي جي مهرباني، اسان ISSP ویکٹر جي پهرين ٽن بٽ کي ڊيڪوڊ ڪري سگهون ٿا:
100 => ”ويرم“
101 => "rdmem"
110 => ”ورگ“
111 => "rdreg"
بهرحال، آن-چپ جي عملن جي مڪمل سمجھ صرف PSoC سان سڌي رابطي ذريعي حاصل ڪري سگھجي ٿي.
5.3. PSoC سان رابطو
جيئن ته Dirk Petrautsky اڳ ۾ ئي آهي بند ٿيل سائپرس جو HSSP ڪوڊ Arduino تي، مون ڪيبورڊ بورڊ جي ISSP هيڊر سان ڳنڍڻ لاءِ Arduino Uno استعمال ڪيو.
مهرباني ڪري نوٽ ڪريو ته منهنجي تحقيق جي دوران، مون ڊرڪ جي ڪوڊ کي تبديل ڪيو. توھان ڳولي سگھوٿا منھنجي تبديلي GitHub تي: هتي ۽ لاڳاپيل Python اسڪرپٽ Arduino سان رابطي لاءِ، منهنجي مخزن ۾ cypress_psoc_tools.
تنهن ڪري، Arduino استعمال ڪندي، مون پهريون ڀيرو "مواصلاتي" لاء صرف "سرڪاري" ویکٹر استعمال ڪيو. مون VERIFY حڪم استعمال ڪندي اندروني ROM پڙهڻ جي ڪوشش ڪئي. جيئن توقع ڪئي وئي، مان اهو ڪرڻ کان قاصر هو. شايد حقيقت اها آهي ته پڙهڻ جي حفاظت بٽ کي فليش ڊرائيو اندر چالو ڪيو ويو آهي.
هن ویکٹر کي استعمال ڪندي (psoc.py ۾ read_security_data ڏسو)، اسان SRAM ۾ 0x80 تي سڀ حفاظتي بٽ حاصل ڪندا آهيون، جتي هر محفوظ بلاڪ ۾ ٻه بٽ هوندا آهن.
نتيجو مايوس ڪندڙ آهي: هر شي محفوظ ڪئي وئي آهي "خارجي پڙهڻ ۽ لکڻ" موڊ ۾. تنهن ڪري، نه رڳو اسان فليش ڊرائيو مان ڪجھ به نه پڙهي سگهون ٿا، پر اسان ڪجهه به نه لکي سگهون ٿا (مثال طور، اتي هڪ ROM ڊمپر نصب ڪرڻ). ۽ تحفظ کي غير فعال ڪرڻ جو واحد رستو مڪمل طور تي پوري چپ کي ختم ڪرڻ آهي. 🙁
6. پهريون (ناڪام) حملو: ROMX
بهرحال، اسان هيٺ ڏنل چال کي آزمائي سگهون ٿا: جيئن ته اسان وٽ صوابديدي آپڊ ڪوڊس کي عمل ڪرڻ جي صلاحيت آهي، ڇو نه ROMX تي عمل ڪيو وڃي، جيڪو فليش ميموري پڙهڻ لاء استعمال ڪيو ويندو آهي؟ اهو طريقو ڪاميابي جو هڪ سٺو موقعو آهي. ڇاڪاڻ ته ReadBlock فنڪشن جيڪو SROM مان ڊيٽا پڙهي ٿو (جيڪو ویکٹر پاران استعمال ڪيو ويندو آهي) چيڪ ڪري ٿو ته ڇا اهو ISSP کان سڏيو وڃي ٿو. بهرحال، ROMX opcode شايد شايد اهڙي چيڪ نه هجي. تنهن ڪري هتي پٿون ڪوڊ آهي (ڪجهه مددگار ڪلاس شامل ڪرڻ کان پوءِ 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 بس کي عارضي بفر ڏانهن منتقل ڪيو ويندو آهي.
اهو بنيادي طور تي سڏي ٿو SROM فنڪشن 0x07، جيئن دستاويز ۾ پيش ڪيو ويو آهي (اطالوي مائن):
هن فنڪشن checksum جي تصديق. اهو حساب ڪري ٿو هڪ 16-بٽ چيڪسم جو استعمال ڪندڙ جي مخصوص بلاڪن جي تعداد جو هڪ فليش بئنڪ ۾، صفر کان شروع ٿئي ٿو. BLOCKID پيٽرولر بلاڪ جي تعداد کي پاس ڪرڻ لاء استعمال ڪيو ويندو آهي جيڪو استعمال ڪيو ويندو جڏهن چيڪسم جي حساب سان. "1" جو قدر صرف بلاڪ صفر لاءِ چيڪسم کي حساب ڏيندو. جڏهن ته "0" فليش بئنڪ جي سڀني 256 بلاڪن جي ڪل چيڪسم کي ڳڻڻ جو سبب بڻائيندو. 16-bit چيڪسم KEY1 ۽ KEY2 ذريعي واپس ڪيو ويو آهي. KEY1 پيٽرولر ذخيرو ڪري ٿو گھٽ-آرڊر 8 بٽس چيڪسم جي، ۽ KEY2 پيٽرولر اعلي-آرڊر 8 بٽس کي ذخيرو ڪري ٿو. ڪيترن ئي فليش بينڪن سان ڊوائيسز لاء، چيڪسم فنڪشن کي سڏيو ويندو آهي هر هڪ لاء الڳ الڳ. بينڪ نمبر جنهن سان اهو ڪم ڪندو اهو FLS_PR1 رجسٽر طرفان مقرر ڪيو ويو آهي (ان ۾ بٽ سيٽ ڪندي ٽارگيٽ فليش بئنڪ سان لاڳاپيل).
نوٽ ڪريو ته ھي ھڪڙو سادو چيڪسم آھي: بائيٽ صرف ھڪ ٻئي پٺيان شامل ڪيا ويا آھن؛ ڪو به فينسي CRC نرالو ناهي. ان کان علاوه، ڄاڻو ته M8C ڪور ۾ رجسٽرن جو تمام ننڍڙو سيٽ آهي، مون سمجهيو ته جڏهن چيڪسم کي ڳڻڻ، وچولي قدر ساڳيا متغيرن ۾ رڪارڊ ڪيا ويندا جيڪي آخرڪار ان پٽ ڏانهن ويندا: KEY1 (0xF8) / KEY2 ( 0xF9).
تنهن ڪري نظريي ۾ منهنجو حملو هن طرح نظر اچي ٿو:
اسان ISSP ذريعي ڳنڍيندا آهيون.
اسان CHECKSUM-SETUP ویکٹر استعمال ڪندي چيڪسم حساب شروع ڪريون ٿا.
اسان هڪ مخصوص وقت کان پوءِ پروسيسر کي ريبوٽ ڪيو.
اسان موجوده چيڪسم سي حاصل ڪرڻ لاءِ رام پڙهون ٿا.
ورجايو 3 ۽ 4 مرحلا، هر دفعي T کي ٿورو وڌايو.
اسان هڪ فليش ڊرائيو مان ڊيٽا کي بحال ڪريون ٿا اڳوڻي چيڪسم سي کي هٽائڻ سان موجوده هڪ مان.
وقت جي هڪ مخصوص مدت لاء انتظار؛ هيٺين نقصانن کي نظر ۾ رکندي:
مون گهڻو وقت ضايع ڪيو جيستائين مون کي معلوم ٿيو ته اهو ڇا نڪتو دير مائڪرو سيڪنڊ صرف دير سان صحيح ڪم ڪري ٿو 16383 μs کان وڌيڪ نه؛
۽ پوءِ وري ساڳئي وقت کي ماريو ويو جيستائين مون دريافت ڪيو ته دير مائڪرو سيڪنڊ، جيڪڏهن 0 ان کي ان پٽ جي طور تي منظور ڪيو وڃي، مڪمل طور تي غلط ڪم ڪري ٿو!
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))
مختصر ۾، هي ڪوڊ ڇا ڪندو آهي:
PSoC کي ريبوٽ ڪري ٿو (۽ ان کي هڪ جادو نمبر موڪلي ٿو).
مڪمل شروعاتي ویکٹر موڪلي ٿو.
ڪال ڪري ٿو Arduino فنڪشن Cmnd_STK_START_CSUM (0x85)، جتي مائڪرو سيڪنڊن ۾ دير کي پيٽرولر طور منظور ڪيو ويو آهي.
هي ڪوڊ 10 مائڪرو سيڪنڊن ۾ 1 ڀيرا ڪيو ويندو آهي. 0xF1 هتي شامل ڪيو ويو آهي ڇاڪاڻ ته اهو صرف رجسٽر هو جيڪو تبديل ڪيو ويو جڏهن چيڪسم جي حساب سان. شايد اهو ڪجهه قسم جو عارضي متغير آهي جيڪو رياضي منطق يونٽ پاران استعمال ڪيو ويو آهي. نوٽ ڪريو بدصورت هيڪ جيڪو آئون استعمال ڪريان ٿو آرڊينو کي ري سيٽ ڪرڻ لاءِ picocom استعمال ڪندي جڏهن Arduino بند ٿي وڃي زندگي جا نشان ڏيکارڻ (نه ڄاڻ ڇو).
7.2. نتيجو پڙهڻ
پٿون اسڪرپٽ جو نتيجو هن طرح ڏسڻ ۾ اچي ٿو (پڙهڻ جي صلاحيت لاءِ آسان):
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 μs في بائيٽ جي برابر آهي، اسان هن وقت کي مناسب وقت تي چيڪسم جي قيمت کي جانچڻ لاءِ استعمال ڪري سگهون ٿا. پهرين رنن لاء، هر شيء بلڪل آساني سان پڙهي ويندي آهي، ڇاڪاڻ ته ڪمپيوٽر جي طريقيڪار جي مدت هميشه لڳ ڀڳ ساڳي آهي. بهرحال، هن ڊمپ جو پڄاڻي گهٽ صحيح آهي ڇو ته هر رن تي ”ننڍي وقت جي انحراف“ اهم ٿيڻ ۾ اضافو ڪري ٿو:
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. پن ڪوڊ اسٽوريج ايڊريس ڳولڻ
هاڻي ته اسان چيڪسم کي پڙهي سگهون ٿا وقت تي اسان کي ضرورت آهي، اسان آساني سان چيڪ ڪري سگهون ٿا ته اهو ڪيئن ۽ ڪٿي تبديل ٿئي ٿو جڏهن اسان:
نتيجو تمام خوشگوار نه هو، ڇاڪاڻ ته اتي ڪيتريون ئي تبديليون هيون. پر آخر ۾ مان اهو طئي ڪرڻ جي قابل ٿيس ته چيڪسم 120000 µs ۽ 140000 µs جي دير جي وچ ۾ تبديل ٿي ويو. پر ”پنڪوڊ“ جيڪو مون اتي ڏيکاريو هو مڪمل طور تي غلط هو - دير جي مائڪرو سيڪنڊ پروسيس جي هڪ نموني جي ڪري، جيڪو عجيب شيون ڪندو آهي جڏهن 0 ان ڏانهن منتقل ڪيو ويندو آهي.
پوءِ، لڳ ڀڳ 3 ڪلاڪ گذرڻ کان پوءِ، مون کي ياد آيو ته SROM سسٽم ڪال CheckSum هڪ دليل وصول ڪري ٿو جيئن ان پٽ جيڪو چيڪسم لاءِ بلاڪن جو تعداد بيان ڪري ٿو! اهو. اسان آساني سان پن ڪوڊ جي اسٽوريج ايڊريس کي مقامي ڪري سگھون ٿا ۽ "غلط ڪوششون" انسداد، 64 بائيٽ بلاڪ جي درستگي سان.
اهڙي طرح پن ڪوڊ ۽ غلط ڪوششن جو ڪائونٽر بلاڪ نمبر 126 ۾ محفوظ نظر اچي ٿو.
7.5. بلاڪ نمبر 126 جو ڍير کڻڻ
بلاڪ # 126 کي لڳ ڀڳ ڪٿي 125x64x18 = 144000μs، چيڪسم جي حساب جي شروعات کان وٺي، منهنجي مڪمل ڊمپ ۾، ۽ اهو ڪافي ممڪن لڳي ٿو. ان کان پوء، دستي طور تي ڪيترن ئي غلط ڊمپس کي ڇڪڻ کان پوء (جڏهن "ننڍي وقت جي انحراف" جي جمع ٿيڻ جي ڪري)، مون کي اهي بائيٽ حاصل ڪرڻ ختم ٿي ويا (145527 μs جي دير سان):
اسان کولڊ بوٽ ٽريس حملي کي استعمال ڪندي ۽ سڌو پن ڪوڊ پڙهڻ سان مخالف سوائپ تحفظ کي نظرانداز ڪري سگھون ٿا.
بهرحال، اسان جي حملي ۾ ڪجهه خاميون آهن هم وقت سازي جي مسئلن جي ڪري. اهو هيٺين ريت بهتر ٿي سگهي ٿو:
"ٿڌي بوٽ ٽريس" حملي جي نتيجي ۾ حاصل ڪيل آئوٽ پٽ ڊيٽا کي صحيح طور تي ڊيڪوڊ ڪرڻ لاءِ يوٽيلٽي لکو؛
هڪ FPGA گيجٽ استعمال ڪريو وڌيڪ صحيح وقت جي دير ٺاهڻ لاءِ (يا Arduino هارڊويئر ٽائمر استعمال ڪريو)؛
ٻيو حملو ڪرڻ جي ڪوشش ڪريو: عمدي طور تي غلط پن ڪوڊ داخل ڪريو، ريبوٽ ڪريو ۽ ريم ڊمپ ڪريو، اميد آھي ته صحيح پن ڪوڊ مقابلي لاءِ RAM ۾ محفوظ ڪيو ويندو. بهرحال، اهو Arduino تي ڪرڻ ايترو آسان ناهي، ڇاڪاڻ ته Arduino سگنل ليول 5 وولٽ آهي، جڏهن ته بورڊ جنهن کي اسين جانچي رهيا آهيون اهو 3,3 وولٽ سگنلن سان ڪم ڪري ٿو.
ھڪڙي دلچسپ شيء جيڪا ڪوشش ڪري سگھجي ٿي وولٹیج جي سطح سان راند ڪرڻ لاء پڙھڻ جي حفاظت کي بائي پاس ڪرڻ لاء. جيڪڏهن اهو طريقو ڪم ڪيو، اسان فليش ڊرائيو مان بلڪل صحيح ڊيٽا حاصل ڪرڻ جي قابل ٿي سگهنداسين - هڪ چيڪسم پڙهڻ تي ڀروسو ڪرڻ بجاءِ غلط وقت جي دير سان.