
مفكك بايتكود بايثون عبر الإصدارات
|buildstatus| |Pypi Installs| |Latest Version| |Supported Python Versions|
|packagestatus|
.. contents::
أداة فك ترجمة أصلية لـ Python عبر الإصدارات وأداة فك ترجمة للشظايا. خليفة decompyle و uncompyle و uncompyle2.
ألقيت محاضرة حول هذا في BlackHat Asia 2024 <https://youtu.be/H-7ZNrpsV50?si=nOaixgYHr7RbILVS>_.
يقوم uncompyle6 بترجمة البايتكود الخاص بـ Python مرة أخرى إلى كود مصدر Python مكافئ. يقبل البايتكود من إصدار Python 1.0 إلى الإصدار 3.8، على مدى أكثر من 24 عامًا من إصدارات Python. نقوم بتضمين بايتكود Python 2.5 الخاص بـ Dropbox وبعض بايتكود PyPy.
حسنًا، سأقولها: هذا البرنامج مذهل. إنه أكثر من مجرد مفكك هاكي عادي. باستخدام تقنية compiler_، يقوم البرنامج بإنشاء شجرة تحليل للبرنامج من التعليمات؛ عقد في المستويات العليا تشبه قليلاً ما قد يأتي من AST الخاص بـ Python. لذلك يمكننا حقًا تصنيف وفهم ما يحدث في أقسام بايتكود Python.
بناءً على ذلك، فإن الشيء الآخر الذي يجعل هذا مختلفًا عن مفككات بايتكود CPython الأخرى هو القدرة على فك ترجمة شظايا فقط من الكود المصدري وإعطاء معلومات الكود المصدري حول إزاحة بايتكود معينة.
أستخدم شظايا الشجرة لفك ترجمة شظايا الكود في وقت التشغيل داخل أدوات التصحيح trepan_ الخاصة بي. لهذا الغرض، يتم تسجيل إزاحات البايتكود وربطها بشظايا الكود المصدري. هذا الغرض، على الرغم من توافقه مع النية الأصلية، إلا أنه مختلف قليلاً. راجع this_ لمزيد من المعلومات.
فك ترجمة شظايا Python، عند إعطاء إزاحة تعليمة، مفيد في عرض تتبعات المكدس ويمكن تضمينه في أي برنامج يريد عرض موقع بمزيد من التفاصيل أكثر من مجرد رقم سطر في وقت التشغيل. يمكن أيضًا استخدام هذا الكود عندما لا توجد معلومات الكود المصدري ولا يوجد سوى بايتكود. مرة أخرى، تستخدم أدوات التصحيح الخاصة بي هذا.
كانت (ولا تزال) عدة فروع لـ decompyle و uncompyle و uncompyle2 و uncompyle3. يأتي الكثير منها أساسًا من نفس قاعدة الكود، و(تقريبًا؟) جميعها لم تعد نشطة الصيانة. أحدها كان جيدًا حقًا في فك ترجمة Python 1.5-2.3، وآخر جيد حقًا في Python 2.7، ولكن فقط ذلك. آخر يعالج Python 3.2 فقط؛ آخر قام بتصحيح ذلك وعالج فقط 3.3. لقد فهمت الفكرة. هذا الكود يجمع كل هذه الفروع معًا ويتقدم للأمام. هناك بعض إعادة الهيكلة والتنظيف الجادة في قاعدة الكود هذه مقارنة بتلك الفروع القديمة. حتى إعادة هيكلة تجريبية أكثر تجري في decompyle3_.
من الواضح أن هذا الأفضل في فك ترجمة Python عبر جميع إصدارات Python. وحتى عندما يكون هناك مشروع آخر يوفر فقط فك الترجمة لمجموعة فرعية من إصدارات Python، فإننا عمومًا نكون أفضل بشكل واضح لتلك أيضًا.
كيف يمكننا معرفة ذلك؟ من خلال أخذ بايتكود Python الموزع مع ذلك الإصدار من Python وفك ترجمته. من بين تلك التي تفك الترجمة بنجاح، يمكننا بعد ذلك التأكد من أن البرامج الناتجة صحيحة نحويًا عن طريق تشغيل مترجم Python لذلك الإصدار من البايتكود. أخيرًا، في الحالات التي يحتوي فيها البرنامج على اختبار لنفسه، يمكننا تشغيل الفحص على الكود المفكك.
نستخدم عمليات آلية للعثور على الأخطاء. في متتبعات المشكلات لمفككات أخرى، ستجد العديد من الأخطاء التي وجدناها على طول الطريق. القليل جدًا منها تم إصلاحه في المفككات الأخرى.
يمكن تشغيل الكود في مستودع git من Python 2.4 إلى أحدث إصدار Python، باستثناء Python 3.0 حتى 3.2. المتطوعون مرحب بهم لمعالجة هذه النواقص إذا كانت هناك رغبة في ذلك.
الطريقة التي يفعل بها ذلك، مع ذلك، هي عن طريق فصل إصدارات Python المتتالية إلى فروع git:
master Python 3.11 وما فوق (يستخدم تثبيت poetry، وعبارات Python الأحدث) python-3.6-to-3.10 Python 3.6 حتى 3.10 (يستخدم f-strings الأحدث، وعبارات أكثر حداثة، وتعليقات نوع أكثر حداثة) python-3.3-to-3.5 Python 3.3 حتى 3.5 (Python 3 عام) python-3.0-to-3.2 Python 3.0 حتى 3.2 (Python 3 المبكر؛ 3.0 كان في بعض المناطق أقرب إلى Python 2.6 منه إلى Python 2.7) python-2.4-to-2.7 Python 2.4 حتى 2.7 (Python 2 عام)
PyPy من الإصدار 2.4 فصاعدًا يعمل أيضًا.
ملفات البايتكود التي يمكنه قراءتها تم اختبارها على بايتكود Python من الإصدارات 1.4، 2.1-2.7، و 3.0-3.8 وإصدارات PyPy اللاحقة.
لإصدارات Python الحديثة (Python 3.11+)، يمكنك التثبيت من PyPI باستخدام الاسم uncompyle6::
pip install uncompyle6
لإصدارات Python قبل 3.11، لا تقم بالتثبيت باستخدام PyPI، بل قم بالتثبيت باستخدام ملف في قسم إصدارات GitHub. كان Python الأقدم يستخدم easy_install <https://python101.pythonlibrary.org/chapter29_pip.html#using-easy-install>_. لكن هذا لم يعد مدعومًا على PyPi أو إصدارات Python الأحدث. والعكس صحيح، poetry ولا pip، (الطرق الأحدث) غير مدعومة على إصدارات Python الأقدم.
إذا كان إصدار Python الذي تقوم بتشغيل uncompyle6 عليه بين Python 2.4 حتى 2.7، استخدم tarball باسم uncompyle6_24-x.y.z.tar.gz.
إذا كان إصدار Python الذي تقوم بتشغيل uncompyle6 عليه بين Python 3.0 حتى 3.2، استخدم tarball باسم uncompyle6_30-x.y.z.tar.gz.
إذا كان إصدار Python الذي تقوم بتشغيل uncompyle6 عليه بين Python 3.3 حتى 3.5، استخدم tarball باسم uncompyle6_33-x.y.z.tar.gz.
إذا كان إصدار Python الذي تقوم بتشغيل uncompyle6 عليه بين Python 3.6 حتى 3.11، استخدم tarball باسم uncompyle6_36-x.y.z.tar.gz.
إذا كان إصدار Python الذي تقوم بتشغيل uncompyle6 عليه هو 3.11 أو أحدث، استخدم tarball باسم uncompyle6-x.y.z.tar.gz.
يمكنك أيضًا تجربة eggs أو wheels التي لها نفس تعيين الإصدار، على سبيل المثال، uncompyle6-x.y.z-py39-none-any.whl لتثبيت Python 3.9. *ومع ذلك، لاحظ أن الإصدار بدون التعيين يعني Python 3.11 أو أعظم.
وبالمثل، يعمل tarball بدون _xx فقط من Python 3.11 أو أعظم.
المنطق وراء استخدام فروع Git +++++++++++++++++++++++++++++++
من المستحيل حاليًا (إن لم يكن غير عملي) أن يكون لديك كود مصدر Python واحد بهذا التعقيد وبهذه الميزات يمكن تشغيله على كل من Python 2.7 و Python 3.13+. اللغات تباعدت كثيرًا، والتعبئة مختلفة تمامًا. في الواقع، ممارسة التعبئة لـ Python 3.11+ غير متوافقة مع Python 2.7 (وما قبلها حتى Python 2.4)، والتي كانت تفضل "easy_install".
التثبيت من النص المصدر +++++++++++++++++++++++
للتثبيت من الكود المصدري، تأكد من أن لديك فرع Git الصحيح. راجع قسم المتطلبات لأسماء فروع Git.
بعد تعيين الفرع الصحيح::
$ pip install -e . # إعداد للتشغيل من شجرة المصدر
يتم أيضًا توفير GNU Makefile، لذا :code:make install (ربما كجذر أو sudo) سيقوم بالخطوات أعلاه.
::
make check
تمت إضافة ملف make من GNU لتسهيل إعداد وتشغيل الأمر الصحيح، وتشغيل الاختبارات من الأسرع إلى الأبطأ.
إذا كان لديك remake_ مثبتًا، يمكنك رؤية قائمة جميع المهام بما في ذلك الاختبارات عبر :code:remake --tasks
تشغيل
::
$ uncompyle6 compiled-python-file-pyc-or-pyo
لمساعدة الاستخدام:
::
$ uncompyle6 -h
في الإصدارات الأقدم من Python، كان من الممكن التحقق من البايتكود عن طريق فك ترجمته ثم تجميعه باستخدام مترجم Python لذلك الإصدار من البايتكود. بعد القيام بذلك، يمكن مقارنة البايتكود الناتج مع البايتكود الأصلي. ومع ذلك، مع تحسن توليد الكود في Python، لم يعد هذا ممكنًا.
إذا كنت تريد التحقق من صحة بناء الجملة لعملية فك الترجمة، أضف الخيار :code:--syntax-verify. ولكن نظرًا لتغير بناء جملة Python. يجب عليك استخدام هذا الخيار إذا كان البايتكود هو البايتكود الصحيح لمترجم Python الذي سيتحقق من بناء الجملة.
يمكنك أيضًا مقارنة النتائج مع إصدار آخر من uncompyle6 حيث توجد أحيانًا تراجعات في فك ترجمة بايتكود معين، مع تحسن الجودة الإجمالية.
بالنسبة لـ Python 3.7 و 3.8، الكود في decompyle3_ أفضل بشكل عام.
أو جرب مفكك Python آخر مثل uncompyle2_ أو unpyc37_ أو pycdc_. نظرًا لأن الأخيرين يعملان بشكل مختلف، فإن الأخطاء هنا غالبًا لا تكون موجودة هناك، والعكس صحيح.
هناك فئة مثيرة للاهتمام من هذه البرامج متاحة بسهولة لتقديم تحقق أقوى: تلك البرامج التي، عند تشغيلها، تختبر نفسها. تتضمن مجموعتنا الاختبارية هذه.
وتأتي Python مع مجموعة أخرى من البرامج مثل هذا: مجموعة اختباراتها للمكتبة القياسية. لدينا بعض الكود في :code:test/stdlib لتسهيل هذا النوع من الفحص أيضًا.
أكبر مشكلة معروفة وقابلة للإصلاح (ولكنها صعبة) تتعلق بمعالجة تدفق التحكم. (Python لديها على الأرجح أكثر مجموعة متنوعة وغريبة من العبارات المركبة التي رأيتها على الإطلاق؛ هناك عبارات "else" على الحلقات وكتل try التي أشك في أن العديد من المبرمجين لا يعرفون عنها).
جميع مفككات Python التي نظرت إليها لديها مشاكل في فك ترجمة تدفق التحكم في Python. في بعض الحالات، يمكننا اكتشاف فك ترجمة خاطئ والإبلاغ عن ذلك.
دعم Python جيد جدًا لـ Python 2
على الطرف الأدنى من إصدارات Python، يبدو فك الترجمة جيدًا جدًا، على الرغم من أنه ليس لدينا أي اختبارات تلقائية معمول بها لاختبارات Python الموزعة. أيضًا، ليس لدينا مترجم Python للإصدارات 1.6 و 2.0.
في سلسلة Python 3، يكون دعم Python أقوى حول 3.4 أو 3.3 ويقل كلما ابتعدت عن هذه الإصدارات. Python 3.0 غريب من حيث أنه، في بعض النواحي، يشبه 2.6 أكثر مما يشبه 3.1 أو 2.7. Python 3.6 يغير الأمور بشكل جذري باستخدام رموز الكلمات بدلاً من رموز البايت. نتيجة لذلك، تم تقليل حقل إزاحة القفز في وسيطة تعليمة القفز. هذا يجعل تعليمات :code:EXTENDED_ARG الآن أكثر انتشارًا في تعليمات القفز؛ في السابق كانت نادرة. ربما للتعويض عن تعليمات :code:EXTENDED_ARG الإضافية، تمت إضافة تحسين إضافي للقفز. لذا بشكل عام، معالجة تدفق التحكم بالوسائل المخصصة، كما يتم حاليًا، أسوأ.
بين Python 3.5 و 3.6 و 3.7، كانت هناك تغييرات كبيرة في تعليمات :code:MAKE_FUNCTION و :code:CALL_FUNCTION.
Python 3.8 يزيل تعليمات :code:SETUP_LOOP و :code:SETUP_EXCEPT و :code:BREAK_LOOP و :code:CONTINUE_LOOP، مما قد يجعل اكتشاف تدفق التحكم أكثر صعوبة، بسبب نقص تحليل تدفق التحكم الأكثر تطورًا المخطط له. سنرى.
حاليًا، ليست جميع الأرقام السحرية لـ Python مدعومة. على وجه التحديد في بعض إصدارات Python، ولا سيما Python 3.6، تغير الرقم السحري عدة مرات داخل الإصدار.
نحن ندعم فقط الإصدارات الصادرة، وليس الإصدارات المرشحة. لاحظ، مع ذلك، أن سحر الإصدار الصادر عادة ما يكون هو نفسه آخر إصدار مرشح قبل الإصدار.
هناك أيضًا مترجمات Python مخصصة، ولا سيما Dropbox، والتي تستخدم سحرها الخاص وتشفير البايتكود. باستثناء مترجم Python 2.5 القديم لـ Dropbox، لا يتم التعامل مع هذا النوع من الأشياء.
نحن أيضًا لا نتعامل مع كود PJOrion_ أو الكود المبهم بطرق أخرى. بالنسبة لـ PJOrion جرب: PJOrion Deobfuscator_ لفك تشفير البايتكود للحصول على بايتكود صالح قبل تجربة هذه الأداة؛ قد يساعد pydecipher_ في ذلك.
لا يمكن لهذا البرنامج فك ترجمة ملفات EXE لنظام Microsoft Windows التي تم إنشاؤها بواسطة Py2EXE_، على الرغم من أنه يمكننا على الأرجح فك ترجمة الكود بعد استخراج البايتكود بشكل صحيح. قد يساعد Pydeinstaller <https://github.com/charles-dyfis-net/pydeinstaller>_ في فك ضغط حزم Pyinstaller.
معالجة قوائم طويلة بشكل مرضي من التعبيرات أو العبارات بطيئة. نحن لا نتعامل مع Cython_ أو MicroPython، والتي لا تستخدم البايتكود.
هناك العديد من الأخطاء في فك الترجمة. وهذا صحيح بالنسبة لكل مفككات CPython الأخرى التي واجهتها، حتى تلك التي ادعت أنها "مثالية" على إصدار معين مثل 2.4.
مع تقدم Python، يصبح فك الترجمة أيضًا أكثر صعوبة لأن التجميع أكثر تطورًا واللغة نفسها أكثر تطورًا. أشك في أن المحاولات المستقبلية ستكون أقل اعتمادًا على الحلول المخصصة مثل unpyc37_ (التي تعتمد على مفكك 3.3) ببساطة لأنه أصبح القيام بذلك أكثر صعوبة. الخبر السار، على الأقل من وجهة نظري، هو أنني أعتقد أنني أفهم ما هو مطلوب لمعالجة المشكلات بشكل أكثر قوة. ولكن الآن، حتى يتم تمويل المشروع بشكل أفضل، لا أنوي بذل أي جهد جاد لدعم إصدارات Python 3.8 أو 3.9، بما في ذلك الأخطاء التي قد تظهر. أتصور أنه في مرحلة ما قد أكون مهتمًا بذلك.
يمكنك بسهولة العثور على أخطاء عن طريق تشغيل الاختبارات ضد مجموعة الاختبارات القياسية التي تستخدمها Python لفحص نفسها. في أي وقت معين، هناك العشرات من المشكلات المعروفة المعزولة بشكل جيد والتي يمكن حلها إذا أراد شخص ما تخصيص الوقت للقيام بذلك. المشكلة هي أنه لا يوجد الكثير من الأشخاص الذين يعملون على إصلاح الأخطاء.
بعض الأخطاء في 3.7 و 3.8 هي ببساطة مسألة إعادة نقل الإصلاحات من decompyle3. أي متطوعين؟
قد تصادف خطأ تريد الإبلاغ عنه. يرجى القيام بذلك بعد قراءة How to report a bug <https://github.com/rocky/python-uncompyle6/blob/master/HOW-TO-REPORT-A-BUG.md>_ واتباع تعليمات فتح مشكلة <https://github.com/rocky/python-uncompyle6/issues/new?assignees=&labels=&template=bug-report.md>_.
كن على علم أنه قد لا يحظى باهتمامي لفترة. إذا قمت برعاية أو دعم المشروع بطريقة ما، سأعطي أولوية لمشاكلك فوق طابور الأشياء الأخرى التي قد أقوم بها بدلاً من ذلك. في حالات نادرة، يمكنني القيام بفك ترجمة يدوية للبايتكود مقابل رسوم. ومع ذلك، هذا مكلف، عادة ما يتجاوز ما يرغب معظم الناس في إنفاقه.
uncompyle6 decompyle3 -- BlackHat 2024 Asia (فيديو https://www.youtube.com/watch?v=NA77SFncppE`_). شكر كبير للمنظمين والمراجعين للسماح لي بالتحدث. هذا النوع من الأشياء يشجعني على العمل على مشاريع مثل هذا.uncompyle6 غير صحيحة، بينما نتائج :code:uncompyle2 صحيحة، ولكن في كثير من الأحيان يكون uncompyle6 صحيحًا عندما يكون uncompyle2 غير صحيح. لأن :code:uncompyle6 يلتزم بالدقة على حساب Python الاصطلاحي، يمكن لـ :code:uncompyle2 إنتاج كود يبدو أكثر طبيعية عندما يكون صحيحًا. حالياً :code:uncompyle2 يتم صيانته بشكل خفيف. راجع متتبع المشكلات _ الخاص به لمزيد من التفاصيل... _Cython: https://en.wikipedia.org/wiki/Cython .. _trepan: https://pypi.python.org/pypi/trepan3k .. _compiler: https://github.com/rocky/python-uncompyle6/wiki/How-does-this-code-work%3F .. _HISTORY: https://github.com/rocky/python-uncompyle6/blob/master/HISTORY.md .. _report_bug: https://github.com/rocky/python-uncompyle6/blob/master/HOW-TO-REPORT-A-BUG.md .. _debuggers: https://pypi.python.org/pypi/trepan3k .. _remake: https://bashdb.sf.net/remake .. _pycdc: https://github.com/zrax/pycdc .. _decompyle3: https://github.com/rocky/python-decompile3 .. _uncompyle2: https://github.com/wibiti/uncompyle2 .. _unpyc37: https://github.com/andrew-tavera/unpyc37 .. _this: https://github.com/rocky/python-uncompyle6/wiki/Deparsing-technology-and-its-use-in-exact-location-reporting .. |buildstatus| image:: https://circleci.com/gh/rocky/python-uncompyle6.svg?style=svg :target: https://app.circleci.com/pipelines/github/rocky/python-uncompyle6 .. |packagestatus| image:: https://repology.org/badge/vertical-allrepos/python:uncompyle6.svg :target: https://repology.org/project/python:uncompyle6/versions .. _PJOrion: http://www.koreanrandom.com/forum/topic/15280-pjorion-%D1%80%D0%B5%D0%B4%D0%B0%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BA%D0%BE%D0%BC%D0%BF%D0%B8%D0%BB%D1%8F%D1%86%D0%B8%D1%8F-%D0%B4%D0%B5%D0%BA%D0%BE%D0%BC%D0%BF%D0%B8%D0%BB%D1%8F%D1%86%D0%B8%D1%8F-%D0%BE%D0%B1%D1%84 .. _pydecipher: .. _Deobfuscator: .. _Py2EXE: .. |Supported Python Versions| image:: .. |Latest Version| image:: :target: .. |Pypi Installs| image::
tracker <https://github.com/wibiti/uncompyle2/issues>How to report a bug <https://github.com/rocky/python-uncompyle6/blob/master/HOW-TO-REPORT-A-BUG.md>_issue tracker <https://github.com/zrax/pycdc/issues>_ الخاص به للتفاصيل. حالياً يتم صيانته بشكل خفيف.