ez_asm

众所周知 ChatGPT 可以看懂汇编,接下来有请二号选手下场解题。根据提供的汇编代码,我们可以还原出大致的 C 语言代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>

char flag[39]; // 定义一个char数组用于存储flag

int main() {
int var_4 = 0; // 定义一个变量var_4,并初始化为0

while (var_4 <= 0x27) { // 循环条件是var_4小于等于0x27
char byte = flag[var_4]; // 取flag数组中的一个字节
byte ^= 0x1E; // 对该字节进行异或运算
flag[var_4] = byte; // 将结果存回flag数组

byte = flag[var_4]; // 取flag数组中的一个字节
byte -= 0x0A; // 对该字节进行减法运算
flag[var_4] = byte; // 将结果存回flag数组

var_4++; // var_4自增1
}

printf("%s\n", flag); // 打印flag字符串
return 0;
}

上述 C 代码大致还原了汇编代码的逻辑。现在,我们可以编写 Python 代码来进行逆运算,给定输入或一个字符串,将其反向操作以获得原始 Flag。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def reverse_flag(flag):
flag = bytearray(flag) # 将字符串转换为字节数组

for i in range(len(flag)):
# 对每个字节执行逆运算
flag[i] += 0x0A
flag[i] ^= 0x1E

return bytes(flag).decode('utf-8') # 将字节数组转换回字符串并返回

# 用于测试的示例输入字符串
input_string = "nhuo[M`7mc7uhc$7midgbTf`7`$7%#ubf7 ci5Y"
original_flag = reverse_flag(input_string.encode('utf-8'))
print(original_flag)

这段 Python 代码执行了与汇编代码中相反的操作,对给定的输入字符串进行逆运算以获得原始 Flag。运行后得到 Flag:flag{It_is_als0_impor@nt_t0_13arn_4sm!}

easy_re

它都说是 easy 了你就相信它一回吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int __cdecl main(int argc, const char **argv, const char **envp)
{
char Str[52]; // [rsp+20h] [rbp-40h] BYREF
int v5; // [rsp+54h] [rbp-Ch]
int j; // [rsp+58h] [rbp-8h]
int i; // [rsp+5Ch] [rbp-4h]

_main();
printf("Input your flag:");
scanf("%s", Str);
v5 = strlen(Str);
for ( i = 0; i < v5; ++i )
Str[i] = (Str[i] >> 4) | (16 * Str[i]);
for ( j = 0; j < v5; ++j )
{
if ( Str[j] != des[j] )
{
printf("Wrong!");
exit(0);
}
}
printf("Right!");
return 0;
}

不难看出其中唯一一个处理步骤是把每个字符的高 4 位和低 4 位交换了,所以直接给它交换回来就是了:

1
2
3
4
5
6
des = '66 C6 16 76 B7 45 27 97 F5 47 03 F5 37 03 C6 67 33 F5 47 86 56 F5 26 96 E6 16 27 97 F5 07 27 03 26 C6 33 D6 D7'.split()
flag = b''

for i in des:
flag += bytes.fromhex(i[1]+i[0])
print(flag.decode())

所以 Flag:flag{Try_t0_s0lv3_the_binary_pr0bl3m}

seed

直接开动态调试把内存扒出来,剩下的自己算:

1
2
3
4
5
6
7
cipher = [bytes.fromhex(char)[0] for char in "40 29 28 e9 c2 04 a4 ed 9f 53 5f 75 3c d1 cd 2b a8 c4 89 69 15 21 16 ef d7 27 92 df ca 53 5f 2a 3c d1 ce 03 a3 ef a5 78 16 1a 2d e1 c4".split()]
key = [bytes.fromhex(char)[0] for char in "26 45 49 8e b9 43 cd 9b fa 0c".split()]

plain = ""
for i in range(len(cipher)):
plain += chr(cipher[i] ^ key[i % 10])
print(plain)

所以 Flag:flag{Give_y0u_the_se3d_and_D0_you_w@nt_t0_do}

easy_math

先解方程:

1
2
3
4
5
6
7
8
9
10
11
12
13
from sympy import symbols, Eq, solve

l = symbols('l0 l1 l2 l3 l4 l5')
equations = [
Eq(593*l[0]+997*l[1]+811*l[2]+258*l[3]+829*l[4]+532*l[5], 0x5b8e0aef71d34ff43),
Eq(605*l[0]+686*l[1]+328*l[2]+602*l[3]+695*l[4]+576*l[5], 0x551a262360964ef7f),
Eq(373*l[0]+512*l[1]+449*l[2]+756*l[3]+448*l[4]+580*l[5], 0x49d158a5657d6931c),
Eq(560*l[0]+635*l[1]+422*l[2]+971*l[3]+855*l[4]+597*l[5], 0x625568d5abbabf4f3),
Eq(717*l[0]+507*l[1]+388*l[2]+925*l[3]+324*l[4]+524*l[5], 0x50ee0c025e70e3c23),
Eq(312*l[0]+368*l[1]+884*l[2]+518*l[3]+495*l[4]+414*l[5], 0x40e735f8aa2815f65)]

solutions = solve(equations, l)
print(solutions)

然后拼一下 Flag:

1
2
3
4
5
6
7
8
from Crypto.Util.number import long_to_bytes

l = [28829613228248624, 26827458353261422, 13642136288051316,
29378135513658469, 32192963475959391, 30791965425607037]

for i in l:
j = long_to_bytes(i).decode('ascii')
print(j, end="")

所以 Flag:flag{N0_One_kn0ws_m@th_B3tter_Th@n_me!!!!}

ez_apk

Android 逆向什么的不会啊怎么办?直接拆 APK 包拿到 classes3.dec 丢进 IDA,代码不多直接看

Screenshot-202310272022.webp

encrypt 这边应该是实现了一个自定义字母表的 Base58,然后还找到了一个 secret,直接去尝试解码:

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
def base58_decode(encoded_str):
# 创建一个字典,将字符映射到对应的值
char_to_value = {c: i for i, c in enumerate(base58_chars)}

# 初始化结果字节数
result = 0
for char in encoded_str:
result *= 58
result += char_to_value[char]

# 将结果的整数值转换为字节数组
result_bytes = bytearray()
while result > 0:
result_bytes.append(result & 0xFF)
result >>= 8

# 翻转字节数组以得到正确的顺序
result_bytes.reverse()

return bytes(result_bytes)

base58_chars = "9LfnoVpi1HrzBSKxhNFeyY745R2g3QmqsTCZJuDvcMdkE8wPGbUXajtAW6"
encoded_str = "5TAYhycAPT1aAd535TGdWYQ8CvfoRjErGEreqhDpqv1LydTqd3mxuK2hhUp9Pws3u9mq6eX"
decoded_bytes = base58_decode(encoded_str)

print(decoded_bytes)

运行后得到 Flag:flag{Jue_1_ju3_Y0ung_and_G0at_1s_go0d_for_yOuR_body}

not gcc

题目给了一个 bc 文件,这是 LLVM IR bitcode 文件,属于编译过程中产生的一个文件,直接让 clang 继续编译就能得到可执行文件。

反编译后看了眼,是个 Sudoku:

1
2
3
4
5
6
7
8
9
sudoku = [4, 0, 7, 0, 0, 3, 2, 0, 8,
5, 0, 0, 0, 2, 0, 9, 0, 0,
0, 1, 2, 9, 8, 0, 0, 0, 4,
7, 0, 9, 1, 0, 4, 8, 0, 0,
0, 6, 1, 0, 0, 0, 4, 7, 0,
0, 0, 3, 2, 7, 0, 0, 0, 6,
0, 8, 6, 3, 0, 0, 0, 4, 0,
0, 2, 0, 7, 4, 0, 6, 3, 0,
3, 0, 4, 0, 0, 2, 0, 0, 0]

先想点办法把这个数独给解决了:

1
2
3
4
5
6
7
8
9
solved = [4, 9, 7, 5, 1, 3, 2, 6, 8,
5, 3, 8, 4, 2, 6, 9, 1, 7,
6, 1, 2, 9, 8, 7, 3, 5, 4,
7, 5, 9, 1, 6, 4, 8, 2, 3,
2, 6, 1, 8, 3, 9, 4, 7, 5,
8, 4, 3, 2, 7, 5, 1, 9, 6,
9, 8, 6, 3, 5, 1, 7, 4, 2,
1, 2, 5, 7, 4, 8, 6, 3, 9,
3, 7, 4, 6, 9, 2, 5, 8, 1]

