考察的是python的exe文件反编译成py文件这个知识点,
所用工具在我的GitHub:https://github.com/Eliauk55/CTF-tools
先用pyinstxtractor.py得到exe转pyc文件
进入目录下的signin.exe_extracted文件夹,用WinHex打开struct文件和main文件
发现main首字节是E3
,而struct文件的E3
在第17字节,所以需要将struct文件的前16字节粘贴到main文件前,补齐一下文件头
选中前16字节,ctrl+c复制。回到main文件,在第一个字节处ctrl+v粘贴
补好文件头的main文件
另存为main.pyc文件。
在线网站无法解密,使用uncompyle6反编译成py文件
安装
python -m pip install uncompyle6
使用
uncompyle6 -o main.py main.pyc
得到main.py文件
# uncompyle6 version 3.7.2
# Python bytecode 3.8 (3413)
# Decompiled from: Python 3.7.7 (tags/v3.7.7:d7c567b08f, Mar 10 2020, 10:41:24) [MSC v.1900 64 bit (AMD64)]
# Embedded file name: main.py
# Compiled at: 1995-09-28 00:18:56
# Size of source mod 2**32: 272 bytes
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from signin import *
from mydata import strBase64
from ctypes import *
import _ctypes
from base64 import b64decode
import os
class AccountChecker:
def __init__(self):
self.dllname = './tmp.dll'
self.dll = self._AccountChecker__release_dll()
self.enc = self.dll.enc #让self.enc等于dll内的enc函数
self.enc.argtypes = (c_char_p, c_char_p, c_char_p, c_int)
self.enc.restype = c_int
self.accounts = {b'SCTFer': b64decode(b'PLHCu+fujfZmMOMLGHCyWWOq5H5HDN2R5nHnlV30Q0EA')}
self.try_times = 0
def __release_dll(self):
with open(self.dllname, 'wb') as (f):
f.write(b64decode(strBase64.encode('ascii')))
return WinDLL(self.dllname)
def clean(self):
_ctypes.FreeLibrary(self.dll._handle)
if os.path.exists(self.dllname):
os.remove(self.dllname)
def _error(self, error_code):
errormsg = {0:'Unknown Error',
1:'Memory Error'}
QMessageBox.information(None, 'Error', errormsg[error_code], QMessageBox.Abort, QMessageBox.Abort)
sys.exit(1)
def __safe(self, username: bytes, password: bytes): #加密函数
pwd_safe = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' #构造一个空字符串
status = self.enc(username, password, pwd_safe, len(pwd_safe)) #传入enc函数
# status为返回值,0成功1失败
return (pwd_safe, status) #返回加密后的密码,
def check(self, username, password):
self.try_times += 1
if username not in self.accounts:
return False
encrypted_pwd, status = self._AccountChecker__safe(username, password) #调用safe函数,将加密后的密码赋值给encrypted
if status == 1: #1失败,0成功
self._AccountChecker__error(1)
if encrypted_pwd != self.accounts[username]: #加密后的密码要等于上面保存的密码
return False
self.try_times -= 1
return True
class SignInWnd(QMainWindow, Ui_QWidget):
def __init__(self, checker, parent=None):
super().__init__(parent)
self.checker = checker
self.setupUi(self)
self.PB_signin.clicked.connect(self.on_confirm_button_clicked)
@pyqtSlot()
def on_confirm_button_clicked(self):
username = bytes((self.LE_usrname.text()), encoding='ascii') #取用户名当作ASCII码解释
password = bytes((self.LE_pwd.text()), encoding='ascii') #取密码当作ASCII解释
if username == b'' or password == b'': #如果用户名或者密码为空
self.check_input_msgbox() #检查输入窗口
else:
self.msgbox(self.checker.check(username, password)) #调用check方法
def check_input_msgbox(self):
QMessageBox.information(None, 'Error', 'Check Your Input!', QMessageBox.Ok, QMessageBox.Ok)
def msgbox(self, status):
msg_ex = {0:'',
1:'',
2:"It's no big deal, try again!",
3:'Useful information is in the binary, guess what?'}
msg = 'Succeeded! Flag is your password' if status else 'Failed to sign in\n' + msg_ex[(self.checker.try_times % 4)]
QMessageBox.information(None, 'SCTF2020', msg, QMessageBox.Ok, QMessageBox.Ok)
if __name__ == '__main__':
app = QApplication(sys.argv)
checker = AccountChecker()
sign_in_wnd = SignInWnd(checker)
sign_in_wnd.show()
app.exec()
checker.clean()
sys.exit()
其中调用了dll中的enc方法
dll会在程序运行的时候动态生成,IDA载入
加密函数
加密函数是个CRC64,
先得到密文
写C语言脚本
#include
#include
unsigned __int64 func(unsigned __int64 Dst)
{
int j;
for (j = 0; j < 64; ++j)
{
if (!(Dst&1))
Dst /=2; //不能算术右移,会保留符号位
else
Dst = ((Dst ^ 0xB0004B7679FA26B3ui64) >>1) + 0x8000000000000000ui64;
}
return Dst;
}
int main(void)
{
char name[6] = { 83,67,84,70,101,114 };
unsigned char enpwd[33] = { 60,177,194,187,231,238,141,246,102,48,227,11,24,112,
178,89,99,170,228,126,71,12,221,145,230,113,231,149,93,244,67,65,0 };
char flag[33];
unsigned __int64 Dst = 0;
int i, j;
for (i = 0; i < 32; ++i)
enpwd[i] ^= name[i % 6];
int num;
num = 0;
for (j = 0; j < 4; ++j)
{
memset(&Dst, 0, sizeof(Dst));
memcpy(&Dst, enpwd + num, 8);
Dst = func(Dst);
memcpy(flag + num, &Dst, 8);
num += 8;
}
flag[32] = 0;
puts(flag);
}
好奇为啥无符号数他会进行算数右移!!!!
写脚本写半天>>1结果不对,,,还是改成了/=2
得到flag为SCTF{We1c0m3_To_Sctf_2020_re_!!}