[原创]Python源码解析-import过程
2023-3-17 10:40:0 Author: bbs.pediy.com(查看原文) 阅读量:9 收藏

[原创]Python源码解析-import过程

2023-3-17 10:40 3270

要讲import的过程,就必然离不开_bootstrap.py文件。基本上import的功能都在这个Py脚本中实现。

在Python初始化的代码中,可以找到函数init_importlib。其中调用了一个函数PyImport_ImportFrozenModule。该函数的参数是字符串"_frozen_importlib"。

文本 描述已自动生成

PyImport_ImportFrozenModule调用其中PyImport_ImportFrozenModuleObject。这里可以看到一个find_frozen函数。

文本 描述已自动生成

进入find_frozen可以看到look_up_frozen的调用。

手机屏幕的截图 描述已自动生成

在look_up_frozen可看到一个循环字符串匹配。匹配的字符串来自于数组_PyImport_FrozenBootstrap。

电脑屏幕截图 描述已自动生成

查看_PyImport_FrozenBootstrap的定义。

继续查看。可以找到"_frozen_importlib"的定义。其主要内容是GET_CODE(importlib__bootstrap)。

文本 描述已自动生成

找到_Py_get_importlibbootstrap_toplevel的定义。importlibbootstrap_do_patchups是个空函数,无需在意。

文本 描述已自动生成

关键是importlibbootstrap_toplevel的定义。查看importlibbootstrap_toplevel的定义。是一个PyCodeObject对象。

其有一个co_code_adaptive成员。该内容就是由_bootstrap.py脚本编译而来。

文本 描述已自动生成

成功获取_frozen_importlib的数据后,就需要加载其代码。到这里,基本就完成了_frozen_importlib模块的加载。

文本 中度可信度描述已自动生成

之后是执行_bootstrap.py中的_install函数(详见_bootstrap.py)。

文本 描述已自动生成

以上内容在pyinit_core完成。之后在pyinit_main中可看到以下代码。

文本 描述已自动生成

进入init_interp_main,可看到以下代码。

文本 描述已自动生成

进入init_importlib_external,可看到以下代码。其中PyObject_CallMethod函数主要功能是执行Python代码的函数(PyCodeObject)。

文本 描述已自动生成

到_bootstrap.py中,可看到此函数定义。其中有一个import语句。这也是Python开始运行执行的第一个import指令。

首先通过dis模块看看import语句是如何执行的。

文本 描述已自动生成

可以看到有一个重要的opcode指令IMPORT_NAME。在Python\ceval.c中可找到处理IMPORT_NAME指令的代码。

文本 描述已自动生成

其实就是执行了一个import_name函数。import_name中调用PyImport_ImportModuleLevelObject函数。

文本 描述已自动生成

继续往下走,可看到以下代码。其中abs_name记录了要import的模块名称。

文本 描述已自动生成

在import_find_and_load可见到下列代码。是执行了_bootstrap.py中的_find_and_load。

文本 描述已自动生成

之后就是进入Python代码了,_find_and_load的定义如下。

文本 描述已自动生成

后续加载环节都在_bootstrap.py中。最终module对象直接由PyObject_CallMethodObjArgs返回。

基于上述所说,import指令最终会执行到_bootstrap.py的_find_and_load函数中。既然如此,就通过Python代码来实现import的Hook。

准备一个函数,如果导入模块是qwe,就替换成base64。注意,函数要实现_find_and_load的基本功能,否则就无法成功加载模块。

文本 描述已自动生成

修改_frozen_importlib._find_and_load的code对象,改成我们自己的函数对象。调用import指令。

文本 中度可信度描述已自动生成

执行后并没有啥报错。查看sys.modules,发现base64已经被加载。

文本 描述已自动生成

注意虽然base64模块加载完成了,但是使用的时候符号还是qwe才行。

这个方法可以hook很多函数。但需要注意一点,在修改function的code成员地址时,代码的运行空间发生了变化。新code所使用的模块、全局变量等,必须是原本模块所引用或含有的,否则会导致执行报错。

新code可以毫无顾忌的使用原本模块引用的模块、变量、符号等。Python在py->PyCodeObject时,不会进行语法检查。

[2023春季班]《安卓高级研修班(网课)》月薪两万班招生中~


文章来源: https://bbs.pediy.com/thread-276520.htm
如有侵权请联系:admin#unsafe.sh