NSSCTF刷题日记
2025.11.18
刚开始使用这个网站,感觉像。。。付费制洛谷?(会员制) 先白嫖做几道看看吧。
[SWPUCTF 2021 新生赛]简简单单的逻辑
好水的题,题目给出了一个 python 文件,打开就能看到源代码。
点击查看代码
flag = 'xxxxxxxxxxxxxxxxxx'
list = [47, 138, 127, 57, 117, 188, 51, 143, 17, 84, 42, 135, 76, 105, 28, 169, 25]
result = ''
for i in range(len(list)):
key = (list[i]>>4)+((list[i] & 0xf)<<4)
result += str(hex(ord(flag[i])^key))[2:].zfill(2)
print(result)
# result=bcfba4d0038d48bd4b00f82796d393dfec
key = (list[i]>>4)+((list[i] & 0xf)<<4)
实际上是将 list 中每个数字的二进制高4位和低4位进行互换
如十六进制的 0xAB 会变成 0xBA
加密是通过异或,再异或一边就能还原回去。
解密脚本如下:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
string result_hex="bcfba4d0038d48bd4b00f82796d393dfec";
int List[17]={47, 138, 127, 57, 117, 188, 51, 143, 17, 84, 42, 135, 76, 105, 28, 169, 25};
string flag;
int hex_change(char c) {
if (c >= '0' && c <= '9') {
return c - '0'; // '0'->0, '9'->9
}
if (c >= 'a' && c <= 'f') {
return c - 'a' + 10; // 'a'->10, 'f'->15
}
if (c >= 'A' && c <= 'F') {
return c - 'A' + 10; // 支持大写字母
}
return 0;
}
signed main(){
int len=17;
for (int i=0;i<len;++i) {
int key=(List[i]>>4) + ((List[i]&0xf)<<4);
char h1=result_hex[i*2];
char l1=result_hex[i*2+1];
int h2=hex_change(h1);
int l2=hex_change(l1);
int ans=h2*16+l2;
flag+=char(ans^key);
}
cout<<flag;
return 0;
}
NSSCTF{EZEZ_RERE}
[SWPUCTF 2025 秋季新生赛]Ultimate Packer for eXecutables
2025.11.19
一眼带壳,先脱壳。
直接扔 UPX 脱壳工具,发现脱不了壳,但 ida 里的样子明显是 UPX 壳的形式。
盲猜魔改 UPX 壳。
扔进 hex 编辑器里(我用的 010editor )
果然 UPX 的标志位(UPX0、UPX1、UPX2、UPX!)被改了。

手动改回来即可正常脱壳。
脱壳后再扔进 ida 里即可见到加密函数。

