コンテンツ
ネイティブ Python クロスバージョン逆コンパイラーおよびフラグメント逆コンパイラー。 decompyle、uncompyle、uncompyle2 の後継。
uncompyle6 は、 Python バイトコードを同等の Python ソース コードに変換します。 Python バージョン 1.0 からバージョン 3.8 までの 24 年以上の Python リリースにわたるバイトコードを受け入れます。 Dropbox の Python 2.5 バイトコードといくつかの PyPy バイトコードが含まれています。
OK、言っておきますが、このソフトウェアは素晴らしいです。これは、通常のハッキーな逆コンパイラー以上のものです。コンパイラー技術を使用して、プログラムは命令からプログラムの解析ツリーを作成します。上位レベルのノードは、Python AST からのものに少し似ています。したがって、Python バイトコードのセクションで何が起こっているかを実際に分類して理解することができます。
これに基づいて、これが他の CPython バイトコード デコンパイラーと異なるもう 1 つの点は、ソース コードの断片だけを逆解析し、特定のバイトコード オフセット周辺のソース コード情報を提供する機能です。
私はツリー フラグメントを使用して、trepan デバッガー内で実行時にコードのフラグメントを逆解析します。そのために、バイトコード オフセットが記録され、ソース コードのフラグメントに関連付けられます。この目的は、当初の目的と一致していますが、少し異なります。詳細については、こちらを参照してください。
命令オフセットを指定した Python フラグメント逆解析は、スタック トレースを表示するのに便利で、実行時に行番号だけでなく詳細な位置を表示したいプログラムに組み込むことができます。このコードは、ソースコード情報が存在せず、バイトコードのみがある場合にも使用できます。繰り返しますが、私のデバッガはこれを利用します。
decompyle、uncompyle、uncompyle2、uncompyle3 のフォークが数多く存在しました (そして今も存在します)。それらの多くは基本的に同じコードベースから来ており、(ほぼ?) それらすべては現在積極的にメンテナンスされていません。 1 人は Python 1.5 ~ 2.3 の逆コンパイルが得意で、もう 1 人は Python 2.7 が得意でしたが、それだけでした。もう 1 つは Python 3.2 のみを処理します。別のパッチはそれにパッチを適用し、3.3 のみを処理しました。わかりますね。このコードは、これらのフォークをすべてまとめて前に進みます。このコード ベースでは、古いフォークに対して重大なリファクタリングとクリーンアップが行われています。 decompyle3 ではさらに実験的なリファクタリングが行われています。
これは明らかに、Python のすべてのバージョンにわたって Python の逆コンパイルに最適です。また、Python バージョンのサブセットに対してのみ逆コンパイルを提供する別のプロジェクトがある場合でも、通常、それらに対しても同様に明らかにより適切に実行します。
どうすればわかりますか?そのバージョンの Python に同梱されている Python バイトコードを取得し、これらを逆コンパイルします。逆コンパイルに成功したものについては、そのバイトコード バージョンの Python インタープリターを実行することで、結果のプログラムが構文的に正しいことを確認できます。最後に、プログラム自体にテストがある場合は、逆コンパイルされたコードに対してチェックを実行できます。
私たちは自動プロセスを使用してバグを発見します。他の逆コンパイラの問題トラッカーでは、その過程で見つかった多数のバグが見つかります。他の逆コンパイラでは修正されるものはほとんどありません。
git リポジトリ内のコードは、Python 3.0 から 3.2 を除き、Python 2.4 から最新の Python バージョンまで実行できます。希望があれば、ボランティアがこれらの欠陥に対処することを歓迎します。
ただし、これを行う方法は、連続する Python バージョンを git ブランチに分離することです。
PyPy 3-2.4 以降も同様に動作します。
読み取ることができるバイトコード ファイルは、バージョン 1.4、2.1 ~ 2.7、および 3.0 ~ 3.8 およびそれ以降の PyPy バージョンの Python バイトコードでテストされています。
uncompyle6
という名前を使用して PyPI からインストールできます。
pip インストール uncompyle6
ソース コードからインストールするには、このプロジェクトは setup.py を使用するため、標準の Python ルーチンに従います。
$ pip install -e 。 # ソースツリーから実行するように設定する
または:
$ python setup.py install # sudoが必要な場合があります
GNU Makefile も提供されているため、 make install
(おそらく root または sudo) で上記の手順を実行できます。
小切手をする
GNU メイクファイルが追加され、適切なコマンドを実行する設定と、最速から最低までのテストの実行をスムーズに行うことができます。
リメイクがインストールされている場合は、 remake --tasks
使用してテストを含むすべてのタスクのリストを確認できます。
走る
$ uncompyle6 *コンパイルされた Python ファイル-pyc-or-pyo*
使用方法に関するヘルプ:
$ uncompyle6 -h
古いバージョンの Python では、バイトコードを逆コンパイルし、そのバイトコード バージョンの Python インタープリタを使用してコンパイルすることでバイトコードを検証できました。これを行うと、生成されたバイトコードを元のバイトコードと比較できるようになります。しかし、Python のコード生成が向上するにつれて、これは実現不可能になりました。
逆コンパイル プロセスの正確性を Python 構文検証で確認したい場合は、 --syntax-verify
オプションを追加します。ただし、Python 構文は変更されるため、バイトコードが構文をチェックする Python インタープリターにとって正しいバイトコードである場合は、このオプションを使用する必要があります。
全体的な品質が向上するにつれて、特定のバイトコードの逆コンパイルでリグレッションが発生する場合があるため、結果を別のバージョンのuncompyle6と相互比較することもできます。
Python 3.7 および 3.8 の場合、一般的に decompyle3 のコードの方が優れています。
または、uncompyle2、unpyc37、pycdc などの特定の別の Python デコンパイラーを試してください。後の 2 つは動作が異なるため、ここにあるバグは多くの場合そこに含まれておらず、その逆も同様です。
これらのプログラムには、より強力な検証を提供する興味深いクラスがあり、すぐに利用できます。これらのプログラムは、実行時に自分自身をテストします。私たちのテストスイートにはこれらが含まれています。
そして Python には、このような別のプログラム セット、つまり標準ライブラリのテスト スイートが付属しています。 test/stdlib
には、この種のチェックを容易にするコードがいくつかあります。
既知であり、おそらく修正可能である (ただし困難な) 最大の問題は、制御フローの処理に関係しています。 (Python には、おそらく私がこれまで見た中で最も多様で厄介な複合文のセットがあります。ループや try ブロックには "else" 句がありますが、これについては多くのプログラマが知らないのではないかと思われます。)
私が調べたすべての Python 逆コンパイラーには、Python の制御フローの逆コンパイルに問題がありました。場合によっては、誤った逆コンパイルを検出して報告することができます。
Python 2 の Python サポートはかなり充実しています
Python のバージョンの下位では、Python の分散テスト用の自動テストが導入されていませんが、逆コンパイルはかなり良好に行われているようです。また、バージョン 1.6 および 2.0 用の Python インタープリターはありません。
Python 3 シリーズでは、Python のサポートは 3.4 または 3.3 あたりで最も強力になり、これらのバージョンから遠ざかるにつれてサポートが低下します。 Python 3.0 は、ある意味、3.1 や 2.7 よりも 2.6 に似ているという点で奇妙です。 Python 3.6 では、バイト コードではなくワード コードを使用することにより、状況が大幅に変わります。その結果、ジャンプ命令引数のジャンプ オフセット フィールドが削減されました。これにより、 EXTENDED_ARG
命令がジャンプ命令でより普及するようになりました。以前は稀でした。おそらく、追加のEXTENDED_ARG
命令を補うために、追加のジャンプ最適化が追加されました。つまり、現在行われているように、アドホックな手段で制御フローを処理することは、より悪いものになります。
Python 3.5、3.6、3.7 の間で、 MAKE_FUNCTION
とCALL_FUNCTION
命令に大きな変更が加えられました。
Python 3.8 では、制御フローの検出を困難にする可能性があるSETUP_LOOP
、 SETUP_EXCEPT
、 BREAK_LOOP
、およびCONTINUE_LOOP
命令が削除され、計画されているより高度な制御フロー分析が欠如します。見てみましょう。
現在、すべての Python マジック ナンバーがサポートされているわけではありません。特に Python の一部のバージョン、特に Python 3.6 では、マジック ナンバーはバージョン内で何度か変更されます。
サポートされるのはリリースされたバージョンのみであり、候補バージョンはサポートされません。ただし、リリースされたバージョンのマジックは通常、リリース前の最後の候補バージョンと同じであることに注意してください。
また、独自のマジックを使用してバイトコードを暗号化する、カスタマイズされた Python インタープリター (特に Dropbox) もあります。 Dropbox の古い Python 2.5 インタープリタを除いて、この種のものは処理されません。
また、PJOrion などの難読化されたコードも扱いません。 PJOrion の場合は、このツールを試す前に、PJOrion Deobfuscator でバイトコードのスクランブルを解除して有効なバイトコードを取得してください。 pydecopher がそれを助けるかもしれません。
このプログラムは、Py2EXE によって作成された Microsoft Windows EXE ファイルを逆コンパイルできませんが、バイトコードを適切に抽出した後でコードを逆コンパイルできる可能性があります。 Pydeinstaller は、Pyinstaller バンドラーの解凍に役立つ場合があります。
異常に長い式やステートメントのリストの処理は遅くなります。バイトコードを使用しないCythonやMicroPythonは取り扱っておりません。
逆コンパイルには多数のバグがあります。そしてそれは、私がこれまでに遭遇した他のすべての CPython デコンパイラーにも当てはまります。2.4 などの特定のバージョンで「完璧」であると主張するものであってもです。
Python が進歩するにつれて、コンパイルがより洗練され、言語自体もより洗練されるため、逆コンパイルも難しくなります。 unpyc37 (3.3 逆コンパイラに基づく) のようなアドホックな試みは、単にそうするのが難しいため、少なくなるのではないかと思います。少なくとも私の立場から見て良いニュースは、より強力な方法で問題に対処するために何が必要かを理解していると思うことです。しかし、今のところ、プロジェクトの資金が潤うまで、私は Python バージョン 3.8 または 3.9 をサポートするための真剣な努力をするつもりはありません。これには、発生する可能性のあるバグも含まれます。いつか、興味を持つかもしれないと想像しています。
Python が自身をチェックするために使用する標準のテスト スイートに対してテストを実行すると、バグを簡単に見つけることができます。常に、十分に分離されており、時間をかけて解決できる既知の問題が数多く存在します。問題は、バグ修正に取り組んでいる人がそれほど多くないことです。
3.7 と 3.8 のバグの一部は、単にdecompyle3の修正をバックポートしただけの問題です。ボランティアはいますか?
報告したいバグに遭遇するかもしれません。バグを報告する方法を読んでから問題を報告し、指示に従ってください。
しばらくの間は私の注意を引かないかもしれないことに注意してください。あなたが何らかの方法でプロジェクトを後援またはサポートしている場合、私は代わりに私が行う可能性のある他のことよりもあなたの問題を優先させます。まれな状況では、有料でバイトコードを手動で逆コンパイルすることができます。ただし、これは膨大であり、通常、ほとんどの人が喜んで支出できる金額を超えています。
uncompyle6
decompyle3
-- BlackHat 2024 Asia (ビデオ)。講演を許可してくださった主催者と査読者に深く感謝します。このようなことが、このようなプロジェクトに取り組む励みになります。uncompyle6
結果が正しくなく、 uncompyle2
結果が正しくない状況もありますが、多くの場合、uncompyle2 が正しくなく uncompyle6 が正しくなります。 uncompyle6
慣用的な Python よりも精度を重視しているため、 uncompyle2
コードが正しい場合には、より自然な外観のコードを生成できます。現在、 uncompyle2
軽くメンテナンスされています。詳細については、問題トラッカーを参照してください。