Improve: client/server - stable client ID via MachineGuid+path (V2)
This commit is contained in:
@@ -225,7 +225,10 @@ std::string GetCurrentUserNameA()
|
||||
|
||||
#define XXH_INLINE_ALL
|
||||
#include "common/xxhash.h"
|
||||
// 基于客户端信息计算唯一ID: { IP, PC, OS, CPU, PATH }
|
||||
|
||||
// 老算法:基于客户端信息计算唯一ID: { IP, PC, OS, CPU, PATH }
|
||||
// 注意:pubIP 不稳定(DHCP/换网络)会让 ID 跳变;同 hostname+同安装路径的多机会撞库。
|
||||
// 保留此函数仅为协议兼容(老服务端仍按这个算法验算 RES_CLIENT_ID)。
|
||||
uint64_t CalcalateID(const std::vector<std::string>& clientInfo)
|
||||
{
|
||||
std::string s;
|
||||
@@ -236,6 +239,52 @@ uint64_t CalcalateID(const std::vector<std::string>& clientInfo)
|
||||
return XXH64(s.c_str(), s.length(), 0);
|
||||
}
|
||||
|
||||
// 读取 Windows 安装时生成的机器 GUID。
|
||||
// HKLM\Software\Microsoft\Cryptography\MachineGuid 是 Windows 安装时生成的随机 GUID,
|
||||
// 重装系统才会变;局域网每台机器都不同(即便同镜像,sysprep 也会重置)。
|
||||
// 这是比 pubIP/PCName/CPU 都更稳定且更具区分度的硬件标识。
|
||||
static std::string GetMachineGuidWindows()
|
||||
{
|
||||
HKEY hKey = NULL;
|
||||
// KEY_WOW64_64KEY: 32 位进程也访问 64 位注册表视图,避免 WOW6432Node 重定向。
|
||||
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
|
||||
"SOFTWARE\\Microsoft\\Cryptography",
|
||||
0, KEY_READ | KEY_WOW64_64KEY, &hKey) != ERROR_SUCCESS) {
|
||||
return std::string();
|
||||
}
|
||||
char buf[64] = {};
|
||||
DWORD sz = sizeof(buf) - 1; // 留 1 字节给 NUL
|
||||
DWORD type = 0;
|
||||
LSTATUS s = RegQueryValueExA(hKey, "MachineGuid", NULL, &type,
|
||||
(BYTE*)buf, &sz);
|
||||
RegCloseKey(hKey);
|
||||
if (s != ERROR_SUCCESS || type != REG_SZ) return std::string();
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
// 路径归一化:先尝试展开成长路径(如 PROGRA~1 -> Program Files),再小写化。
|
||||
// 用于 V2 ID 的输入,保证大小写或长短名变化时同一可执行文件得到同一 ID。
|
||||
static std::string NormalizeExePathLower(const char* path)
|
||||
{
|
||||
char longPath[MAX_PATH] = {};
|
||||
if (GetLongPathNameA(path, longPath, MAX_PATH) == 0) {
|
||||
// 展开失败(路径不存在等罕见情况):直接用原值
|
||||
strcpy_s(longPath, path);
|
||||
}
|
||||
CharLowerA(longPath); // 原地小写化(对 ASCII 简单,对中文路径会按宽字符规则处理)
|
||||
return std::string(longPath);
|
||||
}
|
||||
|
||||
// 新算法:machineGuid + 归一化路径
|
||||
// - 同机同程序:永远同 ID(不依赖 IP/PCName/OS/CPU)。
|
||||
// - 局域网多机相同镜像:MachineGuid 必不同 → ID 必不同。
|
||||
// - 一台机两份程序在不同目录 → ID 不同。
|
||||
uint64_t CalcalateIDv2(const std::string& machineGuid, const std::string& normalizedPath)
|
||||
{
|
||||
std::string s = machineGuid + "|" + normalizedPath;
|
||||
return XXH64(s.c_str(), s.length(), 0);
|
||||
}
|
||||
|
||||
BOOL IsAuthKernel(std::string &str) {
|
||||
BOOL isAuthKernel = FALSE;
|
||||
std::string pid = std::to_string(GetCurrentProcessId());
|
||||
@@ -332,7 +381,17 @@ LOGIN_INFOR GetLoginInfo(DWORD dwSpeed, CONNECT_ADDRESS& conn, const std::string
|
||||
LoginInfor.AddReserved(IsRunningAsAdmin());
|
||||
char cpuInfo[32];
|
||||
sprintf(cpuInfo, "%dMHz", dwCPUMHz);
|
||||
conn.clientID = CalcalateID({ pubIP, szPCName, LoginInfor.OsVerInfoEx, cpuInfo, buf });
|
||||
// V2 ID 算法:MachineGuid + 归一化路径
|
||||
// - 同机同程序路径永远同 ID(不依赖 IP/PCName/OS/CPU 漂移)
|
||||
// - 局域网多机即便同镜像(sysprep 会让 MachineGuid 各不同)也不撞库
|
||||
// MachineGuid 读取失败的极端情况退化到老算法,保兼容。
|
||||
std::string machineGuid = GetMachineGuidWindows();
|
||||
if (!machineGuid.empty()) {
|
||||
conn.clientID = CalcalateIDv2(machineGuid, NormalizeExePathLower(buf));
|
||||
} else {
|
||||
Mprintf("WARN: MachineGuid 读取失败,回退到老 ID 算法\n");
|
||||
conn.clientID = CalcalateID({ pubIP, szPCName, LoginInfor.OsVerInfoEx, cpuInfo, buf });
|
||||
}
|
||||
auto clientID = std::to_string(conn.clientID);
|
||||
Mprintf("此客户端的唯一标识为: %s\n", clientID.c_str());
|
||||
char reservedInfo[64];
|
||||
|
||||
Reference in New Issue
Block a user