首页
社区
课程
招聘
[原创]DASCTF 2023六月挑战赛 二进制专项 RE writeup
发表于: 2023-6-5 12:27 20920

[原创]DASCTF 2023六月挑战赛 二进制专项 RE writeup

2023-6-5 12:27
20920

常年不去上早八课的人,今天居然在八点前就醒了,要问为什么?这比赛从早上八点打到晚上八点>...<(悲)

不过,咱们队伍在下午就把逆向题ak了~居然没有坐牢到晚上(●'◡'●)

动态调试,题目里有个inline hook,在这里打个断点
图片描述

那么网址就是Just_An_APIH00k11.com

die查一下壳
图片描述

有sleep反调试,把sleep nop掉
图片描述

这里读取了名称为cod的资源,用resource hacker把资源复制下来
图片描述

然后向下执行,这里是一个对cod资源进行解密的地方
图片描述

这里要注意的是如果检测到调试器,那么byte_7FF6DA64F000[3]将会被赋值为36
图片描述

所以要把这个if语句通过修改ZF标志位的方式来绕过反调试

cod资源解密脚本如下

用ida打开,看到有花指令
图片描述

nop一下,主要的改动有这几处
图片描述
图片描述
图片描述

于是得到如下的伪代码
图片描述

看算法是魔改的RC4,exp如下

查个壳,是python逆向
图片描述

pyinstxtractor脱一下
图片描述

在线网站看一下ez_py.pyc的源代码

用ida反编译bin1失败,看来是被加密了

用这个代码看一下字节码

在最后面得到了这个

那么解密代码如下

反编译出来是这个
图片描述

那根据提示我们把上面的解密脚本稍作修改

然后用ida反编译bin2__
图片描述

那么这就是正常的逆向题了

btea函数里面是这个,这是一个xxtea算法
图片描述

写一下exp

在这个地方动调
图片描述

可以发现数组的下标在0~12之间循环

我们随便打开一个BMP类型的文件,用010看看
图片描述

对于BMP类型的文件前两个字节必定是43 4D

既然这个加密的bmp的每一个字节进行的都是异或,那我们可以将前两个字节异或看看
图片描述

n和c是密钥enc_by_dasctf的第2个和第3个字符,按照这个序列,我们向后将密钥向后延申看看后面的情况如何
图片描述

所以我们写个脚本,从密钥的第二位开始,循环异或

得到flag
图片描述

查一下壳,是go逆向
图片描述

用这个脚本恢复一下go符号https://github.com/renshareck/IDAGolangHelper_SupportGo1.20

依次点击如下按钮
图片描述

首先判断key正确与否,看来这是个rsa
图片描述

用yafu解一下p和q
图片描述

然后解出密钥

再往后看,
图片描述

动调了一下看到iv和key都是一样的

所以直接写个exp把加密的文件解密

运行一下解密出的exe,就得到flag了
图片描述

 
 
 
 
 
 
 
arr = [0x18, 0x57, 0x68, 0x64]
with open('COD101.bin', 'rb') as f:
    b = f.read()
b = bytearray(b)
for i in range(len(b)):
    b[i] = b[i] ^ arr[i % 4]
with open('COD_de.bin', 'wb') as f:
    f.write(b)
arr = [0x18, 0x57, 0x68, 0x64]
with open('COD101.bin', 'rb') as f:
    b = f.read()
b = bytearray(b)
for i in range(len(b)):
    b[i] = b[i] ^ arr[i % 4]
with open('COD_de.bin', 'wb') as f:
    f.write(b)
 
 
 
class RC4:
    def __init__(self, key) -> None:
        self.key = key
        self.S = 0
 
        self.__rc4_init__()
 
    def __rc4_init__(self):
        S = [i for i in range(256)]
        j = 0
        for i in range(256):
            j = (2 * j + S[i] + key[i % len(key)]) % 256
            S[i], S[j] = S[j], S[i]
        self.S = S
 
    def rc4_encrypt(self, plain) -> list:
        i = 0
        j = 0
        cipher = []
        cnt = 0
        for p in plain:
            p = (p + 256 - cnt % 0xd) % 256
            cnt += 1
            i = (i + j) % 256
            j = (j + self.S[i]) % 256
            self.S[i], self.S[j] = self.S[j], self.S[i]
            tmp = self.S[(self.S[i] + self.S[j] + j) % 256]
            k = p ^ tmp
            cipher.append(k)
        return cipher
 
