难得遇到一个简单的比赛QAQ

go_bytes

打开后找到main函数,可以直接看到两个40长度的for循环,第二个直接比较了

两段分别是

1
2
3
4
5
6
7
8
9
10
11
12
13
for ( i = 0LL; i < 40; ++i )
{
if ( (unsigned __int64)ptr <= i )
runtime_panicIndex(i, ptr, ptr);
v8 = v6;
v9 = *(_BYTE *)(v6 + i);
v10 = i
- 40 * ((__int64)(((unsigned __int128)((i + 1) * (__int128)(__int64)0xCCCCCCCCCCCCCCCDLL) >> 64) + i + 1) >> 5);
if ( (unsigned __int64)ptr <= v10 + 1 )
runtime_panicIndex(v10 + 1, ptr, ptr);
*(_BYTE *)(v8 + i) = (*(_BYTE *)(v10 + v8 + 1) >> 4) | (16 * v9);
v6 = v8;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
for ( j = 0LL; j < 40; ++j )
{
if ( (unsigned __int64)ptr <= j )
runtime_panicIndex(j, ptr, ptr);
v12 = *(unsigned __int8 *)(v6 + j);
main_tmp = (unsigned __int16)(291 * main_tmp + 1110);
if ( v16[j] != (main_tmp ^ v12) )
{
v13 = j;
v21[0] = &RTYPE_string;
v21[1] = &off_4DCF10;
fmt_Fprintln(&go_itab__os_File_io_Writer, os_Stdout, v21, 1LL, 1LL);
os_Exit(0LL);
v6 = v18;
j = v13;
ptr = v14;
}
}

拿到v16然后求出v12,反向位运算即可得到flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from prism import *
xor_data = 0xDEAD
last = [0x22B9, 0xC9F8, 0x8C89, 0xFF18, 0x1439, 0x4E0A, 0x2A8B, 0x07CB, 0xBDEB, 0xFAAB, 0x3FFB, 0x784B, 0x9F1E, 0x4FEB, 0x4D0B, 0xD08E, 0x38BB, 0xCBAE, 0xD2CE, 0x913E, 0x0A6B, 0xF03B, 0x507B, 0x398B, 0x93DE, 0x3CCE, 0x459E, 0x4ABE, 0x553E, 0x316E, 0x33BE, 0x42FE, 0xCECE, 0x4DDE, 0x982B, 0xA31B, 0x802E, 0x12EE, 0xF67A, 0xEB79]
enc = []
for i in range(len(last)):
xor_data = (xor_data*291+1110)&0xffff
enc.append(last[i] ^ xor_data)

def aenc(enc):
for i in range(1,len(enc)-1):
enc[i] = enc[i+1]>>4|((enc[i]<<4)&0xf0)
pl(enc)
aenc(enc)
# DSCTF{faddff8cb4d711edbb2294085339ce84}

bouquet

已知二叉树中序和后序遍历结果,求层序

根据根据后序的输出逐个递归求解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right

def buildTree(inorder, postorder):
if not inorder or not postorder:
return None
root_val = postorder.pop()
root = TreeNode(root_val)
inorder_index = inorder.index(root_val)
root.right = buildTree(inorder[inorder_index+1:], postorder)
root.left = buildTree(inorder[:inorder_index], postorder)
return root

def levelOrder(root):
if not root:
return ""
result = []
queue = [root]
while queue:
level = []
next_queue = []
for node in queue:
level.append(node.val)
if node.left:
next_queue.append(node.left)
if node.right:
next_queue.append(node.right)
result.append(level)
queue = next_queue
return "".join([str(item) for sublist in result for item in sublist])

back = list("j7aw_sC3addq4TAo}8_Fda{SD")
mide = list("ja7Cws_A3daTd4qDo8}F_Sd{a")
root = buildTree(mide, back)

level_order_result = levelOrder(root)
print(level_order_result)

zistel

通过字符串输出找到主函数

image-20241220171522560

找到逻辑,逐个分析调试

基本加密逻辑是

image-20241220171837133

因此要找到每轮通过100261B生成的xorNum

逻辑是通过一个256位替换表进行的替换

image-20241220172004730

写出脚本直接逆即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
DWORD64 thisKey(DWORD key, DWORD num) {
BYTE S[256] = {};
for (int i = 0; i < 256; i++)
{
S[i] = i & 3;
}

DWORD xorData = key ^ num;
PBYTE pxd = (PBYTE)&xorData;
PBYTE pky = (PBYTE)&key;
for (int i = 0; i < 4; i++)
{
DWORD mid = pxd[i];
DWORD x = S[pky[i]];
pxd[i] = pxd[x];
pxd[x] = mid;
}
//std::cout << std::hex << xorData << std::endl;
return key ^ xorData;
}


void enc(DWORD* m, DWORD* key) {
auto& v0 = m[0];
auto& v1 = m[1];
for (int i = 0; i < 20; i++)
{
DWORD tmp = v1;
v1 = v0 ^ thisKey(key[i], v1);
v0 = tmp;
}
std::swap(v0, v1);
}

void dec(DWORD* c, DWORD* key) {
auto& v0 = c[0];
auto& v1 = c[1];
std::swap(v0, v1);
for (int i = 20 - 1; i >= 0; i--)
{
DWORD tmp = v0;
v0 = v1 ^ thisKey(key[i], v0);
v1 = tmp;
}
}


int main(int argc, char* argv[]) {
DWORD last[] = {
0x33293158, 0x60760211, 0x42185F46, 0x63746F29,0
};
DWORD key[] = { 0xBBDBD183, 0x05340F2E, 0xBEEFDEAD, 0xBBDBD183, 0x05340F2E, 0xBEEFDEAD, 0xBBDBD183, 0x05340F2E, 0xBEEFDEAD, 0xBBDBD183, 0x05340F2E, 0xBEEFDEAD, 0xBBDBD183, 0x05340F2E, 0xBEEFDEAD, 0xBBDBD183, 0x05340F2E, 0xBEEFDEAD, 0xBBDBD183, 0x05340F2E };
dec(last, key);
dec(&last[2], key);
std::cout << reinterpret_cast<char*>(last) << std::endl;
return 0;
}
//z1g_I3_S0_Coo0l!