C# WinForms 注册码生成与验证机制详解
在C# WinForms开发中,基于硬件指纹(机器码)的本地授权是一种常见的防破解手段。本文将结合完整代码,解析如何通过WMI接口获取硬件ID,使用自定义算法生成对应注册码,并利用System.Security.AccessControl和Microsoft.Win32.Registry类完成试用计数、状态持久化与验证。
核心机制设计
该方案依赖以下三个关键步骤:
- 硬件指纹采集:读取主板CPU标识与系统盘D:的卷标号。
- 哈希算法映射:将机器码字符转换为ASCII码,经过模运算与位移后生成唯一注册码。
- 环境交互:在主程序入口判断注册表项,控制功能开关与试用计数器。
运行后的主界面会显示当前的注册状态。未注册用户进入试用模式并记录开启次数;已注册用户则解锁完整功能。

准备工作
创建 .NET Framework Windows Forms 项目,并确保引用以下命名空间:
using System.Diagnostics;
using System.Management;
using Microsoft.Win32;
第1步:定义注册逻辑公共类 SoftReg
目的:封装硬件获取与注册码计算逻辑,供UI层调用。
- 获取硬件信息:使用
ManagementClass查询Win32_NetworkAdapterConfiguration中的硬盘卷标与Win32_Processor中的ProcessorId。 - 生成注册码:截取前24位组合串,逐位进行ASCII值处理与偏移,确保输出只包含数字与大写字母。
public class SoftReg
{
// 取得设备硬盘的卷标号 (注意:通常应查询所有LogicalDisk,此处保留原逻辑)
public string GetDiskVolumeSerialNumber()
{
ManagementObject disk = new ManagementObject("win32_logicaldisk.deviceid=\"d:\"");
try
{
disk.Get();
return disk.GetPropertyValue("VolumeSerialNumber").ToString();
}
catch
{
return "Err"; // 增加异常处理防止报错
}
}
//获得CPU的序列号
public string getCpu()
{
string strCpu = null;
ManagementClass myCpu = new ManagementClass("win32_Processor");
ManagementObjectCollection myCpuConnection = myCpu.GetInstances();
foreach (ManagementObject myObject in myCpuConnection)
{
strCpu = myObject.Properties["Processorid"].Value.ToString();
break; // 取第一个CPU标识即可
}
return strCpu;
}
//生成机器码
public string getMNum()
{
string strNum = getCpu() + GetDiskVolumeSerialNumber();
// 若总长度不足24,需做截断或填充保护
if (strNum.Length >= 24)
return strNum.Substring(0, 24);
else
return strNum.PadRight(24, 'X');
}
public int[] intCode = new int[127];
public int[] intNumber = new int[25];
public char[] Charcode = new char[25];
public void setIntCode()
{
for (int i = 1; i < intCode.Length; i++)
{
intCode[i] = i % 9;
}
}
//生成注册码 (简单校验型)
public string getRNum()
{
setIntCode();
for (int i = 1; i < Charcode.Length; i++)
{
// 确保不越界
if (i - 1 < getMNum().Length)
Charcode[i] = Convert.ToChar(getMNum().Substring(i - 1, 1));
else
Charcode[i] = '?';
}
for (int j = 1; j < intNumber.Length; j++)
{
intCode[(int)Charcode[j]] = Charcode[j] % 9;
intNumber[j] = intCode[(int)Charcode[j]] + (int)Charcode[j];
}
string strAsciiName = "";
for (int j = 1; j < intNumber.Length; j++)
{
if (intNumber[j] >= 48 && intNumber[j] <= 57 ||
intNumber[j] >= 65 && intNumber[j] <= 90 ||
intNumber[j] >= 97 && intNumber[j] <= 122)
{
strAsciiName += Convert.ToChar(intNumber[j]).ToString();
}
else
{
// 超出标准字母范围时做回退处理
if (intNumber[j] > 122)
strAsciiName += Convert.ToChar(intNumber[j] - 10).ToString();
else
strAsciiName += Convert.ToChar(intNumber[j] - 9).ToString();
}
}
return strAsciiName;
}
}第2步:配置主窗体 frmMain 启动逻辑
目的:初始化时读取注册表尝试键,自动判定“已注册”、“试用”或“过期”。同时管理tryTimes键用于限制试用期。
- 注册状态检查:遍历
software/mrwxk/mrwxk.ini/下的子键名称是否匹配当前生成的注册码。 - 试用计数:每次成功打开应用,自增
UseTimes,上限设为30次。
public partial class frmMain : Form
{
SoftReg softreg = new SoftReg();
private void frmMain_Load(object sender, EventArgs e)
{
bool isRegistered = false;
try
{
// 注意:HKEY_LOCAL_MACHINE 需要管理员权限才能创建子项
var rootKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("software", true);
if (rootKey != null)
{
using (var softwareKey = rootKey.CreateSubKey("mrwxk"))
{
using (var iniKey = softwareKey.CreateSubKey("mrwxk.ini"))
{
foreach (string subKey in iniKey.GetSubKeyNames())
{
if (subKey == softreg.getRNum())
{
isRegistered = true;
break;
}
}
}
}
}
}
catch { }
if (isRegistered)
{
this.Text = "主窗体(已注册)";
// 假设有一个按钮用来卸载或检查注册
// button1.Enabled = false;
}
else
{
this.Text = "主窗体(未注册)";
HandleTrialMode();
}
}
private void HandleTrialMode()
{
// 读取或使用次数
object val = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\tryTimes", "UseTimes", 0);
int currentTimes = (val as int?) ?? 0;
// 如果尚未初始化过键,则初始化为0
if (val == null)
{
Registry.SetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\tryTimes", "UseTimes", 0, RegistryValueKind.DWord);
MessageBox.Show("欢迎新用户使用本软件", "提示");
currentTimes = 0;
}
else
{
MessageBox.Show($"已使用了 {currentTimes} 次", "提示");
}
// 判断是否过期
if (currentTimes >= 30)
{
MessageBox.Show("试用次数已到!请购买正版注册码。", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
Application.Exit();
}
else
{
// 记录本次使用
Registry.SetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\tryTimes", "UseTimes", currentTimes + 1);
// 这里可以弹出试用剩余次数提示
}
}
}
第3步:实现注册窗口 frmRegister 验证
目的:输入正确的机器码计算出的注册码,写入注册表以激活软件。
- 加载页:自动展示由
getMNum()生成的硬件机器码。 - 确认逻辑:用户输入的值必须精确等于
softreg.getRNum()计算结果才视为有效。 - 写入键:在
HKEY_LOCAL_MACHINE\...\mrwxk.ini下创建一个以其输入值为名的空子键,作为永久凭证。
public partial class frmRegister : Form
{
SoftReg softreg = new SoftReg();
private void frmRegister_Load(object sender, EventArgs e)
{
// 绑定机器码显示
textBox1.Text = softreg.getMNum();
}
private void button1_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(textBox2.Text))
{
MessageBox.Show("注册码输入不能为空!", "警告");
return;
}
// 严格校验
if (textBox2.Text.Equals(softreg.getRNum(), StringComparison.Ordinal))
{
try
{
using (var root = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("software", true))
using (var sec = root.CreateSubKey("mrwxk"))
using (var final = sec.CreateSubKey("mrwxk.ini"))
{
// 写入一个名为输入值的子键,表示该注册码已被登记
final.CreateSubKey(textBox2.Text);
final.Close();
}
MessageBox.Show("注册成功,请重启软件生效!", "提示");
this.Hide();
// 通知主程序重载或直接返回并刷新状态
}
catch (Exception ex)
{
MessageBox.Show($"写入注册表失败,可能权限不足: {ex.Message}", "错误");
}
}
else
{
MessageBox.Show("注册码错误,请重试!", "错误");
}
}
}注意事项与排错
- 权限问题 (UAC):读写
HKEY_LOCAL_MACHINE需要管理员权限。若以普通身份运行,上述代码可能抛出UnauthorizedAccessException。建议配置清单文件请求管理员权限,或在安装程序中统一注册。 - D盘不存在风险:
GetDiskVolumeSerialNumber硬编码了D:。在实际环境中,应枚举所有LogicalDisk找到系统盘或首个分区,否则会导致生成错误的机器码。 - 安全性提升:原文使用的算法是纯客户端对称推导,容易被反编译逆向破解。生产环境中应引入RSA非对称签名或使用云端License服务器验证。
总结
通过上述 C# 代码示例,我们展示了如何构建一套基础的软件授权体系。利用 WMI 锁定硬件特性,结合轻量级 ASCII 哈希算法生成注册码,最后利用 Windows 注册表机制实现状态的持久化存储。虽然该逻辑适合内部小型工具或教育用途,但对于商业发布的产品,建议采用更复杂的加密算法或网络验证服务来防止注册机攻击。 以上就是C#实现注册码注册机制效果详解的详细内容,更多关于C#注册码注册机制的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