然后按程序的逻辑合成下 Flag:

1
2
3
4
for i in range(81):
assert sudoku[i] == 0 or sudoku[i] == solved[i]
print(solved[i] if sudoku[i] == 0 else 0, end="")
print()

pycode

这么长一串 Disassembly 我可不看,直接丢给 ChatGPT 让它尝试去还原一下 Python 代码:

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
import base64

flag = '*******************'
value = ''
output = ''

for i in range(1000):
w = 1024
x = w % 3
y = w // 9
z = x * y
w -= z

for i in range(10000):
w = 20
x = w % 6
y = w // 3
z = x * y
w += z

for i in range(1000):
w = 1024
x = w % 3
y = w // 9
z = x * y
w -= z

for i in range(10000):
w = 20
x = w % 6
y = w // 3
z = x * y
w += z

for i in range(len(flag)):
temp = chr(ord(flag[i]) ^ 8)
value += temp

for i in range(len(value)):
temp = chr(ord(value[i]) + 3)
output += temp

obfuscated_output = base64.b64encode(output.encode()).decode()
obfuscated_output = obfuscated_output[::-1]
obfuscated_output = obfuscated_output.replace('0', 't')
obfuscated_output = obfuscated_output.replace('c', '4')
obfuscated_output = obfuscated_output.replace('+', '-')

print(obfuscated_output)

肉眼可见有一大串没什么用的代码,直接顺手写一个逆运算:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import base64

output = "==AeAF3M-tzO-giQ-AUQosDQ9tGK7MDPuhC47tDNB5Tb8Yn4sdW4"

output = output.replace('t', '0')
output = output.replace('4', 'c')
output = output.replace('-', '+')
output = output[::-1]
output = base64.b64decode(output).decode()

flag = ''
for i in range(len(output)):
temp = chr(ord(output[i]) - 3)
flag += chr(ord(temp) ^ 8)
print(flag)

运行后得到 Flag:flag{1b36920e-c180-b250-6537-30238f5}

Authur's_box

先反编译为伪代码:

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
int result; // eax
char Str1[256]; // [rsp+20h] [rbp-60h] BYREF
char Str[264]; // [rsp+120h] [rbp+A0h] BYREF
unsigned int v6; // [rsp+228h] [rbp+1A8h]
int i; // [rsp+22Ch] [rbp+1ACh]

sub_401A10(argc, argv, envp);
memset(Str1, 0, sizeof(Str1));
memset(Str, 0, 0x100ui64);
sub_4017A5();
puts("Input the flag:");
gets(Str);
v6 = strlen(Str);
if ( v6 == 42 )
{
if ( Str[0] == 102 && Str[1] == 108 && Str[2] == 97 && Str[3] == 103 && Str[4] == 123 && Str[41] == 125 )
{
sub_40182D(Str, v6);
for ( i = 0; i < (int)v6; ++i )
Str1[i] = byte_408A80[i] ^ Str[i];
if ( !strcmp(Str1, &Str2) )
puts("right!");
else
puts("wrong!");
}
result = 0;
}
else
{
puts("Wrong length!");
result = 0;
}
return result;
}

不难看出 byte_408A80Str2 异或的结果便是 Flag。Str2 可以直接在 IDA 里拿到,然后通过动态调试拿 byte_408A80 的值:

Screenshot-202310271935.webp

然后编写脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
string1 = [0xDD, 0x26, 0xE4, 0x0B, 0xB4, 0xE2, 0x20, 0x0B, 0x10, 0x5D,
0xFE, 0x52, 0x5C, 0xF2, 0x08, 0xD1, 0x59, 0x41, 0xFE, 0xCC,
0x82, 0x33, 0xE1, 0x6F, 0xE9, 0x75, 0xDB, 0xEF, 0x21, 0x52,
0x0C, 0xE6, 0x7B, 0x91, 0x07, 0x39, 0x09, 0x72, 0xEA, 0xFC,
0x18, 0xDE]
string2 = [0xBB, 0x4A, 0x85, 0x6C, 0xCF, 0x84, 0x43, 0x3A, 0x26, 0x6D,
0x9F, 0x62, 0x6B, 0xDF, 0x6E, 0xE7, 0x3A, 0x76, 0xD3, 0xF8,
0xE0, 0x00, 0x80, 0x42, 0xD1, 0x42, 0xBD, 0x8B, 0x0C, 0x30,
0x3D, 0xD4, 0x48, 0xA0, 0x3F, 0x58, 0x3A, 0x16, 0xDA, 0x9E,
0x7A, 0xA3]

