2017-03-08 102 views
5

我正在嘗試使用基於PEP302的導入鉤子來捕獲模塊的導入,以便我可以在運行時加載一些加密的.py文件。我正在關注python混淆模板https://github.com/citrusbyte/python-obfuscation需要PEP302實現細節

基本思想很簡單:使用插入到捕獲導入指令的sys.meta_path中的Finder()函數攔截導入命令。 Finder檢查模塊是否是我們想要處理的模塊,如果是,則返回一個自定義的Loader對象。否則它會忽略導入。自定義加載程序在sys.modules中創建一個條目,並讀入python模塊源文件,並使用PEP302文檔中定義的exec將其添加到新創建的模塊中。

這工作大多好,但我有一個具體的情況,我無法弄清楚。假設3個文件,main,foo和bar。主要設置導入鉤然後導入foo,並且吧。 foo本身進口吧。所以情況是:

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和bar文件我,這裏是行爲:

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

這將導致酒吧sys.modules中存在的兩個版本。如果你看一下在兩種情況下sys.modules.keys(),在第一種情況下它只能說明foo和bar。第二種情況顯示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__設置爲None。但在上面的代碼中設置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和酒吧只得到一次進口。加密和非加密模塊的行爲看起來相似。

如果module.__package__未明確設置爲'',我仍不明白module.__package__的設置。