0xD009
2720 字
14 分钟
2024年羊城杯初赛

前言#

这比赛初赛是我在实习上班摸鱼时打的,有解题基本上都打出来了,剩下两道应该是无解或者极少解,看了下也没有做的欲望,有道 Cython 或许后面可以找机会结合去年 CTFCON 上的 talk 看看。

比赛时还做了 AI 的对抗样本,由于一些低级错误没有打出来,有点可惜。

决赛我更是请了两天假,提前离职飞到广州,比赛场地远得离谱,打车花了 ¥200 ,还差点被黑车中介骗 ¥280 ,比完马上马不停蹄地飞回合肥准备第二天的期末缓考,打 CTF 以来最不值的一次线下赛,赛题完全是渗透,我们打了一道 robots.txt 之后就美美爆零了,不得不在小红书狠狠输出了。

sedRust_happyVm#

赛时由 Ichild✌ 解出,脑子也手太快了。

第一阶段去皮后每三位处理输入,类似 base64 但是不换表。

第二阶段每两位进行复杂加密,即题目名称中提到的 vm。

Src 变量是内存空间,该函数(40aba0)利用虚拟机机制做加密,首先通过定义如下的 VM Struct 优化逆向体验:

00000000 VM              struc ; (sizeof=0x420, mappedto_65)
00000000                                         ; XREF: sub_40B2E0/r
00000000 box             db 1024 dup(?)          ; XREF: sub_40B2E0+C0/r
00000000                                         ; sub_40B2E0+C8/r ...
00000400 wregs           dw 8 dup(?)             ; XREF: sub_40B2E0+B8A/w
00000400                                         ; sub_40B2E0+B93/w
00000410 cregs           db 8 dup(?)
00000418 fregs           db 8 dup(?)             ; XREF: sub_40B2E0+1B76/r
00000420 VM              ends

正过来看有些复杂,干脆倒过来看检查点,sub_40A800 中第一个 switch 的 case 7 是影响检查点的唯一处,sub_40A800 是一个递归调用的函数:

void __fastcall sub_40A800(VM *this, unsigned __int8 op)
{
  char op_2_5; // al
  unsigned __int8 op_0_2; // di
  bool v5; // cl
  char v6; // al
  unsigned __int8 v7; // r8
  size_t v8; // rcx
  size_t v9; // rcx
  __int64 _op_0_2; // rax

// 这个函数把 8 位的 op 分成三段:第一段为高三位,第二段为中三位,第三段为低两位,并根据这三段进行运算

  op_2_5 = (op >> 2) & 7;
  op_0_2 = op & 3;
  if ( (op & 0x80u) != 0 )                      // 高三位 >= 2
  {
    switch ( op_2_5 )
    {
      case 0:
        this->fregs[0] += this->fregs[1];
        return;
      case 1:
        this->fregs[0] ^= this->fregs[1];
        return;
      case 2:
        sub_40A800(this, op_0_2 + 0xAC);
        sub_40A800(this, op_0_2 + 0xB8);
        sub_40A800(this, op_0_2 + 0x8C);
        sub_40A800(this, op_0_2 + 0x90);
        sub_40A800(this, op_0_2 + 0xB8);
        op = 0xB0;
        goto LABEL_15;
      case 3:
        v9 = this->wregs[(unsigned __int8)(((op & 0x20) != 0) | (2 * op_0_2))];
        if ( v9 >= 0x100 )
          index_out_of_bounds(v9, 0x100ui64, &off_442EC0);
        _op_0_2 = op_0_2;
        goto LABEL_20;
      case 4:
LABEL_15:
        v8 = this->wregs[(unsigned __int8)(((op & 0x20) != 0) | (2 * op_0_2))];
        if ( v8 >= 0x100 )
          index_out_of_bounds(v8, 0x100ui64, &off_442ED8);
        this->box[(unsigned __int64)op_0_2][v8] = this->fregs[0];
        return;
      case 5:
        _op_0_2 = op_0_2;
        v9 = this->fregs[0];
LABEL_20:
        this->fregs[1] = this->box[_op_0_2][v9];
        break;
      case 6:
        *(_WORD *)this->fregs = this->fregs[1];
        break;
      case 7:
        sub_40A800(this, op_0_2 | 0xA4);
        if ( this->fregs[0] )
          ++this->fregs[4];
        break;
    }
  }
  else
  {
    v5 = (op & 0x20) != 0;
    if ( (op & 0x40) != 0 )                     // 高三位为 1
    {
      switch ( op_2_5 )
      {
        case 0:
          this->wregs[(unsigned __int8)(v5 | (2 * op_0_2))] = this->fregs[0];
          break;
        case 1:
          this->fregs[0] = this->wregs[(unsigned __int8)(v5 | (2 * op_0_2))];
          break;
        case 2:
          this->wregs[(unsigned __int8)(v5 | (2 * op_0_2))] = this->fregs[1];
          break;
        case 3:
          this->fregs[1] = this->wregs[(unsigned __int8)(v5 | (2 * op_0_2))];
          break;
        default:
          return;
      }
    }
    else                                        // 高三位为 0
    {
      v6 = 4 * (op_2_5 == 1);
      if ( (op & 0x20) != 0 )
      {
        this->fregs[2] |= op_0_2 << v6;
      }
      else
      {
        v7 = this->fregs[2];
        this->fregs[1] += (v7 & (unsigned __int8)(0xF << v6)) << (6 - v6);
        this->fregs[2] = v7 & (0xF0u >> v6);
      }
    }
  }
}

