IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    CPython逆向实战分析

    dingjiacan@antvsion.com发表于 2024-12-17 09:57:11
    love 0

    Python代码转换为C代码的时候,将会大大增加框架代码量。

    基础教程 | Cython 官方文档中文版(gitbooks.io)

    1、正向py->c

    先有正向,再有逆向

    pip install cython

    写一个简单的pyx文件

    .pyx 文件是由 Cython 编程语言 "编写" 而成的 Python 扩展模块源代码文件

    print("hello")

    写一个 setup.py文件

    from distutils.core import setup
    from Cython.Build import cythonize

    setup(
       ext_modules = cythonize("test.pyx")
    )

    使用命令开始编译

    python setup.py build_ext --inplace

    image

    生成如下文件

    image

    打开test.c发现有几千行代码

    image

    单纯的一行python代码,生成为c代码就几千行

    调用so文件

    image

    2、逆向分析

    2.1 字符串类型

    _Pyx_CreateStringTabAndInitStrings

    全局字符串赋值一般在_Pyx_CreateStringTabAndInitStrings中,该函数中使用的字符串定义数组形如:

    typedef struct {
        PyObject **p;
        const char *s;
        const Py_ssize_t n;
        const char* encoding;
        const char is_unicode;
        const char is_str;
        const char intern;
    } __Pyx_StringTabEntry;

    而字符串是通过__Pyx_StringTabEntry的数组进行初始化的,也就是说当我们在该函数中看到以下伪代码时:

    v8 = _mm_unpacklo_epi64(&qword_28A98, "AttributeError");
    v9 = 15LL;
    v10 = 0LL;
    v11 = 0x100;
    v12 = 1;

    就代表这是一个{&qword_28A98, "AttributeError", 15, 0, 1, 0, 1}的__Pyx_StringTabEntry,也就是说qword_28A98中将要初始化一个内容是"AttributeError"的字符串对象的地址,在后续调用中,调用到AttributeError字符串的地方都会用&qword_28A98指代



    2.2 整数类型

    _pyx_pymod_exec_chal

    qword_29170 = PyLong_FromLong(113LL, v9, v244, v245);
    if ( qword_29170 )

    qword_29170中将存储一个值为113的整数类型的Python对象。

    qword_29600 = PyLong_FromString("2654435769", 0LL, 0LL);
    if ( qword_29600 )

    大数会用PyLong_FromString函数来初始化,这里qword_29600中将存储一个值为2654435769的整数类型的Python对象,后续用到2654435769的地方将使用qword_29600。

    2.3 import写法

    v539 = _Pyx_ImportDottedModule_constprop_0(random);
    if ( PyDict_SetItem(_pyx_mstate_global_static, random, v539) < 0 )
    {

    导入``random``模块,同``import random

    3、实战分析

    这里提供一道自己出的题目,采用了R**加密,流程很简单。

    让我们开干

    image

    把提供的so文件拖进IDA中

    image

    而且这个函数 _Pyx_CreateStringTabAndInitStrings() 非常大,不能反编译

    目前不知道这个函数的加密,我们先打印其相关的属性,看看能不能找到蛛丝马迹

    import test
    dir(test)

    image

    发现是R**加密,这样逻辑就清晰了

    所以现在的目标是获得R**的秘钥和密文咯,假设R**没有魔改

    刚才我们在函数_Pyx_CreateStringTabAndInitStrings 找到了非常类似密文的值

    9d7422eabf8baf369c09121f02e940099d9c6b538d88e30aac08

    但是没有找到 秘钥,说明秘钥可能就不是字符串,而是byte类型!

    我们先搜索R**相关函数

    image

    image

    发现代码非常多,暂时先不去分析R**算法

    看看哪里调用了我们的R**算法

    image

    函数:_pyx_pymod_exec_test

    image

    但是byte类型怎么初始化呢?

    我们编写一个demo,然后反编译去查看初始化方式即可

    demo.pyx

    key = b'mykekekeke'
    en_flag = b'12312312312312'

    demo_setup.pyx

    from distutils.core import setup
    from Cython.Build import cythonize

    setup(
       ext_modules = cythonize("demo.pyx")
    )

    运行命令

    python demo_setup.py build_ext --inplace

    先看看c文件

    image

    还是很清晰的,直接IDA分析so文件

    image

    发现byte类型也存储在函数_Pyx_CreateStringTabAndInitStrings

    所以我们再翻阅一下,成功找到类似key的代码

    image

    DASCTF{cpython_is_so_easy}

    image

      




沪ICP备19023445号-2号
友情链接