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_!!}
在这里插入图片描述

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