通过这一段分析可以基本确定此 VM 将一字节分为多段进行解释的范式,然而这个过程依然非常复杂,逆向耗时较长,考虑到第二阶段的处理是每两位进行,而每一位是 64*64,搜索空间可以接受,直接考虑 python 复现加密过程然后爆破解决:

#!/usr/bin/env python3

from copy import deepcopy

saved_cregs = [0] * 8
saved_wregs = [0] * 8
saved_fregs = [0] * 8
saved_box = [
        list(bytes.fromhex('2e5a7e1e4c493037aa0538ea00f6c5eb48ec990f3c6b8bb02571baac834a702bd50612fb21845669442224d68776983ef731365f4f6865288aafa0de26b51d9f55b38ea75e2cd7c24d1f5bd2dbab17fe7c0ab10189a1be7afa888cb2b657bda8c1e7d195b7a48d3bcd53f146c873544316349acb3a6a9cd0ef6007cc2abc80320bdcda7fdd276de4e18fe0d99475e37b14a2cecab447c0039d02e24bff5204596fd80c1a918510f9b950417df8c9a96745e5b8df2386f00ec778a54e97815ca640519039fc72290dd39377ae3fad614218c39e2f2dc4626679749b5d33cf6ef415fdee589220e8098213c66ca396bb630835e6e9191cf51b3dedbff2f36411d4')),
        list(bytes.fromhex('7ccf2ec82409c9b4dfd37680aee64c3e83045694bdc71db1c39fb27e39603c6a18ec3d710c41a7bfe890d2375c821e310850d6f96d02ca42af2a788c49a67093eb15a4bafd2c65d711266e0d81d474b9797d5f0734c0da120aab5d2b21c43aede766b814448a67358b1f579ec53f849903cec66368db88eea37a51334097de4b4faafc616f32cdb791851a4ee06c9c5a8d0bb620170f4da187efd913a92f55ccbb9a5ee454ffe57bd8b55b23488f98f77305625943ea7fcb47ac75c1009df0b3530616f5dd9246d5fbf8a2271b4af16b86f6d12595e1e9be2d38f396c228fa581c3b8e9b30f4a8f2690e721945e35277fea02910bcaddc36d08922a5e201b064')),
        list(bytes.fromhex('9a2696de92c251254940233781c312489b038915053595462190e8577aaae5755ae258e9fbc128cead2c702e5e9e19413c5cac590b66936a8329137353ba6faea8a45f444dc554d3fee30199568ca534d924f46d07c4644e0088b0eaf9329c506b84b4a0ec16a6dd8aa32f47602d43ff0c1c8565cbd17b7fc73fc8d8cd4c0d3671d0080467a11ed7779739b2fcf74f0ef34b42d276b578bf1dc9ab453a7e8f09796caf3e7238a2b3f5985d8beb55e7ef2b6202f6b7da1f30e6c6fadb5bb891ccf0878d9ddf7c20b1101886ee8ebb6982d41b0a52f26e9fbee4ed3d14e063f1b96822e1311adca7803bc01727cfa9bd7461117d06fd2a0f4a3394bcf8b6cad5d6')),
        list(bytes.fromhex('c81e1f27707a832e998b2cd82ddecfbc372854b4e73c90c69eccbb0e3f65a72314b1f7785c0095321581ae6e9ff60502eb8d9b5fac0760d21bd9faa0b8a930790f503ba3b601934a1d6661ee56f2af82dd58916835334c4bd740d0c37de30b6794dfe5760d46c00aa5b5eca29ac4b0b2d113591a5e6f88da16c5d42226714fffc936499262c1b32fc7be0c447319ed3e55ad8547db21cee46a3aa61238fc6b45774e1c347557ca696c1018430851259dfbd653848efdd5bd8a80f4ef2a7e6d29d39786e2eaa88ff3a4e9f87b03bff54d7409dc043198e1fe5224115ae85dabc27c4117a19c8c207f5b3963e696bab9f164f006422bf9873dcb48cde08972b7aa'))
]

