Phase 13: Tools & Protocols

रिवर्स इंजीनियरिंग लैंडस्केपः इतिहास, उपकरण परिवार और डिपॉजिटर कैसे बनाया जाता है

पांच उपकरण एक ही वस्तु को पढ़ते हैं और चार पते देते हैं, तीन ब्लॉक गिनती, और एक स्विच के लिए दो उत्तर, और यह सबक एक हर्नर बनाता है जो दिखाता है कि कौन कौन है।

Type: Build

Languages: Python, C, x86-64 assembly, Java (one Ghidra script)

Prerequisites: Phase 13 · 32 (ELF from scratch), Phase 13 · 33 (disassembly and control flow), Phase 13 · 34 (lifting to pseudocode)

Time: ~150 minutes

सीखने के लक्ष्य

  • क्षेत्र के मुख्य उपकरण को 1973 से 2026 तक की तारीख वाली समयरेखा पर रखें और प्रत्येक परिवार का नाम बताइए।
  • एक डिकोम्पाइलर के आठ चरणों का नाम दें और प्रत्येक चरण के लिए गिड्रा, द्विआधारी निंजा, हेक्स-रे, रडार2, रिजिन और एंग्र का उपयोग करने वाला शब्द बताएं।
  • एक निर्देश को ESIL, RzIL, P-code और VEX में ले जाएं और बताएं कि इनमें से कौन सा झंडा उत्सुकता से लिखता है और कौन सा एक थनक स्टोर करता है।
  • पांच उपकरणों के पते को एक तक कम करें .textएक फ़ंक्शन पर घटाव को ऑफसेट और साबित करें।
  • एक तुलना हर्नस बनाएं जो कैप्चर किए गए उपकरण आउटपुट को पढ़ता है और निर्देश स्टार्ट, ब्लॉक, किनारों और फ़ंक्शन स्टार्ट पर समझौते की रिपोर्ट करता है।
  • नाम, कब्जा किए गए साक्ष्य से, जहां प्रत्येक उपकरण कोड का आविष्कार करता है, कोड को याद करता है, या एक अप्रत्यक्ष कूद पर रुकता है।

समस्या

आप एक एजेंट से पूछें कि तीन रिवर्स इंजीनियरिंग टूल क्या कहते हैं के बारे में सारांशित करेंgradeमें ledger-x86_64-O1.o. एजेंट प्रत्येक उपकरण चलाता है, तीन सूची पढ़ता है, और रिपोर्ट करता है कि समारोह पर बैठता है 0x08000050एक उपकरण में, 0x400010एक और में, और 0x100010यह निष्कर्ष निकाला है कि उपकरण कार्य के स्थान के बारे में असहमत हैं।

उपकरण सहमत हैं. ऑब्जेक्ट स्थानांतरित किया जा सकता है और कोई लोड पता नहीं है, इसलिए प्रत्येक उपकरण एक चुनता है. प्रत्येक उपकरण द्वारा दिए गए पते को घटाएं .textऔर हर उत्तर है 0x10एजेंट ने कच्चे पते की तुलना की क्योंकि किसी ने भी उसे नहीं बताया कि प्रत्येक उपकरण में पता का क्या मतलब है।

बाद में उसी एजेंट ने पढ़ा grade-O0चार उपकरणों से 3, 8, 8 और 9 बुनियादी ब्लॉक का निर्माण और रिपोर्ट। सभी चार संख्या असली हैं। एक उपकरण पर बंद कर दियाjmp raxदो उपकरण कूद तालिका को उसके स्थानान्तरण के माध्यम से पढ़ते हैं एक उपकरण एक ब्लॉक को कूद पर एक लेबल लगाने के लिए विभाजित करता है इसके पीछे कारण के बिना ब्लॉक गिनती एक दावा के बिना संख्या है।

यह सबक आपको उन संख्याओं में से किसी पर भी भरोसा करने से पहले आवश्यक मानचित्र है। पाठ 32 से 36 तक एक डिकोडर, एक लिफ्टर, एक सबूत रिकॉर्ड और एक पुनर्निर्माण बनाया गया। ट्रैक के दूसरे हिस्से में उन्हें लोगों द्वारा उपयोग किए जाने वाले उपकरणों के बगल में रखा गया है। ऐसा करने के लिए आपको क्षेत्र का इतिहास, उपकरण के परिवारों में शामिल होने की आवश्यकता है, प्रत्येक डिसीम्पिलर का पाइपलाइन चलता है, और एक हर्नस जो तुलना करता है कि उपकरण आप स्वयं द्वारा संकलित वस्तुओं पर क्या कहते हैं।

पचास तीन साल पुराने चरणों में

इस क्षेत्र में अधिकांश उपकरण से अधिक पुराना है। नीचे दी गई प्रत्येक तिथि में आगे पढ़ने में प्राथमिक स्रोत है।

1973 से 1991 तकः डिबगर्स पहले, फिर डिमॉन्टेबलर

पहली डिकोम्पाइलिंग थीसिस 1973 से हैं। स्टैनफोर्ड में होलैंडर और पर्ड्यू में हाउसेल ने उन्हें लिखा था, और दोनों को आज उद्धरणों के माध्यम से जाना जाता है। उस अवधि के व्यावहारिक उपकरण डिबगर्स थे।adb1977 में बेल लैब्स में ट्यूटोरियल, और डिबगर 1979 में UNIX V7 के साथ भेजा गया।DEBUG, एक 8086 डिमॉन्टेजर के साथ, अगस्त 1981 में पीसी-डॉस 1.00 में भेजा गया। रिचर्ड स्टॉलमैन की जीडीबी 1986 में वितरण में प्रवेश किया। सॉफ्टआईसी ने 1987 में डॉस में एक कर्नेल डिबगर डाल दिया।

इसके बाद बैच डिमॉन्टेलर आए। 1988 में, सोर्सर, V कम्युनिकेशंस से, एक डॉस प्रोग्राम पर कई पास चलाया और टिप्पणी की गई सूची लिखी। GNU द्विआधारी विकल्प 1988 में अनगिनत स्नैपशॉट के साथ शुरू हुए, और objdumpइलफ़ाक गुलफ़ानोव ने जनवरी 1991 में IDA की पहली पंक्ति लिखी और 20 मई 1991 को IDA 0.1 को शेयरवेयर के रूप में जारी किया।

1991 से 2009: इंटरैक्टिव डिमॉन्टेबलर और पहले डिमॉन्टेबलर

क्रिस्टिना सिफुएंटेस ने जुलाई 1994 में क्यूयूटी में "रिवर्स कम्पिलिशन टेक्निक" पूरा किया।dcc, i80286 DOS कार्यक्रमों को C में ले गया, और 1995 के उनके पेपर में Gough ने चरणों को निर्धारित किया जो बाद के हर डिकोम्पाइलर ने रखा। 1997 में REC और 2002 में Boomerang ने BSD लाइसेंस के तहत पहला ओपन-सोर्स डिकोम्पाइलर बनाया।

IDA 1996 में DataRescue में एक वाणिज्यिक उत्पाद बन गया, 1999 में एक प्लगइन SDK प्राप्त किया, और 2005 में स्थापित हेक्स-रेज़ में स्थानांतरित हो गया। हेक्स-रेज डेकम्पिलर 1.0 17 सितंबर 2007 को भेजा गया। उसी वर्ष माइक वान एमेरिक ने "डिकांपिलर के लिए स्टैटिक एकल असाइनमेंट" प्रस्तुत किया, थीसिस जिसने एसएसए को डिकांपिलर डेटा प्रवाह के केंद्र में रखा। हल्वर फ्लेक की "संरचनात्मक तुलना में निष्पादित वस्तुओं" (2004) ने विभेदित परिवार की शुरुआत की, और बिनडीफ अगस्त 2004 में बिक्री पर चला गया।

radare ने फरवरी 2006 में 64-बिट ऑफसेट के साथ एक फोरेंसिक हेक्स एडिटर के रूप में शुरुआत की। एलजीपीएल 3.0 के तहत मॉड्यूलर पुनर्लेखन, radare2, 7 मार्च 2009 को पहली बार जारी किया गया था।

2009 से 2019: ढांचे और मध्यवर्ती प्रतिनिधित्व

