Python软件逆向-SE工具箱

发布时间 2023-08-14 10:57:02作者: .FUYAN

原因

今天在网上看见以个SE工具箱,号称可以通过某人的qq、手机号或者微博进行反查信息,只需知道其中一个便可查询其他信息。我一看,这不就是一社工库吗,于是便想下载来看一下
image

结果发现这软件竟然收费,而且是用python写的
image

破解过程

解包

对exe进行解包用的是pyinstxtractor
下载地址:https://github.com/extremecoders-re/pyinstxtractor/releases/
下载完成后将压缩包进行解压,得到了一下文件
image
然后将要解包的exe放进这个目录
image
打开powershell进入当前目录输入

 python .\pyinstxtractor.py <要解包程序的地址>

然后执行
image
这时在当前目录下便出现了一个新的文件夹
image

反编译

进入该文件夹,找到与exe文件同名的pyc文件,尝试使用uncompyle6进行反编译

pip install uncompyle6
 uncompyle6 .\SE工具箱.pyc >so.py

这里的so.py是将反编译的结果保存至so.py这一文件
image
但是发现使用uncompyle6反编译失败,于是果断选择在网上寻找在线反编译工具

https://tool.lu/pyc/

反编译的到如下代码

#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
# Version: Python 3.9

import threading
import win32api
import pyDes
from binascii import b2a_hex, a2b_hex
import base64
import requests
import re
import os
import random
import time
import PySimpleGUI as Sg
Des_Key = '12345678'
Des_IV = '00000000'
TYPE = 'DB'

class Register:
    
    def __init__(self, TYPE):
        self.TYPE = TYPE
        self.Des_Key = Des_Key
        self.Des_IV = Des_IV

    
    def getCVolumeSerialNumber(self):
        CVolumeSerialNumber = win32api.GetVolumeInformation('C:\\')[1]
        if CVolumeSerialNumber:
            return str(CVolumeSerialNumber)
        return None

    
    def DesEncrypt(self, str):
        k = pyDes.des(self.Des_Key, pyDes.CBC, self.Des_IV, None, pyDes.PAD_PKCS5, **('pad', 'padmode'))
        encryptStr = k.encrypt(str)
        string = base64.b64encode(encryptStr)
        return string

    
    def DesDecrypt(self, string):
        string = base64.b64decode(string)
        k = pyDes.des(self.Des_Key, pyDes.CBC, self.Des_IV, None, pyDes.PAD_PKCS5, **('pad', 'padmode'))
        decryptStr = k.decrypt(string)
        return decryptStr

    
    def Regist_New(self):
        pass
    # WARNING: Decompyle incomplete

    
    def encryCode(self):
        global serialnumber
        rand = str(random.randrange(1, 1000))
        serialnumber = self.getCVolumeSerialNumber()
        content = str({
            'stat': '',
            'Serial': serialnumber,
            'Random': rand,
            'Type': self.TYPE })
        encryptstr = self.DesEncrypt(content).decode('utf8')
        return encryptstr

    
    def checKey(self):
        key = values['-key-']
    # WARNING: Decompyle incomplete

    
    def GetTime(self):
        url = 'http://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp'
    # WARNING: Decompyle incomplete

    
    def CheckTimeTri(self):
        if int(self.GetTime()) >= self.deadline:
            os.remove('conf.bin')
            return 403


headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3877.400 QQBrowser/10.8.4506.400' }