key = [0x5D , 0x42 , 0x62 , 0x29 , 0x3, 0x36 , 0x47 , 0x41 , 0x15, 0x36]
data = [0xF7, 0x2E, 0x34, 0xF0, 0x72, 0xCF, 0x5E, 0x0A, 0xBB, 0xEC, 0xB1, 0x2B, 0x70, 0x88, 0x88, 0xED,
0x46, 0x38, 0xDB, 0xDA, 0x6C, 0xBD, 0xD4, 0x06, 0x77, 0xF2, 0xCF, 0x56, 0x88, 0xC6, 0x31, 0xD2,
0xB7, 0x5A, 0xC1, 0x42, 0xB0, 0xF4, 0x48, 0x37, 0xF5, 0x2C, 0xF5, 0x58]
 
rc4 = RC4(key)
plain = rc4.rc4_encrypt(data)
print(''.join(map(chr,plain)))
class RC4:
    def __init__(self, key) -> None:
        self.key = key
        self.S = 0
 
        self.__rc4_init__()
 
    def __rc4_init__(self):
        S = [i for i in range(256)]
        j = 0
        for i in range(256):
            j = (2 * j + S[i] + key[i % len(key)]) % 256
            S[i], S[j] = S[j], S[i]
        self.S = S
 
    def rc4_encrypt(self, plain) -> list:
        i = 0
        j = 0
        cipher = []
        cnt = 0
        for p in plain:
            p = (p + 256 - cnt % 0xd) % 256
            cnt += 1
            i = (i + j) % 256
            j = (j + self.S[i]) % 256
            self.S[i], self.S[j] = self.S[j], self.S[i]
            tmp = self.S[(self.S[i] + self.S[j] + j) % 256]
            k = p ^ tmp
            cipher.append(k)
        return cipher
 
key = [0x5D , 0x42 , 0x62 , 0x29 , 0x3, 0x36 , 0x47 , 0x41 , 0x15, 0x36]
data = [0xF7, 0x2E, 0x34, 0xF0, 0x72, 0xCF, 0x5E, 0x0A, 0xBB, 0xEC, 0xB1, 0x2B, 0x70, 0x88, 0x88, 0xED,
0x46, 0x38, 0xDB, 0xDA, 0x6C, 0xBD, 0xD4, 0x06, 0x77, 0xF2, 0xCF, 0x56, 0x88, 0xC6, 0x31, 0xD2,
0xB7, 0x5A, 0xC1, 0x42, 0xB0, 0xF4, 0x48, 0x37, 0xF5, 0x2C, 0xF5, 0x58]
 
rc4 = RC4(key)
plain = rc4.rc4_encrypt(data)
print(''.join(map(chr,plain)))
 
 
#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
# Version: Python 3.11
 
import ctypes
from time import *
from ctypes import *
from ctypes import wintypes
from hashlib import md5
 
class _STARTUPINFO(Structure):
    _fields_ = [
        ('cb', c_ulong),
        ('lpReserved', c_char_p),
        ('lpDesktop', c_char_p),
        ('lpTitle', c_char_p),
        ('dwX', c_ulong),
        ('dwY', c_ulong),
        ('dwXSize', c_ulong),
        ('dwYSize', c_ulong),
        ('dwXCountChars', c_ulong),
        ('dwYCountChars', c_ulong),
        ('dwFillAttribute', c_ulong),
        ('dwFlags', c_ulong),
        ('wShowWindow', c_ushort),
        ('cbReserved2', c_ushort),
        ('lpReserved2', c_char_p),
        ('hStdInput', c_ulong),
        ('hStdOutput', c_ulong),
        ('hStdError', c_ulong)]
 
 
class _PROCESS_INFORMATION(Structure):
    _fields_ = [
        ('hProcess', c_void_p),
        ('hThread', c_void_p),
        ('dwProcessId', c_ulong),
        ('dwThreadId', c_ulong)]
 
StartupInfo = _STARTUPINFO()
ProcessInfo = _PROCESS_INFORMATION()
key1 = bytes(md5(b'bin1bin1bin1').hexdigest().encode())
file = open('bin1', 'rb').read()
arr = range(len(file))()
open('bin1', 'wb').write(bytes(arr))
sleep(0)
bet = ctypes.windll.kernel32.CreateProcessA(b'bin1', ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(0), byref(StartupInfo), byref(ProcessInfo))
ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ProcessInfo.hProcess), ctypes.c_int(-1))
open('bin1', 'wb').write(file)
#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
# Version: Python 3.11
 
import ctypes
from time import *
from ctypes import *
from ctypes import wintypes
from hashlib import md5
 
