考察的是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 <stdio.h>
#include <string.h>
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_!!}