首页 > 编程语言 >【Python逆向】深入Pyd逆向

【Python逆向】深入Pyd逆向

时间:2024-12-21 11:30:51浏览次数:3  
标签:pyx 逆向 Python global PyObject int __ Pyd mstate

pyd 文件是编译生成的 Python 扩展模块,是类似 so、dll 的一种 Python 文件。
pyd 文件无法像 pyc文件那样恢复源码,只能通过逆向手段去恢复逻辑。

一、理解pyd文件

1.1 编译pyd

自己编译一个 pyd 保留符号来看。

test.py

import base64
key = [ord(i) for i in "key"]
res = "GVhilbQktqU="
def check(flag):
    if len(flag) != 16:
        return False
    flag = int(flag, 16)
    flag = flag.to_bytes(8, 'big')
    flag = encrypt(flag, key)
    flag = base64.b64encode(bytes(flag)).decode()
    if flag == res:
        return True
    return False
def encrypt(ptext, key):
    S = list(range(256))
    j = 0
    out = []
    for i in range(256):
        j = (j + S[i] + key[i % len(key)]) % 256
        S[i], S[j] = S[j], S[i]
    i = j = 0
    for t in ptext:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        out.append(t ^ S[(S[i] + S[j]) % 256])
    return out
def logic():
    flag = input("Enter flag: ")
    if check(flag):
        print("Correct flag!")
    else:
        print("Wrong flag!")
__test__ = {}

setup.py

from setuptools import setup, Extension
from Cython.Build import cythonize
ext_modules = [
    Extension(
        name = "test",
        sources = ["test.py"],
        extra_compile_args = ["/Zi"],
        extra_link_args = ["/DEBUG"]
    )
]
setup(
    name = "test",
    ext_modules = cythonize(ext_modules, annotate=True),
)

编译:

python .\setup.py build_ext --inplace

在当前目录就会生成 pyd 和对应的 pcb。

二、分析pyd

2.1 全局变量与常量

在分析 pyd 逻辑之前,需要关注这几个函数(全局变量相关):

1、__Pyx_CreateStringTabAndInitStrings
2、__Pyx_InitCachedBuiltins
3、__Pyx_InitCachedConstants
4、__Pyx_InitConstants
5、__Pyx_InitGlobals
6、PyInit_test

这些函数会设置一些全局变量、常量在 _pyx_mstate_global。

__Pyx_CreateStringTabAndInitStrings

这里设置了字符串:

1、程序逻辑本身的字符串;
2、变量名;
3、模块属性;

一般特征为 _pyx_mstate_global ->__pyx_n_s_ + 字符串 为获取目标字符串。
通过其实现字符串的使用、变量的获取、属性的获取。
__Pyx_InitCachedBuiltins

这里获取了程序逻辑会用到的 python 自带的函数:

v6 = _Pyx_PyObject_GetAttrStrNoError(_pyx_mstate_global->__pyx_b, pyx_n_s_input);
_pyx_builtin_input = v6;

__Pyx_InitConstants

设置一些常数,程序要使用时直接 _pyx_mstate_global->__pyx_int_value

v0 = (_object *)PyLong_FromLong(0LL);
_pyx_mstate_global->__pyx_int_0 = v0;
v1 = (_object *)PyLong_FromLong(1LL);
_pyx_mstate_global->__pyx_int_1 = v1;
v2 = (_object *)PyLong_FromLong(8LL);
_pyx_mstate_global->__pyx_int_8 = v2;

__Pyx_InitCachedConstants

同样设置了一些常数,但更多的好像是 tuple,方便了函数传参。

v0 = (_object *)PyTuple_Pack(2LL, _pyx_mstate_global->__pyx_int_8, _pyx_mstate_global->__pyx_n_s_big);
_pyx_mstate_global->__pyx_tuple_ = v0;

PyInit_test

通过一路跳转找到 __pyx_pymod_exec_test


这里会进行一些初始化(库的导入、全局变量初始化...)。
_pyx_mstate_global->__pyx_d 创建了一个空的字典,以便全局变量的读取:

Dict = PyModule_GetDict();
_pyx_mstate_global->__pyx_d = (_object *)Dict;

一些常量的设置:

v26 = (_object *)PyLong_FromLong(256LL)
v27 = _pyx_mstate_global
_pyx_mstate_global->__pyx_int_256 = v26

设置 builtins 的一些 python 自带函数:

v7 = (_object *)PyImport_AddModule("builtins");
_pyx_mstate_global->__pyx_b = v7;
pyx_n_s_input = _pyx_mstate_global->__pyx_n_s_input;
_pyx_builtin_input = v33;

导入 base64 库:

pyx_n_s_base64 = _pyx_mstate_global->__pyx_n_s_base64;
Module = (_object *)PyImport_GetModule(pyx_n_s_base64);
p_ob_refcnt = &Module->ob_refcnt;
PyDict_SetItem(_pyx_mstate_global->__pyx_d, _pyx_mstate_global->__pyx_n_s_base64, p_ob_refcnt)

生成 key 的操作:key = [ord(i) for i in "key"]

p_ob_refcnt = (_QWORD *)PyList_New(0LL);
Iter = PyObject_GetIter(_pyx_mstate_global->__pyx_n_s_key);
v2 = (_QWORD *)Iter;
v46 = *(__int64 (__fastcall **)(_QWORD *))(*(_QWORD *)(Iter + 8) + 224LL);
while (1) {
    v47 = (_object *)v46(v2);
    v3 = v47;
    if ( !v47 )
      break;
    v50 = _pyx_7genexpr__pyx_v_4test_i;
    v51 = v47;
    _pyx_7genexpr__pyx_v_4test_i = v47;
    ob_refcnt_low = LOBYTE(v51[2].ob_refcnt);
    v59 = (_object *)PyLong_FromLong(ob_refcnt_low);
    PyList_Append(p_ob_refcnt, v59);
}
PyDict_SetItem(_pyx_mstate_global->__pyx_d, _pyx_mstate_global->__pyx_n_s_key, p_ob_refcnt);

设置 res = "GVhilbQktqU="

PyDict_SetItem(
    _pyx_mstate_global->__pyx_d,
    _pyx_mstate_global->__pyx_n_s_res,
    _pyx_mstate_global->__pyx_kp_s_GVhilbQktqU
)

设置 check 函数:

v66 = _Pyx_CyFunction_New(
    &_pyx_mdef_4test_1check,
    v64,
    _pyx_mstate_global->__pyx_n_s_check,
    v65,
    _pyx_mstate_global->__pyx_n_s_test,
    _pyx_mstate_global->__pyx_d,
    _pyx_mstate_global->__pyx_codeobj__8
);
PyDict_SetItem(_pyx_mstate_global->__pyx_d, _pyx_mstate_global->__pyx_n_s_check, v66)

通过 _pyx_mdef_4test_1check找到 _pyx_pw_4test_1check

_pyx_pw_4test_1check 会调用 _pyx_pf_4test_check

_pyx_pf_4test_check 是 check 的函数逻辑。

分析逻辑

通过上面的铺垫,现在开始分析一下测试的三个函数。
logic:

通过以下三个函数的片段可知,程序逻辑:flag = input("Enter flag: ")

_Pyx_CreateStringTabAndInitStrings:
__pyx_string_tab[1].p = &_pyx_mstate_global->__pyx_kp_s_Enter_flag;
__pyx_string_tab[1].s = "Enter flag: ";
_Pyx_InitCachedConstants:
v6 = (_object *)PyTuple_Pack(1LL, v5->__pyx_kp_s_Enter_flag, v4);
v8 = _pyx_mstate_global;
_pyx_mstate_global->__pyx_tuple__3 = v6;
_pyx_pf_4test_4logic:
v5 = _Pyx_PyObject_Call(_pyx_builtin_input, _pyx_mstate_global->__pyx_tuple__3, a3);

执行调用 check(flag):