def SeTool():
    global phone, phonediqu, lolName, lolDaqu, qqlm, weibo, qq, qq, phone, weibo
    
    def qqMsg():
        global phone, phonediqu, lolName, lolDaqu, qqlm
        print('正在查询...')
        url = 'https://www.hmily.vip/api/qb/?qq=' + str(qq)
        html = requests.get(url, headers, **('url', 'headers'))
        if html.json()['code'] == 1:
            phone = html.json()['phone']
            phonediqu = html.json()['phonediqu']
            lolName = html.json()['lolName']
            lolDaqu = html.json()['lolDaqu']
            qqlm = html.json()['qqlm']

    
    def phoneMsg():
        global qq, phonediqu, weibo
        print('正在查询...')
        url3 = 'https://hmily.vip/api/phone/?phone=' + str(phone)
        html = requests.get(url3, headers, **('url', 'headers'))
        if html.json()['code'] == 1:
            qq = html.json()['qq']
            phonediqu = html.json()['phonediqu']
            weibo = html.json()['weibo']

    
    def wbMsg():
        global phone, phonediqu
        print('正在查询...')
        url3 = 'https://www.hmily.vip/api/wb/?id=' + str(weibo)
        html = requests.get(url3, headers, **('url', 'headers'))
        if html.json()['code'] == 1:
            phone = html.json()['phone']
            phonediqu = html.json()['phonediqu']

    layout = [
        [
            Sg.T('查询结果:')],
        [
            Sg.Multiline('查询需要时间,提交后请耐心等待结果\n', (70, 20), '-show-', True, **('size', 'key', 'autoscroll'))],
        [
            Sg.T('说明:请选择与输入号码相对应的查询方式', '-text-', 'white', **('key', 'text_color'))],
        [
            Sg.T('请输入查询号码'),
            Sg.In('-content-', **('key',))],
        [
            Sg.T('请选择查询方式')] + (lambda .0: [ Sg.Radio(i, 1, i, **('group_id', 'key')) for i in .0 ])(('qq号', '手机号', '微博UID')),
        [
            Sg.B('确认提交'),
            Sg.B('清空')]]
    window = Sg.Window('SE工具箱', layout)
    flag = Sg.popup_ok_cancel('免责声明:请勿把软件用在违法犯罪途径!\n造成的一切后果本作者概不负责\n如若同意请点击ok进入软件', '提示', ('黑体', 13), **('title', 'font'))
    if flag == 'Cancel':
        os._exit(0)
    (event, values) = window.read(300)
    if res2 == 3 or res1 == 3:
        res = Reg.CheckTimeTri()
        if res == 403:
            Sg.popup('软件使用时间已到期\n请重新购买登录码', '提示', ('黑体', 13), **('title', 'font'))
        
    if event == '确认提交' and values['-content-'] != '':
        phone = '没有查询到'
        phonediqu = '没有查询到'
        lolName = '没有查询到'
        lolDaqu = '没有查询到'
        qqlm = '没有查询到'
        weibo = '没有查询到'
        qq = '没有查询到'
        message = ''
        msg = ''
        t = time.strftime('%Y/%m/%d %H:%M:%S', time.localtime())
        if values['qq号']:
            qq = values['-content-']
            message = window['-show-'].get()
            window['-show-'].update('')
            t1 = threading.Thread(qqMsg, **('target',))
            t1.start()
            t1.join()
            if phone == '没有查询到':
                msg = f'''\n时间: {t}\nQQ号码: {qq}\n未查到任何信息!     \n'''
            else:
                msg = f'''\n查询成功!\n时间: {t}\nQQ号码: {qq}\n手机号码: {phone}\n地区: {phonediqu}\nLOL账号: {lolName}\nLOL大区: {lolDaqu}\nQQ密码: {qqlm}\n    '''
        elif values['手机号']:
            phone = values['-content-']
            message = window['-show-'].get()
            window['-show-'].update('')
            t2 = threading.Thread(phoneMsg, **('target',))
            t2.start()
            t2.join()
            if qq == '没有查询到':
                msg = f'''\n时间: {t}\n手机号码: {phone}\n未查到任何信息!     \n'''
            else:
                msg = f'''\n查询成功!\n时间: {t}\n手机号码: {phone}\n地区: {phonediqu}\nQQ账号: {qq}\n微博ID: {weibo}\n'''
        elif values['微博UID']:
            weibo = values['-content-']
            message = window['-show-'].get()
            window['-show-'].update('')
            wbMsg()
            if phone == '没有查询到':
                msg = f'''\n时间: {t}\n微博ID: {weibo}\n未查到任何信息!     \n'''
            else:
                msg = f'''\n查询成功!\n时间: {t}\n微博ID: {weibo}\n手机号码: {phone}\n地区: {phonediqu}\n'''
        else:
            window['-show-'].update('请选择一个查询方式,点击提交后请耐心等待查询结果')
        window['-show-'].update(message + '\n' + msg)
        window['-content-'].update('')
    if event == '清空':
        window['-show-'].update('')
    if event is None:
        pass
    
    window.close()

Reg = Register(TYPE)
res1 = Reg.Regist_New()
deadline = ''
res2 = ''
if res1 in (1, 2, 3):
    SeTool()
elif res1 == 4:
    Sg.popup('登陆码验证失败 请重新输入', '提示', ('黑体', 13), **('title', 'font'))
if res1 == 5:
    Sg.popup('请勿非法获得验证文件!', '提示', ('黑体', 13), **('title', 'font'))
entryCode = Reg.encryCode()
layout = [
    [
        Sg.Text('输入你的登录码后进入软件', ('黑体', 13), **('font',))],
    [
        Sg.Text('机器码:', True, (7, 1), ('黑体', 12), **('enable_events', 'size', 'font')),
        Sg.InputText(entryCode, '-serial-', **('key',))],
    [
        Sg.Text('登录码:', (7, 1), ('黑体', 12), **('size', 'font')),
        Sg.InputText('', '-key-', **('key',))],
    [
        Sg.Button('确认', ('微软雅黑', 9), **('font',)),
        Sg.Button('退出', ('微软雅黑', 9), **('font',)),
        Sg.Text('点我购买登录码', ((200, 10), (0, 0)), True, '#fff200', **('pad', 'enable_events', 'text_color'))]]
window1 = Sg.Window('SE工具箱', layout)
(event, values) = window1.read()
if event == None:
    pass
elif event == '确认' and values['-key-'] != '':
    res2 = Reg.checKey()
    if res2 == 1:
        Sg.popup('登录成功!', ('黑体', 12), **('font',))
        window1.close()
        SeTool()
    elif res2 == 3:
        timeArry = time.localtime(Reg.deadline / 1000)
        Sg.popup(f'''登录成功!到期时间\n{time.strftime('%Y/%m/%d %H:%M:%S', timeArry)}''', ('黑体', 13), **('font',))
        window1.close()
        SeTool()
    elif res2 == 5:
        Sg.popup('登陆码验证失败 请重新输入', '提示', ('黑体', 12), **('title', 'font'))
if event == '退出':
    pass
elif event == '点我购买登录码':
    Sg.popup('购买登录码20R\n联系QQ:2900548175\n微信号:tangmin903', '提示', ('黑体', 12), **('title', 'font'))
    continue
    window1.close()
    return None

结果

然后翻阅源码发现如下几个接口:

THE END