我正在尝试使用基于PEP302的导入挂钩来捕获模块的导入,因此我可以在运行时加载一些加密的.py文件。我在https://github.com/citrusbyte/python-obfuscation处关注python模糊处理的模板。
基本思路很简单:使用插入到sys.meta_path中的Finder()函数拦截import命令,该函数捕获一个import指令。 Finder检查模块是否是我们想要自己处理的模块,如果是,则返回自定义Loader对象。否则它会忽略导入。自定义加载器在sys.modules中创建一个条目,并读入python模块源并使用exec将其添加到新创建的模块中,如PEP302文档中所定义。
这很好用,但我有一个我无法弄清楚的具体情况。假设3个文件,main,foo和bar。 main设置导入钩然后导入foo和bar。 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中存在两个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__)
感谢。
答案 0 :(得分:0)
在看了很多例子和文档之后,我得到了部分答案。
在上面的代码中,我注意到我没有设置primenumber
。在导入过程中的某个位置,导致在模块定义中设置了module.__package__
条目。这导致foo被视为一个包,它所做的任何导入都被认为是相对于包目录的导入。
在我没有进行模块设置的导入运行时,我看到系统将foo.__package__ = 'foo'
设置为None。但是在上面的代码中设置module.__package__
不起作用。有些东西把它重置为foo。
有效的解决方案是设置module.__package__ = None
(空字符串)。因此,添加模块的代码的工作是:
module.__package__ = ''
现在正在运行,模块foo和bar只导入一次。加密和未加密模块的行为看起来很相似。
如果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__)
未明确设置为module.__package__
,我仍然无法理解''
的设置位置。