首页
社区
课程
招聘
[原创]Python源码解析-import过程
2023-3-17 10:40 10340

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

2023-3-17 10:40
10340

1._bootstrap.py

要讲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指令。

 

2.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返回。

3.扩展编程

基于上述所说,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才行。

 

4.总结

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

 

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


[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

收藏
点赞3
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回