मूल कोड से परेः पायथन, जेवीएम, .नेट, और वेब असेंबली बायकोड
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 बाइट्सः
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 और आठ हैश बाइट्स हैं। चार अनुवादक हेडर में जादू शब्द को छोड़कर सभी पर सहमत हैंः
| Interpreter | Magic bytes | Word | File bytes | grade.co_code bytes | grade instructions |
|---|---|---|---|---|---|
| 3.11.14 | a7 0d 0d 0a | 3495 | 1054 | 80 | 31 |
| 3.12.12 | cb 0d 0d 0a | 3531 | 937 | 62 | 26 |
| 3.13.12 | f3 0d 0d 0a | 3571 | 943 | 70 | 26 |
| 3.14.6 | 2b 0e 0d 0a | 3627 | 965 | 96 | 35 |
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 से हाथ से डिकोड करेंः
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इस तरह शुरू होता हैः
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प्रत्येक सशर्त कूद के बादः
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तीनों का निर्माण करता है कि मापः
| Build | Bytes | Constant pool count | LineNumberTable | LocalVariableTable | SourceFile | grade code bytes |
|---|---|---|---|---|---|---|
javac -g | 1832 | 94 | 7 methods | 6 methods | yes | 50 |
javac | 1581 | 82 | 7 methods | none | yes | 50 |
javac -g:none | 1404 | 79 | none | none | no | 50 |
के 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:
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 = 4036 बाइट्स, एक निर्देश, और पूरे 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समान उपभोग भार के साथ समान सातों को पाता हैः
| Section | Payload | Count | What it holds for ledger |
|---|---|---|---|
| Type | 10 to 26 | 3 | (i32) -> nil, (i32, i32) -> i32, (i32) -> i32 |
| Import | 28 to 39 | 1 | env.log with type 0 |
| Function | 41 to 46 | 4 | type index for each defined function |
| Memory | 48 to 51 | 1 | one page, no maximum |
| Export | 53 to 110 | 5 | memory and the four function names |
| Code | 113 to 271 | 4 | bodies of 23, 63, 44, and 23 bytes |
| Data | 273 to 290 | 1 | F\0D\0C\0B\0A\0 at offset 1024 |
फ़ंक्शन और कोड अनुभागों के बीच विभाजन मौजूद है ताकि ब्राउज़र पूरी फ़ाइल पहुंचने से पहले संकलन शुरू कर सके। प्रत्येक कोड प्रविष्टि एक आकार, स्थानीय घोषणाओं का वेक्टर और एक अभिव्यक्ति है।gradeस्थानीय वेक्टर है 01 7f: एक समूह का एक i32. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .bucket, उसके प्रकार के साथ और उसके नाम के बिना।
नियंत्रण प्रवाह संरचना द्वारा संरचित है। विनिर्देश कहता है शाखाओं केवल संलग्न करने के लिए लक्षित कर सकते हैं।block,loopया ifलेबल को घोंसला गहराई से सूचकांकित किया जाता है। br_tableएक ऑपरेंड के माध्यम से एक अप्रत्यक्ष शाखा का प्रदर्शन करता है जो एक लेबल सूची को सूचकांकित करता है।gradeफ़ाइल ऑफसेट पर 0xa3:
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 बाइट्स को परिभाषित किया गया हैः
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 MainRVA पर मेटाडेटा रूट 0x2178हस्ताक्षर से शुरू होता है 42 53 4a 42, जो पढ़ता है BSJB, फिर संस्करण 1.1 और स्ट्रिंग v4.0.30319. पांच धारा हेडर निम्नलिखित हैंः#~विलय में0x6c, तो #Strings,#US,#GUIDऔर #Blob. II.24.2 कहता है कि प्रत्येक प्रकार की धारा अधिकतम एक बार होती है।#~धारा एक से शुरू होती है HeapSizesबाइट, यहाँ शून्य, तो प्रत्येक स्ट्रिंग, GUID, और ब्लेब सूचकांक दो बाइट चौड़ाई है, और एक 64-बिट Validमुखौटा जो वर्तमान तालिकाओं का नाम है। 14 बिट्स सेट कर रहे हैंः
| Table | Id | Rows | Row size | What the rows say |
|---|---|---|---|---|
| Module | 0x00 | 1 | 10 | the module name and its GUID |
| TypeRef | 0x01 | 21 | 6 | System.Object, System.Console, 19 more |
| TypeDef | 0x02 | 4 | 14 | <Module>, Ledger, and two compiler helpers |
| Field | 0x04 | 2 | 6 | Labels and a static array initialiser |
| MethodDef | 0x06 | 6 | 14 | the five methods and .cctor |
| Param | 0x08 | 5 | 6 | before, after, score, values, score |
| MemberRef | 0x0a | 16 | 6 | 12 attribute constructors and the 4 methods that Main calls |
| CustomAttribute | 0x0c | 12 | 6 | attributes the compiler and the SDK add |
| StandAloneSig | 0x11 | 3 | 2 | the three local variable signatures |
| Assembly, AssemblyRef, ClassLayout, FieldRva, NestedClass | 1, 2, 1, 1, 1 | identity, 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विधि शरीर एक वसा सिर के साथ शुरू होता हैः
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 0x11000001StandAloneSigपंक्ति 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तालिका के बाद निर्देश के संबंध में लक्ष्यः
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, जो कि प्रकाश व्यवस्था पर पाठकों को चलाता हैः
| Container | Body bytes | Function name | Parameter names | Parameter and return types | Local names | Line numbers | Control flow |
|---|---|---|---|---|---|---|---|
| ELF object, clang -O0 | 118 | grade in .symtab | none | none | none | none, no .debug_* sections | 5 jumps and 1 indirect jump through a relocation table |
| CPython 3.14 pyc | 96 | co_qualname | score | none | bucket | co_linetable, first line 10 | 4 compare and POP_JUMP_IF_FALSE pairs |
JVM class, javac -g | 50 | constant pool | score in LocalVariableTable | (I)I | none beyond the parameter | LineNumberTable, 6 rows | 1 tableswitch |
| WebAssembly | 63 | Export section | only with a name section | (i32) -> i32 | only with a name section | none | 6 nested blocks, 1 br_table, 4 br |
| .NET assembly | 45 | MethodDef | score in Param | static int32(int32) | none, types only in StandAloneSig | none without a PDB | 1 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 प्रत्येक दावे के प्राधिकरण के रूप में उस अंतर को रिकॉर्ड करता है।
इसे बनाओ
डेमो चलाएँः
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इस क्रम मेंः
Readerकर्सर और पूर्णांक चौड़ाई रखता है।uleb()औरsleb()वे LEB128 रीडर है कि Wasm और .NET ब्लेब ढेर की जरूरत है.read_pyc_header(),UnmarshallerऔरPycFileएक पीसी पढ़ें।parse_dis_text()कैदियों को पढ़ता हैdisसूचीबद्धता ताकि क्रॉस-वेरिएशन तुलना के लिए परीक्षण के समय चार व्याख्याताओं की आवश्यकता न हो।ClassFileवर्ग फ़ाइल पढ़ता है औरdisassemble_jvm()इसका कोड डिक्रिप्ट करता है।parse_javap_code()औरcompare_with_javap()वे Oracle चेक हैं।WasmModuleखंडों को पढ़ता है औरdisassemble_wasm()एक अभिव्यक्ति को उसकी गहराई से डिक्रिप्ट करता है।compare_with_wasm_objdump()यह ओरेकल चेक है।CliAssemblyपीई, सीएलआई हेडर, मेटाडेटा रूट, स्ट्रीम और तालिकाओं पर चलता है।TABLE_SCHEMASऔरCODED_INDEXESII.22 और II.24.2.6 डेटा के रूप में हैं।disassemble_cil()एक शरीर को डिक्रिप्ट करता है औरcompare_with_metadump()जाँचें.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और जो कुछ भी लिखा है उसे प्रिंट करता है।
इसका प्रयोग करें
अपने द्वारा बनाए गए कंटेनर पर इस क्रम में पाठकों का उपयोग करें।
- पहले बाइट्स पढ़ें और प्रारूप का नाम. दो बाइट्स फिर
0d 0aएक पीसी है,ca fe ba beकक्षा फ़ाइल,00 61 73 6dएक मॉड्यूल,4d 5aडेटा निर्देशिका 14 के साथ एक विधानसभा सेट करें। - हेडर पढ़ें और उस उत्पादक संस्करण को लिखें जिसका नाम है। एक pyc के लिए जो जादू शब्द है, एक वर्ग फ़ाइल के लिए मुख्य संस्करण, एक विधानसभा के लिए रनटाइम और मेटाडेटा संस्करण स्ट्रिंग।
- आप इसे चलाने से पहले उस संस्करण के साथ चलाने की योजना बना रहे प्रत्येक डिकोम्पाइलर की जांच करें। छत और उपकरण इसे दस्तावेज कहां रिकॉर्ड करें।
- एक ही फ़ाइल पर रीडर और प्रारूप के अपने उपकरण को चलाएं और उन्हें पंक्ति-दर-पंक्ति तुलना करें। एक असंगतता रीडर में बग या उपकरण में परिवर्तन है, और सूची सबूत होने से पहले किसी को भी समझा जाना चाहिए।
- आपके द्वारा पसंद किए जाने वाले फ़ंक्शन के लिए रखती है तालिका भरें, प्रत्येक तथ्य को याद रखें या खो दें और तालिका, विशेषता या अनुभाग का नाम दें जहां से यह आया है।
- केवल उसके बाद डिकोम्पाइलर आउटपुट पढ़ें, प्रत्येक नाम को चिह्नित करें और इसे एक संग्रहीत तथ्य या निष्कर्ष के रूप में टाइप करें।
कंटेनरों के साथ ओरेकल पाठ फ़ाइलों को रखें। जब एक अनुवादक, जेडीके, एसडीके, या wabt संस्करण बदलता है, पुनर्निर्माण के साथ build_fixtures.shऔर फिर से पकड़, क्योंकि एक बदल सूची एक बदल गया फिटिंग है।
इंटरैक्टिव लैब
लैब एः हेडर पढ़ें, फिर कोड ऑब्जेक्ट
codeनिर्देशिका, खुला पायथनः
cd phases/13-tools-and-protocols/43-bytecode-and-managed-formats/code
python3 -qदौड़ें:
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 फ़ाइल पर और त्रुटि पढ़ें।
लैब बी: निरंतर पूल श्रृंखला
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सरणी एक ही है, गुणों नहीं हैं.
लैब सी: गहराई और लेबल
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 नामों.
लैब डीः टोकन से बाइट्स तक
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. इसका उपयोग एक बाइटकोड कंटेनर को हेडर रिपोर्ट में बदलने के लिए करें, एक फ़ंक्शन की एक चेक की गई सूची और एक तथ्यों की तालिका जो प्रत्येक नाम, प्रकार और संरचना को संग्रहीत या खोए हुए के रूप में चिह्नित करती है। इसके लिए प्रारूप के अपने उपकरण को एक ओरेकल के रूप में, किसी भी डिकोम्पाइलर से पहले एक संस्करण की जांच और प्रत्येक खोए हुए तथ्य के रहने के स्थान का विवरण की आवश्यकता होती है।
जाँचें
डेमो और निर्धारक सूट चलाएंः
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()उत्पादन करता है
उत्पादन विफलता मोड
| Failure | What the weak tool reports | What the analysis must prove |
|---|---|---|
| Decompiler older than the interpreter | Unsupported opcode, output marked incomplete, or a claim of obfuscation | The magic word, the release it names, and the tool's documented ceiling |
| pyc read with the wrong interpreter | marshal.loads raises or returns garbage | Our 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 content | COMPARE_OP_INT in a listing | A pyc holds the unspecialised form, specialisation happens in memory after warm-up |
| Local names reported for a default javac build | var1, var2 presented as source names | LocalVariableTable is present only with -g, the 50 code bytes are identical either way |
| Branch target off by the instruction length | A JVM listing whose jumps land mid-instruction | Offsets relative to the branch opcode, checked against javap |
| Switch padding skipped | A tableswitch with a wrong default and shifted cases | Zero 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 spellings | get_local versus local.get, a function at 0x8b versus 0x8e | Same bytes, and the listing that the comparison was captured with |
| Table row size guessed | Every row after the first table misread | Row sizes from HeapSizes, row counts, and coded index widths, equal to the oracle's |
| Local names expected in a release assembly | V_0 presented as the source name | Locals have types in StandAloneSig and names only in a PDB that DebugType none did not write |
| Reader guesses an unknown opcode or type code | A plausible mnemonic | FormatError with the offset, and the oracle comparison stops there |
| Oracle captured from another build | Tests pass on stale text | build_fixtures.sh names every tool version and writes versions.txt and sha256.txt |
परिचालन नियम
सबसे पहले हेडर पढ़ें और उस निर्माता का नाम बताइए। एक पाठक के साथ कंटेनर पढ़ें जो यह नहीं जानता कि वह क्या जानता है, और उसी फ़ाइल पर प्रारूप के अपने उपकरण के साथ इसकी सूची की जांच करें। फिर, एक डिकोम्पाइलर के आउटपुट में प्रत्येक नाम और टाइप के लिए, चाहे कंटेनर ने इसे संग्रहीत किया हो या उपकरण ने इसे निष्कर्ष निकाला हो।
आगे पढ़ना
- PEP 552: Deterministic pycs
- CPython
Include/internal/pycore_magic_number.h - Python
marshalmodule documentation - CPython
Python/marshal.c - Python 3.14
dismodule documentation - PEP 659: Specializing Adaptive Interpreter
- PEP 626: Precise line numbers for debugging and other tools
- PEP 790: Python 3.15 Release Schedule
- uncompyle6 on PyPI,decompyle3 on PyPI,xdis on PyPI,pycdc on GitHub,PyLingual on GitHub
- The Java Virtual Machine Specification, Java SE 25, Chapter 4: The class File Format
- The Java Virtual Machine Specification, Java SE 25, Chapter 6: The Java Virtual Machine Instruction Set
- javac manual, Java SE 25और javap manual
- CFR,Procyon,Vineflower,Fernflower in intellij-community,JADX
- Harrand, Soto-Valero, Monperrus, Baudry, "Java Decompiler Diversity and its Application to Meta-decompilation" (JSS 2020)
- ECMA-335, Common Language Infrastructure, 6th edition (June 2012)
- PE Format, Microsoft Learn
- System.Reflection.Metadata.Ecma335.TableIndex
- ILSpy on GitHub,ilspycmd on NuGet,dnSpyEx on GitHub
- WebAssembly Core Specification: Binary Format, Modulesऔर Values
- WebAssembly Core Specification: Custom Sections (name section)
- WebAssembly tool-conventions: Debugging
- wabt 1.0.42 release notes,wasm-tools,Binaryen,ghidra-wasm-plugin
- radare2 on GitHub, संस्करण 6.2.4 इस पाठ के लिए स्रोत से बनाया गया
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.