pyx_n_s_check = _pyx_mstate_global->__pyx_n_s_check;
AttrStrNoError = (_object *)_PyDict_GetItem_KnownHash(
    _pyx_mstate_global->__pyx_d,
    pyx_n_s_check,
    pyx_n_s_check[1].ob_type
);
v13 = _pyx_mstate_global->__pyx_d;
__pyx_callargs[1] = v6;
v20 = _Pyx_PyObject_FastCallDict(AttrStrNoError, &__pyx_callargs[-v16 + 1], (unsigned int)(v16 + 1), pyx_d);

判断 check 结果:

if check(flag):
        print("Correct flag!")
    else:
        print("Wrong flag!")
IsTrue = v20 == (_object *)_Py_TrueStruct;
if ( IsTrue )
{
    v24 = _Pyx_PyObject_Call(_pyx_builtin_print, _pyx_mstate_global->__pyx_tuple__4, v21);
}
else
{
    v24 = _Pyx_PyObject_Call(_pyx_builtin_print, _pyx_mstate_global->__pyx_tuple__5, v21);
}

check:

if len(flag) != 16: return False
_object *__fastcall _pyx_pf_4test_check(_object *__pyx_v_flag, _object *__pyx_self) {
    v3 = PyObject_Size(__pyx_self);
    if ( v3 != 16 )
        goto LABEL_4;
    ...
}
flag = int(flag, 16):
v8 = (_object *)PyTuple_New(2LL, v4);
++v2->ob_refcnt;
v11 = _pyx_mstate_global;
v8[1].ob_type = (_typeobject *)v2;
++v11->__pyx_int_16->ob_refcnt;
v8[2].ob_refcnt = (__int64)v11->__pyx_int_16;
v12 = _Pyx_PyObject_Call(PyLong_Type, v8, v9);
flag = flag.to_bytes(8, 'big'):
_Pyx_InitCachedConstants:
v0 = (_object *)PyTuple_Pack(2LL, _pyx_mstate_global->__pyx_int_8, _pyx_mstate_global->__pyx_n_s_big);
_pyx_mstate_global->__pyx_tuple_ = v0;
_pyx_pf_4test_check:
Attr = (_object *)PyObject_GetAttr(v12, pyx_n_s_to_bytes);
v19 = _Pyx_PyObject_Call(Attr, _pyx_mstate_global->__pyx_tuple_, v18);
flag = encrypt(flag, key):
v24 = _pyx_mstate_global->__pyx_n_s_encrypt;
Item_KnownHash = (_object *)_PyDict_GetItem_KnownHash(_pyx_mstate_global->__pyx_d, v24, v24[1].ob_type);
AttrStrNoError = Item_KnownHash;
v30 = v21->__pyx_n_s_key;
BuiltinName = (_object *)_PyDict_GetItem_KnownHash(v21->__pyx_d, v30, v30[1].ob_type);
pyx_d = _pyx_mstate_global->__pyx_d;
_pyx_dict_version = (unsigned __int64)_pyx_mstate_global->__pyx_d[1].ob_type;
_pyx_dict_cached_value = BuiltinName;
v33 = 0;
__pyx_callargs[0] = p_ob_base;
__pyx_callargs[1] = v19;
__pyx_callargs[2] = BuiltinName;
v36 = _Pyx_PyObject_FastCallDict(AttrStrNoError, &__pyx_callargs[-v33 + 1], (unsigned int)(v33 + 2), v20);
flag = base64.b64encode(bytes(flag)).decode():
v42 = _pyx_mstate_global->__pyx_n_s_base64;
v43 = (_object *)_PyDict_GetItem_KnownHash(_pyx_mstate_global->__pyx_d, v42, v42[1].ob_type);
AttrStrNoError = v43;
pyx_n_s_b64encode = v39->__pyx_n_s_b64encode;v47 = PyObject_GetAttr(AttrStrNoError, pyx_n_s_b64encode);
v49 = (_object *)v47;
v52 = 0LL;
v53 = 0;
args[1] = v52;
v74 = v50;
AttrStrNoError = _Pyx_PyObject_FastCallDict(v49, &__pyx_callargs[-v53 - 1], (unsigned int)(v53 + 1), v51);
pyx_n_s_decode = _pyx_mstate_global->__pyx_n_s_decode;
v58 = PyObject_GetAttr(AttrStrNoError, pyx_n_s_decode);
v49 = (_object *)v58;
v65 = _Pyx_PyObject_FastCallDict(v49, &args[-v61], v62, v59);
if flag == res: return True
else: return False
v2 = v65;
v69 = _pyx_mstate_global->__pyx_n_s_res;
AttrStrNoError = (_object *)_PyDict_GetItem_KnownHash(_pyx_mstate_global->__pyx_d, v69, v69[1].ob_type);
v49 = (_object *)PyObject_RichCompare(v2, AttrStrNoError, 2LL);
IsTrue = _Pyx_PyObject_IsTrue(v49);
if ( !IsTrue )
{
    LABEL_4:
    v5 = ++_Py_FalseStruct;
    goto LABEL_157;
}
v5 = ++_Py_TrueStruct;
LABEL_157:
return (_object *)v5;