def load():
        global cregs, wregs, fregs, box
        cregs = deepcopy(saved_cregs)
        wregs = deepcopy(saved_wregs)
        fregs = deepcopy(saved_fregs)
        box = deepcopy(saved_box)

def save():
        global saved_cregs, saved_wregs, saved_fregs, saved_box
        saved_cregs = cregs
        saved_wregs = wregs
        saved_fregs = fregs
        saved_box = box

def a(op):
        op_0_2 = op & 3
        op_2_5 = (op >> 2) & 7
        op_5_6 = (op >> 5) & 1
        op_6_8 = (op >> 6) & 3

        assert op_6_8 <= 2
        if op_6_8 == 0:
                assert op_2_5 <= 1
                offset = 4 * op_2_5
                if op_5_6:
                        # print(f'fregs[2] |= {hex(op_0_2 << offset)}')
                        fregs[2] |= op_0_2 << offset
                else:
                        # print(f'fregs[1] += (fregs[2] & {hex(0xf << offset)}) << {(6 - offset)}')
                        fregs[1] += (fregs[2] & (0xf << offset)) << (6 - offset)
                        # print(f'fregs[2] &= {hex(0xf0 >> offset)}')
                        fregs[2] &= 0xf0 >> offset
        elif op_6_8 == 1:
                assert op_2_5 <= 3
                # src = f'fregs[{op_2_5 >> 1}]'
                # dst = f'wregs[{op_0_2 * 2 + op_5_6}]'
                if op_2_5 & 1:
                        # src, dst = dst, src
                        fregs[op_2_5 >> 1] = wregs[op_0_2 * 2 + op_5_6]
                else:
                        # pass
                        wregs[op_0_2 * 2 + op_5_6] = fregs[op_2_5 >> 1]
                # print(f'{dst} = {src}')
        elif op_6_8 == 2:
                if op_2_5 == 0:
                        # print(f'fregs[0] += fregs[1]')
                        fregs[0] += fregs[1]
                        fregs[0] &= 0xff
                elif op_2_5 == 1:
                        # print(f'fregs[0] ^= fregs[1]')
                        fregs[0] ^= fregs[1]
                elif op_2_5 == 2:
                        a(0xac | op_0_2)
                        a(0xb8 | op_0_2)
                        a(0x8c | op_0_2)
                        a(0x90 | op_0_2)
                        a(0xb8 | op_0_2)
                        a(0xb0 | op_0_2)
                elif op_2_5 == 3:
                        # print(f'fregs[1] = box[{op_0_2}][wregs[{op_0_2 * 2 + op_5_6}]]')
                        fregs[1] = box[op_0_2][wregs[op_0_2 * 2 + op_5_6]]
                elif op_2_5 == 4:
                        # print(f'box[{op_0_2}][wregs[{op_0_2 * 2 + op_5_6}]] = fregs[0]')
                        box[op_0_2][wregs[op_0_2 * 2 + op_5_6]] = fregs[0]
                elif op_2_5 == 5:
                        # print(f'fregs[1] = box[{op_0_2}][fregs[0]]')
                        fregs[1] = box[op_0_2][fregs[0]]
                elif op_2_5 == 6:
                        # print(f'fregs[0] = fregs[1]');
                        fregs[0] = fregs[1]
                        # print(f'fregs[1] = 0');
                        fregs[1] = 0
                elif op_2_5 == 7:
                        a(0xa4 | op_0_2)
                        # print(f'fregs[4] += fregs[0] != 0')
                        fregs[4] += fregs[0] != 0
        else:
                assert False

