SCTF2024-ez_cython出题分享
SCTF2024-ez_cython出题分享
出题思路
因为cython本身的语言特性,类似于加了一个强混淆,就将关键的魔改xxtea加密算法和密钥和密文打包在生成的pyd文件中
这里我将key的获取留了一个后门,封包成一个类的get,可以通过import库的导入进行分析
ez_cython的wp
1.解包
简单的解包得到pyc文件
反编译pyc文件(线上方便点)
可以看到这里是导入的一个库,关键的check函数是sub14514函数(在cython打包的pyd文件库中,无符号表),所以逆向分析pyd文件即可
2.传参
避免验证的时候一次传入一个参数的麻烦
import cy
def str_hex(input_str):
return [ord(char) for char in input_str]
def main():
while True:
input_str = input("input:")
if input_str == '':
break
guess_hex = str_hex(input_str)
if cy.sub14514(guess_hex):
print(f"ok")
break
else:
print(f"no")
if __name__ == '__main__':
main()
可以列出所有的导入库
import pefile
def import_check(pyd_file):
pe = pefile.PE(pyd_file)
for entry in pe.DIRECTORY_ENTRY_IMPORT:
print(f"Module: {entry.dll.decode('utf-8')}")
for imp in entry.imports:
print(f" Function: {imp.name.decode('utf-8') if imp.name else None}")
import_check('cy.cp38-win_amd64.pyd')
Module: python38.dll
Function: PyErr_SetString
Function: PyObject_GetIter
Function: PyNumber_Add
Function: _Py_CheckRecursiveCall
Function: PyDict_Next
Function: PyErr_Format
Function: PyDict_Type
Function: PyObject_RichCompare
Function: PyTuple_Type
Function: _Py_FalseStruct
Function: PyFloat_Type
Function: PyModule_NewObject
Function: PyMethod_Type
Function: PyLong_Type
Function: PyType_IsSubtype
Function: PyNumber_Subtract
Function: PyExc_OverflowError
Function: PyCode_NewWithPosOnlyArgs
Function: _Py_Dealloc
Function: PyTuple_GetItem
Function: PyImport_GetModuleDict
Function: PyModule_GetDict
Function: PyObject_Free
Function: PyErr_ExceptionMatches
Function: PyNumber_And
Function: PyObject_GC_Del
Function: PyObject_ClearWeakRefs
Function: PyObject_Not
Function: PyUnicode_AsUTF8
Function: PyUnicode_FromFormat
Function: PyList_New
Function: PyNumber_Rshift
Function: PyImport_AddModule
Function: PyType_Ready
Function: PyObject_GetAttrString
Function: PyErr_Clear
Function: PyTuple_GetSlice
Function: PyUnicode_Decode
Function: _PyObject_GenericGetAttrWithDict
Function: PyDict_SetItem
Function: PyDict_New
Function: PyUnicode_Type
Function: _PyDict_GetItem_KnownHash
Function: PyNumber_Index
Function: PyMem_Free
Function: PyExc_StopIteration
Function: PyList_Type
Function: PyErr_NoMemory
Function: PyDict_GetItemString
Function: PyObject_GetItem
Function: PyModuleDef_Init
Function: PyObject_GC_Track
Function: PyBytes_FromStringAndSize
Function: PyNumber_Long
Function: PyUnicode_Compare
Function: PyExc_TypeError
Function: PyNumber_Lshift
Function: PyMem_Realloc
Function: PyObject_IsTrue
Function: PyExc_NameError
Function: PyTuple_Pack
Function: _PyUnicode_Ready
Function: PyMem_Malloc
Function: PyExc_IndexError
Function: PyExc_ImportError
Function: _Py_TrueStruct
Function: PyExc_SystemError
Function: PyObject_SetItem
Function: _PyObject_GC_New
Function: PyNumber_TrueDivide
Function: PyUnicode_FromString
Function: PyObject_Size
Function: PyObject_Call
Function: PyType_Type
Function: PyUnicode_FromStringAndSize
Function: _PyObject_GetDictPtr
Function: PyExc_AttributeError
Function: PyFloat_FromDouble
Function: PyLong_FromLongLong
Function: PyDict_Size
Function: PyDict_SetItemString
Function: PyLong_FromString
Function: PyTuple_New
Function: _Py_NoneStruct
Function: PyObject_GetAttr
Function: Py_GetVersion
Function: PyInterpreterState_GetID
Function: PyNumber_Xor
Function: PyObject_Hash
Function: PyObject_GC_UnTrack
Function: PyLong_FromLong
Function: PyObject_SetAttrString
Function: PyMethod_New
Function: PyExc_RuntimeError
Function: _PyThreadState_UncheckedGet
Function: PyTraceBack_Here
Function: PyObject_GenericGetAttr
Function: PyLong_FromSsize_t
Function: PyErr_Occurred
Function: PyImport_ImportModuleLevelObject
Function: _PyDict_SetItem_KnownHash
Function: PyLong_AsSsize_t
Function: PyFrame_New
Function: PyExc_RuntimeWarning
Function: PyErr_WarnEx
Function: PyErr_GivenExceptionMatches
Function: PyCode_NewEmpty
Function: _Py_CheckRecursionLimit
Function: PyThreadState_Get
Function: PyOS_snprintf
Function: PyCFunction_Type
Function: PyUnicode_InternFromString
Function: PyObject_SetAttr
Function: PyList_Append
Function: PyBaseObject_Type
Module: KERNEL32.dll
Function: GetSystemTimeAsFileTime
Function: RtlCaptureContext
Function: RtlLookupFunctionEntry
Function: RtlVirtualUnwind
Function: UnhandledExceptionFilter
Function: SetUnhandledExceptionFilter
Function: GetCurrentProcess
Function: TerminateProcess
Function: IsProcessorFeaturePresent
Function: QueryPerformanceCounter
Function: GetCurrentProcessId
Function: GetCurrentThreadId
Function: InitializeSListHead
Function: DisableThreadLibraryCalls
Function: IsDebuggerPresent
Module: VCRUNTIME140.dll
Function: strrchr
Function: __C_specific_handler
Function: memset
Function: memcpy
Function: __std_type_info_destroy_list
Function: memcmp
Module: api-ms-win-crt-runtime-l1-1-0.dll
Function: _initterm_e
Function: _seh_filter_dll
Function: _configure_narrow_argv
Function: _initialize_narrow_environment
Function: _initialize_onexit_table
Function: _initterm
Function: _execute_onexit_table
Function: _cexit
根据这里的xor,shift,可以大致猜测是一个tea家族
3.DATA
在ida中逆向分析pyd文件,可以发现对于key的获取
也可以找到key的生成,DATA异或0xAA
key:
83, 121, 67, 49, 48, 86, 101, 82, 102, 48, 82, 86, 101, 114
常量定义
可以通过注⼊cy类,获取运算过程(学到了)
import cy
class Symbol:
def __init__(self, name):
self.name = name
def __repr__(self):
return self.name
def __rshift__(self, other):
if isinstance(other, Symbol):
expression = Symbol(f"({self.name} >> {other.name})")
else:
expression = Symbol(f"({self.name} >> {other})")
return expression
def __lshift__(self, other):
if isinstance(other, Symbol):
expression = Symbol(f"({self.name} << {other.name})")
else:
expression = Symbol(f"({self.name} << {other})")
return expression
def __rxor__(self, other):
if isinstance(other, Symbol):
expression = Symbol(f"({self.name} ^ {other.name})")
else:
expression = Symbol(f"({self.name} ^ {other})")
return expression
def __xor__(self, other):
if isinstance(other, Symbol):
expression = Symbol(f"({self.name} ^ {other.name})")
else:
expression = Symbol(f"({self.name} ^ {other})")
return expression
def __add__(self, other):
if isinstance(other, Symbol):
expression = Symbol(f"({self.name} + {other.name})")
else:
expression = Symbol(f"({self.name} + {other})")
return expression
def __and__(self, other):
if isinstance(other, Symbol):
expression = Symbol(f"({self.name} & {other.name})")
else:
expression = Symbol(f"({self.name} & {other})")
return expression
class AList:
def __init__(self, nums):
self.nums = [Symbol(str(num)) for num in nums]
def __getitem__(self, key):
return self.nums[key]
def copy(self):
return AList(self.nums)
def __len__(self):
return len(self.nums)
def __setitem__(self, key, value):
print(f"new_{self.nums[key]} = {value}")
self.nums[key] = Symbol(f"new_{self.nums[key].name}")
def __eq__(self, other):
print(f"{self.nums} == {other}")
return self.nums == other
inp = AList([f"a[{i}]" for i in range(32)])
res = cy.sub14514(inp)
if __name__ == '__main__':
print(res)
enc:
4108944556, 3404732701, 1466956825, 788072761, 1482427973, 782926647, 1635740553, 4115935911, 2820454423, 3206473923, 1700989382, 2460803532, 2399057278, 968884411, 1298467094, 1786305447, 3953508515, 2466099443, 4105559714, 779131097, 288224004, 3322844775, 4122289132, 2089726849, 656452727, 3096682206, 2217255962, 680183044, 3394288893, 697481839, 1109578150, 2272036063
4.加密分析
通过对程序的逆向分析,我们找到关键函数以及生成的对象的定位
其中对xor和shr等api的交叉引用,可以分析出sub50804是xxtea的一个MX函数
def shift(a, b, c, d, e, f):
return ((((a >> 3) ^ (b << 3)) + ((b >> 4) ^ (a << 2))) ^ ((b ^ c) + (d[(e & 2) ^ f] ^ a)))
sub50520是XXTEA加密逻辑核心函数,经过大致的分析可以推断是一个xxtea的加密
分析得到实现流程:
def encrypt(data, key):
delta = 0x9E3779B9
n = len(data)
rounds = int(4 + 60 / n)
sum = 0
last = data[n - 1]
for _ in range(rounds):
sum = (sum + delta) & 0xFFFFFFFF
e = (sum >> 3) & 3
for p in range(n - 1):
next = data[p + 1]
data[p] = (data[p] + shift(last, next, sum, key, p, e)) & 0xFFFFFFFF
last = data[p]
next = data[0]
data[n - 1] = (data[n - 1] + shift(last, next, sum, key, n - 1, e)) & 0xFFFFFFFF
last = data[n - 1]
return data
sub14514实际上是加密的check部分,利用前面得到的enc,key直接解密即可
5.EXP
xxtea的密钥只取前四位即可
def shift(a, b, c, d, e, f):
return ((((a >> 3) ^ (b << 3)) + ((b >> 4) ^ (a << 2))) ^ ((b ^ c) + (d[(e & 2) ^ f] ^ a))) & 0xFFFFFFFF
def dec(data, key):
delta = 0x9E3779B9
n = len(data)
rounds = int(4 + 60 / n)
sum = (rounds * delta) & 0xFFFFFFFF
first = data[0]
for _ in range(rounds):
e = (sum >> 3) & 3
for p in range(n - 1, 0, -1):
prev = data[p - 1]
data[p] = (data[p] - shift(prev, first, sum, key, p, e)) & 0xFFFFFFFF
first = data[p]
prev = data[n - 1]
data[0] = (data[0] - shift(prev, first, sum, key, 0, e)) & 0xFFFFFFFF
first = data[0]
sum = (sum - delta) & 0xFFFFFFFF
return data
enc = [
4108944556, 3404732701, 1466956825, 788072761, 1482427973,
782926647, 1635740553, 4115935911, 2820454423, 3206473923,
1700989382, 2460803532, 2399057278, 968884411, 1298467094,
1786305447, 3953508515, 2466099443, 4105559714, 779131097,
288224004, 3322844775, 4122289132, 2089726849, 656452727,
3096682206, 2217255962, 680183044, 3394288893, 697481839,
1109578150, 2272036063
]
key = [83, 121, 67, 49]
dec_data = dec(enc, key)
asc = ''.join(chr(value) for value in dec_data)
print(asc)
0 条评论
可输入 255 字