主要的加密函数为
\(y = 122 \times x - 23\)
解密方程为:
\(122 \times x \equiv (y + 23) \pmod{256}\)
考虑到 CTF 题的 flag 一般只用常用字符
解这个方程最简单的办法就是在常用字符范围内枚举爆破(32 到 126)。
解密脚本如下:
#include<bits/stdc++.h>
using namespace std;
unsigned char s[] = {
0x15, 0x77, 0x77, 0xD7, 0xF1, 0x45, 0x87, 0x6B,
0x49, 0x19, 0xEF, 0x93, 0xB7, 0x93, 0x93, 0xA3,
0xB7, 0x23, 0xAB, 0x93, 0xA3, 0x17, 0xB1, 0x3D,
0x49, 0xA3, 0x7B
};
signed main(){
int len=sizeof(s);
for (int i=0;i<len;++i) {
for (int j=32;j<=126;++j) {
int k=(j*122-23)%256;
if (k==s[i]) {
cout<<char(j); break;
}
}
}
return 0;
}
求得 flag 为
NSSCTF{Upx?ysyy!sauy!c4rp!}
注:
- 解释一下解密方程这个 模上 \(256\) 怎么来的。
我们输入的是个 char 数组,char 类型的变量只能存最后 \(8\) 位。
即:砍掉高位、只留低 \(8\) 位
相当于对 \(256\) 取模。
- 还有一个地方需要注意,
处理密文(尤其是 Hex 数据)永远建议使用 unsigned char 或者 uint8_t,否则只要出现大于 0x7F 的字节,就会因为符号位问题导致比较失败。
我一开始定义密文数组用的是 char ,结果输出结果一直不对。
因为密文数组里存在 0xD7 这种值。
常用编译器(如 GCC ),定义 char 时默认是 signed char (有符号)。
虽然 unsigned char (无符号) 和 signed char 范围都是 256 ,但也略有不同。
-
unsigned char: 0 ~ 255
-
signed char: -128 ~ 127
0xD7 (二进制 11010111)
作为 unsigned char (无符号) 是 \(215\) 。
作为 char (有符号) 则是 \(-41\) (最高位是 \(1\) 被当成负数了 ) 。
在比较 \(215 == -41\) 时,结果显然是 false,脚本根本找不到匹配的字符,自然会出错。
[LitCTF 2025]easy_tea
2025.11.21
下载下来的程序名叫 ”花“ ,可以想到花指令 (其实是题目标签里有)
[青海民族大学 2025 新生赛]你的flag被加密啦!
2025.11.24
这题评分这么低不是没理由的。
纯粹的分析 python 代码逆向,有点无聊了。
解题脚本(python):
点击查看代码
def custom_decrypt(ciphertext):
decrypted = ""
key = [3, 5, 2]
key_index = 0
for char in ciphertext:
if 'a' <= char <= 'z':
shift = key[key_index]
# 逆向操作:减去 shift
# Python 的 % 运算对负数处理很方便: -3 % 26 = 23,符合凯撒密码逻辑
new_char = chr((ord(char) - ord('a') - shift) % 26 + ord('a'))
key_index = (key_index + 1) % len(key)
elif 'A' <= char <= 'Z':
shift = key[key_index]
new_char = chr((ord(char) - ord('A') - shift) % 26 + ord('A'))
key_index = (key_index + 1) % len(key)
elif '0' <= char <= '9':
num = int(char)
# 逆向操作:减去 7
new_num = (num - 7) % 10
new_char = str(new_num)
# 注意:数字不改变 key_index
else:
new_char = char
# 注意:符号不改变 key_index
decrypted += new_char
return decrypted
cipher_text = "iqcj{qafmgh89991}"
flag = custom_decrypt(cipher_text)
print(f"Flag: {flag}")
[GHCTF 2025]LockedSecret
2025.11.24
先是 UPX 魔改壳。

可以看到 UPX 壳的开头莫名出现了一串乱码,但经实测并无影响。
问题还是因为 UPX 的标志位被改了, 010editor 里改回来即可正常脱壳。
脱壳后扔入 ida 里查看主函数

