You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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.

Core Concept

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.

Step-by-Step Implementation

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:

  1. Install PyInstaller if you haven't:
    pip install pyinstaller
    
  2. 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.

Key Notes
  • 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

火山引擎 最新活动