UPX5.0界面化一键加壳/脱壳工具

查看 95|回复 9
作者:killerzeno   
UPX5.0界面化一键加壳/脱壳工具
打包时需要有upx.exe,我放附件里。


image.png (76.97 KB, 下载次数: 0)
下载附件
2025-4-22 15:47 上传


upx.zip
(575.04 KB, 下载次数: 348)
2025-4-22 15:46 上传
点击文件名下载附件
下载积分: 吾爱币 -1 CB

[Python] 纯文本查看 复制代码import os
import shutil
import subprocess
import sys
import time
from PyQt5.QtWidgets import (QApplication, QWidget, QVBoxLayout, QHBoxLayout, QLabel,
                             QLineEdit, QPushButton, QComboBox, QCheckBox, QMessageBox,
                             QProgressBar, QFileDialog, QFrame)
from PyQt5.QtGui import QFont, QIcon, QPalette, QColor
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QSize, QMimeData
def resource_path(relative_path):
    """
    获取资源文件的绝对路径,无论是在开发环境还是打包后的环境中。
    """
    try:
        # PyInstaller 创建的临时文件夹路径
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)
class WorkerThread(QThread):
    progress_signal = pyqtSignal(int)
    finished_signal = pyqtSignal()
    error_signal = pyqtSignal(str)
    def __init__(self, command):
        super().__init__()
        self.command = command
    def run(self):
        try:
            # 隐藏子进程窗口
            startupinfo = None
            if os.name == 'nt':
                startupinfo = subprocess.STARTUPINFO()
                startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
            process = subprocess.Popen(
                self.command,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                startupinfo=startupinfo
            )
            start_time = time.time()
            total_time_estimate = 10  # 估计的总时间,单位为秒
            while True:
                if process.poll() is not None:
                    break
                elapsed_time = time.time() - start_time
                progress = int((elapsed_time / total_time_estimate) * 100)
                if progress > 100:
                    progress = 100
                self.progress_signal.emit(progress)
                time.sleep(0.1)
            self.finished_signal.emit()
        except Exception as e:
            self.error_signal.emit(str(e))