class _STARTUPINFO(Structure):
    _fields_ = [
        ('cb', c_ulong),
        ('lpReserved', c_char_p),
        ('lpDesktop', c_char_p),
        ('lpTitle', c_char_p),
        ('dwX', c_ulong),
        ('dwY', c_ulong),
        ('dwXSize', c_ulong),
        ('dwYSize', c_ulong),
        ('dwXCountChars', c_ulong),
        ('dwYCountChars', c_ulong),
        ('dwFillAttribute', c_ulong),
        ('dwFlags', c_ulong),
        ('wShowWindow', c_ushort),
        ('cbReserved2', c_ushort),
        ('lpReserved2', c_char_p),
        ('hStdInput', c_ulong),
        ('hStdOutput', c_ulong),
        ('hStdError', c_ulong)]
 
 
class _PROCESS_INFORMATION(Structure):
    _fields_ = [
        ('hProcess', c_void_p),
        ('hThread', c_void_p),
        ('dwProcessId', c_ulong),
        ('dwThreadId', c_ulong)]
 
StartupInfo = _STARTUPINFO()
ProcessInfo = _PROCESS_INFORMATION()
key1 = bytes(md5(b'bin1bin1bin1').hexdigest().encode())
file = open('bin1', 'rb').read()
arr = range(len(file))()
open('bin1', 'wb').write(bytes(arr))
sleep(0)
bet = ctypes.windll.kernel32.CreateProcessA(b'bin1', ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(0), byref(StartupInfo), byref(ProcessInfo))
ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ProcessInfo.hProcess), ctypes.c_int(-1))
open('bin1', 'wb').write(file)
 
import marshal, dis
 
f = open("ez_py.pyc", "rb").read()
 
code = marshal.loads(f[16:])            #这边从16位开始取因为是python3 python2从8位开始取
 
dis.dis(code)
import marshal, dis
 
f = open("ez_py.pyc", "rb").read()
 
code = marshal.loads(f[16:])            #这边从16位开始取因为是python3 python2从8位开始取
 
dis.dis(code)
Disassembly of <code object <listcomp> at 0x00000297CC7F8E70, file "ez_py.py", line 59>:
 59           0 RESUME                   0
              2 BUILD_LIST               0
              4 LOAD_FAST                0 (.0)
        >>    6 FOR_ITER                50 (to 108)
              8 STORE_FAST               1 (i)
             10 LOAD_GLOBAL              0 (key1)
             22 LOAD_FAST                1 (i)
             24 LOAD_GLOBAL              3 (NULL + len)
             36 LOAD_GLOBAL              0 (key1)
             48 PRECALL                  1
             52 CALL                     1
             62 BINARY_OP                6 (%)
             66 BINARY_SUBSCR
             76 LOAD_GLOBAL              4 (file)
             88 LOAD_FAST                1 (i)
             90 BINARY_SUBSCR
            100 BINARY_OP               12 (^)
            104 LIST_APPEND              2
            106 JUMP_BACKWARD           51 (to 6)
        >>  108 RETURN_VALUE
Disassembly of <code object <listcomp> at 0x00000297CC7F8E70, file "ez_py.py", line 59>:
 59           0 RESUME                   0

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

最后于 2023-6-5 13:09 被oacia编辑 ,原因:
上传的附件:
收藏
免费 7
支持
分享
最新回复 (6)
雪    币: 3573
活跃值: (31026)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2023-6-6 09:19
1
雪    币: 719
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
ez_exe师傅用的什么编译器呢?我用pycharm写那个字节码,他的输出结果没有实际的参数值
2023-6-7 20:52
0
雪    币: 3507
活跃值: (4853)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
4
zxk1ng ez_exe师傅用的什么编译器呢?我用pycharm写那个字节码,他的输出结果没有实际的参数值
用python3.11来运行输出ez_py.pyc字节码的代码
2023-6-8 12:55
0
雪    币: 928
活跃值: (1878)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
5
cool!
2023-10-7 15:38
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
为什么我查看字节码提示这个
dis.dis(marshal.load(f))
ValueError: bad marshal data (unknown type code)
2023-11-8 21:33
0
雪    币: 3507
活跃值: (4853)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
7
mb_estrypsw 为什么我查看字节码提示这个[em_2] dis.dis(marshal.load(f)) ValueError: bad marshal data (unknown type code)
用与pyc相同版本的python运行代码就可以查看到字节码了,例如这里的代码你用python3.11运行就不会报错了
2023-11-8 22:51
0
游客
登录 | 注册 方可回帖
返回
//