-
-
[原创] SUSCTF 2022 DigitalCircuits 分析过程及解题脚本
-
发表于: 2022-3-11 10:19 8235
-
下载是一个main.exe,根据ico可以知道是python生成的exe文件,python中通过pyinstaller进行py转exe,在默认情况下,并且只有一个exe文件,所以猜测应该是-F进行转换,所以此时可以尝试用pyinstxtractor进行解包:
生成一个_extracted文件夹:
进入文件夹找到同名的pyc文件,对比正常的stuct.pyc文件发现少了16个字节的py头:
将py头复制过去即可反编译,这里无法用在线反编译猜测应该是文件过大,所以采用python进行反编译:
反编译(需要注意python的版本,3.9以上的好像反编译会失败)
根据if可以得知传入的参数非0即1,所以可以知道应该是逻辑指令,f1就是&
,f2就是|
,f3取非,所以这部分就跟题目名称对上了,数电三大基础逻辑运算:
代入f1-f3
得到:(a & ~b) | (~a & b)
,emm,就是xor
,在数电中的基础逻辑语句只有三个,异或虽然在python中是有^
这个符号代替的,但实际原理就是题目中的那样进行逻辑操作:
简化:
f5同样代入:
得到,没看懂在干啥:
找到f6调用的位置:
测试一下:
得到res: 10011110001101110111100110111010
可以发现f6其实就是做了个二进制加法,传入的两个参数为二进制字符串,对于二进制字符串,字符串的高位为数据低位,所以传入之后会先对字符串进行翻转:
那么f5
的三次异或就可以理解了,最开始z=0
,然后传入的x=1
,y=1
,s = x ^ y ^ z = 0
,然后第二个c
是用来检测是否产生进位,明显0b01 + 0b01 = 0b10
,会产生进位,所以c = 1
,然后将进位值给到z
,代入下一轮循环,最终生成
f7,f8
都是传入一个二进制字符串,然后传入一个n
,很明显,f7
就是左移,f8
就是右移,n
为位数
f9逐位异或,最终就是整体异或:
首先是限制了flag
格式为SUSCTF{xxx}
,flag
正文内容为24
字节,进行三次循环,每次循环取8个字节,分成前后4个字节,然后拼接成32位的字符串,bin(ord(flagstr[i]))[2:].zfill(8)
字符转二进制字符串
处理完字符串之后通过f10进行处理,这里传入了k0-k3
应该是4
个key:
转成16进制看看:
将d也转成16进制,发现TEA算法特征
f10代入功能代码进行简化,可以得到f10就是TEA算法的加密过程:
测试:
每次循环的结果是二进制字符串的拼接:
每次循环取flag的8个字节,加密结果互不影响,所以最终拼接会得到192个字节的长度,与res进行比较:
那么只需要将res按64字节分成三份,分别进行解密即可得到真正的flag
得到flag:
考点:
比起以往的XCTF联赛逆向,这次的题目感觉像是入门题了,整体难度不高,该题的难点在于将TEA算法用二进制的形式进行描述,但只要将功能代码分析代入简化,便能轻松秒杀
pip3 install uncompyle6
pip3 install uncompyle6
uncompyle6
-
o .
/
DigitalCircuits.pyc
uncompyle6
-
o .
/
DigitalCircuits.pyc
# uncompyle6 version 3.8.0
# Python bytecode 3.7.0 (3394)
# Decompiled from: Python 3.9.6 (tags/v3.9.6:db3ff76, Jun 28 2021, 15:26:21) [MSC v.1929 64 bit (AMD64)]
# Embedded file name: DigitalCircuits.py
# Compiled at: 1995-09-28 00:18:56
# Size of source mod 2**32: 257 bytes
import
time
def
f1(a, b):
if
a
=
=
'1'
:
if
b
=
=
'1'
:
return
'1'
return
'0'
def
f2(a, b):
if
a
=
=
'0'
:
if
b
=
=
'0'
:
return
'0'
return
'1'
def
f3(a):
if
a
=
=
'1'
:
return
'0'
if
a
=
=
'0'
:
return
'1'
def
f4(a, b):
return
f2(f1(a, f3(b)), f1(f3(a), b))
def
f5(x, y, z):
s
=
f4(f4(x, y), z)
c
=
f2(f1(x, y), f1(z, f2(x, y)))
return
(s, c)
def
f6(a, b):
ans
=
''
z
=
'0'
a
=
a[::
-
1
]
b
=
b[::
-
1
]
for
i
in
range
(
32
):
ans
+
=
f5(a[i], b[i], z)[
0
]
z
=
f5(a[i], b[i], z)[
1
]
return
ans[::
-
1
]
def
f7(a, n):
return
a[n:]
+
'0'
*
n
def
f8(a, n):
return
n
*
'0'
+
a[:
-
n]
def
f9(a, b):
ans
=
''
for
i
in
range
(
32
):
ans
+
=
f4(a[i], b[i])
return
ans
def
f10(v0, v1, k0, k1, k2, k3):
s
=
'00000000000000000000000000000000'
d
=
'10011110001101110111100110111001'
for
i
in
range
(
32
):
s
=
f6(s, d)
v0
=
f6(v0, f9(f9(f6(f7(v1,
4
), k0), f6(v1, s)), f6(f8(v1,
5
), k1)))
v1
=
f6(v1, f9(f9(f6(f7(v0,
4
), k2), f6(v0, s)), f6(f8(v0,
5
), k3)))
return
v0
+
v1
k0
=
'0100010001000101'
.zfill(
32
)
k1
=
'0100000101000100'
.zfill(
32
)
k2
=
'0100001001000101'
.zfill(
32
)
k3
=
'0100010101000110'
.zfill(
32
)
flag
=
input
(
'please input flag:'
)
if
flag[
0
:
7
] !
=
'SUSCTF{'
or
flag[(
-
1
)] !
=
'}'
:
print
(
'Error!!!The formate of flag is SUSCTF{XXX}'
)
time.sleep(
5
)
exit(
0
)
flagstr
=
flag[
7
:
-
1
]
if
len
(flagstr) !
=
24
:
print
(
'Error!!!The length of flag 24'
)
time.sleep(
5
)
exit(
0
)
else
:
res
=
''
for
i
in
range
(
0
,
len
(flagstr),
8
):
v0
=
flagstr[i:i
+
4
]
v0
=
bin
(
ord
(flagstr[i]))[
2
:].zfill(
8
)
+
bin
(
ord
(flagstr[(i
+
1
)]))[
2
:].zfill(
8
)
+
bin
(
ord
(flagstr[(i
+
2
)]))[
2
:].zfill(
8
)
+
bin
(
ord
(flagstr[(i
+
3
)]))[
2
:].zfill(
8
)
v1
=
bin
(
ord
(flagstr[(i
+
4
)]))[
2
:].zfill(
8
)
+
bin
(
ord
(flagstr[(i
+
5
)]))[
2
:].zfill(
8
)
+
bin
(
ord
(flagstr[(i
+
6
)]))[
2
:].zfill(
8
)
+
bin
(
ord
(flagstr[(i
+
7
)]))[
2
:].zfill(
8
)
res
+
=
f10(v0, v1, k0, k1, k2, k3)
if
res
=
=
'001111101000100101000111110010111100110010010100010001100011100100110001001101011000001110001000001110110000101101101000100100111101101001100010011100110110000100111011001011100110010000100111'
:
print
(
'True'
)
else
:
print
(
'False'
)
time.sleep(
5
)
# uncompyle6 version 3.8.0
# Python bytecode 3.7.0 (3394)
# Decompiled from: Python 3.9.6 (tags/v3.9.6:db3ff76, Jun 28 2021, 15:26:21) [MSC v.1929 64 bit (AMD64)]
# Embedded file name: DigitalCircuits.py
# Compiled at: 1995-09-28 00:18:56
# Size of source mod 2**32: 257 bytes
import
time
def
f1(a, b):
if
a
=
=
'1'
:
if
b
=
=
'1'
:
return
'1'
return
'0'
def
f2(a, b):
if
a
=
=
'0'
:
if
b
=
=
'0'
:
return
'0'
return
'1'
def
f3(a):
if
a
=
=
'1'
:
return
'0'
if
a
=
=
'0'
:
return
'1'
def
f4(a, b):
return
f2(f1(a, f3(b)), f1(f3(a), b))
def
f5(x, y, z):
s
=
f4(f4(x, y), z)
c
=
f2(f1(x, y), f1(z, f2(x, y)))
return
(s, c)
def
f6(a, b):
ans
=
''
z
=
'0'
a
=
a[::
-
1
]
b
=
b[::
-
1
]
for
i
in
range
(
32
):
ans
+
=
f5(a[i], b[i], z)[
0
]
z
=
f5(a[i], b[i], z)[
1
]
return
ans[::
-
1
]
def
f7(a, n):
return
a[n:]
+
'0'
*
n
def
f8(a, n):
return
n
*
'0'
+
a[:
-
n]
def
f9(a, b):
ans
=
''
for
i
in
range
(
32
):
ans
+
=
f4(a[i], b[i])
return
ans
def
f10(v0, v1, k0, k1, k2, k3):
s
=
'00000000000000000000000000000000'
d
=
'10011110001101110111100110111001'
for
i
in
range
(
32
):
s
=
f6(s, d)
v0
=
f6(v0, f9(f9(f6(f7(v1,
4
), k0), f6(v1, s)), f6(f8(v1,
5
), k1)))
v1
=
f6(v1, f9(f9(f6(f7(v0,
4
), k2), f6(v0, s)), f6(f8(v0,
5
), k3)))
return
v0
+
v1
k0
=
'0100010001000101'
.zfill(
32
)
k1
=
'0100000101000100'
.zfill(
32
)
k2
=
'0100001001000101'
.zfill(
32
)
k3
=
'0100010101000110'
.zfill(
32
)
flag
=
input
(
'please input flag:'
)
if
flag[
0
:
7
] !
=
'SUSCTF{'
or
flag[(
-
1
)] !
=
'}'
:
print
(
'Error!!!The formate of flag is SUSCTF{XXX}'
)
time.sleep(
5
)
exit(
0
)
flagstr
=
flag[
7
:
-
1
]
if
len
(flagstr) !
=
24
:
print
(
'Error!!!The length of flag 24'
)
time.sleep(
5
)
exit(
0
)
else
:
res
=
''
for
i
in
range
(
0
,
len
(flagstr),
8
):
v0
=
flagstr[i:i
+
4
]
v0
=
bin
(
ord
(flagstr[i]))[
2
:].zfill(
8
)
+
bin
(
ord
(flagstr[(i
+
1
)]))[
2
:].zfill(
8
)
+
bin
(
ord
(flagstr[(i
+
2
)]))[
2
:].zfill(
8
)
+
bin
(
ord
(flagstr[(i
+
3
)]))[
2
:].zfill(
8
)
v1
=
bin
(
ord
(flagstr[(i
+
4
)]))[
2
:].zfill(
8
)
+
bin
(
ord
(flagstr[(i
+
5
)]))[
2
:].zfill(
8
)
+
bin
(
ord
(flagstr[(i
+
6
)]))[
2
:].zfill(
8
)
+
bin
(
ord
(flagstr[(i
+
7
)]))[
2
:].zfill(
8
)
res
+
=
f10(v0, v1, k0, k1, k2, k3)
if
res
=
=
'001111101000100101000111110010111100110010010100010001100011100100110001001101011000001110001000001110110000101101101000100100111101101001100010011100110110000100111011001011100110010000100111'
:
print
(
'True'
)
else
:
print
(
'False'
)
time.sleep(
5
)
def
f1(a, b):
if
a
=
=
'1'
:
if
b
=
=
'1'
:
return
'1'
return
'0'
def
f2(a, b):
if
a
=
=
'0'
:
if
b
=
=
'0'
:
return
'0'
return
'1'
def
f3(a):
if
a
=
=
'1'
:
return
'0'
if
a
=
=
'0'
:
return
'1'
def
f1(a, b):
if
a
=
=
'1'
:
if
b
=
=
'1'
:
return
'1'
return
'0'
def
f2(a, b):
if
a
=
=
'0'
:
if
b
=
=
'0'
:
return
'0'
return
'1'
def
f3(a):
if
a
=
=
'1'
:
return
'0'
if
a
=
=
'0'
:
return
'1'
def
f4(a, b):
return
f2(f1(a, f3(b)), f1(f3(a), b))
def
f4(a, b):
return
f2(f1(a, f3(b)), f1(f3(a), b))
def
f4(a, b):
return
a ^ b
def
f4(a, b):
return
a ^ b
def
f5(x, y, z):
s
=
f4(f4(x, y), z)
c
=
f2(f1(x, y), f1(z, f2(x, y)))
return
(s, c)
def
f5(x, y, z):
s
=
f4(f4(x, y), z)
c
=
f2(f1(x, y), f1(z, f2(x, y)))
return
(s, c)
def
f5(x, y, z):
s
=
x ^ y ^ z
c
=
(x & y) | (z & (x | y))
return
(s, c)
def
f5(x, y, z):
s
=
x ^ y ^ z
c
=
(x & y) | (z & (x | y))
return
(s, c)
def
f6(a, b):
ans
=
''
z
=
'0'
a
=
a[::
-
1
]
b
=
b[::
-
1
]
for
i
in
range
(
32
):
ans
+
=
f5(a[i], b[i], z)[
0
]
z
=
f5(a[i], b[i], z)[
1
]
return
ans[::
-
1
]
def
f6(a, b):
ans
=
''
z
=
'0'
a
=
a[::
-
1
]
b
=
b[::
-
1
]
for
i
in
range
(
32
):
ans
+
=
f5(a[i], b[i], z)[
0
]
z
=
f5(a[i], b[i], z)[
1
]