众所周知,Python 类题目最难的一类是使用 cython(https://github.com/cython/cython)工具将 Python 代码转成 C 代码并编译成二进制库。此类题目比单纯使用 Python/C API 编写 C 代码编译成二进制库的方式更加复杂,cython 工具作为一类通用工具,为了提高稳健性,其在转换时会对 Python 代码做额外处理(包括对引用计数的调整),从而干扰我们的逆向。当然,也正是因为它是通用工具,其整体框架和对类似 Python 字节码的处理也有一定规律,当我们熟悉这个规律以后,手撕 cython 二进制库就非常轻松了。
先用最经典的 Hello world 做例子,保存为hello_world.py
:
print("Hello, World!")
然后调用 cython 转成 C 并编译:
cythonize -i hello_world.py
然后我们可以看到一个hello_world.c
生成在同一目录中,可以看到这个 c 文件足足有4155行……!
足以证明其框架代码和处理代码之多。
实际上真正执行了print("Hello, World!")
的代码是以下几行,作用写在了注释中:
// 字符串赋值
static const char __pyx_k_print[] = "print";
static const char __pyx_k_Hello_World[] = "Hello, World!";
// 将字符串和变量/变量名联系在一起
static int __Pyx_CreateStringTabAndInitStrings(void) {
__Pyx_StringTabEntry __pyx_string_tab[] = {
// ...
{&__pyx_kp_s_Hello_World, __pyx_k_Hello_World, sizeof(__pyx_k_Hello_World), 0, 0, 1, 0},
// ...
{&__pyx_n_s_print, __pyx_k_print, sizeof(__pyx_k_print), 0, 0, 1, 1},
// ...
};
return __Pyx_InitStrings(__pyx_string_tab);
}
// 获取print代码对象,并以arg_tuple为参数进行调用
static int __Pyx_Print(PyObject* stream, PyObject *arg_tuple, int newline) {
// ...
if (unlikely(!__pyx_print)) {
__pyx_print = PyObject_GetAttr(__pyx_b, __pyx_n_s_print);
// ...
}
// ...
result = PyObject_Call(__pyx_print, arg_tuple, kwargs);
// ...
}
// print参数只有一个的情况
static int __Pyx_PrintOne(PyObject* stream, PyObject *o) {
// ...
PyObject* arg_tuple = PyTuple_Pack(1, o);
// ...
res = __Pyx_Print(stream, arg_tuple, 1);
// ...
}
// 调用__Pyx_PrintOne(0, __pyx_kp_s_Hello_World)
static CYTHON_SMALL_CODE int __pyx_pymod_exec_hello_world(PyObject *__pyx_pyinit_module) {
// ...
if (__Pyx_PrintOne(0, __pyx_kp_s_Hello_World) < 0) __PYX_ERR(0, 1, __pyx_L1_error)
// ...
}
print 函数的调用实际上还是做了优化的,普通的函数调用会在后文中介绍。
然后也是同一个思路,在二进制库中可以找到:
int __cdecl _Pyx_CreateStringTabAndInitStrings()
{
// ...
__pyx_string_tab[1].encoding = 0LL;
*(__m128i *)&__pyx_string_tab[1].p = _mm_unpacklo_epi64(
(__m128i)(unsigned __int64)&_pyx_mstate_global_static.__pyx_kp_s_Hello_World,
(__m128i)(unsigned __int64)"Hello, World!");
// ...
__pyx_string_tab[1].n = 14LL;
*(_WORD *)&__pyx_string_tab[1].is_unicode = 256;
__pyx_string_tab[1].intern = 0;
// ...
*(__m128i *)&__pyx_string_tab[7].p = _mm_unpacklo_epi64(
(__m128i)(unsigned __int64)&_pyx_mstate_global_static.__pyx_n_s_print,
(__m128i)(unsigned __int64)"print");
__pyx_string_tab[7].n = 6LL;
__pyx_string_tab[7].encoding = 0LL;
*(_WORD *)&__pyx_string_tab[7].is_unicode = 256;
__pyx_string_tab[7].intern = 1;
// ...
}
__int64 __fastcall _pyx_pymod_exec_hello_world(PyObject *__pyx_pyinit_module)
{
// ...
if ( PyDict_GetItemString(ModuleDict, "hello_world")
|| (int)PyDict_SetItemString(v17, "hello_world", _pyx_m) >= 0 )
{
v18 = (PyObject *)PyTuple_Pack(1LL, _pyx_mstate_global_static.__pyx_kp_s_Hello_World);
if ( !v18 )
goto LABEL_42;
if ( (_pyx_print
|| (pyx_b = _pyx_mstate_global_static.__pyx_b,
(_pyx_print = (PyObject *)PyObject_GetAttr(
_pyx_mstate_global_static.__pyx_b,
_pyx_mstate_global_static.__pyx_n_s_print)) != 0LL))
&& (v19 = (PyObject *)PyObject_Call(_pyx_print, v18, 0LL), (pyx_b = v19) != 0LL) )
{
v22 = v19->ob_refcnt-- == 1;
if ( v22 )
_Py_Dealloc(v19);
v21 = 0;
}
// ...
}
Pyx_CreateStringTabAndInitStrings
和 C 源码中的大致一致;pyx_pymod_exec_hello_world
把__Pyx_PrintOne
展开编进了函数中(都被指定了__attribute((cold))
扩展的函数),这里调用主要是把__pyx_kp_s_Hello_World
即字符串"Hello, World!"
的 PyObject 打成一个 tuple,然后用PyObject_Call
调用PyObject_GetAttr
拿到的print
函数的 PyCodeObject,完成了对print("Hello, World!")
的调用。
这也是普通函数的调用流程,有一个 tuple 存非关键字参数(args)、一个 dict 存关键字参数(kwargs),然后调用PyObject_Call
,其三个参数分别是被调用函数的 PyCodeObject、args tuple、kwargs dict,这样就完成了对 Python 函数的调用。
手撕 cython 无非就是把它调用了什么 Python 函数还原出来,所以可以围绕伪代码中的PyObject_Call
进行简单拼凑,其他的操作(如赋值、运算、循环等)也可以在阅读伪代码时通过排除非关键代码的情况下得出。
将hello_world.py
改一下:
for i in range(16):
print("Hello, World!")
加了一个循环,cython 转成的 C 代码里是:
static CYTHON_SMALL_CODE int __pyx_pymod_exec_hello_world2(PyObject *__pyx_pyinit_module) {
// ...
for (__pyx_t_2 = 0; __pyx_t_2 < 16; __pyx_t_2+=1) {
__pyx_t_3 = __Pyx_PyInt_From_long(__pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_3);
if (PyDict_SetItem(__pyx_d, __pyx_n_s_i, __pyx_t_3) < 0) __PYX_ERR(0, 1, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_print, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
}
// ...
}
可以看到 Python 代码中的 for 循环转成了for (__pyx_t_2 = 0; __pyx_t_2 < 16; __pyx_t_2+=1)
。
__Pyx_PyInt_From_long
函数是将数字转化为 Python 中的数字类型的 PyObject,便于后续计算(虽然这里并没有用到 for 循环中的变量 i),PyDict_SetItem(__pyx_d, __pyx_n_s_i, __pyx_t_3)
是将转化后的数字存进变量 i 中。
然后关键的 print 还是那一句 __Pyx_PyObject_Call(__pyx_builtin_print, _pyx_tuple, NULL)
,_pyx_tuple
是在常量初始化时赋值的,跟前文一样是将被转成字符串类型 PyObject 的字符串打进 tuple 中:
static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) {
// ...
__pyx_tuple_ = PyTuple_Pack(1, __pyx_kp_s_Hello_World); if (unlikely(!__pyx_tuple_)) __PYX_ERR(0, 2, __pyx_L1_error)
// ...
}
在回到前面的 C 代码中,类似if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1, __pyx_L1_error)
的代码作用是为了避免前一个函数(如这里的__Pyx_PyInt_From_long
)失败导致 return 的结果(这里的__pyx_t_3
)为 0,从而引发空指针解引用漏洞。此类 handle error 的代码我们可以忽略。
至于__Pyx_GOTREF
和__Pyx_DECREF
等类似函数是用于调整 PyObject 的引用计数,此处由于不是重点不再细说,只要知道这是用于维稳的非关键函数即可。
再看二进制库反编译后的伪代码,提取了包含关键代码的一部分,写了一些注释以辅助理解:
__int64 __fastcall _pyx_pymod_exec_hello_world2(PyObject *__pyx_pyinit_module)
{
// ...
// 确认有没有 range,实际上 range(16) 已经在后面被融入 for 循环里了
if ( !_Pyx_GetBuiltinName(_pyx_mstate_global_static.__pyx_n_s_range)
// 获取 print 的 PyCodeObject
|| (BuiltinName = _Pyx_GetBuiltinName(_pyx_mstate_global_static.__pyx_n_s_print),
(_pyx_builtin_print = BuiltinName) == 0LL) )
// handle error,忽略
{
v27 = 2333;
v28 = 1;
goto LABEL_63;
}
// 把字符串 "Hello, World!" 打成一个 tuple
_pyx_mstate_global_static.__pyx_tuple_ = (PyObject *)PyTuple_Pack(
1LL,
_pyx_mstate_global_static.__pyx_kp_s_Hello_World);
// handle error,忽略
if ( !_pyx_mstate_global_static.__pyx_tuple_ )
{
v27 = 2335;
v28 = 1;
goto LABEL_63;
}
// for 循环开始
for ( k = 0LL; k != 16; ++k )
{
// 上文的 __Pyx_PyInt_From_long
v18 = PyLong_FromLong(k);
v19 = (_QWORD *)v18;
// handle error,忽略
if ( !v18 )
{
v27 = 2354;
LABEL_147:
code_line = 1;
goto LABEL_148;
}
// 给 i 赋值
if ( (int)PyDict_SetItem(_pyx_mstate_global_static.__pyx_d, _pyx_mstate_global_static.__pyx_n_s_i, v18) < 0 )
{
// handle error,忽略
v27 = 2356;
goto LABEL_60;
}
// 处理引用计数,忽略
v20 = (*v19)-- == 1LL;
if ( v20 )
_Py_Dealloc(v19);
// 把前面的 print 和 tuple 做引用,继续 handle error,除了赋值外都可以忽略
v21 = _pyx_builtin_print;
pyx_tuple = _pyx_mstate_global_static.__pyx_tuple_;
tp_call = _pyx_builtin_print->ob_type->tp_call;
if ( tp_call )
{
if ( (unsigned int)Py_EnterRecursiveCall(" while calling a Python object") )
goto LABEL_145;
v24 = (_QWORD *)tp_call(v21, pyx_tuple, 0LL);
Py_LeaveRecursiveCall();
if ( !v24 )
{
if ( !PyErr_Occurred() )
PyErr_SetString(PyExc_SystemError, "NULL result without error in PyObject_Call");
LABEL_145:
code_line = 2;
v27 = 2363;
LABEL_148:
v28 = 1;
goto LABEL_64;
}
}
// 无 error,调用 PyObject_Call 来调用函数
else
{
v24 = (_QWORD *)PyObject_Call(_pyx_builtin_print, _pyx_mstate_global_static.__pyx_tuple_, 0LL);
// handle error,忽略
if ( !v24 )
goto LABEL_145;
}
// 处理引用计数,忽略
v20 = (*v24)-- == 1LL;
if ( v20 )
_Py_Dealloc(v24);
}
// ...
}
其中类似:
if ( !_pyx_mstate_global_static.__pyx_tuple_ ) // 或者 < 0 等
{
v27 = 2335;
v28 = 1;
goto LABEL_63;
}
结构的代码基本都是用于 handle error 的。
而类似:
v20 = (*v24)-- == 1LL;
if ( v20 )
_Py_Dealloc(v24);
结构的代码都是用来调整引用计数的,如果引用计数为 1 会将该 PyObject 销毁,这也是 Python 的 GC 机制。
所以以上两类代码都可以认为是非关键代码,不是我们逆向时需要关注的。
至此,结合注释,从上面的伪代码中很容易恢复出原 Python 代码。
那么,如果 Python 模块中用了乱七八糟的运算符呢?
我们可以先看只有一个运算符的例子:
num = 0
for i in range(16):
num ^= i
print(f"get {num}.")
再 cythonize 成 C,明显复杂了。忽略非关键代码,依旧是写了注释辅助理解,有些地方可能结合字节码看更明显:
static CYTHON_SMALL_CODE int __pyx_pymod_exec_xor(PyObject *__pyx_pyinit_module)
{
// ...
// num = 0
if (PyDict_SetItem(__pyx_d, __pyx_n_s_num, __pyx_int_0) < 0) __PYX_ERR(0, 1, __pyx_L1_error)
// 0 - 15 的 for 循环
for (__pyx_t_2 = 0; __pyx_t_2 < 16; __pyx_t_2+=1) {
// __Pyx_PyInt_From_long 创建数字类型的 PyObject
__pyx_t_3 = __Pyx_PyInt_From_long(__pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 2, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_3);
// 给 i 赋值
// STORE_NAME i
if (PyDict_SetItem(__pyx_d, __pyx_n_s_i, __pyx_t_3) < 0) __PYX_ERR(0, 2, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
// __pyx_t_3 此时为 num 的引用
// LOAD_NAME num
__Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_num); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 3, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_3);
// __pyx_t_4 此时为 i 的引用
// LOAD_NAME i
__Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_i); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 3, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_4);
// PyNumber_InPlaceXor 为替代xor,__pyx_t_5 为 __pyx_t_3 ^ __pyx_t_4 的结果,即 __pyx_t_5 = (num ^= i)
// INPLACE_XOR
__pyx_t_5 = PyNumber_InPlaceXor(__pyx_t_3, __pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 3, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_5);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
// 给 num 赋值 __pyx_t_5
// STORE_NAME num
if (PyDict_SetItem(__pyx_d, __pyx_n_s_num, __pyx_t_5) < 0) __PYX_ERR(0, 3, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
// 此时 __pyx_t_5 是一个长度为 3 的 tuple
__pyx_t_5 = PyTuple_New(3); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 4, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_5);
// __pyx_t_6 和 __pyx_t_7 的初始化赋值
__pyx_t_6 = 0;
__pyx_t_7 = 127;
__Pyx_INCREF(__pyx_kp_u_get);
// __pyx_t_6 是字符串总长度,这里加了 len("get ")
__pyx_t_6 += 4;
__Pyx_GIVEREF(__pyx_kp_u_get);
// __pyx_t_5 tuple 的索引为 0 的部分是 "get "
PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_kp_u_get);
// 此时 __pyx_t_4 为 num 的引用
// LOAD_NAME num
__Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_num); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 4, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_4);
// 将 num 转化为 f"{num}",即字符串,存入 __pyx_t_3 中
__pyx_t_3 = __Pyx_PyObject_FormatSimple(__pyx_t_4, __pyx_empty_unicode); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
// 更新 __pyx_t_7 即 MAX_CHAR
__pyx_t_7 = (__Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_3) > __pyx_t_7) ? __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_3) : __pyx_t_7;
// __pyx_t_6 是字符串总长度,这里加了 len(__pyx_t_3),即 len(f"{num}")
__pyx_t_6 += __Pyx_PyUnicode_GET_LENGTH(__pyx_t_3);
__Pyx_GIVEREF(__pyx_t_3);
// __pyx_t_5 tuple 的索引为 1 的部分是 f"{num}"
PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_3);
__pyx_t_3 = 0;
__Pyx_INCREF(__pyx_kp_u_);
// __pyx_t_6 是字符串总长度,这里加了 len(".")
__pyx_t_6 += 1;
__Pyx_GIVEREF(__pyx_kp_u_);
// __pyx_t_5 tuple 的索引为 2 的部分是 "."
PyTuple_SET_ITEM(__pyx_t_5, 2, __pyx_kp_u_);
// cython 函数 __Pyx_PyUnicode_Join,将字符串连接,第一个参数是字符串 tuple,第二个是 tuple 的长度,第三个是结果长度,第四个是 MAX_CHAR
// static PyObject* __Pyx_PyUnicode_Join(PyObject** values, Py_ssize_t value_count, Py_ssize_t result_ulength, Py_UCS4 max_char)
// 这里是将 ("get ", f"{num}", ".") 拼接起来,存入 __pyx_t_3 中
// BUILD_STRING 3
__pyx_t_3 = __Pyx_PyUnicode_Join(__pyx_t_5, 3, __pyx_t_6, __pyx_t_7); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 4, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
// __Pyx_PyObject_CallOneArg 用来调用只有一个参数的函数,这里相当于 print(__pyx_t_3) 即 print(f"get {num}.")
__pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_builtin_print, __pyx_t_3); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 4, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_5);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
}
// ...
}
换一个更复杂的运算作为例子(经典 TEA):
import ctypes
v = [0x11111111, 0x22222222]
k = [0x33333333, 0x44444444, 0x55555555, 0x66666666]
v1, v2 = [ctypes.c_uint32(x) for x in v]
tea_sum = ctypes.c_uint32(0)
delta = 0x9e3779b9
for n in range(32, 0, -1):
tea_sum.value += delta
v1.value += (v2.value << 4) + k[0] ^ v2.value + tea_sum.value ^ (v2.value >> 5) + k[1]
v2.value += (v1.value << 4) + k[2] ^ v1.value + tea_sum.value ^ (v1.value >> 5) + k[3]
print([v1.value, v2.value])
cythonize 后,解释在注释里,结合字节码看:
static CYTHON_SMALL_CODE int __pyx_pymod_exec_tea(PyObject *__pyx_pyinit_module)
{
// ...
// __Pyx_ImportDottedModule 导入模块
// IMPORT_NAME ctypes
__pyx_t_2 = __Pyx_ImportDottedModule(__pyx_n_s_ctypes, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
// STORE_NAME ctypes
if (PyDict_SetItem(__pyx_d, __pyx_n_s_ctypes, __pyx_t_2) < 0) __PYX_ERR(0, 1, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
// 此时 __pyx_t_2 为一个长度为 2 的 list
__pyx_t_2 = PyList_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
__Pyx_INCREF(__pyx_int_286331153);
__Pyx_GIVEREF(__pyx_int_286331153);
// __pyx_t_2[0] = __pyx_int_286331153 = 286331153
if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 0, __pyx_int_286331153)) __PYX_ERR(0, 3, __pyx_L1_error);
__Pyx_INCREF(__pyx_int_572662306);
__Pyx_GIVEREF(__pyx_int_572662306);
// __pyx_t_2[1] = __pyx_int_572662306 = 572662306
if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 1, __pyx_int_572662306)) __PYX_ERR(0, 3, __pyx_L1_error);
// v = __pyx_t_2
// STORE_NAME v
if (PyDict_SetItem(__pyx_d, __pyx_n_s_v, __pyx_t_2) < 0) __PYX_ERR(0, 3, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
// 此时 __pyx_t_2 为一个长度为 4 的 list
__pyx_t_2 = PyList_New(4); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
__Pyx_INCREF(__pyx_int_858993459);
__Pyx_GIVEREF(__pyx_int_858993459);
// __pyx_t_2[0] = __pyx_int_858993459 = 858993459
if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 0, __pyx_int_858993459)) __PYX_ERR(0, 4, __pyx_L1_error);
__Pyx_INCREF(__pyx_int_1145324612);
__Pyx_GIVEREF(__pyx_int_1145324612);
// __pyx_t_2[1] = __pyx_int_1145324612 = 1145324612
if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 1, __pyx_int_1145324612)) __PYX_ERR(0, 4, __pyx_L1_error);
__Pyx_INCREF(__pyx_int_1431655765);
__Pyx_GIVEREF(__pyx_int_1431655765);
// __pyx_t_2[2] = __pyx_int_1431655765 = 1431655765
if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 2, __pyx_int_1431655765)) __PYX_ERR(0, 4, __pyx_L1_error);
__Pyx_INCREF(__pyx_int_1717986918);
__Pyx_GIVEREF(__pyx_int_1717986918);
// __pyx_t_2[3] = __pyx_int_1717986918 = 1717986918
if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 3, __pyx_int_1717986918)) __PYX_ERR(0, 4, __pyx_L1_error);
// v = __pyx_t_2
// STORE_NAME v
if (PyDict_SetItem(__pyx_d, __pyx_n_s_k, __pyx_t_2) < 0) __PYX_ERR(0, 4, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
// 列表推导式,额外 PyCodeObject,也就是 dis 里的 code object <listcomp>
{
// BUILD_LIST 0
__pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 5, __pyx_L4_error)
__Pyx_GOTREF(__pyx_t_2);
// __pyx_t_3 = v
__Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_v); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 5, __pyx_L4_error)
__Pyx_GOTREF(__pyx_t_3);
// handle error
if (likely(PyList_CheckExact(__pyx_t_3)) || PyTuple_CheckExact(__pyx_t_3)) {
__pyx_t_4 = __pyx_t_3; __Pyx_INCREF(__pyx_t_4);
__pyx_t_5 = 0;
__pyx_t_6 = NULL;
} else {
// __pyx_t_4 = iter(v)
__pyx_t_5 = -1; __pyx_t_4 = PyObject_GetIter(__pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 5, __pyx_L4_error)
__Pyx_GOTREF(__pyx_t_4);
// __pyx_t_6 = NextFunc(__pyx_t_4) = next
__pyx_t_6 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_4); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 5, __pyx_L4_error)
}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
for (;;) {
if (likely(!__pyx_t_6)) {
// if list
if (likely(PyList_CheckExact(__pyx_t_4))) {
{
Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_4);
#if !CYTHON_ASSUME_SAFE_MACROS
if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 5, __pyx_L4_error)
#endif
if (__pyx_t_5 >= __pyx_temp) break;
}
#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
__pyx_t_3 = PyList_GET_ITEM(__pyx_t_4, __pyx_t_5); __Pyx_INCREF(__pyx_t_3); __pyx_t_5++; if (unlikely((0 < 0))) __PYX_ERR(0, 5, __pyx_L4_error)
#else
__pyx_t_3 = __Pyx_PySequence_ITEM(__pyx_t_4, __pyx_t_5); __pyx_t_5++; if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 5, __pyx_L4_error)
__Pyx_GOTREF(__pyx_t_3);
#endif
} else {
{
Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_4);
#if !CYTHON_ASSUME_SAFE_MACROS
if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 5, __pyx_L4_error)
#endif
if (__pyx_t_5 >= __pyx_temp) break;
}
#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
__pyx_t_3 = PyTuple_GET_ITEM(__pyx_t_4, __pyx_t_5); __Pyx_INCREF(__pyx_t_3); __pyx_t_5++; if (unlikely((0 < 0))) __PYX_ERR(0, 5, __pyx_L4_error)
#else
__pyx_t_3 = __Pyx_PySequence_ITEM(__pyx_t_4, __pyx_t_5); __pyx_t_5++; if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 5, __pyx_L4_error)
__Pyx_GOTREF(__pyx_t_3);
#endif
}
} else {
// __pyx_t_3 = next(__pyx_t_4) = next(iter(v))
__pyx_t_3 = __pyx_t_6(__pyx_t_4);
if (unlikely(!__pyx_t_3)) {
PyObject* exc_type = PyErr_Occurred();
if (exc_type) {
if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();
else __PYX_ERR(0, 5, __pyx_L4_error)
}
break;
}
__Pyx_GOTREF(__pyx_t_3);
}
__Pyx_XGOTREF(__pyx_7genexpr__pyx_v_3tea_x);
// __pyx_7genexpr__pyx_v_3tea_x = __pyx_t_3
__Pyx_DECREF_SET(__pyx_7genexpr__pyx_v_3tea_x, __pyx_t_3);
__Pyx_GIVEREF(__pyx_t_3);
__pyx_t_3 = 0;
// __pyx_t_7 = ctypes
__Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_n_s_ctypes); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 5, __pyx_L4_error)
__Pyx_GOTREF(__pyx_t_7);
// __pyx_t_8 = __pyx_t_7.c_uint32 = ctypes.c_uint32
__pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_c_uint32); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 5, __pyx_L4_error)
__Pyx_GOTREF(__pyx_t_8);
__Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
__pyx_t_7 = NULL;
__pyx_t_9 = 0;
#if CYTHON_UNPACK_METHODS
if (unlikely(PyMethod_Check(__pyx_t_8))) {
__pyx_t_7 = PyMethod_GET_SELF(__pyx_t_8);
if (likely(__pyx_t_7)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_8);
__Pyx_INCREF(__pyx_t_7);
__Pyx_INCREF(function);
__Pyx_DECREF_SET(__pyx_t_8, function);
__pyx_t_9 = 1;
}
}
#endif
{
// __pyx_t_3 = ctypes.c_uint32(__pyx_7genexpr__pyx_v_3tea_x) = ctypes.c_uint32(next(iter(v)))
PyObject *__pyx_callargs[2] = {__pyx_t_7, __pyx_7genexpr__pyx_v_3tea_x};
__pyx_t_3 = __Pyx_PyObject_FastCall(__pyx_t_8, __pyx_callargs+1-__pyx_t_9, 1+__pyx_t_9);
__Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0;
if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 5, __pyx_L4_error)
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
}
// __pyx_t_2.append(__pyx_t_3)
if (unlikely(__Pyx_ListComp_Append(__pyx_t_2, (PyObject*)__pyx_t_3))) __PYX_ERR(0, 5, __pyx_L4_error)
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
}
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_GOTREF(__pyx_7genexpr__pyx_v_3tea_x);
__Pyx_DECREF_SET(__pyx_7genexpr__pyx_v_3tea_x, Py_None);
goto __pyx_L8_exit_scope;
__pyx_L4_error:;
__Pyx_GOTREF(__pyx_7genexpr__pyx_v_3tea_x);
__Pyx_DECREF_SET(__pyx_7genexpr__pyx_v_3tea_x, Py_None);
goto __pyx_L1_error;
__pyx_L8_exit_scope:;
}
if (1) {
// sequence = __pyx_t_2
PyObject* sequence = __pyx_t_2;
Py_ssize_t size = __Pyx_PySequence_SIZE(sequence);
// check if len(sequence) == 2 else handle error
if (unlikely(size != 2)) {
if (size > 2) __Pyx_RaiseTooManyValuesError(2);
else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size);
__PYX_ERR(0, 5, __pyx_L1_error)
}
// __pyx_t_4 = sequence[0] = __pyx_t_2[0]
// __pyx_t_3 = sequence[1] = __pyx_t_2[1]
#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
__pyx_t_4 = PyList_GET_ITEM(sequence, 0);
__pyx_t_3 = PyList_GET_ITEM(sequence, 1);
__Pyx_INCREF(__pyx_t_4);
__Pyx_INCREF(__pyx_t_3);
#else
__pyx_t_4 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 5, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_4);
__pyx_t_3 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 5, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_3);
#endif
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
}
// v1 = __pyx_t_4 = __pyx_t_2[0]
if (PyDict_SetItem(__pyx_d, __pyx_n_s_v1, __pyx_t_4) < 0) __PYX_ERR(0, 5, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
// v2 = __pyx_t_3 = __pyx_t_2[1]
if (PyDict_SetItem(__pyx_d, __pyx_n_s_v2, __pyx_t_3) < 0) __PYX_ERR(0, 5, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
// __pyx_t_2 = ctypes
// LOAD_NAME ctypes
__Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_ctypes); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 6, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
// __pyx_t_3 = __pyx_t_2.__pyx_n_s_c_uint32 = ctypes.c_uint32
// LOAD_METHOD c_uint32
__pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_c_uint32); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 6, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
// __Pyx_InitCachedConstants 中有:__pyx_tuple__2 = PyTuple_Pack(1, __pyx_int_0);
// __pyx_t_2 = ctypes.c_uint32(0)
__pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_tuple__2, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 6, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
// tea_sum = __pyx_t_2 = ctypes.c_uint32(0)
// STORE_NAME tea_sum
if (PyDict_SetItem(__pyx_d, __pyx_n_s_tea_sum, __pyx_t_2) < 0) __PYX_ERR(0, 6, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
// delta = __pyx_int_2654435769 = 2654435769
if (PyDict_SetItem(__pyx_d, __pyx_n_s_delta, __pyx_int_2654435769) < 0) __PYX_ERR(0, 7, __pyx_L1_error)
// 32 - 1 的循环,for n in range(32, 0, -1)
for (__pyx_t_10 = 32; __pyx_t_10 > 0; __pyx_t_10-=1) {
// __pyx_t_2 = long(__pyx_t_10)
__pyx_t_2 = __Pyx_PyInt_From_long(__pyx_t_10); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 8, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
// n = __pyx_t_2 = long(__pyx_t_10)
// STORE_NAME n
if (PyDict_SetItem(__pyx_d, __pyx_n_s_n, __pyx_t_2) < 0) __PYX_ERR(0, 8, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
// __pyx_t_2 = __pyx_n_s_tea_sum
// LOAD_NAME tea_sum
__Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_tea_sum); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 9, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
// __pyx_t_3 = __pyx_t_2.value = tea_sum.value
// LOAD_ATTR value
__pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_value); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 9, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
// __pyx_t_2 = __pyx_n_s_delta
// LOAD_NAME delta
__Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_delta); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 9, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
// __pyx_t_4 = (__pyx_t_3 += __pyx_t_2) = (tea_sum.value += delta)
// INPLACE_ADD
__pyx_t_4 = PyNumber_InPlaceAdd(__pyx_t_3, __pyx_t_2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 9, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
// __pyx_t_2 = __pyx_n_s_tea_sum
// LOAD_NAME tea_sum
__Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_tea_sum); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 9, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
// __pyx_t_2.value = __pyx_t_4
// tea_sum.value = (tea_sum.value += delta)
// STORE_ATTR value
if (__Pyx_PyObject_SetAttrStr(__pyx_t_2, __pyx_n_s_value, __pyx_t_4) < 0) __PYX_ERR(0, 9, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
// __pyx_t_2 = __pyx_n_s_v1 = v1
__Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_v1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
// __pyx_t_4 = __pyx_t_2.value = v1.value
__pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_value); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
// __pyx_t_2 = __pyx_n_s_v2
__Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_v2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
// __pyx_t_3 = __pyx_t_2.value = v2.value
__pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_value); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
// __pyx_t_2 = __pyx_t_3 << __pyx_int_4 = v2.value << 4
__pyx_t_2 = __Pyx_PyInt_LshiftObjC(__pyx_t_3, __pyx_int_4, 4, 0, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
// __pyx_t_3 = k
__Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_k); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_3);
// __pyx_t_8 = k[0]
__pyx_t_8 = __Pyx_GetItemInt(__pyx_t_3, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_8);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
// __pyx_t_3 = __pyx_t_2 + __pyx_t_8 = (v2.value << 4) + k[0]
__pyx_t_3 = PyNumber_Add(__pyx_t_2, __pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
// __pyx_t_8 = __pyx_n_s_v2 = v2
__Pyx_GetModuleGlobalName(__pyx_t_8, __pyx_n_s_v2); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_8);
// __pyx_t_2 = __pyx_t_8.value = v2.value
__pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_8, __pyx_n_s_value); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
// __pyx_t_8 = __pyx_n_s_tea_sum = tea_sum
__Pyx_GetModuleGlobalName(__pyx_t_8, __pyx_n_s_tea_sum); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_8);
// __pyx_t_7 = __pyx_t_8.value = tea_sum.value
__pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_8, __pyx_n_s_value); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_7);
__Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
// __pyx_t_8 = __pyx_t_2 + __pyx_t_7 = v2.value + tea_sum.value
__pyx_t_8 = PyNumber_Add(__pyx_t_2, __pyx_t_7); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_8);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
// __pyx_t_7 = __pyx_t_3 ^ __pyx_t_8 = ((v2.value << 4) + k[0]) ^ (v2.value + tea_sum.value)
__pyx_t_7 = PyNumber_Xor(__pyx_t_3, __pyx_t_8); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_7);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
// __pyx_t_8 = __pyx_n_s_v2 = v2
__Pyx_GetModuleGlobalName(__pyx_t_8, __pyx_n_s_v2); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_8);
// __pyx_t_3 = __pyx_t_8.value = v2.value
__pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_8, __pyx_n_s_value); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
// __pyx_t_8 = __pyx_t_3 >> __pyx_int_5 = v2.value >> 5
__pyx_t_8 = __Pyx_PyInt_RshiftObjC(__pyx_t_3, __pyx_int_5, 5, 0, 0); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_8);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
// __pyx_t_3 = k
__Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_k); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_3);
// __pyx_t_2 = k[1]
__pyx_t_2 = __Pyx_GetItemInt(__pyx_t_3, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
// __pyx_t_3 = __pyx_t_8 + __pyx_t_2 = (v2.value >> 5) + k[1]
__pyx_t_3 = PyNumber_Add(__pyx_t_8, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
// __pyx_t_2 = __pyx_t_7 ^ __pyx_t_3 = ((v2.value << 4) + k[0]) ^ (v2.value + tea_sum.value) ^ ((v2.value >> 5) + k[1])
__pyx_t_2 = PyNumber_Xor(__pyx_t_7, __pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
// __pyx_t_3 = (__pyx_t_4 += __pyx_t_2) = (v1.value += ((v2.value << 4) + k[0]) ^ (v2.value + tea_sum.value) ^ ((v2.value >> 5) + k[1]))
__pyx_t_3 = PyNumber_InPlaceAdd(__pyx_t_4, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
// __pyx_t_2 = v1
__Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_v1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
// __pyx_t_2.value = v1.value = __pyx_t_3 = (v1.value += ((v2.value << 4) + k[0]) ^ (v2.value + tea_sum.value) ^ ((v2.value >> 5) + k[1]))
if (__Pyx_PyObject_SetAttrStr(__pyx_t_2, __pyx_n_s_value, __pyx_t_3) < 0) __PYX_ERR(0, 10, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
// __pyx_t_2 = v2
__Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_v2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
// __pyx_t_3 = __pyx_t_2.value = v2.value
__pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_value); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
// __pyx_t_2 = v1
__Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_v1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
// __pyx_t_4 = __pyx_t_2.value = v1.value
__pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_value); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
// __pyx_t_2 = __pyx_t_4 << 4 = v1.value << 4
__pyx_t_2 = __Pyx_PyInt_LshiftObjC(__pyx_t_4, __pyx_int_4, 4, 0, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
// __pyx_t_4 = k
__Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_k); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_4);
// __pyx_t_7 = __pyx_t_4[2] = k[2]
__pyx_t_7 = __Pyx_GetItemInt(__pyx_t_4, 2, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_7);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
// __pyx_t_4 = __pyx_t_2 + __pyx_t_7 = (v1.value << 4) + k[2]
__pyx_t_4 = PyNumber_Add(__pyx_t_2, __pyx_t_7); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
// __pyx_t_7 = v1
__Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_n_s_v1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_7);
// __pyx_t_2 = __pyx_t_7.value = v1.value
__pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_value); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
// __pyx_t_7 = tea_sum
__Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_n_s_tea_sum); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_7);
// __pyx_t_8 = __pyx_t_7.value = tea_sum.value
__pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_value); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_8);
__Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
// __pyx_t_7 = __pyx_t_2 + __pyx_t_8 = v1.value + tea_sum.value
__pyx_t_7 = PyNumber_Add(__pyx_t_2, __pyx_t_8); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_7);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
// __pyx_t_8 = __pyx_t_4 ^ __pyx_t_7 = ((v1.value << 4) + k[2]) ^ (v1.value + tea_sum.value)
__pyx_t_8 = PyNumber_Xor(__pyx_t_4, __pyx_t_7); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_8);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
// __pyx_t_7 = v1
__Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_n_s_v1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_7);
// __pyx_t_4 = __pyx_t_7.value = v1.value
__pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_value); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
// __pyx_t_7 = __pyx_t_4 >> 5 = v1.value >> 5
__pyx_t_7 = __Pyx_PyInt_RshiftObjC(__pyx_t_4, __pyx_int_5, 5, 0, 0); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_7);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
// __pyx_t_4 = k
__Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_k); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_4);
// __pyx_t_2 = __pyx_t_4[3] = k[3]
__pyx_t_2 = __Pyx_GetItemInt(__pyx_t_4, 3, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
// __pyx_t_4 = __pyx_t_7 + __pyx_t_2 = (v1.value >> 5) + k[3]
__pyx_t_4 = PyNumber_Add(__pyx_t_7, __pyx_t_2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
// __pyx_t_2 = __pyx_t_8 + __pyx_t_4 = ((v1.value << 4) + k[2]) ^ (v1.value + tea_sum.value) ^ ((v1.value >> 5) + k[3])
__pyx_t_2 = PyNumber_Xor(__pyx_t_8, __pyx_t_4); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
// __pyx_t_4 = (__pyx_t_3 += __pyx_t_2) = (v2.value += ((v1.value << 4) + k[2]) ^ (v1.value + tea_sum.value) ^ ((v1.value >> 5) + k[3]))
__pyx_t_4 = PyNumber_InPlaceAdd(__pyx_t_3, __pyx_t_2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
// __pyx_t_2 = v2
__Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_v2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
// __pyx_t_2.value = v2.value = __pyx_t_4 = (v2.value += ((v1.value << 4) + k[2]) ^ (v1.value + tea_sum.value) ^ ((v1.value >> 5) + k[3]))
if (__Pyx_PyObject_SetAttrStr(__pyx_t_2, __pyx_n_s_value, __pyx_t_4) < 0) __PYX_ERR(0, 11, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
}
// __pyx_t_2 = v1
__Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_v1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 12, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
// __pyx_t_4 = __pyx_t_2.value = v1.value
__pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_value); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 12, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
// __pyx_t_2 = v2
__Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_v2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 12, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
// __pyx_t_3 = __pyx_t_2.value = v2.value
__pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_value); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 12, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
// BUILD_LIST 2
__pyx_t_2 = PyList_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 12, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
__Pyx_GIVEREF(__pyx_t_4);
// __pyx_t_2[0] = __pyx_t_4 = v1.value
if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 0, __pyx_t_4)) __PYX_ERR(0, 12, __pyx_L1_error);
__Pyx_GIVEREF(__pyx_t_3);
// __pyx_t_2[1] = __pyx_t_3 = v2.value
if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 1, __pyx_t_3)) __PYX_ERR(0, 12, __pyx_L1_error);
__pyx_t_4 = 0;
__pyx_t_3 = 0;
// print([v1.value, v2.value])
__pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_print, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 12, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
// ...
}
整理一下就是:
v = [286331153, 572662306]
k = [858993459, 1145324612, 1431655765, 1717986918]
sequence = [ctypes.c_uint32(x) for x in v]
v1, v2 = sequence
tea_sum = ctypes.c_uint32(0)
delta = 2654435769
for n in range(32, 0, -1):
tea_sum.value += delta
v1.value += ((v2.value << 4) + k[0]) ^ (v2.value + tea_sum.value) ^ ((v2.value >> 5) + k[1])
v2.value += ((v1.value << 4) + k[2]) ^ (v1.value + tea_sum.value) ^ ((v1.value >> 5) + k[3])
print([v1.value, v2.value])
Python 短短 11 行的代码,转化成 C 居然有 357 行,可见其折磨程度…… XD
然而伪代码更折磨,比如列表推导式:
__int64 __fastcall _pyx_pymod_exec_tea(__int64 __pyx_pyinit_module, PyObject *pyx_n_s_name)
{
// ...
if ( _pyx_mstate_global_static.__pyx_d[1].ob_type == (PyTypeObject *)_pyx_dict_version_50 )
{
ModuleGlobalName = _pyx_dict_cached_value_49;
if ( _pyx_dict_cached_value_49 )
{
++_pyx_dict_cached_value_49->ob_refcnt;
goto LABEL_94;
}
ModuleGlobalName = _Pyx_GetBuiltinName(_pyx_mstate_global_static.__pyx_n_s_v);
}
else
{
pyx_n_s_name = (PyObject *)&_pyx_dict_version_50;
ModuleGlobalName = _Pyx__GetModuleGlobalName(
_pyx_mstate_global_static.__pyx_n_s_v,
&_pyx_dict_version_50,
&_pyx_dict_cached_value_49);
}
if ( !ModuleGlobalName )
{
v51 = 0LL;
v52 = 0LL;
v43 = 0LL;
v159 = 2699;
goto __pyx_L4_error;
}
LABEL_94:
ob_type = ModuleGlobalName->ob_type;
if ( ob_type == (PyTypeObject *)&PyList_Type || ob_type == (PyTypeObject *)&PyTuple_Type )
{
++ModuleGlobalName->ob_refcnt;
v43 = ModuleGlobalName;
v44 = 0LL;
v45 = 0LL;
goto LABEL_104;
}
Iter = PyObject_GetIter(ModuleGlobalName);
v43 = (PyObject *)Iter;
if ( !Iter )
{
v51 = 0LL;
v52 = 0LL;
v159 = 2706;
goto __pyx_L4_error;
}
v45 = -1LL;
v44 = *(__int64 (__fastcall **)(PyObject *))(*(_QWORD *)(Iter + 8) + 224LL);
if ( !v44 )
{
v51 = 0LL;
v52 = 0LL;
v159 = 2708;
goto __pyx_L4_error;
}
while ( 1 )
{
LABEL_104:
v26 = ModuleGlobalName->ob_refcnt-- == 1;
if ( v26 )
_Py_Dealloc(ModuleGlobalName);
if ( v44 )
break;
ob_refcnt = v43[1].ob_refcnt;
if ( v43->ob_type == (PyTypeObject *)&PyList_Type )
{
if ( ob_refcnt <= v45 )
goto LABEL_142;
ModuleGlobalName = (PyObject *)*(&v43[1].ob_type->ob_base.ob_base.ob_refcnt + v45++);
++ModuleGlobalName->ob_refcnt;
}
else
{
if ( ob_refcnt <= v45 )
goto LABEL_142;
ModuleGlobalName = (PyObject *)*((_QWORD *)&v43[1].ob_type + v45++);
++ModuleGlobalName->ob_refcnt;
}
LABEL_118:
v53 = _pyx_7genexpr__pyx_v_3tea_x;
_pyx_7genexpr__pyx_v_3tea_x = ModuleGlobalName;
v26 = v53->ob_refcnt-- == 1;
if ( v26 )
_Py_Dealloc(v53);
if ( _pyx_mstate_global_static.__pyx_d[1].ob_type == (PyTypeObject *)_pyx_dict_version_48 )
{
ModuleGlobalName = _pyx_dict_cached_value_47;
if ( _pyx_dict_cached_value_47 )
{
++_pyx_dict_cached_value_47->ob_refcnt;
goto LABEL_126;
}
ModuleGlobalName = _Pyx_GetBuiltinName(_pyx_mstate_global_static.__pyx_n_s_ctypes);
}
else
{
pyx_n_s_name = (PyObject *)&_pyx_dict_version_48;
ModuleGlobalName = _Pyx__GetModuleGlobalName(
_pyx_mstate_global_static.__pyx_n_s_ctypes,
&_pyx_dict_version_48,
&_pyx_dict_cached_value_47);
}
if ( !ModuleGlobalName )
{
v51 = 0LL;
v52 = 0LL;
v159 = 2758;
goto __pyx_L4_error;
}
LABEL_126:
pyx_n_s_name = _pyx_mstate_global_static.__pyx_n_s_c_uint32;
AttrStr = _Pyx_PyObject_GetAttrStr(ModuleGlobalName, _pyx_mstate_global_static.__pyx_n_s_c_uint32);
v51 = AttrStr;
if ( !AttrStr )
{
v52 = ModuleGlobalName;
v159 = 2760;
ModuleGlobalName = 0LL;
__pyx_L4_error:
__pyx_pyinit_module = (__int64)_pyx_7genexpr__pyx_v_3tea_x;
_pyx_7genexpr__pyx_v_3tea_x = (PyObject *)&Py_NoneStruct;
v26 = (*(_QWORD *)__pyx_pyinit_module)-- == 1LL;
if ( v26 )
{
valuer = v51;
_Py_Dealloc(__pyx_pyinit_module);
v51 = valuer;
}
v160 = 5;
if ( !pyx_empty_tuple )
{
LABEL_478:
if ( !ModuleGlobalName )
{
LABEL_479:
v161 = 1LL;
goto LABEL_484;
}
LABEL_482:
v26 = ModuleGlobalName->ob_refcnt-- == 1;
v161 = 1LL;
if ( v26 )
{
__pyx_pyinit_module = (__int64)ModuleGlobalName;
tbb = v51;
_Py_Dealloc(ModuleGlobalName);
v51 = tbb;
v161 = 1LL;
}
LABEL_484:
if ( v43 )
{
v26 = v43->ob_refcnt-- == 1;
if ( v26 )
{
__pyx_pyinit_module = (__int64)v43;
tbc = v51;
valuebj = v161;
_Py_Dealloc(v43);
v51 = tbc;
v161 = valuebj;
}
}
if ( v52 )
{
v26 = v52->ob_refcnt-- == 1;
if ( v26 )
{
__pyx_pyinit_module = (__int64)v52;
tbd = v51;
valuebk = v161;
_Py_Dealloc(v52);
v51 = tbd;
v161 = valuebk;
}
}
if ( v51 )
{
v26 = v51->ob_refcnt-- == 1;
if ( v26 )
{
__pyx_pyinit_module = (__int64)v51;
valuebl = v161;
_Py_Dealloc(v51);
v161 = valuebl;
}
}
if ( !_pyx_m )
{
if ( !PyErr_Occurred(__pyx_pyinit_module, pyx_n_s_name, v161) )
PyErr_SetString(PyExc_ImportError, "init tea");
return (unsigned int)-(_pyx_m == 0LL);
}
if ( !_pyx_mstate_global_static.__pyx_d || !(_DWORD)v161 )
goto LABEL_538;
v122 = _PyThreadState_UncheckedGet();
v123 = (PyThreadState *)v122;
if ( !_pyx_mstate_global_static.__pyx_cython_runtime )
goto LABEL_516;
v124 = *(PyObject **)(v122 + 88);
v125 = *(PyObject **)(v122 + 96);
*(_OWORD *)&v123->curexc_type = 0LL;
valuen = v125;
curexc_traceback = v123->curexc_traceback;
v123->curexc_traceback = 0LL;
tba = curexc_traceback;
DictPtr = (__int64 *)_PyObject_GetDictPtr();
v128 = DictPtr;
if ( DictPtr )
{
Item_KnownHash = (void *)_pyx_dict_cached_value_1;
if ( *(_QWORD *)(*DictPtr + 24) != _pyx_dict_version_2 )
{
Item_KnownHash = (void *)_PyDict_GetItem_KnownHash(
*DictPtr,
_pyx_mstate_global_static.__pyx_n_s_cline_in_traceback,
_pyx_mstate_global_static.__pyx_n_s_cline_in_traceback[1].ob_type);
if ( !Item_KnownHash )
PyErr_Clear();
v130 = *v128;
_pyx_dict_cached_value_1 = (__int64)Item_KnownHash;
_pyx_dict_version_2 = *(_QWORD *)(v130 + 24);
}
if ( !Item_KnownHash )
{
LABEL_510:
PyObject_SetAttr(
_pyx_mstate_global_static.__pyx_cython_runtime,
_pyx_mstate_global_static.__pyx_n_s_cline_in_traceback,
&Py_FalseStruct);
goto LABEL_512;
}
}
else
{
v131 = _Pyx_PyObject_GetAttrStrNoError(
_pyx_mstate_global_static.__pyx_cython_runtime,
_pyx_mstate_global_static.__pyx_n_s_cline_in_traceback);
if ( !v131 )
{
PyErr_Clear();
goto LABEL_510;
}
v207 = v131;
if ( (unsigned int)PyObject_Not(v131) )
Item_KnownHash = &Py_FalseStruct;
else
Item_KnownHash = &Py_TrueStruct;
v26 = v207->ob_refcnt-- == 1;
if ( v26 )
_Py_Dealloc(v207);
}
if ( Item_KnownHash == &Py_FalseStruct
|| Item_KnownHash != &Py_TrueStruct && (unsigned int)PyObject_Not(Item_KnownHash) )
{
LABEL_512:
v159 = 0;
}
v132 = v160;
_Pyx_ErrRestoreInState(v123, v124, valuen, tba);
if ( v159 )
LABEL_516:
v132 = -v159;
entries = _pyx_code_cache.entries;
if ( _pyx_code_cache.entries )
{
v134 = _pyx_bisect_code_objects(_pyx_code_cache.entries, _pyx_code_cache.count, v132);
if ( v135 > v134 )
{
v136 = &entries[v134];
if ( v132 == v136->code_line )
{
code_object = v136->code_object;
++v136->code_object->ob_base.ob_refcnt;
goto LABEL_529;
}
}
}
v138 = v123->curexc_traceback;
curexc_type = v123->curexc_type;
v140 = "init tea";
curexc_value = v123->curexc_value;
*(_OWORD *)&v123->curexc_type = 0LL;
valueo = v138;
v123->curexc_traceback = 0LL;
if ( v159 )
{
v142 = PyUnicode_FromFormat("%s (%s:%d)", "init tea", "tea.c", v159);
v162 = (PyObject *)v142;
if ( v142 )
{
v140 = (const char *)PyUnicode_AsUTF8(v142);
if ( v140 )
goto LABEL_524;
v26 = v162->ob_refcnt-- == 1;
if ( v26 )
_Py_Dealloc(v162);
}
LABEL_533:
if ( curexc_type )
{
v26 = curexc_type->ob_refcnt-- == 1;
if ( v26 )
_Py_Dealloc(curexc_type);
}
if ( curexc_value )
{
v26 = curexc_value->ob_refcnt-- == 1;
if ( v26 )
_Py_Dealloc(curexc_value);
}
if ( valueo )
{
v26 = valueo->ob_refcnt-- == 1;
if ( v26 )
_Py_Dealloc(valueo);
}
LABEL_538:
v147 = _pyx_m;
if ( _pyx_m )
{
v26 = _pyx_m->ob_refcnt-- == 1;
_pyx_m = 0LL;
if ( v26 )
_Py_Dealloc(v147);
}
return (unsigned int)-(_pyx_m == 0LL);
}
LABEL_524:
code_object = (PyCodeObject_0 *)PyCode_NewEmpty("tea.py", v140, v160);
if ( v162 )
{
v26 = v162->ob_refcnt-- == 1;
if ( v26 )
_Py_Dealloc(v162);
}
if ( !code_object )
goto LABEL_533;
_Pyx_ErrRestoreInState(v123, curexc_type, curexc_value, valueo);
v143 = _pyx_code_cache.entries;
if ( !_pyx_code_cache.entries )
{
v144 = (__Pyx_CodeObjectCacheEntry *)PyMem_Malloc(1024LL);
if ( v144 )
{
_pyx_code_cache.entries = v144;
v144->code_line = v132;
*(_QWORD *)&_pyx_code_cache.count = 0x4000000001LL;
v144->code_object = code_object;
++code_object->ob_base.ob_refcnt;
}
goto LABEL_529;
}
count = _pyx_code_cache.count;
v149 = _pyx_bisect_code_objects(_pyx_code_cache.entries, _pyx_code_cache.count, v132);
v150 = v149;
if ( count > v149 )
{
v151 = &v143[v149];
if ( v132 == v151->code_line )
{
v152 = v151->code_object;
v151->code_object = code_object;
v26 = v152->ob_base.ob_refcnt-- == 1;
if ( v26 )
_Py_Dealloc(v152);
goto LABEL_529;
}
}
if ( count == _pyx_code_cache.max_count )
{
v153 = count + 64;
v154 = (__Pyx_CodeObjectCacheEntry *)PyMem_Realloc(v143, 16LL * v153);
v143 = v154;
if ( v154 )
{
_pyx_code_cache.entries = v154;
_pyx_code_cache.max_count = v153;
goto LABEL_558;
}
}
else
{
LABEL_558:
v155 = _pyx_code_cache.count;
v156 = &v143[_pyx_code_cache.count];
for ( j = _pyx_code_cache.count; (int)v150 < j; v156[1] = v143[j] )
{
--j;
--v156;
}
v158 = &v143[v150];
_pyx_code_cache.count = v155 + 1;
v158->code_line = v132;
v158->code_object = code_object;
++code_object->ob_base.ob_refcnt;
}
LABEL_529:
v145 = PyFrame_New(v123, code_object, _pyx_mstate_global_static.__pyx_d, 0LL);
v146 = (_QWORD *)v145;
if ( v145 )
{
*(_DWORD *)(v145 + 100) = v160;
PyTraceBack_Here(v145);
}
v26 = code_object->ob_base.ob_refcnt-- == 1;
if ( v26 )
_Py_Dealloc(code_object);
if ( v146 )
{
v26 = (*v146)-- == 1LL;
if ( v26 )
_Py_Dealloc(v146);
}
goto LABEL_538;
}
LABEL_476:
v26 = pyx_empty_tuple->ob_refcnt-- == 1;
if ( v26 )
{
__pyx_pyinit_module = (__int64)pyx_empty_tuple;
valuebi = v51;
_Py_Dealloc(pyx_empty_tuple);
v51 = valuebi;
}
goto LABEL_478;
}
v26 = ModuleGlobalName->ob_refcnt-- == 1;
if ( v26 )
{
valuep = AttrStr;
_Py_Dealloc(ModuleGlobalName);
v51 = valuep;
}
if ( v51->ob_type == (PyTypeObject *)&PyMethod_Type )
{
p_ob_base = &v51[1].ob_type->ob_base.ob_base;
v56 = 0;
if ( p_ob_base )
{
v57 = (PyObject *)v51[1].ob_refcnt;
++p_ob_base->ob_refcnt;
++v57->ob_refcnt;
v26 = v51->ob_refcnt-- == 1;
if ( v26 )
{
valueq = p_ob_base;
_Py_Dealloc(v51);
p_ob_base = valueq;
}
v51 = v57;
v56 = 1;
}
}
else
{
p_ob_base = 0LL;
v56 = 0;
}
tb = p_ob_base;
pyx_n_s_name = (PyObject *)&__pyx_callargs[v56 ^ 1];
value = v51;
*(__m128 *)__pyx_callargs = _mm_loadh_ps((const double *)&_pyx_7genexpr__pyx_v_3tea_x);
v58 = _Pyx_PyObject_FastCallDict(v51, (PyObject **)pyx_n_s_name, v56 + 1, p_ob_base);
v51 = value;
ModuleGlobalName = v58;
if ( tb )
{
v26 = tb->ob_refcnt-- == 1;
if ( v26 )
{
_Py_Dealloc(tb);
v51 = value;
}
}
if ( !ModuleGlobalName )
{
v52 = 0LL;
v159 = 2781;
goto __pyx_L4_error;
}
v26 = v51->ob_refcnt-- == 1;
if ( v26 )
_Py_Dealloc(v51);
v47 = pyx_empty_tuple[1].ob_refcnt;
if ( v47 >= pyx_empty_tuple[2].ob_refcnt )
{
pyx_n_s_name = ModuleGlobalName;
if ( (unsigned int)PyList_Append(pyx_empty_tuple, ModuleGlobalName) )
{
v51 = 0LL;
v52 = 0LL;
v159 = 2785;
goto __pyx_L4_error;
}
}
else
{
v48 = pyx_empty_tuple[1].ob_type;
++ModuleGlobalName->ob_refcnt;
*(&v48->ob_base.ob_base.ob_refcnt + v47) = (Py_ssize_t)ModuleGlobalName;
pyx_empty_tuple[1].ob_refcnt = v47 + 1;
}
}
ModuleGlobalName = (PyObject *)v44(v43);
if ( ModuleGlobalName )
goto LABEL_118;
v50 = (PyObject *)((__int64 (*)(void))PyErr_Occurred)();
if ( v50 )
{
pyx_n_s_name = PyExc_StopIteration;
if ( PyExc_StopIteration != v50 && !_Pyx_PyErr_GivenExceptionMatches(v50, PyExc_StopIteration) )
{
v51 = 0LL;
v52 = 0LL;
v159 = 2748;
goto __pyx_L4_error;
}
PyErr_Clear();
}
LABEL_142:
v26 = v43->ob_refcnt-- == 1;
if ( v26 )
_Py_Dealloc(v43);
__pyx_pyinit_module = (__int64)_pyx_7genexpr__pyx_v_3tea_x;
_pyx_7genexpr__pyx_v_3tea_x = (PyObject *)&Py_NoneStruct;
v26 = (*(_QWORD *)__pyx_pyinit_module)-- == 1LL;
if ( v26 )
_Py_Dealloc(__pyx_pyinit_module);
v59 = pyx_empty_tuple[1].ob_refcnt;
if ( v59 != 2 )
{
if ( v59 <= 2 )
{
if ( v59 >= 0 )
{
v60 = "s";
if ( v59 == 1 )
v60 = "";
pyx_n_s_name = (PyObject *)"need more than %zd value%.1s to unpack";
__pyx_pyinit_module = PyExc_ValueError;
PyErr_Format(PyExc_ValueError, "need more than %zd value%.1s to unpack", v59, v60);
}
}
else
{
pyx_n_s_name = (PyObject *)"too many values to unpack (expected %zd)";
__pyx_pyinit_module = PyExc_ValueError;
PyErr_Format(PyExc_ValueError, "too many values to unpack (expected %zd)", 2uLL);
}
v43 = 0LL;
v159 = 2804;
v160 = 5;
goto LABEL_475;
}
v61 = (PyObject **)pyx_empty_tuple[1].ob_type;
v43 = *v61;
ModuleGlobalName = v61[1];
++(*v61)->ob_refcnt;
++ModuleGlobalName->ob_refcnt;
v26 = pyx_empty_tuple->ob_refcnt-- == 1;
if ( v26 )
_Py_Dealloc(pyx_empty_tuple);
pyx_n_s_name = _pyx_mstate_global_static.__pyx_n_s_v1;
__pyx_pyinit_module = (__int64)_pyx_mstate_global_static.__pyx_d;
if ( (int)PyDict_SetItem(_pyx_mstate_global_static.__pyx_d, _pyx_mstate_global_static.__pyx_n_s_v1, v43) < 0 )
{
v159 = 2819;
LABEL_575:
v51 = 0LL;
v52 = 0LL;
v160 = 5;
goto LABEL_478;
}
v26 = v43->ob_refcnt-- == 1;
if ( v26 )
_Py_Dealloc(v43);
pyx_n_s_name = _pyx_mstate_global_static.__pyx_n_s_v2;
__pyx_pyinit_module = (__int64)_pyx_mstate_global_static.__pyx_d;
if ( (int)PyDict_SetItem(_pyx_mstate_global_static.__pyx_d, _pyx_mstate_global_static.__pyx_n_s_v2, ModuleGlobalName) < 0 )
{
v43 = 0LL;
v159 = 2821;
goto LABEL_575;
}
v26 = ModuleGlobalName->ob_refcnt-- == 1;
if ( v26 )
_Py_Dealloc(ModuleGlobalName);
// ...
}
当然,还有一些出题人会将二进制 strip 去除符号表从而增加题目难度。
全局操作的执行一般在__pyx_moduledef_slots
中Py_mod_exec
槽的函数,__pyx_moduledef_slots
一般在PyInit中可以引用到:
__int64 PyInit_MODNAME()
{
return PyModuleDef_Init(&qword_18000F130);
}
如这里的qword_18000F130
就是__pyx_moduledef
,而__pyx_moduledef
和__pyx_moduledef_slots
的结构一般如下(假如模块名为 MODNAME ):
#if PY_MAJOR_VERSION >= 3
#if CYTHON_PEP489_MULTI_PHASE_INIT
static PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def); /*proto*/
static int __pyx_pymod_exec_MODNAME(PyObject* module); /*proto*/
static PyModuleDef_Slot __pyx_moduledef_slots[] = {
{Py_mod_create, (void*)__pyx_pymod_create},
{Py_mod_exec, (void*)__pyx_pymod_exec_MODNAME}, // 全局操作执行函数
{0, NULL}
};
#endif
#ifdef __cplusplus
namespace {
struct PyModuleDef __pyx_moduledef =
#else
static struct PyModuleDef __pyx_moduledef =
#endif
{
PyModuleDef_HEAD_INIT,
"tea",
0, /* m_doc */
#if CYTHON_PEP489_MULTI_PHASE_INIT
0, /* m_size */
#elif CYTHON_USE_MODULE_STATE
sizeof(__pyx_mstate), /* m_size */
#else
-1, /* m_size */
#endif
__pyx_methods /* m_methods */,
#if CYTHON_PEP489_MULTI_PHASE_INIT
// 这个位置的偏移能找到 __pyx_moduledef_slots
__pyx_moduledef_slots, /* m_slots */
#else
NULL, /* m_reload */
#endif
#if CYTHON_USE_MODULE_STATE
__pyx_m_traverse, /* m_traverse */
__pyx_m_clear, /* m_clear */
NULL /* m_free */
#else
NULL, /* m_traverse */
NULL, /* m_clear */
NULL /* m_free */
#endif
};
#ifdef __cplusplus
} /* anonymous namespace */
#endif
#endif
在__pyx_pymod_exec_MODNAME
中可以找到各函数对应的函数体及全局变量的赋值等,例如以下伪代码一般为函数定义的部分:
v24 = PyCMethod_New(&off_18000F110, 0i64, qword_180010330, 0i64);
v25 = (_QWORD *)v24;
if ( !v24 )
{
v10 = 5502;
goto LABEL_97;
}
if ( (int)PyDict_SetItem(qword_1800106C8, qword_180010478, v24) >= 0 )
{
v26 = (*v25)-- == 1i64;
if ( v26 )
Py_Dealloc(v25);
这里off_18000F110
就是该函数的 PyMethodDef,PyDict_SetItem
的作用就是将该函数名存到当前模块的__dict__
中,调用函数时会使用qword_180010478
进行寻找。PyMethodDef 结构体内成员为:
ctypedef struct PyMethodDef:
const char* ml_name
PyCFunction ml_meth
int ml_flags
const char* ml_doc
其中ml_name
为该函数名的字符串,ml_meth
为该函数的函数体,ml_flags
为该函数的标识,ml_doc
为该函数的文档。所以这里看off_18000F110
的内容就可以知道sub_180001000
其实是函数keyExpend
:
.data:000000018000F110 off_18000F110 dq offset aKeyexpend ; "keyExpend"
.data:000000018000F118 dq offset sub_180001000
.data:000000018000F120 dq 3
.data:000000018000F128 dq 0
同理,我们需要找模块某函数的实现,可以先搜索该函数名,然后从函数名的交叉引用找到该函数的函数体,从而进行逆向。
而调用keyExpend
函数(qword_180010478
)的部分代码:
if ( qword_180010800 != *(_QWORD *)(qword_1800106C8 + 24) )
{
// 获取函数名
v139 = qword_180010478;
Item_KnownHash = (_QWORD *)PyDict_GetItem_KnownHash(
qword_1800106C8,
qword_180010478,
*(_QWORD *)(qword_180010478 + 24));
qword_180010800 = *(_QWORD *)(qword_1800106C8 + 24);
qword_180010608 = (__int64)Item_KnownHash;
if ( Item_KnownHash )
{
++*Item_KnownHash;
goto LABEL_193;
}
if ( !PyErr_Occurred() )
{
v138 = v139;
goto LABEL_191;
}
LABEL_385:
v8 = 108;
v9 = 4591i64;
goto LABEL_408;
}
if ( qword_180010608 )
{
++*(_QWORD *)qword_180010608;
Item_KnownHash = (_QWORD *)qword_180010608;
goto LABEL_192;
}
v138 = qword_180010478;
LABEL_191:
Item_KnownHash = (_QWORD *)_Pyx_GetBuiltinName(v138);
LABEL_192:
if ( !Item_KnownHash )
goto LABEL_385;
LABEL_193:
v140 = 0i64;
v5 = 0i64;
v204 = 0i64;
v221 = 0i64;
if ( Item_KnownHash[1] == PyMethod_Type )
{
v5 = (_QWORD *)Item_KnownHash[3];
v204 = 0i64;
v221 = 0i64;
if ( v5 )
{
v141 = (_QWORD *)Item_KnownHash[2];
v142 = Item_KnownHash;
++*v5;
Item_KnownHash = v141;
++*v141;
v31 = (*v142)-- == 1i64;
if ( v31 )
Py_Dealloc(v142);
v140 = 1i64;
v204 = 1i64;
v221 = 1i64;
}
}
// 构造参数
v143 = PyTuple_New(v140 + 2, v117, v99, v98);
v3 = v143;
if ( !v143 )
{
v218 = 4622;
goto LABEL_204;
}
if ( v5 )
{
*(_QWORD *)(v143 + 24) = v5;
v5 = 0i64;
}
// 参数赋值
++*v209;
*(_QWORD *)(v143 + 8 * v221 + 24) = v209;
++*v213;
*(_QWORD *)(v143 + 8 * v204 + 32) = v213;
// _Pyx_PyObject_Call 是根据伪代码和 cython 源码对比确定的库函数
// 调用函数
v29 = _Pyx_PyObject_Call(Item_KnownHash, v143);
// GC 和 handle error
if ( !v29 )
{
v218 = 4633;
LABEL_204:
v8 = 108;
LABEL_205:
if ( !Item_KnownHash )
goto LABEL_395;
goto LABEL_393;
}
v31 = (*(_QWORD *)v3)-- == 1i64;
if ( v31 )
Py_Dealloc(v3);
v31 = (*Item_KnownHash)-- == 1i64;
v3 = 0i64;
if ( v31 )
Py_Dealloc(Item_KnownHash);
v31 = (*(_QWORD *)v29)-- == 1i64;
if ( v31 )
Py_Dealloc(v29);
v144 = v137[2];
if ( v144 == -1 )
{
v8 = 111;
v218 = 4647;
goto LABEL_398;
}
而对数字的初始化如以下代码:
qword_180010640 = PyLong_FromLong(0i64);
if ( qword_180010640 )
{
qword_1800107C8 = PyLong_FromLong(1i64);
if ( qword_1800107C8 )
{
qword_180010850 = PyLong_FromLong(2i64);
if ( qword_180010850 )
{
qword_180010730 = PyLong_FromLong(3i64);
if ( qword_180010730 )
{
qword_1800105A8 = PyLong_FromLong(4i64);
if ( qword_1800105A8 )
{
qword_180010898 = PyLong_FromLong(7i64);
if ( qword_180010898 )
{
qword_180010590 = PyLong_FromLong(8i64);
if ( qword_180010590 )
{
qword_180010878 = PyLong_FromLong(9i64);
if ( qword_180010878 )
{
qword_1800106E8 = PyLong_FromLong(10i64);
if ( qword_1800106E8 )
{
qword_1800105D0 = PyLong_FromLong(14i64);
if ( qword_1800105D0 )
{
qword_1800107D8 = PyLong_FromLong(16i64);
if ( qword_1800107D8 )
{
qword_1800107E8 = PyLong_FromLong(22i64);
if ( qword_1800107E8 )
{
qword_180010600 = PyLong_FromLong(24i64);
if ( qword_180010600 )
{
qword_180010748 = PyLong_FromLong(46i64);
if ( qword_180010748 )
{
qword_180010610 = PyLong_FromLong(52i64);
if ( qword_180010610 )
{
qword_1800108B0 = PyLong_FromLong(58i64);
// ...
因为还叠加了错误处理,所以伪代码看起来更庞大和复杂,而这些全局变量也没有 symbol,也为后续的逆向增加了难度,比如:
v45 = qword_180010780;
v46 = (_QWORD *)qword_1800107B0;
v47 = (_QWORD *)qword_1800106E0;
v48 = (_QWORD *)qword_1800107B8;
++*(_QWORD *)qword_180010780;
**(_QWORD **)(v44 + 24) = v45;
v49 = qword_180010628;
++*(_QWORD *)qword_180010628;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 8i64) = v49;
v50 = qword_180010758;
++*(_QWORD *)qword_180010758;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 16i64) = v50;
++*v46;
v51 = (_QWORD *)qword_1800107C0;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 24i64) = v46;
++*v51;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 32i64) = v51;
v52 = qword_180010550;
++*(_QWORD *)qword_180010550;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 40i64) = v52;
v53 = qword_180010640;
++*(_QWORD *)qword_180010640;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 48i64) = v53;
v54 = qword_1800105D0;
++*(_QWORD *)qword_1800105D0;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 56i64) = v54;
v55 = qword_180010768;
++*(_QWORD *)qword_180010768;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 64i64) = v55;
v56 = qword_1800106B0;
++*(_QWORD *)qword_1800106B0;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 72i64) = v56;
v57 = qword_1800106E8;
++*(_QWORD *)qword_1800106E8;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 80i64) = v57;
v58 = qword_180010858;
++*(_QWORD *)qword_180010858;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 88i64) = v58;
v59 = qword_1800107A0;
++*(_QWORD *)qword_1800107A0;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 96i64) = v59;
v60 = qword_180010590;
++*(_QWORD *)qword_180010590;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 104i64) = v60;
++*v47;
v61 = (_QWORD *)qword_180010638;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 112i64) = v47;
++*v48;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 120i64) = v48;
++*v61;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 128i64) = v61;
v62 = qword_180010648;
++*(_QWORD *)qword_180010648;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 136i64) = v62;
v63 = qword_180010678;
++*(_QWORD *)qword_180010678;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 144i64) = v63;
v64 = qword_180010610;
++*(_QWORD *)qword_180010610;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 152i64) = v64;
v65 = qword_1800107E8;
++*(_QWORD *)qword_1800107E8;
v66 = (_QWORD *)qword_180010788;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 160i64) = v65;
v67 = qword_1800108D8;
++*(_QWORD *)qword_1800108D8;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 168i64) = v67;
v68 = qword_1800107F8;
++*(_QWORD *)qword_1800107F8;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 176i64) = v68;
v69 = qword_180010740;
++*(_QWORD *)qword_180010740;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 184i64) = v69;
v70 = qword_180010830;
++*(_QWORD *)qword_180010830;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 192i64) = v70;
++*v66;
v71 = (_QWORD *)qword_180010718;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 200i64) = v66;
++*v71;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 208i64) = v71;
v72 = qword_1800107A8;
++*(_QWORD *)qword_1800107A8;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 216i64) = v72;
v73 = qword_180010658;
++*(_QWORD *)qword_180010658;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 224i64) = v73;
v74 = qword_1800108B0;
++*(_QWORD *)qword_1800108B0;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 232i64) = v74;
v75 = qword_1800105E8;
++*(_QWORD *)qword_1800105E8;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 240i64) = v75;
v76 = qword_1800108A0;
++*(_QWORD *)qword_1800108A0;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 248i64) = v76;
v77 = qword_180010690;
++*(_QWORD *)qword_180010690;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 256i64) = v77;
++*v47;
v78 = (_QWORD *)qword_180010840;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 264i64) = v47;
++*v66;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 272i64) = v66;
++*v78;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 280i64) = v78;
++*v46;
v79 = (_QWORD *)qword_180010850;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 288i64) = v46;
++*v79;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 296i64) = v79;
v80 = qword_180010728;
++*(_QWORD *)qword_180010728;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 304i64) = v80;
v81 = qword_1800105E0;
++*(_QWORD *)qword_1800105E0;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 312i64) = v81;
v82 = qword_1800106B8;
++*(_QWORD *)qword_1800106B8;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 320i64) = v82;
v83 = qword_180010698;
++*(_QWORD *)qword_180010698;
v214 = (_QWORD *)v44;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 328i64) = v83;
v84 = qword_180010630;
++*(_QWORD *)qword_180010630;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 336i64) = v84;
v85 = qword_180010570;
++*(_QWORD *)qword_180010570;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 344i64) = v85;
++*v48;
v86 = (_QWORD *)qword_180010818;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 352i64) = v48;
++*v46;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 360i64) = v46;
++*v86;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 368i64) = v86;
v87 = qword_1800105A0;
++*(_QWORD *)qword_1800105A0;
*(_QWORD *)(*(_QWORD *)(v44 + 24) + 376i64) = v87;
这里面的全局变量其实都是数字,不过因为去除符号表所以不明显。
而对 Module 的引用类似:
v15 = (_QWORD *)PyImport_AddModule("builtins");
qword_180010860 = (__int64)v15;
if ( !v15 )
{
v10 = 5459;
goto LABEL_97;
}
++*v15;
qword_180010860
其实就是对builtins
模块的引用。
这些符号表的恢复理论上可以使用脚本自动化恢复,便于手动逆向,当然对不同功能的代码段(如定义函数、调用函数等)大致熟悉了以后,直接手撕也是比较简单的。