for i in range(42):
print(chr(string1[i] ^ string2[i]), end="")
print('')

得到 Flag:flag{fc160a07-f6c7-4b3a-87fd-b12318a3d0bb}

easyre

1
2
3
4
5
6
% ./easyre.exe
Plz input key (0<key<100):Traceback (most recent call last):
File "main.py", line 7, in <module>
x = sp.symbols('x')
KeyboardInterrupt
[17832] Failed to execute script 'main' due to unhandled exception!

由此可见这是个 Python 脚本打包得到的程序,使用工具解包得到 pyc 文件,然后再反编译得到 Python 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import base64
import marshal
import sympy as sp

encoded_data = b'#`VVVVVVVVVVVVVVVVVVVVVSVVVVFVVVV_YZVVVVMVU|VNFV@pU|V{xUMVYvVzBSMVDSVFRVMFDSV\\VQMV@%7fVAxPMFU{V@BPp`]vU%B_MF]eVy]VMFY|UxZUVFUbTPBSMVrSVFRVMV%7fCVT|]N`^VVVVVVVVVVVVVVVpVVVVPVVVVF`VVV_GFVVVVsVU\'V@FUp`PSVO\'TMV].V$FUMVPSVBFVOC".U_`SqV]/UU|VQ`U/V_`RsV]/V^ZUQpVMVUtVMVR@V_\'SqV]/Vo|VqV]/UU|VVpU/Vy`RGVU/Vy`SGVUoPPFTUVU.U_\'SsVXSV_\'QqVQRVQ&pqFM/UPFSQ`U|VENVqFE/V$`TqVFMVUtVMVR@V_\'SqV]/Vo|VqV]/UU|VVpU/Vy`RGVU/Vy`SGVU/Vy`TqVFMV_`TqVZMVUtVMVR@VU|VqFs/UvVRqVM/U\'RVxFRUV_QfqVACVT|RCb|VVFVV!FVVVVSgVFVVVT|Q%pEdvOY\'%pAnN@"yMsxSuPAb%p{~rOE{NO]nNOyvUzQ`tPAbMT|^%pYeMO{vTOUdN@{bsPA#sYxUB.xUvcxUvAx\\N%{`vPAnsPA#sYxRN%%7f%7ftcxUv!|Vtp/VVVS!UzM&u~"`rsx[tzZ\'O%AbN$]"t_FUVVVVto`VVVVVVF`UUV^ZVDVU_V^^VFNTTVRZVEVUPpRNVEVTt%7fRVVVUmT`VVVPA#N@&`uPAqv%A"tnxVVVSN{U!ez%M\'!&&VP ez!UZmA.\'X"g^\'/NUcvXd.TPRTTD!&UB\\`dT.R}Q{!QQUdr~UguyU&sTU"u$An^PMdN@t!rpA&sPNcXQxSr@Am@p]bu\'#gT_^EVVVVtp|VVVUvU@YxM@Ye%pA`tz{bsYxQv@"`sOCvUzAbN%.|MsxRMzo%7fM&x]M@"}ty{`sPA|tp/VVVUnS`VVV_^GVVVVt%7fVVVVSvTSocu%E&uPB<VFVVV_ZFVVVVTUFRVFFTTVRZVpxTTVR\\Vp**'
xor_key = int(input('Plz input key (0<key<100):'))
x = sp.symbols('x')
f = x ** 2 + x + 1
integral_value = sp.integrate(f, (x, 1, xor_key))
check_value = 13024
if integral_value * 3 == check_value:
xor_decoded_data = bytes(
(lambda x: [byte ^ xor_key for byte in x])(encoded_data))
decoded_data = base64.b64decode(xor_decoded_data)
code_obj = marshal.loads(decoded_data)
exec(code_obj)
else:
print('Wrong!!')