def b(op):
        op_1_3 = (op >> 1) & 3
        op_3_5 = (op >> 3) & 3
        op_5_6 = (op >> 5) & 1
        op_6_8 = (op >> 6) & 3
        if op_6_8 == 0:
                # print(f'cregs[{2 * op_1_3}] = cregs[{2 * op_1_3 + 1}]')
                cregs[2 * op_1_3] = cregs[2 * op_1_3 + 1]
                # print(f'cregs[{2 * op_1_3 + 1}] = 0')
                cregs[2 * op_1_3 + 1] = 0
                # print(f'cregs[{2 * op_3_5}] = cregs[{2 * op_3_5 + 1}]')
                cregs[2 * op_3_5] = cregs[2 * op_3_5 + 1]
                # print(f'cregs[{2 * op_3_5 + 1}] = 0')
                cregs[2 * op_3_5 + 1] = 0
        elif op_6_8 == 1:
                # print(f'cregs[{op_3_5 | (4 * op_5_6)}] = cregs[{op_1_3}]')
                cregs[op_3_5 | (4 * op_5_6)] = cregs[op_1_3]
        elif op_6_8 == 2:
                if op_5_6:
                        # print(f'fregs[{op_3_5}] = cregs[{2 * op_1_3}]')
                        fregs[op_3_5] = cregs[2 * op_1_3]
                else:
                        # print(f'cregs[{2 * op_1_3 + 1}] = fregs[{op_3_5}]')
                        cregs[2 * op_1_3 + 1] = fregs[op_3_5]
        elif op_6_8 == 3:
                # print(f'fregs[3] = {hex(op & 0x3f)}')
                fregs[3] = op & 0x3f
        else:
                assert False

def c(op1, op2):
        op1 &= 3
        assert op2 <= 0xf
        a(0x4c | op1)
        b(0xa0 | (op2 << 1))
        a(0x80)
        a(0x40 | op1)
        a(0x8c | op1)
        a(0x64 | op1)
        a(0x80)
        a(0x60 | op1)
        a(0x88 | op1)

