boxmoe_header_banner_img

欢迎来到烨的世界~

加载中

文章导读

SQCTF-RE


avatar
liuye 2025年4月21日 64

RE

慕然回首,那人却在灯火阑珊处

查看迷宫问题

把迷宫导出来

查看代码x <= 8 && maze[10 * x + 10 + y]可得迷宫的尺寸是 910

用python打印出来

复制代码
# 迷宫字符串
maze_str = (
    "S**#########*########**#########**#########*###**##***###**##*#####**##*#####*E##*******############"
)

# 每行的字符数
characters_per_row = 10

# 打印迷宫
for i in range(0, len(maze_str), characters_per_row):
    print(maze_str[i:i+characters_per_row])

迷宫如下,不算复杂,手对照解

S**#######

##*#######

#**#######

##**######

###*###**#

#***###**#

#*#####**#

#*#####*E#

#*******##

ezRe

pyinstxtractor.py 33.exe

在线网站反编译pyc

https://tool.lu/pyc

Base64解密5ed2be45-2e83-48d2-b631-c088e51ee964

鹅鹅鹅,曲项向天歌

pyinstxtractor.py eee.exe

在线网站解码pyc

https://tool.lu/pyc

简单逆向

复制代码
def decrypt_flag():
    ciphertext = 'itd~tzw_know_sanmenxbZ8'
    part2_1_enc = ciphertext[:7]
    part2_2_enc = ciphertext[7:20]
    part2_3_enc = ciphertext[20:]
    part2_1 = ''.join([chr(ord(c) - 5) for c in part2_1_enc])
    part2_2 = part2_2_enc
    part2_3 = ''.join([chr(ord(c) + 7) for c in part2_3_enc])
    part2 = part2_1 + part2_2 + part2_3
    flag = 'SQCTF{' + part2 + '}'
    return flag

decrypted_flag = decrypt_flag()
print("解密后的flag是:", decrypted_flag)
复制代码
# SQCTF{do_your_know_sanmenxia?}
复制代码
 

圣人当仁不让

分析代码先经过vm_execute加密再经过base64加密

Exp:

复制代码
import base64

def reverse_vm_execute(data):
    decrypted_data = bytearray(data)
    for i in range(min(len(decrypted_data), 17)):
        decrypted_data[i] = (decrypted_data[i] + 2) % 256
        decrypted_data[i] = (decrypted_data[i] - 5) % 256
        decrypted_data[i] = decrypted_data[i] ^ 0xAA
    return bytes(decrypted_data)

encoded_str = "/P7sAe/U0s7c1vjb0vjfyt=="
decoded_data = base64.b64decode(encoded_str)
final_data = reverse_vm_execute(decoded_data)
print("Decrypted Data:", final_data.decode('utf-8', 'ignore'))

往事暗沉不可追

Ai一把梭

分析 VM 代码

题目提供了一个简单的虚拟机(SimpleVM),它支持三条指令:

  • LOAD reg, addr:将内存地址 addr 的值加载到寄存器 reg
  • XOR reg, value:将寄存器 reg 的值与 value 异或
  • STORE reg, addr:将寄存器 reg 的值写回内存地址 addr

程序执行的 bytecode 为:

复制代码
vbnet
复制代码
复制编辑
复制代码
LOAD  0, 16
复制代码
XOR   0, 85
复制代码
STORE 0, 32
复制代码
LOAD  1, 32
复制代码
XOR   1, 170
复制代码
STORE 1, 48

并且题目将一个 16 字节的数组

复制代码
ini
复制代码
复制编辑
复制代码
encrypted_data = [127, 131, 125, 123, 135, 127, 133, 123, 125, 131, 127, 135, 131, 123, 135, 125]

加载到了内存地址 16 开始的位置。

分步模拟指令

注意:题目的代码中 execute 函数并没有用循环处理所有指令,而只执行了一组指令(实际上只处理了第一条数据)。但根据题目的描述,“解密后的数据就是 flag”,很可能是要求对整个 encrypted_data 数组逐字节解密。

先看虚拟机如何处理一次“解密过程”:

  1. LOAD 0, 16
    寄存器 0 得到 memory[16],即加密数据的第 1 个字节:127
  2. XOR 0, 85
    对 127 异或 85,计算:
复制代码
复制编辑
复制代码
127 ^ 85 = 42

此时寄存器 0 变为 42

  1. STORE 0, 32
    将 42 存入内存地址 32
  2. LOAD 1, 32
    将内存地址 32 的值加载到寄存器 1,即 42
  3. XOR 1, 170
    对 42 异或 170,计算:
复制代码
复制编辑
复制代码
42 ^ 170 = 128

此时寄存器 1 变为 128

  1. STORE 1, 48
    将 128 存入内存地址 48

观察这两次 XOR 操作:

  • 第一次 XOR 用的是 85
  • 第二次 XOR 用的是 170

实际上,对于任意一个字节 x,有
  (x ^ 85) ^ 170 = x ^ (85 ^ 170)
