# NSSCTF Round#18 Basic Writeup
# 前言
写的有点乱,有问题还请各位佬指出 Orz
# Re
# GenshinWishSimulator
unity 游戏,把 Assembly-CSharp.dll
丢到 dnspy 分析
发现一个 Check
方法
z3 梭一下
from z3 import * | |
bucket = [Int('bucket_%d' % i) for i in range(16)] | |
solver = Solver() | |
solver.add(bucket[0] * 40 + bucket[1] * 65 + bucket[2] * -53 + bucket[3] * 70 + bucket[4] * -84 + bucket[5] * -38 + bucket[6] * 94 + bucket[7] * -39 + | |
bucket[8] * -91 + bucket[9] * -35 + bucket[10] * 54 + bucket[11] * 17 + bucket[12] * 45 + bucket[13] * 92 + bucket[14] * -29 + bucket[15] * 61 == 3004) | |
solver.add(bucket[0] * -15 + bucket[1] * 74 + bucket[2] * -89 + bucket[3] * -82 + bucket[4] * -92 + bucket[5] * 27 + bucket[6] * 21 + bucket[7] * -24 + | |
bucket[8] * -82 + bucket[9] * -58 + bucket[10] * -36 + bucket[11] * 64 + bucket[12] * -49 + bucket[13] * -22 + bucket[14] * 59 + bucket[15] * -47 == -674) | |
solver.add(bucket[0] * 67 + bucket[1] * -23 + bucket[2] * 63 + bucket[3] * -38 + bucket[4] * -32 + bucket[5] * 61 + bucket[6] * -71 + bucket[7] * 49 + | |
bucket[8] * 83 + bucket[9] * -92 + bucket[10] * -16 + bucket[11] * 65 + bucket[12] * -22 + bucket[13] * 12 + bucket[14] * -85 + bucket[15] * 74 == 945) | |
solver.add(bucket[0] * -49 + bucket[1] * 48 + bucket[2] * -11 + bucket[3] * 20 + bucket[4] * -14 + bucket[5] * 92 + bucket[6] * -19 + bucket[7] * 32 + | |
bucket[8] * 64 + bucket[9] * -77 + bucket[10] * 49 + bucket[11] * -19 + bucket[12] * 72 + bucket[13] * -64 + bucket[14] * 85 + bucket[15] * 54 == 1721) | |
solver.add(bucket[0] * 36 + bucket[1] * -21 + bucket[2] * -59 + bucket[3] * -54 + bucket[4] * -96 + bucket[5] * -81 + bucket[6] * -33 + bucket[7] * 31 + | |
bucket[8] * -41 + bucket[9] * -70 + bucket[10] * -27 + bucket[11] * 24 + bucket[12] * 95 + bucket[13] * -61 + bucket[14] * -17 + bucket[15] * -52 == -2198) | |
solver.add(bucket[0] * 78 + bucket[1] * -62 + bucket[2] * 70 + bucket[3] * -69 + bucket[4] * 38 + bucket[5] * 90 + bucket[6] * -52 + bucket[7] * 41 + | |
bucket[8] * 63 + bucket[9] * -65 + bucket[10] * -15 + bucket[11] * 59 + bucket[12] * -31 + bucket[13] * 54 + bucket[14] * 33 + bucket[15] * -57 == -1833) | |
solver.add(bucket[0] * 56 + bucket[1] * 75 + bucket[2] * 71 + bucket[3] * 78 + bucket[4] * -39 + bucket[5] * -84 + bucket[6] * 55 + bucket[7] * 54 + | |
bucket[8] * -12 + bucket[9] * -57 + bucket[10] * 32 + bucket[11] * -19 + bucket[12] * 13 + bucket[13] * -83 + bucket[14] * 11 + bucket[15] * -67 == 829) | |
solver.add(bucket[0] * 10 + bucket[1] * -97 + bucket[2] * 56 + bucket[3] * -61 + bucket[4] * 45 + bucket[5] * -22 + bucket[6] * 33 + bucket[7] * 81 + | |
bucket[8] * 32 + bucket[9] * 49 + bucket[10] * -19 + bucket[11] * -18 + bucket[12] * 80 + bucket[13] * -98 + bucket[14] * 79 + bucket[15] * -36 == -2551) | |
solver.add(bucket[0] * 24 + bucket[1] * -61 + bucket[2] * 91 + bucket[3] * 93 + bucket[4] * 76 + bucket[5] * 54 + bucket[6] * -33 + bucket[7] * -29 + | |
bucket[8] * -72 + bucket[9] * 20 + bucket[10] * 48 + bucket[11] * 79 + bucket[12] * 76 + bucket[13] * 68 + bucket[14] * 51 + bucket[15] * 25 == 2996) | |
solver.add(bucket[0] * -83 + bucket[1] * -77 + bucket[2] * -64 + bucket[3] * -38 + bucket[4] * -13 + bucket[5] * -85 + bucket[6] * 33 + bucket[7] * -76 + | |
bucket[8] * 27 + bucket[9] * 14 + bucket[10] * -79 + bucket[11] * -63 + bucket[12] * -78 + bucket[13] * 53 + bucket[14] * -73 + bucket[15] * 61 == -2315) | |
solver.add(bucket[0] * 84 + bucket[1] * -67 + bucket[2] * 57 + bucket[3] * 26 + bucket[4] * 94 + bucket[5] * 20 + bucket[6] * -71 + bucket[7] * -88 + | |
bucket[8] * -28 + bucket[9] * -13 + bucket[10] * -40 + bucket[11] * 76 + bucket[12] * -14 + bucket[13] * 33 + bucket[14] * 76 + bucket[15] * -75 == -150) | |
solver.add(bucket[0] * -60 + bucket[1] * 88 + bucket[2] * -66 + bucket[3] * -72 + bucket[4] * 41 + bucket[5] * 49 + bucket[6] * 48 + bucket[7] * -77 + | |
bucket[8] * -42 + bucket[9] * 25 + bucket[10] * -50 + bucket[11] * -84 + bucket[12] * 40 + bucket[13] * 50 + bucket[14] * -83 + bucket[15] * -27 == -1919) | |
solver.add(bucket[0] * -16 + bucket[1] * -53 + bucket[2] * -21 + bucket[3] * -44 + bucket[4] * 26 + bucket[5] * -56 + bucket[6] * -90 + bucket[7] * -93 + | |
bucket[8] * -73 + bucket[9] * 48 + bucket[10] * 15 + bucket[11] * -43 + bucket[12] * -61 + bucket[13] * -24 + bucket[14] * 71 + bucket[15] * 67 == -1199) | |
solver.add(bucket[0] * 55 + bucket[1] * -34 + bucket[2] * -22 + bucket[3] * 60 + bucket[4] * 93 + bucket[5] * -95 + bucket[6] * 50 + bucket[7] * 36 + | |
bucket[8] * -48 + bucket[9] * -26 + bucket[10] * -94 + bucket[11] * -35 + bucket[12] * 21 + bucket[13] * -27 + bucket[14] * 91 + bucket[15] * -76 == -1163) | |
solver.add(bucket[0] * 64 + bucket[1] * -50 + bucket[2] * -23 + bucket[3] * -70 + bucket[4] * -78 + bucket[5] * 34 + bucket[6] * 26 + bucket[7] * 64 + | |
bucket[8] * -72 + bucket[9] * 10 + bucket[10] * -96 + bucket[11] * 61 + bucket[12] * -15 + bucket[13] * 31 + bucket[14] * 36 + bucket[15] * 50 == -266) | |
solver.add(bucket[0] * -27 + bucket[1] * 86 + bucket[2] * -61 + bucket[3] * 89 + bucket[4] * -53 + bucket[5] * 10 + bucket[6] * -42 + bucket[7] * 92 + bucket[8] * -48 + bucket[9] * 13 + bucket[10] * 84 + bucket[11] * -71 + bucket[12] * 93 + bucket[13] * 54 + bucket[14] * -69 + bucket[15] * -30 == 892 | |
) | |
if solver.check() == sat: | |
model = solver.model() | |
for i in range(16): | |
print(f"bucket[{i}] = {model[bucket[i]]};") | |
else: | |
print("No solution found") | |
# bucket[0] = 1; | |
# bucket[1] = 14; | |
# bucket[2] = 1; | |
# bucket[3] = 17; | |
# bucket[4] = 2; | |
# bucket[5] = 1; | |
# bucket[6] = 1; | |
# bucket[7] = 0; | |
# bucket[8] = 2; | |
# bucket[9] = 4; | |
# bucket[10] = 1; | |
# bucket[11] = 17; | |
# bucket[12] = 2; | |
# bucket[13] = 0; | |
# bucket[14] = 2; | |
# bucket[15] = 16; |
得到的数据写死在 GachaHistoryBucket::GetBucket
里面
启动一下原神,抽奖,直接出金
NSSCTF{2vRZt8PXkBH9R2jmrQKL8nUXgLAC6MAaW9rN9gkvThPC75GAL4xgxhhbwA}
# 炒鸡常见的编码哇
就是 base64,中间多了一个打乱二进制位的步骤,手撕一下,后面我直接开爆了
shit code (能跑就行)
table = [ | |
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, | |
0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, | |
0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xE0, 0xE1, 0xE2, 0xE3, | |
0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, | |
0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, | |
0xF8, 0xF9, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, | |
0xB7, 0xB8, 0xAA, 0xAE | |
] | |
enc = bytearray.fromhex("E2F7D3E2C8B4D8C5CFB4E7EEE1D9F1EFCBEBD9C9CEC5D9E5CCB7D1EDE0B4F1EEE0E7D2F6CBF3C9F3D3D5EF") | |
idx = [] | |
for i in enc: | |
idx.append(table.index(i)) | |
s = [] | |
for i in idx: | |
s.append(bin(i)[2:].zfill(6)) | |
res = "" | |
for i in s: | |
for j in range(0, 0b111111): | |
c = list(bin(j)[2:].zfill(6)) | |
l = 0 | |
r = 0 | |
for k in range(0, 256, 2): | |
l = (k + 1) % 256 | |
r = (l + r + 1) % 256 | |
c[l % 6], c[r % 6] = c[r % 6], c[l % 6] | |
d = "".join(c) | |
if d == i: | |
res += bin(j)[2:].zfill(6) | |
break | |
b = [res[i:i+8] for i in range(0, len(res), 8)] | |
for i in b: | |
print(chr(int(i, 2)), end="") |
NSSCTF{Y0u_4reThe_K1ng_0fBase64}
# EzADVM
小白第一次做出来 vm 题哎嘿
这题逻辑挺简单的 (命名有点随意 hh)
先解析一下指令
code = [ | |
0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0x53, | |
0x57, 0x44, 0x61, 0x44, 0x64, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, | |
0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, | |
0xE5, 0xD4, 0xA1, 0x53, 0x57, 0x44, 0x61, 0x44, 0x64, 0xF1, | |
0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, | |
0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, | |
0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0x53, | |
0x57, 0x44, 0x61, 0x44, 0x64, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, | |
0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, | |
0xE5, 0xD4, 0xA1, 0x53, 0x57, 0x44, 0x61, 0x44, 0x64, 0xF1, | |
0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, | |
0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0x66, 0x6C, 0x61, | |
0x67, 0x7B, 0x59, 0x75, 0x69, 0x73, 0x61, 0x62, 0x65, 0x61, | |
0x75, 0x74, 0x69, 0x66, 0x75, 0x6C, 0x67, 0x69, 0x72, 0x6C, | |
0x7D, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, | |
0xE5, 0xD4, 0xA1, 0x66, 0x6C, 0x61, 0x67, 0x7B, 0x59, 0x75, | |
0x69, 0x73, 0x61, 0x62, 0x65, 0x61, 0x75, 0x74, 0x69, 0x66, | |
0x75, 0x6C, 0x67, 0x69, 0x72, 0x6C, 0x7D, 0xF1, 0xC3, 0xB2, | |
0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0x66, | |
0x6C, 0x61, 0x67, 0x7B, 0x59, 0x75, 0x69, 0x73, 0x61, 0x62, | |
0x65, 0x61, 0x75, 0x74, 0x69, 0x66, 0x75, 0x6C, 0x67, 0x69, | |
0x72, 0x6C, 0x7D, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0xF1, | |
0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0x53, 0x57, 0x44, 0x61, 0x44, | |
0x64, 0x66, 0x6C, 0x61, 0x67, 0x7B, 0x59, 0x75, 0x69, 0x73, | |
0x61, 0x62, 0x65, 0x61, 0x75, 0x74, 0x69, 0x66, 0x75, 0x6C, | |
0x67, 0x69, 0x72, 0x6C, 0x7D, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, | |
0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, | |
0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0x53, | |
0x57, 0x44, 0x61, 0x44, 0x64, 0x66, 0x6C, 0x61, 0x67, 0x7B, | |
0x59, 0x75, 0x69, 0x73, 0x61, 0x62, 0x65, 0x61, 0x75, 0x74, | |
0x69, 0x66, 0x75, 0x6C, 0x67, 0x69, 0x72, 0x6C, 0x7D, 0xF1, | |
0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0x66, 0x6C, 0x61, 0x67, 0x7B, | |
0x59, 0x75, 0x69, 0x73, 0x61, 0x62, 0x65, 0x61, 0x75, 0x74, | |
0x69, 0x66, 0x75, 0x6C, 0x67, 0x69, 0x72, 0x6C, 0x7D, 0xF1, | |
0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, | |
0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, | |
0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0x53, | |
0x57, 0x44, 0x61, 0x44, 0x64, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, | |
0xA1, 0x99, 0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, | |
0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, | |
0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, | |
0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, | |
0xBF, 0xBB, 0x66, 0x6C, 0x61, 0x67, 0x7B, 0x59, 0x75, 0x69, | |
0x73, 0x61, 0x62, 0x65, 0x61, 0x75, 0x74, 0x69, 0x66, 0x75, | |
0x6C, 0x67, 0x69, 0x72, 0x6C, 0x7D, 0xBF, 0xBB, 0xBF, 0xBB, | |
0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, | |
0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, 0x53, 0x57, 0x44, 0x44, | |
0xBF, 0xBB, 0xBF, 0xBB, 0x99, 0x53, 0x57, 0x44, 0x44, 0x53, | |
0x57, 0x44, 0x44, 0x88, 0xFF, 0x53, 0x57, 0x44, 0x44] | |
for i in code: | |
match i: | |
case 0xA1: | |
print("flag[i - 1] = reg_4 & reg_6") | |
case 0xC3: | |
print("reg_6 = reg_0 | reg_1") | |
case 0xB2: | |
print("reg_2 = ~reg_0") | |
case 0xE5: | |
print("reg_3 = ~reg_1") | |
case 0xF1: | |
print("reg_0 = input[i]") | |
print("reg_1 = input[++i]") | |
case 0xD4: | |
print("reg_4 = reg_3 | reg_2") | |
case 0xBF: | |
print("reg_i = i++") | |
print("reg_5[0] = flag[reg_i]") | |
case 0x99: | |
print("i = 0") | |
case 0xBB: | |
print("flag[i - 1] = i + reg_5[0] - 1") |
解析下来慢慢分析,其实就这么点内容
for i in range(32): | |
flag[i] = (~input[i + 1] | ~input[i] ) & (input[i] | input[i + 1]) | |
for i in range(32): | |
flag[i] += i |
那么就直接解就好了,位运算那里直接根据 flag 头是 N
,然后开爆!
enc = bytearray.fromhex("1D01121A1642390F380913312838676E1B617C241F4744816A2C6D2B2C2D6A9C") | |
for i in range(len(enc)): | |
enc[i] = enc[i] - i | |
s = ord("N") | |
print("N", end="") | |
for i in enc: | |
for j in range(32, 128): | |
a = (~j | ~s ) & (s | j) | |
if a == i: | |
s = j | |
print(chr(j), end="") | |
break |
NSSCTF{H@ppy_Ch1ne5_NEwY3ar!1!1}
# 新年礼物
ida 打开分析半天无果,应该是把 dll 和 exe 打包在一起了
010Editor 搜索 PE 文件的一些特征,然后从 MZ
开始复制一直到文件结束
得到一个 dll,dnspy 打开来瞅瞅
嗯?不让我输入 NSSCTF2024
,还要求 sha256 前几位一样,斯,脑子好痒,想不出来
把代码全抠出来,把可恶的 if 给他删掉
运行,输入 NSSCTF2024
,getflag
NSSCTF{Hapiniuyier_ctfer_Hiddendragonintheabyss,soaringthroughthenineheavens}