-
-
[原创] 看雪 2022 KCTF 春季赛 第五题 危机四伏
-
发表于: 2022-5-20 04:58 9455
-
(看到出题战队顿感不妙,必是一道硬题)
(p.s. 本贴算不上writeup,只是一篇零散的记录)
惯例 IDA,main 函数 F5 报错 "function frame is wrong"
不过我们还有 Ghidra,虽然反编译效果远不如 IDA,但是对于某些畸形文件有奇效(例如,IDA 要求一个函数的范围是连续的,Ghidra 就没有这个限制)。
Ghidra 看 main 函数的逻辑(可以配合 IDA,重新标记变量类型和函数签名),很普通的 fgets 获取 name 和 key 的输入,然后 name paddnig到 16 字节,key hexdecode 后是 32 字节。(p.s. 这里的 hexdecode 不限制大小写,所以题目多解)
接下来初始化了一串常量,调用疑似 zlib 算法解码。
能看到 main 函数还调用了 VirtualAlloc
,大概猜测前面的逻辑是解码 shellcode。
中间抛出了 C++ 异常。找到了几篇个人感觉不错的文章,对程序执行流程和相关的数据结构都有比较系统的介绍:
可以在 IDA 里沿着 _main_SEH
结构体一路找到所有的 catch 块与对应的 throw,不过 Ghidra 直接把所有的 catch 块都识别为了函数,且这些块都在 main 函数后面。顺着往下看,在 0x401efa
处发现了 retf
指令(这大概就是 IDA F5 失败的原因)。
(以上其实全都没用,还不如一开始就直接动态调试)
x32dbg调试,hexdecode 后的 32 字节的 key 保存在 0x8934b9
处。在 0x401efa
处下断点,按 shift+F9
无视异常执行,发现 retf 的目标地址就是之前 VirtualAlloc
出来的内存开头,先 dump 出来。
retf 指令之前有 push 0x33
,所以 retf
指令修改了 cs
寄存器把架构从 32位切换到了 64位。
按 64 位架构反编译,IDA 的效果不好(需要不停的手动 make code),Ghidra 相当舒服(能自动按照 jmp 指令生成基本块)。
shellcode 由大量基本块构成,每个块只有若干条指令,然后 jmp 到其他块,以此类推。Ghidra 识别为了函数,但是基本块太多,反编译时报了 "Decompiler process died" 错误。
(看着汇编指令,梦回去年春季赛第七题,完全一样的混淆,瞬间绝望)
这种切换架构的程序目前只有 WinDbg (x64)
能够正常调试(虽然体验比 x64dbg 差很多)。对 0x8934b9
下数据断点,确实能在 shellcode 里的访存指令断下来。
而且当 shellcode 结束后,0x8934b9
开始的长 32字节的值会变成 base64 码表的字符。
单步调试跟了一段时间后放弃,找出自己去年的 writeup,先按老方法 unicorn 跑一遍 trace,得到了 400多万 行汇编(麻了);然后再筛一遍 taint,筛完竟然还剩 47万 多行汇编。
看了下筛选结果,大部分都是死代码(所以,不做死代码消除根本达不到化简的效果,而且脚本存在大量bug,跑出来的结果应该也严重失实)
走投无路之时,不知道为啥试了下把题目给的公开输入的key输入到去年题目的exp中,没想到输出的竟然就是题目给的公开输入的name!今年的题目算法与去年的(至少主要部分)完全一样!
去年的算法,从key得到name的过程大概有4个阶段:
动态调试可发现第一处 retf (0x401efa
) 只做了第一阶段的变换,从 0x8934b9
获取到的变换后的值与去年的算法相同。
同理,第二处 retf (0x402158
) 完成了第二和第三阶段的变换,可以发现后16字节的结果写入了 0x8995f1
处,前8字节的结果写入了0x8935d9
处
继续分析 main 函数,发现程序在 0x4021a1
处验证了 0x8935d9
处的8个字节都是0,在 0x40229d
处验证了 0x8995f1
与输入的 name padding之后的值相等。两个验证都通过则输出"Succeed!"。
观察发现 0x8995f1
的16字节结果与去年的算法相同,而0x8935d9
处的8个字节结果与去年的算法不同。8字节的变换是一个循环异或再异或常量,合理猜测算法没变,只是常量变了。因为第二阶段的算法没有变化,所以稍微推导一下即可得到新的“常量”。(实际上不是常量,而是随着后16字节变化的,但是当name固定为KCTF时可以按常量处理)
exp:(仅适用于name输入为KCTF的情况;与去年的算法相比只有doencode3/dodecode3的常量不同)
题目答案:
================================================================================
破解VMP类型的混淆,感觉最优的做法应该就是充分利用编译器的优化能力去除冗余指令。
之前在公众号看到了的一篇推文 [原创]angr符号变量转LLVM IR,作者 R1mao 实现了把 angr 的符号变量转换为 LLVM IR 的Python程序。文中还提到了一个项目 VMProtect-devirtualization ,给出了完整的基于符号执行和LLVM重编译的示例。
(R1mao 到目前为止在论坛发了3篇文章,都是非常硬核的干货好文,值得学习)
除了符号执行,还可以考虑 retdec
(retdec反编译器的特点是支持重新编译)(参考此帖评论区)
(注:以上方案都未在本题尝试,希望有兴趣的人可以折腾下看看效果)
def
p16(n):
n &
=
0xffff
return
n.to_bytes(
2
,
'little'
)
def
u16(s):
assert
(
len
(s)
=
=
2
)
return
int
.from_bytes(s,
'little'
)
def
p64(n):
n &
=
0xffffffffffffffff
return
n.to_bytes(
8
,
'little'
)
def
u64(s):
assert
(
len
(s)
=
=
8
)
return
int
.from_bytes(s,
'little'
)
def
rol16(n, k):
n &
=
0xffff
return
((n << k) | (n >> (
16
-
k))) &
0xffff
def
ror16(n, k):
n &
=
0xffff
return
((n >> k) | (n << (
16
-
k))) &
0xffff
def
doencrypt1(buf, indextable):
assert
(
len
(buf)
=
=
16
)
buf1
=
bytearray(buf)
v1
=
u16(buf1[
0
:
2
])
# s1 ^ k4
v2
=
u16(buf1[
2
:
4
])
# s2 ^ k4
v3
=
u16(buf1[
4
:
6
])
# s3 + k3
v4
=
u16(buf1[
6
:
8
])
# s4 - k3
v5
=
u16(buf1[
8
:
0xa
])
# s5 + k2
v6
=
u16(buf1[
0xa
:
0xc
])
# s6 + k2
v7
=
u16(buf1[
0xc
:
0xe
])
# s7 ^ k1
v8
=
u16(buf1[
0xe
:
0x10
])
# s8 ^ k1
t1
=
v2 ^ v1
# s2 ^ s1
t2
=
(v4
+
v3) &
0xffff
# s4 + s3
t3
=
(v5
-
v6) &
0xffff
# s5 - s6
cl
=
bin
(v8 ^ v7).lstrip(
"0b"
).count(
'1'
)
# s8 ^ s7# hamming distance
v7
=
ror16(v7, cl)
v8
=
ror16(v8, cl)
k1
=
( (t2 & t1) | ((~t1) & t3) ) &
0xffff
k2
=
( ((k1
*
t1) >> cl)
+
0x18
) &
0xffff
k3
=
( k2 ^ t3 ) &
0xffff
# 0x79c6
k4
=
( (k2 & k1) | (k3 & (k2 | k1)) ) &
0xffff
s1
=
p16(v1 ^ k4)
s2
=
p16(v2 ^ k4)
s3
=
p16(v3
-
k3)
s4
=
p16(v4
+
k3)
s5
=
p16(v5
-
k2)
s6
=
p16(v6
-
k2)
s7
=
p16(v7 ^ k1)
s8
=
p16(v8 ^ k1)
buf1[indextable[
0
]]
=
s1[
1
]
buf1[indextable[
8
]]
=
s1[
0
]
buf1[indextable[
1
]]
=
s2[
1
]
buf1[indextable[
9
]]
=
s2[
0
]
buf1[indextable[
2
]]
=
s3[
1
]
buf1[indextable[
10
]]
=
s3[
0
]
buf1[indextable[
3
]]
=
s4[
1
]
buf1[indextable[
11
]]
=
s4[
0
]
buf1[indextable[
4
]]
=
s5[
1
]
buf1[indextable[
12
]]
=
s5[
0
]
buf1[indextable[
5
]]
=
s6[
1
]
buf1[indextable[
13
]]
=
s6[
0
]
buf1[indextable[
6
]]
=
s7[
1
]
buf1[indextable[
14
]]
=
s7[
0
]
buf1[indextable[
7
]]
=
s8[
1
]
buf1[indextable[
15
]]
=
s8[
0
]
return
buf1
def
dodecrypt1(serial, indextable):
assert
(
len
(serial)
=
=
16
)
buf1
=
bytearray(serial)
s1
=
(buf1[indextable[
0
]] <<
8
) | buf1[indextable[
8
]]
s2
=
(buf1[indextable[
1
]] <<
8
) | buf1[indextable[
9
]]
s3
=
(buf1[indextable[
2
]] <<
8
) | buf1[indextable[
10
]]
s4
=
(buf1[indextable[
3
]] <<
8
) | buf1[indextable[
11
]]
s5
=
(buf1[indextable[
4
]] <<
8
) | buf1[indextable[
12
]]
s6
=
(buf1[indextable[
5
]] <<
8
) | buf1[indextable[
13
]]
s7
=
(buf1[indextable[
6
]] <<
8
) | buf1[indextable[
14
]]
s8
=
(buf1[indextable[
7
]] <<
8
) | buf1[indextable[
15
]]
'''
s1 = u16(buf1[0xb:0xd]) # 0x80c8
s2 = u16(buf1[9:0xb]) # 0x8b84
s3 = u16(buf1[7:9]) # 0xefa8
s4 = u16(buf1[5:7]) # 0xf12e
s5 = u16(buf1[3:5]) # 0x0x7a
s6 = u16(buf1[1:3]) # 0xba4d
s7 = (buf1[0] << 8) | buf1[0xf] # 0x7d70
s8 = u16(buf1[0xd:0xf]) # 0x31b8
'''
t1
=
s2 ^ s1
# 0xb4c
t2
=
(s4
+
s3) &
0xffff
# 0xe0d6
t3
=
(s5
-
s6) &
0xffff
# 0xe22d
cl
=
bin
(s8 ^ s7).lstrip(
"0b"
).count(
'1'
)
# 6 # hamming distance
print
(
hex
(s1),
hex
(s2),
hex
(s3),
hex
(s4),
hex
(s5),
hex
(s6),
hex
(s7),
hex
(s8))
print
(
hex
(t1),
hex
(t2),
hex
(t3),
hex
(cl))
k1
=
( (t2 & t1) | ((~t1) & t3) ) &
0xffff
# 0xe065
buf1[
0xc
:
0xc
+
2
]
=
p16(rol16(s7 ^ k1, cl))
buf1[
0xe
:
0xe
+
2
]
=
p16(rol16(s8 ^ k1, cl))
k2
=
( ((k1
*
t1) >> cl)
+
0x18
) &
0xffff
# 0x9beb
buf1[
0x8
:
0x8
+
2
]
=
p16(s5
+
k2)
buf1[
0xa
:
0xa
+
2
]
=
p16(s6
+
k2)
k3
=
( k2 ^ t3 ) &
0xffff
# 0x79c6
buf1[
0x6
:
0x6
+
2
]
=
p16(s4
-
k3)
buf1[
0x4
:
0x4
+
2
]
=
p16(s3
+
k3)
k4
=
( (k2 & k1) | (k3 & (k2 | k1)) ) &
0xffff
buf1[
0x0
:
0x0
+
2
]
=
p16(s1 ^ k4)
buf1[
0x2
:
0x2
+
2
]
=
p16(s2 ^ k4)
print
(
hex
(k1),
hex
(k2),
hex
(k3),
hex
(k4))
return
buf1
def
doencode2(s):
assert
(
len
(s)
%
3
=
=
0
)
chartable
=
[
149
,
226
,
128
,
198
,
234
,
195
,
213
,
141
,
158
,
197
,
179
,
98
,
100
,
77
,
118
,
186
,
146
,
253
,
222
,
127
,
66
,
114
,
129
,
173
,
121
,
84
,
115
,
133
,
134
,
94
,
241
,
132
,
106
,
245
,
99
,
216
,
254
,
168
,
192
,
200
,
79
,
201
,
199
,
3
,
123
,
229
,
223
,
2
,
0
,
13
,
31
,
60
,
19
,
34
,
37
,
59
,
43
,
23
,
170
,
160
,
246
,
151
,
89
,
88
,
109
,
15
,
12
,
6
,
61
,
27
,
14
,
33
,
20
,
38
,
45
,
4
,
18
,
28
,
9
,
1
,
46
,
51
,
53
,
35
,
32
,
11
,
56
,
26
,
50
,
44
,
57
,
124
,
209
,
242
,
92
,
117
,
161
,
8
,
36
,
16
,
40
,
41
,
63
,
49
,
7
,
10
,
47
,
17
,
25
,
30
,
62
,
21
,
29
,
42
,
58
,
52
,
22
,
5
,
54
,
55
,
39
,
48
,
24
,
108
,
74
,
122
,
68
,
152
,
150
,
105
,
196
,
235
,
204
,
73
,
190
,
181
,
72
,
113
,
148
,
225
,
163
,
177
,
120
,
250
,
83
,
70
,
64
,
203
,
188
,
71
,
131
,
193
,
238
,
249
,
232
,
97
,
169
,
251
,
194
,
210
,
76
,
85
,
218
,
247
,
126
,
217
,
143
,
172
,
227
,
82
,
96
,
155
,
233
,
86
,
156
,
137
,
87
,
180
,
81
,
125
,
176
,
116
,
142
,
162
,
157
,
237
,
182
,
224
,
95
,
252
,
75
,
110
,
165
,
65
,
208
,
167
,
187
,
240
,
140
,
145
,
101
,
185
,
212
,
230
,
135
,
184
,
191
,
248
,
236
,
159
,
154
,
211
,
111
,
147
,
93
,
102
,
136
,
67
,
91
,
80
,
243
,
130
,
183
,
206
,
103
,
231
,
244
,
255
,
175
,
205
,
214
,
220
,
171
,
104
,
90
,
138
,
221
,
239
,
228
,
189
,
78
,
164
,
119
,
178
,
69
,
166
,
153
,
112
,
219
,
107
,
215
,
144
,
207
,
174
,
139
,
202
]
rchartable
=
[
None
]
*
256
for
i, c
in
enumerate
(chartable):
rchartable[c]
=
i
r
=
b""
for
i
in
range
(
0
,
len
(s),
3
):
x, y, z
=
s[i], s[i
+
1
], s[i
+
2
]
a
=
(x &
0x3
) | ((z &
0xf
) <<
2
)
b
=
(y &
0x3c
) | ((x &
0xc
) >>
2
)
c
=
(x >>
4
) | ((y &
0x3
) <<
4
)
d
=
((y &
0xc0
) >>
2
) | (z >>
4
)
r
+
=
bytes([rchartable[a], rchartable[b], rchartable[c], rchartable[d]])
return
r
def
dodecode2(s):
assert
(
len
(s)
%
4
=
=
0
)
chartable
=
[
149
,
226
,
128
,
198
,
234
,
195
,
213
,
141
,
158
,
197
,
179
,
98
,
100
,
77
,
118
,
186
,
146
,
253
,
222
,
127
,
66
,
114
,
129
,
173
,
121
,
84
,
115
,
133
,
134
,
94
,
241
,
132
,
106
,
245
,
99
,
216
,
254
,
168
,
192
,
200
,
79
,
201
,
199
,
3
,
123
,
229
,
223
,
2
,
0
,
13
,
31
,
60
,
19
,
34
,
37
,
59
,
43
,
23
,
170
,
160
,
246
,
151
,
89
,
88
,
109
,
15
,
12
,
6
,
61
,
27
,
14
,
33
,
20
,
38
,
45
,
4
,
18
,
28
,
9
,
1
,
46
,
51
,
53
,
35
,
32
,
11
,
56
,
26
,
50
,
44
,
57
,
124
,
209
,
242
,
92
,
117
,
161
,
8
,
36
,
16
,
40
,
41
,
63
,
49
,
7
,
10
,
47
,
17
,
25
,
30
,
62
,
21
,
29
,
42
,
58
,
52
,
22
,
5
,
54
,
55
,
39
,
48
,
24
,
108
,
74
,
122
,
68
,
152
,
150
,
105
,
196
,
235
,
204
,
73
,
190
,
181
,
72
,
113
,
148
,
225
,
163
,
177
,
120
,
250
,
83
,
70
,
64
,
203
,
188
,
71
,
131
,
193
,
238
,
249
,
232
,
97
,
169
,
251
,
194
,
210
,
76
,
85
,
218
,
247
,
126
,
217
,
143
,
172
,
227
,
82
,
96
,
155
,
233
,
86
,
156
,
137
,
87
,
180
,
81
,
125
,
176
,
116
,
142
,
162
,
157
,
237
,
182
,
224
,
95
,
252
,
75
,
110
,
165
,
65
,
208
,
167
,
187
,
240
,
140
,
145
,
101
,
185
,
212
,
230
,
135
,
184
,
191
,
248
,
236
,
159
,
154
,
211
,
111
,
147
,
93
,
102
,
136
,
67
,
91
,
80
,
243
,
130
,
183
,
206
,
103
,
231
,
244
,
255
,
175
,
205
,
214
,
220
,
171
,
104
,
90
,
138
,
221
,
239
,
228
,
189
,
78
,
164
,
119
,
178
,
69
,
166
,
153
,
112
,
219
,
107
,
215
,
144
,
207
,
174
,
139
,
202
]
tmp
=
bytearray(
len
(s))
for
i, c
in
enumerate
(s):
tmp[i]
=
chartable[c]
for
c
in
tmp:
assert
(c <
0x40
)
r
=
b""
for
i
in
range
(
0
,
len
(tmp),
4
):
a, b, c, d
=
tmp[i], tmp[i
+
1
], tmp[i
+
2
], tmp[i
+
3
]
x
=
((c <<
4
) &
0xff
) | ((b &
0x3
) <<
2
) | (a &
0x3
)
y
=
((d &
0xf0
) <<
2
) | (b &
0x3c
) | ((c &
0x3f
) >>
4
)
z
=
((d <<
4
) &
0xff
) | ((a &
0x3f
) >>
2
)
r
+
=
bytes([x, y, z])
return
r
def
doencode3(r, constn
=
0x8267f5d9b0ea143c
):
assert
(
len
(r)
=
=
8
)
r
=
p64(u64(r)^constn)
s
=
bytearray(
8
)
s[
3
]
=
r[
0
]
s[
2
]
=
r[
2
] ^ s[
3
]
s[
1
]
=
r[
1
] ^ s[
2
]
s[
0
]
=
r[
3
] ^ s[
1
]
s[
7
]
=
r[
4
]
s[
6
]
=
r[
6
] ^ s[
7
]
s[
5
]
=
r[
5
] ^ s[
6
]
s[
4
]
=
r[
7
] ^ s[
5
]
return
s
def
dodecode3(s, constn
=
0x8267f5d9b0ea143c
):
assert
(
len
(s)
=
=
8
)
r
=
bytearray(
8
)
r[
0
]
=
s[
3
]
r[
1
]
=
s[
1
] ^ s[
2
]
r[
2
]
=
s[
2
] ^ s[
3
]
r[
3
]
=
s[
0
] ^ s[
1
]
r[
4
]
=
s[
7
]
r[
5
]
=
s[
5
] ^ s[
6
]
r[
6
]
=
s[
6
] ^ s[
7
]
r[
7
]
=
s[
4
] ^ s[
5
]
return
p64(u64(r)^constn)
def
name_to_serial(name):
assert
(
len
(name) <
=
16
)
#buf5 = bytearray(b"\x9a\x1e\x1d\x1c\x1b\x1a\x19\x18\x17\x16\x15\x14\x13\x12\x11\x10")
buf5
=
bytearray(
16
-
i
for
i
in
range
(
16
))
buf5[:
len
(name)]
=
name
if
len
(name) <
16
:
buf5[
len
(name)]
=
0
print
(buf5.
hex
())
# stage4
indextable3
=
[
0xb
,
0xd
,
0xf
,
0x1
,
0x3
,
0x5
,
0x7
,
0x9
,
0xc
,
0xe
,
0x0
,
0x2
,
0x4
,
0x6
,
0x8
,
0xa
]
buf3_2
=
doencrypt1(buf5, indextable3)
print
(buf3_2.
hex
())
# stage3
print
(
"buf5"
, buf5[:
8
])
#buf3_1 = doencode3(buf5[:8])
buf3_1
=
doencode3(b
'\0'
*
8
, u64(bytes.fromhex(
"5E 87 C4 F6 8F C6 60 81"
.replace(
" "
,""))))
print
(buf3_1.
hex
())
buf3
=
buf3_1
+
buf3_2
# stage2
buf2
=
doencode2(buf3)
print
(buf2.
hex
())
# stage1
indextable1
=
[
0xc
,
0xa
,
0x8
,
0x6
,
0x4
,
0x2
,
0x0
,
0xe
,
0xb
,
0x9
,
0x7
,
0x5
,
0x3
,
0x1
,
0xf
,
0xd
]
indextable2
=
[
0xb
,
0x9
,
0x7
,
0x5
,
0x3
,
0x1
,
0xf
,
0xd
,
0x8
,
0x6
,
0x4
,
0x2
,
0x0
,
0xe
,
0xc
,
0xa
]
serial
=
doencrypt1(buf2[:
16
], indextable1)
+
doencrypt1(buf2[
16
:], indextable2)
print
(
"serial"
)
print
(serial.
hex
())
return
serial
def
serial_to_name(serial):
assert
(
len
(serial)
=
=
32
)
# stage1
indextable1
=
[
0xc
,
0xa
,
0x8
,
0x6
,
0x4
,
0x2
,
0x0
,
0xe
,
0xb
,
0x9
,
0x7
,
0x5
,
0x3
,
0x1
,
0xf
,
0xd
]
indextable2
=
[
0xb
,
0x9
,
0x7
,
0x5
,
0x3
,
0x1
,
0xf
,
0xd
,
0x8
,
0x6
,
0x4
,
0x2
,
0x0
,
0xe
,
0xc
,
0xa
]
buf2
=
dodecrypt1(serial[:
16
], indextable1)
+
dodecrypt1(serial[
16
:], indextable2)
print
(
"buf2:"
, buf2.
hex
(), buf2)
# stage2
buf3
=
dodecode2(buf2)
print
(
"buf3"
, buf3.
hex
())
# stage3
print
(buf3[:
8
].
hex
())
buf4
=
dodecode3(buf3[:
8
])
# stage4
indextable3
=
[
0xb
,
0xd
,
0xf
,
0x1
,
0x3
,
0x5
,
0x7
,
0x9
,
0xc
,
0xe
,
0x0
,
0x2
,
0x4
,
0x6
,
0x8
,
0xa
]
buf5
=
dodecrypt1(buf3[
8
:], indextable3)
print
(buf5)
# stage5
#assert(buf4 == buf5[:8])
return
bytes(buf5)
print
(name_to_serial(b
"KCTF"
).
hex
().upper())
def
p16(n):
n &
=
0xffff
return
n.to_bytes(
2
,
'little'
)
def
u16(s):
assert
(
len
(s)
=
=
2
)
return
int
.from_bytes(s,
'little'
)
def
p64(n):
n &
=
0xffffffffffffffff
return
n.to_bytes(
8
,
'little'
)
def
u64(s):
assert
(
len
(s)
=
=
8
)
return
int
.from_bytes(s,
'little'
)
def
rol16(n, k):
n &
=
0xffff
return
((n << k) | (n >> (
16
-
k))) &
0xffff
def
ror16(n, k):
n &
=
0xffff
return
((n >> k) | (n << (
16
-
k))) &
0xffff
def
doencrypt1(buf, indextable):
assert
(
len
(buf)
=
=
16
)
buf1
=
bytearray(buf)
v1
=
u16(buf1[
0
:
2
])
# s1 ^ k4
v2
=
u16(buf1[
2
:
4
])
# s2 ^ k4
v3
=
u16(buf1[
4
:
6
])
# s3 + k3
v4
=
u16(buf1[
6
:
8
])
# s4 - k3
v5
=
u16(buf1[
8
:
0xa
])
# s5 + k2
v6
=
u16(buf1[
0xa
:
0xc
])
# s6 + k2
v7
=
u16(buf1[
0xc
:
0xe
])
# s7 ^ k1
v8
=
u16(buf1[
0xe
:
0x10
])
# s8 ^ k1
t1
=
v2 ^ v1
# s2 ^ s1
t2
=
(v4
+
v3) &
0xffff
# s4 + s3
t3
=
(v5
-
v6) &
0xffff
# s5 - s6
cl
=
bin
(v8 ^ v7).lstrip(
"0b"
).count(
'1'
)
# s8 ^ s7# hamming distance
v7
=
ror16(v7, cl)
v8
=
ror16(v8, cl)
k1
=
( (t2 & t1) | ((~t1) & t3) ) &
0xffff
k2
=
( ((k1
*
t1) >> cl)
+
0x18
) &
0xffff
k3
=
( k2 ^ t3 ) &
0xffff
# 0x79c6
k4
=
( (k2 & k1) | (k3 & (k2 | k1)) ) &
0xffff
s1
=
p16(v1 ^ k4)
s2
=
p16(v2 ^ k4)
s3
=
p16(v3
-
k3)
s4
=
p16(v4
+
k3)
s5
=
p16(v5
-
k2)
s6
=
p16(v6
-
k2)
s7
=
p16(v7 ^ k1)
s8
=
p16(v8 ^ k1)
buf1[indextable[
0
]]
=
s1[
1
]
buf1[indextable[
8
]]
=
s1[
0
]
buf1[indextable[
1
]]
=
s2[
1
]
buf1[indextable[
9
]]
=
s2[
0
]
buf1[indextable[
2
]]
=
s3[
1
]
buf1[indextable[
10
]]
=
s3[
0
]
buf1[indextable[
3
]]
=
s4[
1
]
buf1[indextable[
11
]]
=
s4[
0
]
buf1[indextable[
4
]]
=
s5[
1
]
buf1[indextable[
12
]]
=
s5[
0
]
buf1[indextable[
5
]]
=
s6[
1
]
buf1[indextable[
13
]]
=
s6[
0
]
buf1[indextable[
6
]]
=
s7[
1
]
buf1[indextable[
14
]]
=
s7[
0
]
buf1[indextable[
7
]]
=
s8[
1
]
buf1[indextable[
15
]]
=
s8[
0
]
return
buf1
def
dodecrypt1(serial, indextable):
assert
(
len
(serial)
=
=
16
)
buf1
=
bytearray(serial)
s1
=
(buf1[indextable[
0
]] <<
8
) | buf1[indextable[
8
]]
s2
=
(buf1[indextable[
1
]] <<
8
) | buf1[indextable[
9
]]
s3
=
(buf1[indextable[
2
]] <<
8
) | buf1[indextable[
10
]]
s4
=
(buf1[indextable[
3
]] <<
8
) | buf1[indextable[
11
]]
s5
=
(buf1[indextable[
4
]] <<
8
) | buf1[indextable[
12
]]
s6
=
(buf1[indextable[
5
]] <<
8
) | buf1[indextable[
13
]]
s7
=
(buf1[indextable[
6
]] <<
8
) | buf1[indextable[
14
]]
s8
=
(buf1[indextable[
7
]] <<
8
) | buf1[indextable[
15
]]
'''
s1 = u16(buf1[0xb:0xd]) # 0x80c8
s2 = u16(buf1[9:0xb]) # 0x8b84
s3 = u16(buf1[7:9]) # 0xefa8
s4 = u16(buf1[5:7]) # 0xf12e
s5 = u16(buf1[3:5]) # 0x0x7a
s6 = u16(buf1[1:3]) # 0xba4d
s7 = (buf1[0] << 8) | buf1[0xf] # 0x7d70
s8 = u16(buf1[0xd:0xf]) # 0x31b8
'''
t1
=
s2 ^ s1
# 0xb4c
t2
=
(s4
+
s3) &
0xffff
# 0xe0d6
t3
=
(s5
-
s6) &
0xffff
# 0xe22d
cl
=
bin
(s8 ^ s7).lstrip(
"0b"
).count(
'1'
)
# 6 # hamming distance
print
(
hex
(s1),
hex
(s2),
hex
(s3),
hex
(s4),
hex
(s5),
hex
(s6),
hex
(s7),
hex
(s8))
print
(
hex
(t1),
hex
(t2),
hex
(t3),
hex
(cl))
k1
=
( (t2 & t1) | ((~t1) & t3) ) &
0xffff
# 0xe065
buf1[
0xc
:
0xc
+
2
]
=
p16(rol16(s7 ^ k1, cl))
buf1[
0xe
:
0xe
+
2
]
=
p16(rol16(s8 ^ k1, cl))
k2
=
( ((k1
*
t1) >> cl)
+
0x18
) &
0xffff
# 0x9beb
buf1[
0x8
:
0x8
+
2
]
=
p16(s5
+
k2)
buf1[
0xa
:
0xa
+
2
]
=
p16(s6
+
k2)
k3
=
( k2 ^ t3 ) &
0xffff
# 0x79c6
buf1[
0x6
:
0x6
+
2
]
=
p16(s4
-
k3)
buf1[
0x4
:
0x4
+
2
]
=
p16(s3
+
k3)
k4
=
( (k2 & k1) | (k3 & (k2 | k1)) ) &
0xffff