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

众所周知,Python 类题目最难的一类是使用 cython(https://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行……!

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

足以证明其框架代码和处理代码之多。
实际上真正执行了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), 0010},
    // ...
    {&__pyx_n_s_print, __pyx_k_print, sizeof(__pyx_k_print), 0011},
    // ...
  };
  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(01, __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(01, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    if (PyDict_SetItem(__pyx_d, __pyx_n_s_i, __pyx_t_3) < 0) __PYX_ERR(01, __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(02, __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(02, __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(01, __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(02, __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(02, __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(03, __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(03, __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(03, __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(03, __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(04, __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(04, __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(04, __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(04, __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(04, __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 = [0x111111110x22222222]
k = [0x333333330x444444440x555555550x66666666]
v1, v2 = [ctypes.c_uint32(x) for x in v]
tea_sum = ctypes.c_uint32(0)
delta = 0x9e3779b9
for n in range(320-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(01, __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(01, __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(03, __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(03, __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(03, __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(03, __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(04, __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(04, __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(04, __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(04, __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(04, __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(04, __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(05, __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(05, __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(05, __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(05, __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(05, __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(05, __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(05, __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(05, __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(05, __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(05, __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(05, __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(05, __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(05, __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(05, __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(05, __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(05, __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(05, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_4);
    __pyx_t_3 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(05, __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(05, __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(05, __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(06, __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(06, __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(06, __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(06, __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(07, __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(08, __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(08, __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(09, __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(09, __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(09, __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(09, __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(09, __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(09, __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(010, __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(010, __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(010, __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(010, __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, 400); if (unlikely(!__pyx_t_2)) __PYX_ERR(010, __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(010, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
// __pyx_t_8 = k[0]
    __pyx_t_8 = __Pyx_GetItemInt(__pyx_t_3, 0long1, __Pyx_PyInt_From_long, 001); if (unlikely(!__pyx_t_8)) __PYX_ERR(010, __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(010, __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(010, __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(010, __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(010, __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(010, __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(010, __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(010, __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(010, __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(010, __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, 500); if (unlikely(!__pyx_t_8)) __PYX_ERR(010, __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(010, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
// __pyx_t_2 = k[1]
    __pyx_t_2 = __Pyx_GetItemInt(__pyx_t_3, 1long1, __Pyx_PyInt_From_long, 001); if (unlikely(!__pyx_t_2)) __PYX_ERR(010, __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(010, __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(010, __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(010, __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(010, __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(010, __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(011, __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(011, __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(011, __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(011, __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, 400); if (unlikely(!__pyx_t_2)) __PYX_ERR(011, __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(011, __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, 2long1, __Pyx_PyInt_From_long, 001); if (unlikely(!__pyx_t_7)) __PYX_ERR(011, __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(011, __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(011, __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(011, __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(011, __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(011, __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(011, __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(011, __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(011, __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(011, __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, 500); if (unlikely(!__pyx_t_7)) __PYX_ERR(011, __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(011, __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, 3long1, __Pyx_PyInt_From_long, 001); if (unlikely(!__pyx_t_2)) __PYX_ERR(011, __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(011, __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(011, __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(011, __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(011, __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(011, __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(012, __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(012, __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(012, __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(012, __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(012, __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(012, __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(012, __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(012, __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 = [286331153572662306]
k = [858993459114532461214316557651717986918]
sequence = [ctypes.c_uint32(x) for x in v]
v1, v2 = sequence
tea_sum = ctypes.c_uint32(0)
delta = 2654435769
for n in range(320-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_slotsPy_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}, // 全局操作执行函数
  {0NULL}
};
#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模块的引用。
这些符号表的恢复理论上可以使用脚本自动化恢复,便于手动逆向,当然对不同功能的代码段(如定义函数、调用函数等)大致熟悉了以后,直接手撕也是比较简单的。


原文始发于微信公众号(山石网科安全技术研究院):Cython 二进制库逆向分析全面指南

版权声明:admin 发表于 2024年7月16日 上午8:48。
转载请注明:Cython 二进制库逆向分析全面指南 | CTF导航

相关文章