def f(op1, op2):
        op1_bytes = op1.to_bytes(4, 'little')

        op2_0 = op2 & 0xff
        op1_bytes_op2_0 = op1_bytes[op2_0]
        b(0xc0 | (op1_bytes_op2_0 & 0x3f))
        b(0x98 | ((((op1_bytes_op2_0 >> 6) + op2_0) & 3) << 1))

        op2_1 = (op2 >> 8) & 0xff
        op1_bytes_op2_1 = op1_bytes[op2_1]
        b(0xc0 | (op1_bytes_op2_1 & 0x3f))
        b(0x98 | ((((op1_bytes_op2_1 >> 6) + op2_1) & 3) << 1))

        op2_2 = (op2 >> 16) & 0xff
        op1_bytes_op2_2 = op1_bytes[op2_2]
        b(0xc0 | (op2_2 & 0x3f))
        b(0x98 | ((((op2_2 >> 6) + op2_2) & 3) << 1))

        op2_3 = (op2 >> 24) & 0xff
        op1_bytes_op2_3 = op1_bytes[op2_3]
        b(0xc0 | (op2_3 & 0x3f))
        b(0x98 | ((((op2_3 >> 6) + op2_3) & 3) << 1))

        b(((op2_2 << 3) | (op2_3 << 1)) & 0xff)

        c(op2_0, op2_2)
        c(op2_1, op2_3)

        
        b(0xc0 | (op1_bytes_op2_2 & 0x3f))
        b(0x98 | ((op2_2 & 3) << 1))

        b(0xc0 | (op1_bytes_op2_3 & 0x3f))
        b(0x98 | ((op2_3 & 3) << 1))

        a(0x20 | (op1_bytes_op2_2 >> 6))
        a(0x24 | (op1_bytes_op2_3 >> 6))

        b(((op2_2 << 3) | (op2_3 << 1)) & 0xff)

        b(((op2_0 << 3) | (op2_1 << 1)) & 0xff)

        a(0x8c | op2_0)
        a(0xb8 | op2_0)
        a(0xac | op2_0)
        a(0x80)
        a(0xb4 | op2_0)
        a(0x98 | op2_0)
        b(0xa8 | (op2_0 << 1))
        a(0x84)
        b(0xa8 | (op2_2 << 1))
        a(0x00)
        a(0x9c)
        a(0x8c | op2_1)
        a(0xb8 | op2_1)
        a(0xac | op2_1)
        a(0x80)
        a(0xb4 | op2_1)
        a(0x98 | op2_1)
        b(0xa8 | (op2_1 << 1))
        a(0x84)
        b(0xa8 | ((op2_3 & 3) << 1))
        a(0x04)
        a(0x9c)

def bf(x, y, x_0, x_1):
        for i in range(0x40):
                for j in range(0x40):
                        load()
                        f(x | (i << (8 * x_0)) | (j << (8 * x_1)), y)
                        if fregs[4] == 0:
                                save()
                                return i, j
        assert False

values = [
        [0xB1000018, 0x3000201, 1, 2],
        [0xA4090000, 0x3020100, 0, 1],
        [0x2AA600, 0x2010003, 3, 0],
        [0x1B009E, 0x2000103, 3, 1],
        [0x570096, 0x2000103, 3, 1],
        [0xAD005D, 0x2000103, 3, 1],
        [0xAE750000, 0x2030100, 0, 1],
        [0x65AC00, 0x1020300, 0, 3],
        [0x8C09, 0x1000203, 3, 2],
        [0x76A0, 0x1000203, 3, 2],
        [0x472C0000, 0x2030100, 0, 1],
        [0x10000001, 0x30201, 1, 2],
        [0x7C000F, 0x20301, 1, 3],
        [0xBA0047, 0x20301, 1, 3],
        [0x953000, 0x1020003, 3, 0],
        [0x74009B00, 0x3010200, 0, 2],
        [0x2D00003F, 0x3000102, 2, 1],
        [0x9A2D, 0x1000203, 3, 2],
        [0x3187, 0x1000302, 2, 3],
        [0xBA43, 0x10302, 2, 3],
        [0x2C70, 0x1000302, 2, 3],
        [0x56004C00, 0x3010200, 0, 2]
]

flag_s = []
for value in values:
        flag_s.extend(bf(*value))
        print(flag_s)

flag = []
for i in range(0, len(flag_s), 4):
        flag.append(((flag_s[i + 0] << 2) | (flag_s[i + 1] >> 4)) & 0xff)
        flag.append(((flag_s[i + 1] << 4) | (flag_s[i + 2] >> 2)) & 0xff)
        flag.append(((flag_s[i + 2] << 6) | (flag_s[i + 3] >> 0)) & 0xff)

print(bytes(flag))
# c669733af3ce4459b88016420b81cb15

pic#

比较简单,爆破 rc4 key 即可:

