3.17逆向分析练习

“真相在代码中沉睡,等待逆向者将其唤醒…”

老师说要写像研究生的报告…

题目链接:http://124.16.75.116:52014/challenges

ezzre

使用ExeinfoPE对目标进行检查,目标是一个64位exe文件,有upx壳。使用upx命令脱壳后用ida查看

main的主要逻辑:用户输入flag,对flag进行s78操作得到flag2,如果flag2的每一位都等于answer每一位加一,就输出Good

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
printf_0("plz input your flag:");
Stream = __iob_func();
fgets_0(flag, 100, Stream);
flag[strcspn_0(flag, "\n")] = 0;
input_length = strlen(flag);
flag2 = s78(flag, input_length);
MAX = 1;
qmemcpy(answer, "YlwgY2snLGceY17vYE82LGIKWykucU8DLVPgeP@@", 40);
*(_WORD *)&answer[40] = 255;
for ( i = 0; i < strlen(flag2); ++i )
{
if ( flag2[i] != answer[i] + 1 )
MAX = 0;
}
if ( MAX == 1 )
printf_0("Good");
else
printf_0("Wrong!");

(使用了ChatGPT)

s78是base64加密

1
2
3
encoded_data[j] = base64_table[(triple >> 18) & 0x3F];
encoded_data[j + 1] = base64_table[(triple >> 12) & 0x3F];
encoded_data[j + 2] = base64_table[(triple >> 6) & 0x3F];

所以总体关系是Base64(flag) = answer + 1,对answer +1进行base64解码得到flag

解密脚本:

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

answer = "YlwgY2snLGceY17vYE82LGIKWykucU8DLVPgeP@@"

# 每个字符 +1
flag2 = ''.join(chr(ord(c) + 1) for c in answer)

print("Base64:", flag2)

# Base64 解码
flag = base64.b64decode(flag2)

print("Flag:", flag.decode())

运行得到

1
2
Base64: ZmxhZ3toMHdfZ28wZF93MHJLXzlvdV9EMWQhfQAA
Flag: flag{h0w_go0d_w0rK_9ou_D1d!}

re2

(ChatGPT分析)

main:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if ( fgets(s, 256, stdin) )
{
n29_1 = strcspn(s, "\n");
n7 = 7;
n29 = 0;
s[n29_1] = 0;
if ( (_DWORD)n29_1 == 29 )
{
while ( v9[n29 + 11] == __ROL1__(v9[(unsigned int)n29 % 0xB] ^ n7 ^ s[n29], (unsigned int)n29 % 5) )
{
++n29;
n7 += 13;
if ( n29 == 29 )
{
puts("OK");
return 0;
}
}
}
puts("NO");
}

校验方程:

1
v9[n29 + 11] = rol( v9[n29 % 11] ^ n7 ^ s[n29], n29 % 5 )

v9 的构造

1
2
3
4
5
for (i = 0; i < 11; i++)
v9[i] = byte_2040[i] ^ 0x74;

for (j = 0; j < 29; j++)
v9[j+11] = byte_2020[j] ^ 0x74;
  • v9[0..10] → key
  • v9[11..39] → target(用于校验)

输入限制, flag 长度 = 29

1
if (strlen(s) == 29)

n7 变化

1
2
3
初始:n7 = 7;
每轮: n7 += 13;
第 i 轮:n7 = 7 + 13*i

逆向公式:

1
2
3
4
5
v9[i+11] = rol(v9[i%11] ^ n7 ^ s[i], i%5)
=>
ror(v9[i+11], i%5) = v9[i%11] ^ n7 ^ s[i]
=>
s[i] = ror(v9[i+11], i%5) ^ v9[i%11] ^ n7

注意rol和n7、s等都是8位的,在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
def rol(x, r):
return ((x << r) | (x >> (8 - r))) & 0xff

def ror(x, r):
return ((x >> r) | (x << (8 - r))) & 0xff


byte_2040 = [74, 75, 229, 51, 46, 35, 89, 221, 107, 150, 160]
byte_2020 = [43, 250, 51, 4, 213, 31, 86, 226, 60, 104,
95, 255, 123, 230, 156, 157,
173, 198, 76, 45, 239, 47, 161, 135, 248,
16, 150, 5, 109]

# 构造 v9
v9 = []

for i in range(11):
v9.append(byte_2040[i] ^ 0x74)

for j in range(29):
v9.append(byte_2020[j] ^ 0x74)

# 逆推出 s
res = []
n7 = 7

for i in range(29):
target = v9[i + 11]
r = i % 5

val = ror(target, r) ^ v9[i % 11] ^ n7
res.append(val & 0xff)

n7 = (n7 + 13) & 0xff

flag = ''.join(chr(x) for x in res)
print(flag)

运行得到flag

1
flag{tiny_vm_style_transform}

easyyre

(ChatGPT分析)

是一道RUST题,看着吓人,逻辑还挺简单的

main函数主要逻辑:

1
2
3
4
5
6
//处理输入
let input = stdin().read_line().trim_end().to_string();
//翻转
let rev = input.chars().rev().collect::<String>();
//转字节
let bytes = rev.as_bytes();

链式异或。key(n85)是每一轮更新的

1
2
3
4
5
6
7
8
let mut key = 85;
let mut out = String::new();

for b in bytes {
let x = b ^ key;
out.push(x as char);
key = x;
}

最后与目标字符串比较。找到目标字符串的值:

1
.rodata:000000000004D129 28 4F 29 4C 28 4B 29 48 33 54…    _O_L_K_H3T5Y? db '(O)L(K)H3T5Y?'   

脚本:

1
2
3
4
5
6
7
8
9
10
11
12
target = "(O)L(K)H3T5Y?"
t = [ord(c) for c in target]

res = []
key = 85
for x in t:
res.append(x ^ key)
key = x

print("bytes:", res)
print("hex:", [hex(x) for x in res])
print("repr:", repr(''.join(chr(x) for x in res[::-1])))

得到flag

1
flag{abcdefg}