re學習筆記(67)SCTF-re-signin

考察的是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_!!}
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章