Windows平台下Python便携USB程序的专属U盘绑定安全功能实现方案问询
Got it, let's walk through exactly how to build this USB-locked Python executable for Windows—matching the behavior of that education software you described, where cloning the USB's image lets the program work, but copying files alone doesn't.
The key here is tying your program to the Volume Serial Number of the original USB drive. This is a unique number generated when the drive is formatted, and it gets copied over when you create an image of the drive. Unlike USB device hardware IDs (which are unique to the physical USB stick), the volume serial number stays intact in clones—so your program will recognize the cloned drive as valid, just like the original.
1. Get the USB Drive's Volume Serial Number
We'll use Windows API calls via ctypes (no extra libraries needed) to fetch the serial number of the drive where your program lives. Here's the code:
import os import sys import ctypes from ctypes import wintypes def get_volume_serial_number(drive): # Drive should be formatted like "C:\\" kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) GetVolumeInformationW = kernel32.GetVolumeInformationW GetVolumeInformationW.argtypes = [ wintypes.LPCWSTR, # Root path of the drive wintypes.LPWSTR, # Buffer for volume name (unused here) wintypes.DWORD, # Size of volume name buffer wintypes.LPDWORD, # Pointer to store serial number wintypes.LPDWORD, # Pointer for max component length (unused) wintypes.LPDWORD, # Pointer for file system flags (unused) wintypes.LPWSTR, # Buffer for file system name (unused) wintypes.DWORD # Size of file system name buffer ] GetVolumeInformationW.restype = wintypes.BOOL serial_number = wintypes.DWORD() # Call the API, ignoring unused parameters success = GetVolumeInformationW( drive, None, 0, ctypes.byref(serial_number), None, None, None, 0 ) if not success: raise ctypes.WinError(ctypes.get_last_error()) return serial_number.value
2. Add Locking Logic
Next, we'll add logic to:
- On first run: Save the drive's serial number to a hidden system file on the USB
- On subsequent runs: Compare the current drive's serial number to the saved one. If they don't match, show an error and exit.
We'll also encrypt the saved serial number to prevent users from tampering with it:
import hashlib def encrypt_serial(serial, secret_key="your_unique_secret_key"): # Simple hash-based encryption (replace the key with your own!) combined = str(serial) + secret_key return hashlib.sha256(combined.encode()).hexdigest() def main(): # Get the drive where the program is located program_path = os.path.abspath(sys.executable if hasattr(sys, 'frozen') else __file__) drive_letter = os.path.splitdrive(program_path)[0] + "\\" lock_file_path = os.path.join(drive_letter, ".usb_lock") try: current_serial = get_volume_serial_number(drive_letter) if not os.path.exists(lock_file_path): # First run: Initialize the lock file encrypted_serial = encrypt_serial(current_serial) with open(lock_file_path, 'w') as lock_file: lock_file.write(encrypted_serial) # Mark the file as hidden and system to avoid accidental edits ctypes.windll.kernel32.SetFileAttributesW(lock_file_path, 0x02 | 0x04) print("Program initialized successfully.") else: # Check against saved serial number with open(lock_file_path, 'r') as lock_file: stored_hash = lock_file.read().strip() if encrypt_serial(current_serial) != stored_hash: # Show error dialog and exit ctypes.windll.user32.MessageBoxW( 0, "Error: This program can only run on the original USB device.", "USB Lock Error", 0x00000010 # Error icon ) sys.exit(1) # ------------------------------ # Put your main program logic here print("Program running normally!") # ------------------------------ except Exception as e: ctypes.windll.user32.MessageBoxW( 0, f"Critical error: {str(e)}", "USB Lock Error", 0x00000010 ) sys.exit(1) if __name__ == "__main__": main()
3. Package as a Portable Executable
Use PyInstaller to turn your Python script into a single, portable .exe file that works without a Python installation:
- Install PyInstaller if you haven't:
pip install pyinstaller - Package the script:
# For GUI programs (hides console window) pyinstaller --onefile --noconsole your_script.py # For console programs (keeps console window) pyinstaller --onefile your_script.py
The generated .exe will be in the dist folder—copy this and any other required files (like your encrypted videos) to the USB drive.
- Drive Formatting: If the user formats the original USB, the volume serial number will change, and the program will stop working. You may want to add a note about this.
- Tampering Prevention: The hidden lock file can still be viewed if users enable "Show hidden files" in Windows. The hash encryption makes it hard to modify, but for stronger protection, you could use a lightweight encryption library like
cryptography. - Cloning Behavior: Just like the education software, creating an image of the USB and writing it to another drive will copy the volume serial number, so the program will work on the cloned drive.
内容的提问来源于stack exchange,提问作者Stellar Mouse