LLDB को 8 जून 2010 को LLVM उप-परियोजना के रूप में घोषित किया गया था। BAP, अपनी बीआईएल मध्यवर्ती भाषा के साथ बाइनरी एनालिसिस प्लेटफॉर्म, CAV 2011 में दिखाई दिया। 1 मार्च 2011 को Google ने BinDiff के निर्माताओं, zynamics को अधिग्रहण किया। हॉपर 2011 के अंत में मैक ऐप स्टोर पर दिखाई दिया। मैट गोडबोल्ट ने 2012 में कंपाइलर एक्सप्लोरर शुरू किया ताकि एक C ++ प्रोग्रामर एक कंपाइलर द्वारा उत्पादित असेंबली देख सके।

angr को अगस्त 2013 में कोड की पहली पंक्ति मिली। फीनिक्स पेपर (Schwartz, Lee, Woo, Brumley, USENIX Security 2013) में 40 के साथ अर्थशास्त्र-संरक्षण संरचना दिखाई गई।gotoड्रीम (Yakdan और अन्य, NDSS 2015) ने gotoपैटर्न से स्वतंत्र संरचना के साथ बयान। वेक्टर 35 की स्थापना 14 जनवरी 2015 को हुई थी, और बाइनरी निंजा 23 जुलाई 2016 को अपनी लो लेवल आईएल और पायथन एपीआई के साथ बिक्री पर चला गया था। एएनजीआर को 2015 में सार्वजनिक किया गया था और अगस्त 2016 में डार्पा साइबर ग्रैंड चैलेंज में तीसरा स्थान प्राप्त किया था। मार्च 2016 में बिनडीफ मुफ्त में बन गया। कटर 1.0 ने दिसंबर 2017 में रडार 2 को Qt GUI दिया। 2018 में गुइलफानोव ने रिकॉन में "डेकम्पिलर इंटर्न्सः माइक्रोकोड" प्रस्तुत किया, हेक्स-रेस आईआर का पहला सार्वजनिक विवरण।

2019 से 2026: खुला डिकोम्पाइलर और अनुसंधान मोड़

Ghidra 9.0 को 5 मार्च 2019 को Apache 2.0 के तहत RSA सम्मेलन में NSA द्वारा जारी किया गया था, जिसमें एक महीने बाद GitHub पर पूर्ण स्रोत था। अंक 8.19.2.4 उसी वर्ष एक प्रारंभिक डिसीमुलेटर जोड़ा गया। बाइनरी निंजा 2.0 ने 20 मई 2020 को अपना हाई लेवल आईएल डिकंपिलर भेजा। 8 दिसंबर 2020 को रिज़िन को रडार 2 के लिए एक कांटा के रूप में घोषित किया गया था, और कटर टीम ने इसे स्थानांतरित कर दिया। आईडीए फ्रीवेयर 7.6 ने मई 2021 में एक क्लाउड x64 डिकोम्पाइलर जोड़ा।

बिनडीफ 8 25 सितंबर 2023 को अपाचे 2.0 के तहत ओपन सोर्स था। SAILR (बास्क और अन्य, USENIX सुरक्षा 2024) एंग्र का डिफ़ॉल्ट संरक्षक बन गया और तर्क दिया कि केवल झूठा gotoबिनरी निंजा 4.0 ने फरवरी 2024 में एक मुफ्त संस्करण जोड़ा, और आईडीए 9.0 जोड़ा idalibसीखे हुए-डिकॉम्पिलर पेपर SLaDe (2023) से LLM4Decompile (2024) से लेकर DecompileBench (2025) तक और एजेंट-एस्स्स्टेड पठनीयता और अधिक को पुनः संकलन करने वाले और कम को संरक्षित करने वाले डिकॉम्पिलर पर दो 2026 अध्ययनों पर चलते हैं।

इस पाठ में 14 अक्टूबर 2026 को चलाने वाले संस्करण वर्तमान हैंः गिदरा 12.1.4 (21 सितंबर 2026), रडार2 6.2.4 (5 अक्टूबर 2026), रिज़िन 0.9.1 (29 जून 2026), और एंग्र 10.0.3 (10 अक्टूबर 2026). बाइनरी निंजा 6.0 "क्रिप्टन" (3 सितंबर 2026) और आईडीए 9.4 (13 जुलाई 2026) वर्तमान बंद उपकरण हैं। यह पाठ उन्हें नहीं चलाया।

उपकरण परिवार

एक उपकरण एक परिवार का है, उसके द्वारा उत्पन्न होने के आधार पर। परिवार एक कार्यक्रम में ओवरलैप करते हैं, और ओवरलैप वह है जहां अधिकांश भ्रम शुरू होता है।

डिसेम्ब्लेटर

एक रैखिक स्वीप कोड अनुभाग के पहले बाइट से अंतिम तक डिकोड करता है।objdump -dऔर llvm-objdump -dइस तरह से काम करते हैं, और कोई भी नियंत्रण प्रवाह ग्राफ बनाता है.objdumpइनपुट 2.47 (26 जुलाई 2026) GPL-3.0 या बाद में है। LLVM 23.1.3 LLVM अपवाद के साथ Apache-2.0 है। एप्पल के कमांड लाइन टूल जहाज llvm-objdump"Apple LLVM संस्करण 17.0.0", और यह इस पाठ की प्रति है।

एक इंटरैक्टिव डिमॉन्टेजर ज्ञात प्रविष्टियों से पुनरावर्ती अवतरण चलाता है, फ़ंक्शन स्टार्ट के लिए हेरिस्टिक्स जोड़ता है, और एक डेटाबेस रखता है।Disassemblerइसके अलावा ऑटो एनालिसिस एनालिज़र), बाइनरी निंजा (रिकर्सिव अवतरण, फिर अज्ञात क्षेत्रों पर रैखिक स्वीप), हॉपर, रडार2 और रिजिन (aa,aaa,af), कटर और आईएआईटीओ के साथ इस परिवार में सभी हैं। एंड्रीसे और अन्य (यूएसएनआईएक्स सिक्योरिटी 2016) ने संकलक-जनित द्विआधारी पर उनमें से नौ को मापा। निर्देश सटीकता 100 प्रतिशत के करीब थी, और हार्ड आदिम कार्य शुरू होती थी, जिसमें झूठी नकारात्मक दरें 20 प्रतिशत या उससे अधिक थीं।

डिसीपिलर

वाणिज्यिक डिकॉम्पिलरः हेक्स-रेज डिकॉम्पिलर (एक्स86 से आरआईएससी-वी तक बारह लक्ष्य परिवार), बाइनरी निंजा का एचएलआईएल इसके Pseudo C रेंडरिंग के साथ, और हॉपर का pseudo-कोड दृश्य। ओपन डेकोम्पाइलरः गिड्रा डेकोम्पाइलर, एक Apache-2.0 के तहत एक C ++ इंजन जिसे r2ghidra और rz-ghidra प्लगइन के रूप में पुनः उपयोग करते हैं और जो pypcode को लिफ्टर के रूप में पुनः उपयोग करते हैं; BSD-2-Clause के तहत संरचनात्मक SAILR के साथ AIL पर Angr डेकोम्पाइलर; जावास्क्रिप्ट में r2dec और jsdec; बूमरंग और dccइतिहास के रूप में। रडार 2 में भी एक अंतर्निहित है pdc, "सी-जैसे वाक्यविन्यास में छद्म विघटनकर्ता आउटपुट". रिज़िन में कोई अंतर्निहित विघटनकर्ता नहीं है।pdcरिज़िन 0. 9. 1 में मौजूद नहीं है और pdgआरज़-गीद्रा प्लगइन की जरूरत है।

डिबगर्स

GDB (1986) के साथ GEF और pwndbg फ्रंट-एंड, LLDB (2010), WinDbg के साथ टाइम ट्रैवल डिबगिंग (2017), OllyDbg (2014 में जमे हुए), x64dbg (GPL-3.0, 2014), अपने पायथन कनेक्टरों के साथ गिड्रा डिबगर, बाइनरी निंजा डिबगर, और अंतर्निहित डिबगर रडार 2 और रिज़िन। पाठ 42 में अपने स्वयं के निर्माण पर उनमें से दो का उपयोग किया जाता है।

द्विआधारी विश्लेषण ढांचे