encrypt:

S = list(range(256)):
v9 = _Pyx_PyObject_Call(
    _pyx_builtin_range, 
    _pyx_mstate_global->__pyx_tuple__2, 
    __pyx_self
);
pyx_int_1 = (_object *)PySequence_List(v9);
j = 0
out = []
for i in range(256):
        j = (j + S[i] + key[i % len(key)]) % 256
        S[i], S[j] = S[j], S[i]

v13 = pyx_int_1;
obj = pyx_int_1;
pyx_int_0 = v16->__pyx_int_0;
v17 = PyList_New(0LL);
v64 = (_QWORD *)v17;
for ( i = 0; i < 256; ++i )
{
    v19 = PyLong_FromLong((unsigned int)i);
    v20 = (_object *)v19;
    v6 = v19;
    Item = _Pyx_PyObject_GetItem(v13, v20);
    pyx_int_1 = Item;
    v9 = (_object *)PyNumber_Add(pyx_int_0, Item);
    v23 = PyObject_Size(__pyx_self);
    v24 = PyLong_FromSsize_t(v23);
    pyx_int_1 = (_object *)v24;
    v4 = (_object *)PyNumber_Remainder(v6, v24);
    pyx_int_1 = _Pyx_PyObject_GetItem(__pyx_self, v4);
    v4 = (_object *)PyNumber_Add(v9, pyx_int_1);
    v27 = _Pyx_PyInt_RemainderObjC(v4, _pyx_mstate_global->__pyx_int_256, v25, v26, v61);
    pyx_int_1 = _Pyx_PyObject_GetItem(obj, v27);
    v4 = _Pyx_PyObject_GetItem(obj, (_object *)v6);
    PyObject_SetItem(obj, v6, pyx_int_1);
    PyObject_SetItem(obj, pyx_int_0, v4);
}
for t in ptext:
    i = (i + 1) % 256
    j = (j + S[i]) % 256
    S[i], S[j] = S[j], S[i]
    out.append(t ^ S[(S[i] + S[j]) % 256])
