
इंजेक्टेबल रीयल-मोड x86 डीबगर BIOS रिवर्स इंजीनियरिंग और सीरियल केबल के माध्यम से मनमाने रीयल-मोड कोड डीबगिंग के लिए, GDB एकीकरण और हार्डवेयर ब्रेकपॉइंट/वॉचपॉइंट समर्थन के साथ।
BREAD (BIOS Reverse Engineering & Advanced Debugger) एक 'इंजेक्टेबल' रियल-मोड x86 डीबगर है जो किसी अन्य पीसी से सीरियल केबल के माध्यम से वास्तविक हार्डवेयर पर मनमाने रियल-मोड कोड को डीबग कर सकता है।
BREAD लीगेसी BIOS को रिवर्स इंजीनियर करने के कई असफल प्रयासों से उभरा। यह देखते हुए कि अधिकांश - यदि सभी नहीं - BIOS विश्लेषण डिसअसेंबलर का उपयोग करके स्थिर रूप से किया जाता है, BIOS को समझना अत्यंत कठिन हो जाता है, क्योंकि किसी दिए गए कोड में रजिस्टरों या मेमोरी के मान जानने का कोई तरीका नहीं है।
इसके बावजूद, BREAD रियल-मोड में मनमाने कोड जैसे बूट करने योग्य कोड या DOS प्रोग्राम को भी डीबग कर सकता है।
त्वरित डेमो:
https://user-images.githubusercontent.com/8294550/217709970-9007a1e3-7352-470d-a22f-cbb5219d5547.mp4
BREAD के माध्यम से CPU स्ट्रिंग नाम बदलना
यह डीबगर दो भागों में विभाजित है: डीबगर (पूरी तरह से असेंबली में लिखा गया और डीबग किए जा रहे हार्डवेयर पर चल रहा है) और ब्रिज, जो C में लिखा गया है और Linux पर चल रहा है।
डीबगर इंजेक्टेबल कोड है, जो 16-बिट रियल-मोड में लिखा गया है, और इसे BIOS ROM या किसी अन्य रियल-मोड कोड में रखा जा सकता है। जब निष्पादित किया जाता है, तो यह उपयुक्त इंटरप्ट हैंडलर सेट करता है, प्रोसेसर को सिंगल-स्टेप मोड में डालता है, और सीरियल पोर्ट पर कमांड की प्रतीक्षा करता है।
दूसरी ओर, ब्रिज, डीबगर और GDB के बीच की कड़ी है। ब्रिज GDB के साथ TCP के माध्यम से संचार करता है और सीरियल पोर्ट के माध्यम से डीबगर को अनुरोध/प्रतिक्रिया अग्रेषित करता है। ब्रिज के पीछे का विचार GDB पैकेटों की जटिलता को दूर करना और मशीन के साथ संवाद करने के लिए एक सरल प्रोटोकॉल स्थापित करना है। इसके अलावा, सरल प्रोटोकॉल अंतिम कोड आकार को छोटा करने में सक्षम बनाता है, जिससे डीबगर को विभिन्न वातावरणों में इंजेक्ट करना आसान हो जाता है।
जैसा कि निम्नलिखित आरेख में दिखाया गया है:
+---------+ सरल पैकेट्स +----------+ GDB पैकेट्स +---------+
| |--------------->| |--------------->| |
| dbg | | bridge | | gdb |
|(real HW)|<---------------| (Linux) |<---------------| (Linux) |
+---------+ सीरियल +----------+ TCP +---------+
GDB स्टब को लागू करके, BREAD में कई विशेषताएं बॉक्स से बाहर आती हैं। निम्नलिखित कमांड समर्थित हैं:
GDB में एक कच्चे बाइनरी, जैसे BIOS, को रिवर्स इंजीनियर करने का अर्थ स्वचालित रूप से इसके मूल प्रतीक न होना है। हालांकि, जैसे-जैसे RE प्रक्रिया आगे बढ़ती है, उपयोगकर्ता/प्रोग्रामर/हैकर कोड के कुछ भागों की बेहतर समझ प्राप्त करता है, और IDA, Cutter, Ghidra जैसे स्थैतिक विश्लेषण उपकरण एनोटेशन, टिप्पणियां, फ़ंक्शन परिभाषाएं और अधिक जोड़ने की अनुमति देते हैं। ये संवर्द्धन उपयोगकर्ता की उत्पादकता को काफी बढ़ाते हैं।
इसे ध्यान में रखते हुए, प्रोजेक्ट में symbolify.py नामक एक सहायक Python स्क्रिप्ट है। प्रतीकों (पता लेबल) की एक सूची दी गई है, यह इन प्रतीकों के साथ एक न्यूनतम ELF फ़ाइल उत्पन्न करता है। इस ELF को बाद में GDB में लोड किया जा सकता है और डीबगिंग प्रक्रिया को बहुत सरल बनाने के लिए उपयोग किया जा सकता है।
प्रतीक फ़ाइल में व्हाइटस्पेस, खाली पंक्तियाँ, टिप्पणियां (#), और पते की पंक्ति पर टिप्पणियां शामिल हो सकती हैं। पते दशमलव या हेक्साडेसिमल प्रारूप में हो सकते हैं, और लेबल/प्रतीक (एक या अधिक व्हाइटस्पेस वर्णों द्वारा अलग) [a-z0-9_]+ के रूप में हो सकते हैं, जैसे (एक वास्तविक उदाहरण symbols/ami_ipm41d3.txt में पाया जा सकता है):
#
# यह एक टिप्पणी है
#
0xdeadbeef my_symbol1
0x123 othersymbol # यह फ़ंक्शन xyz करता है
# दशमलव पते का उदाहरण
456 anotherone
उदाहरण के लिए, symbols/ami_ipm41d3.txt पर उपलब्ध प्रतीक फ़ाइल पर विचार करते हुए, उपयोगकर्ता कुछ इस प्रकार कर सकता है:
$ ./simbolify.py symbols/ami_ipm41d3.txt ip41symbols.elf
फिर, इसे GDB में लोड करें जैसे:
(gdb) add-symbol-file ip41symbols.elf 0
add symbol table from file "ip41symbols.elf" at
.text_addr = 0x0
(y or n) y
Reading symbols from ip41symbols.elf...
(No debugging symbols found in ip41symbols.elf)
(gdb) p cseg_
cseg_change_video_mode_logo cseg_get_cpuname
(gdb) p cseg_
ध्यान दें कि GDB का ऑटो-पूर्ण भी अपेक्षित रूप से काम करता है, अद्भुत है ना?
कितनी? हाँ। चूंकि डीबग किया जा रहा कोड इस बात से अनजान है कि इसे डीबग किया जा रहा है, यह कई तरीकों से डीबगर में हस्तक्षेप कर सकता है, कुछ नाम रखने के लिए:
संरक्षित-मोड जंप: यदि डीबग किया गया कोड संरक्षित-मोड में स्विच होता है, तो इंटरप्ट हैंडलर आदि की संरचनाएं बदल जाती हैं और कोड के उस बिंदु पर डीबगर अब आमंत्रित नहीं किया जाएगा। हालांकि, यह संभव है कि पिछली पूर्ण स्थिति को पुनर्स्थापित करते हुए रियल मोड में वापस जाने से डीबगर फिर से काम कर सके।
IDT परिवर्तन: यदि किसी कारण से डीबग किया गया कोड IDT या इसके आधार पते को बदलता है, तो डीबगर हैंडलर ठीक से आमंत्रित नहीं होंगे।
स्टैक: BREAD एक स्टैक का उपयोग करता है और मानता है कि यह मौजूद है! इसे उन स्थानों पर नहीं डाला जाना चाहिए जहाँ स्टैक अभी तक कॉन्फ़िगर नहीं किया गया है।
BIOS डीबगिंग के लिए, अन्य सीमाएं हैं जैसे: BIOS कोड को शुरुआत (बूटब्लॉक) से डीबग करना संभव नहीं है, क्योंकि BREAD के सही ढंग से काम करने के लिए न्यूनतम सेटअप (जैसे RAM) आवश्यक है। हालांकि, CS:EIP को F000:FFF0 पर सेट करके "वार्म-रीबूट" करना संभव है। इस परिदृश्य में, BIOS आरंभीकरण को फिर से अनुसरण किया जा सकता है, क्योंकि BREAD पहले से ही ठीक से लोड है। कृपया ध्यान दें कि वार्म-रीबूट के दौरान BIOS आरंभीकरण का "कोड-पथ" कोल्ड-रीबूट से भिन्न हो सकता है और निष्पादन प्रवाह बिल्कुल समान नहीं हो सकता है।
निर्माण के लिए केवल GNU Make, एक C कंपाइलर (जैसे GCC, Clang, या TCC), NASM, और एक Linux मशीन की आवश्यकता होती है।
डीबगर के दो ऑपरेशन मोड हैं: पोलिंग (डिफ़ॉल्ट) और इंटरप्ट-आधारित:
पोलिंग मोड सबसे सरल दृष्टिकोण है और विभिन्न वातावरणों में अच्छी तरह से काम करना चाहिए। हालांकि, पोलिंग प्रकृति के कारण, उच्च CPU उपयोग होता है:
$ git clone https://github.com/Theldus/BREAD.git
$ cd BREAD/
$ make
इंटरप्ट-आधारित मोड लगातार पोलिंग करने के बजाय नया डेटा प्राप्त करने के लिए UART इंटरप्ट का उपयोग करके CPU उपयोग को अनुकूलित करता है। इसके परिणामस्वरूप CPU डीबगर से कमांड प्राप्त करने तक 'हॉल्ट' स्थिति में रहता है, और इस प्रकार, इसे CPU के 100% संसाधनों का उपभोग करने से रोकता है। हालांकि, चूंकि इंटरप्ट हमेशा सक्षम नहीं होते हैं, यह मोड डिफ़ॉल्ट विकल्प के रूप में सेट नहीं है:
$ git clone https://github.com/Theldus/BREAD.git
$ cd BREAD/
$ make UART_POLLING=no