angr (VEX IR, प्रतीकात्मक निष्पादन, CFGFastऔर CFGEmulated, decompiler), BAP (BIL, OCaml), Dyninst, Jakstab, और ByteWeight फ्रेमवर्क हैं कि Andriesse नाम दिया है. Ghidra PyGhidra के माध्यम से एक पुस्तकालय है, द्विआधारी निंजा के माध्यम से import binaryninja, और आईडीए के माध्यम से idalib. .

प्रारूप और इंजन पुस्तकालय

LIEF 1.0.0 (12 जुलाई 2026, Apache-2.0) ELF, PE, Mach-O, COFF और Android प्रारूपों को पार्स करता है। CLE, "CLE Loads Everything", Angr का लोडर है। कैपस्टोन 5.0.9 (28 मई 2026, BSD-3-Clause) को डिकोड करता है; कीस्टोन 0.9.2 (GPL-2.0) असेंबल्स; यूनिकॉर्न 2.1.4 (GPL-2.0) अनुकरण करता है। रडार 2 6.2.4 बंडल कैपस्टोन 5 और रिज़िन 0.9.1 विक्रेताओं कैपस्टोन, ज़ीडिस और ट्री-सिटर।

डिफिंग उपकरण और संकलक पक्ष दर्शक

BinDiff 8 (Apache-2.0) के साथ अपने BinExport 12 प्लगइन के साथ IDA प्रो, बाइनरी निंजा, और गिड्रा; डायफोर 3.4.3 (11 अक्टूबर 2026, AGPL-3.0) के रूप में एक IDA प्लगइन; radiff2और rz-diff. संकलक एक्सप्लोरर (BSD-2-Clause) इस सूची में बाकी सभी चीजों की अग्रिम दिशा है, जो कि स्रोत टुकड़े के लिए संकलक द्वारा उत्सर्जित असेंबली को दर्शाता है। पाठ 44 में अंतर परिवार का उपयोग किया जाता है।

संस्करण, लाइसेंस और इस पाठ में क्या था

ToolVersion read on 2026-10-14LicenceHeadless entryRan here
Ghidra12.1.4Apache-2.0analyzeHeadless, pyghidra.start()yes, on all four objects
radare26.2.4LGPL-3.0r2 -qc '<cmds>' file, rabin2yes
rizin0.9.1LGPL-3.0rizin -qc '<cmds>' file, rz-binyes
angr10.0.3BSD-2-Clauseangr.Project in Pythonyes
llvm-objdumpApple LLVM 17.0.0Apache-2.0 with LLVM exceptionllvm-objdump -d -ryes
Binary Ninja6.0 "Krypton"commercial; Free edition for non-commercial usebinaryninja.load() with a Commercial, Ultimate, or headless licenceno, documentation only
IDA Pro9.4commercial subscription; IDA Free for non-commercial x86 and x86-64idat, ida -A -S, idalibno, documentation only
Hopper6.6.0commercial, perpetualnone documentedno, documentation only
Cutter2.5.0GPL-3.0GUI over rizinno

बिनरी निंजा का फ्री संस्करण केवल x86, x86-64, ARMv7 और AArch64 को डिकोम्पिल करता है और इसमें कोई एपीआई नहीं है। IDA Free में कोई IDAPython, कोई SDK नहीं है, और कोई idalibइन दो उपकरणों के बारे में हर कथन इस पाठ में उनके प्रलेखन और रिलीज नोट्स से आता है, और आंकड़ा उन्हें नहीं चलाया के रूप में चिह्नित करता है.

डिपॉइलर पाइपलाइन, चरण-दर-चरण

1994 में सिफुएंटेस ने चरणों का नाम दियाः वाक्यविन्यास विश्लेषण, अर्थ विश्लेषण, मध्यवर्ती कोड जनरेशन, नियंत्रण प्रवाह ग्राफ जनरेशन, डेटा प्रवाह विश्लेषण, नियंत्रण प्रवाह विश्लेषण और कोड जनरेशन। उसने उन्हें मशीन-निर्भर फ्रंट एंड, मशीन और भाषा-निर्भर मध्य और भाषा-निर्भर बैक एंड में विभाजित किया। तब से हर डिसीम्पिलर उस आकार को बनाए रखता है और भागों का नाम बदल देता है। नीचे दी गई तालिका में इस पाठ में उपयोग किए जाने वाले आठ चरणों और प्रत्येक उपकरण के नाम को बताया गया है। चित्र में समान तालिका है जिसमें उपकरण स्तंभों का चयन किया जा सकता है।

StageGhidraBinary NinjaHex-Rays / IDAradare2rizinangr
LoaderElfLoader, MachoLoader, PeLoader; .ldefs picks the languageBinaryView, BinaryViewTypeloader module (LDSC)RBin (rabin2)RzBin (rz-bin)CLE (cle.Loader, main_object)
DisassemblyDisassembler; SLEIGH .slaspec compiled to .sla; analyzers "Disassemble Entry Points", "Function Start Search"architecture plugin; Recursive Descent, then linear sweep phasesprocessor module (ana.cpp, emu.cpp, out.cpp); autoanalysis queues; FLIRTRArch plugin to RAnalOp; aa, aaa, afRzAnalysis plugin; aa, aaa, afCapstone blocks; CFGFast function start search
CFG recovery"Generate Basic Blocks and the CFG"; BlockGraph; "Decompiler Switch Analysis"Function, BasicBlock; "Control Flow Graph (CFG) Analysis" phasembl_graph_t, ready at MMAT_LOCOPTafb, agf, aabafb, agf, aab (Nucleus)CFGFast, CFGEmulated; kb.functions; IRSB
Lifting"Generate Raw P-code"; Varnodes in ram, register, const, uniqueLifted IL, LLIL, Mapped MLIL, MLILmicrocode (minsn_t, mop_t); MMAT_GENERATEDESIL (asm.esil, ae)RzIL (aoi, aez)VEX (pyvex.lift, IRSB), then AIL
SSAHeritage, ActionHeritage; MULTIEQUAL, INDIRECTLLIL SSA, MLIL SSA, HLIL SSA; HLIL_VAR_PHIno named SSA; use-def data flow in MMAT_GLBOPT1 to 3none; ESIL is built for emulationnone; RzIL is built for emulation_stage_transform_to_ssa_level0 and level1; SeqNodeDephication
Data flow and typesActionDeadCode, ActionInferTypes, the Rule pool; prototype from .cspecMLIL constant propagation, variables and types; analyzeReturns"Transform microcode"; MMAT_CALLS, MMAT_GLBOPT, MMAT_LVARS; TILafv, afc, aaft; ESIL emulationafv, afc, aftCallingConventionAnalysis, VariableRecoveryFast, Typehoon
StructuringCollapseStructure; BlockIf, BlockWhileDo, BlockSwitch, BlockGotoHLIL_IF, HLIL_WHILE, HLIL_SWITCH; AST at root"Generate ctree"; structural analysis; goto regionspdc; pdd (r2dec); pdg (r2ghidra)pdg (rz-ghidra); jsdecRegionIdentifier; RecursiveStructurer with SAILRStructurer
Emission"Emit Final C Tokens"; PrintC, ActionNameVars, ActionSetCastsHLIL rendering; Pseudo C, Pseudo Rust, Pseudo Python"Beautify ctree; Print ctree"; cfunc_ttext of pdc, pdd, pdgpdg textCStructuredCodeGenerator; codegen.text

लोडर

लोडर कंटेनर को पार्स करता है, अनुभागों का नक्शा बनाता है, और प्रतीकों और स्थानांतरणों को पढ़ता है। स्थानांतरित करने योग्य वस्तु में अभी तक कुछ भी पता नहीं है, इसलिए लोडर एक चुनता है।0x08000000, जो कि डालता है .textपर0x08000040क्योंकि अनुभाग फ़ाइल ऑफसेट से शुरू होता है 0x40. सीएलई स्थान .textपर0x400000. . . गिदरा की ElfLoaderइसे 0x100000. .llvm-objdumpभागों के विपरीत छपाई और कोई आधार नहीं है।

