DASCTF X GFCTF 2024|四月开启第一局 —— re前三题wp

四月安恒月赛

prese

平坦化混淆

经过输入测试和代码分析可发现,核心加密是这一句的逻辑,这一句会根据输入的长度生成temp数组

尝试得到输入与输出的映射关系后解:

cipher = [0x86, 0x83, 0x91, 0x81, 0x96, 0x84, 0xB9, 0xA5, 0xAD, 0xAD, 0xA6, 0x9D, 0xB6, 0xAA, 0xA7,
          0x9D, 0xB0, 0xA7, 0x9D, 0xAB, 0xB1, 0x9D, 0xA7, 0xA3, 0xB1, 0xBB, 0xAA, 0xAA, 0xAA, 0xAA, 0xBF, 0]
a = [chr(i) for i in range(96, 96+32)]
print("".join(a))
src = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}"
for i in range(64+31, 64+31+31):
    print(chr(i), end="")
# exit()
table = [0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF] + \
    [0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE] + \
    [0xBF, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E,
        0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D]
# for i in range(len(table)):
#    table[i] ^= 0x22
print(len(src), len(table))
flag = ""
table = bytes(table)
for i in range(32):
    cipher[i] ^= 0x22
    index = table.find(cipher[i])
    flag += src[index]
    # print(index)
print(flag)
for i in cipher:
    print(hex(i), end=" ")


DASCTF{good_the_re_is_easyhhhh}

ezVM

ezvm的check dll是一个fake逻辑
ezvm exe会生成新的check dll去调用

调用这个函数的前提是key输入对,总之尝试解一下key。
首先key是16位数字

然后是一个vm

vm exp:

cipher = b"QTFVASnst~pST^PsT~pSt~psytr}}}}}}}}}}}}}}}}h"
cipher = [0x0D, 0x08, 0x1A, 0x0A, 0x1D, 0x0F, 0x32, 0x78, 0x2A, 0x7B, 0x2A, 0x7B, 0x7C, 0x7D, 0x71, 0x64, 0x7A, 0x2C, 0x7B, 0x7D, 0x64,
          0x28, 0x7D, 0x71, 0x2C, 0x64, 0x78, 0x78, 0x7D, 0x7A, 0x64, 0x28, 0x7A, 0x7D, 0x70, 0x7F, 0x28, 0x7A, 0x2B, 0x7E, 0x7D, 0x79, 0x79, 0x34]
for i in range(44):
    cipher[i] ^= 0x49
print(bytes(cipher))
vm = [0x000000A2, 0x00000000, 0x00000084, 0x000000A3, 0x00000008, 0x00000000, 0x000000A3, 0x00000008, 0x00000001, 0x000000B0, 0x00000008, 0x0000013C, 0x000000B2, 0x000000A3, 0x00000009, 0x00000001, 0x000000A3, 0x00000009, 0x00000002, 0x000000A3, 0x00000009, 0x00000003, 0x000000B0, 0x00000009, 0x0000009E, 0x000000B2, 0x000000A6, 0x00000004, 0x00000016, 0x000000A3, 0x00000000, 0x00000004, 0x000000B0, 0x00000000, 0x00000379, 0x000000B2, 0x000000A4, 0x00000005, 0x0000000B, 0x000000A1, 0x00000008, 0x00000005, 0x000000A3, 0x00000008, 0x00000006, 0x000000B0,
      0x00000008, 0x00000026, 0x000000B2, 0x000000A3, 0x00000007, 0x00000006, 0x000000B0, 0x00000007, 0x00000060, 0x000000B2, 0x000000A1, 0x00000009, 0x00000001, 0x000000A3, 0x00000009, 0x00000002, 0x000000A5, 0x00000009, 0x00000005, 0x000000B0, 0x00000009, 0x0000006F, 0x000000B2, 0x000000A6, 0x00000005, 0x00000007, 0x000000A1, 0x00000008, 0x00000000, 0x000000A5, 0x00000008, 0x00000006, 0x000000A3, 0x00000008, 0x00000005, 0x000000B0, 0x00000008, 0x0000035B, 0x000000B2, 0x000000A3, 0x00000003, 0x00000004, 0x000000B0, 0x00000003, 0x000002C2, 0x000000B2, 0x000000C0]
i = 0
while vm[i] != 192:
    op = vm[i]
    if op < 178:
        arg1 = vm[i+1]
        arg2 = vm[i+2]
    if op == 160:
        print("mov key[" + str(arg1) + "] ," + str(arg2))
    if op == 161:
        print("mov key[" + str(arg1) + "] ,key[" + str(arg2)+"]")
    if op == 162:
        print("add key[" + str(arg1) + "] ," + str(arg2))
    if op == 163:
        print("add key[" + str(arg1) + "] ,key[" + str(arg2)+"]")
    if op == 164:
        print("sub key[" + str(arg1) + "] ," + str(arg2))
    if op == 165:
        print("sub key[" + str(arg1) + "] ,key[" + str(arg2)+"]")
    if op == 166:
        print("mul key[" + str(arg1) + "] ," + str(arg2))
    if op == 167:
        print("mul key[" + str(arg1) + "] ,key[" + str(arg2)+"]")
    if op == 176:
        print("cmp key[" + str(arg1) + "] ," + str(arg2))
    if op == 177:
        print("cmp key[" + str(arg1) + "] , key[" + str(arg2)+"]")
    if op == 178:
        print("jz out")
        i += 1
        continue
    i += 3

add key[0] ,132
add key[8] ,key[0]
add key[8] ,key[1]
cmp key[8] ,316
jz out
add key[9] ,key[1]
add key[9] ,key[2]
add key[9] ,key[3]
cmp key[9] ,158
jz out
mul key[4] ,22
add key[0] ,key[4]
cmp key[0] ,889
jz out
sub key[5] ,11
mov key[8] ,key[5]
add key[8] ,key[6]
cmp key[8] ,38
jz out
add key[7] ,key[6]
cmp key[7] ,96
jz out
mov key[9] ,key[1]
add key[9] ,key[2]
sub key[9] ,key[5]
cmp key[9] ,111
jz out
mul key[5] ,7
mov key[8] ,key[0]
sub key[8] ,key[6]
add key[8] ,key[5]
cmp key[8] ,859
jz out
add key[3] ,key[4]
cmp key[3] ,706
jz out

多项表达式,可以用z3解。

import dis
from z3 import *


def solve():
    s = Solver()
    d = [BitVec('v'+str(x), 8) for x in range(8)]
    print(d[0])
    values = []
    s.add(d[0] + 132 + d[1] == 316)  # d[0] += 132
    s.add(d[1] + d[2] + d[3] == 158)
    # d[4] *= 22 d[0] = d[0] + 132 + d[4] * 22
    s.add(d[4] * 22 + d[0] + 132 == 889)
    s.add(d[5] - 11 + d[6] == 38)  # d[5] -= 11
    s.add(d[7] + d[6] == 96)  # d[7] += d[6]
    s.add(d[1] + d[2] - d[5] + 11 == 111)
    s.add((d[5]-11) * 7 + d[0] + 132 + d[4] * 22 - d[6] == 859)  # (d[5]-11)*7
    s.add(d[3] + d[4] * 22 == 706)
    for i in range(8):
        s.add(d[i] < 100)
    if s.check() == sat:
        result = [0] * len(d)
        keyword = 'v'
        offset = 0
        m = s.model()
        print(m)
        for l in range(len(result)):
            for i in m:
                # print(i.name,type(i))
                # 取定义的nums与i名比对
                if keyword + str(l + offset) == str(i):
                    value = m[i]
                    values.append(value)
            # for i in values:
            #    print(i)

        print("values: ", values)
        key = ""
        for i in values:
            key += str(i)
        print(key, len(key))


solve()

输入正确后可动调进入真实dll。其简单做了一个异或加密

cipher = [0x0D, 0x08, 0x1A, 0x0A, 0x1D, 0x0F, 0x32, 0x78, 0x2A, 0x7B, 0x2A, 0x7B, 0x7C, 0x7D, 0x71, 0x64, 0x7A, 0x2C, 0x7B, 0x7D, 0x64,
          0x28, 0x7D, 0x71, 0x2C, 0x64, 0x78, 0x78, 0x7D, 0x7A, 0x64, 0x28, 0x7A, 0x7D, 0x70, 0x7F, 0x28, 0x7A, 0x2B, 0x7E, 0x7D, 0x79, 0x79, 0x34]
for i in range(44):
    cipher[i] ^= 0x49
print(bytes(cipher))

DASCTF{1c2c2548-3e24-a48e-1143-a3496a3b7400}

unwind

此题先有一个简单的xxtea

而后实际上,在这个去除符号的程序里,这个strcmp是唯一保留的符号,是自定义的strcmp。:


这个程序会在程序开头略微修改指令:

修改后该strcmp会触发异常,进而触发异常处理程序。
不断动调可发现,此题除了main里的xxtea,还做了连续两次的xtea
exp:

from ctypes import *


def MX(z, y, total, key, p, e):
    temp1 = (z.value >> 5 ^ y.value << 2) + (y.value >> 3 ^ z.value << 4)
    temp2 = (total.value ^ y.value) + (key[(p & 3) ^ e.value] ^ z.value)

    return c_uint32(temp1 ^ temp2)