def rc4_encrypt(key, plaintext):
    S = list(range(256))
    j = 0
    out = []

    # Key-scheduling algorithm (KSA)
    for i in range(256):
        j = (j + S[i] + key[i % len(key)]) % 256
        S[i], S[j] = S[j], S[i]

    # Pseudo-random generation algorithm (PRGA)
    i = j = 0
    for char in plaintext:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        k = S[(S[i] + S[j]) % 256]
        out.append(char ^ k ^ 0x11)

    return bytes(out)

with open('flag.png.bak', 'rb') as f: data = f.read()

data_ = [i ^ 0x31 for i in data]

from tqdm import tqdm
from string import printable

# key = bytes.fromhex('3031373364')
# plaintext = rc4_encrypt(key, data_)
# print(key)
# if plaintext.startswith(b'\x89PNG\r\n\x1a\n'):
#     print(f"Key: {key.hex()}")
#     with open('real_flag.png', 'wb') as f: f.write(plaintext)

for i1 in printable:
    for i2 in tqdm(printable):
        for i3 in printable:
            for i4 in printable:
                for i5 in printable:
                    key = bytes([ord(i1), ord(i2), ord(i3), ord(i4), ord(i5)])
                    plaintext = rc4_encrypt(key, data_)
                    print(key)
                    if plaintext.startswith(b'\x89PNG\r\n\x1a\n'):
                        print(f"Key: {key.hex()}")
                        exit()

# b'0173d'
# Key: 3031373364

docCrack#

解压 docm 拿到 VBA ,用以下脚本反编译:

import oletools.olevba

def extract_vba_code(file_path):
    vba_parser = oletools.olevba.VBA_Parser(file_path)
    
    if vba_parser.detect_vba_macros():
        for (filename, stream_path, vba_filename, vba_code) in vba_parser.extract_macros():
            print("\n\nFound VBA code in file:", vba_filename)
            print("Code:\n", vba_code)

    vba_parser.close()

file_path = 'vbaProject.bin'
extract_vba_code(file_path)

去除掉所用的 Debug.Print "Never Gonna Give U Up~~~" 得到:

Sub AutoOpen()

    Set fso = CreateObject("Scripting.FileSystemObject")

    Set objShell = CreateObject("WScript.Shell")

    

    isContinue = 7

    temp = MsgBox("I?am???Vcke?!!!_I???m??Hac?er??!!???_am_Hac?er!!!_I_a?_????ok?r!!!", vbCritical, "Hacked_by_??????")

    Do

        inflag = InputBox("Give me your flag", "Hacked_by_??????")

        If inflag = "" Then

            inflag = "noflag"

        End If

        Result = ""

        For i = 1 To Len(inflag)

            res = Chr(Asc(Mid(inflag, i, 1)) Xor 7)

            Result = Result & res

        Next i
         tempPath = ThisDocument.Path & "\temp1"

        Set tempfile = fso.CreateTextFile(tempPath, True)

        fso.GetFile(tempPath).Attributes = 2

        tempfile.WriteLine xpkdb

        tempfile.Close

        ...

        batPath = ThisDocument.Path & "\temp.bat"

        Set batFile = fso.CreateTextFile(batPath, True)

        fso.GetFile(batPath).Attributes = 2

        batFile.WriteLine "@echo off"

        batFile.WriteLine "cd /d " & ThisDocument.Path

        batFile.WriteLine "certutil -decode temp1 temp|certutil -decode temp temp.exe"

        batFile.WriteLine "del temp"

        batFile.WriteLine "temp.exe " & """" & Result & """"

        batFile.WriteLine "del temp.exe"

        batFile.Close

        Set objExec = objShell.Exec(batPath)

        Set objStdOut = objExec.StdOut

        Do While Not objStdOut.AtEndOfStream

            output = Trim(objStdOut.ReadLine)

        Loop

        output = Left(output, Len(output))

        StartTime = Timer

        Do While Timer < StartTime + 1

            DoEvents

        Loop

        fso.DeleteFile batPath

        fso.DeleteFile tempPath

    

        If output = "good" Then

            temp = MsgBox("good!!!", , "congratulations!!!")

            Exit Do

        Else

            temp = MsgBox("Sorry, U are wrong!!!", , "Hacked_by_??????")

            isContinue = MsgBox("Continue?", vbYesNo + vbQuestion, "Warning")

        End If

    Loop While isContinue = 6

