2017-03-08 100 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__的设置。