Python 程序打包exe加入授权码和注册机

一、总体思路

软件授权方案大概分成两个部分:程序本体 和 注册机

当用户启动程序时,程序会检验本地的 授权文件 是否合法,若验证通过,则直接进入程序,若未找到授权文件或者授权文件校验失败,则进入重新授权流程。进入授权流程时,程序先扫描本机运行环境,生成 机器码 ,然后提示用户找管理员获取授权码;用户将机器码发送给管理员,管理员将机器码输入 注册机 中,生成与该机器码唯一绑定的 授权码 后,发送给用户;用户在程序中输入授权码,验证通过后正式进入程序,并在本地生成授权文件。

下面是我的软件授权方案的流程图。

授权流程图

以上便是我这套软件授权方案的总体思路,接下来,我会教大家如何用 python 来实现它。

二、实现过程

实现这套授权机制,我们需要解决以下几个小问题。

  1. 如何使授权码与机器唯一绑定,仅在本台机器上有效?
  2. 如何生成验证码,以及如何验证授权码是否有效?
  3. 如何保护自己的授权码不那么容易被人破解?

带着这些问题,我们继续往下看。

2.1 获取机器信息

要回答第一个问题,首先要搞明白,软件如何判断自己运行在哪一台机器上?

我们知道,每一台机器都会有一个唯一 Mac 地址,我们可以用它来作为机器的唯一标识。

此外为了保险,我们还可以获取机器的 CPU 序列号硬盘序列号主板序列号 等等数据,与 Mac 地址 共同作为一台机器的唯一标识。

windows 系统下,我们可以使用 wmi 的库来获取机器的硬件信息。

没有安装 wmi 库的,可以运行下面的命令行来安装。

text

pip install wmi 
2.1.1 获取 CPU 序列号

python

import wmi m_wmi = wmi.WMI() cpu_info = m_wmi.Win32_Processor() if len(cpu_info) > 0: serial_number = cpu_info[0].ProcessorId print(serial_number) 
2.1.2 获取 MAC 地址

python

import wmi m_wmi = wmi.WMI() for network in m_wmi.Win32_NetworkAdapterConfiguration(): mac_address = network.MacAddress if mac_address != None: print(mac_address) 
2.1.3 获取硬盘序列号

python

import wmi m_wmi = wmi.WMI() disk_info = m_wmi.Win32_PhysicalMedia() if len(disk_info) > 0: serial_number = disk_info[0].SerialNumber.strip() print(serial_number) 
2.1.4 获取主板序列号

python

import wmi m_wmi = wmi.WMI() board_info = self.m_wmi.Win32_BaseBoard() if len(board_info) > 0: board_id = board_info[0].SerialNumber.strip().strip('.') print(board_id) 

2.2 生成机器码

使用上述方法,我们可以获取到机器的 CPU 序列号硬盘序列号主板序列号 与 Mac 地址 信息,通过这些信息,我们便可以生成唯一标识一台机器的 机器码

理论上,我们将这些数据直接进行字符串拼接,便可作为机器码使用,但是实际上,这样做存在一些问题。

  1. 机器码过长,使用体验不太友好。
  2. 直接暴露机器的硬件数据,有信息安全隐患。

所以我们需要对机器的这些硬件数据进行一些处理,生成一个长度适中的,既可以作为机器的唯一标识,又不会暴露机器硬件数据的机器码。

carbon

mac_address = get_mac_address() cpu_serial = get_cpu_serial() disk_serial = get_disk_serial() board_serial = get_board_serial() combine_str = mac_address + cpu_serial + disk_serial + board_serial combine_byte = combine_str.encode("utf-8") machine_code = hashlib.md5(combine_byte).hexdigest() print(machine_code.upper()) 

众所周知,MD5 是一种常用的不可逆的数据加密算法,我们用它对机器硬件数据进行加密,一方面它加密后的结果长度固定(32个字符),另一方面也可以在一定程度上保护数据安全。

2.3 授权验证逻辑

想要在离线的情况下实现 授权码 和 机器码 唯一绑定,意味着授权码是由机器码经过一系列复杂的加密算法处理后得到的。

授权码验证的逻辑也比较简单,大概有三种思路:

  1. 将机器码使用相同的加密算法处理,得到的结果与验证码进行比较。
  2. 将验证码使用对应的解密算法处理,得到的结果与机器码进行比较。
  3. 使用特定的算法分别处理机器码和授权码,将得到的结果进行比较。

一般来讲,第一种思路实现起来会比较简单一些,因为它只需要写一套加密算法即可(软件验证部分跟授权码生成部分用的是同一套加密算法),而且无需考虑解密的问题,安全性会更高(因为可以使用不可逆的加密算法)

大概的验证逻辑如下:

verilog

machine_code = getMachineCode() encrypt_code = Encrypted(machine_code.encode("utf-8")) if os.path.exists("register.bin"): with open("register.bin", "r") as f: key_code = f.read() if key_code == encrypt_code: print("验证通过") else: print("验证失败") else: print("验证失败") 

2.3 生成授权码

如何将机器码加密生成授权码,可以使用的加密算法其实五花八门,每个人都可以自己研究一套自己独有的加密方法,尤其是不需要考虑解密,不要求算法可逆的情况下,问题就更简单了。

比如:

  • 你可以提取机器码的奇数位或偶数位,或者自己定义的任意位置的字符出来,组合成授权码。
  • 可以将指定位置的字符进行交换,得到的字符串作为授权码。
  • 可以将其中的某些字符替换成其它字符,得到的字符串作为授权码。
  • 甚至可以直接再进行一次 MD5 加密,结果作为授权码。

