😇 [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
最终效果: