【发布时间】:2017-03-08 20:29:32
【问题描述】:
我正在尝试使用基于 PEP302 的导入挂钩来捕获模块的导入,这样我就可以拥有一些在运行时加载的加密 .py 文件。我在https://github.com/citrusbyte/python-obfuscation 关注python 混淆模板。
基本思想很简单:使用插入到 sys.meta_path 中的 Finder() 函数来拦截导入命令,该函数捕获导入指令。 Finder 检查该模块是否是我们想要自己处理的模块,如果是,则返回一个自定义 Loader 对象。否则它会忽略导入。自定义加载器在 sys.modules 中创建一个条目,并读取 python 模块源并使用 PEP302 文档中定义的 exec 将其添加到新创建的模块中。
这几乎可以正常工作,但我有一种我无法弄清楚的具体情况。假设有 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 和 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 中存在两个版本的 bar。如果您在这两种情况下查看 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__)
谢谢。
【问题讨论】:
标签: python python-import