先打开 sub_401100() 这个函数。
可以看到是通过随机数函数初始化数组。
点击查看代码
int sub_401100()
{
int i; // [esp+0h] [ebp-4h]
srand(0xC17FF9CC);
for ( i = 0; i < 8; ++i )
{
if ( i )
dword_4043D8[i] = dword_4043D4[i] ^ rand();
else
dword_4043D8[0] = rand();
dword_4043D8[i] %= 256;
}
return 0;
}
再点开 sub_401190(Str) 这个函数,可以看到是 XTEA 加密
直接写逆向脚本有点困难,但其实可以在这个函数结束设断点提取出 key 再写脚本。
不过我选择 AI (真的写不动了)。
点击查看代码
import struct
# 1. 密钥 (来自你的 Dump)
# unsigned int data[5]
# 我们只需要前4个作为 TEA/XTEA 的 Key
KEY = [0x423DF72D, 0x05F59A01, 0x633FCF1D, 0x77D19122]
# 2. 密文数据 (byte_404060)
encrypted_bytes = bytes([
0xDC, 0x45, 0x1E, 0x03, 0x89, 0xE9, 0x76, 0x27, 0x47, 0x48, 0x23, 0x01, 0x70, 0xD2, 0xCE, 0x64,
0xDA, 0x7F, 0x46, 0x33, 0xB1, 0x03, 0x49, 0xA3, 0x27, 0x00, 0xD1, 0x2C, 0x37, 0xB3, 0xBD, 0x75
])
# 3. 常量表
CONSTANTS = [
0x5E2377FF, # C1
-0x43B91002, # C2
0x1A6A67FD, # C3
0x788DDFFC, # C4
-0x294EA805, # C5
0x34D4CFFA, # C6
-0x6D07B807, # C7
-0xEE44008 # C8
]
# 转无符号
C = [c & 0xFFFFFFFF for c in CONSTANTS]
def T(val, k_a, k_b, c):
"""
加密核心变换函数: ((k_a + (val >> 5)) ^ (val + c) ^ (k_b + val * 16))
"""
val &= 0xFFFFFFFF
p1 = (k_a + (val >> 5)) & 0xFFFFFFFF
p2 = (val + c) & 0xFFFFFFFF
p3 = (k_b + (val * 16)) & 0xFFFFFFFF
return p1 ^ p2 ^ p3
def decrypt_block(v_low, v_high):
# 输入对应 Str[0] (L_final) 和 Str[4] (R_final)
# 1. 初始异或还原
# 代码中: *(_DWORD *)&Str[...] = VAL ^ 0xF;
L = v_low ^ 0xF
R = v_high ^ 0xF
# 注意:反编译代码中的变量赋值流向决定了逆向顺序
# 我们将变量命名为 L, R,并逐步回退状态
# === 逆向 Steps 15 & 16 (Using C8) ===
# 正向逻辑:
# L7 = L6 + T(R7, K01, C8)
# R8 = R7 + T(L7, K23, C8)
# 此时 L=L7, R=R8
# 1. 还原 R7
term = T(L, KEY[3], KEY[2], C[7])
R = (R - term) & 0xFFFFFFFF
# 2. 还原 L6
term = T(R, KEY[1], KEY[0], C[7])
L = (L - term) & 0xFFFFFFFF
# === 逆向 Steps 13 & 14 (Using C7) ===
# R7 = R6 + T(L6, K23, C7) -> 还原 R6
term = T(L, KEY[3], KEY[2], C[6])
R = (R - term) & 0xFFFFFFFF
# L6 = L5 + T(R6, K01, C7) -> 还原 L5
term = T(R, KEY[1], KEY[0], C[6])
L = (L - term) & 0xFFFFFFFF
# === 逆向 Steps 11 & 12 (Using C6) ===
# R6 = R5 + T(L5, K23, C6) -> 还原 R5
term = T(L, KEY[3], KEY[2], C[5])
R = (R - term) & 0xFFFFFFFF
# L5 = L4 + T(R5, K01, C6) -> 还原 L4
term = T(R, KEY[1], KEY[0], C[5])
L = (L - term) & 0xFFFFFFFF
# === 逆向 Steps 9 & 10 (Using C5) ===
# R5 = R4 + T(L4, K23, C5) -> 还原 R4
term = T(L, KEY[3], KEY[2], C[4])
R = (R - term) & 0xFFFFFFFF
# L4 = L3 + T(R4, K01, C5) -> 还原 L3
term = T(R, KEY[1], KEY[0], C[4])
L = (L - term) & 0xFFFFFFFF
# === 逆向 Step 8 (Using C4) ===
# R4 = R3 + T(L3, K23, C4) -> 还原 R3
term = T(L, KEY[3], KEY[2], C[3])
R = (R - term) & 0xFFFFFFFF
# === 逆向 "Mixed Round" Steps 5, 6, 7 (Using C3 and C4) ===
# 这是一个特殊的复合步骤,正向逻辑如下:
# L_temp = L2 + T(R2, K01, C3)
# R3 = R2 + T(L_temp, K23, C3) <-- 对应代码 v12
# L3 = L_temp + T(R3, K01, C4) <-- 对应代码 v1
# 当前我们有 L3 (即 L) 和 R3 (即 R)
# 1. 还原 L_temp
# L_temp = L3 - T(R3, K01, C4)
term = T(R, KEY[1], KEY[0], C[3]) # C4 is at index 3
L_temp = (L - term) & 0xFFFFFFFF
# 2. 还原 R2 (此时 R 变为 R2)
# R2 = R3 - T(L_temp, K23, C3)
term = T(L_temp, KEY[3], KEY[2], C[2]) # C3 is at index 2
R = (R - term) & 0xFFFFFFFF
# 3. 还原 L2 (此时 L 变为 L2)
# L2 = L_temp - T(R2, K01, C3)
term = T(R, KEY[1], KEY[0], C[2]) # C3 is at index 2
L = (L_temp - term) & 0xFFFFFFFF
# === 逆向 Steps 3 & 4 (Using C2) ===
# R2 = R1 + T(L2, K23, C2) -> 还原 R1
term = T(L, KEY[3], KEY[2], C[1])
R = (R - term) & 0xFFFFFFFF
# L2 = L1 + T(R1, K01, C2) -> 还原 L1
term = T(R, KEY[1], KEY[0], C[1])
L = (L - term) & 0xFFFFFFFF
# === 逆向 Steps 1 & 2 (Using C1) ===
# R1 = R0 + T(L1, K23, C1) -> 还原 R0 (Initial High)
term = T(L, KEY[3], KEY[2], C[0])
R = (R - term) & 0xFFFFFFFF
# L1 = L0 + T(R0, K01, C1) -> 还原 L0 (Initial Low)
term = T(R, KEY[1], KEY[0], C[0])
L = (L - term) & 0xFFFFFFFF
return L, R
# 4. 执行解密
flag = b""
for i in range(0, 32, 8):
block = encrypted_bytes[i:i+8]
v0, v1 = struct.unpack("<2I", block)
dec_L, dec_R = decrypt_block(v0, v1)
flag += struct.pack("<2I", dec_L, dec_R)
print("Flag:", flag.decode('utf-8', errors='ignore'))
NSSCTF{!!!Y0u_g3t_th3_s3cr3t!!!}
[LitCTF 2025]Robbie Wanna Revenge
11.25
久违的 Unity 游戏题。
这次不是 Mono ,没法套上次的经验。
[LitCTF 2025]灵感菇🍄哩菇哩菇哩哇擦灵感菇灵感菇🍄
2025.11.25
这题目真叫这个名。
上道题目做半天没做出来,做到杂项缓缓。
题目给了一个网站,里头就一个“获取我的灵感菇”,按一下就生成这串抽象东西:

多生成了几次,发现每次生成的是一样的。
自己思考无果,最终逐渐理解一切------这种杂项题就该 bdfs 啊!
😓
直接搜索灵感菇编码,然后在 github 上找到破译脚本
还是探姬的(绷不住了)。
。。。。
直接执行脚本就能出 flag
这题是动态生成 flag ,所以重开题目要重新跑一边脚本

附上一段探姬对这题目的评价

[LitCTF 2025]消失的文字
2025.11.25
再做一道杂项缓缓。
下载下来得到如下:

解压 hidden-word .zip 需要输入密码。
把 .pcapng 文件扔随波逐流里,USB鼠标流量分析,得到压缩包密码。


密码是:868F-83BD-FF
解压下来后得到一个 hidden-word.txt
这个文件名就是提示

[央企杯 2025]big_e_rsa
12.16
密码题
考察 RSA 算法
解密脚本:
点击查看代码
from sage.all import *
from hashlib import md5
# 题目给出的数据
e = 1551272466605872863416403977607292631633701035332147619334397735304780667522023412306036671510826302844606446851894336124057998125262840234194050349637823374524170830050888493129093785047790768479824853974485992897094462464812937258543116078662875776075027424552496083294550754325632098348117392765307939361584083284301895309303537418746278506279259977605077340832463160592170634327044102649366071222424124607846377204960029629274181604893740461442615864409257969910222040007572920062878004810852999179043297689530784435487435361166796498735890127211075763324999654593958063926772895325778380833510441152388535129397
N = 114844384426038454254660651833814261274384746047765676028021231000119586728613054758356259645955152450739070905660390543576514347506026385857367390443306247721678976046962085618294460484178352540250850748434273095861501307425230078443520622440057792872004498471410258909184474490354627866870431592356692438209
# 1. 恢复 d
# 注意:必须使用与题目相同的计算方式(Integer(N)**RR(...))以复现相同的精度截断
# 题目中: d = Integer(N)**RR(0.31) -> 这是一个实数
# 题目中: e = inverse(Integer(d), phi_N) -> 这里将实数 d 转换为了整数
d_calc = Integer(Integer(N)**RR(0.31))
print(f"[*] Calculated d: {d_calc}")
# 2. 恢复 T (phi_N in challenge code)
# e * d = 1 + k * T => T = (e*d - 1) / k
# 估算 k: T 约为 N^2, 所以 k 约为 (e*d)/N^2
numerator = e * d_calc - 1
k_approx = numerator // (N**2)
# 确保整除
if numerator % k_approx == 0:
T = numerator // k_approx
print(f"[*] Recovered T: {T}")
else:
print("[!] Error: k approximation failed or d is incorrect.")
exit()
# 3. 解一元二次方程求 S = p + q
# 方程: S^2 + (N+1)S + (N^2 - N + 1 - T) = 0
a = 1
b = N + 1
c = N**2 - N + 1 - T
# 使用求根公式
delta = b**2 - 4*a*c
if delta < 0:
print("[!] Delta < 0, check math.")
exit()
delta_sqrt = Integer(delta).isqrt()
if delta_sqrt**2 != delta:
print("[!] Delta is not a perfect square.")
exit()
S = (-b + delta_sqrt) // (2*a)
print(f"[*] Recovered p+q: {S}")
# 4. 生成 Flag
flag_hash = md5(str(S).encode()).hexdigest()
flag = f'flag{{{flag_hash}}}'
print(f"[*] Flag: {flag}")
[GHCTF 2025]ASM?Signin!
12.16
逆向题
考察 ASM 语法。
过程有点枯燥,就是单纯翻译 ASM 语句。
交给 AI 哩


解题脚本:
点击查看代码
# 原始数据 DATA1
data1 = [
0x26, 0x27, 0x24, 0x25, 0x2A, 0x2B, 0x28, 0x00,
0x2E, 0x2F, 0x2C, 0x2D, 0x32, 0x33, 0x30, 0x00,
0x36, 0x37, 0x34, 0x35, 0x3A, 0x3B, 0x38, 0x39,
0x3E, 0x3F, 0x3C, 0x3D, 0x3F, 0x27, 0x34, 0x11
]
# 加密后的 Flag 数据 DATA2
data2 = [
0x69, 0x77, 0x77, 0x66, 0x73, 0x72, 0x4F, 0x46,
0x03, 0x47, 0x6F, 0x79, 0x07, 0x41, 0x13, 0x47,
0x5E, 0x67, 0x5F, 0x09, 0x0F, 0x58, 0x63, 0x7D,
0x5F, 0x77, 0x68, 0x35, 0x62, 0x0D, 0x0D, 0x50
]
# 模拟 DO1 函数:对 data1 进行置换
si = 0
for _ in range(8):
# 计算 DI
di = si + 4
# 模拟 JL NOWRAP 和 SUB DI, 28 逻辑
if di >= 28:
di -= 28
# 模拟 DO2:交换 4 个字节
for k in range(4):
# Python 中的多重赋值可以方便地进行交换
data1[si+k], data1[di+k] = data1[di+k], data1[si+k]
si += 4
# 此时 data1 已经是置换后的密钥了
# print("Permuted Key:", [hex(x) for x in data1])
# 模拟 ENC 的逆过程解密
flag = []
for i in range(0, 32, 4):
# 根据汇编逻辑:
# Input[0] ^ DATA1[1]
# Input[1] ^ DATA1[2]
# Input[2] ^ DATA1[2]
# Input[3] ^ DATA1[3]
# 当前块在 data1 和 data2 中的起始索引为 i
c0 = data2[i+0] ^ data1[i+1]
c1 = data2[i+1] ^ data1[i+2]
c2 = data2[i+2] ^ data1[i+2]
c3 = data2[i+3] ^ data1[i+3]
flag.extend([c0, c1, c2, c3])
# 输出结果
flag_str = "".join(chr(x) for x in flag)
print("Flag:", flag_str)
[GCCCTF 2025]constraint
2025.12.17
看到题目标签里有壳就做了,结果只是正常的 UPX 壳,脱壳后加密函数直接暴露出来了。
加密函数
_BOOL8 __fastcall verify_flag(char *Buffer)
{
_BOOL8 result; // rax
bool v3; // zf
__int64 i; // rdx
unsigned __int8 v5; // [rsp+18h] [rbp-68h]
unsigned __int8 v6; // [rsp+19h] [rbp-67h]
unsigned __int8 v7; // [rsp+1Ah] [rbp-66h]
unsigned __int8 v8; // [rsp+1Bh] [rbp-65h]
unsigned __int8 v9; // [rsp+1Ch] [rbp-64h]
unsigned __int8 v10; // [rsp+1Dh] [rbp-63h]
unsigned __int8 v11; // [rsp+1Eh] [rbp-62h]
unsigned __int8 v12; // [rsp+1Fh] [rbp-61h]
result = 0;
if ( ~(strlen(Buffer) + 1) == -18 )
{
v3 = memcmp(Buffer, "GCCCTF{", 7u) == 0;
result = !v3;
if ( v3 )
{
if ( Buffer[15] == 125 )
{
for ( i = 0; i != 8; ++i )
*(&v5 + i) = Buffer[i + 7];
if ( 13 * v9 + 11 * v7 + 3 * v6 + 7 * v5 == 2145
&& 9 * v10 + 12 * v8 + 8 * v6 + 4 * v12 == 2491
&& 5 * v7 + 6 * v5 + 8 * v11 + 7 * v12 == 2299
&& 11 * v9 + 9 * v8 + 6 * v10 + 10 * v11 == 3165 )
{
return (v10 ^ (unsigned __int8)(v6 ^ v5 ^ v7 ^ v9 ^ v8)) == 95;
}
}
}
else
{
return 0;
}
}
return result;
}
pyhton Z3 脚本求解
点击查看代码
from z3 import *
# 创建求解器
s = Solver()
# 定义 8 个 32 位向量变量 (对应 Buffer[7] 到 Buffer[14])
# 使用 BitVec(32) 可以同时支持加法乘法和异或运算
x = [BitVec(f'x{i}', 32) for i in range(8)]
# 添加 ASCII 可打印字符约束 (32 - 126)
for i in range(8):
s.add(x[i] >= 32)
s.add(x[i] <= 126)
# 变量映射 (根据反编译代码分析)
# v5 -> x[0]
# v6 -> x[1]
# v7 -> x[2]
# v8 -> x[3]
# v9 -> x[4]
# v10 -> x[5]
# v11 -> x[6]
# v12 -> x[7]
# 方程组约束
# 13 * v9 + 11 * v7 + 3 * v6 + 7 * v5 == 2145
s.add(13 * x[4] + 11 * x[2] + 3 * x[1] + 7 * x[0] == 2145)
# 9 * v10 + 12 * v8 + 8 * v6 + 4 * v12 == 2491
s.add(9 * x[5] + 12 * x[3] + 8 * x[1] + 4 * x[7] == 2491)
# 5 * v7 + 6 * v5 + 8 * v11 + 7 * v12 == 2299
s.add(5 * x[2] + 6 * x[0] + 8 * x[6] + 7 * x[7] == 2299)
# 11 * v9 + 9 * v8 + 6 * v10 + 10 * v11 == 3165
s.add(11 * x[4] + 9 * x[3] + 6 * x[5] + 10 * x[6] == 3165)
# XOR 约束
# v10 ^ (v6 ^ v5 ^ v7 ^ v9 ^ v8) == 95
# 注意:C语言中异或操作是右结合的,但异或本身满足交换律和结合律,顺序不影响结果
s.add((x[5] ^ x[1] ^ x[0] ^ x[2] ^ x[4] ^ x[3]) == 95)
# 求解
if s.check() == sat:
model = s.model()
# 提取结果并拼接字符串
flag_content = "".join([chr(model[x[i]].as_long()) for i in range(8)])
print(f"Found internal flag: {flag_content}")
print(f"Full Flag: GCCCTF{{{flag_content}}}")
else:
print("No solution found. Check constraints.")
GCCCTF{F14gH3re}
[VNCTF 2025]Fuko's starfish
2025.12.21
好题。
给出一个 .exe 文件和一个 .dll文件,启动exe, .dll 加载成功会提示我们完成三个游戏。
扔 ida 里头,sub_140001490 里是猜数字游戏
想动调,奈何太菜。干脆开玩(
第二个游戏是贪吃蛇,感觉没坑,索性开玩(
最后一个要输密钥,sub_180001650 函数里头个 AES 加密,可以跟进找到一个生成密钥的函数,带花需要去花指令(恶心心)。
解密脚本:
点击查看代码
#include <stdio.h>
#include <stdlib.h>
int main(){
srand(114514);
for (int i = 0; i < 16; i++)
{
int v10 = rand();
printf("%02x",((unsigned char)(v10 + (v10 / 255))) ^ 0x17);
}
return 0;
}
// 09e5fdeb683175b6b13b840891eb78d2
[网络与数据安全挑战赛 2025]easyReee
2026.1.5
扔 ida 里后先找到主函数

可以看到负责 check 的函数是 sub_11C9
数组的值可在 ida 里直接提取。
python 脚本如下:

竟然只是简单的异或加密。
点击查看代码
# 提取的密文数据
data = [
0x1A, 0x1A, 0xC8, 0x16, 0xC6, 0x14, 0x3A, 0x3D, 0xC5, 0x13,
0xC2, 0x40, 0xBD, 0xBA, 0xBC, 0x74, 0xBB, 0x76, 0xBF, 0x4B,
0x4B, 0x4B, 0x7B, 0xB4, 0x4D, 0x62, 0x61, 0xAD, 0x60, 0x56,
0x63, 0xAF, 0x78, 0x54, 0x56, 0x74
]
flag_inner = ""
for i in range(len(data)):
target = data[i]
# 模拟 (i - 75),并只取低8位,因为最终比较是转为 unsigned __int8
# python的负数异或与C不同,所以这里手动截断为8位整数模拟C的行为
key = (i - 75) & 0xFF
# 反向异或
xor_result = target ^ key
# 反向加法 (减去75),并处理可能的下溢出(& 0xFF)
original_char = (xor_result - 75) & 0xFF
flag_inner += chr(original_char)
print("Decoded string:", flag_inner)
print("Final Flag: DASCTF{" + flag_inner + "}")
[GFCTF 2021]wordy
2026.1.5
花指令好题。
拿 ida 打开之后见到的第一个函数长这样

点进 main 函数里

看到 jmp 指令(警觉)
jmp 到 loc_1144+1
找到 001146 这一行。
按下 C (code:把字节编程汇编指令)
然后就能得到一长串数据。
一直翻到最后会发现还有一些数据很怪,

按 U (undefine :变回原始字节)
之后就能正常查看了。
无意间翻到一个大括号

合理猜测这一整串都是 flag ,但中间穿插了些花指令,出现了一大堆无用的数据。
接下来对着一串一个一个按 C 还原成汇编,逐渐发现规律

ida 识别出的这些带引号的字符连起来就是 flag (一个一个还原太麻烦了,可以用脚本)
[NSSRound#3 Team]jump_by_jump_revenge
2026.1.7
考察花指令
进 main 函数看到这个

在 View-A 里查看 main

没找到花指令。但是有个 jmp main_0
跟着找到 jmp main_0

也没有花指令
跟着继续跳转。

一路跳转到 loc_4118DA
这里 jmp near ptr 0C086A4CCh 通过跳转到一个无效地址使 ida 没法正常反编译
按 D 给它转换成数据(硬指令。?)


浙公网安备 33010602011771号