总之,方法是非常多样化的,只要你生成的授权码可以正常使用,并且没那么容易让别人猜出你授权码生成的规律即可。

作为示例,我演示一下我 Demo 中的加密方法。

python

import base64 import hashlib from pyDes import * def Encrypted(self, code): Des_key = "posdvsgt" Des_IV = "\x11\2\x2a\3\1\x27\2\0" k = des(Des_key, CBC, Des_IV, pad=None, padmode=PAD_PKCS5) EncryptStr = k.encrypt(code) base64_code = base64.b32encode(EncryptStr) md5_code = hashlib.md5(base64_code).hexdigest().upper() return md5_code 

通过上述加密算法,我们可以通过机器码生成授权码,并且通过一系列加密算法的组合加密,基本上很难观察出机器码和授权码之间的关系,更没办法推算出你具体用了什么加密方法。

需要说明的是,

不管使用什么算法,凡离线方式的加密必然是可以被破解的,只是破解的时间和成本问题,所以上述的加密只是提高了破解门槛,防小白不防大神。

想要万无一失,还得是在线授权验证。

2.5 打包测试

核心算法搞定以后,整理一下代码就可以打包测试了。


可以使用 pyinstaller 库来把代码打包成 .exe 程序。

没有安装 pyinstaller 库的,可以运行下面的命令行来安装。

text

pip install pyinstaller 

使用 pyinstaller 库打包的命令如下:

text

pyinstaller -F xxx.py 

打包完成以后,会在当前目录下的 dist 文件夹中,生成 xxx.exe 可执行程序。


首次启动程序时(无授权文件),会提示输入激活码,即授权码。

随便输入错误的授权码,会验证失败,提示重新输入。

此时我们启动注册机,根据提示复制机器码 BD1F7DF8646CD3A101C3DA8610672ED1 到注册机中,生成激活码。

复制并输入激活码,此时授权验证成功,程序可以正常使用,输出了 Hello World! 字样。

后续再次启动程序时,由于已有授权文件,所以可以直接进入。

三、改进措施

当然,作为 V1.0 版本的授权码机制,其实还是有很多值得改进的地方,比如:

  1. 设置授权有效期,过期则需要重新授权
  2. 授权方式改成在线,安全性更高的同时也可以进行更加精细化的授权管理。
  3. 授权后台管理系统,更加方便地管理自己的软件授权。 ....

如果后续大家有需求,我也有精力的话,可以把它做的更加完善一些。

Read more

StarRocks vs MySQL 全面深度对比

一、核心定位差异 根本性差异 维度 StarRocks MySQL 数据库类型 OLAP(联机分析处理) OLTP(联机事务处理) 设计目标 大规模数据分析 高并发事务处理 存储方式 列式存储 行式存储 应用场景 数据仓库、实时分析、BI报表 业务系统、交易系统、网站后台 形象比喻 * MySQL:像 Excel,适合一行一行操作数据 * StarRocks:像 数据透视表,适合对整列数据做聚合分析 二、架构设计对比 1. 存储架构 方面 StarRocks MySQL 存储格式 列式存储(每列单独存储) 行式存储(每行连续存储) 压缩效率 ✅ 极高(同列数据类型一致) ⚠️ 一般(行内数据类型多样)

By Ne0inhk
金仓数据库 MongoDB 兼容:多模融合下的架构之道与实战体验

金仓数据库 MongoDB 兼容:多模融合下的架构之道与实战体验

引言:从“平替”到“超越”的技术跨越 在国产化替代(信创)浪潮下,选择数据库不再只是考量“能否使用”,更多关注其“好用与否”,还要看是否能做到“无缝切换”。提到 MongoDB,想必大家都不生疏,作为 NoSQL 领域的佼佼者,凭借自身灵活的数据架构和飞快的读写效率,斩获诸多互联网及物联网项目,不过须要诚实地表明,一旦关乎到企业核心业务,譬如要确保数据完全一致,执行繁杂的关联查询或者实施统一运作管理时,MongoDB 就常常会有些力不从心。 电科金仓(Kingbase)所给出的多模融合数据库方案颇具趣味,该方案并非仅仅创建一层适配层来博取眼球,其实在架构层面上执行了“降维打击”,经由内核级别的 MongoDB 协议适配 并结合自主研发的 OSON 存储引擎,金仓把“关系型数据库稳定的基础”与“NoSQL 灵活的特性”融合起来,现在,让我们一起探究金仓数据库(KingbaseES,

By Ne0inhk
【SpringBoot】从学会使用maven开始

【SpringBoot】从学会使用maven开始

🎬 那我掉的头发算什么:个人主页 🔥 个人专栏: 《javaSE》《数据结构》《数据库》《javaEE》 ⛺️待到苦尽甘来日 引言 当我们在创建一个新的idea项目时,不知道大家注意过没有 在这个页面中除了IntelliJ选项之外,还有一个Maven选项。而这个Maven恰好就是我们今天这篇文章的重头戏! 文章目录 * 引言 * 创建Maven项目 * pom文件 * 项目基本信息 * GAV * properties * 依赖管理核心:dependencies与dependency * Maven的配置与使用 * 生命周期 * 下载依赖到本地仓库 * 新建Maven仓库 创建Maven项目 单单创建一个Maven项目其实很简单,只需要在原有的基础上把本来创建的idea项目改成Maven就好了。此处的GroupId和ArtifactId在工作中参与大项目时会使用到,表示组名和项目的一些信息。 创建完成后的项目中的目录与我们之前idea的目录差异很大,有了很多没见过的模块,比如: * tar

By Ne0inhk