Phase 13: Tools & Protocols

मूल कोड से परेः पायथन, जेवीएम, .नेट, और वेब असेंबली बायकोड

एक बाइटकोड फ़ाइल एक प्रोग्राम है इसके साथ-साथ इसके बारे में संकलक के नोट्स, और यह पाठ पाठकों को बनाता है जो दिखाता है कि प्रत्येक कंटेनर कौन से नोट रखता है।

Type: Build

Languages: Python, Java, C#, WebAssembly text

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

Time: ~150 minutes

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

  • 16 बाइट पढ़ें .pycPEP 552 से हेडर और कोड वस्तु को बिना marshalचार अनुवादक संस्करणों द्वारा लिखित फ़ाइलों के लिए मॉड्यूल।
  • JVMS अध्याय 4 से JVM वर्ग फ़ाइल को पार्स करें: निरंतर पूल, फ़ील्ड, विधियां, Codeविशेषता, और तालिकाओं जो javac -gजोड़ता है।
  • JVM में ओपकोड को डिस्कनेक्ट करें Ledger.classऔर सूचीबद्ध करने के खिलाफ साबित javap -cएक ही स्रोत के चार निर्माण पर।
  • वेब असेंबली मॉड्यूल सेक्शन सेक्शन पढ़ें, प्रत्येक फ़ंक्शन बॉडी को डिकोड करें, और परिणाम को साबित करें wasm-objdump -d. .
  • पीई डेटा निर्देशिका से .नेट असेंबली के ECMA-335 मेटाडेटा को MethodDefपंक्तियों और प्रत्येक विधि के CIL, ILSpy द्वारा उपयोग किए जाने वाले पाठक पुस्तकालय के खिलाफ जाँच की गई।
  • पांच कंटेनरों में एक फ़ंक्शन के लिए मापें, प्रत्येक प्रारूप में कौन से नाम, प्रकार और नियंत्रण संरचना रखी जाती है और कौन से खो जाते हैं।

समस्या

तुमने बनाया हैledger.pyऔर पाया ledger.cpython-314.pycमें __pycache__आप एक एजेंट से पूछा कि फ़ाइल में क्या है, एजेंट एक decompiler चलाया. उपकरण मुद्रित.Unsupported opcodeऔर एक पंक्ति जो कहती है # WARNING: Decompyle incompleteएजेंट ने निष्कर्ष निकाला कि फ़ाइल को अस्पष्ट कर दिया गया था।

फ़ाइल को अस्पष्ट नहीं किया गया था. इसके पहले दो बाइट्स हैं2b 0e, छोटे-एंडियन शब्द 3627. यह संख्या CPython 3.14 लिखता है, और decompileer के opcode तालिकाओं 3.13. पर बंद कर दिया है। उपकरण पुराना था. एजेंट हेडर नहीं पढ़ा, तो यह अंतर नहीं बता सकता था.

पाठ 33 ने दिखाया कि मूल कोड क्या खोता हैः पैरामीटर नाम, प्रकार, और switchजो एक कूद टेबल बन गया। बाइटकोड कंटेनर कम खोते हैं, और प्रत्येक कुछ अलग खोता है। एक पीसी प्रत्येक चर का नाम और कोई प्रकार नहीं रखता है। एक वर्ग फ़ाइल केवल तब टाइप और स्थानीय नाम रखता है जब आप पूछते हैं। एक वासम मॉड्यूल नियंत्रण संरचना को बनाए रखता है और नामों को छोड़ देता है जब तक कि एक कस्टम अनुभाग उन्हें नहीं ले जाता है। एक .NET असेंबली एक तालिका में पैरामीटर नाम रखता है और स्थानीय नामों को एक अलग फ़ाइल में छोड़ देता है। आप उन में से किसी पर भी डिकॉम्पिलर के आउटपुट का न्याय नहीं कर सकते जब तक आप नहीं जानते कि कंटेनर को किस नोट से शुरू करना था।

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

पीसी हेडर चार शब्द है

PEP 552 हेडर को चार 32-बिट शब्दों के रूप में परिभाषित करता है। पहला जादुई संख्या है। दूसरा एक बिट क्षेत्र है। बिट 0 सेट का मतलब है कि फ़ाइल हैश-आधारित है। बिट 1 सेट का मतलब है check_source: अनुवादक आयात पर स्रोत हैश करता है और तुलना करता है। बिट 0 स्पष्ट के साथ, शब्द तीन और चार स्रोत mtime और स्रोत आकार हैं। बिट 0 सेट के साथ, वे स्रोत के 64-बिट SipHash रखते हैं।

जादू संख्या में रहता है Include/internal/pycore_magic_number.h3.11 के बाद से इसका नियम यह है कि पायथन 3.n 2900 + 50n से शुरू होता है, और रिलीज़ चक्र के भीतर प्रत्येक बाइटकोड परिवर्तन में एक जोड़ता है। संग्रहीत टोकन 16 बिट संख्या है जिसके बाद \r\n, तो एक पाठ मोड में खोला गया pyc एक गलत जादू प्राप्त करता है. अंतिम मान हैं 3495 के लिए 3.11, 3531 के लिए 3.12, 3571 के लिए 3.13, 3627 के लिए 3.14, और 3666 के लिए 3.15. पायथन 3.15.0 2026-10-09 पर जारी किया गया था और इस मशीन पर स्थापित नहीं है जो इन फिक्स्चर बनाया है, इसलिए इसकी संख्या हेडर फ़ाइल से आता है और यहां की फ़ाइल से नहीं।

फिक्स्चर प्रति अनुवादक दो pyc फ़ाइलें रखती हैं। compile_pyc.pyउन्हें लिखा था py_compile.compile(..., dfile="ledger.py")ताकि संग्रहीत फ़ाइल का नाम होledger.py3.14 फ़ाइलों के पहले 16 बाइट्सः

output
checked-hash   2b 0e 0d 0a  03 00 00 00  c7 16 c7 fc c5 1d 81 01
timestamp      2b 0e 0d 0a  00 00 00 00  8d 60 cf 6a  f1 01 00 00

समयशीर्षक शब्द-शब्द पढ़ें। 03 00 00 00या 00 00 00 00यह ध्वज शब्द है।8d 60 cf 6aहै 0x6acf608d = 1791975565, mtime of ledger.pyजब फ़ाइल बनाई गई थी।f1 01 00 00यह स्रोत आकार 497 है। चेक-हैश फ़ाइल में ध्वज 3 और आठ हैश बाइट्स हैं। चार अनुवादक हेडर में जादू शब्द को छोड़कर सभी पर सहमत हैंः

InterpreterMagic bytesWordFile bytesgrade.co_code bytesgrade instructions
3.11.14a7 0d 0d 0a349510548031
3.12.12cb 0d 0d 0a35319376226
3.13.12f3 0d 0d 0a35719437026
3.14.62b 0e 0d 0a36279659635

read_pyc_header()में code/main.pyइन फ़ील्ड को लौटाता है और शब्द से संस्करण का नाम देता है। importlib.util.MAGIC_NUMBERचल रहे अनुवादक के लिए एक ही चार बाइट देता है। python3 code/main.py compareस्रोत को प्रत्येक के साथ संकलित करता है python3.11python3.15पर पाया गयाPATHप्रत्येक के लिए यह शीर्षक प्रिंट करता है हमारे पाठक तथ्य के साथ देखता है कि अनुवादक खुद के बारे में रिपोर्ट करता है।