而 85 ^ 170 = 255
因此整体操作相当于:
  decrypted = encrypted ^ 255

注意到 8 位数与 255 异或,相当于按位取反(即 ~x,对于 8 位数据,~x = 255 – x)。

应用于整个 encrypted_data

题目中有 16 个字节,加密数据为:

复制代码
复制编辑
复制代码
127, 131, 125, 123, 135, 127, 133, 123, 125, 131, 127, 135, 131, 123, 135, 125

对每个字节 x 进行操作 x ^ 255 得到:

加密字节 x计算结果
127255 – 127 = 128128
131255 – 131 = 124124
125255 – 125 = 130130
123255 – 123 = 132132
135255 – 135 = 120120
127255 – 127 = 128128
133255 – 133 = 122122
123255 – 123 = 132132
125255 – 125 = 130130
131255 – 131 = 124124
127255 – 127 = 128128
135255 – 135 = 120120
131255 – 131 = 124124
123255 – 123 = 132132
135255 – 135 = 120120
125255 – 125 = 130130

于是解密后的数据为:

复制代码
复制编辑
复制代码
128,124,130,132,120,128,122,132,130,124,128,120,124,132,120,130

题目说明“解密后的数据就是 flag,用逗号隔开”,并且要求 flag 的格式为 SQCTF{...}

得出 flag

综合上述步骤,最终 flag 就是将解密后的数字直接用逗号分隔后放在 SQCTF{} 内:

复制代码
复制编辑
复制代码
SQCTF{128,124,130,132,120,128,122,132,130,124,128,120,124,132,120,130}

这就是本题的 flag。


注意

  1. 虽然题目提供的虚拟机代码中只处理了一次操作,但根据描述,整个加密数据需要逐字节还原。
  2. 由于 XOR 的结合律,先 XOR 85 后 XOR 170 相当于直接 XOR 255,即对每个字节取反。

你可以用 Python 快速验证:

复制代码
python
复制代码
复制编辑
复制代码
encrypted_data = [127, 131, 125, 123, 135, 127, 133, 123, 125, 131, 127, 135, 131, 123, 135, 125]
复制代码
decrypted = [x ^ 255 for x in encrypted_data]
复制代码
print(decrypted)
复制代码
# 输出: [128, 124, 130, 132, 120, 128, 122, 132, 130, 124, 128, 120, 124, 132, 120, 130]

最终提交 flag 为:

SQCTF{128,124,130,132,120,128,122,132,130,124,128,120,124,132,120,130}

春风也有春风愁

Ida分析

v7 = (v8 ^ 0xA5) + 55然后和v6去比较

v6=70FBF715FA08FD0B0D0F0E011431130DFB

但是解出来的值不对

回去尝试用前半段去解

发现解出来是逆逆序,sqctf{ea

后一段逆序解出来的是asy_xor}

猜测可能是sqctf{easy_xor}

v6_hex = “70FBF715FA08FD0B0D”
v7_hex = “0F0E011431130DFB”
v6_bytes = bytes.fromhex(v6_hex)
v7_hex = bytes.fromhex(v7_hex)

flag = “”
flag1 = “”
for b in v6_bytes:
    decrypted = ((b – 55) % 256) ^ 0xA5
    flag += chr(decrypted)
flag=flag[::-1]

for b in v7_hex:
    decrypted = ((b – 55) % 256) ^ 0xA5
    flag1 += chr(decrypted)

flag1=flag1[::-1]
print(“Recovered flag:”, flag,flag1)

回想了一下应该是段序问题,当时64位一看没想过这个问题

遇事不决,可问春风

复制代码
有个亦或函数result.append((char) (c ^ 'B'));

拼接了一个字符串

