SQCTF-RE
查看迷宫问题
把迷宫导出来
查看代码x <= 8 && maze[10 * x + 10 + y]可得迷宫的尺寸是 9 行 和 10 列
用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#
#*******##
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
数组逐字节解密。
先看虚拟机如何处理一次“解密过程”:
LOAD 0, 16 寄存器 0 得到 memory[16]
,即加密数据的第 1 个字节:127
XOR 0, 85 对 127 异或 85,计算:
复制代码
复制编辑
复制代码
127 ^ 85 = 42
此时寄存器 0 变为 42
STORE 0, 32 将 42 存入内存地址 32
LOAD 1, 32 将内存地址 32 的值加载到寄存器 1,即 42
XOR 1, 170 对 42 异或 170,计算:
复制代码
复制编辑
复制代码
42 ^ 170 = 128
此时寄存器 1 变为 128
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 计算 结果 127 255 – 127 = 128 128 131 255 – 131 = 124 124 125 255 – 125 = 130 130 123 255 – 123 = 132 132 135 255 – 135 = 120 120 127 255 – 127 = 128 128 133 255 – 133 = 122 122 123 255 – 123 = 132 132 125 255 – 125 = 130 130 131 255 – 131 = 124 124 127 255 – 127 = 128 128 135 255 – 135 = 120 120 131 255 – 131 = 124 124 123 255 – 123 = 132 132 135 255 – 135 = 120 120 125 255 – 125 = 130 130
于是解密后的数据为:
复制代码
复制编辑
复制代码
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。
注意
虽然题目提供的虚拟机代码中只处理了一次操作,但根据描述,整个加密数据需要逐字节还原。
由于 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)
暂无评论