मार्शल कोड ऑब्जेक्ट फ़ील्ड द्वारा फ़ील्ड लिखता है

प्रत्येक फिक्स्चर का बाइट 16 है e3. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .0x80 | ord('c'): के साथ कोड वस्तु के लिए मार्शल प्रकार कोडFLAG_REFसेट, जो पाठक को बाद के लिए वस्तु को याद करने के लिए कहता है rसंदर्भ। मार्शल प्रलेखन में कहा गया है कि प्रारूप उद्देश्य से अनौपचारिक है और कोड ऑब्जेक्ट संस्करणों के बीच संगत नहीं हैं। दोनों कथन सही हैं, और प्रारूप अभी भी पढ़ने के लिए पर्याप्त छोटा है। Python/marshal.cप्रकार कोडों की सूची देता हैः Nकोई नहीं,iएक 32-बिट int, sबाइट्स, zऔर Zलघु ASCII स्ट्रिंग्स, (और )टप्पे, cएक कोड वस्तु, rकंटेनर अपने बच्चों के सामने अपना संदर्भ स्थान आरक्षित करते हैं, इसलिए पाठक भी ऐसा ही करता है।

w_complex_object()3.11 से 3.15 के लिए यह हैargcount,posonlyargcount,kwonlyargcount,stacksize,flags32 बिट इंच के रूप में, तो code,consts,names,localsplusnames,localspluskinds,filename,name,qualnameवस्तुओं के रूप में, तो firstlineno, तो linetableऔर exceptiontable. 3.14 फ़ाइल के मॉड्यूल कोड वस्तु को बाइट 17 से हाथ से डिकोड करेंः

output
00 00 00 00   argcount 0
00 00 00 00   posonlyargcount 0
00 00 00 00   kwonlyargcount 0
01 00 00 00   stacksize 1
00 00 00 00   flags 0
f3 22 00 00 00   type 's' with FLAG_REF, 34 bytes of co_code follow
80 00  52 06  74 00  52 01  17 00  74 01 ...

कोड बाइट्स प्रत्येक निर्देश के लिए दो हैंः 80 00है RESUME 0,52 06है LOAD_CONST 6,74 00है STORE_NAME 0और 17 00है MAKE_FUNCTION. फिक्स्चर में 3.14 सूची में वही पांच मॉड्यूल स्तर के बयान छापे जाते हैं।codeलगातार आते हैं, जो चार घोंसले कोड वस्तुओं को पकड़ते हैं, और उनके बाद names('LABELS', 'percent_change', 'grade', 'total', 'grade_label'). .

Unmarshallerमें code/main.pyइस लेआउट और पुराने एक है कि 3.9 और 3.10 इस्तेमाल किया पढ़ा, जहां nlocals,varnames,freevarsऔर cellvarsयह एक अलग क्षेत्र है।CodeObjectवास्तविक वस्तु के समान विशेषता नामों के साथ। varnamesफ़िल्टर localsplusnamesद्वारा CO_FAST_LOCALथोड़ा सा localspluskinds. . के लिए .gradeचार फ़ाइलों में से प्रत्येक में यह वापस आता है ('score', 'bucket'),firstlineno10, और एक गैर-खाली linetable. . परीक्षणtest_unmarshaller_agrees_with_the_running_interpreterप्रत्येक क्षेत्र की तुलना करता है marshal.loads()अन्य तीन फ़ाइलें हमारे कोड द्वारा पठनीय हैं और गैर पठनीय हैंmarshalइस अनुवादक के तहत।

चार अनुवादक, चार बीटकोड ग्रेड के लिए

इस डिस्कूमेंटेशन में प्रत्येक संस्करण पर एक चेतावनी हैः बाइटकोड CPython का एक कार्यान्वयन विवरण है और यह गारंटी नहीं दी जाती है कि यह समान रहेगा। फिक्स्चर में दिखाया गया है कि Python की 11 पंक्तियों के लिए इसका क्या मतलब है। python3.1N -m dis ledger.pyप्रत्येक अनुवादक के लिए कैप्चर किया गया था।

3.11 gradeइस तरह शुरू होता हैः