v32 = _pyx_mstate_global;
v33 = (_QWORD *)v6;
v6 = (__int64)v32->__pyx_int_0;
v34 = _pyx_mstate_global;
v35 = v34->__pyx_int_0;
Iter = PyObject_GetIter(__pyx_v_key);
v39 = *(__int64 (__fastcall **)(_QWORD))(*(_QWORD *)(Iter + 8) + 224LL);
v66 = v39;
while ( 2 ) {
    if ( !v39 ) {
        pyx_int_1 = _pyx_mstate_global->__pyx_int_1;
        v44 = *(_object **)(v6 + 8);
        v48 = _Pyx_PyInt_RemainderObjC(pyx_int_1, _pyx_mstate_global->__pyx_int_256, v30, v31, v61);
        v50 = _Pyx_PyObject_GetItem(obj, v48);pyx_int_1 = (_object *)PyNumber_Add(pyx_int_0, v50);
        v53 = _Pyx_PyInt_RemainderObjC(pyx_int_1, _pyx_mstate_global->__pyx_int_256, v51, v52, v62);
        pyx_int_0 = v53;
        v55 = v53;
        v9 = _Pyx_PyObject_GetItem(obj, v53);
        pyx_int_1 = _Pyx_PyObject_GetItem(obj, (_object *)v6);
        PyObject_SetItem(obj, v6, v9);
        PyObject_SetItem(obj, v55, pyx_int_1);
        pyx_int_1 = _Pyx_PyObject_GetItem(obj, (_object *)v6);
        v56 = _Pyx_PyObject_GetItem(obj, v55);
        v5 = (_object *)PyNumber_Add(pyx_int_1, v56);
        v9 = _Pyx_PyInt_RemainderObjC(v5, _pyx_mstate_global->__pyx_int_256, v57, v58, v63);
        v5 = _Pyx_PyObject_GetItem(obj, v9);
        v9 = (_object *)PyNumber_Xor(v65, v5);
        PyList_Append(v64, v9);
    }
}

实践分析

这里用 ciscb ccb 比赛的 Cython 题目进行实践。
exe 解包后,反编译 pyc 得到源码:

import ez
flag = input()
flag1 = list(flag)
value = []
b = 0
ck = 0
if len(flag1) == 24:
    for i in range(0, len(flag1), 4):
        b = (ord(flag1[i]) << 16) | (ord(flag1[i + 1]) << 8) | ord(flag1[i + 2]) | ord(flag1[i + 3])
        value.append(b)
    key = [102, 108, 97, 103]
    flag_encrypt = []
    for i in range(0, 6, 2):
        print(f"{value[i]:x} {value[i + 1]:x}")
        res = ez.encrypt(value[i], value[i + 1], key)
        flag_encrypt.append(res)
    ck = ez.check(flag_encrypt)
    if ck == 3:
        print('yes!!!,you get right flag')
    else:
        print('wrong!!!')
else:
    print('wrong!!!')

主要逻辑在 ez.pyd,但这加密方式一眼 tea。
bindiff 用 test.pyd恢复符号,对着看去分析。
根据 ez.encrypt 字符串来找引用函数,一般是第二个。
分析代码如下(省略一些不影响逻辑分析的):

