import hashlib import platform import subprocess import sys import os import uuid from pathlib import Path class MachineCodeGenerator: """机器码生成器,支持多种方法生成唯一的机器标识""" def __init__(self): self.cache_file = Path.home() / ".exe_encrypt_machine_id" self.system = platform.system() def _run_command(self, cmd, shell=True): """安全执行系统命令""" try: if isinstance(cmd, str): cmd_list = cmd.split() if not shell else cmd else: cmd_list = cmd result = subprocess.run( cmd_list, shell=shell, capture_output=True, text=True, timeout=10, creationflags=subprocess.CREATE_NO_WINDOW if sys.platform == "win32" else 0 ) if result.returncode == 0: return result.stdout.strip() return None except Exception: return None def get_windows_machine_code(self): """获取Windows系统的机器码""" identifiers = [] # 方法1: 获取主板序列号 try: output = self._run_command('wmic baseboard get serialnumber /value') if output: for line in output.split('\n'): if 'SerialNumber=' in line: serial = line.split('=')[1].strip() if serial and serial.lower() not in ['to be filled by o.e.m.', '']: identifiers.append(('motherboard', serial)) except: pass # 方法2: 获取CPU信息 try: output = self._run_command('wmic cpu get processorid /value') if output: for line in output.split('\n'): if 'ProcessorId=' in line: cpu_id = line.split('=')[1].strip() if cpu_id: identifiers.append(('cpu', cpu_id)) except: pass # 方法3: 获取BIOS信息 try: output = self._run_command('wmic bios get serialnumber /value') if output: for line in output.split('\n'): if 'SerialNumber=' in line: bios_serial = line.split('=')[1].strip() if bios_serial and bios_serial.lower() not in ['to be filled by o.e.m.', '']: identifiers.append(('bios', bios_serial)) except: pass # 方法4: 获取硬盘序列号 try: output = self._run_command('wmic diskdrive get serialnumber /value') if output: for line in output.split('\n'): if 'SerialNumber=' in line: disk_serial = line.split('=')[1].strip() if disk_serial and len(disk_serial) > 5: identifiers.append(('disk', disk_serial)) break # 只取第一个有效的硬盘序列号 except: pass # 方法5: 获取网卡MAC地址 try: output = self._run_command('getmac /v /fo csv') if output: lines = output.split('\n') for line in lines[1:]: # 跳过标题行 if ',' in line and 'Physical Address' in line: parts = line.split(',') if len(parts) > 2: mac = parts[2].strip('"').replace('-', ':') if len(mac) == 17 and mac != "N/A": identifiers.append(('mac', mac)) break except: pass # 如果没有获取到硬件标识符,使用系统信息 if not identifiers: identifiers.append(('system', f"{platform.node()}-{platform.processor()}")) return identifiers def get_linux_machine_code(self): """获取Linux系统的机器码""" identifiers = [] # 方法1: 机器ID try: machine_id_file = Path('/etc/machine-id') if machine_id_file.exists(): machine_id = machine_id_file.read_text().strip() if machine_id: identifiers.append(('machine_id', machine_id)) except: pass # 方法2: DMI信息 try: output = self._run_command('dmidecode -s system-serial-number') if output and output.lower() not in ['not specified', 'to be filled by o.e.m.']: identifiers.append(('system_serial', output)) except: pass # 方法3: CPU信息 try: cpuinfo = Path('/proc/cpuinfo') if cpuinfo.exists(): content = cpuinfo.read_text() for line in content.split('\n'): if 'Serial' in line and ':' in line: serial = line.split(':')[1].strip() if serial and serial != '0000000000000000': identifiers.append(('cpu_serial', serial)) break except: pass # 方法4: MAC地址 try: output = self._run_command('cat /sys/class/net/*/address') if output: for line in output.split('\n'): mac = line.strip() if len(mac) == 17 and mac != '00:00:00:00:00:00': identifiers.append(('mac', mac)) break except: pass # 备用方法: 使用hostname和架构 if not identifiers: identifiers.append(('system', f"{platform.node()}-{platform.machine()}")) return identifiers def get_mac_machine_code(self): """获取macOS系统的机器码""" identifiers = [] # 方法1: 硬件UUID try: output = self._run_command('system_profiler SPHardwareDataType | grep "Hardware UUID"') if output and ':' in output: uuid = output.split(':')[1].strip() if uuid: identifiers.append(('hardware_uuid', uuid)) except: pass # 方法2: 序列号 try: output = self._run_command('system_profiler SPHardwareDataType | grep "Serial Number"') if output and ':' in output: serial = output.split(':')[1].strip() if serial: identifiers.append(('serial', serial)) except: pass # 方法3: MAC地址 try: output = self._run_command('ifconfig en0 | grep ether') if output: mac = output.split()[1] if mac: identifiers.append(('mac', mac)) except: pass # 备用方法 if not identifiers: identifiers.append(('system', f"{platform.node()}-{platform.processor()}")) return identifiers def get_cached_machine_code(self): """获取缓存的机器码""" try: if self.cache_file.exists(): cached_code = self.cache_file.read_text().strip() if len(cached_code) == 16: # 验证格式 return cached_code except: pass return None def save_machine_code(self, machine_code): """保存机器码到缓存""" try: self.cache_file.parent.mkdir(parents=True, exist_ok=True) self.cache_file.write_text(machine_code) # 设置只读权限 if self.system == "Windows": import stat self.cache_file.chmod(stat.S_IREAD) else: os.chmod(self.cache_file, 0o444) except: pass def generate_machine_code(self): """生成机器码""" # 首先尝试从缓存读取 cached_code = self.get_cached_machine_code() if cached_code: return cached_code # 根据系统获取硬件标识符 if self.system == "Windows": identifiers = self.get_windows_machine_code() elif self.system == "Linux": identifiers = self.get_linux_machine_code() elif self.system == "Darwin": # macOS identifiers = self.get_mac_machine_code() else: # 未知系统,使用通用方法 identifiers = [('system', f"{platform.node()}-{platform.processor()}-{platform.system()}")] # 组合所有标识符 combined_data = "" for identifier_type, identifier_value in identifiers: combined_data += f"{identifier_type}:{identifier_value}|" # 添加一些系统固定信息作为增强 combined_data += f"os:{platform.system()}|" combined_data += f"arch:{platform.machine()}|" # 生成哈希 hash_obj = hashlib.sha256(combined_data.encode('utf-8')) machine_code = hash_obj.hexdigest()[:16].upper() # 保存到缓存 self.save_machine_code(machine_code) return machine_code def get_detailed_info(self): """获取详细的机器信息(用于调试)""" info = { "system": platform.system(), "release": platform.release(), "version": platform.version(), "machine": platform.machine(), "processor": platform.processor(), "node": platform.node(), "python_version": platform.python_version(), } # 获取硬件标识符 if self.system == "Windows": identifiers = self.get_windows_machine_code() elif self.system == "Linux": identifiers = self.get_linux_machine_code() elif self.system == "Darwin": identifiers = self.get_mac_machine_code() else: identifiers = [] info["hardware_identifiers"] = identifiers info["machine_code"] = self.generate_machine_code() info["cache_file"] = str(self.cache_file) info["cache_exists"] = self.cache_file.exists() return info # 全局实例 _machine_code_generator = MachineCodeGenerator() def get_machine_code(): """获取当前系统的机器码(主要接口函数)""" return _machine_code_generator.generate_machine_code() def get_machine_info(): """获取详细的机器信息""" return _machine_code_generator.get_detailed_info() def reset_machine_code(): """重置机器码缓存""" try: if _machine_code_generator.cache_file.exists(): _machine_code_generator.cache_file.unlink() return True except: return False def verify_machine_code_stability(): """验证机器码的稳定性(多次生成应该相同)""" codes = [] for _ in range(3): # 清除缓存,重新生成 reset_machine_code() code = get_machine_code() codes.append(code) # 检查是否都相同 stable = all(code == codes[0] for code in codes) return stable, codes if __name__ == "__main__": print("=== 机器码生成器测试 ===") # 获取机器码 machine_code = get_machine_code() print(f"机器码: {machine_code}") # 获取详细信息 info = get_machine_info() print(f"\n=== 系统信息 ===") print(f"系统: {info['system']} {info['release']}") print(f"架构: {info['machine']}") print(f"处理器: {info['processor']}") print(f"主机名: {info['node']}") print(f"Python版本: {info['python_version']}") print(f"\n=== 硬件标识符 ===") for identifier_type, identifier_value in info['hardware_identifiers']: print(f"{identifier_type}: {identifier_value}") print(f"\n=== 缓存信息 ===") print(f"缓存文件: {info['cache_file']}") print(f"缓存存在: {info['cache_exists']}") # 稳定性测试 print(f"\n=== 稳定性测试 ===") stable, codes = verify_machine_code_stability() print(f"稳定性: {'通过' if stable else '失败'}") print(f"测试结果: {codes}") if not stable: print("⚠️ 警告: 机器码不稳定,可能导致授权问题!")