网站首页 > 技术文章 正文
采用C#语言实现。
特性:
跨平台(Windows / Linux / macOS) 且 无需管理员权限 的 C# 实现,功能与 Go 版本保持一致:
- 采集 CPU 特性 + 主板 UUID + 第一块物理磁盘序列号 + 第一块启用网卡 MAC
- 做 SHA-256 并取前 32 位十六进制字符作为脱敏硬件指纹
- 完全使用 托管代码 / WMI / sysfs / IOKit 包装库,不调用 shell
项目结构(单文件即可编译)
HardwareId.csproj
Program.cs
1. HardwareId.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<!-- 跨平台硬件信息库 -->
<ItemGroup>
<PackageReference Include="System.Management" Version="8.0.0" /> <!-- Windows WMI -->
<PackageReference Include="Hardware.Info" Version="15.0.0" /> <!-- 跨平台磁盘 / 网卡 -->
</ItemGroup>
</Project>
2. Program.cs(完整代码,含中文注释)
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using Hardware.Info; // NuGet: Hardware.Info
using System.Management; // 仅 Windows 下用到
class Program
{
static void Main()
{
try
{
string hwId = StableHardwareID();
Console.WriteLine(hwId);
}
catch (Exception ex)
{
Console.Error.WriteLine(#34;获取硬件指纹失败: {ex}");
Environment.Exit(1);
}
}
/// <summary>
/// 生成跨平台稳定且脱敏的硬件指纹。
/// 步骤:CPU 特性 → 主板 UUID → 主硬盘序列号 → 第一块启用网卡 MAC
/// 拼接后 SHA-256,取前 32 位十六进制字符。
/// </summary>
static string StableHardwareID()
{
var sb = new StringBuilder();
// 1) CPU 特性:Vendor + Family + Model + Stepping
sb.Append(GetCpuFeatureString()).Append('|');
// 2) 主板 UUID(Windows WMI;Linux/macOS 读取 sysfs/IOKit)
sb.Append(GetMotherboardUuid()).Append('|');
// 3) 第一块非可移动磁盘序列号
sb.Append(GetFirstDiskSerial()).Append('|');
// 4) 第一块启用中、非回环 MAC 地址
sb.Append(GetFirstActiveMac());
// 5) SHA-256 并取前 32 位
using var sha = SHA256.Create();
byte[] hash = sha.ComputeHash(Encoding.UTF8.GetBytes(sb.ToString()));
return Convert.ToHexString(hash).Substring(0, 32).ToLowerInvariant();
}
#region 私有辅助函数
/// <summary>
/// 获取 CPU 的 Vendor + Family + Model + Stepping
/// </summary>
static string GetCpuFeatureString()
{
var hi = new HardwareInfo();
hi.RefreshCPUList();
var cpu = hi.CpuList.FirstOrDefault()
?? throw new Exception("无法获取 CPU 信息");
return #34;{cpu.Manufacturer}-{cpu.Family}-{cpu.Model}-{cpu.Stepping}";
}
/// <summary>
/// 主板 UUID(Windows 走 WMI;其余平台由 Hardware.Info 提供)
/// </summary>
static string GetMotherboardUuid()
{
if (OperatingSystem.IsWindows())
{
using var mc = new ManagementClass("Win32_ComputerSystemProduct");
using var moc = mc.GetInstances();
var uuid = moc.Cast<ManagementObject>()
.Select(m => m["UUID"]?.ToString())
.FirstOrDefault(u => !string.IsNullOrWhiteSpace(u));
return uuid ?? throw new Exception("无法读取主板 UUID");
}
else
{
var hi = new HardwareInfo();
hi.RefreshMotherboardList();
return hi.MotherboardList.FirstOrDefault()?.SerialNumber
?? throw new Exception("无法读取主板 UUID");
}
}
/// <summary>
/// 第一块非可移动、非 USB 磁盘的序列号
/// </summary>
static string GetFirstDiskSerial()
{
var hi = new HardwareInfo();
hi.RefreshDriveList();
var disk = hi.DriveList
.FirstOrDefault(d => !d.IsRemovable && d.Size > 0)
?? throw new Exception("未找到物理磁盘");
return disk.SerialNumber?.Trim() ?? throw new Exception("磁盘无序列号");
}
/// <summary>
/// 第一块启用中、非回环网卡的 MAC 地址(去掉冒号并小写)
/// </summary>
static string GetFirstActiveMac()
{
var hi = new HardwareInfo();
hi.RefreshNetworkAdapterList();
var nic = hi.NetworkAdapterList
.FirstOrDefault(n => n.OperationalStatus == "Up" &&
!n.MACAddress.StartsWith("00:00:00"))
?? throw new Exception("未找到可用 MAC 地址");
return nic.MACAddress.Replace(":", "").ToLowerInvariant();
}
#endregion
}
3. 编译 & 运行
# 还原依赖
dotnet restore
# 运行(Windows / Linux / macOS 均可)
dotnet run
输出示例(32 位十六进制,已脱敏):
3e8f2c4a7b91c0e5d8e3f1a2b9c4d7f6
与原 Go 实现对照
功能 | Go 实现 | C# 实现 |
CPU 信息 | gopsutil | HardwareInfo.CpuList |
主板 UUID | host.Info().HostID | WMI / HardwareInfo.MotherboardList |
磁盘序列号 | ghw | HardwareInfo.DriveList |
MAC 地址 | gopsutil | HardwareInfo.NetworkAdapterList |
哈希 | SHA-256 | System.Security.Cryptography |
跨平台 | ||
管理员权限 | 不需要 | 不需要 |
如需进一步扩展(缓存、在线校验、加密传输),可直接在 StableHardwareID() 结果之上继续封装。
猜你喜欢
- 2025-10-14 微软工程师不会告诉你的.NET8秘密:如何用C#榨干CPU性能?
- 2025-10-14 如何使用 Spire.PDF 在 C# 中创建和绘制 PDF
- 2024-08-09 .NET LINQ分析AWS ELB日志避免996
- 2024-08-09 探索编程之美:揭秘LINQ、Lambda和表达式树的神奇能力
- 2024-08-09 LINQ(1-5)操作SQL数据库案例练习-C#LINQ基础学习
- 2024-08-09 LINQ(1-4)操作SQL数据库案例练习-C#LINQ基础学习
- 2024-08-09 问题:SQL 查询语句执行顺序是什么?
- 2024-08-09 SQL 查询并不是从 SELECT 开始的(sql查询语句条件不为0)
- 2024-08-09 LINQ(1-3)操作SQL数据库案例练习-C#LINQ基础学习
- 2024-08-09 LINQ并行执行扩展PLINQ链式调用语法(三)
- 最近发表
- 标签列表
-
- cmd/c (90)
- c++中::是什么意思 (84)
- 标签用于 (71)
- 主键只能有一个吗 (77)
- c#console.writeline不显示 (95)
- pythoncase语句 (88)
- es6includes (74)
- sqlset (76)
- apt-getinstall-y (100)
- node_modules怎么生成 (87)
- chromepost (71)
- flexdirection (73)
- c++int转char (80)
- mysqlany_value (79)
- static函数和普通函数 (84)
- el-date-picker开始日期早于结束日期 (76)
- js判断是否是json字符串 (75)
- c语言min函数头文件 (77)
- asynccallback (87)
- localstorage.removeitem (77)
- vector线程安全吗 (70)
- java (73)
- js数组插入 (83)
- mac安装java (72)
- 无效的列索引 (74)