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

Spring Boot 微服务架构设计与实现

Spring Boot 微服务架构设计与实现

Spring Boot 微服务架构设计与实现 25.1 学习目标与重点提示 学习目标:掌握Spring Boot微服务架构设计与实现的核心概念与使用方法,包括微服务架构的定义与特点、Spring Boot与微服务的集成、Spring Boot与微服务的配置、Spring Boot与微服务的基本方法、Spring Boot的实际应用场景,学会在实际开发中处理微服务架构设计与实现问题。 重点:微服务架构的定义与特点、Spring Boot与微服务的集成、Spring Boot与微服务的配置、Spring Boot与微服务的基本方法、Spring Boot的实际应用场景。 25.2 微服务架构概述 微服务架构是Java开发中的重要组件。 25.2.1 微服务架构的定义 定义:微服务架构是一种软件架构风格,将应用程序拆分为一组独立的服务,每个服务运行在自己的进程中,通过网络进行通信。 作用: * 提高应用程序的可扩展性。 * 提高应用程序的可维护性。 * 提高应用程序的可靠性。 常见的微服务架构: * Spring Cloud:Spring

By Ne0inhk
从 Oracle RAC 到金仓高可用集群:平滑切换的架构对比与落地指南

从 Oracle RAC 到金仓高可用集群:平滑切换的架构对比与落地指南

从Oracle RAC到金仓高可用集群:平滑切换的架构对比与落地指南 前言 做金融、政务、运营商等行业的数据库架构师,对Oracle RAC一定不陌生——作为业内成熟的高可用集群方案,Oracle RAC凭借多节点共享存储的架构,支撑了无数核心系统的7×24小时运行。但在国产化替代的大趋势下,“去O”不仅要解决单库的兼容问题,更要攻克高可用集群的平滑迁移难题:毕竟核心系统对停机时间的容忍度几乎为0,一旦集群切换出问题,轻则业务中断,重则引发数据错乱、监管风险,这也是很多企业在“去O”过程中最不敢触碰的环节。 很多企业的顾虑很实际:金仓的高可用集群和Oracle RAC架构差异有多大?核心的高可用能力比如故障自动切换、负载均衡、数据一致性,能和Oracle RAC持平吗?迁移过程中怎么保障业务不中断?原有基于Oracle RAC的运维体系能复用吗?这些问题如果没有明确答案,企业根本不敢轻易启动集群迁移。 作为国产数据库的领军者,电科金仓的KingbaseES(KES)针对Oracle RAC用户的迁移痛点,打造了一套高度兼容、能力对标、无缝切换的高可用集群解决方案,不仅在架构设

By Ne0inhk
Spring Cloud 熔断降级详解:用 “保险丝“ 类比,Sentinel 实战教程

Spring Cloud 熔断降级详解:用 “保险丝“ 类比,Sentinel 实战教程

欢迎文末添加好友交流,共同进步! “ 俺はモンキー・D・ルフィ。海贼王になる男だ!” * 📋 目录 * 什么是熔断降级 * 定义 * 为什么需要熔断降级? * 保险丝类比:形象理解熔断机制 * 生活中的保险丝 * 熔断器工作原理对比 * 熔断器三种状态 * Sentinel 核心概念 * 什么是 Sentinel? * 核心概念对比 * Sentinel vs Hystrix 对比 * Sentinel 实战教程 * 环境准备 * 1. 添加依赖 * 2. 配置文件 * 基础示例:注解方式 * 3. 主启动类 * 4. 创建订单服务 * 5. 控制器 * 高级配置:规则定义 * 6. 流控规则配置 * OpenFeign 集成 * 7. Feign客户端集成Sentinel * 8. Feign降级处理 * 规则持久化(

By Ne0inhk
快学快用系列:一文学会java后端WebApi开发

快学快用系列:一文学会java后端WebApi开发

文章目录 * 第一部分:Web API开发基础概念 * 1.1 什么是Web API * 1.2 RESTful API设计原则 * 第二部分:开发环境搭建 * 2.1 环境要求 * 2.2 创建Spring Boot项目 * 2.3 配置文件 * 第三部分:项目架构设计 * 3.1 分层架构 * 3.2 包结构设计 * 第四部分:数据模型设计 * 4.1 实体类设计 * 4.2 DTO设计 * 第五部分:数据访问层实现 * 5.1 Repository接口 * 5.2 自定义Repository实现 * 第六部分:业务逻辑层实现

By Ne0inhk