End Sub

中间有一大段字符串,两次解码之后得到一个 PE 文件,逻辑非常简单:

v9 = [0] * 54

v9[0] = 0x10C0
v9[1] = 4480
v9[2] = 5376
v9[3] = 4352
v9[4] = 5312
v9[5] = 4160
v9[6] = 7936
v9[7] = 5184
v9[8] = 6464
v9[9] = 6528
v9[10] = 5632
v9[11] = 3456
v9[12] = 7424
v9[13] = 5632
v9[14] = 6336
v9[15] = 6528
v9[16] = 6720
v9[17] = 6144
v9[18] = 6272
v9[19] = 7488
v9[20] = 6656
v9[21] = 7296
v9[22] = 7424
v9[23] = 2432
v9[24] = 2432
v9[25] = 2432
v9[26] = 5632
v9[27] = 4416
v9[28] = 3456
v9[29] = 7168
v9[30] = 6528
v9[31] = 7488
v9[32] = 6272
v9[33] = 5632
v9[34] = 3520
v9[35] = 6208
v9[36] = 5632
v9[37] = 4736
v9[38] = 6528
v9[39] = 6400
v9[40] = 7488
v9[41] = 3520
v9[42] = 5632
v9[43] = 5184
v9[44] = 3456
v9[45] = 0x1D40
v9[46] = 0x1C80
v9[47] = 0xC80
v9[48] = 0x1880
v9[49] = 0x1D00
v9[50] = 2432
v9[51] = 2432
v9[52] = 2432
v9[53] = 0x1E80

for i in range(0, 54):
    v9[i] = v9[i] >> 6
    v9[i] = v9[i] ^ 7
print(bytes(v9).decode('utf-8'))

# DASCTF{Vba_1s_dangerous!!!_B1ware_0f_Macr0_V1ru5es!!!}

你这主函数保真吗?#

看样子只是简单的计算,离散余弦变换+ROT13

cip = [
  513.355,
  -37.7986,
  8.7316,
  -10.7832,
  -1.3097,
  -20.5779,
  6.98641,
  -29.2989,
  15.9422,
  21.4138,
  29.4754,
  -2.77161,
  -6.58794,
  -4.22332,
  -7.20771,
  8.83506,
  -4.38138,
  -19.3898,
  18.3453,
  6.88259,
  -14.7652,
  14.6102,
  24.7414,
  -11.6222,
  -9.754759999999999,
  12.2424,
  13.4343,
  -34.9307,
  -35.735,
  -20.0848,
  39.689,
  21.879,
  26.8296
]

import numpy as np

def dct1d(data):
    n = len(data)
    dct_result = np.zeros_like(data, dtype=float)
    for k in range(n):
        sum_val = 0
        for i in range(n):
            sum_val += data[i] * np.cos((np.pi / n) * (i + 0.5) * k)
        if k == 0:
            dct_result[k] = np.sqrt(1/n) * sum_val
        else:
            dct_result[k] = np.sqrt(2/n) * sum_val
    return dct_result

def idct1d(dct_data):
    n = len(dct_data)
    idct_result = np.zeros_like(dct_data, dtype=float)
    for i in range(n):
        sum_val = 0
        for k in range(n):
            if k == 0:
                coeff = np.sqrt(1/n)
            else:
                coeff = np.sqrt(2/n)
            sum_val += coeff * dct_data[k] * np.cos((np.pi / n) * (i + 0.5) * k)
        idct_result[i] = sum_val
    return idct_result
# 假设这是离散傅里叶变换后的结果

X = np.array(cip)
x = idct1d(X)
for i in range(len(x)):
    print(chr(int(round(x[i]))), end='')

Wh0_1s_Ma1n_@nd_FunnY_Dct

2024年羊城杯初赛
https://0xd009.github.io/posts/2024年羊城杯初赛-reverse-writeup/
作者
0xD009
发布于
2024-09-15
许可协议
CC BY-NC-SA 4.0