2017-03-08 20 views
5

モジュールのインポートをキャッチするためにPEP302ベースのインポートフックを使用しようとしていますので、実行時に読み込まれる暗号化された.pyファイルを持つことができます。私はhttps://github.com/citrusbyte/python-obfuscationのpython難読化に関するテンプレートに従っています。PEP302実装の詳細が必要

基本的な考え方は簡単です。import命令をキャッチするsys.meta_pathに挿入されたFinder()関数を使用してimportコマンドをインターセプトします。 Finderは、モジュールが自分自身を処理したいモジュールであるかどうかをチェックし、もしそうなら、カスタムLoaderオブジェクトを返します。それ以外の場合は、インポートは無視されます。カスタムローダはsys.modulesにエントリを作成し、Pythonモジュールのソースを読み込み、PEP302のドキュメントで定義されているようにexecを使用して新しく作成したモジュールに追加します。

これはほとんどうまく動作しますが、わかりにくい特定の状況が1つあります。 3つのファイルmain、foo、barを仮定します。 mainはインポートフックを設定し、fooとbarをインポートします。 foo自体はbarをインポートします。したがって、状況は次のとおりです。

main: 
    set_import_hook 
    import foo 
    import bar 
foo: 
    import bar 
bar: 
    <irrelevant> 

私は、渡されているものを見るためのフックとして設定されたFinder関数内のデバッグステートメントを持っています。

私は暗号化されていないコード私が処理し、自分自身をsys.modulesに追加していない(つまり、コードを持っている場合は、プリントアウトは、次のような動作を示しています。

Finder (foo) 
Finder (bar) called from inside foo when foo itself is loaded 
Finder (bar) called from main after returning from the import foo 

私が処理し、fooとバーファイルをロード私自身、ここでの動作は次のとおりです。

Finder (foo) 
Finder (foo.bar) tries to load bar in the context of foo 
Finder (bar) called from main after returning from import foo 

これはバーの2つのバージョンがsys.modulesに存在することが原因となるあなたがsys.modules.keysを見れば()の2つの場合に、最初のケースではそれが唯一のショー。 fooとbarを表示し、2番目のケースではfoo、foo.bar、barを表示します

この現象はわかりません。モジュールを作成するプロセスは、PEP 302文書に記載されています。これは私が使用しているものです:

module = sys.modules.setdefault(name, imp.new_module(name)) 
    module.__file__ = filename 
    module.__path__ = [os.path.dirname(os.path.abspath(file.name))] 
    module.__loader__ = self 
    sys.modules[name] = module 
    exec(src, module.__dict__) 

ありがとう。

答えて

0

さまざまな例とドキュメントを見て、私は部分的な答えがあります。

上記のコードでは、私はmodule.__package__を設定していないことに気付きました。インポートプロセスのどこかで、モジュール定義にfoo.__package__ = 'foo'というエントリが設定されました。これにより、fooはパッケージとみなされ、パッケージディレクトリに対する相対的なインポートとみなされたすべてのインポートが行われました。

モジュールの設定を行っていなかったインポートに対して実行すると、module.__package__がシステムによって[なし]に設定されていることがわかりました。しかし、上記のコードでmodule.__package__ = Noneを設定しても機能しませんでした。何かをfooにリセットします。

解決策は、module.__package__ = ''(ヌル文字列)を設定することでした。だから、モジュールを追加するためのコードの作業部分は次のとおりです。

module = sys.modules.setdefault(name, imp.new_module(name)) 
module.__file__ = filename 
module.__path__ = [os.path.dirname(os.path.abspath(file.name))] 
module.__loader__ = self 
module.__package__ = '' 
sys.modules[name] = module 
exec(src, module.__dict__) 

これは今働いている、とモジュールfooとbarは一度だけインポートします。暗号化されたモジュールと暗号化されていないモジュールの動作は似ています。

明示的に''に設定されていないと、module.__package__がどこに設定されるのかまだ分かりません。

関連する問題