class UPXTool(QWidget):
    def __init__(self):
        super().__init__()
        self.setup_style()
        self.initUI()
        # 动态获取upx.exe路径
        self.upx_path = self.get_upx_path()
        self.file_path = ""
        self.compression_level = "-9"
        self.create_backup = False
        self.worker = None
        # 启用拖拽功能
        self.setAcceptDrops(True)
    def get_upx_path(self):
        """动态获取upx.exe路径,处理打包后和开发环境两种情况"""
        try:
            # 如果是打包后的环境
            if getattr(sys, 'frozen', False):
                # 获取打包后的可执行文件所在目录
                base_path = os.path.dirname(sys.executable)
                upx_path = os.path.join(base_path, 'upx.exe')
            else:
                # 开发环境,使用脚本所在目录
                base_path = os.path.dirname(os.path.abspath(__file__))
                upx_path = os.path.join(base_path, 'upx.exe')
            # 检查文件是否存在
            if not os.path.exists(upx_path):
                # 尝试在系统PATH中查找
                which_upx = shutil.which('upx')
                if which_upx:
                    return which_upx
                raise FileNotFoundError("无法找到upx.exe")
            return upx_path
        except Exception as e:
            QMessageBox.critical(self, "错误", f"初始化失败: {str(e)}")
            return "upx.exe"  # 最后尝试直接使用系统PATH中的upx
    def setup_style(self):
        # 设置应用程序的全局样式
        self.setStyleSheet("""
            QWidget {
                background-color: #f5f5f5;
                color: #333333;
            }
            QLineEdit {
                border: 2px solid #cccccc;
                border-radius: 5px;
                padding: 10px;
                font-size: 14px;
                background-color: white;
                min-height: 20px;
            }
            QLineEdit:focus {
                border: 2px solid #4CAF50;
            }
            QPushButton {
                border: none;
                border-radius: 5px;
                padding: 12px 24px;
                font-size: 14px;
                font-weight: bold;
                color: white;
                min-width: 120px;
                min-height: 30px;
            }
            QPushButton:hover {
                opacity: 0.9;
            }
            QPushButton:pressed {
                padding: 12px 24px;
            }
            QComboBox {
                border: 2px solid #cccccc;
                border-radius: 5px;
                padding: 10px;
                font-size: 14px;
                background-color: white;
                min-height: 20px;
            }
            QComboBox:focus {
                border: 2px solid #4CAF50;
            }
            QCheckBox {
                font-size: 14px;
                spacing: 8px;
                min-height: 20px;
            }
            QCheckBox::indicator {
                width: 20px;
                height: 20px;
            }
            QProgressBar {
                border: 2px solid #cccccc;
                border-radius: 5px;
                text-align: center;
                font-size: 14px;
                height: 30px;
            }
            QProgressBar::chunk {
                background-color: #4CAF50;
                border-radius: 3px;
            }
            QLabel {
                font-size: 14px;
            }
            .TitleLabel {
                font-size: 28px;
                font-weight: bold;
                color: #333333;
                padding: 10px 0;
            }
            .SectionFrame {
                border-radius: 8px;
                background-color: white;
                border: 1px solid #e0e0e0;
                padding: 5px;
            }
            /* 拖拽文件时的样式 */
            QLineEdit[fileDrag="true"] {
                border: 2px dashed #4CAF50;
                background-color: #f0fff0;
            }
        """)
    def initUI(self):
        self.setWindowTitle("UPX5.0 - 加壳/脱壳工具 By:Killerzeno")
        self.setWindowIcon(QIcon(resource_path("logo.ico")))  # 使用 resource_path 处理图标路径
        # 设置窗口大小并禁止最大化
        self.setFixedSize(800, 600)  # 增大窗口尺寸
        # 主布局
        main_layout = QVBoxLayout()
        main_layout.setContentsMargins(30, 20, 30, 20)  # 增加边距
        main_layout.setSpacing(25)  # 增加控件间距
        # 标题 - 增大字体
        title_label = QLabel("UPX5.0 - 加壳/脱壳工具")
        title_label.setObjectName("TitleLabel")
        title_label.setAlignment(Qt.AlignCenter)
        title_label.setStyleSheet("""
            QLabel {
                font-size: 28px;
                font-weight: bold;
                color: #333333;
                padding: 10px 0;
            }
        """)
        main_layout.addWidget(title_label)
        # 文件选择部分
        file_frame = QFrame()
        file_frame.setObjectName("SectionFrame")
        file_layout = QVBoxLayout(file_frame)
        file_layout.setContentsMargins(20, 20, 20, 20)  # 增加内边距
        file_layout.setSpacing(15)
        file_label = QLabel("选择要处理的文件 (或直接拖拽文件到此处):")
        file_label.setStyleSheet("font-weight: bold; font-size: 15px;")
        file_input_layout = QHBoxLayout()
        self.file_entry = QLineEdit()
        self.file_entry.setPlaceholderText("点击浏览选择文件或拖拽文件到这里...")
        self.file_entry.setProperty("fileDrag", "false")  # 初始化拖拽状态属性
        file_button = QPushButton("浏览")
        file_button.setStyleSheet("""
            background-color: #2196F3;
            font-size: 14px;
            min-width: 100px;
        """)
        file_button.setIcon(QIcon.fromTheme("document-open"))
        file_button.setIconSize(QSize(18, 18))  # 增大图标
        file_button.clicked.connect(self.browse_file)
        file_input_layout.addWidget(self.file_entry, stretch=5)
        file_input_layout.addWidget(file_button, stretch=1)
        file_input_layout.setSpacing(15)
        file_layout.addWidget(file_label)
        file_layout.addLayout(file_input_layout)
        main_layout.addWidget(file_frame)
        # 设置部分
        settings_frame = QFrame()
        settings_frame.setObjectName("SectionFrame")
        settings_layout = QVBoxLayout(settings_frame)
        settings_layout.setContentsMargins(20, 20, 20, 20)
        settings_layout.setSpacing(20)
        # 压缩级别
        level_layout = QHBoxLayout()
        level_label = QLabel("压缩级别:")
        level_label.setStyleSheet("font-weight: bold; font-size: 15px;")
        self.level_combobox = QComboBox()
        self.level_combobox.addItems([f"级别 {i} " for i in range(1, 10)])
        self.level_combobox.setCurrentIndex(8)  # 默认选择级别9
        self.level_combobox.setStyleSheet("font-size: 14px; min-height: 30px;")
        level_layout.addWidget(level_label)
        level_layout.addWidget(self.level_combobox, stretch=1)
        level_layout.addStretch()
        # 备份选项
        self.backup_checkbox = QCheckBox("创建备份文件 (.bak)")
        self.backup_checkbox.setChecked(True)
        self.backup_checkbox.setStyleSheet("font-size: 14px;")
        settings_layout.addLayout(level_layout)
        settings_layout.addWidget(self.backup_checkbox)
        main_layout.addWidget(settings_frame)
        # 操作按钮 - 增大按钮尺寸
        button_layout = QHBoxLayout()
        button_layout.setSpacing(30)  # 增加按钮间距
        self.compress_button = QPushButton("加壳")
        self.compress_button.setStyleSheet("""
            background-color: #4CAF50;
            font-size: 16px;
            min-width: 150px;
            min-height: 40px;
        """)
        self.compress_button.setIcon(QIcon.fromTheme("document-edit"))
        self.compress_button.setIconSize(QSize(18, 18))
        self.compress_button.clicked.connect(self.compress)
        self.decompress_button = QPushButton("脱壳")
        self.decompress_button.setStyleSheet("""
            background-color: #FF5722;
            font-size: 16px;
            min-width: 150px;
            min-height: 40px;
        """)
        self.decompress_button.setIcon(QIcon.fromTheme("document-revert"))
        self.decompress_button.setIconSize(QSize(18, 18))
        self.decompress_button.clicked.connect(self.decompress)
        button_layout.addStretch()
        button_layout.addWidget(self.compress_button)
        button_layout.addWidget(self.decompress_button)
        button_layout.addStretch()
        main_layout.addLayout(button_layout)
        # 进度条 - 增大高度
        self.progress_bar = QProgressBar()
        self.progress_bar.setRange(0, 100)
        self.progress_bar.setTextVisible(True)
        self.progress_bar.setFormat("等待操作...")
        self.progress_bar.setStyleSheet("font-size: 14px;")
        main_layout.addWidget(self.progress_bar)
        # 状态栏 - 增大字体
        self.status_label = QLabel("就绪")
        self.status_label.setAlignment(Qt.AlignRight)
        self.status_label.setStyleSheet("""
            color: #666666;
            font-size: 13px;
            padding-top: 10px;
        """)
        main_layout.addWidget(self.status_label)
        self.setLayout(main_layout)
    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls():
            event.acceptProposedAction()
            self.file_entry.setProperty("fileDrag", "true")
            self.file_entry.style().polish(self.file_entry)  # 刷新样式
    def dragLeaveEvent(self, event):
        self.file_entry.setProperty("fileDrag", "false")
        self.file_entry.style().polish(self.file_entry)  # 刷新样式
    def dropEvent(self, event):
        self.file_entry.setProperty("fileDrag", "false")
        self.file_entry.style().polish(self.file_entry)  # 刷新样式
        if event.mimeData().hasUrls():
            urls = event.mimeData().urls()
            if urls:
                file_path = urls[0].toLocalFile()
                if os.path.isfile(file_path):
                    self.file_path = file_path
                    self.file_entry.setText(file_path)
                    self.status_label.setText(f"已选择文件: {os.path.basename(file_path)}")
                else:
                    QMessageBox.warning(self, "警告", "请拖拽有效的文件")
    def browse_file(self):
        path, _ = QFileDialog.getOpenFileName(
            self,
            "选择文件",
            "",
            "可执行文件 (*.exe);;所有文件 (*)"
        )
        if path:
            self.file_path = path
            self.file_entry.setText(path)
            self.status_label.setText(f"已选择文件: {os.path.basename(path)}")
    def compress(self):
        file_path = self.file_path
        level = f"-{self.level_combobox.currentIndex() + 1}"  # 从1-9转换为-1到-9
        if not self.validate_inputs():
            return
        self.create_backup = self.backup_checkbox.isChecked()
        if self.create_backup:
            if not self.create_backup_file(file_path):
                return
        command = [self.upx_path, level, file_path]
        self.start_worker(command, "加壳")
    def decompress(self):
        file_path = self.file_path
        if not self.validate_inputs():
            return
        self.create_backup = self.backup_checkbox.isChecked()
        if self.create_backup:
            if not self.create_backup_file(file_path):
                return
        command = [self.upx_path, "-d", file_path]
        self.start_worker(command, "脱壳")
    def validate_inputs(self):
        if not os.path.exists(self.upx_path):
            QMessageBox.critical(
                self,
                "错误",
                f"未找到UPX可执行文件,请确保upx.exe与程序在同一目录下\n当前路径: {self.upx_path}"
            )
            return False
        if not os.path.exists(self.file_path):
            QMessageBox.critical(
                self,
                "错误",
                "请先选择有效的文件路径"
            )
            return False
        return True
    def create_backup_file(self, file_path):
        backup_path = file_path + ".bak"
        try:
            shutil.copy2(file_path, backup_path)
            self.status_label.setText(f"已创建备份文件: {os.path.basename(backup_path)}")
            return True
        except Exception as e:
            QMessageBox.critical(
                self,
                "备份失败",
                f"无法创建备份文件: {str(e)}"
            )
            return False
    def start_worker(self, command, operation_name):
        self.worker = WorkerThread(command)
        self.worker.progress_signal.connect(self.update_progress)
        self.worker.finished_signal.connect(lambda: self.on_finished(operation_name))
        self.worker.error_signal.connect(self.on_error)
        self.compress_button.setEnabled(False)
        self.decompress_button.setEnabled(False)
        self.file_entry.setEnabled(False)
        self.progress_bar.setFormat(f"{operation_name}中... %p%")
        self.status_label.setText(f"{operation_name}文件...")
        self.worker.start()
    def update_progress(self, value):
        self.progress_bar.setValue(value)
    def on_finished(self, operation_name):
        self.progress_bar.setValue(100)
        self.progress_bar.setFormat("操作完成")
        # 创建自定义的消息框
        msg = QMessageBox()
        msg.setIcon(QMessageBox.Information)
        msg.setWindowTitle("成功")
        msg.setText(f"{operation_name}操作已完成!")
        msg.setStyleSheet("""
            QMessageBox {
                background-color: #f5f5f5;
                font-size: 14px;
            }
            QMessageBox QLabel {
                color: #333333;
                font-size: 15px;
            }
            QMessageBox QPushButton {
                color: #333333;
                background-color: #e0e0e0;
                border: 1px solid #cccccc;
                padding: 8px 20px;
                border-radius: 4px;
                font-size: 14px;
                min-width: 80px;
            }
            QMessageBox QPushButton:hover {
                background-color: #d0d0d0;
            }
        """)
        msg.exec_()
        self.reset_ui()
        self.status_label.setText(f"{operation_name}完成 - {os.path.basename(self.file_path)}")
    def on_error(self, error):
        self.progress_bar.setFormat("操作失败")
        QMessageBox.critical(
            self,
            "错误",
            f"操作失败: {error}"
        )
        self.reset_ui()
        self.status_label.setText(f"错误: {error}")
    def reset_ui(self):
        self.compress_button.setEnabled(True)
        self.decompress_button.setEnabled(True)
        self.file_entry.setEnabled(True)
if __name__ == "__main__":
    app = QApplication(sys.argv)
    # 设置应用程序字体
    font = QFont()
    font.setFamily("Microsoft YaHei" if sys.platform == "win32" else "Noto Sans")
    font.setPointSize(10)
    app.setFont(font)
    # 创建并显示主窗口
    ex = UPXTool()
    ex.show()
    sys.exit(app.exec_())

文件, 脱壳

wn0071   

支持一下
byh3025   

谢谢发布原创作品
berylsun   

加了壳后就必须用这个工具才能脱壳的吗?
ZX0228   

win10  神州网信版,闪退
ie15   

十分感谢,下载来试试效果
Sandyang   

界面不错,先收藏,说不定那天就用得上,加壳就行了,脱就没什么必要了.
lazhou   

下载学习,谢谢!
Patches   

upx.exe是脱壳工具吧
kenxy   

没有出错提示和成不成功的判断
您需要登录后才可以回帖 登录 | 立即注册

返回顶部