1. 项目背景与核心价值
最近在整理过往项目资料时,翻出一套用VBA开发的软件授权管理系统,这套系统曾在我们团队内部稳定运行了3年多,累计管理过2000+设备授权。不同于常见的序列号验证方式,这套系统采用了"一机一码"的授权机制,特别适合需要控制软件分发范围的场景。
核心组件包含两个部分:
- 发码端(管理后台):用Excel+VBA开发的授权码生成与管理系统
- 客户端(验证模块):需要集成到用户VBA项目中的验证组件
这种方案最大的优势是能精确绑定设备硬件信息,防止授权码被随意传播。实测下来,相比传统序列号验证,盗版率能降低70%以上。下面我就把这套系统的完整实现方案分享给大家。
2. 技术方案设计思路
2.1 一机一码原理实现
核心验证逻辑基于设备指纹技术,通过采集以下硬件信息生成唯一设备ID:
- 主板序列号(通过WMI获取)
- 硬盘卷序列号
- 网卡MAC地址
- CPU ID
这些信息经过MD5哈希处理后生成32位设备指纹码。在实际项目中,我们测试发现:
- 同一设备重复生成的指纹码100%一致
- 不同设备碰撞概率低于0.0001%
- 虚拟机环境下也能稳定生成唯一ID
重要提示:部分企业内网可能会屏蔽WMI查询,这种情况下需要准备备用方案,比如改用注册表读取部分硬件信息。
2.2 发码端架构设计
发码端采用Excel+VBA实现,主要包含以下功能模块:
| 模块名称 | 功能说明 | 关键技术点 |
|---|---|---|
| 授权管理 | 生成/作废授权码 | 随机数生成+ASE加密 |
| 设备指纹库 | 存储已注册设备信息 | ADODB连接Access数据库 |
| 有效期控制 | 设置授权时限 | DateDiff函数计算日期差 |
| 日志记录 | 记录所有授权操作 | 文本文件追加写入 |
数据库设计采用最简单的单表结构:
CREATE TABLE Licenses ( LicenseID TEXT(32) PRIMARY KEY, DeviceHash TEXT(32), UserName TEXT(50), ExpireDate DATE, IsActivated BIT )2.3 客户端验证流程
客户端验证逻辑分为三个层次:
- 首次验证:联网校验授权码有效性
- 日常验证:本地校验设备指纹+有效期
- 定期验证:每30天强制联网复核一次
验证过程全部封装在单独的clsLicense类模块中,主程序只需三行代码即可集成:
Dim lic As New clsLicense If Not lic.CheckLicense() Then Exit Sub ' 正常业务代码...3. 核心代码实现详解
3.1 设备指纹生成代码
以下是获取硬件信息的核心函数:
Function GetDeviceHash() As String Dim objWMIService As Object Set objWMIService = GetObject("winmgmts:\\.\root\cimv2") ' 获取主板信息 Dim colItems As Object, objItem As Object Set colItems = objWMIService.ExecQuery("Select * From Win32_BaseBoard") For Each objItem In colItems hashStr = hashStr & objItem.SerialNumber Next ' 获取CPU信息(代码类似,略) ' 获取硬盘信息(代码类似,略) ' 生成MD5哈希 GetDeviceHash = MD5(hashStr) End Function3.2 授权码生成算法
采用"设备指纹+随机盐值+日期"的组合加密方案:
Function GenerateLicense(deviceHash As String, days As Integer) As String Dim salt As String salt = Right(Format(Now, "yyyymmddhhmmss"), 6) Dim rawKey As String rawKey = deviceHash & salt & CStr(days) ' AES加密 Dim crypt As New clsAES GenerateLicense = crypt.Encrypt(rawKey, masterKey) End Function3.3 验证逻辑实现
客户端验证类的核心方法:
Public Function CheckLicense() As Boolean ' 检查本地缓存 If VerifyLocalCache() Then CheckLicense = True Exit Function End If ' 联网验证 Dim http As New MSXML2.XMLHTTP60 http.Open "POST", serverURL, False http.send BuildRequestXML() If http.Status = 200 Then ParseResponse http.responseText UpdateLocalCache CheckLicense = True Else CheckLicense = False End If End Function4. 部署与使用指南
4.1 发码端配置步骤
准备环境:
- Excel 2010及以上版本
- 启用VBA宏权限(信任中心设置)
- 安装Microsoft ActiveX Data Objects库
初始化数据库:
- 修改connStr连接字符串指向你的Access数据库
- 首次运行会自动创建数据表结构
管理员设置:
- 在config工作表中设置超级管理员密码
- 建议修改默认的AES加密密钥
4.2 客户端集成方法
导入以下组件到你的VBA项目:
- clsLicense.cls(核心验证类)
- modCrypto.bas(加密模块)
- modHardware.bas(硬件信息模块)
在ThisWorkbook中添加启动验证:
Private Sub Workbook_Open() Dim lic As New clsLicense lic.ServerURL = "http://your-server/api" If Not lic.CheckLicense() Then MsgBox "授权验证失败,程序将关闭", vbCritical ThisWorkbook.Close False End If End Sub5. 常见问题解决方案
5.1 硬件变更处理
当用户更换硬件时,设备指纹会发生变化。我们设计了两种解决方案:
弹性验证模式(推荐):
- 允许3次硬件变更
- 每次变更需重新验证
- 记录变更历史备查
人工审核模式:
- 用户提交变更申请
- 管理员后台审核通过
- 生成新的绑定授权码
5.2 离线环境适配
针对不能联网的设备,可以采用U盾模式:
- 将授权信息写入USBKey
- 客户端读取U盾中的证书文件
- 使用RSA签名验证真伪
实现代码片段:
Function VerifyUSBKey() As Boolean Dim cert As String cert = ReadFile("E:\license.dat") If VerifyRSASign(cert, publicKey) Then LoadLicenseFromString cert VerifyUSBKey = True End If End Function6. 安全增强建议
根据我们实际运营经验,建议增加以下防护措施:
代码混淆:
- 使用VBA代码混淆工具
- 关键函数名称随机化
- 添加伪代码干扰
反调试检测:
If IsDebuggerPresent() Then CorruptProject Application.Quit End If- 心跳监测:
- 随机时间间隔上报使用数据
- 异常使用模式自动锁定
这套系统经过我们多年迭代,目前已经形成了一套完整的VBA软件授权解决方案。特别是在WPS环境下也测试通过,只需要确保安装了VBA 7.1插件即可正常使用。如果大家在实现过程中遇到具体问题,可以参考项目中的示例代码,或者根据实际需求调整验证策略。