附件给了个exe,是pyinstaller打包的结果,没操作过这种程序,赛场上也没做出来,现在再来做一做(输在了没准备工具上)
环境准备
解包需要两个工具
-
pyinstxtractor.py:exe -> pyc
-
uncompyle6:pyc -> py
安装:
git clone https://github.com/extremecoders-re/pyinstxtractor.git
#通过清华镜像源,下载快
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple uncompyle
如果python版本高于3.8,需要去做一些修改:
Windows下,修改uncompyle
包的脚本,在python的lib目录中,推荐用everything去搜索该文件(C:\Users\selph\AppData\Local\Programs\Python\Python311\Lib\site-packages\uncompyle6\bin\uncompile.py
)
搜索该关键词requires
,然后找到这些二元组,把我们自己用的python版本添加进去,保存即可正常使用
代码提取
exe->pyc:
.\pyinstxtractor-ng.exe filename.exe
pyc->py:
uncompyle6.exe -o . filename.pyc
逆向分析
拿到的是混淆过的脚本:
# uncompyle6 version 3.7.4
# Python bytecode 3.8 (3413)
# Decompiled from: Python 3.11.4 (tags/v3.11.4:d2340ef, Jun 7 2023, 05:45:37) [MSC v.1934 64 bit (AMD64)]
# Embedded file name: 1111.py
def f():
sss = '这是什么算法!'
def OOO0OOooooooO000OOOOO000OOooooooO(OOOOOooooooO000OOOOO000OOooooooO):
OOOOOooooooO000OOOOO000OOooooooO = [chr(x) for x in OOOOOooooooO000OOOOO000OOooooooO]
for OOOOOooooOoooooooooooooooOOOOOOOOOO000OOooooooO in range(len(OOOOOooooooO000OOOOO000OOooooooO)):
if OOOOOooooooO000OOOOO000OOooooooO[OOOOOooooOoooooooooooooooOOOOOOOOOO000OOooooooO].isupper() == True:
OOOOOooooooO000OOOOO000OOooooooO[OOOOOooooOoooooooooooooooOOOOOOOOOO000OOooooooO] = chr((ord(OOOOOooooooO000OOOOO000OOooooooO[OOOOOooooOoooooooooooooooOOOOOOOOOO000OOooooooO]) - 52) % 26 + 65)
else:
if OOOOOooooooO000OOOOO000OOooooooO[OOOOOooooOoooooooooooooooOOOOOOOOOO000OOooooooO].islower() == True:
OOOOOooooooO000OOOOO000OOooooooO[OOOOOooooOoooooooooooooooOOOOOOOOOO000OOooooooO] = chr((ord(OOOOOooooooO000OOOOO000OOooooooO[OOOOOooooOoooooooooooooooOOOOOOOOOO000OOooooooO]) - 84) % 26 + 97)
return [ord(x) for x in ''.join(OOOOOooooooO000OOOOO000OOooooooO)]
def OOO0OOOooooooO000OOOOO000OOooooooO(OOOOO0000OOOooooooO0000OOOOO000OOooooooO, OOOOOooooO0OOoooooooooooooooOOOOOOOOOO000OOooooooO):
j = 0
OOOO0OOOooooooO000OOOOO000OOooooooO = ''
for OOOOOooooOoooooooooooooooOOOOOOOOOO000OOooooooO in range(len(OOOOO0000OOOooooooO0000OOOOO000OOooooooO)):
if OOOOO0000OOOooooooO0000OOOOO000OOooooooO[OOOOOooooOoooooooooooooooOOOOOOOOOO000OOooooooO].isalpha():
OOOO0OOOooooooO0000OOOOO000OOooooooO = ord(OOOOOooooO0OOoooooooooooooooOOOOOOOOOO000OOooooooO[(j % len(OOOOOooooO0OOoooooooooooooooOOOOOOOOOO000OOooooooO))].upper()) - 65
if OOOOO0000OOOooooooO0000OOOOO000OOooooooO[OOOOOooooOoooooooooooooooOOOOOOOOOO000OOooooooO].isupper():
OOOO0OOOooooooO000OOOOO000OOooooooO += chr((ord(OOOOO0000OOOooooooO0000OOOOO000OOooooooO[OOOOOooooOoooooooooooooooOOOOOOOOOO000OOooooooO]) - 39 - OOOO0OOOooooooO0000OOOOO000OOooooooO) % 26 + 65)
else:
OOOO0OOOooooooO000OOOOO000OOooooooO += chr((ord(OOOOO0000OOOooooooO0000OOOOO000OOooooooO[OOOOOooooOoooooooooooooooOOOOOOOOOO000OOooooooO]) - 71 - OOOO0OOOooooooO0000OOOOO000OOooooooO) % 26 + 97)
j += 1
else:
OOOO0OOOooooooO000OOOOO000OOooooooO += OOOOO0000OOOooooooO0000OOOOO000OOooooooO[OOOOOooooOoooooooooooooooOOOOOOOOOO000OOooooooO]
else:
return OOOO0OOOooooooO000OOOOO000OOooooooO
def OOOOOooooooO000OOoooooooooooooooOOOOOOOOOO000OOooooooO(OOOOOooooO0OOoooooooooooooooOOOOOOOOOO000OOooooooO):
s = len(OOOOOooooO0OOoooooooooooooooOOOOOOOOOO000OOooooooO)
if s != 5:
return 0
for OOOOOooooOoooooooooooooooOOOOOOOOOO000OOooooooO in range(s):
if OOOOOooooO0OOoooooooooooooooOOOOOOOOOO000OOooooooO[OOOOOooooOoooooooooooooooOOOOOOOOOO000OOooooooO].islower() == False:
return 0
return 1
def check(OOOOOooooO0OOoooooooooooooooOOOOOOOOOO000OOooooooO):
if OOOOOooooooO000OOoooooooooooooooOOOOOOOOOO000OOooooooO(OOOOOooooO0OOoooooooooooooooOOOOOOOOOO000OOooooooO) == 0:
return 0
OOO = OOO0OOooooooO000OOOOO000OOooooooO([82, 115, 121, 114, 116, 127, 124, 104, 104, 105, 104, 106, 106, 105, 122, 104, 105, 124, 116, 122, 105, 104, 124, 103, 122, 103, 106, 106, 103, 122, 106, 103, 105, 106, 106, 115, 105, 106, 103, 115, 97, 113, 125])
arr = 'Aixit{815r1736-128j-d184-0734-eg67sed34nad}'
OOOO0OOOooooooO000OOOOO000OOooooooO = OOO0OOOooooooO000OOOOO000OOooooooO(arr, OOOOOooooO0OOoooooooooooooooOOOOOOOOOO000OOooooooO)
for OOOOOooooOoooooooooooooooOOOOOOOOOO000OOooooooO in range(len(OOOO0OOOooooooO000OOOOO000OOooooooO)):
OOOOOooooO000OOoooooooooooooooOOOOOOOOOO000OOooooooO = ord(OOOO0OOOooooooO000OOOOO000OOooooooO[OOOOOooooOoooooooooooooooOOOOOOOOOO000OOooooooO])
if OOOOOooooO000OOoooooooooooooooOOOOOOOOOO000OOooooooO | 68 != OOO[OOOOOooooOoooooooooooooooOOOOOOOOOO000OOooooooO]:
return 0
return 1
if __name__ == '__main__':
print('欢迎来到ctf登陆系统')
OOOOOooooOooooooooooooOOOOOOOOOO000OOooooooO = input('请输入用户名:')
OOOOOooooOooooooooooooOOOOOOOO000OOooooooO = input('请输入密码:')
OOOOOooooOooooooooooooOOOOOOOOOO000OOooooooO += OOOOOooooOooooooooooooOOOOOOOO000OOooooooO
if check(OOOOOooooOooooooooooooOOOOOOOOOO000OOooooooO) == True:
print('登录成功!flag的格式为flag{xxxxx-xxxxxx-xxxxx-xxxxxxxxx}')
else:
print('登录失败')
重命名一下变量:
# uncompyle6 version 3.7.4
# Python bytecode 3.8 (3413)
# Decompiled from: Python 3.11.4 (tags/v3.11.4:d2340ef, Jun 7 2023, 05:45:37) [MSC v.1934 64 bit (AMD64)]
# Embedded file name: 1111.py
def f():
sss = '这是什么算法!'
def fun1(param1):
param1 = [chr(x) for x in param1]
for i in range(len(param1)):
if param1[i].isupper():
param1[i] = chr((ord(param1[i]) - 52) % 26 + 65)
else:
if param1[i].islower():
param1[i] = chr((ord(param1[i]) - 84) % 26 + 97)
return [ord(x) for x in ''.join(param1)]
def fun2(arr, userinput):
j = 0
res = ''
for i in range(len(arr)):
if arr[i].isalpha():
index = ord(userinput[(j % len(userinput))].upper()) - 65
if arr[i].isupper():
res += chr((ord(arr[i]) - 39 - index) % 26 + 65)
else:
res += chr((ord(arr[i]) - 71 - index) % 26 + 97)
j += 1
else:
res += arr[i]
return res
def fun3(param1):
s = len(param1)
if s != 5:
return 0
for i in range(s):
if not param1[i].islower():
return 0
return 1
def check(userinput):
if fun3(userinput) == 0:
return 0
target = fun1([82, 115, 121, 114, 116, 127, 124, 104, 104, 105, 104, 106, 106, 105, 122, 104, 105, 124, 116, 122, 105, 104, 124, 103, 122, 103, 106, 106, 103, 122, 106, 103, 105, 106, 106, 115, 105, 106, 103, 115, 97, 113, 125])
print(target)
arr = 'Aixit{815r1736-128j-d184-0734-eg67sed34nad}'
res = fun2(arr, userinput)
for i in range(len(res)):
if ord(res[i]) | 68 != target[i]:
return 0
return 1
if __name__ == '__main__':
print('欢迎来到ctf登陆系统')
buf = input('请输入用户名:')
buf2 = input('请输入密码:')
buf += buf2
if check(buf):
print('登录成功!flag的格式为flag{xxxxx-xxxxxx-xxxxx-xxxxxxxxx}')
else:
print('登录失败')
这里输入的用户名和密码会拼接成为一个key,作为参数进入check函数进行校验
fun3限制用户输入,必须是5个字节,且全都是小写
fun1会固定生成一个数组target
fun2会处理用户输入生成一个数组res
然后把res数组或一个68,然后和target数组比对,如果全相同,则表示验证成功
由于或操作的存在,逆向算法存在一定困难,所以可以采用暴力破解的方式:
import string
res = [69, 102, 108, 101, 103, 127, 124, 117, 117, 118, 117, 119, 119, 118, 109, 117, 118, 124, 103, 109, 118, 117, 124, 116, 109, 116, 119, 119, 116, 109, 119, 116, 118, 119, 119, 102, 118, 119, 116, 102, 110, 100, 125]
arr = 'Aixit{815r1736-128j-d184-0734-eg67sed34nad}'
def fun2(arr, userinput):
j = 0
res_ = ''
for i in range(len(arr)):
if arr[i].isalpha():
index = ord(userinput[(j % len(userinput))].upper()) - 65
if arr[i].isupper():
res_ += chr((ord(arr[i]) - 39 - index) % 26 + 65)
else:
res_ += chr((ord(arr[i]) - 71 - index) % 26 + 97)
j += 1
else:
res_ += arr[i]
return res_
def brute():
for i in string.ascii_lowercase:
for j in string.ascii_lowercase:
for k in string.ascii_lowercase:
for l in string.ascii_lowercase:
for m in string.ascii_lowercase:
res_ = fun2(arr, i + j + k + l + m)
for n in range(len(res_)):
if ord(res_[n]) | 68 != res[n]:
break
if n == len(res_) - 1:
print(i + j + k + l + m)
return
brute()
提取fun1计算结果,和fun2函数
因为输入就5个字符,所以就爆破5个字符的内容,如果前5字符符合了,后面生成的结果也会符合
结果:admin
答案:flag{815r1736-128g-r184-0734-wt67sbr34fnd}