def xxdecrypt(n, v, key):
    delta = 0x9e3779b9
    rounds = 6 + 52//n

    total = c_uint32(rounds * delta)
    y = c_uint32(v[0])
    e = c_uint32(0)

    while rounds > 0:
        e.value = (total.value >> 2) & 3
        for p in range(n-1, 0, -1):
            z = c_uint32(v[p-1])
            v[p] = c_uint32((v[p] - MX(z, y, total, key, p, e).value)).value
            y.value = v[p]
        z = c_uint32(v[n-1])
        v[0] = c_uint32(v[0] - MX(z, y, total, key, 0, e).value).value
        y.value = v[0]
        total.value -= delta
        rounds -= 1

    return v


def decrypt(v, key):
    v0, v1 = c_uint32(v[0]), c_uint32(v[1])
    delta = 0x9E3779B9
    rounds = 36
    total = c_uint32(delta * rounds)

    for i in range(rounds):
        v1.value -= (((v0.value << 4) ^ (v0.value >> 5)) +
                     v0.value) ^ (total.value + key[(total.value >> 11) & 3])
        total.value -= delta
        v0.value -= (((v1.value << 4) ^ (v1.value >> 5)) +
                     v1.value) ^ (total.value + key[total.value & 3])

    return v0.value, v1.value


# 标准xtea
if __name__ == "__main__":
    cipher = [0xC1, 0xA7, 0xAA, 0x87, 0xB6, 0x21, 0x73, 0x85, 0x8C, 0xD2, 0x71, 0x0E, 0xF2, 0x39, 0xDF,
              0xCA, 0x14, 0xCA, 0xEF, 0x58, 0xD8, 0xD9, 0xE7, 0xD7, 0x5D, 0x5C, 0x9F, 0xF2, 0x5E, 0xD4, 0x5E, 0x5F]
    value = [0] * (len(cipher)//4)
    print("cypher len:", len(cipher))
    print(hex(0x86 ^ 0xeb), hex(0x10 ^ 0xeb))
    for i in range(0, len(cipher), 4):
        if 'bytes' in str(type(cipher)):
            value[i//4] = int.from_bytes(cipher[i:i+4], 'little')
        elif 'list' in str(type(cipher)):
            try:
                value[i//4] = (ord(cipher[i]) | (ord(cipher[i+1]) << 8)
                               | (ord(cipher[i+2]) << 16) | (ord(cipher[i+3]) << 24))
            except:
                value[i//4] = ((cipher[i]) | ((cipher[i+1]) << 8)
                               | ((cipher[i+2]) << 16) | ((cipher[i+3]) << 24))
    key = b"D\x00\x00\x00A\x00\x00\x00S\x00\x00\x00!"
    k = [int.from_bytes(key[i:i+4], 'little')
         for i in range(0, len(key), 4)]
    flag = b""
    for i in range(0, len(value), 2):
        res = decrypt(value[i:i+2], k)
        flag += res[0].to_bytes(4, 'little') + res[1].to_bytes(4, 'little')
    print(flag)
    cipher = flag
    for i in range(0, len(cipher), 4):
        if 'bytes' in str(type(cipher)):
            value[i//4] = int.from_bytes(cipher[i:i+4], 'little')
        elif 'list' in str(type(cipher)):
            try:
                value[i//4] = (ord(cipher[i]) | (ord(cipher[i+1]) << 8)
                               | (ord(cipher[i+2]) << 16) | (ord(cipher[i+3]) << 24))
            except:
                value[i//4] = ((cipher[i]) | ((cipher[i+1]) << 8)
                               | ((cipher[i+2]) << 16) | ((cipher[i+3]) << 24))
    flag = b""
    for i in range(0, len(value), 2):
        res = decrypt(value[i:i+2], k)
        flag += res[0].to_bytes(4, 'little') + res[1].to_bytes(4, 'little')
    print(flag)

    cipher = flag
    # padding
    cipher = bytes(cipher)
    padlen = 0
    if len(cipher) % 4 != 0:
        padlen = 4 - len(cipher)
    cipher = cipher.ljust(len(cipher)+padlen, b'\x00')
    key = key.ljust(16, b'\x00')
    print(cipher)
    print(key)
    # bytes convert to 32bit int
    v = [int.from_bytes(cipher[i:i+4], 'little')
         for i in range(0, len(cipher), 4)]
    k = [int.from_bytes(key[i:i+4], 'little')
         for i in range(0, len(key), 4)]
    print(v)
    print(k)
    n = len(v)
    res = xxdecrypt(n, v, k)
    flag = b''
    for i in res:
        flag += i.to_bytes(4, 'little')

    print(flag)
"""
Data is :  0x12345678 0x78563412
Encrypted data is :  0xae685ec7 0x59af4238
Decrypted data is :  0x12345678 0x78563412
"""

DASCTF{Gr3@t!Y0u_have_50lv3d_1T}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值