“SQCTF{i_am_a_” + password + FLAG_SUFFIX;

Key给了=66

encrypted_parts = [“5”, “#”, “)”, “7”, “5”, “#”, “)”, “7”]
encrypted = ”.join(encrypted_parts)
xor_key = 66
decrypted = ”.join([chr(ord(c) ^ xor_key) for c in encrypted])
flag = f”SQCTF{{i_am_a_{decrypted}}}”
print(“Flag 是:”, flag)

你若安好便是晴

题目提示喝杯

用findcrypt识别一下

分析一下代码,先经过tea再经过sub_100

查看tea发现有挺多魔改

魔改了魔数和加密过程还有加密符号

再查看sub_100是一个亦或算法

回去查看main函数,发现没有比较,下个断点flag就出来了

人生自古谁无死

分析一下代码,程序没有输入判断,猜测程序可能存在自解密

但是有反调试

看了一下加密逻辑主要在handle_strings

Puts是个输出函数

在check之前下个断点

把rip栈针改到handle_strings()的位置

在ret的位置下个断点

运行一下,v13就是flag

天下谁人不识君

简单逆向爆破所有字符去做比较

s = ‘wesyvbniazxchjko1973652048@$+-&*<>’
result = ‘v7b3boika$h4h5j0jhkh161h79393i5x010j0y8n$i’

flag = ”

for i in range(0, len(result), 2):
    c1 = result[i]
    c2 = result[i+1]
    index = i // 2
    found = False
    for c in range(32, 127):
        s1 = c // 17
        s2 = c % 17
        e1 = s[(s1 + index) % 34]
        e2 = s[-(s2 + index + 1) % 34]
        if e1 == c1 and e2 == c2:
            flag += chr(c)
            found = True
            break
    if not found:
        flag += ‘?’  # 标记未匹配的字符

print(‘Recovered flag:’, flag)

不劳春风解我忧

Xxtea_encrypt字符没有删除,猜测xxtea

V=是key

Block是密文

直接上板子出来了

#include <stdio.h>

#include <stdint.h>

#include <string.h>

#define DELTA 0x9e3779b9

void xxtea_decrypt(uint32_t *v, int n, uint32_t *key) {

    uint32_t y, z, sum;

    int p, rounds, e;

    rounds = 6 + 52 / n;

    sum = rounds * 0x9E3779B9; 

    y = v[0];

    do {

        e = (sum >> 2) & 3;

        for (p = n – 1; p > 0; p–) {

            z = v[p – 1];

            v[p] -= ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (key[(p & 3) ^ e] ^ z));

            y = v[p];

        }

        z = v[n – 1];

        v[0] -= ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (key[(p & 3) ^ e] ^ z));

        y = v[0];

        sum -= 0x9E3779B9; 

    } while (sum != 0); 

}

int main() {

    uint32_t key[4] = {0x12345678 ,0x9ABCDEF0 ,0xFEDCBA98 ,0x87654321};

    uint32_t data[] = {0x8F748963 ,0xCB1D96A8};

    int data_len = sizeof(data) / sizeof(data[0]);

    printf(“Original Data:\n”);

    for (int i = 0; i < data_len; i++) {

        printf(“%u\n”, data[i]);

    }

    xxtea_decrypt(data, data_len, key);

    printf(“Decrypted Data (Printable Characters):\n”);

    for (int i = 0; i < data_len; i++) {

        char c = (char)data[i];

       printf(“%c%c%c%c”,*((char*)&data[i]+0),*((char*)&data[i]+1),*((char*)&data[i]+2),*((char*)&data[i]+3));//这个地方也是很重要的

    }

    printf(“\n”);

    return 0;

}

即随本心

pyinstxtractor.py 即随本心.exe

丢在线网站

https://tool.lu/pyc

简单看了一下,经过aes再经过base64

Key和iv都给了,直接上脚本

from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import base64

# 给定的数据
expected_encrypted_data = ‘MTIzNDU2Nzg5MGFiY2RlZpOn0SHxbVMvaa7jQztMCBtCCiuX+ZRBzSfcL01St5Bmi8BjGeuXliictrjqzSpCGw==’

# 解码base64
decoded_data = base64.b64decode(expected_encrypted_data)

# 提取IV和密文
iv = decoded_data[:16]  # 前16字节是IV
ciphertext = decoded_data[16:]  # 剩余部分是密文

# 使用相同的密钥
key = b’1234567890abcdef’

# 创建AES解密器
cipher = AES.new(key, AES.MODE_CBC, iv)

# 解密
padded_plaintext = cipher.decrypt(ciphertext)

# 去除填充
try:
    plaintext = unpad(padded_plaintext, AES.block_size)
    print(“解密成功!Flag是:”, plaintext.decode(‘utf-8’))
except ValueError:
    print(“解密失败,可能是填充不正确”)

唧唧复唧唧,木兰当户织

Ida打开看了一下有upx

Upx-d 唧唧复唧唧,木兰当户织.exe

查看代码,就一个base64

随波逐流SQCTF{xixibuxixi,mulandanghuzhi}把中文字改成英文字符

看山不是山

pyinstxtractor.py 看水不是水.exe

丢在线网站https://tool.lu/pyc/

可以看出是伪随机,没学过,ai一把梭

复制代码
def decrypt(encrypted_data):
    result = []
    key = 439041101  # 0x1A2B3C4D
    for i in range(len(encrypted_data)):
        byte = encrypted_data[i]
        # 逆向加法操作
        byte = (byte - i) & 255
        # 逆向异或操作
        byte = (byte ^ (key >> ((i % 4) * 8))) & 255
        result.append(byte)
    return bytes(result)

# 目标加密数据
target = bytes.fromhex('738495a6b7c8d9e0f123456789abcdef')

# 解密得到原始输入
original_data = decrypt(target)
print("原始输入:", original_data)
print("十六进制:", original_data.hex())

SQCTF{3ebfb8b9fefff8c3a426104630a294fa}

击败abyssun

呜呜呜,被游戏逆向思维误导了

一直搁那搜血量,干了一个小时

后面搜红温了才想起来flag头固定

直接用CE搜SQCTF

拉下来改长度50



评论(0)

查看评论列表

暂无评论


发表评论

00:00/00:00