[CTF] 2022 CNSS Recruit Reverse 复现wp
😇 [Baby] Welcome to Reverse World
IDA打开即是flag.

cnss{1t_s3ems_l1ke_Y0u_c4n_us3_IDA_n0w!}
💔 [Baby] Find me
根据提示打开Strings窗口, 已经可以看到第一段和最后一段flag

根据提示Learn about Functions and you can see the second part of flag., 在旁边的functions窗口找到第二段flag

根据提示Learn about Xref and you can see the third part of flag.和Find out which function refer to me!找到第三段flag(右键Xref)

把每一段拼接起来即可
cnss{W0w!Y0u_Comp1et3ly_Uns7and_h0w_t0_us3_ID4_N0w!}
💫 [Easy] 回レ! 雪月花
打开ida, 在main里F5, 查看加密逻辑:

第一次处理是异或0x11, 点进encode查看第二次处理:

这里稍微理解一下, 比如v5, 它的二进制位有8位, 后7位即为a2的前面七位, 第一位即为a1的最后一位, v7异或v6的值正好相反, 与v5的信息组合即可还原出a1和a2. 同样的, 将v6异或v5还原的值, 二进制位后6位为a4的前6位, 前两位为a3的最后两位, 与v8异或v7的值组合, 即可还原出a3和a4.
下面为还原脚本:
def decode(v5, v6, v7, v8):
a1 = (((v7 ^ v6) & 0b01111111) << 1) + (v5 >> 7)
a2 = ((v5 & 0b01111111) << 1) + ((v7 ^ v6) >> 7)
a3 = (((v8 ^ v7) & 0b00111111) << 2) + ((v6 ^ v5) >> 6)
a4 = (((v6 ^ v5) & 0b00111111) << 2) + ((v8 ^ v7) >> 6)
return a1, a2, a3, a4
cipher = [63, 143, 163, 188, 141, 39, 122, 103, 226, 3,
162, 224, 172, 234, 149, 139, 163, 237, 204, 182,
50, 140, 148, 82, 130, 138, 20, 198, 245, 174,
104, 115]
for i in range(28, -1, -1):
cipher[i], cipher[i+1], cipher[i+2], cipher[i+3] = decode(cipher[i], cipher[i+1], cipher[i+2], cipher[i+3])
print(''.join(chr(c ^ 0x11) for c in cipher))
cnss{So_d1zzy...Wh3r3_am_i_N0w?}
👁 [Easy] 邪王真眼
IDA打开可以看到加密:

拿到加密后的字符串UR3oWS5E0G03tRibWRrR0cEx
查看encode函数:

根据加密特征, 猜测是base64, 查看alpha数组(字符表), 可以发现不是标准的base64表:

EXP即进行一个换表解密:
import base64
originString = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' # 原索引表
changedString = 'abcd4EFGHij8k0lMNOPqr6stU91VWXyz7+/ABCDefg2hI5JKLmnopQRST3uvwxYZ' # 替换后的索引表
encodedString = 'UR3oWS5E0G03tRibWRrR0cEx' # 加密后的字符串
print(base64.b64decode(encodedString.translate(str.maketrans(changedString, originString))))
cnss{E4sy_bAse64!}
🔪 [Easy] 恭喜你获得了flag提现机会!
IDA打开发现需要通过某些方式调用outputflag函数

可以直接nop掉if, 让程序直接执行outputflag

nop后效果:


写入到文件, 直接打开即可

cnss{3njoy_H4cK1ng!}
💻 [Easy+] diannaobaozhale
反写汇编, 没啥说的, 直接对着写就好了

a = [0x63, 0x6E, 0x73, 0x73, 0x7B]
print(''.join(chr(c) for c in a), end='')
v5 = 0x63
v4 = 0
while v4 <= 9:
print(chr(v5), end='')
v5 = (v5 + 2) ^ 1
v4 += 1
print(chr(0x7d), end='')
cnss{cdghklopst}
🤡 [Middle] Vip of Mihoyo
IDA打开发现是虚拟机, 导出操作码后可以发现对每一个字符的处理都是一样的:

7, a, 2, 8, 3, 14, 1, 10, 5, 128, 6, b可以翻译为(flag[a] * 8 - 14 + 10)^128 == b
那么flag[a]就等于((b^128)-10+14)//8, 直接解码即可
以下为解码脚本
# 注释掉的这部分是对ida导出的byte数组进行小端转换为整数, 获得实际的opcode
# opcode = [0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
# 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
# 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00,
# 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
# 0x06, 0x00, 0x00, 0x00, 0x94, 0x03, 0x00, 0x00, 0x07, 0x00,
# 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
# 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00,
# 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,
# 0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00,
# 0x00, 0x00, 0xEC, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
# 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00,
# 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,
# 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00,
# 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
# 0x14, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00,
# 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
# 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00,
# 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
# 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x03,
# 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
# 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00,
# 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
# 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x80, 0x00,
# 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x54, 0x03, 0x00, 0x00,
# 0x07, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00,
# 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
# 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00,
# 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
# 0x06, 0x00, 0x00, 0x00, 0xAC, 0x02, 0x00, 0x00, 0x07, 0x00,
# 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
# 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00,
# 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,
# 0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00,
# 0x00, 0x00, 0x3C, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
# 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00,
# 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,
# 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00,
# 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
# 0xCC, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00,
# 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
# 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00,
# 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
# 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xD4, 0x03,
# 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
# 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00,
# 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
# 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x80, 0x00,
# 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x74, 0x02, 0x00, 0x00,
# 0x07, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x02, 0x00,
# 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
# 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00,
# 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
# 0x06, 0x00, 0x00, 0x00, 0x2C, 0x02, 0x00, 0x00, 0x07, 0x00,
# 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
# 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00,
# 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,
# 0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00,
# 0x00, 0x00, 0xE4, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
# 0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00,
# 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,
# 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00,
# 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
# 0x74, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0D, 0x00,
# 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
# 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00,
# 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
# 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x24, 0x01,
# 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,
# 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00,
# 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
# 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x80, 0x00,
# 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1C, 0x03, 0x00, 0x00,
# 0x07, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x02, 0x00,
# 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
# 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00,
# 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
# 0x06, 0x00, 0x00, 0x00, 0x0C, 0x03, 0x00, 0x00, 0x07, 0x00,
# 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
# 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00,
# 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,
# 0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00,
# 0x00, 0x00, 0x24, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
# 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00,
# 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,
# 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00,
# 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
# 0x94, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x12, 0x00,
# 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
# 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00,
# 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
# 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1C, 0x03,
# 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
# 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00,
# 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
# 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x80, 0x00,
# 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0C, 0x02, 0x00, 0x00,
# 0x07, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00,
# 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
# 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00,
# 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
# 0x06, 0x00, 0x00, 0x00, 0x24, 0x03, 0x00, 0x00, 0x07, 0x00,
# 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
# 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00,
# 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,
# 0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00,
# 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
# 0x16, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00,
# 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,
# 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00,
# 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
# 0x84, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x17, 0x00,
# 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
# 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00,
# 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
# 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x64, 0x03,
# 0x00, 0x00]
# opcode = [opcode[i + 3] << 24 | opcode[i + 2] << 16 | opcode[i + 1] << 8 | opcode[i] for i in range(0, len(opcode), 4)]
# print(opcode)
# 转换后的opcode
opcode = [7, 0, 2, 8, 3, 14, 1, 10, 5, 128, 6, 916,
7, 1, 2, 8, 3, 14, 1, 10, 5, 128, 6, 1004,
7, 2, 2, 8, 3, 14, 1, 10, 5, 128, 6, 788,
7, 3, 2, 8, 3, 14, 1, 10, 5, 128, 6, 788,
7, 4, 2, 8, 3, 14, 1, 10, 5, 128, 6, 852,
7, 5, 2, 8, 3, 14, 1, 10, 5, 128, 6, 684,
7, 6, 2, 8, 3, 14, 1, 10, 5, 128, 6, 828,
7, 7, 2, 8, 3, 14, 1, 10, 5, 128, 6, 460,
7, 8, 2, 8, 3, 14, 1, 10, 5, 128, 6, 980,
7, 9, 2, 8, 3, 14, 1, 10, 5, 128, 6, 628,
7, 10, 2, 8, 3, 14, 1, 10, 5, 128, 6, 556,
7, 11, 2, 8, 3, 14, 1, 10, 5, 128, 6, 996,
7, 12, 2, 8, 3, 14, 1, 10, 5, 128, 6, 628,
7, 13, 2, 8, 3, 14, 1, 10, 5, 128, 6, 292,
7, 14, 2, 8, 3, 14, 1, 10, 5, 128, 6, 796,
7, 15, 2, 8, 3, 14, 1, 10, 5, 128, 6, 780,
7, 16, 2, 8, 3, 14, 1, 10, 5, 128, 6, 548,
7, 17, 2, 8, 3, 14, 1, 10, 5, 128, 6, 916,
7, 18, 2, 8, 3, 14, 1, 10, 5, 128, 6, 796,
7, 19, 2, 8, 3, 14, 1, 10, 5, 128, 6, 524,
7, 20, 2, 8, 3, 14, 1, 10, 5, 128, 6, 804,
7, 21, 2, 8, 3, 14, 1, 10, 5, 128, 6, 276,
7, 22, 2, 8, 3, 14, 1, 10, 5, 128, 6, 388,
7, 23, 2, 8, 3, 14, 1, 10, 5, 128, 6, 868]
# 这里是把虚拟机转写成python版本了(好理解一点)
def vm():
flag = "asdasdasdasdasdasd"
i = 0
v5 = 0
operator = {
1: lambda a,b: a+b,
2: lambda a,b: a*b,
3: lambda a,b: a-b,
4: lambda a,b: a//b,
5: lambda a,b: a^b,
}
while i <= 287:
v3 = opcode[i+1]
if opcode[i] in operator:
v5 = operator[opcode[i]](v5,v3)
elif opcode[i] == 6:
if v5 != v3:
return False
elif opcode[i] == 7:
v5 = ord(flag[v3])
elif opcode[i] == 8:
flag[v3] = chr(v5)
v5 &= 0xff
i+=2
return True
def decode():
flag = ''.join(chr(((opcode[i + 11] ^ 128) - 10 + 14) // 8) for i in range(0, len(opcode), 12))
print(flag)
return flag
decode()
cnss{Fx*k_Vm_5trUctRu3!}
⭐ [Middle] Super Mario Code
打开IDA, 发现main是乱码, 根据题目可以知道是SMC.

动调找到解码后的SMC(可能需要到断点的时候按u将main取消定义了再按p重新生成函数)


可以看见就是个异或加密, 脚本解密就行
from Crypto.Util.number import *
a = 0x200E103830302D20
b = 0x3A3072261C30721C
c = b"b s-$1\"76/\"7r,-0b>"
a = long_to_bytes(a)[::-1]
b = long_to_bytes(b)[::-1]
cipher = a + b + c
flag = "".join([chr(i^0x43) for i in cipher])
print(flag)
cnss{SMc_1s_e1sy!c0ngratulat1ons!}
🌸 [Middle] 花花
打开IDA无法反汇编, 结合题目发现是花指令
类似这样的都是花指令,一般nop掉再重新按p生成函数即可


可以得到两部分加密函数
main函数:

第一部分:

第二部分:

脚本解密即可
cipher = list('Jew{PwcnwJJsCMMM1qyPZE5iHshiOF')
l = len(cipher)
for i in range(len(cipher)-1,-1,-1):
tmp = cipher[i]
cipher[i] = cipher[(i+9)%l]
cipher[(i+9)%l] = tmp
for i in range(len(cipher)-1,-1,-1):
tmp = cipher[i]
cipher[i] = cipher[(i+3)%l]
cipher[(i+3)%l] = tmp
a = [0, 0, 4, 6, 16, 20, 36, 42, 64, 72, 100, 110, 144, 156, 196, 210, 256, 272, 324, 342, 400, 420, 484, 506, 576, 600, 676, 702, 784, 812, 900, 930, 1024, 1056, 1156, 1190, 1296, 1332, 1444, 1482, 1600, 1640, 1764, 1806, 1936, 1980, 2116, 2162, 2304, 2352, 2500, 2550, 2704, 2756, 2916, 2970, 3136, 3192, 3364,
3422, 3600, 3660, 3844, 3906, 4096, 4160, 4356, 4422, 4624, 4692, 4900, 4970, 5184, 5256, 5476, 5550, 5776, 5852, 6084, 6162, 6400, 6480, 6724, 6806, 7056, 7140, 7396, 7482, 7744, 7832, 8100, 8190, 8464, 8556, 8836, 8930, 9216, 9312, 9604, 9702]
alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789}{'
l = len(alphabet)
for i,c in enumerate(cipher):
indexC = alphabet.index(c)
indexF = ((indexC - a[i]) + 10*l)%l
cipher[i] = alphabet[indexF]
print(''.join(cipher))
cnss{Fl0w3rC0de1sRe41llyC0oOl}
❤ [Middle] Shino 的心跳大冒险
一直走流程到最后发现flag被挡住了

这里用Cheat Engine的骚操作直接扫描cnss这个字符串即可(想到CE是因为它是常用游戏作弊器)



cnss{W0w!Y0u_4re_K1ng_0f_R3vers1g_n0W!!!}
这道题还有很多其他做法,比如修改资源删掉这张图片(应该是官解)、修改资源文件修改字体大小让flag漏出来(SSG爷的做法)等等,可以自己试试,方法很多
🦠 [Easy?] Baby XOR?
打开IDA发现加密逻辑,尝试之后发现不对。看汇编可以发现try...catch

按u将整个main函数(包括catch部分)全部undefinded掉,然后在catch处按p将catch部分生成为函数。


进入_Encrypt函数,根据S、ST、K可以大致猜测到为RC4加密

根据提示利用Meet In the Middle攻击,明文部分即为png的文件头,我们取四个字节当明文,再从密文中选四个字节作为对应的密文
等式对应如下
下面为爆破程序,实测使用Cython和pypy均可将运行时间控制在十多分钟,使用原版python大概需要四十分钟以上
import binascii
import itertools
def rc4_crypt(PlainBytes:bytes, KeyBytes:bytes) -> bytes:
cipherList = []
keyLen = len(KeyBytes)
plainLen = len(PlainBytes)
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + KeyBytes[i % keyLen]) % 256
S[i], S[j] = S[j], S[i]
i = 0
j = 0
for m in range(plainLen):
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
k = S[(S[i] + S[j]) % 256]
cipherList.append(k ^ PlainBytes[m])
return bytes(cipherList)
def main():
keys = [bytes([i, j, k, l]) for i, j, k, l in itertools.product(range(81), repeat=4)]
with open("./setu_encoded.png","rb") as f:
cipherText = b"".join((i-17) for i in f.read()[:4])
plainText = b"\x89\x50\x4E\x47"
dic = {}
for key in keys:
encoded = rc4_crypt(plainText, key)
dic[encoded] = key
# print(f'\r{binascii.b2a_hex(key)} : {binascii.b2a_hex(encoded)}', end='', flush=True)
for key in keys:
# print(f'\r{binascii.b2a_hex(key)}', end='', flush=True)
if rc4_crypt(cipherText, key) in dic:
print(f"\nFound: {binascii.b2a_hex(key)} , {binascii.b2a_hex(dic[rc4_crypt(cipherText, key)])}")
main()
可以跑出来两个key分别为35, 31, 34, 69和25, 6, 19, 6解密setu即可
flag怎么把关键部位挡住了啊喂
cnss{Re4a1_Fu1_St4ck_CtfER_1s_cl3r}
🧠 [Hard] Brainfuck++
反反调试
IDA打开调试时发现有反调试,在exe的逆向里并没有发现反调试相关的代码,于是进入dll中寻找,利用Strings定位到反调试所在之处


反调试逻辑还是较为简单的,将这一大部分nop掉即可

nop的效果为

动态调试
开始动态调试,这里将Application改成Brainfuck++.exe

我选择在此处打断点(因为上面那部分字符串异或的结果是brainfuck++.exe)

成功捕获断点

这里查看v3的值,就可以找到被dll更改过的brainfuck++码。

这里可以发现会对数据预处理,从最后一位开始异或后一位,(最后一位的后一位被赋值成了4,动调可以看出来,这里不再赘述),解密时也要做反向的操作。
按住F8单步步过,一直到程序等待输入的时候

尝试搜索flag字符串,可以找到stack里有flag相关的字符串

这里给这个内存空间打上断点

输入数据继续调试, 进入到了一部分无法反汇编的代码,可以先在这里打个断点,然后取消刚刚在内存空间打的断点。

这里我们直接将这一部分代码按u取消定义,到上面去按p创建函数。


可以发现这里就是虚拟机的函数。在调用dll里的函数的这一步打上断点

继续运行,成功捕获

按下F7步进,可以进入加密的函数

这里照样遇到了不能反编译,按之前的方法先取消再创建即可。


这里的v2数组可以猜测就是加密后的字符串了,直接导出即可
v2 = [203, 189, 254, 233, 107, 96, 96, 40, 30, 206, 230, 99, 176, 194, 46, 15, 111, 237, 3, 85, 235, 139, 61, 138, 60, 229, 116, 153, 130, 37, 245, 63]
点击进入sub_401550, 可以看出明显的TEA加密

在里面打上断点,运行进入。
可以发现v4就是delta,值为0x9E3779B9

a2是key,值为[0x69207A6C, 0x7475706E, 0x65687420, 0x616C6620]

解密
写脚本解密即可
from ctypes import *
from Crypto.Util.number import *
delta = 0x9E3779B9
def decrypt(v, k):
v0, v1 = c_uint32(v[0]), c_uint32(v[1])
k0, k1, k2, k3 = k[0], k[1], k[2], k[3]
total = c_uint32(delta * 32)
for i in range(32):
v1.value -= ((v0.value<<4) + k2) ^ (v0.value + total.value) ^ ((v0.value>>5) + k3)
v0.value -= ((v1.value<<4) + k0) ^ (v1.value + total.value) ^ ((v1.value>>5) + k1)
total.value -= delta
return v0.value, v1.value
def toLittleEndian(x):
return x[0] + (x[1] << 8) + (x[2] << 16) + (x[3] << 24)
if __name__ == "__main__":
cipher = [203, 189, 254, 233, 107, 96, 96, 40, 30, 206, 230, 99, 176, 194, 46, 15, 111, 237, 3, 85, 235, 139, 61, 138, 60, 229, 116, 153, 130, 37, 245, 63]
key = [0x69207A6C, 0x7475706E, 0x65687420, 0x616C6620]
bytes = b''
for i in range(0, len(cipher), 8):
v = [toLittleEndian(cipher[i:i+4]), toLittleEndian(cipher[i+4:i+8])]
res = decrypt(v, key)
bytes += long_to_bytes(res[0])[::-1] + long_to_bytes(res[1])[::-1]
flag = list(bytes)
flag.append(4)
for i in range(len(flag)-1):
flag[i] ^= flag[i+1]
flag = ''.join([chr(i) for i in flag])
print(flag)
cnss{k1nG_0f_tHE_BRa1nFuCk++!!!}
😴 [BOSS] Crazy Hacker
⚓ [Real World] 互联网海盗
抓包找到sign生成

进index搜索sign:(带冒号是因为只匹配json中的

给四个sign:都打上断点

点击翻译按钮进入断点, 跟随断点来到这个位置, 就找到了sign的生成函数.

复制到python中, 给这里取个函数名:


利用execjs执行一遍试试:
import execjs
js = r"""
function e(t, e) {
(null == e || e > t.length) && (e = t.length);
for (var n = 0, r = new Array(e); n < e; n++)
r[n] = t[n];
return r
}
function n(t, e) {
for (var n = 0; n < e.length - 2; n += 3) {
var r = e.charAt(n + 2);
r = "a" <= r ? r.charCodeAt(0) - 87 : Number(r),
r = "+" === e.charAt(n + 1) ? t >>> r : t << r,
t = "+" === e.charAt(n) ? t + r & 4294967295 : t ^ r
}
return t
}
var r = null;
function signGen(t) {
var o, i = t.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);
if (null === i) {
var a = t.length;
a > 30 && (t = "".concat(t.substr(0, 10)).concat(t.substr(Math.floor(a / 2) - 5, 10)).concat(t.substr(-10, 10)))
} else {
for (var s = t.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), c = 0, u = s.length, l = []; c < u; c++)
"" !== s[c] && l.push.apply(l, function(t) {
if (Array.isArray(t))
return e(t)
}(o = s[c].split("")) || function(t) {
if ("undefined" != typeof Symbol && null != t[Symbol.iterator] || null != t["@@iterator"])
return Array.from(t)
}(o) || function(t, n) {
if (t) {
if ("string" == typeof t)
return e(t, n);
var r = Object.prototype.toString.call(t).slice(8, -1);
return "Object" === r && t.constructor && (r = t.constructor.name),
"Map" === r || "Set" === r ? Array.from(t) : "Arguments" === r || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r) ? e(t, n) : void 0
}
}(o) || function() {
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")
}()),
c !== u - 1 && l.push(i[c]);
var p = l.length;
p > 30 && (t = l.slice(0, 10).join("") + l.slice(Math.floor(p / 2) - 5, Math.floor(p / 2) + 5).join("") + l.slice(-10).join(""))
}
for (var d = "".concat(String.fromCharCode(103)).concat(String.fromCharCode(116)).concat(String.fromCharCode(107)), h = (null !== r ? r : (r = window[d] || "") || "").split("."), f = Number(h[0]) || 0, m = Number(h[1]) || 0, g = [], y = 0, v = 0; v < t.length; v++) {
var _ = t.charCodeAt(v);
_ < 128 ? g[y++] = _ : (_ < 2048 ? g[y++] = _ >> 6 | 192 : (55296 == (64512 & _) && v + 1 < t.length && 56320 == (64512 & t.charCodeAt(v + 1)) ? (_ = 65536 + ((1023 & _) << 10) + (1023 & t.charCodeAt(++v)),
g[y++] = _ >> 18 | 240,
g[y++] = _ >> 12 & 63 | 128) : g[y++] = _ >> 12 | 224,
g[y++] = _ >> 6 & 63 | 128),
g[y++] = 63 & _ | 128)
}
for (var b = f, w = "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(97)) + "".concat(String.fromCharCode(94)).concat(String.fromCharCode(43)).concat(String.fromCharCode(54)), k = "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(51)) + "".concat(String.fromCharCode(94)).concat(String.fromCharCode(43)).concat(String.fromCharCode(98)) + "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(102)), x = 0; x < g.length; x++)
b = n(b += g[x], w);
return b = n(b, k),
(b ^= m) < 0 && (b = 2147483648 + (2147483647 & b)),
"".concat((b %= 1e6).toString(), ".").concat(b ^ f)
}
"""
def signGen(text):
return execjs.compile(js).call('signGen', text)
print(signGen("CNSS"))
发现报错execjs._exceptions.ProgramError: ReferenceError: window is not defined,这里我们可以直接搜索window发现是对r进行定义, 在断点中查看r的值, 可以发现r是一个定值


r = "320305.131321201"
所以我们把js中r的定义语句删掉, 换成let r = "320305.131321201";


即可正常运行

稍微修改代码逻辑, 打包一下, 最终程序:
import execjs
js = r"""
function e(t, e) {
(null == e || e > t.length) && (e = t.length);
for (var n = 0, r = new Array(e); n < e; n++)
r[n] = t[n];
return r
}
function n(t, e) {
for (var n = 0; n < e.length - 2; n += 3) {
var r = e.charAt(n + 2);
r = "a" <= r ? r.charCodeAt(0) - 87 : Number(r),
r = "+" === e.charAt(n + 1) ? t >>> r : t << r,
t = "+" === e.charAt(n) ? t + r & 4294967295 : t ^ r
}
return t
}
let r = "320305.131321201";
function signGen(t) {
var o, i = t.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);
if (null === i) {
var a = t.length;
a > 30 && (t = "".concat(t.substr(0, 10)).concat(t.substr(Math.floor(a / 2) - 5, 10)).concat(t.substr(-10, 10)))
} else {
for (var s = t.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), c = 0, u = s.length, l = []; c < u; c++)
"" !== s[c] && l.push.apply(l, function(t) {
if (Array.isArray(t))
return e(t)
}(o = s[c].split("")) || function(t) {
if ("undefined" != typeof Symbol && null != t[Symbol.iterator] || null != t["@@iterator"])
return Array.from(t)
}(o) || function(t, n) {
if (t) {
if ("string" == typeof t)
return e(t, n);
var r = Object.prototype.toString.call(t).slice(8, -1);
return "Object" === r && t.constructor && (r = t.constructor.name),
"Map" === r || "Set" === r ? Array.from(t) : "Arguments" === r || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r) ? e(t, n) : void 0
}
}(o) || function() {
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")
}()),
c !== u - 1 && l.push(i[c]);
var p = l.length;
p > 30 && (t = l.slice(0, 10).join("") + l.slice(Math.floor(p / 2) - 5, Math.floor(p / 2) + 5).join("") + l.slice(-10).join(""))
}
for (var d = "".concat(String.fromCharCode(103)).concat(String.fromCharCode(116)).concat(String.fromCharCode(107)), h = (null !== r ? r : (r = window[d] || "") || "").split("."), f = Number(h[0]) || 0, m = Number(h[1]) || 0, g = [], y = 0, v = 0; v < t.length; v++) {
var _ = t.charCodeAt(v);
_ < 128 ? g[y++] = _ : (_ < 2048 ? g[y++] = _ >> 6 | 192 : (55296 == (64512 & _) && v + 1 < t.length && 56320 == (64512 & t.charCodeAt(v + 1)) ? (_ = 65536 + ((1023 & _) << 10) + (1023 & t.charCodeAt(++v)),
g[y++] = _ >> 18 | 240,
g[y++] = _ >> 12 & 63 | 128) : g[y++] = _ >> 12 | 224,
g[y++] = _ >> 6 & 63 | 128),
g[y++] = 63 & _ | 128)
}
for (var b = f, w = "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(97)) + "".concat(String.fromCharCode(94)).concat(String.fromCharCode(43)).concat(String.fromCharCode(54)), k = "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(51)) + "".concat(String.fromCharCode(94)).concat(String.fromCharCode(43)).concat(String.fromCharCode(98)) + "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(102)), x = 0; x < g.length; x++)
b = n(b += g[x], w);
return b = n(b, k),
(b ^= m) < 0 && (b = 2147483648 + (2147483647 & b)),
"".concat((b %= 1e6).toString(), ".").concat(b ^ f)
}
"""
def signGen(text):
return execjs.compile(js).call('signGen', text)
while True:
text = str(input('输入文本: '))
print(signGen(text))
pyinstaller打包
pyinstaller.exe sign.py -F
最终效果:


浙公网安备 33010602011771号