__int64 __fastcall _pyx_pf_4test_2encrypt(
    __int64 a1, __int64 arg_v0, __int64 arg_v1, __int64 arg_key
){
    v12 = pyx_mstate_global->__pyx_n_s_c_uint32_; // c_uint32
    AttrStrNoError = (_QWORD *)PyDict_GetItem_KnownHash(pyx_mstate_global->__pyx_d, v12, v12[1].ob_type);
    v13 = 0;
    v102[0] = arg_v0;
    BuiltinName = (_QWORD *)_Pyx_PyObject_FastCallDict((__int64)AttrStrNoError, &v102[-v13], (unsigned int)(v13 + 1));

    v21 = pyx_mstate_global->__pyx_n_s_c_uint32_;
    Item_KnownHash = (_QWORD *)PyDict_GetItem_KnownHash(pyx_mstate_global->__pyx_d, v21, v21[1].ob_type);
    v102[1] = Item;
    v103[0] = arg_v1;
    AttrStrNoError = (_QWORD *)_Pyx_PyObject_FastCallDict((__int64)Item_KnownHash, &v103[-v22], (unsigned int)(v22 + 1));

    v29 = v25->__pyx_n_s_c_uint32_;
    v30 = (_QWORD *)PyDict_GetItem_KnownHash(v25->__pyx_d, v29, v29[1].ob_type);
    v25 = pyx_mstate_global;
    BuiltinName = v30;
    pyx_int_0 = v25->__pyx_int_0;
    v103[1] = (__int64)v31;
    v101 = _Pyx_PyObject_FastCallDict((__int64)BuiltinName, &pyx_int_0 - v32, v32 + 1);
    v35 = (_QWORD *)v101;
    AttrStrNoError = (_QWORD *)v101;
    v99 = pyx_int_1415865428;
    v105 = 0;
    v18 = 11;
    do
    {
        pyx_n_s_value = pyx_mstate_global->__pyx_n_s_value;
        Attr = PyObject_GetAttr(Item_KnownHash, pyx_n_s_value);
        AttrStrNoError = (_QWORD *)Attr;
        v42 = pyx_mstate_global->__pyx_n_s_value;
        v44 = PyObject_GetAttr(v26, v42);
        BuiltinName = (_QWORD *)v44;
        Item_KnownHash = (_QWORD *)_Pyx_PyInt_LshiftObjC(v44, pyx_mstate_global->__pyx_int_value_3);

        v45 = pyx_mstate_global->__pyx_n_s_value;
        v46 = *(__int64 (__fastcall **)(_QWORD *, _object *))(v26[1] + 144i64);
        v47 = PyObject_GetAttr(v26, v45);
        BuiltinName = (_QWORD *)v47;
        Item = _Pyx_PyInt_RshiftObjC(v47, pyx_mstate_global->__pyx_int_value_6, 6i64);

        BuiltinName = (_QWORD *)PyNumber_Xor(Item_KnownHash, Item);

        v48 = pyx_mstate_global->__pyx_n_s_value;
        v49 = *(__int64 (__fastcall **)(_QWORD *, _object *))(v26[1] + 144i64);
        v50 = PyObject_GetAttr(v26, v48);
        Item = v50;
        Item_KnownHash = (_QWORD *)PyNumber_Add(BuiltinName, v50);

        v51 = pyx_mstate_global->__pyx_n_s_value;
        v53 = PyObject_GetAttr(v101, v51);
        v54 = pyx_mstate_global->__pyx_n_s_value;
        v56 = PyObject_GetAttr(v101, v54);
        v58 = PyNumber_And(v56, pyx_mstate_global->__pyx_int_value_3);
        v5 = (_QWORD *)v58;
        BuiltinName = (_QWORD *)_Pyx_PyObject_GetItem(arg_key, v5);
        v5 = (_QWORD *)PyNumber_Add(Item, BuiltinName);

        BuiltinName = (_QWORD *)PyNumber_Xor(Item_KnownHash, v5);

        v5 = (_QWORD *)PyNumber_InPlaceAdd(AttrStrNoError, BuiltinName);

        v59 = pyx_mstate_global->__pyx_n_s_value;
        v61 = PyObject_SetAttr(v98, v59, v5);
        v62 = pyx_mstate_global->__pyx_n_s_value;
        v64 = PyObject_GetAttr(v101, v62);
        BuiltinName = (_QWORD *)PyNumber_InPlaceAdd(v64, v99);
        v67 = PyObject_SetAttr(v101, v65, BuiltinName);


        v68 = pyx_mstate_global->__pyx_n_s_value;
        v70 = PyObject_GetAttr(v26, v68);
        BuiltinName = (_QWORD *)v70;
        v71 = pyx_mstate_global->__pyx_n_s_value;
        v73 = PyObject_GetAttr(v98, v71);
        AttrStrNoError = (_QWORD *)_Pyx_PyInt_LshiftObjC(v73, pyx_mstate_global->__pyx_int_value_3);

        v74 = pyx_mstate_global->__pyx_n_s_value;
        v76 = PyObject_GetAttr(v98, v74);
        Item_KnownHash = (_QWORD *)_Pyx_PyInt_RshiftObjC(v76, pyx_mstate_global->__pyx_int_value_6, 6i64);
        v5 = (_QWORD *)PyNumber_Xor(AttrStrNoError, Item_KnownHash);

        v77 = pyx_mstate_global->__pyx_n_s_value;
        v79 = PyObject_GetAttr(v98, v77);
        Item_KnownHash = (_QWORD *)v79;
        AttrStrNoError = (_QWORD *)PyNumber_Add(v5, v79);
        v80 = pyx_mstate_global->__pyx_n_s_value;
        v82 = PyObject_GetAttr(v101, v80);
        Item_KnownHash = (_QWORD *)v82;
        v83 = pyx_mstate_global->__pyx_n_s_value;
        v85 = PyObject_GetAttr(v101, v83);
        Item = _Pyx_PyInt_RshiftObjC(v85, pyx_mstate_global->__pyx_int_4, 11i64);
        v87 = PyNumber_And(Item, pyx_mstate_global->__pyx_int_value_3);
        Item = _Pyx_PyObject_GetItem(arg_key, v5);
        v5 = (_QWORD *)PyNumber_Add(Item_KnownHash, Item);
        Item = PyNumber_Xor(AttrStrNoError, v5);
        v5 = (_QWORD *)PyNumber_InPlaceAdd(BuiltinName, Item);
        v88 = pyx_mstate_global->__pyx_n_s_value;
        v90 = PyObject_SetAttr(v26, v88, v5);
        Item_KnownHash = v98;
        ++v105;
    }
    while ( v105 < 64 );
    v91 = pyx_mstate_global->__pyx_n_s_value;
    v93 = PyObject_GetAttr(v98, v91);
    v94 = pyx_mstate_global->__pyx_n_s_value;
    v96 = PyObject_GetAttr(v26, v94);
    Item = v96;
    v97 = PyTuple_New(2i64);
    *(_QWORD *)(v97 + 24) = v5;
    *(_QWORD *)(v97 + 32) = Item;
    return v37;
}

还原 python 代码:

def encrypt(v0, v1, key):
    v0 = ctypes.c_uint32(v0)
    v1 = ctypes.c_uint32(v1)
    num = ctypes.c_uint32(0)
    for i in range(64):
        t1 = v1.value + (v1.value  << 3 ^ v1.value >> 6)
        t2 = num.value + key[num.value & 3]
        t3 = t1 ^ t2
        v0.value = v0.value + t3
        num.value = num.value + 1415865428
        t1 = v0.value + (v0.value << 3 ^ v0.value >> 6)
        t2 = num.value + key[num.value >> 11 & 3]
        t3 = t1 ^ t2
        v1.value = v1.value + t3
    return v0.value, v1.value

还有一个 ez.check,直接使用了 ez.data 与加密结果进行比较。
因此直接解密:

def decrypt(v0, v1, key):
    num = 0
    delta = 0x54646454
    for i in range(64):
        num += delta
        num = num & 0xFFFFFFFF
    for i in range(64):
        t1 = (v0 + ((v0 << 3) ^ (v0 >> 6))) & 0xFFFFFFFF
        t2 = (num + key[(num >> 11) & 3]) & 0xFFFFFFFF
        t3 = t1 ^ t2
        v1 = v1 - t3
        v1 &= 0xFFFFFFFF
        num = num - delta
        num = num & 0xFFFFFFFF
        t1 = (v1 + ((v1 << 3) ^ (v1 >> 6))) & 0xFFFFFFFF
        t2 = (num + key[num & 3]) & 0xFFFFFFFF
        t3 = t1 ^ t2
        v0 = v0 - t3
        v0 &= 0xFFFFFFFF
    return v0, v1
key = [102, 108, 97, 103]
result = [2129084917, 4147024244, 2971480309, 1606961219, 710575902, 4012634395]
flag = []
for i in range(3):
    v0, v1 = result[i * 2], result[i * 2 + 1]
    flag += decrypt(v0, v1, key)
flag_str = ""
for i in flag:
    flag_str += i.to_bytes(4, "big").decode()
print(flag_str)

来源

https://xz.aliyun.com/t/16800?time__1311=Gui%3DGIfG7KGNDQUPBK0Q5SbctcED

标签:pyx,逆向,Python,global,PyObject,int,__,Pyd,mstate
From: https://www.cnblogs.com/o-O-oO/p/18620575

相关文章

  • 【Python GUI 编程】tkinter :Ttk 组合框 Combobox
    在本文中,将介绍如何创建一个tkinterCombobox组合框小部件,该小部件允许用户从一组值中选择一个值。Combobox组合框小部件是新增的Ttk主题小部件,是Entry文本框和Listbox列表框的组合。除了允许在一组值中选择一个值外,它还允许输入自定义值。创建组合框要创建组合框小部......
  • 使用 pickle 模块在 Python 中进行 pickling 和 unpickling
    pickle—Python对象序列化python 是一种广泛使用的通用高级编程语言。在本文中,我们将学习使用pickle模块在Python中进行pickling和unpickling。PythonPickle模块pickle模块用于实现二进制协议,用于序列化和反序列化Python对象结构。Pickli......
  • 【Python GUI 编程】tkinter:Ttk 选项卡 Notebook
    在本文中,将介绍如何使用TkinterNotebook小部件创建选项卡。Notebook是由TkinterTtk模块引入的强大小部件。允许开发者创建包含多个选项卡的界面,每个选项卡可以包含不同的内容。创建Notebook小部件,请使用如下构造函数:notebook=ttk.Notebook(master,**kw)添加选项卡......
  • 使用Python进行量化交易,关键知识点有哪些?
    炒股自动化:申请官方API接口,散户也可以python炒股自动化(0),申请券商API接口python炒股自动化(1),量化交易接口区别Python炒股自动化(2):获取股票实时数据和历史数据Python炒股自动化(3):分析取回的实时数据和历史数据Python炒股自动化(4):通过接口向交易所发送订单Python炒股自动化(5):......
  • 【2024最新】基于Python+Mysql+django的公务员考试信息管理系统Lw+PPT
    作者:计算机搬砖家开发技术:SpringBoot、php、Python、小程序、SSM、Vue、MySQL、JSP、ElementUI等,“文末源码”。专栏推荐:SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码精品专栏:Java精选实战项目源码、Python精选实战项目源码、大数据精选实战项目源码......
  • 【2024最新】基于Python+Mysql+django的宾馆管理系统Lw+PPT
    作者:计算机搬砖家开发技术:SpringBoot、php、Python、小程序、SSM、Vue、MySQL、JSP、ElementUI等,“文末源码”。专栏推荐:SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码精品专栏:Java精选实战项目源码、Python精选实战项目源码、大数据精选实战项目源码......
  • 【2024最新】基于Python+Mysql+django的高校教室管理系统Lw+PPT
    作者:计算机搬砖家开发技术:SpringBoot、php、Python、小程序、SSM、Vue、MySQL、JSP、ElementUI等,“文末源码”。专栏推荐:SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码精品专栏:Java精选实战项目源码、Python精选实战项目源码、大数据精选实战项目源码......
  • Django:一个王者级Web开发Python框架
    大家好啊!今天我要和大家分享Python世界中的"网站开发利器"——Django框架。它就像是一个全能的网站建筑师,不仅自带了后台管理系统、数据库接口、用户认证等功能,还能帮我们处理各种安全问题。使用Django,我们可以快速搭建一个功能完善的网站。无论你是想做个人博客,还是想开发企业......
  • python3:访问apple server api
     一,安装用到的库:(venv)liuhongdi@lhdpc:/data/work/python/xiaoqu$pip3installPyJWTCollectingPyJWTDownloadingPyJWT-2.10.1-py3-none-any.whl.metadata(4.0kB)DownloadingPyJWT-2.10.1-py3-none-any.whl(22kB)Installingcollectedpackages:PyJWTSucces......
  • AI开发:支持向量机(SVM)鸢尾花模型入门教程- Python 机器学习
    最近接触了一些数据分析的任务,越来越多地听到支持向量机(SVM),之前我们也一起学习过 AI开发:支持向量机(SVM)入门教程-Python机器学习今天我们再由浅入深的地来重温和学习这个AI算法,以便我们进一步掌握如何熟悉和使用这一AI大杀器。SVM用在哪里 --文本分类垃圾邮件过滤:通......