लोडर भी स्थानांतरण पर भिन्न होते हैं। Ghidra उन्हें आयात पर संसाधित करता है, और CLE उन्हें लागू करता है। radare2 ऑब्जेक्ट को खोलने पर एक संकेत प्रिंट करता हैः स्थानांतरण लागू नहीं किए गए थे, और bin.relocs.apply=trueलोडर स्थानांतरण के साथ क्या करता है, यह तय करता है कि प्रत्येक बाद के चरण में क्या देखा जा सकता है, और आप प्रभाव को अनुभव करेंगे -O0नीचे की मेज पर कूदें।

विघटन

पाठ 33 दोनों तरीकों का निर्माण किया. टेबल में प्रत्येक उपकरण को छोड़करllvm-objdumpपुनरावर्ती अवतरण चलाता है और फिर समारोह शुरू करने के लिए एक खोज जोड़ता है। बाइनरी निंजा के दस्तावेजों में चरणों का क्रम हैः पुनरावर्ती अवतरण, कॉल लक्ष्य विश्लेषण, सीएफजी विश्लेषण "अज्ञात क्षेत्रों के रैखिक विघटन" और टेल कॉल विश्लेषण के रूप में नामित किया गया है। गिड्रा अपने विश्लेषकों को प्राथमिकता के आधार पर चलाता है, "एंट्री पॉइंट्स को डिसाम्बल करें" और "फंक्शन स्टार्ट सर्च" जल्दी। IDA ऑटो-विश्लेषण कतारों को रखता है, प्रत्येक प्राथमिकता के साथ, और पुस्तकालय कोड के लिए FLIRT हस्ताक्षर। Angr के CFGFastदस्तावेज़ चार स्रोतों के कार्य शुरू होता हैः प्रतीकों, एक प्रोग्यू स्कैन, कॉल लक्ष्य, और शेष बाइट्स की एक पूरी स्कैन। यह अंतिम स्रोत जहां एंग्र पैडिंग पर कार्यों का आविष्कार करता है।

CFG वसूली

प्रत्येक उपकरण ब्लॉक को काटता है जैसे कि पाठ 33 ने किया था, एक अंतर के साथ आप मापेंगे।call, क्योंकि इसके IRSB एक एकल प्रविष्टि, बहु-बहिरी ब्लॉक है और एक कॉल एक बाहर निकलने है. Ghidra, रडार2, और रिज़िन एक कॉल के माध्यम से चल रहे हैं. पर.grade_labelपर-O0, जो बुलाता हैgrade, एएनआरआर दो ब्लॉक रिपोर्ट करता है और अन्य तीन रिपोर्ट 1। निर्देश समान हैं।

उठाना

द्विआधारी निंजा लिफ्टिंग को "नीचे स्तर की भाषा से उच्चतम माना जाने वाला मध्यवर्ती भाषा में अनुवाद" के रूप में परिभाषित करता है। आईआर क्या हैं इसके लिए अलग हैं। पी-कोड और वीईएक्स विश्लेषण और डिकोम्पिलिंग के लिए बनाए गए थे। ईएसआईएल और आरज़िल अनुकरण के लिए बनाए गए थे, और उनमें से किसी में भी एसएसए चरण नहीं है। हेक्स-रे माइक्रोकोड 72 ऑपकोड के साथ आरआईएससी-जैसे कोड के रूप में शुरू होता है और परिपक्वता स्तरों से गुजरता है।MMAT_GENERATEDMMAT_LVARS. बाइनरी निंजा लिफ्ट आईएल पर बढ़ता है, फिर एलएलआईएल में स्थितियों में ध्वज को मोड़ता है, और एमएलआईएल "रजिस्टर और मेमोरी एक्सेस को चर में अनुवाद करता है। अगले खंड में इन आईआर के चार को एक साथ एक निर्देश पर रखा गया है।

एसएसए

वान एमेरिक के प्रबंध में सूचीबद्ध किया गया है कि एसएसए एक डिकोम्पाइलर को क्या खरीदता हैः एबीआई परिकल्पना के बिना अभिव्यक्ति प्रसार, पैरामीटर और वापसी पहचान, संरक्षण विश्लेषण, प्रकार विश्लेषण के रूप में एक दुर्लभ डेटा प्रवाह समस्या, और अप्रत्यक्ष कूद और कॉल का विश्लेषण। गिड्रा ने अपने एसएसए निर्माण को कहा Heritageऔर दो संचालन जो केवल ग्राफ में मौजूद जोड़ता है,MULTIEQUALपीआई औरINDIRECTबाइनरी निंजा में प्रत्येक आईएल स्तर पर एसएसए फॉर्म का खुलासा होता है।Clinicहेक्स-रेस एसएसए फॉर्म का नाम नहीं देता है और अपने वैश्विक अनुकूलन पास में डेटा प्रवाह का उपयोग करता है।

डेटा प्रवाह और प्रकार

गिद्रा का मुख्य सरलता लूप "मृत कोड को समाप्त करें", "स्थानीय प्रकारों को प्रचारित करें", और "अधिकांश पुनर्लेखन करें" तब तक चलता है जब तक कि कुछ भी नहीं बदलता है, पुनर्लेखन के साथ एक पूल द्वारा किया जाता है Ruleहेक्स-रे माइक्रोकोड को परिवर्तित करता है, कॉल तर्क का पता लगाता हैMMAT_CALLS, और स्थानीय चर को आवंटित करता है MMAT_LVARS. Angr runs CallingConventionAnalysis,VariableRecoveryFastऔर Typehoon, नोनन, लॉगिनॉव, और कोक के बहुरूपिक प्रकार का निष्कर्ष लागू करना। पाठ 41 इस चरण के बारे में है।

संरचना

गिदरा की CollapseStructureएक संरचना से मेल खाने वाले उप-ग्राफ की खोज करता है, उन्हें एक नोड में ढक देता है, और जब यह फंस जाता है तो एक किनारा हटा देता है और इसे अव्यवस्थित चिह्नित करता है। हेक्स-रेस CFG को कम करता हैif,while,doऔर switchऔर शेष को goto क्षेत्रों के रूप में छोड़ देता है। angr एकल-प्रवेश, एकल-निष्पत्ती क्षेत्रों की पहचान करता है और उन्हें संरचना के साथ SAILRStructurerडिफ़ॉल्ट रूप से, के साथPhoenixStructurerऔर DreamStructurerपाठ 34 एक संरक्षक ने हाथ से लिखा था।

उत्सर्जन

Ghidra C टोकन के माध्यम से जारी करता है PrintCएक ओपेन सुंदर प्रिंटर के साथ बाद में ActionNameVarsऔर ActionSetCasts. हेक्स-रेस ctree को सुंदर बनाता है और प्रिंट करता है. द्विआधारी निंजा HLIL को Pseudo C, Pseudo Rust, या Pseudo Python के रूप में प्रस्तुत करता है। angr लौटाता है codegen.text. रडार 2 फिंगरप्रिंट्स pdc,pddया pdg. .

चार आईआर में एक निर्देश

ले लो48 83 ec 10,subq $0x10, %rsp. इसे पेपर पर पाठ 33 के नियमों के साथ डिकोड करें.

  1. 48क्या REX के साथ W = 1ओपेरांड 64 बिट्स है।
  2. 838-बिट तत्काल के साथ समूह-1 अंकगणितीय ओपकोड है। ModRM reg क्षेत्र ऑपरेशन का चयन करता है।
  3. ecModRM है 11 101 100. .mod = 11रजिस्टर फॉर्म है। reg = 101है /5, जो है sub. .r/m = 100है %rsp. .
  4. 10तत्काल है, 16.

चार लिफ्टर्स को ये चार बाइट्स दिए गए थे। फिक्स्चर में सटीक कमांड और पूरा टेक्स्ट है।

रडार2 6.2.4 से ESIL 30 टोकन की एक अल्पविराम से अलग स्ट्रिंग हैः

text16,0x8000000000000000,-,!,16,rsp,-=,63,$o,^,of,:=,63,$s,sf,:=,$z,zf,:=,$p,pf,:=,64,$b,cf,:=,4,$b,af,:=

यह एक स्टैक मशीन है।16,rsp,-=प्रत्येक ध्वज को एक आंतरिक ऑपरेटर के साथ लिखा जाता हैः$oअतिप्रवाह, $sचिह्न, $zशून्य, $pसमता, $bउधार ले लो।

