فراتر از کد بومی: پایتون، JVM، .NET و Bytecode WebAssembly
Type: Build
Languages: Python, TypeScript, Java, C#, WebAssembly text
Prerequisites: Phase 13 · 32 (ELF from scratch), 33 (disassembly and control flow)
Time: ~150 minutes
اهداف یادگیری
- 16-byte رو بخونيد
.pycسرنخ از PEP 552 و رمز را بدونmarshalماژول برای فایل هایی که توسط چهار نسخه مترجم نوشته شده است. - تجزیه یک فایل کلاس JVM از JVMS فصل 4: مجموعه ثابت، زمینه ها، روش ها،
Codeویژگی و جدول هایی کهjavac -gاضافه می کنه - کد های JVM را در جدا کنید
Ledger.classو اثبات ثبت نام در مقابلjavap -cبر روی چهار ساختاری از همان منبع - بخش ماژول WebAssembly را به بخش بخونید، هر بدن عملکرد را رمزگذاری کنید و نتیجه را با
wasm-objdump -d. . - از دایرکتوری داده های PE به
MethodDefردیف ها و CIL هر روش، با کتابخانه خواننده ای که ILSpy استفاده می کند بررسی می شود. - اندازه گیری، برای یک تابع در پنج ظرف، کدام نام، نوع و ساختار کنترل هر فرمت نگه دارد و کدام را از دست می دهد.
مشکل
تو ساختيledger.pyو پیدا شدledger.cpython-314.pycدر__pycache__از يه مامور پرسيديد که پرونده چي هست، مامور يه دستگاه تخريب کننده رو اجرا کردUnsupported opcodeو یک خط که میگه# WARNING: Decompyle incompleteمامور نتیجه گرفت که پرونده ها پوشيده شده
پرونده رو پوشيده نکرد دو بايت اولش2b 0eاین عدد CPython 3.14 می نویسد و جدول های کد آپکامپایلر در 3.13 متوقف می شوند. این ابزار قدیمی بود. عامل سر را نمی خواند، بنابراین نمی توانست تفاوت را تشخیص دهد.
درس 33 نشان داد که کد بومی چه چیزی را از دست می دهد: نام پارامتر، انواع و switchکه تبدیل به یک میز پرتاب شد. کانتینر های بایت کد کمتر از دست می دهند و هر کدام چیزی متفاوت از دست می دهند. یک pyc هر نام متغیر را نگه می دارد و هیچ نوعی ندارد. یک فایل کلاس فقط زمانی که شما درخواست کنید نوعها و نام های محلی را حفظ می کند. یک ماژول Wasm ساختار کنترل را حفظ می کند و نام ها را می گذارد مگر اینکه بخش سفارشی آنها را حمل کند. یک مجموعه .NET نام پارامتر را در یک جدول نگه می دارد و نام های محلی را به یک فایل جداگانه می گذارد. شما نمی توانید از هر یک از آنها نتیجه ی یک کمپایلر را قضاوت کنید تا زمانی که بدانید که آن ظرف با چه یادداشت هایی شروع شده است.
این درس چهار خواننده را در کتابخانه استاندارد پایتون ایجاد می کند. هر کدام کانتینر را از اولین بائتهای خود می خوانند، یک تابع را لیست می کنند و در ابزار فرمت خود در وسایل ساخت شده شما بررسی می شوند. بخش آخر می گوید:gradeازledgerدر هر پنج ظرف هم کنار هم
سرپرستی "پی سی" چهار کلمه است
PEP 552 عنوان را به عنوان چهار کلمه 32 بت تعریف می کند. اولین کلمه عدد جادویی است. دومین یک میدان بیت است. بیت 0 مجموعه به معنای فایل مبتنی بر هش است. بیت 1 مجموعه به معنای check_source: مترجم منبع را در واردات هاش می کند و مقایسه می کند. با بیت 0 پاک، کلمات سه و چهار mtime منبع و اندازه منبع هستند. با بیت 0 مجموعه، آنها یک SipHash 64 بیت از منبع را دارند.
شماره جادويي درInclude/internal/pycore_magic_number.h. قاعده آن از 3.11 این است که پایتون 3.n از 2900 + 50n شروع می شود و هر تغییر بایت کد در یک چرخه انتشار یک اضافه می کند. توکن ذخیره شده عدد 16 بیت است که از آن بعد \r\nدر این حالت، پیتون 3.15.0 در سال 2026-10-09 منتشر شد و در ماشین که این وسایل را ساخته است نصب نشده است، بنابراین شماره آن از فایل سرپرستی و نه از یک فایل در اینجا است.
چراغ ها دو فایل pyc در هر مترجم دارند.compile_pyc.pyنوشته بودpy_compile.compile(..., dfile="ledger.py")تا نام فایل ذخیره شده باشدledger.pyنه مسیر ماشین ساخت. اولین 16 بایت فایل 3.14:
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 6a0x6acf608d = 1791975565, mtime از ledger.pyوقتی پرونده ساخته شدf1 01 00 00در این فایل ها، 3 و 8 بایت ها شامل است. چهار مترجم در همه چیز در عنوان موافقند، به جز کلمه جادویی:
| 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.11بهpython3.15در PATHبرای هر یک از آنها سرنخ را چاپ می کند که خواننده ما در کنار حقایق که مترجم در مورد خود گزارش می دهد می بیند.
مارشال کدهاي موضوعي را به صورت فيلدهاي
بايت 16 از هر دستگاهe3. اینا0x80 | ord('c'): کد نوع مارشال برای یک شی کد با FLAG_REFمجموعه ای که به خواننده میگه برای بعد از این موضوع را به یاد داشته باشهrاسناد مارشال می گوید که فرمت به طور عمدی مستند نشده است و که اشیاء کد بین نسخه ها سازگار نیستند. هر دو بیانیه درست است و فرمت هنوز به اندازه کافی کوچک است تا برای خواندن باشد. Python/marshal.cکد های نوع را ذکر می کند: Nهيچکسiیک int 32 بیتsبائتهایzوZرشته های کوتاه ASCII، (و)دوتاcیک شی رمز، rکنتینر ها جای مرجع خود را قبل از بچه هایشان ذخیره می کنند، بنابراین خواننده همین کار را می کند.
w_complex_object()برای 3.11 تا 3.15 این استargcount،posonlyargcount،kwonlyargcount،stacksize،flagsبه عنوان 32 بایت اینچ، پس 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 است و هیچ تضمینی وجود ندارد که ثابت بماند.python3.1N -m dis ledger.pyبرای هر مترجم ضبط شد.
در 3.11gradeشروعش اينطوره:
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_OPدر 16 دنبالش 22 هست پس دو تا از اونها هستshow_caches=True3.12 جایگزین می شودLOAD_CONSTو اضافهRETURN_VALUEباRETURN_CONST، نام پرش رو به POP_JUMP_IF_FALSEو درمانگرهاgradeاز 80 تا 62 بايت. 3.13 چاپ برچسب ها L1بهL4به جای تعویض و دادن CLI -Cبرای مخزن و-Oبرای تعویضات 3.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بائتهاي پي سي هرگز آنها را در خود ندارد چون تخصص در حافظه اتفاق می افتد.
به همین دلیل است که decompiler ها دارای سقف نسخه هستند. uncompyle6 3.9.3 می گوید که بایت کد را از پایتون 1.0 تا 3.8 پذیرفته است. decompyle3 3.9.3 3.7 و 3.8 را می خواند. xdis 6.3.0, جداکننده نسخه های متقاطع پشت هر دو، تا 3.13 می خواند. pycdc دارای جدول های opcode تا python_3_13.cppدر فایل ساختش و در یک کد چاپ نامعلومUnsupported opcodeو نشان دهنده محصول نامکمل است. PyLingual ادعا می کند که هر نسخه منتشر شده از 3.6 و استفاده مترجم از 3.8 تا 3.15 برای بازسازی و بررسی محصول خود را. برای یک فایل 3.14، سه مورد اول رد یا شکست می یابد و تنها دو مورد آخر اعمال می شود. قبل از انتخاب یک ابزار کلمه جادویی را بخوانید.
پرونده کلاس ها یک فرهنگ لغت خود را حفظ می کند
JVMS Java SE 25، بخش 4.1 طرح را به عنوان یک ساختار می دهد: magic،minor_version،major_version،constant_pool_count, استخر ثابت ,access_flags،this_class،super_class، رابط ها ، زمینه ها ، روش ها ، ویژگی ها0xCAFEBABEیک ماشین مجازی جاوا SE 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میگه پارامتر یک استintهر روش، میدان و کلاس که کد لمس می کند چنین ورودی دارد و تایید کننده در بخش 4.10 یک فایل را که دستورالعمل آن با آنها مخالف است رد می کند.ClassFileکلاس درcode/main.pyتمام 17 تاگ ثابت را از جدول 4.4 می خواند و یک را درمان می کند LongیاDoubleبه عنوان دو نقطه. این در یک برچسب ناشناخته و باایت ها پس از ویژگی آخر افزایش می یابد.
ویژگی ها به کلاس، هر زمینه، هر روش و CodeJVMS می گوید که ماشین مجازی باید ویژگی هایی را که نمی داند نادیده بگیرد، به همین دلیل می توان بدون تغییر یک جسم روش جدول های دیبگ را اضافه یا رها کرد. راهنمای javac می گوید -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بدونش یک decompiler قسمت 0 را می بیندintو باید اسم ای اختراع کنهStackMapTableدر هر ساخت باقی می ماند چون تایید کننده به آن نیاز دارد و BootstrapMethodsویژگی باقی می ماند چونmainرشته ها رو به هم متصل مي کنهinvokedynamic. .
کدنویچ میز ها با دست
فصل 6 JVMS هر دستورالعمل را به عنوان یک بایت آپکد و آپراند که نام های آپکد را می دهد تعریف می کند. آفس های شاخه ارزش های امضا شده 16 بیت نسبت به آدرس آپکد شاخه هستند که از x86-64 متفاوت است، جایی که جابجایی نسبت به دستورالعمل بعدی است. tableswitchوlookupswitchبا صفر تا سه بايت پديده شروع ميکنن تا 32 بيت اپرندها از آدرس 4 شروع بشه
بائتهاي gradeاز pc 4 در Ledger-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 دستور توافق دارند. آزمونtest_branch_offsets_are_relative_to_the_branch_instructionچک هاifneدر pc 1 فرود در 6if_icmpgeدر 13 فرود در 33 وgotoدر 30 به عقب در 10 فرود مياد
رادار2 6.2.4 که از منبع برای این درس ها ساخته شده است، همان فایل را می خواند.rabin2 -Iگزارش هاarch java،lang java 21،linenum trueوlsyms true, که خواندن نسخه و دو جدول دیبگ است. pd 14 @ sym.Ledger.gradeچاپشtableswitchبا تيرها به پنج هدفشUnable to parse code attribute: 2در این فایل، که یک محدودیت ابزار نام خود و یک دلیل برای حفظjavapبه عنوان کلام. decompileers برای این فرمت در مقایسه با پایتون بالغ هستند. CFR 0.152 به مجوز MIT صادر شده پروکیون 0.6.0 و Vineflower 1.12.0 Apache 2.0 هستند و Vineflower یک شکنی Fernflower با پشتیبانی از جاوا 21 است. خود "فرن فلوور" در داخل مخزن جامعه "انتلج" زندگی می کنه JADX 1.5.6 فرمت Android DEX را پوشش می دهد و JD-GUI آخرین نسخه اش در سال 2019 بود. هاراند، سوتو والرو، مونپرروس و باودری هشت مورد را در سال 2020 اندازه گیری کردند. بهترین تولیدات ترکیب درست برای 84 درصد از کلاس ها و تولیدات معادل معنوی برای 78 درصد. متاداکامپلر آنها ۳۷.۶ درصد از کلاس هایی را که هیچ ابزار دیگری نمی توانست با آن ها کار کند، بازیابی کرد. انواع، نام ها و دسته های تایید شده باعث می شوند که فرمت قابل تجزیه باشد. آنها هیچ یک از decompiler کامل نمی کنند.
یک ماژول وسم یک لیست از بخش ها است
مشخصات اصلی یک ماژول را به عنوان پیشگام تعریف می کند00 61 73 6d 01 00 00 00، رشته\0asmو نسخه 1، و بعد از آن بخش ها. هر بخش یک بایت ID است، یک u32اندازه در LEB128 و محتوای آن. IDs 1 تا 13 بخش های شناخته شده هستند، هر یک در حد حداکثر یک بار و به ترتیب. ID 0 یک بخش سفارشی با نام است، اجازه می دهد در هر نقطه. همه اعداد کامل LEB128 هستند، بنابراین e4 00100 و 80 081024مست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, هر کد آپ بايتي از unreachableبهi64.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'}برای تابع 3wasm-stripدر ورق ذخیره سازی کنوانسیون ابزار دو حامل دیگر را توصیف می کند. DWARF می تواند به عنوان.debug_*بخش های سفارشی.sourceMappingURLبخش سفارشی می تواند به یک نقشه منبع اشاره کند که شماره ستون آن باایت های تعویض شده به دوگانه است.
ابزارها در طول سال 2026 حرکت کردند.wasm-decompile، و ساخت Homebrew روی این ماشین دقیقاً ۱۱ ابزار باقی مانده را دارد.print،objdumpوdemangle. نسخه_133 بينيارين ارائه ميدهwasm-disرادار2 6.2.4 ماژول رو هم ميخوادrabin2 -Iمیگهarch wasm. نمادش برايgradeشروع می شه0x8e، جایی که متری محلی شروع می شود، در حالی که wasm-objdumpبرچسب ها تابع در 0x8bدر فهرستش از يادداشت هاي قدیمی تر استفاده ميکنهget_local،set_localوbrtable 11 4 4 ...با چاپ شماره برچسب بائتهای در هر سه ابزار یکسان هستند و املاکی متفاوت است، بنابراین یک مقایسه باید نام ابزار را که با آن ضبط شده است نام دهد. تحقیقات برای این درس هیچ ماژول پردازنده WebAssembly در دایرکتوری پردازنده های Ghidra پیدا نکردند و این لیست به طور کامل خوانده نشد. افزونه Ghidra-wasm v2.4.0 طرف سوم هدف Ghidra 12.0 است. مشخصات خودش یک سند زنده است. صفحه W3C برای wasm-core-2یک طرح توصیه کاندید از 13 اکتبر 2026 است که خلاصه آن نسخه 3.0 را توصیف می کند و طرح ویرایشگر نیز همان تاریخ را دارد.
ECMA-335 متاداتا پایگاه داده برنامه است
یک مجموعه .NET یک فایل PE است.LedgerNet.dllبا شروع می شهMZ، سه بخش به اسمش داده شده.text،.rsrcو.reloc، و اعلام میکنه0x14cبه این دلیل که کامپایلر کد خنثی سیستم عامل را منتشر کرده است. دایرکتوری داده 14 از سرپرست اختیاری، سرپرست زمان اجرا CLR، به RVA اشاره دارد 0x2008ECMA-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 Mainریشه متادتا در RVA 0x2178با امضا شروع میشه42 53 4a 42، که میگهBSJB، بعد نسخه 1.1 و رشتهv4.0.30319پنج تا از سرپرستان جریان ها:#~در تعویض0x6c، پس#Strings،#US،#GUIDو#BlobII.24.2 می گوید هر نوع جریان حداکثر یک بار رخ می دهد.#~جریان با یک شروع می شودHeapSizesبايت، صفر در اینجا، پس هر رشته، GUID، و شاخص نقطه دو بايت گسترده است، و یک 64 بيتValidماسک که نام جدول های موجود را مشخص می کند. چهارده بیت تنظیم شده است:
| 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 ردیف دارد. یک شاخص کدگذاری شده که می تواند به جدول های n با بایت های برچسب اشاره کند دو بایت است در حالی که هر یک از این جدول ها کمتر از 2^(16-b) ردیف دارد. CliAssemblyاندازه 14 ردیف را از این قوانین محاسبه می کند و ردیف ها شمارش می شوند. سیستم.عكس.پرداد متادایی در وسایل گزارش می دهد اندازه های مشابه و تعویضات جدول مشابه است، که این روش آزمایش ثابت حسابداری است.
III.1.9 نشان دهنده را تعریف می کند: بائت بالا جدول است، سه بائت پایین ردیف مبتنی بر 1 است. 0x06000002.MethodDefخط 2 . این خط RVA دارد0x2060، اسمGrade، و یه خال امضا00 01 08 08: کنوانسیون تماس پیش فرض، یک پارامتر، بازگشت int32، پارامترint32. اونParamListنقاط در ردیف 3 از Param، که اسمشscore. ميز پارام براي اينه که اين جاسوسها ميتونن چاپ کننGrade(int score)از ساخت و ساز آزاد شده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 08.LOCAL_SIG، یه محلیint32. محلی دارای نوع و نام نیست. ECMA-335 نام های محلی را در قالب تغییر تغییر اشکال بخش V نگه می دارد و SDK .NET آنها را به یک PDB می نویسد. این ابزار با DebugTypeهيچکدوم، پس هيچ ميز و پرونده اي با اين اسم نيستbucket.PercentChangeدر عوض يه سرگير کوچولو داره: اولين بايتش3a.0x0e << 2 | 2، يه جسم 14 بايت بدون هيچ محلي و يک دسته پيش فرض از 8
45 بايت کد از Gradeبا جدول کد Opcode بخش III رمزگذاری شود. switchکد آپکود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.کليک .کليک براي همه اين هاMetaDump، یک برنامه کوتاه C# در چراغ های ساخته شدهSystem.Reflection.Metadataاین تعداد صف ها، اندازه و تعویض هر جدول، RVA هر روش، امضا، نام پارامتر ها و بائتهای IL و 226 میدان از System.Reflection.Emit.OpCodes.compare_with_metadump()با تمام 246 چک موافقم جدول زمان اجرا 218 کد اضافه هشتprefixجدول درس 219 مطلب دارد چون شاملno.از III.2.2 که جدول emit هرگز نداشت.
ابزار برای فرمت: ILSpy 11.0 (MIT، منتشر شده 2026-08-12) از طریق ساخت ورودی Avalonia در macOS اجرا می شود. ilspycmd11.1.0.9782 چاپ IL با -ilو روش رو به صورت نماد با -m 0x06000002. dnSpyEx 6.6.0 فقط در ویندوز ادامه داره dnSpyildasmسفینه ها به عنوان بسته های NuGet به جای داخل SDK. radare2 6.2.4 میتا داده ها را هم می خواند: rabin2 -Iمیگهarch cilوclass PE32وisلیست هاLedger.Grade(int:score):intاین ابزار با .NET SDK 8.0.205 ساخته شده است زیرا این SDK در ماشین ساخت نصب شده است. .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 |
جدول نتایج تجزیه کننده را که خواهید دید توضیح می دهد. درس 34 مقایسهint total(const int *, int)باint total(long param_1, uint param_2)که گیدرا از کد بومی نتیجه گرفت، زیرا کد بومی هیچ یک از این ستون ها را حفظ نمی کند. یک pyc هر نام و هیچ نوع را حفظ می کند، و جریان کنترل آن پریدن هایی است که شکل آنها هر نسخه تغییر می کند، بنابراین پیکپین ها در هر نسخه شکسته می شوند و نام ها را به صورت رایگان بازیابی می کنند. یک فایل کلاس انواع و دسته های تأیید شده را حفظ می کند، نام ها را حفظ می کند وقتی-gدر حال اجرا است و بیان می کندswitchیک ماژول "ویسم" ساختار را با ساخت نگه می دارد، بنابراینwasm2watیک مجموعه .NET کامل ترین توصیف را حفظ می کند، زیرا جدول های متادتا قانونی هستند و هنوز هم برای نام یک محلی نیاز به PDB دارند.
جدول به شما می گوید که decompiler با چه چیزی کار می کند و کدام از خروجی ها یک واقعیت ذخیره شده را کپی می کنند و کدام یک را نتیجه می دهند. نام پارامتر در خروجی ILSpy کپی است. نام محلی در همان خروجی یک نتیجه است مگر اینکه PDB وجود داشته باشد. درس 35 این تفاوت را به عنوان مقام هر ادعای ثبت می کند.
آن را بسازید
نمایش نمایش را اجرا کن:
cd phases/13-tools-and-protocols/43-bytecode-and-managed-formats
python3 code/main.py
npx tsx code/main.tsمحصول یک گزارش JSON است. برای هر pyc هر دو عنوان، فایل و را می دهدgradeاندازه ها، تعداد دستورالعمل ها و نام های کد های opcode از لیست گرفته شده، و اینکه آیا مترجم در حال اجرا می تواند آن را بخواند. برای هر کلاس ساخت آن را به نسخه، اندازه، شمارش جدول دیبگ، و javapبرای هر ساخت و ساز Wasm بخش ها، انواع، عملکردها، محتوای بخش نام وwasm-objdumpبرای جمع آوری، این CLI را به عنوان، جریان، شمارش ردیف جدول، روش ها و سیستم می دهد.PATH. .
بخونcode/main.pyدر این ترتیب:
Readerدر برنده و عرض عددی کامل قرار دارد.uleb()وsleb()این خواننده های LEB128 هستند که واسم و .NET نیاز دارند.read_pyc_header()،UnmarshallerوPycFileيه پي سي رو بخونparse_dis_text()از دستگیران میخوادdisلیست ها به طوری که مقایسه بین نسخه ها به چهار مترجم در زمان آزمون نیاز ندارد.ClassFileپرونده کلاس رو میخواد وdisassemble_jvm()کدش رو رمزنگاري ميکنهparse_javap_code()وcompare_with_javap().آرهکل چک ميکنهWasmModuleبخش ها رو مي خواد وdisassemble_wasm()یک عبارت را با عمق آن رمزنگاری می کند.compare_with_wasm_objdump()این چکِ آسمانییهCliAssemblyدر پی، CLI سر، metadata root، جریان ها و جدول ها راه می رود.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 که کلمه جادویی است، برای یک فایل کلاس نسخه اصلی، برای یک مجموعه رشته های نسخه اجرا و متادتا.
- قبل از اجرا کردن هر نسخه ای که می خواهید اجرا کنید را با آن نسخه مقایسه کنید. سقف و جایی که ابزار آن را مستند می کند را ثبت کنید.
- در یک فایل، خواننده و ابزار فرمت خود را اجرا کنید و آنها را ردیف به ردیف مقایسه کنید. یک عدم مطابقت یک خطا در خواننده یا تغییر در ابزار است و هر یک از آنها باید قبل از اینکه لیست به عنوان مدرک شناخته شود درک شود.
- جدول نگهدارنده ها را برای عملکرد مورد علاقه تان پر کنید. هر واقعیت را به عنوان نگه داشته یا گم شده نشان دهید و جدول، ویژگی یا بخش که از آن آمده نام دهید.
- فقط بعد از آن محصول تخلیق کننده را بخوانید. هر نام را نشان دهید و آن را به عنوان یک کپی از یک واقعیت ذخیره شده یا به عنوان یک نتیجه گیری تایپ کنید.
فایل های متن Oracle را در کانتینرها نگه دارید. هنگامی که یک مترجم، JDK، SDK یا نسخه wabt تغییر می کند، با build_fixtures.shو دوباره ضبطش کنیم، چون لیست تغییر داده شده یک قسمت تغییر داده شده است.
آزمایشگاه تعاملی
لابراتوار A: سر و بعد کدهای موردی را بخوانید
از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 زیر مترجم خود را و خطا را بخوانید.
آزمایشگاه B: زنجیره ثابت استخر
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صفات یکسان هستند، صفات یکسان نیستند.
آزمایشگاه C: عمق و برچسب ها
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 اسم
لابراتوار D: از توکن به بایت
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")]محاسبه تعویض فایل RVA 0x2060از.textسرگوشن بخش با دست و مقایسه با asm.rva_to_offset(0x2060)پس نگاه کن بالاasm.row(0x08, 3)و پیدا کن اسمش کجاستscoreزندگی می کنه
آزمایشگاه تمرین
یک زبان منبع پنجم را به مقایسه اضافه کنید، یا یک واقعیت ششم را به جدول اضافه کنید.
الزامات:
- یک تابع با یک حلقه و یک متغیر محلی را در یک زبان که شما سازنده آن را دارید، بنویسید، به عنوان مثال Kotlin به یک فایل کلاس یا Rust به یک ماژول Wasm. محصول و لیست Oracle را با دستور دقیق در
build_fixtures.sh. . - با هر دستور و دستورات اوکرال موافق باشید. فقط زمانی که دستگاه به آنها نیاز دارد، اوکرال اضافه کنید.
- طولاني
what_each_keeps()با ظرف جدید و با یک واقعیت دیگر برای هر ظرف: آیا جسم دارای یک میز استثنا یاtryمنطقه - ظرف جدید را به اضافه کنید
figure_data()و دوباره بازنشسته شدنsite/figures-re-43.js. . - یک آزمون را بنویسید که وقتی یک خواننده یک واقعیت را بدون نام دادن جدول، ویژگی یا بخش که آن را در بر دارد گزارش می دهد، شکست می خورد.
موفقیت به معنیpython3 code/main.py keepsکه نشان می دهد خط جدید با شواهد برای هر سلول و هر مقایسه Oracle هنوز هم موافق است.
درس هنرپیشه
این درس شاملoutputs/skill-bytecode-and-managed-formats.mdاز آن برای تبدیل یک کانتینر بایت کد به یک گزارش سر، یک لیست چک شده از یک تابع و یک جدول واقعیت هایی که هر نام، نوع و ساختار را به عنوان ذخیره یا گم شده نشان می دهد استفاده کنید. این نیاز به ابزار خود از فرمت به عنوان یک کلام، بررسی نسخه قبل از هر decompiler و بیانیه ای از جایی که هر واقعیت گم شده زندگی می کند.
بررسی کنید
نمایش و مجموعه تعیین کننده را اجرا کنید:
cd phases/13-tools-and-protocols/43-bytecode-and-managed-formats
python3 code/main.py
npx tsx code/main.ts
python3 -m unittest discover -s code/tests -vبررسی باید ثابت کند:
- چهار سرنخ pyc دارای کلمات جادویی 3495, 3531, 3571, و 3627, پرچم های 3, و یک هشت باایت, و فایل های تایم استیمپ پرچم های 0, mtime 1791975565, و اندازه 497
- هر کلمه جادويي براي 3.11 و بعدش در محدوده ي
2900 + 50nقانون آزاد کردن - unmarshaller همان نام ها، ثابت ها، بائتهای کد، نام متغیرها و جدول خط را به عنوان
marshal.loads()در پرونده که مترجم اجرا می کند نوشته شده است - همه چهار پرونده اسم ماژول رو نگه می دارن
('score', 'bucket')برایgrade، اولين خط 10 وledger.pyبه عنوان نام فایل grade.co_codeاین هشتاد، ۶۲، ۷۰ و ۹۶ بایت در چهار نسخه است و لیست های ضبط شده دارای دستورالعمل ۳۱، ۲۶، ۲۶ و ۳۵ هستند- فهرست 3.11 داره
POP_JUMP_FORWARD_IF_FALSE، 3.12 و 3.13 دارندRETURN_CONST، و 3.14 دارهLOAD_SMALL_INT،LOAD_FAST_BORROWوNOT_TAKEN - ۳.۱۴
-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و#47بهString F - دستگاه جداسازی JVM موافق است
javap -c -pدر 108 از 108 دستورالعمل در هر چهار ساخت tableswitchدر pc 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 و 1i32محلی- نام های عملکردی از صادرات بدون بخش نام و نام های محلی فقط با آن می آیند
- LEB128
e4 00100 است7f-1 است80 081024 است و نوع بلوک مثلwasm-objdump - یک پیش فرض اشتباه، نسخه 2 و افزایش کد غیرقابل شناخت
FormatError - مجموعه PE32 با ماشین
0x14c, CLI سر در RVA0x2008, زمان اجرا 2.5 ,ILONLY، و نقطه ورود0x06000005 - نسخه متاداتا اینه
v4.0.30319، پنج جریان وجود دارد و 14 جدول تعداد صف ها و اندازه صف ها را گزارش می دهد - خواننده .NET با سیستم.آزمایش.متاداتا در 246 از 246 چک موافق است
Gradeدارای پارامتر استscore، امضاstatic int32(int32)، يه سرپرستي چاق باMaxStack2 و 45 بايت کد و 1int32محلی بدون نام- CIL
switchهدف هاbr.s،ldsfld،callوldstrاپراندها از طریق جدول ها و توده ها حل می شوند - جدول کد های CIL هر کد های زمان اجرا را پوشش می دهد و فقط اضافه می کند
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.