文章摘要
微软上周发布了一个非常重要的 Defender 更新,适用于 Win10(KB5063709 / KB5063877 / KB5063871 / KB5063889)和 Win11(KB5063878、KB5063875)。 X 用户 @Necoru_cat 发现,KB5063878 在特定情况下可能导致固态硬盘(SSD)和机械硬盘(HDD)出现严重故障,部分设备在大容量数据写入后无法被系统识别。损坏硬盘。
特定做了这个工具
下面是python源代码
import sys
import subprocess
import platform
import winreg
import tkinter as tk
from PyQt5.QtWidgets import (
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QListWidget, QPushButton, QLabel, QTextBrowser, QCheckBox,
QProgressBar, QGroupBox, QMessageBox
)
from PyQt5.QtCore import QThread, pyqtSignal
class PatchUninstaller(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Windows 问题补丁卸载工具 by吾爱破解")
self.setGeometry(300, 300, 800, 600)
# 定义问题补丁列表
self.win10_patches = ["KB5063709", "KB5063877", "KB5063871", "KB5063889"]
self.win11_patches = ["KB5063878", "KB5063875"]
self.init_ui()
self.detect_os_and_patches()
def init_ui(self):
# 主组件
main_widget = QWidget()
main_layout = QVBoxLayout()
# 操作系统信息
self.os_label = QLabel()
self.os_label.setStyleSheet("font-weight: bold; font-size: 14px; color: #2c3e50;")
main_layout.addWidget(self.os_label)
# 补丁检测区域
patch_group = QGroupBox("检测到的问题补丁")
patch_layout = QVBoxLayout()
self.patch_list = QListWidget()
self.patch_list.setSelectionMode(QListWidget.MultiSelection)
patch_layout.addWidget(self.patch_list)
# 操作选项
self.block_reinstall = QCheckBox("卸载后阻止系统重新安装这些补丁")
self.block_reinstall.setChecked(True)
patch_layout.addWidget(self.block_reinstall)
# 进度条
self.progress = QProgressBar()
self.progress.setVisible(False)
patch_layout.addWidget(self.progress)
# 按钮区域
button_layout = QHBoxLayout()
self.select_all_btn = QPushButton("全选")
self.select_all_btn.setStyleSheet("background-color: #3498db; color: white;")
self.select_all_btn.clicked.connect(self.select_all)
self.rescan_btn = QPushButton("重新检测")
self.rescan_btn.setStyleSheet("background-color: #2ecc71; color: white;")
self.rescan_btn.clicked.connect(self.detect_os_and_patches)
self.uninstall_btn = QPushButton("卸载选中补丁")
self.uninstall_btn.setStyleSheet("background-color: #e74c3c; color: white;")
self.uninstall_btn.clicked.connect(self.start_uninstall)
button_layout.addWidget(self.select_all_btn)
button_layout.addWidget(self.rescan_btn)
button_layout.addWidget(self.uninstall_btn)
button_layout.addStretch()
patch_layout.addLayout(button_layout)
patch_group.setLayout(patch_layout)
main_layout.addWidget(patch_group)
# 日志区域
log_group = QGroupBox("操作日志")
log_layout = QVBoxLayout()
self.log_browser = QTextBrowser()
self.log_browser.setStyleSheet("""
background-color: #f8f9fa;
border: 1px solid #ddd;
border-radius: 4px;
padding: 10px;
font-family: Consolas, monospace;
""")
log_layout.addWidget(self.log_browser)
log_group.setLayout(log_layout)
main_layout.addWidget(log_group)
main_widget.setLayout(main_layout)
self.setCentralWidget(main_widget)
# 状态栏
self.statusBar().showMessage("就绪 - 请先检测系统补丁")
def detect_os_and_patches(self):
"""检测操作系统和已安装的问题补丁"""
self.log_browser.clear()
self.log_browser.append("正在检测操作系统版本...")
try:
# 获取Windows版本信息
with winreg.OpenKey(
winreg.HKEY_LOCAL_MACHINE,
r"SOFTWARE\Microsoft\Windows NT\CurrentVersion"
) as key:
product_name = winreg.QueryValueEx(key, "ProductName")
current_build = winreg.QueryValueEx(key, "CurrentBuild")
# 确定操作系统类型
if "Windows 10" in product_name:
os_type = "Windows 10"
patch_list = self.win10_patches
elif "Windows 11" in product_name:
os_type = "Windows 11"
patch_list = self.win11_patches
else:
os_type = f"检测到: {product_name} (仅支持Win10/11)"
patch_list = []
self.os_label.setText(f"操作系统: {os_type} (Build {current_build})")
self.log_browser.append(f">> 系统检测完成: {product_name} (Build {current_build})")
except Exception as e:
self.os_label.setText("操作系统: 检测失败")
self.log_browser.append(f">> 系统检测失败: {str(e)}")
self.statusBar().showMessage("操作系统检测失败")
return
# 检测问题补丁
self.log_browser.append("\n正在扫描已安装补丁...")
self.patch_list.clear()
found_patches = []
if patch_list:
for patch in patch_list:
self.log_browser.append(f"检查补丁: {patch}...")
try:
# 使用WMIC检查补丁安装状态
result = subprocess.run(
["wmic", "qfe", "list", "brief"],
capture_output=True,
text=True,
creationflags=subprocess.CREATE_NO_WINDOW
)
if patch in result.stdout:
found_patches.append(patch)
self.log_browser.append(f" [已安装] {patch}")
else:
self.log_browser.append(f" [未安装] {patch}")
except Exception as e:
self.log_browser.append(f" [检测失败] {patch}: {str(e)}")
# 显示检测结果
if found_patches:
self.patch_list.addItems(found_patches)
for i in range(self.patch_list.count()):
self.patch_list.item(i).setSelected(True)
self.statusBar().showMessage(f"发现 {len(found_patches)} 个问题补丁")
else:
self.log_browser.append("\n>> 未检测到问题补丁")
self.statusBar().showMessage("未检测到问题补丁")
def select_all(self):
"""选择/取消所有补丁"""
if self.patch_list.count() > 0:
for i in range(self.patch_list.count()):
self.patch_list.item(i).setSelected(True)
self.log_browser.append("\n>> 已选中所有补丁")
def start_uninstall(self):
"""启动卸载线程"""
selected_items = self.patch_list.selectedItems()
if not selected_items:
QMessageBox.warning(self, "警告", "请选择要卸载的补丁!")
return
patches = [item.text() for item in selected_items]
block_reinstall = self.block_reinstall.isChecked()
reply = QMessageBox.question(
self,
"确认操作",
f"确定要卸载 {len(patches)} 个补丁吗?\n此操作可能需要几分钟时间,完成后建议重启系统。",
QMessageBox.Yes | QMessageBox.No
)
if reply == QMessageBox.Yes:
self.progress.setVisible(True)
self.progress.setRange(0, len(patches))
self.uninstall_btn.setEnabled(False)
self.patch_list.setEnabled(False)
# 启动卸载线程
self.worker = UninstallWorker(patches, block_reinstall)
self.worker.progress_signal.connect(self.update_progress)
self.worker.log_signal.connect(self.log_browser.append)
self.worker.finished.connect(self.uninstall_finished)
self.worker.start()
def update_progress(self, value):
"""更新进度条"""
self.progress.setValue(value)
def uninstall_finished(self):
"""卸载完成处理"""
self.progress.setVisible(False)
self.uninstall_btn.setEnabled(True)
self.patch_list.setEnabled(True)
self.log_browser.append("\n>> 操作已完成! 建议重启系统使更改生效")
self.statusBar().showMessage("操作完成 - 请查看日志")
# 显示完成通知
QMessageBox.information(
self,
"完成",
"卸载操作已完成!\n请在操作日志中查看详细结果。\n\n建议重启系统使更改生效。"
)
class UninstallWorker(QThread):
"""执行卸载操作的线程"""
progress_signal = pyqtSignal(int)
log_signal = pyqtSignal(str)
finished = pyqtSignal()
def __init__(self, patches, block_reinstall):
super().__init__()
self.patches = patches
self.block_reinstall = block_reinstall
def run(self):
"""执行卸载操作"""
self.log_signal.emit("\n===== 开始卸载操作 =====")
# 卸载每个选中的补丁
for i, patch in enumerate(self.patches):
self.log_signal.emit(f"\n卸载补丁 {patch}...")
self.progress_signal.emit(i+1)
try:
# 执行卸载命令
result = subprocess.run(
["wusa", "/uninstall", f"/kb:{patch[2:]}", "/quiet", "/norestart"],
capture_output=True,
text=True,
creationflags=subprocess.CREATE_NO_WINDOW,
timeout=300 # 5分钟超时
)
if result.returncode == 0:
self.log_signal.emit(f" [成功] {patch} 已卸载")
# 应用重装阻止
if self.block_reinstall:
self.block_patch_reinstall(patch)
else:
error_msg = result.stderr.strip() or "未知错误"
self.log_signal.emit(f" [失败] 错误代码: {result.returncode}")
self.log_signal.emit(f" 错误信息: {error_msg}")
except subprocess.TimeoutExpired:
self.log_signal.emit(f" [超时] 卸载 {patch} 操作超时")
except Exception as e:
self.log_signal.emit(f" [异常] 卸载失败: {str(e)}")
self.log_signal.emit("\n===== 所有操作已完成 =====")
self.finished.emit()
def block_patch_reinstall(self, patch):
"""阻止补丁重新安装(通过注册表)"""
reg_path = r"SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate"
value_name = f"BlockKB{patch}"
try:
with winreg.CreateKey(winreg.HKEY_LOCAL_MACHINE, reg_path) as key:
winreg.SetValueEx(key, value_name, 0, winreg.REG_DWORD, 1)
self.log_signal.emit(f" [已阻止] 补丁 {patch} 将被禁止重新安装")
except Exception as e:
self.log_signal.emit(f" [警告] 阻止重安装失败: {str(e)}")
if __name__ == "__main__":
# 检查管理员权限
if platform.system() == "Windows":
import ctypes
if ctypes.windll.shell32.IsUserAnAdmin() == 0:
ctypes.windll.shell32.ShellExecuteW(
None, "runas", sys.executable, " ".join(sys.argv), None, 1
)
sys.exit()
app = QApplication(sys.argv)
app.setStyle("Fusion")
window = PatchUninstaller()
window.show()
sys.exit(app.exec_())