रिज़िन 0. 9. 1 से RzIL 14 के साथ एक S- अभिव्यक्ति है setप्रभावः

text(seq (set op1 (var rsp)) (set op2 (bv 64 0x10)) (set sub (- (var op1) (var op2))) (set rsp (var sub))
     (set _result (var sub)) (set pf (! (lsb (let _val (cast 8 false (var _result)) ...))))
     (set zf (is_zero (var _result))) (set sf (msb (var _result))) ... (set cf (|| ...)) (set of (|| ...)) (set af (|| ...)))

प्रत्येक झंडा बिटकॉइन पर एक बुलियन अभिव्यक्ति है।let. .

SLEIGH विनिर्देश से P-कोड x86:LE:64:defaultपypcode 4.0.1 के माध्यम से नौ ऑपरेशन के बाद है IMARK:

textCF = RSP < 0x10
OF = sborrow(RSP, 0x10)
RSP = RSP - 0x10
SF = RSP s< 0x0
ZF = RSP == 0x0
unique[58300:8] = RSP & 0xff
unique[58400:1] = popcount(unique[58300:8])
unique[58500:1] = unique[58400:1] & 0x1
PF = unique[58500:1] == 0x0

uniqueध्वज निर्देश पर गणना की जाती है, उत्सुकता से, औरCFऔर OFघटाने से पहले गणना की जाती है RSP. .

pyvex 10.0.3 से VEX सात बयानों के बाद है IMark:

textt2 = GET:I64(offset=48)
t0 = Sub64(t2,0x0000000000000010)
PUT(offset=144) = 0x0000000000000008
PUT(offset=152) = t2
PUT(offset=160) = 0x0000000000000010
PUT(offset=168) = 0x0000000000000000
PUT(offset=48) = t0

कोई ध्वज दिखाई नहीं देता है। VEX नामों को अतिथि राज्य में उनके ऑफसेट द्वारा पंजीकृत किया जाता है, और ऑफसेट 48 है rsp144 से 168 तक की कटौती हैcc_op,cc_dep1,cc_dep2और cc_ndep. लिफ्टर ऑपरेशन कोड 8 को संग्रहीत करता है, जो 64 बिट घटावट है, और दो ऑपरेन्ड। एक बाद की शाखा जो एक ध्वज पढ़ती है, इसे थन से गणना करती है। यही कारण है किpcode.writesFlagsसच है और vex.computesFlagsहर्नस रिपोर्ट में गलत है, और क्यों VEX चार में से सबसे छोटा है।

वही चार लिफ्टर्स पर 48 63 c7,movslq %edi, %rax, gradeपर-O1, 5 ESIL टोकन (32,edi,~,rax,=), 1 आरज़िल set, 1 पी-कोड ऑपरेशन (RAX = sext(EDI)), और 4 VEX कथन। कोई भी लिफ्टर एक ध्वज नहीं लिखता है, क्योंकि निर्देश में कोई नहीं है। उस निर्देश की गिदरा की अपनी सूची, सिरहीन स्क्रिप्ट के माध्यम से कैप्चर की गई है, उसी ऑपरेशन को प्रिंट करती है जैसे (register, 0x0, 8) INT_SEXT (register, 0x38, 4): रजिस्टर ऑफसेट 0 है RAX, ऑफसेट 0x38है RDI, और आकार 8 और 4 बाइट हैं।

83 f9 04,cmpl $0x4, %ecx, सीमाओं की जांच सेgrade, 30 ESIL टोकन देता है, 13 RzIL setप्रभाव, 10 पी-कोड संचालन, और 7 VEX बयान के साथ cc_op7, 32-बिट घटाव. कुछ भी नहीं लिखता है।%ecx. दो घटाव चौड़ाई आप VEX में मिल जाएगा 32 बिट्स के लिए 7 और 64 बिट्स के लिए 8 हैं, और अनुवादक आप निर्माण उस तालिका को ले जाता है.

एक कार्य के लिए चार पता आधार

इससे पहले कि हर्नस किसी भी चीज़ की तुलना कर सके उसे अपने साथ सहमत होना होगा कि फ़ंक्शन कहां है।gradeमें ledger-x86_64-O1.o. .

ToolAddress of .textAddress of gradeOffset
llvm-objdump0x00x100x10 - 0x0 = 0x10
radare2, rizin0x080000400x080000500x08000050 - 0x08000040 = 0x10
angr0x4000000x4000100x400010 - 0x400000 = 0x10
Ghidra0x1000000x1000100x100010 - 0x100000 = 0x10

प्रतीक तालिका में कहा गया हैgradeहै .text + 0x10आकार 46 के साथ। प्रत्येक उपकरण एक बार आधार को हटा दिया जाता है। हर्नस प्रत्येक पकड़ से आधार पढ़ता हैःiSjरडार2 और रिज़िन में, .textअंगर कैप्चर में अनुभाग प्रविष्टि, .textGhidra कैप्चर में स्मृति ब्लॉक, और शून्य के लिए स्वीप. परीक्षण test_every_tool_places_grade_at_offset_0x10_from_its_own_baseइस तथ्य को ठीक करता है।

जहाँ उपकरण सहमत हैं और जहाँ वे विभाजित हैं

हर्नेस में code/main.pyयह आंकड़े रिपोर्ट करता है, और परीक्षणों में प्रत्येक का दावा है।

समझौता मामलाः -O1 पर लेजर

चार फ़ंक्शन, 56 निर्देश फ़ैश में, 54 प्रतीक के अंदर और 2 पैडिंग में। प्रत्येक उपकरण में एक ही निर्देश की रिपोर्ट होती है जो प्रत्येक फ़ंक्शन में शुरू होता हैः 9, 14, 13 और 18. चार ग्राफ बिल्डर 3, 3, 5 और 4 ब्लॉक और 2, 3, 5 और 4 किनारों की रिपोर्ट करते हैं, और किनार सेट समान होते हैं, जोड़े के लिए जोड़े, रडार2, रिज़िन, एंग्र और गिड्रा पर।totalपाठ 33 हाथ से खींची गई हैं।

अंतर केवल पैडिंग में है।66 90के बादgrade,90के बादtotal) द्वारा डिकोड किया जाता है, जो रोकने का कोई कारण नहीं है, और द्वारा Angr, जो बनाता है sub_40003eऔर sub_40005fरडार 2, रिज़िन और गिदरा उनमें से किसी का दावा नहीं करते हैं।

वेक्टरिज़ेड केसः -O2 पर लेजर

totalचार ग्राफ बिल्डरों में से प्रत्येक में 13 किनारों के साथ 10 ब्लॉकों में 41 निर्देश हैं। पाठ 33 से SSE2 लूप और स्कारल शेष लूप को हर जगह एक ही तरह से काट दिया जाता है। angr फिर से पैडिंग पर दो फ़ंक्शन जोड़ता है।

कूद तालिकाः -O0 पर ग्रेड

यहाँ उपकरण विभाजित हैं, और विभाजन सबक है।

ToolBlocksEdgesWhat the capture says
radare232the block at 0x62 has no successor; bytes 0x76 to 0x9a are never reached; 8 instruction starts missing
rizin811the block at 0x62 carries a switch_op with 5 cases and 4 distinct targets
angr87the case blocks exist, and the transfer at 0x62 goes to an unresolvable target node
Ghidra912switchD label at 0x74 splits the block; four COMPUTED_JUMP flows to 0x76, 0x7f, 0x88, 0x91

जब वे उन तक पहुंचे तो चारों ने एक ही 33 निर्देशों को डिकोड किया। रडार 2 पर रुक गया।jmp raxऔर 36 बाइट्स को अनचाहे छोड़ दिया, और हर्नस नाम जो कि याद किए गए कोड के रूप में भिन्न होते हैं। रिजिन और गिदरा ने चार अलग-अलग लक्ष्यों को पाया कि पाठ 33 में पढ़ा गया है पांच स्थानांतरणों से .rela.rodata. Angr अंदर के मामले ब्लॉक सूचीबद्ध करता है gradeऔर अभी भी कूद ब्लॉक से उन्हें करने के लिए कोई किनारा नहीं है; इसकी पकड़ पर स्थानांतरण रिकॉर्ड करता है 0x62एक हल नहीं किया जा सकता लक्ष्य नोड के लिए नेतृत्व के रूप में, और इसके decompiler एक कम्प्यूटेड प्रिंट किया goto. गिद्र में एक ब्लॉक और एक किनारा है रिज़िन के समान नियंत्रण प्रवाह के लिए क्योंकि उसके स्विच विश्लेषण ने jmp raxऔर ब्लॉक मॉडल एक लेबल पर एक नया ब्लॉक शुरू करता है।

