#!/usr/bin/env python3 """ Bandizip Professional Patcher ============================= 一键补丁器:备份、patch、验证、恢复。 Patch 内容(共 8 处,35 字节): 1. sub_1400D18F0 @ 0xD0CF0 -> B0 01 C3 (mov al,1; ret) 在线验证跳过 2. sub_1400CF980 @ 0xCED80 -> B0 01 C3 (mov al,1; ret) 写注册表跳过 3. sub_1400CF470 @ 0xCE870 -> B0 01 C3 (mov al,1; ret) Edition 检查返回 true 4. sub_140133648 @ 0x132A48 -> 90*6 (NOP) 注册码长度检查跳过 5. sub_140133655 @ 0x132A55 -> 90*6 (NOP) 数据有效性检查跳过 6. sub_14013366A @ 0x132A6A -> 90*6 (NOP) @ 符号检查跳过 7. sub_140133678 @ 0x132A78 -> 90*6 (NOP) @ 位置检查跳过 8. sub_14013180B @ 0x130C0B -> D4 03 00 00 版本号 Standard->Professional 使用方法: python bandizip_patcher.py # 交互模式 python bandizip_patcher.py patch # 直接 patch python bandizip_patcher.py restore # 恢复原始 python bandizip_patcher.py status # 检查状态 """ import os import sys import shutil import winreg # ============ 配置 ============ BANDIZIP_DIR = r'D:\Apps\Bandizip' EXE_PATH = os.path.join(BANDIZIP_DIR, 'Bandizip.exe') BACKUP_PATH = EXE_PATH + '.bak' REG_KEY = r'SOFTWARE\Bandizip' REG_VALUE = 'Edition' REG_DATA = 'PRO' # Patch 定义: (文件偏移, 原始字节, 补丁字节, 描述) PATCHES = [ (0xD0CF0, b'\x48\x89\x5C\x24\x08\x55', b'\xB0\x01\xC3', 'sub_1400D18F0 (online verify -> return 1)'), (0xCED80, b'\x48\x89\x5C\x24\x18\x55', b'\xB0\x01\xC3', 'sub_1400CF980 (registry write -> return 1)'), (0xCE870, b'\x4C\x8B\xDC\x49\x89\x5B', b'\xB0\x01\xC3', 'sub_1400CF470 (Edition check -> return 1)'), (0x132A48, b'\x0F\x85\x4B\x06\x00\x00', b'\x90\x90\x90\x90\x90\x90', 'NOP: register code length check'), (0x132A55, b'\x0F\x8C\x3E\x06\x00\x00', b'\x90\x90\x90\x90\x90\x90', 'NOP: data validity check'), (0x132A6A, b'\x0F\x84\x29\x06\x00\x00', b'\x90\x90\x90\x90\x90\x90', 'NOP: @ symbol check'), (0x132A78, b'\x0F\x8E\x1B\x06\x00\x00', b'\x90\x90\x90\x90\x90\x90', 'NOP: @ position check'), (0x130C0B, b'\x98\x00\x00\x00', b'\xD4\x03\x00\x00', 'Version: Standard(0x98) -> Professional(0x3D4)'), ] def is_patched(): """检查是否已 patch""" if not os.path.exists(EXE_PATH): return False with open(EXE_PATH, 'rb') as f: for offset, orig, patch, desc in PATCHES: f.seek(offset) current = f.read(len(patch)) if current != patch: return False return True def is_backup_exists(): """检查备份是否存在""" return os.path.exists(BACKUP_PATH) def is_bandizip_running(): """检查 Bandizip 是否正在运行""" try: import subprocess result = subprocess.run(['tasklist', '/FI', 'IMAGENAME eq Bandizip.exe'], capture_output=True, text=True, timeout=5) return 'Bandizip.exe' in result.stdout except Exception: return False def kill_bandizip(): """关闭 Bandizip 进程""" try: import subprocess subprocess.run(['taskkill', '/F', '/IM', 'Bandizip.exe'], capture_output=True, timeout=5) import time time.sleep(2) return True except Exception: return False def backup(): """备份原始文件""" if is_backup_exists(): print(' [OK] Backup already exists: ' + BACKUP_PATH) return True try: shutil.copy2(EXE_PATH, BACKUP_PATH) print(' [OK] Backup created: ' + BACKUP_PATH) return True except PermissionError: print(' [!] Permission denied. Run as Administrator.') return False except Exception as e: print(' [!] Backup failed: ' + str(e)) return False def apply_patches(): """应用所有 patch""" try: with open(EXE_PATH, 'r+b') as f: for offset, orig, patch, desc in PATCHES: f.seek(offset) current = f.read(len(patch)) if current == patch: print(' [SKIP] Already patched: ' + desc) continue f.seek(offset) f.write(patch) print(' [OK] ' + desc) return True except PermissionError: print(' [!] Permission denied. Close Bandizip and run as Administrator.') return False except Exception as e: print(' [!] Patch failed: ' + str(e)) return False def restore(): """恢复原始文件""" if not is_backup_exists(): print(' [!] No backup found: ' + BACKUP_PATH) return False try: shutil.copy2(BACKUP_PATH, EXE_PATH) print(' [OK] Restored from backup: ' + EXE_PATH) return True except PermissionError: print(' [!] Permission denied. Close Bandizip and run as Administrator.') return False except Exception as e: print(' [!] Restore failed: ' + str(e)) return False def set_registry(): """设置注册表 Edition = PRO""" try: with winreg.CreateKeyEx(winreg.HKEY_LOCAL_MACHINE, REG_KEY, 0, winreg.KEY_SET_VALUE) as key: winreg.SetValueEx(key, REG_VALUE, 0, winreg.REG_SZ, REG_DATA) print(' [OK] Registry: HKLM\\' + REG_KEY + '\\' + REG_VALUE + ' = ' + REG_DATA) return True except PermissionError: print(' [!] Registry write denied. Run as Administrator.') return False except Exception as e: print(' [!] Registry write failed: ' + str(e)) return False def check_status(): """检查当前状态""" print('=' * 50) print(' Bandizip Patcher - Status') print('=' * 50) # 文件存在 if os.path.exists(EXE_PATH): print(' [OK] Bandizip.exe found: ' + EXE_PATH) else: print(' [!] Bandizip.exe not found: ' + EXE_PATH) return # 备份状态 if is_backup_exists(): print(' [OK] Backup exists') else: print(' [!] No backup') # Patch 状态 patched_count = 0 total = len(PATCHES) if os.path.exists(EXE_PATH): with open(EXE_PATH, 'rb') as f: for offset, orig, patch, desc in PATCHES: f.seek(offset) current = f.read(len(patch)) if current == patch: patched_count += 1 status = '[PATCHED]' elif current == orig: status = '[ORIGINAL]' else: status = '[UNKNOWN]' print(' ' + status + ' 0x{:06X}: '.format(offset) + desc) print('') print(' Patched: ' + str(patched_count) + '/' + str(total)) # 注册表状态 try: with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, REG_KEY) as key: val, _ = winreg.QueryValueEx(key, REG_VALUE) print(' [Registry] Edition = ' + val) except Exception: print(' [Registry] Edition not set') # 进程状态 if is_bandizip_running(): print(' [WARNING] Bandizip is running! Close it before patching.') else: print(' [OK] Bandizip is not running') print('=' * 50) def do_patch(): """执行完整 patch 流程""" print('=' * 50) print(' Bandizip Patcher - Apply') print('=' * 50) if not os.path.exists(EXE_PATH): print(' [!] Bandizip.exe not found: ' + EXE_PATH) return False if is_bandizip_running(): print(' [..] Bandizip is running, closing...') if not kill_bandizip(): print(' [!] Cannot close Bandizip. Close it manually.') return False print('\n [1/3] Backup...') if not backup(): return False print('\n [2/3] Patching...') if not apply_patches(): return False print('\n [3/3] Registry...') set_registry() print('\n' + '=' * 50) print(' [DONE] All patches applied successfully!') print(' Use keygen to generate a product key.') print('=' * 50) return True def do_restore(): """执行恢复流程""" print('=' * 50) print(' Bandizip Patcher - Restore') print('=' * 50) if is_bandizip_running(): print(' [..] Bandizip is running, closing...') if not kill_bandizip(): print(' [!] Cannot close Bandizip. Close it manually.') return False print('\n [1/1] Restoring...') if restore(): print('\n' + '=' * 50) print(' [DONE] Restored to original.') print('=' * 50) return True return False def main(): print('=' * 50) print(' Bandizip Professional Patcher v1.0') print('=' * 50) print('') if len(sys.argv) > 1: cmd = sys.argv[1].lower() if cmd == 'patch': do_patch() return elif cmd == 'restore': do_restore() return elif cmd == 'status': check_status() return else: print(' Usage: python bandizip_patcher.py [patch|restore|status]') return # 交互模式 print(' Commands:') print(' 1. Patch - Apply all patches') print(' 2. Restore - Restore original file') print(' 3. Status - Check current status') print(' 4. Exit') print('') try: choice = input(' Select [1-4]: ').strip() except EOFError: choice = '1' if choice == '1': do_patch() elif choice == '2': do_restore() elif choice == '3': check_status() else: print(' Bye!') if __name__ == '__main__': main()