最近在分析一个国外某个体育游戏,热度最高的外挂样本。发现使用的是Python脚本并且Pyd编译后的,中间存在部分名称混淆并且Pyd的二进制函数量巨大,故而研究了一下Pyd逆向用来高效逆向这类样本。顺便记录一下方便后面查阅。(ps:pyd逆向内容还是挺多的,兜兜转转玩了一个月hhh)如果你觉得我的文章对你有帮助请帮忙点个赞吧。文章中有啥错误的位置欢迎指出。
在研究Pyd逆向之前我们需要了解一下Python这种解释语言是如何变成Pyd的。 通过阅读Cython源码我了解一下,如下图: 本质上它是一个脚本语言向C语言转换的过程。所以在逆向之前我们需要能正确认识Python的二进制形式,也就是Cython的函数。 最关键的是,我们在Windows上编译出来的Pyd实际上就是一个动态库,同理linux平台下就是一个so。看图: 通过导出表就可以看出来导出了两个函数,一个是我们的dllmain,剩下一个文章下面会详细介绍。
通过Cython源码我们梳理清楚我们的def 函数是怎么转换成C函数的。 这里就拿部分源码画图举例: 这是整个Cython的编译流程。 这个里面存在几个重要问题, a. Python解释器如何知道Pyd中的函数信息? b. python解释器怎么感知模块中的函数以及对象的信息 c. 虚拟机层和native层是如何互相调用以及交互的? d. python函数最后会变成什么样子?
入口函数 PyInit_模块名 上面提到过,Pyd导出了两个一个是dllmain和一个PyInit_模块名的函数 PyInit_模块名就是关键。源码实现在ModuleNode.py,下面是部分实现代码
PyInit_模块名 实际上会导出我们当前这个模块的函数信息。
这个是核心,通过源码来看,cython会经历这几个步骤: 1.收集函数信息 2.生成方法表 3.生成单个条目 4.生成模块定义 5.引用方法表 逆向我们需要关注的就是生成过程中的函数表__pyx_moduledef 和模块定义结构体__pyx_methods 这一部分定义是在我们的Python解释器的目录下,而Cython只是引入了这些结构,我拿3.11举例: 头文件路径:x:\xx\include\methodobject.h和moduleobject.h,methodobject.h
PyInit_模块名 在源码中的实现 ModuleNode.py:3092-3098:
生成出来的C代码应该是这样:
在二进制底层中我们就可以通过导出函数,直接定位到我们想要的: 这个就是我们想要的__pyx_moduledef,这样就可以手工查看这个模块中的所有Python函数了。(如果不这样做,通过解释器层面需要import xxx,并且需要补环境才行,而且有时候可能还会遇到隐藏问题) 顺带定义一下ida的结构体
实战看一下: 当前这个函数表是没有的因为这个是一个类模型,所以不存在单一的函数。
当我们外部的脚本语言需要调用Pyc是怎么做的呢?从源码中分析简化流程后就是这样:
核心还是这个 PyInit_模块 的函数。在此之前我们需要了解一下PyTypeObject这个就是存储类信息的结构体,我们了解一下结构: 实现在cpython的解释器源码中(xxx:\xxx\cpython\Include\cpython\object.h):
这个结构体就包含了当前这个模块这个类的所有信息: 比较重要的有这些
基于这个我们就可以完整解析这个模块里面的内容了。 怎么找到这个表结构体?回到最开始的问题系统如何加载的。如图,(梳理的调用,链篇幅有限我就不一个一个找了):\
所以在ida中我们可以通过PyModuleDef -> m_slots -> exec函数 -> PyType_Ready 调用,就能找到 PyTypeObject也就是我们的_typeobject。 slots的结构体定义:
slots就是加载这个模块之前需要执行的函数来对整个pyd进行初始化。通过源码分析可以知道我们这个模块的类的初始化是在m_slots[1],并且是一个可变长的,遇到0则结束。生成的源码位置在这里:cython\Cython\Compiler\ModuleNode.py 这个code.putln就是插入一行生成的代码,经过整理部分伪代码(如果存在好几个类的话):
通过ida 跟踪验证一下上面的流程 这里就是slot 定义一下PyTypeObject结构体来解析一下它:
导出的是动态创建的!! 接下来讲一下动态创建。
说白了也在exec里面,对实现感兴趣可以重点看一下这个函数generate_execution_code,这里展示稍微一下动态创建的Cython代码是什么:
如何找到呢?重点就是这个,在函数内找到这个 PyObject_Call(PyType_Type....)核心就是它PyType_Type 所以动态创建的也就是普通类是没有静态对象信息的结构体,但是我们还是可以从代码中分析找到函数表,核心就是找到 _Pyx_CyFunction_New。 根据特征码可以吧整个类信息都给分析出来,不用补全环境,并且打印函数地址。这些都是这个模块里面的成员方法: 参数1就是 PyMethodDef
我们逆向的时候核心点就是,这些二进制函数是怎么进入解释器层的?怎么调用的外部函数or方法? 分情况讨论 1.PYD内调用 Pyd内a.xx ——》b.xx的时候因为在一个pyd会调用优化后的 `__Pyx_PyObject 优化的调用函数,并且根据优化就不会进入解释器层,这样加快程序运行。 2.Pyd调用另外一个pyd 当pyd内调用另一个Pyd函数的时候:a.xx ->pydb.c.xxx 这个时候也会经过 __Pyx_PyObject,但是首先需要获取外部pyd的函数才能调用 流程如下:
我找一个例子:
3.Pyd进解释器层调用解释器里面的函数 则直接会调用pythonxx..dll中的导出函数,主要是这几个:
核心主要就是这个PyObject_Call
调用 Python 函数:
我初步的介绍一下这些函数是干什么:
一般是这种变参:func(*args, **kwargs) 不定参数调用
一般是这种:func(a, b, c) 固定参数调用。所以这个是笔者见到最多的最多调用方式!
obj.method()无参方法
obj.fun()调用场景,这种也是非常多的 这些函数都是没有符号名的,要么自己去做sig让ida识别,或者是自己肉眼识别。(不过这也是一个非常好利用的点,后面会讲)
这个问题我们直接通过底层就能看清楚,我先说一下,实际上python那种弱类型的特点,但是碰上了cpp这种强类型语言,所以他必须有一个包装函数来处理这些参数问题。我拿样本中驱动代码的一个方法举例:(下面是从ida里面拷贝出来的f5代码)
这个实际上就是一个标准的包装函数,也就是python的入口,他有几个重要标志:
通过这个特征我们可以拿到这个函数是是几个参数的,这个非常关键。接下里我展示一下如何静态分析判断函数参数以及函数名和编码信息 通过Python的异常回溯信息可以判断这个函数对应的是哪个成员方法:
通过源码分析可得知参数如下: 源码位置:Exceptions.c:840-841 和 972-1012
参数数量可以直接通过伪代码看出来这里在对参数数量进行检查:
最后在讲一下这个包装函数在Cython中怎么实现的: 首先这个包装函数有好几种变体,会根据不同参数来生成不同的包装类这样来优化调用,我整理了一个表格如下:
当我们了解了这么多以后,实际上可以发现,Pyd调用有一个致命缺陷。就是他的外部调用都依赖于包装函数 这里还是抛出三个问题: 一个Pyd程序如何定位? 遇到名称混淆处理? 怎么处理编译后庞大的Pyd函数?
首先在逆向之前我们肯定需要有一个定位点的,这里主要的定位手法就是如下两种: 第一种: 如果能运行环境。获取可以补全环境,最好还实在解释器层进行处理。通过打印Pyd信息获取里面的元数据,可以猜出我们需要的分析函数 第二种:静态分析 这里手法比较多:通过写ida脚本提取识别所有的函数,方法函数。主要可以通过包装函数中的 __Pyx_AddTraceback 函数即可拿到所有函数 写一个ida脚本就行了,给一个脚本吧:
效果如图: 我们把函数名给还原回来了:
这是笔者遇到的挑战之一,很多时候,一些作者会在编译的时候进行名称混淆防止你分析。 如图: 这种直接硬干不是好事,这里我建议使用 frida-python-bridge对关键函数进行hook。hook的主要针对这几个函数:
给个脚本
我们可以hook之后就可以打印一下参数和返回值就大概知道这个函数在干什么,frida是天然支持这些python类型的。这样一跑函数干什么无处遁形,还可以针对几个你觉得高度怀疑的函数进行小范围trace,范围太大容易崩掉。这里就不贴代码了,原理搞明白了就好弄。如果要处理函数内的调用则需要自己sig一下识别一下这些内部的快速调用。
其实这个把它当做一种特殊的混淆去对待 函数庞大的原因是因为为了兼容解释器特性还需要像c一样快,里面就有大量的异常和内存管理代码,gl锁等等等,真正有效代码极小。 分析他无非就是去掉这些多余的垃圾代码,我们只需要真正的python函数的调用。 所以就有两种方法:
传统手法 由于python转换成c是有一套转规则的以及对应的匹配模块这个在cython中是有的,可以针对进行模式匹配。(这里不展示这种了留点底子吧hhh),贴一个对于模版转换的源码位置吧有兴趣自己慢慢写可以。
捷进 实际上就是要识别垃圾代码并且删除,而且没有我们传统混淆那些,虚假控制流这些东西,只有一些“垃圾代码“。 可以写一个md脚本调用ai接口切块识别到一些垃圾函数给他删掉优化掉(目前笔者使用这个已经还原出一些超大函数)。 流程就是函数拷贝下来(可以使用mcp工具)->让ai进行切片识别这些多余的代码删除掉,写入文件funxxx.c 大概提示词如下:(这个提示词很重要,如果直接对话肯定没有任何结果,建议还是往mcp或者代码驱动ai这方面靠)
总体来说pyd逆向主要就是量大,所以传统方法逆向的话速度太慢,最好还是利用他的机制进行定位。下次我在填完变量成员的坑。
def generate_module_init_func(self, imported_modules, shared_utility_exporter, env, code):
subfunction = self.mod_init_subfunction(self.pos, self.scope, code)
self.generate_pymoduledef_struct(env, code)
code.enter_cfunc_scope(self.scope)
code.putln("")
code.put_code_here(UtilityCode.load("PyModInitFuncType", "ModuleSetupCode.c"))
modinit_func_name = EncodedString(f"PyInit_{env.module_name}")
header3 = "__Pyx_PyMODINIT_FUNC %s(void)" % self.mod_init_func_cname('PyInit', env)
code.putln("%s CYTHON_SMALL_CODE; /*proto*/" % header3)
if self.scope.is_package:
code.putln("#if !defined(CYTHON_NO_PYINIT_EXPORT) && (defined(_WIN32) || defined(WIN32) || defined(MS_WINDOWS))")
code.putln("__Pyx_PyMODINIT_FUNC PyInit___init__(void) { return %s(); }" % (
self.mod_init_func_cname('PyInit', env)))
code.putln("#endif")
... ....
def generate_module_init_func(self, imported_modules, shared_utility_exporter, env, code):
subfunction = self.mod_init_subfunction(self.pos, self.scope, code)
self.generate_pymoduledef_struct(env, code)
code.enter_cfunc_scope(self.scope)
code.putln("")
code.put_code_here(UtilityCode.load("PyModInitFuncType", "ModuleSetupCode.c"))
modinit_func_name = EncodedString(f"PyInit_{env.module_name}")
header3 = "__Pyx_PyMODINIT_FUNC %s(void)" % self.mod_init_func_cname('PyInit', env)
code.putln("%s CYTHON_SMALL_CODE; /*proto*/" % header3)
if self.scope.is_package:
code.putln("#if !defined(CYTHON_NO_PYINIT_EXPORT) && (defined(_WIN32) || defined(WIN32) || defined(MS_WINDOWS))")
code.putln("__Pyx_PyMODINIT_FUNC PyInit___init__(void) { return %s(); }" % (
self.mod_init_func_cname('PyInit', env)))
code.putln("#endif")
... ....
struct PyMethodDef {
const char *ml_name;
PyCFunction ml_meth;
int ml_flags;
const char *ml_doc;
};
struct PyMethodDef {
const char *ml_name;
PyCFunction ml_meth;
int ml_flags;
const char *ml_doc;
};
struct PyModuleDef {
PyModuleDef_Base m_base;
const char* m_name;
const char* m_doc;
Py_ssize_t m_size;
PyMethodDef *m_methods;
PyModuleDef_Slot *m_slots;
traverseproc m_traverse;
inquiry m_clear;
freefunc m_free;
};
struct PyModuleDef {
PyModuleDef_Base m_base;
const char* m_name;
const char* m_doc;
Py_ssize_t m_size;
PyMethodDef *m_methods;
PyModuleDef_Slot *m_slots;
traverseproc m_traverse;
inquiry m_clear;
freefunc m_free;
};
#define METH_VARARGS 0x0001
#define METH_KEYWORDS 0x0002
#define METH_NOARGS 0x0004
#define METH_O 0x0008
#define METH_VARARGS 0x0001
#define METH_KEYWORDS 0x0002
#define METH_NOARGS 0x0004
#define METH_O 0x0008
code.putln(header3)
code.putln("#if CYTHON_PEP489_MULTI_PHASE_INIT")
code.putln("{")
code.putln("return PyModuleDef_Init(&%s);" % Naming.pymoduledef_cname)
code.putln("}")
code.putln(header3)
code.putln("#if CYTHON_PEP489_MULTI_PHASE_INIT")
code.putln("{")
code.putln("return PyModuleDef_Init(&%s);" % Naming.pymoduledef_cname)
code.putln("}")
PyMODINIT_FUNC PyInit_mymodule(void) {
return PyModuleDef_Init(&__pyx_moduledef); /* ← 就这一行 */
}
PyMODINIT_FUNC PyInit_mymodule(void) {
return PyModuleDef_Init(&__pyx_moduledef); /* ← 就这一行 */
}
struct PyMethodDef {
__int64 ml_name;
__int64 ml_meth;
int ml_flags;
int _pad;
__int64 ml_doc;
};
struct PyModuleDef {
__int64 ob_refcnt;
__int64 ob_type;
__int64 m_init;
__int64 m_index;
__int64 m_copy;
__int64 m_name;
__int64 m_doc;
__int64 m_size;
__int64 m_methods;
__int64 m_slots;
__int64 m_traverse;
__int64 m_clear;
__int64 m_free;
};
struct PyMethodDef {
__int64 ml_name;
__int64 ml_meth;
int ml_flags;
int _pad;
__int64 ml_doc;
};
struct PyModuleDef {
__int64 ob_refcnt;
__int64 ob_type;
__int64 m_init;
__int64 m_index;
__int64 m_copy;
__int64 m_name;
__int64 m_doc;
__int64 m_size;
__int64 m_methods;
__int64 m_slots;
__int64 m_traverse;
__int64 m_clear;
__int64 m_free;
};
import cert
│
▼
PyInit_cert() ← 模块入口函数
│
├─→ PyModuleDef_Init() ← 创建模块对象
│
├─→ PyType_Ready(Certificate) ← 初始化类的 PyTypeObject
│
└─→ PyObject_SetAttr(module, "Certificate", &type) ← 把类加到模块里
import cert
│
▼
PyInit_cert() ← 模块入口函数
│
├─→ PyModuleDef_Init() ← 创建模块对象
│
├─→ PyType_Ready(Certificate) ← 初始化类的 PyTypeObject
│
└─→ PyObject_SetAttr(module, "Certificate", &type) ← 把类加到模块里
struct _typeobject {
PyObject_VAR_HEAD
const char *tp_name; /* For printing, in format "<module>.<name>" */
Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */
/* Methods to implement standard operations */
destructor tp_dealloc;
Py_ssize_t tp_vectorcall_offset;
getattrfunc tp_getattr;
setattrfunc tp_setattr;
PyAsyncMethods *tp_as_async; /* formerly known as tp_compare (Python 2)
or tp_reserved (Python 3) */
reprfunc tp_repr;
/* Method suites for standard classes */
PyNumberMethods *tp_as_number;
PySequenceMethods *tp_as_sequence;
PyMappingMethods *tp_as_mapping;
/* More standard operations (here for binary compatibility) */
hashfunc tp_hash;
ternaryfunc tp_call;
reprfunc tp_str;
getattrofunc tp_getattro;
setattrofunc tp_setattro;
/* Functions to access object as input/output buffer */
PyBufferProcs *tp_as_buffer;
/* Flags to define presence of optional/expanded features */
unsigned long tp_flags;
const char *tp_doc; /* Documentation string */
/* Assigned meaning in release 2.0 */
/* call function for all accessible objects */
traverseproc tp_traverse;
/* delete references to contained objects */
inquiry tp_clear;
/* Assigned meaning in release 2.1 */
/* rich comparisons */
richcmpfunc tp_richcompare;
/* weak reference enabler */
Py_ssize_t tp_weaklistoffset;
/* Iterators */
getiterfunc tp_iter;
iternextfunc tp_iternext;
/* Attribute descriptor and subclassing stuff */
PyMethodDef *tp_methods;
PyMemberDef *tp_members;
PyGetSetDef *tp_getset;
// Strong reference on a heap type, borrowed reference on a static type
PyTypeObject *tp_base;
PyObject *tp_dict;
descrgetfunc tp_descr_get;
descrsetfunc tp_descr_set;
Py_ssize_t tp_dictoffset;
initproc tp_init;
allocfunc tp_alloc;
newfunc tp_new;
freefunc tp_free; /* Low-level free-memory routine */
inquiry tp_is_gc; /* For PyObject_IS_GC */
PyObject *tp_bases;
PyObject *tp_mro; /* method resolution order */
PyObject *tp_cache;
PyObject *tp_subclasses;
PyObject *tp_weaklist;
destructor tp_del;
/* Type attribute cache version tag. Added in version 2.6 */
unsigned int tp_version_tag;
destructor tp_finalize;
vectorcallfunc tp_vectorcall;
};
struct _typeobject {
PyObject_VAR_HEAD
const char *tp_name; /* For printing, in format "<module>.<name>" */
Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */
/* Methods to implement standard operations */
destructor tp_dealloc;
Py_ssize_t tp_vectorcall_offset;
getattrfunc tp_getattr;
setattrfunc tp_setattr;
PyAsyncMethods *tp_as_async; /* formerly known as tp_compare (Python 2)
or tp_reserved (Python 3) */
reprfunc tp_repr;
/* Method suites for standard classes */
PyNumberMethods *tp_as_number;
PySequenceMethods *tp_as_sequence;
PyMappingMethods *tp_as_mapping;
/* More standard operations (here for binary compatibility) */
hashfunc tp_hash;
ternaryfunc tp_call;
reprfunc tp_str;
getattrofunc tp_getattro;
setattrofunc tp_setattro;
/* Functions to access object as input/output buffer */
PyBufferProcs *tp_as_buffer;
/* Flags to define presence of optional/expanded features */
unsigned long tp_flags;
const char *tp_doc; /* Documentation string */
/* Assigned meaning in release 2.0 */
/* call function for all accessible objects */
traverseproc tp_traverse;
/* delete references to contained objects */
inquiry tp_clear;
/* Assigned meaning in release 2.1 */
/* rich comparisons */
richcmpfunc tp_richcompare;
/* weak reference enabler */
Py_ssize_t tp_weaklistoffset;
/* Iterators */
getiterfunc tp_iter;
iternextfunc tp_iternext;
/* Attribute descriptor and subclassing stuff */
PyMethodDef *tp_methods;
PyMemberDef *tp_members;
PyGetSetDef *tp_getset;
// Strong reference on a heap type, borrowed reference on a static type
PyTypeObject *tp_base;
PyObject *tp_dict;
descrgetfunc tp_descr_get;
descrsetfunc tp_descr_set;
Py_ssize_t tp_dictoffset;
initproc tp_init;
allocfunc tp_alloc;
newfunc tp_new;
freefunc tp_free; /* Low-level free-memory routine */
inquiry tp_is_gc; /* For PyObject_IS_GC */
PyObject *tp_bases;
PyObject *tp_mro; /* method resolution order */
PyObject *tp_cache;
PyObject *tp_subclasses;
PyObject *tp_weaklist;
destructor tp_del;
/* Type attribute cache version tag. Added in version 2.6 */
unsigned int tp_version_tag;
destructor tp_finalize;
vectorcallfunc tp_vectorcall;
};
struct _typeobject {
// 基本信息
const char *tp_name; // 类名 "cert.Certificate"
Py_ssize_t tp_basicsize; // 实例对象大小
// 特殊方法
destructor tp_dealloc; // 析构函数 (__del__)
reprfunc tp_repr; // __repr__
hashfunc tp_hash; // __hash__
ternaryfunc tp_call; // __call__
reprfunc tp_str; // __str__
getiterfunc tp_iter; // __iter__
iternextfunc tp_iternext; // __next__
initproc tp_init; // __init__
newfunc tp_new; // __new__
// ★ 最重要的 ★
PyMethodDef *tp_methods; // 类的所有方法表!
PyMemberDef *tp_members; // 成员变量
PyGetSetDef *tp_getset; // property
// 继承信息
PyTypeObject *tp_base; // 父类
PyObject *tp_bases; // 所有基类
PyObject *tp_mro; // 方法解析顺序
};
struct _typeobject {
// 基本信息
const char *tp_name; // 类名 "cert.Certificate"
Py_ssize_t tp_basicsize; // 实例对象大小
// 特殊方法
destructor tp_dealloc; // 析构函数 (__del__)
reprfunc tp_repr; // __repr__
hashfunc tp_hash; // __hash__
ternaryfunc tp_call; // __call__
reprfunc tp_str; // __str__
getiterfunc tp_iter; // __iter__
iternextfunc tp_iternext; // __next__
initproc tp_init; // __init__
newfunc tp_new; // __new__
// ★ 最重要的 ★
PyMethodDef *tp_methods; // 类的所有方法表!
PyMemberDef *tp_members; // 成员变量
PyGetSetDef *tp_getset; // property
// 继承信息
PyTypeObject *tp_base; // 父类
PyObject *tp_bases; // 所有基类
PyObject *tp_mro; // 方法解析顺序
};
PyInit_cert()
│ ModuleNode.py:3097
└─→ return PyModuleDef_Init(&__pyx_moduledef);
│
│ ModuleNode.py:3668
└─→ m_slots = __pyx_moduledef_slots[]
│
│ ModuleNode.py:3630
└─→ {Py_mod_exec, exec_func}
│
│ ModuleNode.py:3227-3228
└─→ generate_type_init_code()
│
│ ModuleNode.py:3907-3914
└─→ for entry in c_class_entries:
generate_type_ready_code(entry)
│
│ Nodes.py:5889
└─→ __Pyx_PyType_Ready(&PyTypeObject)
PyInit_cert()
│ ModuleNode.py:3097
└─→ return PyModuleDef_Init(&__pyx_moduledef);
│
│ ModuleNode.py:3668
└─→ m_slots = __pyx_moduledef_slots[]
│
│ ModuleNode.py:3630
└─→ {Py_mod_exec, exec_func}
│
│ ModuleNode.py:3227-3228
└─→ generate_type_init_code()
│
│ ModuleNode.py:3907-3914
└─→ for entry in c_class_entries:
generate_type_ready_code(entry)
│
│ Nodes.py:5889
└─→ __Pyx_PyType_Ready(&PyTypeObject)
struct PyModuleDef_Slot {
int slot;
void *value;
};
struct PyModuleDef_Slot {
int slot;
void *value;
};
static CYTHON_SMALL_CODE int __pyx_pymod_exec_cert(PyObject *__pyx_m)
{
if (__Pyx_PyType_Ready(&__pyx_type_4cert_Certificate) < 0) __PYX_ERR(...)
if (PyObject_SetAttr(__pyx_m, __pyx_n_s_Certificate, (PyObject *)&__pyx_type_4cert_Certificate) < 0) __PYX_ERR(...)
if (__Pyx_PyType_Ready(&__pyx_type_4cert_User) < 0) __PYX_ERR(...)
if (PyObject_SetAttr(__pyx_m, __pyx_n_s_User, (PyObject *)&__pyx_type_4cert_User) < 0) __PYX_ERR(...)
if (__Pyx_PyType_Ready(&__pyx_type_4cert_Session) < 0) __PYX_ERR(...)
if (PyObject_SetAttr(__pyx_m, __pyx_n_s_Session, (PyObject *)&__pyx_type_4cert_Session) < 0) __PYX_ERR(...)
return 0;
}
static CYTHON_SMALL_CODE int __pyx_pymod_exec_cert(PyObject *__pyx_m)
{
if (__Pyx_PyType_Ready(&__pyx_type_4cert_Certificate) < 0) __PYX_ERR(...)
if (PyObject_SetAttr(__pyx_m, __pyx_n_s_Certificate, (PyObject *)&__pyx_type_4cert_Certificate) < 0) __PYX_ERR(...)
if (__Pyx_PyType_Ready(&__pyx_type_4cert_User) < 0) __PYX_ERR(...)
if (PyObject_SetAttr(__pyx_m, __pyx_n_s_User, (PyObject *)&__pyx_type_4cert_User) < 0) __PYX_ERR(...)
if (__Pyx_PyType_Ready(&__pyx_type_4cert_Session) < 0) __PYX_ERR(...)
if (PyObject_SetAttr(__pyx_m, __pyx_n_s_Session, (PyObject *)&__pyx_type_4cert_Session) < 0) __PYX_ERR(...)
return 0;
}
typedef __int64 Py_ssize_t;
typedef unsigned __int64 size_t;
struct PyObject {
Py_ssize_t ob_refcnt;
void *ob_type;
};
struct PyVarObject {
struct PyObject ob_base;
Py_ssize_t ob_size;
};
struct PyMethodDef {
const char *ml_name;
void *ml_meth;
int ml_flags;
const char *ml_doc;
};
struct PyTypeObject {
struct PyVarObject ob_base;
const char *tp_name;
Py_ssize_t tp_basicsize;
Py_ssize_t tp_itemsize;
void *tp_dealloc;
Py_ssize_t tp_vectorcall_offset;
void *tp_getattr;
void *tp_setattr;
void *tp_as_async;
void *tp_repr;
void *tp_as_number;
void *tp_as_sequence;
void *tp_as_mapping;
void *tp_hash;
void *tp_call;
void *tp_str;
void *tp_getattro;
void *tp_setattro;
void *tp_as_buffer;
unsigned __int64 tp_flags;
const char *tp_doc;
void *tp_traverse;
void *tp_clear;
void *tp_richcompare;
Py_ssize_t tp_weaklistoffset;
void *tp_iter;
void *tp_iternext;
struct PyMethodDef *tp_methods;
void *tp_members;
void *tp_getset;
struct PyTypeObject *tp_base;
struct PyObject *tp_dict;
void *tp_descr_get;
void *tp_descr_set;
Py_ssize_t tp_dictoffset;
void *tp_init;
void *tp_alloc;
void *tp_new;
void *tp_free;
void *tp_is_gc;
struct PyObject *tp_bases;
struct PyObject *tp_mro;
struct PyObject *tp_cache;
struct PyObject *tp_subclasses;
struct PyObject *tp_weaklist;
void *tp_del;
unsigned int tp_version_tag;
int _padding;
void *tp_finalize;
void *tp_vectorcall;
};
typedef __int64 Py_ssize_t;
typedef unsigned __int64 size_t;
struct PyObject {
Py_ssize_t ob_refcnt;
void *ob_type;
};
struct PyVarObject {
struct PyObject ob_base;
Py_ssize_t ob_size;
};
struct PyMethodDef {
const char *ml_name;
void *ml_meth;
int ml_flags;
const char *ml_doc;
};
struct PyTypeObject {
struct PyVarObject ob_base;
const char *tp_name;
Py_ssize_t tp_basicsize;
Py_ssize_t tp_itemsize;
void *tp_dealloc;
Py_ssize_t tp_vectorcall_offset;
void *tp_getattr;
void *tp_setattr;
void *tp_as_async;
void *tp_repr;
void *tp_as_number;
void *tp_as_sequence;
void *tp_as_mapping;
void *tp_hash;
void *tp_call;
void *tp_str;
void *tp_getattro;
void *tp_setattro;
void *tp_as_buffer;
unsigned __int64 tp_flags;
const char *tp_doc;
void *tp_traverse;
void *tp_clear;
void *tp_richcompare;
Py_ssize_t tp_weaklistoffset;
void *tp_iter;
void *tp_iternext;
struct PyMethodDef *tp_methods;
void *tp_members;
void *tp_getset;
struct PyTypeObject *tp_base;
struct PyObject *tp_dict;
void *tp_descr_get;
void *tp_descr_set;
Py_ssize_t tp_dictoffset;
void *tp_init;
void *tp_alloc;
void *tp_new;
void *tp_free;
void *tp_is_gc;
struct PyObject *tp_bases;
struct PyObject *tp_mro;
struct PyObject *tp_cache;
struct PyObject *tp_subclasses;
struct PyObject *tp_weaklist;
void *tp_del;
unsigned int tp_version_tag;
int _padding;
void *tp_finalize;
void *tp_vectorcall;
};
import cert
│
▼
PyInit_cert() ← Python 调用入口
│
▼
返回 PyModuleDef (带 m_slots)
│
▼
Python 解释器看到 Py_mod_exec slot
│
▼
调用 exec 函数 (sub_18000A570) ← 这时候开始创建!
│
├── 1. 初始化内部 scope struct (PyType_Ready)
├── 2. 导入依赖模块
├── 3. 创建方法字典 dict = {}
├── 4. 创建每个方法对象,放入 dict
├── 5. type("Certificate", (), dict) ← 类在这里诞生!
└── 6. module.__dict__["Certificate"] = class
▼
import 完成,Certificate 可用
import cert
│
▼
PyInit_cert() ← Python 调用入口
│
▼
返回 PyModuleDef (带 m_slots)
│
▼
Python 解释器看到 Py_mod_exec slot
│
▼
调用 exec 函数 (sub_18000A570) ← 这时候开始创建!
│
├── 1. 初始化内部 scope struct (PyType_Ready)
├── 2. 导入依赖模块
├── 3. 创建方法字典 dict = {}
├── 4. 创建每个方法对象,放入 dict
├── 5. type("Certificate", (), dict) ← 类在这里诞生!
└── 6. module.__dict__["Certificate"] = class
▼
import 完成,Certificate 可用
/* ==================== 第1步:创建类字典 ==================== */
// 来源: Nodes.py:5334 - self.dict.generate_evaluation_code(code)
// ObjectHandling.c:1419 - PyDict_New
__pyx_t_1 = PyDict_New(); // 创建空字典
if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_1);
/* ==================== 第2步:创建方法并添加到字典 ==================== */
// 来源: CythonFunction.c:1335 - __Pyx_CyFunction_New
// 来源: ObjectHandling.c:1423 - __Pyx_SetNameInClass
// 创建 __init__ 方法
__pyx_t_2 = __Pyx_CyFunction_New(
&__pyx_mdef_4cert_11Certificate_1__init__, // PyMethodDef*
0, // flags
__pyx_n_s_Certificate___init__, // qualname
NULL, // closure
__pyx_n_s_cert, // module name
__pyx_d, // globals
NULL // code
);
if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
// 把 __init__ 添加到类字典
if (__Pyx_SetNameInClass(__pyx_t_1, __pyx_n_s_init, __pyx_t_2) < 0)
__PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
// 创建 verify 方法
__pyx_t_2 = __Pyx_CyFunction_New(
&__pyx_mdef_4cert_11Certificate_3verify, // PyMethodDef*
0,
__pyx_n_s_Certificate_verify,
NULL, __pyx_n_s_cert, __pyx_d, NULL
);
if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 14, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
// 把 verify 添加到类字典
if (__Pyx_SetNameInClass(__pyx_t_1, __pyx_n_s_verify, __pyx_t_2) < 0)
__PYX_ERR(0, 14, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* ==================== 第3步:调用 type() 创建类 ==================== */
// 来源: ExprNodes.py:10180 - __Pyx_Py3ClassCreate
// 来源: ObjectHandling.c:1257
__pyx_t_2 = __Pyx_Py3ClassCreate(
(PyObject*)&PyType_Type, // metaclass = type
__pyx_n_s_Certificate, // name = "Certificate"
__pyx_empty_tuple, // bases = ()
__pyx_t_1, // dict = {__init__: func, verify: func}
NULL, // mkw = NULL
0, // calculate_metaclass
0 // allow_py2_metaclass
);
if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* ==================== 第4步:注册到模块字典 ==================== */
// 来源: Nodes.py:5364 - self.target.generate_assignment_code
if (PyDict_SetItem(__pyx_d, __pyx_n_s_Certificate, __pyx_t_2) < 0)
__PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* ==================== 第1步:创建类字典 ==================== */
// 来源: Nodes.py:5334 - self.dict.generate_evaluation_code(code)
// ObjectHandling.c:1419 - PyDict_New
__pyx_t_1 = PyDict_New(); // 创建空字典
if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_1);
/* ==================== 第2步:创建方法并添加到字典 ==================== */
// 来源: CythonFunction.c:1335 - __Pyx_CyFunction_New
// 来源: ObjectHandling.c:1423 - __Pyx_SetNameInClass
// 创建 __init__ 方法
__pyx_t_2 = __Pyx_CyFunction_New(
&__pyx_mdef_4cert_11Certificate_1__init__, // PyMethodDef*
0, // flags
__pyx_n_s_Certificate___init__, // qualname
NULL, // closure
__pyx_n_s_cert, // module name
__pyx_d, // globals
NULL // code
);
if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
// 把 __init__ 添加到类字典
if (__Pyx_SetNameInClass(__pyx_t_1, __pyx_n_s_init, __pyx_t_2) < 0)
__PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
// 创建 verify 方法
__pyx_t_2 = __Pyx_CyFunction_New(
&__pyx_mdef_4cert_11Certificate_3verify, // PyMethodDef*
0,
__pyx_n_s_Certificate_verify,
NULL, __pyx_n_s_cert, __pyx_d, NULL
);
if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 14, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
// 把 verify 添加到类字典
if (__Pyx_SetNameInClass(__pyx_t_1, __pyx_n_s_verify, __pyx_t_2) < 0)
__PYX_ERR(0, 14, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* ==================== 第3步:调用 type() 创建类 ==================== */
// 来源: ExprNodes.py:10180 - __Pyx_Py3ClassCreate
// 来源: ObjectHandling.c:1257
__pyx_t_2 = __Pyx_Py3ClassCreate(
(PyObject*)&PyType_Type, // metaclass = type
__pyx_n_s_Certificate, // name = "Certificate"
__pyx_empty_tuple, // bases = ()
__pyx_t_1, // dict = {__init__: func, verify: func}
NULL, // mkw = NULL
0, // calculate_metaclass
0 // allow_py2_metaclass
);
if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
/* ==================== 第4步:注册到模块字典 ==================== */
// 来源: Nodes.py:5364 - self.target.generate_assignment_code
if (PyDict_SetItem(__pyx_d, __pyx_n_s_Certificate, __pyx_t_2) < 0)
__PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
1. PyImport_ImportModule("pyd_B")
→ 获取 pyd_B 的模块对象
2. PyObject_GetAttr(pyd_B_module, "some_func")
→ 获取函数对象(是个 PyCFunction)
3. __Pyx_PyObject_FastCall(func_obj, args, nargs)
→ pyd_A 内部的包装函数
4. 检查 func_obj 的类型和标志
├─ 如果是 METH_O: 直接调用 func_obj->ml_meth(self, arg)
│ 这个指针指向 pyd_B 里的 C 函数
│
└─ 否则: PyVectorcall_Function() 或 PyObject_Call()
5. pyd_B 里的 __pyx_pw_some_func() 执行
1. PyImport_ImportModule("pyd_B")
→ 获取 pyd_B 的模块对象
2. PyObject_GetAttr(pyd_B_module, "some_func")
→ 获取函数对象(是个 PyCFunction)
3. __Pyx_PyObject_FastCall(func_obj, args, nargs)
→ pyd_A 内部的包装函数
4. 检查 func_obj 的类型和标志
├─ 如果是 METH_O: 直接调用 func_obj->ml_meth(self, arg)
│ 这个指针指向 pyd_B 里的 C 函数
│
└─ 否则: PyVectorcall_Function() 或 PyObject_Call()
5. pyd_B 里的 __pyx_pw_some_func() 执行
"PyObject_Call",
"PyObject_CallObject",
"PyObject_CallNoArgs",
"PyObject_CallOneArg",
"_PyObject_Call"
"PyObject_Call",
"PyObject_CallObject",
"PyObject_CallNoArgs",
"PyObject_CallOneArg",
"_PyObject_Call"
Cython 函数
源码位置
作用
__Pyx_PyObject_Call
ObjectHandling.c:2544
通用调用 (func, args, kwargs)
__Pyx_PyObject_FastCall
ObjectHandling.c:2268
快速调用 (vectorcall)
__Pyx_PyObject_CallNoArg
ObjectHandling.c:2626
无参数调用
__Pyx_PyObject_CallOneArg
ObjectHandling.c:2613
单参数调用
__Pyx_PyObject_Call2Args
ObjectHandling.c:2600
双参数调用
__Pyx_PyObject_FastCallMethod
ObjectHandling.c:2321
调用方法
static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(
PyObject *func,
PyObject *arg,
PyObject *kw
) {
ternaryfunc call = Py_TYPE(func)->tp_call;
if (unlikely(!call))
return PyObject_Call(func, arg, kw);
Py_EnterRecursiveCall(" while calling a Python object");
result = (*call)(func, arg, kw);
Py_LeaveRecursiveCall();
return result;
}
static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(
PyObject *func,
PyObject *arg,
PyObject *kw
) {
ternaryfunc call = Py_TYPE(func)->tp_call;
if (unlikely(!call))
return PyObject_Call(func, arg, kw);
Py_EnterRecursiveCall(" while calling a Python object");
result = (*call)(func, arg, kw);
Py_LeaveRecursiveCall();
return result;
}
#define __Pyx_PyObject_FastCall(func, args, nargs) \
__Pyx_PyObject_FastCallDict(func, args, (size_t)(nargs), NULL)
static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(
PyObject *func,
PyObject *const *args,
size_t nargs,
PyObject *kwargs
) {
if (nargs == 0 && kwargs == NULL) {
if (__Pyx_CyOrPyCFunction_Check(func) && (flags & METH_NOARGS))
return __Pyx_PyObject_CallMethO(func, NULL);
}
if (nargs == 1 && kwargs == NULL) {
if (__Pyx_CyOrPyCFunction_Check(func) && (flags & METH_O))
return __Pyx_PyObject_CallMethO(func, args[0]);
}
vectorcallfunc f = __Pyx_PyVectorcall_Function(func);
if (f) return f(func, args, nargs, NULL);
return __Pyx_PyObject_Call(func, args_tuple, kwargs);
}
#define __Pyx_PyObject_FastCall(func, args, nargs) \
__Pyx_PyObject_FastCallDict(func, args, (size_t)(nargs), NULL)
static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(
PyObject *func,
PyObject *const *args,
size_t nargs,
PyObject *kwargs
) {
if (nargs == 0 && kwargs == NULL) {
if (__Pyx_CyOrPyCFunction_Check(func) && (flags & METH_NOARGS))
return __Pyx_PyObject_CallMethO(func, NULL);
}
if (nargs == 1 && kwargs == NULL) {
if (__Pyx_CyOrPyCFunction_Check(func) && (flags & METH_O))
return __Pyx_PyObject_CallMethO(func, args[0]);
}
vectorcallfunc f = __Pyx_PyVectorcall_Function(func);
if (f) return f(func, args, nargs, NULL);
return __Pyx_PyObject_Call(func, args_tuple, kwargs);
}
static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) {
PyObject *arg[2] = {NULL, NULL};
return __Pyx_PyObject_FastCall(func, arg + 1, 0 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET);
}
static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) {
PyObject *arg[2] = {NULL, NULL};
return __Pyx_PyObject_FastCall(func, arg + 1, 0 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET);
}
static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) {
PyObject *args[2] = {NULL, arg};
return __Pyx_PyObject_FastCall(func, args + 1, 1 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET);
}
static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) {
PyObject *args[2] = {NULL, arg};
return __Pyx_PyObject_FastCall(func, args + 1, 1 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET);
}
传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2026-1-26 17:01
被BitWarden编辑
,原因: