首页
社区
课程
招聘
[原创]KCTF 第四题 神秘信号 WriteUP
发表于: 2024-8-21 15:13 3558

[原创]KCTF 第四题 神秘信号 WriteUP

2024-8-21 15:13
3558

先使用 pyinstxtractor.py 解包 main.exe
使用 pycdc 查看 main.pyc 代码:

主要逻辑在 CrackMe中, 然而在解包出的文件中并未找到 CrackMe 源文件;
考虑分析一下python import的过程, 于是下载题目所使用的 python 3.8.10 的源代码, 以及安装python 3.8.10 勾选上安装调试文件 得到python38.pdb 开始动态调试python38.dll

在一边看源码下断点, 一边使用pycdc检查解包出的其他文件时发现base64.pyc中有奇怪的代码:

对base64的main函数的code object进行了替换, 可以使用如下代码将其写入文件并用pycdc检查

pycdc -c test.dump -v 3.8

可以发现是替换了字符的base64
修下pycdc代码的lambda .0部分以及写出解码函数:

之前分析python38源码得知 _PyEval_EvalFrameDefault为python主要解释执行函数, 结合pdb分析dll可以找到 python38.dll+0x28595处为_PyEval_EvalFrameDefault中处理BINARY_XOR的部分, 通过windbg调试命令
bp python38.dll+0x28595 "db rcx+0x18 rcx+0x1f;db rdx+0x18 rdx+0x1f;g"
可以看到python中执行的每个xor的输入

变种base64代码中有对data中的字符i = i ^ 85, 85对应0x55, 与它进行xor的字符串QI8F应该就是KCTF经过之前某种处理的结果
确定xor另一个字符总是0x55之后可以将命令换为bp python38.dll+0x28595 "db rcx+0x18 rcx+0x1f;g"来检查该种处理结果
从main.py得知dZpKdrsiB6cndrGY的解码结果+KCTF处理结果QI8F应为变种base64的输入, 解码dZpKdrsiB6cndrGY得到b"T'00-l5-\x1a0(k"
并在检查字符处理结果时可发现处理类似字符替换, 每个字符会位置无关的变成另一个字符
且检查公开提供的验证码D7CHel419lo 7AFWor080ld!6891可得到对应HUIT'0X[c0-lUKF5-\x1a\d\0(kVdc[

可找到H对应T e对应' l对应0 等
对照b"T'00-l5-\x1a0(k"进行替换
即可得到KCTF最终的验证码为Hello World!KCTF

# Source Generated with Decompyle++
# File: main.pyc (Python 3.8)
 
import CrackMe
print('(账号密码由字母大小写、数字、!、空格组成)')
print('请输入账号:')
h = input()
z = CrackMe.main(h)
if len(z) < 20:
    key = 'dZpKdrsiB6cndrGY' + z
else:
    key = z[0:4] + 'dZpK' + z[4:8] + 'drsi' + z[8:12] + 'B6cn' + z[12:16] + 'drGY' + z[16:]
print('请输入验证码:')
h = input()
m = CrackMe.main(h)
if key == m:
    print('Success')
 
print('Fail')
continue
continue
# Source Generated with Decompyle++
# File: main.pyc (Python 3.8)
 
import CrackMe
print('(账号密码由字母大小写、数字、!、空格组成)')
print('请输入账号:')
h = input()
z = CrackMe.main(h)
if len(z) < 20:
    key = 'dZpKdrsiB6cndrGY' + z
else:
    key = z[0:4] + 'dZpK' + z[4:8] + 'drsi' + z[8:12] + 'B6cn' + z[12:16] + 'drGY' + z[16:]
print('请输入验证码:')
h = input()
m = CrackMe.main(h)
if key == m:
    print('Success')
 
print('Fail')
continue
continue
# ...
def main():
Unsupported opcode: BEGIN_FINALLY
    '''Small main program'''
    import sys
    import getopt
# WARNING: Decompyle incomplete
 