output
 11           2 LOAD_FAST                0 (score)
              4 LOAD_CONST               1 (10)
              6 BINARY_OP                2 (//)
             10 STORE_FAST               1 (bucket)
 12          12 LOAD_FAST                1 (bucket)
             14 LOAD_CONST               2 (9)
             16 COMPARE_OP               5 (>=)
             22 POP_JUMP_FORWARD_IF_FALSE     2 (to 28)

BINARY_OPऑफसेट 6 पर बैठता है और अगले निर्देश 10 पर। उनके बीच के दो बाइट्स PEP 659 से एक इनलाइन कैश प्रविष्टि हैं, विशेषज्ञता अनुकूलन व्याख्याता। COMPARE_OP16 पर 22 के बाद है, तो यह दो कैश प्रविष्टियों का मालिक है. कैश छिपा रहे हैं जब तक आप पास नहीं करते हैं.show_caches=True3.12 प्रतिस्थापन LOAD_CONSTऔर RETURN_VALUEके साथRETURN_CONST, कूद को POP_JUMP_IF_FALSEऔर संकुचित हो जाता है grade80 से 62 बाइट तक। 3.13 प्रिंट लेबल L1L4इसके बजाय ऑफसेट करता है और CLI देता है -Cकैश और -O3.14 हटाता है RETURN_CONSTफिर से, जोड़ता है LOAD_SMALL_INTऔर LOAD_FAST_BORROW, और सम्मिलित NOT_TAKENप्रत्येक सशर्त कूद के बादः

output
 12         20       LOAD_FAST_BORROW         1 (bucket)
            22       LOAD_SMALL_INT           9
            24       COMPARE_OP             188 (bool(>=))
            26       CACHE                    0 (counter: 0)
            28       POP_JUMP_IF_FALSE        3 (to L1)
            30       CACHE                    0 (counter: 0)
            32       NOT_TAKEN

-C -Oसूचीबद्ध दिखाता है 13 CACHEअंदर प्रविष्टियाँ grade: पांच के बाद BINARY_OP, एक के बाद एक COMPARE_OP, एक के बाद एक POP_JUMP_IF_FALSEअनुकूलन फिचर दिखाता है कि क्या कैश के लिए हैं. 200 कॉल के बाद,dis.dis(grade, adaptive=True)छापें RESUME_CHECKऔर COMPARE_OP_INTजहां सादा सूची में था RESUMEऔर COMPARE_OPऔर totalदिखाता हैFOR_ITER_LIST,BINARY_OP_ADD_INTऔर JUMP_BACKWARD_NO_JIT. विशेष रूप से एक ही में रहते हैं co_codeएक pyc कभी भी उन्हें शामिल नहीं है, क्योंकि विशेषज्ञता स्मृति में होता है.

इस कारण से डिकोम्पाइलर संस्करण सीमाओं है. uncompyle6 3.9.3 बताता है कि यह पायथन 1.0 से 3.8 तक बाइटकोड स्वीकार करता है. decompyle3 3.9.3 3.7 और 3.8 पढ़ता है। xdis 6.3.0, दोनों के पीछे क्रॉस-वेरशन डिमॉन्टेलर, 3.13. तक पढ़ता है। pycdc में अप कोड तालिकाएं हैं।python_3_13.cppइसकी निर्माण फ़ाइल में, और एक अज्ञात opcode प्रिंट पर Unsupported opcodePyLingual 3.6 के बाद से जारी किए गए प्रत्येक संस्करण का दावा करता है और 3.8 से 3.15 तक अपने स्वयं के आउटपुट को फिर से संकलित करने और जांचने के लिए व्याख्याताओं का उपयोग करता है। 3.14 फ़ाइल के लिए, पहले तीन अस्वीकार या विफल होते हैं, और केवल अंतिम दो लागू होते हैं। किसी उपकरण को चुनने से पहले जादुई शब्द पढ़ें।

कक्षा फ़ाइल अपनी-अपनी शब्दकोश बनाए रखती है

JVMS जावा एसई 25, धारा 4.1, एक संरचना के रूप में लेआउट देता हैः magic,minor_version,major_version,constant_pool_count, निरंतर पूल, access_flags,this_class,super_class, इंटरफेस, क्षेत्रों, तरीकों, गुणों. जादू है0xCAFEBABE. जावा एसई 25 वर्चुअल मशीन प्रमुख संस्करण 45 से 69 तक स्वीकार करती है और 65535 के एक नाबालिग एक पूर्वावलोकन सुविधा फ़ाइल को चिह्नित करता है।Ledger-g.classहैंca fe ba be 00 00 00 41 00 5e: प्रमुख 65 जावा 21 है, और 0x5e= 94 निरंतर पूल संख्या है। Ledger-jdk25.class, उसी स्रोत से javac 25.0.2 द्वारा बनाया गया है, शुरू होता है ca fe ba be 00 00 00 45: मेजर 69.

निरंतर पूल वह जगह है जहाँ वर्ग फ़ाइल अपनी शब्दकोश रखता है।#13-gनिर्माण एक है Methodrefजो कक्षा पर अंक #8और नाम और प्रकार #14. सूचकांक के बाद देता है Ledger.grade:(I)I, जो कि ठीक है क्या हैjavap -vबाद में छापें //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .(I)Iएक हैintपैरामीटर और एक intपरिणाम।([I)Iपरtotalकहते हैं पैरामीटर एक है intarray. प्रत्येक विधि, क्षेत्र और वर्ग कोड स्पर्श करता है इस तरह के एक प्रविष्टि है, और खंड 4.10 में सत्यापनकर्ता एक फ़ाइल को अस्वीकार करता है जिसका निर्देश उनसे असहमत हैं।ClassFileकक्षा में code/main.pyतालिका 4.4 से सभी 17 निरंतर टैग पढ़ता है और एक Longया Doubleयह एक अज्ञात टैग पर और बाइट्स पर पिछले विशेषता के बाद उठता है।

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

BuildBytesConstant pool countLineNumberTableLocalVariableTableSourceFilegrade code bytes
javac -g1832947 methods6 methodsyes50
javac1581827 methodsnoneyes50
javac -g:none140479nonenoneno50

के 50 कोड बाइट्सgradeसभी तीनों फाइलों में समान हैं, और परीक्षण यह जाँचता है।-g के लिए जोड़ता हैgradeएक हैLocalVariableTableपंक्ति: प्रारंभ 0, लंबाई 50, स्लॉट 0, नाम score, वर्णक Iइसके बिना एक डिस्कोम्पाइलर प्रकार 0 स्लॉट देखता हैintऔर एक नाम का आविष्कार करना है।StackMapTableहर निर्माण में रहता है क्योंकि सत्यापनकर्ता की जरूरत है, और BootstrapMethodsविशेषता रहता है क्योंकि main के माध्यम से स्ट्रिंगों को सहसंयोजकinvokedynamic. .

टेबल स्विच को हाथ से डिकोड करें

JVMS के अध्याय 6 में प्रत्येक निर्देश को एक ऑपकोड बाइट और उन ऑपरेन्ड के रूप में परिभाषित किया गया है जो ऑपकोड नाम देते हैं। शाखा ऑफसेट शाखा ऑपकोड के पते के संबंध में 16-बिट हस्ताक्षरित मान हैं, जो x86-64 से भिन्न है, जहां विस्थापन अगले निर्देश के संबंध में है। tableswitchऔर lookupswitchशून्य से तीन पैडिंग बाइट्स के साथ शुरू करें ताकि उनके 32-बिट ऑपरेन्ड एक पते से शुरू हो जो चार का गुणक है।

के बाइट्सgradeLedger-g.class:

output
aa                 tableswitch at pc 4
00 00 00           padding to pc 8
00 00 00 2c        default: 4 + 44 = 48
00 00 00 06        low 6
00 00 00 0a        high 10
00 00 00 2a        case 6:  4 + 42 = 46
00 00 00 28        case 7:  4 + 40 = 44
00 00 00 26        case 8:  4 + 38 = 42
00 00 00 24        case 9:  4 + 36 = 40
00 00 00 24        case 10: 4 + 36 = 40

36 बाइट्स, एक निर्देश, और पूरे switch (score / 10)9 और 10 के लिए अपने साझा मामले के साथ।switchपाठ 33 में सीमाओं की जांच की आवश्यकता थी, एक lea, ए movslq, एक addयहाँ लक्ष्य निर्देश में हैं, और इसलिए तथ्य यह है कि वे एक साथ आते हैं.

disassemble_jvm()सभी 202 परिभाषित ऑपकोडों को उनके ऑपरेन्ड चौड़ाई के साथ कवर करता है, पैडिंग नियम का पालन करता है, और ऑपरेन्ड को रास्ता देता है javapकरता है।compare_with_javap()कैदियों को विश्लेषण करता है javap -c -pबहु-लाइन सहित पाठ tableswitchसभी चार निर्माण 108 में से 108 निर्देशों पर सहमत हैं। परीक्षण test_branch_offsets_are_relative_to_the_branch_instructionचेकifne6 पर लैंडिंग पर pc 1 पर।if_icmpge33 पर 13 पर लैंडिंग, और goto30 पर वापस 10 पर लैंडिंग।

रडार 2 6.2.4, इन सबक के लिए स्रोत से बनाया गया, एक ही फ़ाइल पढ़ता है। rabin2 -Iरिपोर्ट arch java,lang java 21,linenum trueऔर lsyms true, जो संस्करण और दो डिबग तालिकाओं का पढ़ना है। pd 14 @ sym.Ledger.gradetableswitchयह अपने पांच लक्ष्यों के लिए तीरों के साथ. यह भी छपता हैUnable to parse code attribute: 2इस फ़ाइल पर, जो एक सीमा है उपकरण नाम खुद और एक कारण रखने के लिए हैjavapएक प्रवचन के रूप में। इस प्रारूप के लिए डिकॉम्पिलर पायथन की तुलना में परिपक्व हैं। सीएफआर 0.152 MIT लाइसेंस प्राप्त है। प्रोकोन 0.6.0 और वाइनफ्लावर 1.12.0 अपाचे 2.0 हैं, और वाइनफ्लावर जावा 21 समर्थन के साथ एक फर्नफ्लावर कांटा है। Fernflower स्वयं इंटेलिजेंस समुदाय भंडारण के अंदर रहता है। जेएडीएक्स 1.5.6 एंड्रॉइड डीईएक्स प्रारूप को कवर करता है, और जेडी-जीयूआई को 2019 में इसकी अंतिम रिलीज हुई थी। हर्रैंड, सोटो-वैलेरो, मोनपर्रस और बाउड्री ने 2020 में उनमें से आठ को मापा। 84 प्रतिशत वर्गों के लिए सबसे अच्छा संश्लेषणात्मक रूप से सही आउटपुट और 78 प्रतिशत के लिए अर्थिक रूप से समकक्ष आउटपुट का उत्पादन किया गया। उनके मेटा-डिकॉम्पिलर ने 37.6 प्रतिशत वर्गों को बहाल किया जो किसी भी उपकरण द्वारा संभाल नहीं किए गए थे। प्रकार, नाम और सत्यापित स्टैक स्वरूप को डिसीम्पल करने योग्य बनाते हैं। वे किसी एक डिकॉम्पिलर को पूरा नहीं करते हैं।

एक वासम मॉड्यूल खंडों की सूची है

मूल विनिर्देश एक मॉड्यूल को प्रस्तावना के रूप में परिभाषित करता है 00 61 73 6d 01 00 00 00, स्ट्रिंग \0asmऔर संस्करण 1, अनुभागों के बाद. प्रत्येक अनुभाग एक आईडी बाइट है, एक u32LEB128 में आकार और इसकी सामग्री। 1 से 13 तक के आईडी ज्ञात खंड हैं, प्रत्येक अधिकतम एक बार और क्रम में। Id 0 एक नाम के साथ एक कस्टम खंड है, कहीं भी अनुमति दी जाती है। सभी पूर्णांक LEB128 हैं, इसलिए e4 00100 है और 80 08यह 1024 है।wasm-objdump -hपरledger.wasmसात धाराओं की सूची देता है, और WasmModuleसमान उपभोग भार के साथ समान सातों को पाता हैः

SectionPayloadCountWhat it holds for ledger
Type10 to 263(i32) -> nil, (i32, i32) -> i32, (i32) -> i32
Import28 to 391env.log with type 0
Function41 to 464type index for each defined function
Memory48 to 511one page, no maximum
Export53 to 1105memory and the four function names
Code113 to 2714bodies of 23, 63, 44, and 23 bytes
Data273 to 2901F\0D\0C\0B\0A\0 at offset 1024

फ़ंक्शन और कोड अनुभागों के बीच विभाजन मौजूद है ताकि ब्राउज़र पूरी फ़ाइल पहुंचने से पहले संकलन शुरू कर सके। प्रत्येक कोड प्रविष्टि एक आकार, स्थानीय घोषणाओं का वेक्टर और एक अभिव्यक्ति है।gradeस्थानीय वेक्टर है 01 7f: एक समूह का एक i32. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .bucket, उसके प्रकार के साथ और उसके नाम के बिना।

नियंत्रण प्रवाह संरचना द्वारा संरचित है। विनिर्देश कहता है शाखाओं केवल संलग्न करने के लिए लक्षित कर सकते हैं।block,loopया ifलेबल को घोंसला गहराई से सूचकांकित किया जाता है। br_tableएक ऑपरेंड के माध्यम से एक अप्रत्यक्ष शाखा का प्रदर्शन करता है जो एक लेबल सूची को सूचकांकित करता है।gradeफ़ाइल ऑफसेट पर 0xa3:

output
0e                  br_table
0b                  11 labels follow
04 04 04 04 04 04   buckets 0 to 5: label 4, the outermost block, returns 0
03 02 01 00         buckets 6, 7, 8, 9: labels 3, 2, 1, 0
00                  bucket 10: label 0, shared with 9
04                  default label 4

प्रत्येक लेबल एक गहराई है। लेबल 0 सबसे अंदर है block, और उसके बाद कोड endहै i32.const 4इसके बाद br 4परिणाम ब्लॉक से बाहर।blockतालिका के सामने निर्देश, ग्यारह लेबल, और पांच brनिर्देशों के बाद यह पूरे हो जाते हैं switch, और एक सत्यापित किसी भी शाखा को अस्वीकार करता है जो संरचना छोड़ देता है। disassemble_wasm()गहराई को ट्रैक करता है तो सूचीबद्ध अनुभागों जैसे wasm-objdump, से प्रत्येक एकल-बाइट ऑप्ट कोड को कवर करता है unreachablei64.extend32_sऔर पकड़े हुए लोगों से मेल खाता हैwasm-objdump -dदोनों निर्माणों के लिए 77 में से 77 निर्देशों पर।

नाम एक साधारण मॉड्यूल छोड़ने वाली एक चीज हैं।wasm-objdumpअभी भी छप <grade>क्योंकि निर्यात अनुभाग फ़ंक्शन सूचकांक 2 के लिए स्ट्रिंग का नक्शा करता है, और पाठक वही करता है। 290-बाइट फ़ाइल में स्थानीय नाम कहीं भी मौजूद नहीं हैं। wat2wasm --debug-namesएक कस्टम अनुभाग जोड़ा nameमॉड्यूल नाम, फ़ंक्शन नाम और स्थानीय नाम के लिए उपखंडों के साथ। फ़ाइल 425 बाइट तक बढ़ जाती है। पाठक पाता है {0: 'score', 1: 'bucket'}फ़ंक्शन 2 और {0: 'values', 1: 'count', 2: 'sum', 3: 'i'}फ़ंक्शन 3 के लिए। wasm-stripउपकरण-संविधान भंडार दो और वाहक का वर्णन करता है। DWARF को एम्बेड किया जा सकता है.debug_*कस्टम अनुभाग।sourceMappingURLकस्टम अनुभाग एक स्रोत नक्शा पर इंगित कर सकता है जिसका कॉलम संख्या बाइट ऑफसेट बाइनरी में हैं।

2026-09-15 में जारी किए गए 1.0.42 के दौरान उपकरण को स्थानांतरित किया गया। हटा दिया गया।wasm-decompile, और Homebrew इस मशीन पर बनाया गया है ठीक ही 11 शेष उपकरण है.print,objdumpऔर demangle. बिनारयण संस्करण_133 प्रदान करता है wasm-dis. रडार2 6.2.4 मॉड्यूल भी पढ़ता है.rabin2 -Iकहते हैंarch wasm. . . यह प्रतीक है .grade0x8e, जहां स्थानीय वेक्टर शुरू होता है, जबकि wasm-objdump पर कार्य को लेबल करता है0x8bइसकी सूची पुराने mnemonics का उपयोग करता है।get_local,set_localऔर brtable 11 4 4 ...लेबल की गिनती मुद्रित के साथ। तीनों उपकरणों में बाइट समान हैं और वर्तनी भिन्न है, इसलिए तुलना को उस उपकरण का नाम देना चाहिए जिसके साथ इसे कैप्चर किया गया था। इस पाठ के लिए शोध में गिदरा की प्रोसेसर निर्देशिका में कोई वेब असेंबली प्रोसेसर मॉड्यूल नहीं मिला, और उस सूची को पूरी तरह से नहीं पढ़ा गया था। तृतीय पक्ष के गिड्रा-वॉसम प्लगइन v2.4.0 गिड्रा 12.0 को लक्षित करता है। विनिर्देश स्वयं एक जीवित दस्तावेज है। W3C पृष्ठ के लिए wasm-core-213 अक्टूबर 2026 का एक उम्मीदवार सिफारिश का मसौदा है जिसका सार रिलीज 3.0 का वर्णन करता है, और संपादकों का मसौदा उसी तिथि पर है।

ECMA-335 मेटाडेटा कार्यक्रम का स्वयं का डेटाबेस है

एक .NET असेंबली एक पीई फ़ाइल है। LedgerNet.dll से शुरू होता हैMZ, तीन अनुभागों का नाम दिया गया है .text,.rsrcऔर .reloc, और मशीन घोषित 0x14cक्योंकि संकलक ने प्लेटफॉर्म-तटस्थ कोड जारी किया। वैकल्पिक हेडर, CLR रनटाइम हेडर के डेटा निर्देशिका 14 RVA पर इंगित करता है 0x2008. ECMA-335 II.25.3.3 में 72 बाइट्स को परिभाषित किया गया हैः

output
48 00 00 00   Cb 72
02 00 05 00   MajorRuntimeVersion 2, MinorRuntimeVersion 5
78 21 00 00   MetaData RVA 0x2178
84 07 00 00   MetaData size 1924
01 00 00 00   Flags: COMIMAGE_FLAGS_ILONLY
05 00 00 06   EntryPointToken 0x06000005, MethodDef row 5, which is Main

RVA पर मेटाडेटा रूट 0x2178हस्ताक्षर से शुरू होता है 42 53 4a 42, जो पढ़ता है BSJB, फिर संस्करण 1.1 और स्ट्रिंग v4.0.30319. पांच धारा हेडर निम्नलिखित हैंः#~विलय में0x6c, तो #Strings,#US,#GUIDऔर #Blob. II.24.2 कहता है कि प्रत्येक प्रकार की धारा अधिकतम एक बार होती है।#~धारा एक से शुरू होती है HeapSizesबाइट, यहाँ शून्य, तो प्रत्येक स्ट्रिंग, GUID, और ब्लेब सूचकांक दो बाइट चौड़ाई है, और एक 64-बिट Validमुखौटा जो वर्तमान तालिकाओं का नाम है। 14 बिट्स सेट कर रहे हैंः

TableIdRowsRow sizeWhat the rows say
Module0x00110the module name and its GUID
TypeRef0x01216System.Object, System.Console, 19 more
TypeDef0x02414<Module>, Ledger, and two compiler helpers
Field0x0426Labels and a static array initialiser
MethodDef0x06614the five methods and .cctor
Param0x0856before, after, score, values, score
MemberRef0x0a16612 attribute constructors and the 4 methods that Main calls
CustomAttribute0x0c126attributes the compiler and the SDK add
StandAloneSig0x1132the three local variable signatures
Assembly, AssemblyRef, ClassLayout, FieldRva, NestedClass1, 2, 1, 1, 1identity, references, layout

एक पंक्ति आकार कहीं भी संग्रहीत नहीं किया जाता है। II.22 प्रत्येक स्तंभ को एक प्रकार देता है, और II.24.2.6 आकार नियम देता है। एक ढेर सूचकांक दो या चार बाइट्स द्वारा HeapSizes. एक साधारण तालिका सूचकांक दो बाइट्स है जबकि उस तालिका में 65536 से कम पंक्तियां हैं। एक कोडित सूचकांक जो b टैग बिट्स के साथ n तालिकाओं में इंगित कर सकता है, दो बाइट्स है जबकि उन प्रत्येक तालिकाओं में 2^(16-बी) से कम पंक्तियां हैं। CliAssemblyइन नियमों से 14 पंक्तियों के आकार की गणना की जाती है और पंक्तियों की गिनती होती है। सिस्टम. रिफ्लेक्शन. फिक्स्चर में मेटाडेटा डंप समान आकार और समान तालिका ऑफसेट रिपोर्ट करता है, जो कि परीक्षण अंकगणित साबित करने के लिए है।

III.1.9 टोकन को परिभाषित करता हैः उच्च बाइट तालिका है, निम्न तीन बाइट 1 आधारित पंक्ति हैं। 0x06000002है MethodDefपंक्ति 2। उस पंक्ति में RVA है 0x2060, नाम Grade, और एक हस्ताक्षर ब्लाब 00 01 08 08: डिफ़ॉल्ट कॉल कॉन्फ़िगरेशन, एक पैरामीटर, रिटर्न int32, पैरामीटर int32. . यह है .ParamList की पंक्ति 3 पर अंकParam, जिसका नाम है score. पैराम टेबल है कि क्यों ILSpy प्रिंट कर सकते हैंGrade(int score)एक striped रिलीज निर्माण से।0x2060विधि शरीर एक वसा सिर के साथ शुरू होता हैः

output
13 30         flags 0x13: fat, init locals; size 3 dwords
02 00         MaxStack 2
2d 00 00 00   CodeSize 45
01 00 00 11   LocalVarSigTok 0x11000001

StandAloneSigपंक्ति 1 संभालती है 07 01 08LOCAL_SIG, एक स्थानीय, int32. स्थानीय एक प्रकार है और कोई नाम नहीं है. ECMA-335 विभाजन V के डिबग इंटरचेंज प्रारूप में स्थानीय नाम रखता है, और .NET SDK उन्हें एक PDB में लिखता है. यह फिक्स्चर के साथ बनाया गया था DebugTypeकोई भी नहीं, इसलिए कोई तालिका और कोई फ़ाइल नाम नहीं हैbucket. .PercentChangeइसके बजाय एक छोटी सी हेडर हैः इसकी पहली बाइट 3aहै 0x0e << 2 | 2, एक 14 बाइट शरीर के साथ कोई स्थानीय और एक डिफ़ॉल्ट स्टैक 8

के 45 कोड बाइट्सGradeविभाजन III ओपकोड तालिका के साथ डिकोड करें। switchहै opcode 0x45इसके बाद एक u32गिनती और इतने सारे int32तालिका के बाद निर्देश के संबंध में लक्ष्यः

output
IL_0000: 02           ldarg.0
IL_0001: 1f 0a        ldc.i4.s 10
IL_0003: 5b           div
IL_0004: 0a           stloc.0
IL_0005: 06           ldloc.0
IL_0006: 1c           ldc.i4.6
IL_0007: 59           sub
IL_0008: 45 05 00 00 00 08 00 00 00 06 00 00 00 04 00 00 00 02 00 00 00 02 00 00 00
                      switch (IL_0029, IL_0027, IL_0025, IL_0023, IL_0023)
IL_0021: 2b 08        br.s IL_002b
IL_0023: 1a 2a        ldc.i4.4, ret

संकलितकर्ता से पहले 6 घटाया switch, तो मामला 6 पहला लक्ष्य है।disassemble_cil()तालिकाओं के माध्यम से टोकन प्रस्तुत करता हैः ldsfld Labels,call Grade,call System.Console::WriteLineऔर ldstr ' '#USइस सब के लिए Oracle हैMetaDump, एक छोटा सी # कार्यक्रम पर निर्मित फिक्स्चर मेंSystem.Reflection.Metadataयह प्रत्येक तालिका की पंक्ति संख्या, आकार, और ऑफसेट, प्रत्येक विधि के RVA, हस्ताक्षर, पैरामीटर नाम, और IL बाइट्स, और 226 क्षेत्रों को प्रिंट करता है System.Reflection.Emit.OpCodes. .compare_with_metadump()सभी 246 चेक पर सहमत है। रनटाइम तालिका में 218 ऑप्टकोड प्लस आठ हैं।prefixपाठ की तालिका में 219 प्रविष्टियाँ हैं क्योंकि इसमें शामिल हैं no.III.2.2 से, जो कि जारी तालिका में कभी नहीं था।

प्रारूप के लिए उपकरणः ILSpy 11.0 (MIT, 2026-08-12) macOS पर अपने Avalonia डेस्कटॉप बिल्ड के माध्यम से चलाया जाता है। ilspycmd11.1.0.9782 छपाई आईएल के साथ -ilऔर एक विधि का चयन करता है -m 0x06000002. dnSpyEx 6.6.0 dnSpy को केवल विंडोज पर जारी रखता है.ildasmRadar2 6.2.4 मेटाडेटा भी पढ़ता हैः rabin2 -Iकहते हैंarch cilऔर class PE32और isसूची Ledger.Grade(int:score):intयह इस बिल्ड में कोई सीआईएल डिमॉन्टेबलर नहीं है। यह फिक्चर .NET SDK 8.0.205 के साथ बनाया गया था क्योंकि यह बिल्ड मशीन पर स्थापित एसडीके है। .NET 10 2025-11-11 से चालू है और उसी ECMA-335 संरचनाओं को लिखता है।

प्रत्येक कंटेनर में क्या रखा जाता है

डाल gradeएक मेज में सभी पांच कंटेनरों से. प्रत्येक पंक्ति से आता हैpython3 code/main.py keeps, जो कि प्रकाश व्यवस्था पर पाठकों को चलाता हैः

ContainerBody bytesFunction nameParameter namesParameter and return typesLocal namesLine numbersControl flow
ELF object, clang -O0118grade in .symtabnonenonenonenone, no .debug_* sections5 jumps and 1 indirect jump through a relocation table
CPython 3.14 pyc96co_qualnamescorenonebucketco_linetable, first line 104 compare and POP_JUMP_IF_FALSE pairs
JVM class, javac -g50constant poolscore in LocalVariableTable(I)Inone beyond the parameterLineNumberTable, 6 rows1 tableswitch
WebAssembly63Export sectiononly with a name section(i32) -> i32only with a name sectionnone6 nested blocks, 1 br_table, 4 br
.NET assembly45MethodDefscore in Paramstatic int32(int32)none, types only in StandAloneSignone without a PDB1 switch, 1 br.s

तालिका में आप देखेंगे कि decompileer के परिणामों की व्याख्या की है. पाठ 34 तुलना int total(const int *, int)के साथ int total(long param_1, uint param_2)कि गिड्रा ने मूल कोड से निष्कर्ष निकाला, क्योंकि मूल कोड इन स्तंभों में से कोई भी नहीं रखता है। एक pyc हर नाम और कोई प्रकार रखता है, और इसकी नियंत्रण प्रवाह उन कूद है जिनका आकार हर रिलीज में बदलता है, इसलिए पायथन डिसीपिलर प्रति संस्करण तोड़ते हैं और मुफ्त में नाम पुनर्प्राप्त करते हैं। एक वर्ग फ़ाइल प्रकार और सत्यापित स्टैक रखता है, नाम रखता है जब-gहै, और व्यक्त करता है switchएक वासम मॉड्यूल संरचना को निर्माण द्वारा बनाए रखता है, इसलिए wasm2watएक .NET असेंबली सबसे पूर्ण विवरण रखता है, क्योंकि मेटाडेटा तालिकाएं मानदंडात्मक हैं, और अभी भी स्थानीय के नाम के लिए एक पीडीबी की आवश्यकता होती है।

तालिका आपको बताती है कि डिकोम्पाइलर को किस चीज के साथ काम करना था, और इसके कौन से आउटपुट संग्रहीत तथ्य को कॉपी करते हैं और कौन सा निष्कर्ष निकालता है। ILSpy आउटपुट में एक पैरामीटर नाम एक प्रतिलिपि है। एक ही आउटपुट में एक स्थानीय नाम एक निष्कर्ष है जब तक कि एक PDB मौजूद नहीं था। पाठ 35 प्रत्येक दावे के प्राधिकरण के रूप में उस अंतर को रिकॉर्ड करता है।

इसे बनाओ

डेमो चलाएँः

bash
cd phases/13-tools-and-protocols/43-bytecode-and-managed-formats
python3 code/main.py

आउटपुट एक JSON रिपोर्ट है. प्रत्येक pyc के लिए यह दोनों हेडर, फ़ाइल और gradeआकार, निर्देश गिनती और कैप्चर सूची से opcode नाम, और चल रहे अनुवादक इसे पढ़ सकते हैं कि नहीं. प्रत्येक वर्ग निर्माण के लिए यह संस्करण, आकार, डिबग तालिका गिनती, और देता है javapप्रत्येक वासम निर्माण के लिए यह खंड, प्रकार, कार्य, नाम-खंड सामग्री और wasm-objdumpअनुबंध. यह विधानसभा के लिए सीएलआई हेडर, धाराओं, तालिका पंक्तियों की गिनती, तरीकों और सिस्टम.रिफ्लेक्शन.मेटाडेटा समझौते को देता है। यह तालिका और व्याख्याकों की सूची के साथ समाप्त होता है जो कि PATH. .

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

  1. Readerकर्सर और पूर्णांक चौड़ाई रखता है। uleb()और sleb()वे LEB128 रीडर है कि Wasm और .NET ब्लेब ढेर की जरूरत है.
  2. read_pyc_header(),Unmarshallerऔर PycFileएक पीसी पढ़ें। parse_dis_text()कैदियों को पढ़ता है disसूचीबद्धता ताकि क्रॉस-वेरिएशन तुलना के लिए परीक्षण के समय चार व्याख्याताओं की आवश्यकता न हो।
  3. ClassFileवर्ग फ़ाइल पढ़ता है और disassemble_jvm()इसका कोड डिक्रिप्ट करता है।parse_javap_code()और compare_with_javap()वे Oracle चेक हैं।
  4. WasmModuleखंडों को पढ़ता है और disassemble_wasm()एक अभिव्यक्ति को उसकी गहराई से डिक्रिप्ट करता है।compare_with_wasm_objdump()यह ओरेकल चेक है।
  5. CliAssemblyपीई, सीएलआई हेडर, मेटाडेटा रूट, स्ट्रीम और तालिकाओं पर चलता है। TABLE_SCHEMASऔर CODED_INDEXESII.22 और II.24.2.6 डेटा के रूप में हैं। disassemble_cil()एक शरीर को डिक्रिप्ट करता है और compare_with_metadump()जाँचें.
  6. NativeObjectकार्य प्रतीकों को सूचीबद्ध करने के लिए पर्याप्त ELF पढ़ता है और पाठ 33 सूचीबद्ध करना अपने पाठ के रूप में लेता है। what_each_keeps()और figure_data()तुलना का निर्माण करें।

पांच और आदेश हैं।python3 code/main.py pyc FILE,class FILE,wasm FILEऔर dll FILEआप उन्हें दिए गए फ़ाइल में संरचना और प्रत्येक फ़ंक्शन की सूची प्रिंट करें। python3 code/main.py compareसंकलित करता है ledger.pyप्रत्येक अनुवादक के साथ PATHऔर जो कुछ भी लिखा है उसे प्रिंट करता है।

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

अपने द्वारा बनाए गए कंटेनर पर इस क्रम में पाठकों का उपयोग करें।

  1. पहले बाइट्स पढ़ें और प्रारूप का नाम. दो बाइट्स फिर 0d 0aएक पीसी है, ca fe ba beकक्षा फ़ाइल, 00 61 73 6dएक मॉड्यूल, 4d 5aडेटा निर्देशिका 14 के साथ एक विधानसभा सेट करें।
  2. हेडर पढ़ें और उस उत्पादक संस्करण को लिखें जिसका नाम है। एक pyc के लिए जो जादू शब्द है, एक वर्ग फ़ाइल के लिए मुख्य संस्करण, एक विधानसभा के लिए रनटाइम और मेटाडेटा संस्करण स्ट्रिंग।
  3. आप इसे चलाने से पहले उस संस्करण के साथ चलाने की योजना बना रहे प्रत्येक डिकोम्पाइलर की जांच करें। छत और उपकरण इसे दस्तावेज कहां रिकॉर्ड करें।
  4. एक ही फ़ाइल पर रीडर और प्रारूप के अपने उपकरण को चलाएं और उन्हें पंक्ति-दर-पंक्ति तुलना करें। एक असंगतता रीडर में बग या उपकरण में परिवर्तन है, और सूची सबूत होने से पहले किसी को भी समझा जाना चाहिए।
  5. आपके द्वारा पसंद किए जाने वाले फ़ंक्शन के लिए रखती है तालिका भरें, प्रत्येक तथ्य को याद रखें या खो दें और तालिका, विशेषता या अनुभाग का नाम दें जहां से यह आया है।
  6. केवल उसके बाद डिकोम्पाइलर आउटपुट पढ़ें, प्रत्येक नाम को चिह्नित करें और इसे एक संग्रहीत तथ्य या निष्कर्ष के रूप में टाइप करें।

कंटेनरों के साथ ओरेकल पाठ फ़ाइलों को रखें। जब एक अनुवादक, जेडीके, एसडीके, या wabt संस्करण बदलता है, पुनर्निर्माण के साथ build_fixtures.shऔर फिर से पकड़, क्योंकि एक बदल सूची एक बदल गया फिटिंग है।

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

लैब एः हेडर पढ़ें, फिर कोड ऑब्जेक्ट

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

bash
cd phases/13-tools-and-protocols/43-bytecode-and-managed-formats/code
python3 -q

दौड़ें:

python
from main import *
pyc = load_pyc("ledger.cpython-311.pyc")
pyc.header.to_dict()
pyc.module.names
pyc.functions()["grade"].varnames
len(pyc.functions()["grade"].code)

पहले कॉल से पहले जादुई शब्द लिखें और फिर लोड करेंledger.cpython-314.pycऔर दोनों की तुलना करोcodeलम्बाई. फिर कोशिश करो import marshal; marshal.loads(pyc.data[16:])अपने अनुवादक के तहत 3.11 फ़ाइल पर और त्रुटि पढ़ें।

लैब बी: निरंतर पूल श्रृंखला

python
cls = load_class("Ledger-g.class")
cls.constant(13)
cls.constant(14)
cls.describe_constant(13)
[row["text"] for row in jvm_listing(cls, "grade")]

अनुसरण करें#13#8और #14, फिर Utf8कॉल करने से पहले हाथ से प्रविष्टियाँdescribe_constant. . फिर लोड .Ledger-gnone.classऔर कॉलcls.method("grade").attribute_names()दोनों पर।Codeसरणी एक ही है, गुणों नहीं हैं.

लैब सी: गहराई और लेबल

python
module = load_wasm("ledger.wasm")
[(row["depth"], row["text"]) for row in wasm_listing(module, "grade")]
module.function_name(2)
load_wasm("ledger-names.wasm").names["locals"][2]

br_tableपंक्ति और गहराई पढ़ें.endइसके बाद पंक्तियों और प्रत्येक तालिका में एक लेबल संख्या के साथ मेल खाता है। फिर खोलें ledger.watऔर block $sixउस लेबल 3 नामों.

लैब डीः टोकन से बाइट्स तक

python
asm = load_assembly("LedgerNet.dll")
asm.method("Grade")
body = asm.method_body(asm.method("Grade")["RVA"])
body.fat, body.max_stack, body.code_size, hex(body.local_signature_token)
asm.token_text(0x11000001)
[row["text"] for row in cil_listing(asm, "GradeLabel")]

आरवीए के फ़ाइल ऑफसेट की गणना करें 0x2060.textअनुभाग के शीर्षक को हाथ से और तुलना करें asm.rva_to_offset(0x2060). . तो ऊपर देखो .asm.row(0x08, 3)और पता लगाएँ कि नाम कहाँ है scoreजीवन।

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

तुलना में पांचवीं स्रोत भाषा या तालिका में छठी तथ्य जोड़ें।

आवश्यकताएँः

  • एक भाषा में एक लूप और एक स्थानीय चर के साथ एक फ़ंक्शन लिखें जिसका संकलक आपके पास है, उदाहरण के लिए Kotlin एक वर्ग फ़ाइल या Rust एक Wasm मॉड्यूल में। आउटपुट और ओरेकल सूची को सटीक कमांड के साथ प्रतिबद्ध करें build_fixtures.sh. .
  • प्रत्येक निर्देश पर संबंधित पाठक को अध्यापक के साथ सहमत करें। केवल तब अपकोड जोड़ें जब डिवाइस को उनकी आवश्यकता हो।
  • विस्तार what_each_keeps()नए कंटेनर के साथ, और प्रत्येक कंटेनर के लिए एक और तथ्य के साथः चाहे शरीर एक अपवाद तालिका ले जाता है या tryक्षेत्र।
  • में नया कंटेनर जोड़ेंfigure_data()और पुनरुत् थानsite/figures-re-43.js. .
  • एक परीक्षा लिखें जो असफल हो जब कोई पाठक उस तालिका, विशेषता या खंड का नाम दिए बिना एक तथ्य को बनाए रखा गया है।

सफलता का अर्थ हैpython3 code/main.py keepsप्रत्येक सेल के लिए सबूत के साथ नई पंक्ति दिखाता है, और हर ओरेकल तुलना अभी भी सहमत है।

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

इस सबक में शामिल है outputs/skill-bytecode-and-managed-formats.md. इसका उपयोग एक बाइटकोड कंटेनर को हेडर रिपोर्ट में बदलने के लिए करें, एक फ़ंक्शन की एक चेक की गई सूची और एक तथ्यों की तालिका जो प्रत्येक नाम, प्रकार और संरचना को संग्रहीत या खोए हुए के रूप में चिह्नित करती है। इसके लिए प्रारूप के अपने उपकरण को एक ओरेकल के रूप में, किसी भी डिकोम्पाइलर से पहले एक संस्करण की जांच और प्रत्येक खोए हुए तथ्य के रहने के स्थान का विवरण की आवश्यकता होती है।

जाँचें

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

bash
cd phases/13-tools-and-protocols/43-bytecode-and-managed-formats
python3 code/main.py
python3 -m unittest discover -s code/tests -v

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

  • चार pyc हेडर पर जादुई शब्द 3495, 3531, 3571, और 3627 हैं, ध्वज 3 और एक 8-बाइट हैश, और टाइमस्टैम्प फ़ाइलें ध्वज 0, mtime 1791975565 और आकार 497 हैं
  • 3.11 और बाद के लिए प्रत्येक जादुई शब्द सीमा में बैठता है 2900 + 50nनियम अपनी रिहाई देता है
  • unmarshaler वही नाम, स्थिर, कोड बाइट्स, चर नाम, और पंक्ति तालिका वापस करता है marshal.loads()फ़ाइल पर चल रही अनुवादक ने लिखा
  • सभी चार फ़ाइलें मॉड्यूल के नाम रखती हैं,('score', 'bucket')के लिएgrade, पहली पंक्ति 10 और ledger.pyफ़ाइल नाम के रूप में
  • grade.co_codeचार संस्करणों में 80, 62, 70 और 96 बाइट है और कैप्चर सूची में 31, 26, 26 और 35 निर्देश हैं
  • 3.11 सूची में POP_JUMP_FORWARD_IF_FALSE, 3.12 और 3.13 में RETURN_CONST, और 3.14 में LOAD_SMALL_INT,LOAD_FAST_BORROWऔर NOT_TAKEN
  • 3.14 -C -Oसूची में 13 कैश प्रविष्टियाँ दिखाई देती हैं grade, उनमें से पांच बाद में BINARY_OP, और अनुकूलन सूची दिखाता है COMPARE_OP_INT
  • बिना हेडर के0d 0a, एक छोटा सिर, और एक शरीर है कि एक कोड वस्तु उठाने नहीं है FormatError
  • एक निर्देश सूची केवल चल रहे अनुवादक द्वारा लिखे गए pyc के लिए मौजूद है और कैप्चर किए गए से मेल खाती है disआउटपुट
  • वर्ग फ़ाइलों में प्रमुख 65 या 69, आकार 1581, 1832, 1404, और 1581 हैं, और निरंतर पूल गिनती 82, 94, 79, और 82 हैं
  • निरंतर #13निर्णय लेता है Method Ledger.grade:(I)Iऔर #47String F
  • JVM डिसेम्ब्लर सहमत है javap -c -pचारों निर्माणों में 108 में से 108 निर्देशों पर
  • tableswitchpc 4 पर 36 बाइट्स है, कम 6, उच्च 10, डिफ़ॉल्ट 48, और लक्ष्य 46, 44, 42, 40, 40
  • तीन डिबग स्तर विशेषता गणना बदलते हैं और 50 कोड बाइट्स छोड़ gradeसमान
  • ifne,if_icmpgeऔर gotoलक्ष्य शाखा ओपकोड के सापेक्ष हैं
  • एक गलत जादू, पिछड़ते बाइट्स, और एक अनिश्चित ओप कोड वृद्धि FormatError
  • सात वासम अनुभागों में उपयोगिता भार का आदान-प्रदान है wasm-objdump -hछापें, और नामों का निर्माण एक जोड़ता है nameकस्टम अनुभाग 293 से 425 तक
  • प्रकार, env.logआयात, पांच निर्यात, और 1024 डिकोड पर डेटा खंड के रूप में लिखा गया है ledger.wat
  • वासम विघटनकर्ता सहमत है wasm-objdump -dदोनों निर्माणों में 77 में से 77 निर्देशों पर
  • grade6 घोंसले हुए ब्लॉक है, एक br_tableलेबल के साथ 4 4 4 4 4 4 3 2 1 0 0और डिफ़ॉल्ट 4 गहराई 6 पर, और एक i32स्थानीय
  • कार्य नामों का नाम अनुभाग के बिना निर्यात से आता है और केवल इसके साथ स्थानीय नाम
  • LEB128 e4 00100 है।7fहै -1, 80 08है 1024, और ब्लॉक प्रकार के रूप में प्रस्तुत wasm-objdump
  • एक गलत प्रस्तावना, संस्करण 2, और एक अज्ञात opcode वृद्धि FormatError
  • मशीन के साथ PE32 है।0x14c, RVA में CLI हेडर 0x2008, रनटाइम 2.5 ,ILONLY, और प्रवेश बिंदु 0x06000005
  • मेटाडेटा संस्करण v4.0.30319, पांच धाराओं मौजूद हैं, और 14 तालिकाओं में पंक्तियों की गिनती और पंक्तियों के आकार Oracle रिपोर्ट
  • .NET पाठक 246 चेक में से 246 पर सिस्टम.रिफ्लेक्शन.मेटाडेटा से सहमत है
  • Gradeपैरामीटर है score, हस्ताक्षर static int32(int32), एक मोटी हेडर के साथ MaxStack2 और 45 कोड बाइट्स, और एक int32नाम के बिना स्थानीय
  • सीआईएल switchलक्ष्य, br.s,ldsfld,callऔर ldstrओपेरांड तालिकाओं और ढेरों के माध्यम से हल करते हैं
  • सीआईएल ऑपकोड तालिका प्रत्येक रनटाइम ऑपकोड को कवर करती है और केवल जोड़ती है no.
  • रखती तालिका में पैरामीटर नाम की रिपोर्ट चार कंटेनरों में और कोई भी मूल कोड के लिए नहीं है, और तीन में प्रकार
  • डेमो में प्रत्येक ओरेकल लाइन n के n पढ़ता है
  • इंटरैक्टिव आंकड़ा एक ही डेटा को शामिल करता है figure_data()उत्पादन करता है

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

FailureWhat the weak tool reportsWhat the analysis must prove
Decompiler older than the interpreterUnsupported opcode, output marked incomplete, or a claim of obfuscationThe magic word, the release it names, and the tool's documented ceiling
pyc read with the wrong interpretermarshal.loads raises or returns garbageOur unmarshaller reads names, constants, and sizes from any 3.9 to 3.15 file, and instructions come from the matching dis
Specialised opcodes mistaken for the file's contentCOMPARE_OP_INT in a listingA pyc holds the unspecialised form, specialisation happens in memory after warm-up
Local names reported for a default javac buildvar1, var2 presented as source namesLocalVariableTable is present only with -g, the 50 code bytes are identical either way
Branch target off by the instruction lengthA JVM listing whose jumps land mid-instructionOffsets relative to the branch opcode, checked against javap
Switch padding skippedA tableswitch with a wrong default and shifted casesZero to three padding bytes to a 4-aligned pc, 36 bytes for five cases
Wasm names assumed stripped"no symbols"Exports name every exported function, locals need the name section, wasm-strip removes only that section
Three tools, three spellingsget_local versus local.get, a function at 0x8b versus 0x8eSame bytes, and the listing that the comparison was captured with
Table row size guessedEvery row after the first table misreadRow sizes from HeapSizes, row counts, and coded index widths, equal to the oracle's
Local names expected in a release assemblyV_0 presented as the source nameLocals have types in StandAloneSig and names only in a PDB that DebugType none did not write
Reader guesses an unknown opcode or type codeA plausible mnemonicFormatError with the offset, and the oracle comparison stops there
Oracle captured from another buildTests pass on stale textbuild_fixtures.sh names every tool version and writes versions.txt and sha256.txt

परिचालन नियम

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

आगे पढ़ना

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.