长亭百川云 - 文章详情

Cython 二进制库逆向分析全面指南

山石网科安全技术研究院

156

2024-07-18

众所周知,Python 类题目最难的一类是使用 cythonhttps://github.com/cython/cython)工具将 Python 代码转成 C 代码并编译成二进制库。此类题目比单纯使用 Python/C API 编写 C 代码编译成二进制库的方式更加复杂,cython 工具作为一类通用工具,为了提高稳健性,其在转换时会对 Python 代码做额外处理(包括对引用计数的调整),从而干扰我们的逆向。当然,也正是因为它是通用工具,其整体框架和对类似 Python 字节码的处理也有一定规律,当我们熟悉这个规律以后,手撕 cython 二进制库就非常轻松了。

初探 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
进行简单拼凑,其他的操作(如赋值、运算、循环等)也可以在阅读伪代码时通过排除非关键代码的情况下得出。

从 cython 中识别关键代码

将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 代码。

cython 中的运算

那么,如果 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);  
  // ...  
}

cython 符号表恢复

当然,还有一些出题人会将二进制 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
模块的引用。

这些符号表的恢复理论上可以使用脚本自动化恢复,便于手动逆向,当然对不同功能的代码段(如定义函数、调用函数等)大致熟悉了以后,直接手撕也是比较简单的。

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2