a = main.__code__.replace(1, (), b'd\x01}\x01d\x02}\x02d\x03}\x03d\x04}\x04|\x00D\x00]\x1c}\x05|\x05d\x05A\x00}\x05|\x04|\x05\xa0\x00d\x06d\x07\xa1\x02\x17\x00}\x04q\x14|\x04}\x00t\x01d\x02t\x02|\x00\x83\x01d\x08\x83\x03D\x00]\x90}\x05|\x00|\x05|\x05d\x08\x17\x00\x85\x02\x19\x00}\x06d\x01\xa0\x03d\td\n\x84\x00|\x06D\x00\x83\x01\xa1\x01}\x07t\x01d\x02t\x02|\x07\x83\x01d\x0b\x83\x03D\x00]V}\x08|\x07|\x08|\x08d\x0b\x17\x00\x85\x02\x19\x00}\tt\x02|\t\x83\x01d\x0bk\x00r\xc2|\x02d\x0bt\x02|\t\x83\x01\x18\x007\x00}\x02|\td\x0cd\x0bt\x02|\t\x83\x01\x18\x00\x14\x007\x00}\t|\x01|\x03t\x04|\td\r\x83\x02\x19\x007\x00}\x01q~qF|\x01d\x0e|\x02d\r\x1a\x00\x14\x007\x00}\x01t\x01t\x02|\x01\x83\x01d\r\x1a\x00\x83\x01D\x00]L}\x05|\x01|\x05d\r\x14\x00\x19\x00}\n|\x01|\x05d\r\x14\x00d\x06\x17\x00\x19\x00}\x0b|\x01d\x00|\x05d\r\x14\x00\x85\x02\x19\x00|\x0b\x17\x00|\n\x17\x00|\x01|\x05d\r\x14\x00d\r\x17\x00d\x00\x85\x02\x19\x00\x17\x00}\x01q\xf8|\x01S\x00', (None, '', 0, 'ZQ+U7tSBEKVzyf5coCwb94Dd6raT0eLNin12Hp8mOxFuvMgIPlhRY3WjksqJAXG/', b'', 85, 1, 'little', 3, compile('', '', 'exec').replace(1, (), b'|\x00]\x10}\x01t\x00|\x01d\x00\x83\x02V\x00\x01\x00q\x02d\x01S\x00', ('08b', None), '', 19, 115, (), 0, b'', '', ('format',), 2, 0, 4, ('.0', 'byte'), **('co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_kwonlyargcount', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_posonlyargcount', 'co_stacksize', 'co_varnames')), '', 6, '0', 2, '!'), '', 4, 67, (), 0, b'', '', ('to_bytes', 'range', 'len', 'join', 'int'), 12, 0, 7, ('data', 'encoded_str', 'padding', 'base64_chars', 'ww', 'i', 'chunk', 'binary_str', 'j', 'six_bits', 'a', 'b'), **('co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_kwonlyargcount', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_posonlyargcount', 'co_stacksize', 'co_varnames'))
main.__code__ = a
# ...
def main():
Unsupported opcode: BEGIN_FINALLY
    '''Small main program'''
    import sys
    import getopt
# WARNING: Decompyle incomplete
 
a = main.__code__.replace(1, (), b'd\x01}\x01d\x02}\x02d\x03}\x03d\x04}\x04|\x00D\x00]\x1c}\x05|\x05d\x05A\x00}\x05|\x04|\x05\xa0\x00d\x06d\x07\xa1\x02\x17\x00}\x04q\x14|\x04}\x00t\x01d\x02t\x02|\x00\x83\x01d\x08\x83\x03D\x00]\x90}\x05|\x00|\x05|\x05d\x08\x17\x00\x85\x02\x19\x00}\x06d\x01\xa0\x03d\td\n\x84\x00|\x06D\x00\x83\x01\xa1\x01}\x07t\x01d\x02t\x02|\x07\x83\x01d\x0b\x83\x03D\x00]V}\x08|\x07|\x08|\x08d\x0b\x17\x00\x85\x02\x19\x00}\tt\x02|\t\x83\x01d\x0bk\x00r\xc2|\x02d\x0bt\x02|\t\x83\x01\x18\x007\x00}\x02|\td\x0cd\x0bt\x02|\t\x83\x01\x18\x00\x14\x007\x00}\t|\x01|\x03t\x04|\td\r\x83\x02\x19\x007\x00}\x01q~qF|\x01d\x0e|\x02d\r\x1a\x00\x14\x007\x00}\x01t\x01t\x02|\x01\x83\x01d\r\x1a\x00\x83\x01D\x00]L}\x05|\x01|\x05d\r\x14\x00\x19\x00}\n|\x01|\x05d\r\x14\x00d\x06\x17\x00\x19\x00}\x0b|\x01d\x00|\x05d\r\x14\x00\x85\x02\x19\x00|\x0b\x17\x00|\n\x17\x00|\x01|\x05d\r\x14\x00d\r\x17\x00d\x00\x85\x02\x19\x00\x17\x00}\x01q\xf8|\x01S\x00', (None, '', 0, 'ZQ+U7tSBEKVzyf5coCwb94Dd6raT0eLNin12Hp8mOxFuvMgIPlhRY3WjksqJAXG/', b'', 85, 1, 'little', 3, compile('', '', 'exec').replace(1, (), b'|\x00]\x10}\x01t\x00|\x01d\x00\x83\x02V\x00\x01\x00q\x02d\x01S\x00', ('08b', None), '', 19, 115, (), 0, b'', '', ('format',), 2, 0, 4, ('.0', 'byte'), **('co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_kwonlyargcount', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_posonlyargcount', 'co_stacksize', 'co_varnames')), '', 6, '0', 2, '!'), '', 4, 67, (), 0, b'', '', ('to_bytes', 'range', 'len', 'join', 'int'), 12, 0, 7, ('data', 'encoded_str', 'padding', 'base64_chars', 'ww', 'i', 'chunk', 'binary_str', 'j', 'six_bits', 'a', 'b'), **('co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_kwonlyargcount', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_posonlyargcount', 'co_stacksize', 'co_varnames'))
main.__code__ = a
import dis
import marshal
def f():
    return
 
 
inner = compile('', '', 'exec').replace(co_argcount=1, co_cellvars=(), co_code=b'|\x00]\x10}\x01t\x00|\x01d\x00\x83\x02V\x00\x01\x00q\x02d\x01S\x00', co_consts=('08b', None), co_filename='', co_firstlineno=19, co_flags=115, co_freevars=(), co_kwonlyargcount=0, co_name='', co_names=('format',), co_nlocals=2, co_posonlyargcount=0, co_stacksize=4, co_varnames=('.0', 'byte'))
 
a = f.__code__.replace(co_argcount=1, co_cellvars=(), co_code=b'd\x01}\x01d\x02}\x02d\x03}\x03d\x04}\x04|\x00D\x00]\x1c}\x05|\x05d\x05A\x00}\x05|\x04|\x05\xa0\x00d\x06d\x07\xa1\x02\x17\x00}\x04q\x14|\x04}\x00t\x01d\x02t\x02|\x00\x83\x01d\x08\x83\x03D\x00]\x90}\x05|\x00|\x05|\x05d\x08\x17\x00\x85\x02\x19\x00}\x06d\x01\xa0\x03d\td\n\x84\x00|\x06D\x00\x83\x01\xa1\x01}\x07t\x01d\x02t\x02|\x07\x83\x01d\x0b\x83\x03D\x00]V}\x08|\x07|\x08|\x08d\x0b\x17\x00\x85\x02\x19\x00}\tt\x02|\t\x83\x01d\x0bk\x00r\xc2|\x02d\x0bt\x02|\t\x83\x01\x18\x007\x00}\x02|\td\x0cd\x0bt\x02|\t\x83\x01\x18\x00\x14\x007\x00}\t|\x01|\x03t\x04|\td\r\x83\x02\x19\x007\x00}\x01q~qF|\x01d\x0e|\x02d\r\x1a\x00\x14\x007\x00}\x01t\x01t\x02|\x01\x83\x01d\r\x1a\x00\x83\x01D\x00]L}\x05|\x01|\x05d\r\x14\x00\x19\x00}\n|\x01|\x05d\r\x14\x00d\x06\x17\x00\x19\x00}\x0b|\x01d\x00|\x05d\r\x14\x00\x85\x02\x19\x00|\x0b\x17\x00|\n\x17\x00|\x01|\x05d\r\x14\x00d\r\x17\x00d\x00\x85\x02\x19\x00\x17\x00}\x01q\xf8|\x01S\x00', co_consts=(None, '', 0, 'ZQ+U7tSBEKVzyf5coCwb94Dd6raT0eLNin12Hp8mOxFuvMgIPlhRY3WjksqJAXG/', b'', 85, 1, 'little', 3, inner, '', 6, '0', 2, '!'), co_filename='', co_firstlineno=4, co_flags=67, co_freevars=(), co_kwonlyargcount=0, co_name='', co_names=('to_bytes', 'range', 'len', 'join', 'int'), co_nlocals=12, co_posonlyargcount=0, co_stacksize=7, co_varnames=('data', 'encoded_str', 'padding', 'base64_chars', 'ww', 'i', 'chunk', 'binary_str', 'j', 'six_bits', 'a', 'b'))
f.__code__ = a
# print(dis.dis(f.__code__))
 
marshal.dump(f.__code__, open('test.dump', 'wb'))
import dis
import marshal
def f():
    return
 
 
inner = compile('', '', 'exec').replace(co_argcount=1, co_cellvars=(), co_code=b'|\x00]\x10}\x01t\x00|\x01d\x00\x83\x02V\x00\x01\x00q\x02d\x01S\x00', co_consts=('08b', None), co_filename='', co_firstlineno=19, co_flags=115, co_freevars=(), co_kwonlyargcount=0, co_name='', co_names=('format',), co_nlocals=2, co_posonlyargcount=0, co_stacksize=4, co_varnames=('.0', 'byte'))
 
a = f.__code__.replace(co_argcount=1, co_cellvars=(), co_code=b'd\x01}\x01d\x02}\x02d\x03}\x03d\x04}\x04|\x00D\x00]\x1c}\x05|\x05d\x05A\x00}\x05|\x04|\x05\xa0\x00d\x06d\x07\xa1\x02\x17\x00}\x04q\x14|\x04}\x00t\x01d\x02t\x02|\x00\x83\x01d\x08\x83\x03D\x00]\x90}\x05|\x00|\x05|\x05d\x08\x17\x00\x85\x02\x19\x00}\x06d\x01\xa0\x03d\td\n\x84\x00|\x06D\x00\x83\x01\xa1\x01}\x07t\x01d\x02t\x02|\x07\x83\x01d\x0b\x83\x03D\x00]V}\x08|\x07|\x08|\x08d\x0b\x17\x00\x85\x02\x19\x00}\tt\x02|\t\x83\x01d\x0bk\x00r\xc2|\x02d\x0bt\x02|\t\x83\x01\x18\x007\x00}\x02|\td\x0cd\x0bt\x02|\t\x83\x01\x18\x00\x14\x007\x00}\t|\x01|\x03t\x04|\td\r\x83\x02\x19\x007\x00}\x01q~qF|\x01d\x0e|\x02d\r\x1a\x00\x14\x007\x00}\x01t\x01t\x02|\x01\x83\x01d\r\x1a\x00\x83\x01D\x00]L}\x05|\x01|\x05d\r\x14\x00\x19\x00}\n|\x01|\x05d\r\x14\x00d\x06\x17\x00\x19\x00}\x0b|\x01d\x00|\x05d\r\x14\x00\x85\x02\x19\x00|\x0b\x17\x00|\n\x17\x00|\x01|\x05d\r\x14\x00d\r\x17\x00d\x00\x85\x02\x19\x00\x17\x00}\x01q\xf8|\x01S\x00', co_consts=(None, '', 0, 'ZQ+U7tSBEKVzyf5coCwb94Dd6raT0eLNin12Hp8mOxFuvMgIPlhRY3WjksqJAXG/', b'', 85, 1, 'little', 3, inner, '', 6, '0', 2, '!'), co_filename='', co_firstlineno=4, co_flags=67, co_freevars=(), co_kwonlyargcount=0, co_name='', co_names=('to_bytes', 'range', 'len', 'join', 'int'), co_nlocals=12, co_posonlyargcount=0, co_stacksize=7, co_varnames=('data', 'encoded_str', 'padding', 'base64_chars', 'ww', 'i', 'chunk', 'binary_str', 'j', 'six_bits', 'a', 'b'))
f.__code__ = a
# print(dis.dis(f.__code__))
 
marshal.dump(f.__code__, open('test.dump', 'wb'))
# Source Generated with Decompyle++
# File: test.dump (Python 3.8)
 
encoded_str = ''
padding = 0
base64_chars = 'ZQ+U7tSBEKVzyf5coCwb94Dd6raT0eLNin12Hp8mOxFuvMgIPlhRY3WjksqJAXG/'
ww = b''
for i in data:
    i = i ^ 85
    ww = ww + i.to_bytes(1, 'little')
data = ww
for i in range(0, len(data), 3):
    chunk = data[i:i + 3]
    binary_str = ''.join((lambda .0: for byte in .0:
format(byte, '08b'))(chunk))
    for j in range(0, len(binary_str), 6):
        six_bits = binary_str[j:j + 6]
        if len(six_bits) < 6:
            padding += 6 - len(six_bits)
            six_bits += '0' * (6 - len(six_bits))
        encoded_str += base64_chars[int(six_bits, 2)]
encoded_str += '!' * (padding // 2)
for i in range(len(encoded_str) // 2):
    a = encoded_str[i * 2]
    b = encoded_str[i * 2 + 1]
    encoded_str = encoded_str[:i * 2] + b + a + encoded_str[i * 2 + 2:]
return encoded_str
# Source Generated with Decompyle++
# File: test.dump (Python 3.8)
 
encoded_str = ''
padding = 0
base64_chars = 'ZQ+U7tSBEKVzyf5coCwb94Dd6raT0eLNin12Hp8mOxFuvMgIPlhRY3WjksqJAXG/'
ww = b''
for i in data:
    i = i ^ 85
    ww = ww + i.to_bytes(1, 'little')
data = ww
for i in range(0, len(data), 3):
    chunk = data[i:i + 3]
    binary_str = ''.join((lambda .0: for byte in .0:
format(byte, '08b'))(chunk))
    for j in range(0, len(binary_str), 6):

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2024-8-21 19:03 被tacesrever编辑 ,原因:
收藏
免费 1
支持
分享
最新回复 (2)
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
请问下base64.pyc在哪里?_internal/下没找到这个文件呀
2024-8-28 22:42
0
雪    币: 3089
活跃值: (2894)
能力值: ( LV12,RANK:367 )
在线值:
发帖
回帖
粉丝
3
mb_twxozogd 请问下base64.pyc在哪里?_internal/下没找到这个文件呀
解包main.exe, 在main.exe_extracted/PYZ-00.pyz_extracted里面
如果用我提到的pyinstxtractor.py解的话需要用对应版本的python运行,搜索PyInstaller Extractor也能找到其它的方法,有些就不需要用对应版本的python了.
2024-8-29 01:47
0
游客
登录 | 注册 方可回帖
返回
//