पाठ-33 ग्राफ में 8 ब्लॉक और 11 किनारे थे। रिज़िन इसे बिल्कुल मेल खाता है। यह देखना है कि 9 और 11 और 7 और 2 कोड के चार माप नहीं हैं। वे चार उत्तर हैं कि एक उपकरण ने एक अप्रत्यक्ष कूद के बाद कितनी दूरी तय की और उसने कहां काटने का फैसला किया।

कोड में डेटाः स्वीप-ट्राप

lookupचार तालिका बाइट्स के साथ 24 बाइट्स है 31 c0 90 48पर0x10. स्वीप रिपोर्ट 8 निर्देश उस सीमा में शुरू होता है. हर्नस बहुमत से अपने मतभेदों की सूची देता हैः अतिरिक्त शुरू होता है 0x10,0x12और 0x13, और एक गायब शुरुआत 0x14. . यह है addq $0x1, %raxरडार2, रिज़िन, और गिदरा रिपोर्ट 6 शुरू, 2 ब्लॉक, 1 किनारा, और छोड़ 0x100x14अनचाहे. एएनजीआर रिपोर्ट्स के लिए समान 2 ब्लॉक और 1 किनाराlookupऔर फिर आविष्कार करता है sub_400010तालिका पर बाइट्सः 4 बाइट ब्लॉक में 2 निर्देश जो पर समाप्त होता है0x14, जहां के दूसरे ब्लॉकlookupशुरू होता है, तो REX बाइट पर 0x13इस वस्तु के लिए हार्नेस का अंतिम निष्कर्ष यह है कि कोई ग्राफ बिल्डर डिकोड नहीं करता है0x100x14, तो वे बाइट्स एक फ़ंक्शन के अंदर बैठते हैं और डेटा हैं.

उपकरण द्वारा आविष्कार और चूक

चार वस्तुओं के बीच हर्नस 9 कार्यों का नाम देता है जो एंग्र बिना किसी प्रतीक के आविष्कार करते हैं, प्रत्येक पैडिंग या फंसी टेबल पर। यह एक रेंज का नाम देता है जो रडार2 याद करता है, 36 मामले बाइट्सgradeपर-O0. यह 9 रेंज का नाम देता है जो रैखिक स्वीप डिकोड करता है और कोई ग्राफ बिल्डर कोड के रूप में व्यवहार नहीं करता हैः आठ पैडिंग रिक्तियां प्लस फंक्शन टेबल। यह किसी भी उपकरण में कोई मिस फ़ंक्शन का नाम नहीं देता है।

ग्रेड पर तीन डिस्कोम्पाइलर

कैप्चर किए गए तीन उपकरणों में से C-जैसे पाठ emit करते हैं gradeपर-O1. स्रोत हैswitch (score / 10)पांच मामलों के साथ, सीमाओं की जांच और रिटर्न मानों की तालिका के अनुसार संकलित।

गिद्र 12.1.4:

cuint grade(int param_1)
{
  uint uVar1;
  uint uVar2;

  uVar2 = param_1 / 10 - 6;
  uVar1 = -(param_1 >> 0x1f) ^ (uint)((ulong)((long)param_1 * 0x66666667) >> 0x3f);
  if (uVar2 < 5) {
    uVar1 = *(uint *)(&DAT_001000b4 + (ulong)uVar2 * 4);
  }
  return uVar1;
}

angr 10.0.3:

cextern unsigned int g_4000b4[4];

unsigned int grade(int a0)
{
    unsigned int v1;  // ecx
    unsigned int v2;  // eax

    v1 = (unsigned int)((long long)(a0 * 1717986919) >> 0x22) + (unsigned int)(a0 * 1717986919 >> 63) - 6;
    v2 = 0;
    if (v1 <= 4)
        v2 = g_4000b4[v1];
    return v2;
}

रडार2 6.2.4, pdc:

cvoid sym.grade (int64_t arg1) {
    rax = edi
    rax = rax * 0x66666667
    rcx = rax
    rcx >>= 0x22
    rax >>>= 0x3f
    ecx += eax
    ecx += 0xfffffffa
    eax = 0
    v = ecx - 4
    if (((unsigned) v) <= 0) {
        eax = ecx
        rcx = rip
        eax = dword [rcx + rax*4]
    }
    return
}

पाइपलाइन के खिलाफ तीनों को पढ़ें. Ghidra के शब्द को फिर से लिखना गुना से गुना है0x66666667और 34 से वापस करने के लिए शिफ्ट param_1 / 10Angr समान बाइट्स उठाया और अंकगणित छोड़ दियाa0 * 1717986919 >> 0x22. रडार2s pdcESIL अनुकरण प्लस छद्म वाक्यविन्यासः रजिस्टर नाम, कोई चर, कोई प्रकार नहीं, और सीमाओं की जांच के रूप में मुद्रित<= 0एक असीमित घटाने के बाद. Ghidra तालिका भार के माध्यम से टाइप किया।DAT_001000b4; घोषित किया गया g_4000b4[4]न तो गिदरा और न ही एंग्र ने मामलों की गिनती हासिल की, क्योंकि-O1बाइट्स में कोई स्विच नहीं बचा है।-O0, जहां कूदने की मेज मौजूद है, Ghidra मुद्रित switch(param_1 / 10)6 से 10 के मामलों और डिफ़ॉल्ट के साथ, और angr प्रिंट एक कम्प्यूटेड goto. .

रिजिन का कोई अपने आप का डिसीम्पिलर नहीं है, और कैप्चर रिकॉर्ड है कि pdcद्विआधारी निंजा के HLIL और हेक्स-रेस पेड़ दो आउटपुट है कि इस सबक को पकड़ नहीं सकता है.

इसे बनाओ

डेमो चलाएँः

bashcd phases/13-tools-and-protocols/37-the-reverse-engineering-landscape
python3 code/main.py

आउटपुट एक JSON रिपोर्ट है। यह कैप्चर के समय रिकॉर्ड किए गए उपकरण संस्करणों के साथ और आपके मशीन पर मौजूद उपकरणों के साथ खुलता है, जो सभी अनुपस्थित हो सकते हैं। फिर चार वस्तुओं में से प्रत्येक के लिए यह प्रतीक विस्तार, पैडिंग रिक्तियों, प्रत्येक उपकरण का उपयोग किया आधार, प्रत्येक उपकरण पाया या आविष्कार किया गया है, और प्रत्येक समारोह के लिए निर्देश-शुरू समझौते, ब्लॉक गिनती, किनारे गिनती, और किनारे प्रत्येक उपकरण में कमी है के लिए प्रत्येक उपकरण शुरू करता है। यह प्रति उपकरण बाइट लेखांकन, उपकरण के स्वयं के नोट्स, सादे वाक्य में निष्कर्षों की सूची और आईआर अनुभाग के साथ समाप्त होता हैः कैप्चर किए गए लिफ्ट पर मापा गए गणनाओं के बगल में तीन निर्देशों के लिए अनुवादक का आउटपुट।

अपेक्षित आकारः

json{
  "captureTools": {"llvm-objdump": "Apple LLVM version 17.0.0", "radare2": "radare2 6.2.4 ...", "rizin": "rizin 0.9.1 ...", "angr": "10.0.3", "ghidra": "12.1.4"},
  "localTools": {"radare2": "absent", "...": "..."},
  "fixtures": {
    "ledger-x86_64-O0.o": {
      "bases": {"llvm-objdump": "0x0", "radare2": "0x8000040", "angr": "0x400000", "ghidra": "0x100000", "...": "..."},
      "functions": {"grade": {"blocks": {"radare2": 3, "rizin": 8, "angr": 8, "ghidra": 9}, "edges": {"radare2": 2, "rizin": 11, "angr": 7, "ghidra": 12}, "...": "..."}},
      "findings": ["radare2 never reaches bytes 0x76-0x9a inside grade that the other graph builders decode", "..."]
    }
  },
  "ir": {"translator": [{"text": "subq $0x10, %rsp", "flags": {"pcodeLike": "eager", "vexLike": "thunk"}, "...": "..."}], "observed": {"...": "..."}}
}

