C# WinForms 注册码生成与验证机制详解

Theo
Theo
发布时间:2026-10-16 | 7人浏览过
原创

在C# WinForms开发中,基于硬件指纹(机器码)的本地授权是一种常见的防破解手段。本文将结合完整代码,解析如何通过WMI接口获取硬件ID,使用自定义算法生成对应注册码,并利用System.Security.AccessControl和Microsoft.Win32.Registry类完成试用计数、状态持久化与验证。

核心机制设计

该方案依赖以下三个关键步骤:

  1. 硬件指纹采集:读取主板CPU标识与系统盘D:的卷标号。
  2. 哈希算法映射:将机器码字符转换为ASCII码,经过模运算与位移后生成唯一注册码。
  3. 环境交互:在主程序入口判断注册表项,控制功能开关与试用计数器。

运行后的主界面会显示当前的注册状态。未注册用户进入试用模式并记录开启次数;已注册用户则解锁完整功能。

准备工作

创建 .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#注册码注册机制的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表