不难编写出下面的程序计算出 xor_key 值为 23:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import sympy as sp

xor_key = 0
while True:
try:
x = sp.symbols('x')
f = x ** 2 + x + 1
integral_value = sp.integrate(f, (x, 1, xor_key))
check_value = 13024
assert integral_value * 3 == check_value
except:
xor_key += 1
continue
break

print(xor_key)

那么解一下 Marshal:

1
2
3
4
5
6
7
8
9
10
11
12
import base64
import marshal
from dis import dis

encoded_data = b'...'
xor_key = 23

xor_decoded_data = bytes([byte ^ xor_key for byte in encoded_data])
decoded_data = base64.b64decode(xor_decoded_data)
code_obj = marshal.loads(decoded_data)

dis(code_obj)

阅读 Disassembly 后大致可以得知其内部使用一个 rc4_encrypt 函数,将输入的内容用一个 key 加密后与 check 变量比对。RC4 的解密函数即为加密函数,直接把 check 用相同的 key 丢进 rc4_encrypt 跑一遍就能得到 Flag 了。本来想打算直接:

1
2
3
4
5
6
7
8
9
10
code_obj = marshal.loads(decoded_data)

def input():
pass
try:
exec(code_obj)
except:
pass

print(rc4_encrypt(key, check))

但是一直 Segmentation Fault,最后选择另抄 rc4_encrypt 函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def rc4(key, data):
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]
i = j = 0
result = []
for char in data:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
result.append(char ^ S[(S[i] + S[j]) % 256])
return bytes(result)

print(rc4(key, check))

得到 Flag:flag{d8e8d9d0-b2b1-7304-74b760-90b11ab6a3}

crackme

1
2
% file crackme
crackme: Lua bytecode, version 5.3

直接先 Lua 反编译:

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
print("please input your flag:")
flag = io.read()
code = {}
secret = {54, 57, 566, 532, 1014, 1, 7, 508, 10, 12, 498, 494, 6, 24, 14, 20, 489, 492, 0, 10, 490, 498, 517, 539, 21, 528, 517, 530, 543, 9, 13, 0, 4, 51, 562, 518, 526, 512, 525, 522, 60, 573, 61, 575, 574, 0, 518, 513, 41, 31, 1, 594, 117, 15}
l = string.len(flag)

for i = 1, l do
num = ((string.byte(flag, i) + i) % 333 + 444) % 555 - 1
table.insert(code, num)
end

for i = 1, l do
x = i - 1
if i + 2 >= l then
code[i] = code[i % l + 1] ~ code[(i + 1) % l + 1]
else
code[i] = code[(i + 1) % l] ~ code[(i + 2) % l]
end
end

for i = 1, l do
if secret[i] ~= code[i] then
print("Incorrect")
return
end
end

print("You win,flag is", flag)

剩下的直接交给 Python 怎么暴力怎么来:

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
secret = [None, 54, 57, 566, 532, 1014, 1, 7, 508, 10, 12, 498, 494, 6, 24, 14, 20, 489, 492, 0, 10, 490, 498, 517, 539, 21, 528, 517, 530, 543, 9, 13, 0, 4, 51, 562, 518, 526, 512, 525, 522, 60, 573, 61, 575, 574, 0, 518, 513, 41, 31, 1, 594, 117, 15]

def valid(flag: str) -> bool:
code = [None]
l = len(flag)
for i in range(1, l + 1):
code.append(((((ord(flag[i - 1]) + i) % 333) + 444) % 555) - 1)
for i in range(1, l + 1):
if (i + 2) >= l:
code[i] = code[i % l + 1] ^ code[(i + 1) % l + 1]
else:
code[i] = code[(i + 1) % l] ^ code[(i + 2) % l]
return code[:l-1] == secret[:l-1]

def brute_force(flag: str) -> str:
arr = []
for i in range(32, 127):
if valid(flag + chr(i)):
arr.append(flag + chr(i))
return arr

que = ['flag']
while que:
flag = que.pop()
arr = brute_force(flag)
for flag in arr:
if flag in que:
continue
if len(flag) == len(secret)-1:
print(flag)
exit()
que.append(flag)

运行后得到 Flag:flag{C000ngr4tulat1ons!Y0u_Cr4cked_m3_9c2be68a76f9!!!}