पढ़िए code/main.pyइस क्रम मेंः

  1. read_text_symbols()अनुभाग के शीर्षक और STT_FUNC के प्रतीक.textप्रतीक तालिका एकमात्र जमीन सत्य है कि हार्नेस है, औरTextSection.gaps()इससे भरने का स्रोत है।
  2. parse_objdump(),parse_r2_family(),parse_angr()और parse_ghidra()प्रत्येक एक कैप्चर में बदल जाता है ToolView: एक आधार, निर्देशों के रूप में लंबाई के लिए ऑफसेट, और एक FunctionViewप्रत्येक पार्सर एक उपकरण की शब्दावली को जानता है और कुछ भी नहीं।
  3. majority()और ranges()क्या दोनों सहायक हैं, जिनकी तुलना हर एक व्यक्ति करता है?
  4. function_report()ग्राफ बिल्डरों के बहुमत के खिलाफ निर्देश शुरू करता है, फिर ब्लॉक गिनती, फिर किनारे सेट करता है, और सूचीबद्ध करता है कि प्रत्येक उपकरण में क्या कमी है।
  5. byte_report()प्रत्येक बाइट को प्रतीक के अंदर कोड के रूप में खाता है, पैडिंग, अनक्लेम, आविष्कार या मिस किया गया है, और प्रतीक के अंदर बाइट का नाम देता है जिसे कोई ग्राफ बिल्डर डिकोड नहीं करता है।
  6. findings()उन वाक्य में बदल देता है, और compare()प्रति वस्तु एक रिपोर्ट तैयार करता है।
  7. decode_small(),to_pcode_like()और to_vex_like()अनुवादक हैंः तीन कोडिंग रजिस्टर के रूप में, एक उत्सुक शैली, एक थंक शैली।
  8. observed_ir()पकड़े गए लिफ्टों का माप करता है, तथा figure_data()समय रेखा, चरण तालिका और आंकड़े से पता चलता है कि सबूतों को इकट्ठा करता है।

तीन और आदेश मौजूद हैं।python3 code/main.py compare FIXTURE.oएक वस्तु की रिपोर्ट प्रिंट करता है। python3 code/main.py ir 4883ec10अनुवादक के दो रूपों को एक निर्देश के लिए प्रिंट करता है। python3 code/main.py figure-dataचित्र में सम्मिलित आंकड़ों को प्रिंट करता है।

पकड़े गए थे एक बार द्वारा किया गया था code/fixtures/capture_tools.py, जो प्रत्येक आदेश और संस्करण रिकॉर्ड करता है captures.json. हर्नस और परीक्षण कभी भी उपकरण को शुरू नहीं करते हैं. यदि आपके पास उपकरण हैं, तो फ़ाइलों को ताज़ा करने के लिए कैप्चर स्क्रिप्ट चलाएं, और पर्यावरण के लिए README फिक्स्चर पढ़ें जिसकी आवश्यकता है।

इसका प्रयोग करें

इस क्रम में एक नए वस्तु पर हर्नस का उपयोग करें।

  1. आप स्वयं वस्तु का निर्माण करें और संकलक कमांड को बनाए रखें। किसी भी उपकरण को खोलने से पहले इसके प्रतीक तालिका को पढ़ें, ताकि आप जान सकें कि कितने कार्य हैं और पैडिंग कहां है।
  2. प्रत्येक उपकरण को एक बार सिर रहित मोड में कैप्चर करें। कच्चे आउटपुट और सटीक कमांड को ऑब्जेक्ट के बगल में स्टोर करें। एक असहमति जिसे आप फिर से नहीं पढ़ सकते, कोई निष्कर्ष नहीं है।
  3. आधार की जाँच करें. एक फ़ंक्शन चुनें और पुष्टि करें कि प्रत्येक उपकरण इसे एक ही ऑफसेट पर रखता है जब आप उसके घटाने के बाद .textपता. अगर कोई नहीं है, रुकें और पता करें कि उस उपकरण लोड किया गया था.
  4. तुलना निर्देश पहले शुरू होता है. यदि ग्राफ बिल्डर यहां असहमत हैं, तो बाकी तुलना को डिकोडिंग के बारे में है और विश्लेषण के बारे में नहीं है.
  5. ब्लॉक और किनारों की तुलना करें, और किसी गिनती का न्याय करने से पहले प्रत्येक उपकरण के नोट्स पढ़ें।switch_op, ए COMPUTED_JUMP, या एक हल नहीं किया लक्ष्य नोड अधिकांश मतभेदों की व्याख्या करता है।
  6. बाइट्स के लिए खाता। पैडिंग जो एक उपकरण का दावा करता है वह एक काम में है। प्रतीक बाइट्स जो एक उपकरण छोड़ता है एक स्टॉप वॉक है। प्रतीक बाइट्स जो कोई ग्राफ बिल्डर दावा नहीं करता है वे डेटा हैं।
  7. दस्तावेज से एक विवरण उपयोगी है और एक कैप्चर से एक अलग प्रकार का सबूत है।

इंटरैक्टिव लैब

लैब ए: एक फ़ंक्शन, चार आधार

codeनिर्देशिका, खुला पायथनः

bashcd phases/13-tools-and-protocols/37-the-reverse-engineering-landscape/code
python3 -q

दौड़ें:

pythonfrom main import *
views = load_views("ledger-x86_64-O1.o")
{tool: hex(view.base) for tool, view in views.items()}
{tool: hex(view.functions["grade"].start + view.base) for tool, view in views.items()}

आप दूसरी पंक्ति चलाने से पहले चार कच्चे पते लिखें और इस पाठ में तालिका के खिलाफ उन्हें जांचें. फिर प्रतिस्थापित करेंgradeके साथgrade_labelऔर हाथ से गणना करें कि यह गिदरा में कहाँ बैठता है।

लैब बीः चार पक्षों से कूदने की टेबल

pythonreport = compare("ledger-x86_64-O0.o")
report["functions"]["grade"]["blocks"]
report["functions"]["grade"]["edgesMissingPerTool"]["radare2"]
report["notes"]["rizin"]
report["notes"]["ghidra"]
report["bytes"]["radare2"]["misses"]

रडार 2 की कमी के किनारों की गणना करें और प्रत्येक को एक रेखा से मेल खाने के लिए -O0फिर गिदरा नोट पढ़ें और खोजें switchDगिदरा कैप्चर में लेबल।

लैब सीः एक थन के खिलाफ उत्सुक ध्वज

pythontranslate("48 83 ec 10")["pcodeLike"]
translate("48 83 ec 10")["vexLike"]
translate("83 f9 04")["vexLike"]
{row["name"]: (row["pcode"]["ops"], row["vex"]["statements"]) for row in observed_ir()["instructions"]}

cc_opदोनों आउटपुट में निरंतर और समझाएं कि एक 8 और दूसरा 7 क्यों है। फिर कोशिश करें।translate("48 01 c8")और पढ़ें TranslateError. .

लैब डीः पांच उपकरणों के नीचे जाल

pythonreport = compare("sweep-trap.o")
report["functions"]["lookup"]["instructionStarts"]
report["bytes"]["dataInsideSymbols"]
report["functionStarts"]["angr"]

बाइट्स को डिकोड करें 31 c0 90 48 83 c0 01कागज पर एक झाड़ू के रूप में होगा, तो एक उतार के रूप में होगा के बाद jmp. अतिरिक्त और गायब हो रहा है के साथ अपनी दो सूची मेल खाता है हर्नस रिपोर्ट शुरू होता है.

अभ्यास प्रयोगशाला

पांचवें पकड़ जोड़ें और हर्नर को बढ़ाएं।

आवश्यकताएँः

  • एक उपकरण चुनें जो इस पाठ में नहीं मिला है और जिसे आप अपनी मशीन पर चला सकते हैंः GNU objdump, कैपस्टोन के साथ लाइफ, एक बाइनरी निंजा मुक्त सत्र हाथ से निर्यात, या एक अलग विश्लेषक सेट के साथ गिड्रा. सभी चार वस्तुओं पर सटीक कमांड और संस्करण के साथ इसके आउटपुट को कैप्चर करें captures.json. .
  • एक पार्सर लिखें जो कैप्चर को एक में बदल देता है ToolViewउपकरण के आधार, निर्देश, कार्यों, ब्लॉक जहां उपकरण उन्हें है, और किनारों जहां यह उन्हें है के साथ।
  • में उपकरण जोड़ेंTOOLSऔर, अगर यह एक ग्राफ बनाता है, तो DESCENT_TOOLSडेमो चलाओ और पढ़ें कि बहुमत सेट में क्या बदल गया है।
  • एक परीक्षण लिखें जो उपकरण के ब्लॉक की गणना करता है ledger-x86_64-O1.oऔर एक परीक्षण जो यह बताता है कि यह जाल मेज के साथ क्या करता है।
  • पाठ के लिए एक पैराग्राफ लिखें जो कहता है कि उपकरण के अपने शब्दों में, लोडर, डिमॉन्टेबलर और सीएफजी क्या कहते हैं।

सफलता का अर्थ हैpython3 code/main.pycaptureTools, प्रत्येक कार्य में ledger-x86_64-O1.oरखती है allDescentToolsAgreeसही, और निष्कर्षों के लिएsweep-trap.oबताओ कि नया उपकरण बाइट्स के साथ क्या किया 0x100x14. .

पाठ कलाकृतियाँ

इस सबक में शामिल है outputs/skill-the-reverse-engineering-landscape.md. इसका उपयोग आपके द्वारा बनाए गए एक ऑब्जेक्ट पर कई टूल चलाने के लिए करें, उनके पते को एक आधार तक कम करें, और प्रति फ़ंक्शन रिपोर्ट करें, जहां वे निर्देश स्टार्ट, ब्लॉक और किनारों पर सहमत होते हैं, और प्रत्येक टूल का आविष्कार या चूकता है। इसमें रिकॉर्ड किए गए कमांड और संस्करणों के साथ कैप्चर की आवश्यकता होती है, फ़ाइल से एक प्रतीक तालिका पढ़ी जाती है, और एक कथन जिसमें केवल दस्तावेज से कौन से टूल वर्णित किए गए थे।

जाँचें

डेमो और निर्धारक सूट चलाएंः

bashcd phases/13-tools-and-protocols/37-the-reverse-engineering-landscape
python3 code/main.py
python3 -m unittest discover -s code/tests -v

सत्यापन से साबित होना चाहिएः

  • ELF रीडर में चार फ़ंक्शन प्रतीक होते हैं ledger-x86_64-O1.oआकार 16, 46, 31 और 63 के साथ और दो पैडिंग रिक्तियों के साथ
  • चार वस्तुओं के लिए स्वीप कैप्चर 86, 56, 84 और 11 निर्देश
  • रडार2 और रिज़िन पर एक ही निर्देश, ब्लॉक और किनारों की रिपोर्ट करते हैं ledger-x86_64-O1.o, और केवल रडार 2 हैpdcपाठ
  • अंकsub_40003eऔर sub_40005fबिना प्रतीक के कार्यों के रूप में
  • Ghidra के ब्लॉक के लिए totalपाठ 33 के पांच ब्लॉक हैं और इसके कॉल प्रवाह ग्राफ किनारे नहीं हैं
  • हर उपकरण स्थान gradeविलय में0x10उसके आधार को हटाने के बाद
  • प्रत्येक उपकरण प्रत्येक निर्देश के प्रत्येक कार्य में शुरू करने पर सहमत है ledger-x86_64-O1.o
  • चार ग्राफ बिल्डर 3, 3, 5, 4 ब्लॉक और 2, 3, 5, 4 किनारों की रिपोर्ट करते हैं, जिसमें समान किनार सेट होते हैं
  • totalपर-O2प्रत्येक ग्राफ बिल्डर में 10 ब्लॉक और 13 किनारे हैं
  • gradeपर-O0प्रत्येक उपकरण के नोटों में कारणों के साथ 3, 8, 8 और 9 ब्लॉक और 2, 11, 7 और 12 किनारों में रडार2, रिजिन, एंग्र और गिदरा है
  • grade_labelपर-O0एक ब्लॉक हर जगह है, Angr को छोड़कर, जो कॉल पर एक ब्लॉक समाप्त होता है
  • angr एक फंक्शन प्रति पैडिंग gap प्लस एक फंक्शन पर फंक्शन का आविष्कार करता है, और कोई अन्य उपकरण किसी फंक्शन का आविष्कार या चूकता नहीं है
  • स्वीप लाभ शुरू होता है 0x10,0x12,0x13और हारता है 0x14जाल पर, और कोई ग्राफ बिल्डर डिकोड नहीं 0x100x14
  • निष्कर्षों में रडार2 में याद आया सीमा का नाम और एएनआर में प्रत्येक आविष्कार समारोह
  • मैनिफस्ट सभी 21 कैप्चर फ़ाइलों के लिए एक संस्करण और एक कमांड रिकॉर्ड करता है
  • तीन उपकरण को विघटन grade, और केवल गिदरा विभाजन की भाषा को मोड़ता है
  • अनुवादक एक शैली और एक cc_opएक और में थंक, कोई रजिस्टर नहीं लिखता हैcmp, और कोई ध्वज नहीं movslq
  • अनुवादक मेमोरी फॉर्म, अन्य ऑपकोड, अतिरिक्त REX बिट्स और गलत लंबाई से इनकार करता है
  • अनुवादक का cc_opसंख्या 8 और 7 पकड़े गए VEX में उन लोगों के बराबर हैं
  • कैप्चर किए गए लिफ्ट तीन निर्देशों के लिए 9, 1, 10 पी-कोड ऑपरेशन और 7, 4, 7 VEX विवरण देते हैं
  • समय रेखा 1973 से 2026 तक क्रम में चलती है, पाइपलाइन में आठ चरण और प्रत्येक सेल में एक अवधि के साथ छह उपकरण हैं, और दो बंद उपकरण के रूप में चिह्नित नहीं चल रहे हैं
  • इंटरैक्टिव आंकड़ा उसी डेटा को शामिल करता है जो हार्नेस उत्पन्न करता है

उत्पादन विफलता मोड

FailureWhat the weak report saysWhat the harness must prove
Raw addresses from different tools"the tools disagree about where grade is"one offset after each base is removed, checked on one function
Block count as a measure of code found"Ghidra found the most code"the same instruction starts, with the extra block explained by a label
One tool as the oracle"objdump shows the table bytes are instructions"the sweep is a linear sweep; three graph builders leave the bytes unclaimed
Padding functions counted as discoveries"angr found seven more functions"every one sits in a padding gap or on data, and none has a symbol
A stopped walk reported as dead code"the four case blocks are unreachable"36 bytes missed by one tool and reached by three
Edge counts compared without the notes"rizin and Ghidra disagree on grade"the same four computed targets, one extra split at a label
A decompiler's arithmetic read as the program"the function multiplies by 1717986919"the idiom from lesson 34, folded by one tool and left by another
A closed tool described as if run"Binary Ninja reports five blocks"the figure and the table mark it as documentation only
Captures without commands"we ran radare2"the manifest with version, command, and date for every file
An IR with no flags read as a lossy lift"VEX dropped the flags"the thunk in cc_op, cc_dep1, cc_dep2, evaluated at the branch

परिचालन नियम

प्रत्येक उपकरण को एक बार उसके कमांड और संस्करण के साथ कैप्चर करें, प्रत्येक पते को एक आधार में कम करें, और ब्लॉक से पहले निर्देश शुरू करें और किनारों से पहले ब्लॉक की तुलना करें। प्रत्येक बाइट के लिए दावा, पैडिंग, डेटा या याद किए गए के रूप में खाता बनाएं। अपनी गणना का न्याय करने से पहले किसी उपकरण के अपने नोट को पढ़ें, और बताएं कि आप केवल किन उपकरणों के बारे में पढ़ते हैं।

आगे पढ़ना

This free lesson is part of the AI Engineering from Scratch curriculum. Read the full explanation, run the lesson code, and verify the result in the interactive reader or from the repository source.

Browse the complete course catalog or open this lesson on GitHub.