好友
阅读权限10
听众
最后登录1970-1-1
|
500吾爱币
以下是从win11 x64版获取 pidgenx.dll获取代码,下面代码是使用GetkeyData调用读取rdi内存数据获取
[C#] 纯文本查看 复制代码 using Reloaded.Hooks;
using Reloaded.Hooks.Definitions;
using Reloaded.Hooks.Definitions.Enums;
using Reloaded.Memory.Utilities;
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
// 移除多余的 Reloaded.Hooks.Definitions 引用(4.3 无需,避免冲突)
class Program
{
#region 1. 原生P/Invoke委托与API定义(无修改,适配Winapi)
[UnmanagedFunctionPointer(CallingConvention.Winapi, CharSet = CharSet.Unicode)]
public delegate int GetPKeyDataDelegate(
string productKey,
IntPtr formatArg,
string skuOrChannel,
IntPtr formatArg2,
int flags,
out IntPtr outDataBlob,
out IntPtr outString1,
out IntPtr outString2,
out IntPtr outString3,
int extraFlag
);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
public unsafe delegate long Sub_7FFBB9DBF60CDelegate(
IntPtr a1,
IntPtr a2,
IntPtr a3,
IntPtr a4, // volatile int*
IntPtr lpMem // const wchar_t**(核心解析目标)
);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
[DllImport("kernel32.dll")]
static extern IntPtr GetProcessHeap();
[DllImport("kernel32.dll")]
static extern bool HeapFree(IntPtr hHeap, int flags, IntPtr mem);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool FreeLibrary(IntPtr hModule);
#endregion
#region 2. Hook核心配置(基址+固定偏移量,全局Hook实例)
private const int HOOK_OFFSET = 0x2F924; // ← 正确的 mov rdi,[rbp-41] // 你的固定偏移量0x2F60C
//===================使用asmhook========================
private static IAsmHook _asmHook;
private static ReloadedHooks _hooksInstance;
private static IntPtr _callbackPtr;
private static IntPtr hMod = IntPtr.Zero;
//===================使用asmhook========================
#endregion
static void Main()
{
string productKey = "VD6RP-R2NK7-HBG8F-3DJ8T-KTPKM";
string pkeyConfigXml = AppDomain.CurrentDomain.BaseDirectory + "pkconfig_winNext.xrm-ms";
hMod = IntPtr.Zero;
IntPtr pkeyConfigPtr = IntPtr.Zero;
NativeState.LastMsftPtr = Marshal.AllocHGlobal(8);
Marshal.WriteInt64(NativeState.LastMsftPtr, 0);
try
{
// 加载pidgenx.dll并获取基址
hMod = LoadLibrary("pidgenx.dll");
if (hMod == IntPtr.Zero)
{
Console.WriteLine($"❌ 加载pidgenx.dll失败,错误码:0x{Marshal.GetLastWin32Error():X8}");
return;
}
Console.WriteLine($"✅ pidgenx.dll 64位加载基址:0x{hMod.ToString("X16")}");
// 动态计算Hook地址(核心:基址 + 固定偏移量,适配ASLR)
IntPtr hookAddress = IntPtr.Add(hMod, HOOK_OFFSET);
Console.WriteLine($"✅ 动态计算Hook实际地址:0x{hookAddress.ToString("X16")}(基址+0x{HOOK_OFFSET:X})");
Console.WriteLine($"[+] LastMsftPtr(native) = 0x{NativeState.LastMsftPtr.ToInt64():X16}");
// 3️⃣ 创建 AsmHook
InstallAsmHook(hookAddress.ToInt64());
// 初始化GetPKeyData委托,执行原始逻辑
IntPtr fnGetPKeyData = GetProcAddress(hMod, "GetPKeyData");
if (fnGetPKeyData == IntPtr.Zero)
{
Console.WriteLine($"❌ 获取GetPKeyData地址失败,错误码:0x{Marshal.GetLastWin32Error():X8}");
return;
}
var getPKeyData = Marshal.GetDelegateForFunctionPointer<GetPKeyDataDelegate>(fnGetPKeyData);
// 准备参数并执行GetPKeyData
pkeyConfigPtr = Marshal.StringToHGlobalUni(pkeyConfigXml);
IntPtr outBlob = IntPtr.Zero, outStr1 = IntPtr.Zero, outStr2 = IntPtr.Zero, outStr3 = IntPtr.Zero;
Console.WriteLine("\n📌 按任意键执行GetPKeyData,Hook将自动拦截并解析数据...");
Console.ReadKey();
int hr = getPKeyData(
productKey,
pkeyConfigPtr,
null,
IntPtr.Zero,
0,
out outBlob,
out outStr1,
out outStr2,
out outStr3,
0
);
// 输出GetPKeyData执行结果
if (hr >= 0)
{
Console.WriteLine("\n✅ GetPKeyData执行成功,原始返回结果:");
Console.WriteLine($"outStr1密钥描述: {Marshal.PtrToStringUni(outStr1) ?? "空"}");
Console.WriteLine($"outStr2密钥通道: {Marshal.PtrToStringUni(outStr2) ?? "空"}");
Console.WriteLine($"outStr3密钥子类型: {Marshal.PtrToStringUni(outStr3) ?? "空"}");
Console.WriteLine($"outBlobIID唯一标识: {Marshal.PtrToStringUni(outBlob) ?? "空"}");
}
else
{
Console.WriteLine($"\n❌ GetPKeyData执行失败,错误码:0x{hr:X8}");
}
IntPtr msftPtr = Marshal.ReadIntPtr(NativeState.LastMsftPtr);
if (msftPtr != IntPtr.Zero)
{
string s = Marshal.PtrToStringUni(msftPtr);
Console.WriteLine($"[AdtConfigKeg:] {s}");
}
// 释放GetPKeyData返回的堆内存
IntPtr heap = GetProcessHeap();
if (outStr1 != IntPtr.Zero) HeapFree(heap, 0, outStr1);
if (outStr2 != IntPtr.Zero) HeapFree(heap, 0, outStr2);
if (outStr3 != IntPtr.Zero) HeapFree(heap, 0, outStr3);
if (outBlob != IntPtr.Zero) HeapFree(heap, 0, outBlob);
}
catch (Exception ex)
{
Console.WriteLine($"\n❌ 程序全局异常:{ex.Message}\n{ex.StackTrace}");
}
finally
{
// 安全释放所有资源,避免泄漏
if (_asmHook != null && _asmHook.IsEnabled)
{
_asmHook?.Disable();
Console.WriteLine("\n✅ Reloaded.Hooks 4.3 已安全释放");
}
Marshal.FreeHGlobal(NativeState.LastMsftPtr);
if (pkeyConfigPtr != IntPtr.Zero) Marshal.FreeHGlobal(pkeyConfigPtr);
if (hMod != IntPtr.Zero) FreeLibrary(hMod); // 释放DLL句柄
Console.WriteLine("✅ 所有资源已释放完毕,按任意键退出...");
Console.ReadKey();
}
}
private static void InstallAsmHook(long hookAddress)
{
/*
* 栈布局说明:
* - push 8 个非易失寄存器 = 64 字节
* - sub rsp, 20h = shadow space
*
* 原始 RSP = 当前 rsp + 20h + 8*8
*/
var asm = new[]
{
"use64",
// rdi = msft2009 wchar_t*
$"mov rax, {NativeState.LastMsftPtr.ToInt64()}",
"mov [rax], rdi",
};
_hooksInstance = new ReloadedHooks();
_asmHook = _hooksInstance.CreateAsmHook(
asm,
hookAddress,
AsmHookBehaviour.ExecuteFirst
).Activate();
Console.WriteLine("[+] AsmHook 激活成功");
}
static class NativeState
{
public static IntPtr LastMsftPtr;
}
}
以下是从x86版获取 ProductKeyUtilities.dll 获取代码,另外此版还可调用pidgenx偏移hook传入参数也可获取,下面代码是使用GetkeyData调用读取rdi内存数据获取
[C#] 纯文本查看 复制代码 using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using Reloaded.Hooks;
using Reloaded.Hooks.Definitions;
// 必须导入:FunctionAttribute/Registers 所在命名空间(修复特性缺失的核心)
using Reloaded.Hooks.Definitions.X86;
namespace 密钥检测关键字符串Hook
{
class Program
{
#region 核心配置(保持你的偏移0xA981,统一注释说明)
private const string TARGET_DLL = "ProductKeyUtilities.dll"; // 目标系统DLL
private const int GET_PKEYDATA_HOOK_OFFSET = 0xA981; // Hook偏移:GetPKeyData+0xA981(对应sub_7BBCA981)
private const int VALID_HOOK_CALL_COUNT = 2; // 有效拦截次数:第三次调用
private const string TARGET_MATCH_STR = "msft2009"; // 目标匹配字符串
private const string TEST_PRODUCT_KEY = "VK7JG-NPHTM-C97JM-9MPGT-3V66T"; // 测试产品密钥
#endregion
#region 1. GetPKeyData原生函数委托(StdCall,无修改)
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
private delegate int DelegateGetPKeyData(
string ProductKey,
string PkeyConfigPath,
string MPCID,
string pwszPKeyAlgorithm,
IntPtr OemId,
IntPtr OtherId,
out string IID,
out string Description,
out string channel,
out string subType,
StringBuilder PID
);
#endregion
#region 2. 【核心修复】sub_7BBCA981 Hook委托(添加FunctionAttribute,适配__fastcall)
// 保留UnmanagedFunctionPointer,适配.NET Marshal封送
[Function(CallingConventions.Fastcall)]
private delegate int HookTargetFuncDelegate(int a1, int a2); // 原生:int __fastcall sub_7BBCA981(int a1, int a2)
#endregion
#region 全局变量(Hook实例/委托/模块句柄/调用计数器,无修改)
private static IHook<HookTargetFuncDelegate> _hookTargetFunc; // Hook实例(4.3.3泛型版)
private static DelegateGetPKeyData _nativeGetPKeyData; // GetPKeyData原生委托
private static IntPtr _hModule = IntPtr.Zero; // 目标DLL模块句柄
private static int _hookCallCount = 0; // Hook调用计数器(线程安全)
#endregion
static void Main(string[] args)
{
Console.WriteLine("===== ProductKeyUtilities.dll Hook & Call 开始 =====");
try
{
// 步骤1:加载目标DLL,获取模块句柄
_hModule = LoadLibrary(TARGET_DLL);
if (_hModule == IntPtr.Zero)
{
PrintError($"加载{TARGET_DLL}失败", Marshal.GetLastWin32Error());
return;
}
Console.WriteLine($"✅ 加载{TARGET_DLL}成功,模块基址:0x{_hModule.ToString("X8")}");
// 步骤2:获取GetPKeyData导出函数地址,封送为C#委托
IntPtr getPKeyDataAddr = GetProcAddress(_hModule, "GetPKeyData");
if (getPKeyDataAddr == IntPtr.Zero)
{
PrintError($"获取GetPKeyData地址失败", Marshal.GetLastWin32Error());
FreeLibrary(_hModule);
return;
}
_nativeGetPKeyData = Marshal.GetDelegateForFunctionPointer<DelegateGetPKeyData>(getPKeyDataAddr);
Console.WriteLine($"✅ 获取GetPKeyData地址成功:0x{getPKeyDataAddr.ToString("X8")}");
// 步骤3:【核心修复】计算正确Hook地址(GetPKeyData函数地址 + 偏移,而非模块基址+偏移)
IntPtr hookTargetAddr = IntPtr.Add(_hModule, GET_PKEYDATA_HOOK_OFFSET);
Console.WriteLine($"✅ 计算Hook目标地址成功sub_7BBCA981 [GetPKeyData+{GET_PKEYDATA_HOOK_OFFSET:X4}]:0x{hookTargetAddr.ToString("X8")}");
// 步骤4:创建并启用Hook(Reloaded.Hooks 4.3.3标准写法,无修改)
var hookFactory = new ReloadedHooks();
_hookTargetFunc = hookFactory.CreateHook<HookTargetFuncDelegate>(
HookedGetPKeyData_981,
hookTargetAddr.ToInt64()
);
_hookTargetFunc.Activate();
Console.WriteLine($"✅ sub_7BBCA981 Hook启用成功,等待调用触发...\n");
// 步骤5:调用GetPKeyData原生函数,触发Hook拦截(无修改)
CallGetPKeyData();
// 步骤6:卸载Hook,恢复原生函数逻辑(4.3.3版本核心:Disable())
_hookTargetFunc?.Disable();
Console.WriteLine($"\n✅ Hook已禁用,恢复原生sub_7BBCA981执行逻辑");
}
catch (Exception ex)
{
Console.WriteLine($"❌ 程序执行异常:{ex.Message}\n{ex.StackTrace}");
}
finally
{
// 最终释放所有非托管资源(优化:避免重复Disable())
if (_hookTargetFunc != null)
{
try { _hookTargetFunc.Disable(); } catch { }
}
if (_hModule != IntPtr.Zero) FreeLibrary(_hModule);
Console.WriteLine($"\n✅ 所有非托管资源已释放,程序执行完成");
}
Console.WriteLine("\n按任意键退出程序...");
Console.ReadKey();
}
static int count = 0;
#region Hook拦截函数(匹配2个int参数,无修改)
private static int HookedGetPKeyData_981(int a1, int a2)
{
IntPtr pA1 = (IntPtr)a1;
IntPtr pA2 = (IntPtr)a2;
// 1️⃣ 直接检测 a1
if (TryPrintIfMatch(pA1, "a1 (ECX)"))
return _hookTargetFunc.OriginalFunction(a1, a2);
// 2️⃣ 检测 a2
if (TryPrintIfMatch(pA2, "a2 (EDX)"))
return _hookTargetFunc.OriginalFunction(a1, a2);
// 3️⃣ 检测 a1 + 0x14
if (pA1 != IntPtr.Zero)
{
try
{
IntPtr pExt = Marshal.ReadIntPtr(pA1, 0x14);
if (TryPrintIfMatch(pExt, "a1 + 0x14"))
return _hookTargetFunc.OriginalFunction(a1, a2);
}
catch { }
}
// 4️⃣ 什么都没命中 → 静默放行
return _hookTargetFunc.OriginalFunction(a1, a2);
}
private static bool TryPrintIfMatch(IntPtr ptr, string tag)
{
if (ptr == IntPtr.Zero)
return false;
// 地址基本合法性校验(32位)
long addr = ptr.ToInt64();
if (addr < 0x10000 || addr > 0x7FFFFFFF)
return false;
// 内存可读性探测
if (IsBadReadPtr(ptr, 2))
return false;
if (!TryReadUnicodeString(ptr, 256, out var str))
return false;
if (string.IsNullOrEmpty(str))
return false;
foreach (var key in TARGET_KEYS)
{
if (str.IndexOf(key, StringComparison.OrdinalIgnoreCase) >= 0)
{
Console.WriteLine("======================================");
Console.WriteLine($"🔥 命中关键字符串:{key}");
Console.WriteLine($"📍 来源:{tag}");
Console.WriteLine($"📌 地址:0x{ptr.ToString("X8")}");
string clean = TrimToReadableUnicode(str);
Console.WriteLine($"🧾 内容:{clean}");
Console.WriteLine($"📏 字符串长度:{clean.Length}");
Console.WriteLine("======================================\n");
return true;
}
}
return false;
}
private static readonly string[] TARGET_KEYS =
{
"msft2009",
"msft2005"
};
private static string TrimToReadableUnicode(string input)
{
if (string.IsNullOrEmpty(input))
return input;
var sb = new StringBuilder(input.Length);
foreach (char c in input)
{
// 合法可读字符范围
if (c == '\0')
break;
if (c >= 0x20 && c <= 0x7E || // ASCII
c >= 0x4E00 && c <= 0x9FFF) // CJK
{
sb.Append(c);
}
else
{
break; // 一旦进入二进制,直接截断
}
}
return sb.ToString();
}
private static bool TryReadUnicodeString(
IntPtr ptr,
int maxChars,
out string result)
{
result = null;
if (ptr == IntPtr.Zero)
return false;
long addr = ptr.ToInt64();
if (addr < 0x10000 || addr > 0x7FFFFFFF)
return false;
var sb = new StringBuilder();
for (int i = 0; i < maxChars; i++)
{
IntPtr cur = IntPtr.Add(ptr, i * 2);
// 每次只探测 2 字节(一个 WCHAR)
if (IsBadReadPtr(cur, 2))
break;
char c;
try
{
c = (char)Marshal.ReadInt16(cur);
}
catch
{
break;
}
if (c == '\0')
break;
sb.Append(c);
}
if (sb.Length == 0)
return false;
result = sb.ToString();
return true;
}
#endregion
#region GetPKeyData调用逻辑(无修改,已修复PID=null问题)
private static void CallGetPKeyData()
{
Console.WriteLine("==================== 开始调用GetPKeyData ====================");
string productKey = TEST_PRODUCT_KEY;
string configPath = Path.Combine(Environment.CurrentDirectory, "pkconfig_winNext.xrm-ms");
StringBuilder pidSb = new StringBuilder(512);
string iid = null, description = null, channel = null, subType = null;
if (!File.Exists(configPath))
{
Console.WriteLine($"❌ 配置文件不存在:{configPath}");
Console.WriteLine($"提示:请将pkconfig_winNext.xrm-ms放在程序运行目录下");
return;
}
try
{
int retCode = _nativeGetPKeyData(
productKey, configPath, null, null, IntPtr.Zero, IntPtr.Zero,
out iid, out description, out channel, out subType, pidSb
);
if (retCode == 0)
{
Console.WriteLine("✅ GetPKeyData调用成功,结构化数据如下:");
Console.WriteLine($"产品密钥:{productKey}");
Console.WriteLine($"IID唯一标识:{iid ?? "空"}");
Console.WriteLine($"密钥描述:{description ?? "空"}");
Console.WriteLine($"密钥通道:{channel ?? "空"}");
Console.WriteLine($"密钥子类型:{subType ?? "空"}");
Console.WriteLine($"PID标识码:{pidSb.ToString() ?? "空"}");
}
else
{
PrintError($"GetPKeyData调用失败,返回码", retCode);
PrintError($"系统底层错误码", Marshal.GetLastWin32Error());
}
}
catch (Exception ex)
{
Console.WriteLine($"❌ 调用GetPKeyData异常:{ex.Message}");
}
finally
{
FreeNativeOutString(iid);
FreeNativeOutString(description);
FreeNativeOutString(channel);
FreeNativeOutString(subType);
}
Console.WriteLine("===============================================================");
}
#endregion
#region 辅助方法(无修改)
// 辅助函数:用系统API探测内存是否可读
[DllImport("kernel32.dll")]
private static extern bool IsBadReadPtr(IntPtr lp, uint ucb);
private static void FreeNativeOutString(string str)
{
if (!string.IsNullOrEmpty(str))
{
try
{
IntPtr strPtr = Marshal.StringToHGlobalUni(str);
Marshal.FreeCoTaskMem(strPtr);
}
catch { }
}
}
private static void PrintError(string msg, int errorCode)
{
Console.WriteLine($"❌ {msg}:0x{errorCode:X8}(十进制:{errorCode})");
}
#endregion
#region Kernel32.dll API导入(无修改)
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)]
private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool FreeLibrary(IntPtr hModule);
#endregion
}
}
以下是xml构建
[C#] 纯文本查看 复制代码 private const string AtoReqTemplate = @"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope
xmlns:soapenc=""http://schemas.xmlsoap.org/soap/encoding/""
xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/""
xmlns:xsd=""http://www.w3.org/2001/XMLSchema""
xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">
<soap:Body>
<RequestSecurityToken
xmlns=""http://schemas.xmlsoap.org/ws/2004/04/security/trust"">
<TokenType>ProductActivation</TokenType>
<RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</RequestType>
<UseKey>
<Values
xmlns:q1=""http://schemas.xmlsoap.org/ws/2004/04/security/trust"" soapenc:arrayType=""q1:TokenEntry[1]"">
<TokenEntry>
<Name>PublishLicense</Name>
<Value>{plxml}</Value>
</TokenEntry>
</Values>
</UseKey>
<Claims>
<Values
xmlns:q1=""http://schemas.xmlsoap.org/ws/2004/04/security/trust"" soapenc:arrayType=""q1:TokenEntry[14]"">
<TokenEntry>
<Name>BindingType</Name>
<Value>msft:rm/algorithm/hwid/4.0</Value>
</TokenEntry>
<TokenEntry>
<Name>Binding</Name>
<Value>{binding}</Value>
</TokenEntry>
<TokenEntry>
<Name>ProductKey</Name>
<Value>{pkey}</Value>
</TokenEntry>
<TokenEntry>
<Name>ProductKeyType</Name>
<Value>msft:rm/algorithm/pkey/2009</Value>
</TokenEntry>
<TokenEntry>
<Name>ProductKeyActConfigId</Name>
<Value>{act_config_id}</Value>
</TokenEntry>
<TokenEntry>
<Name>otherInfoPublic.licenseCategory</Name>
<Value>msft:sl/EUL/ACTIVATED/PUBLIC</Value>
</TokenEntry>
<TokenEntry>
<Name>otherInfoPrivate.licenseCategory</Name>
<Value>msft:sl/EUL/ACTIVATED/PRIVATE</Value>
</TokenEntry>
<TokenEntry>
<Name>otherInfoPublic.sysprepAction</Name>
<Value>rearm</Value>
</TokenEntry>
<TokenEntry>
<Name>otherInfoPrivate.sysprepAction</Name>
<Value>rearm</Value>
</TokenEntry>
<TokenEntry>
<Name>ClientInformation</Name>
<Value>SystemUILanguageId=1033;UserUILanguageId=1033;GeoId=244</Value>
</TokenEntry>
<TokenEntry>
<Name>ClientSystemTime</Name>
<Value>{systime}</Value>
</TokenEntry>
<TokenEntry>
<Name>ClientSystemTimeUtc</Name>
<Value>{utctime}</Value>
</TokenEntry>
<TokenEntry>
<Name>otherInfoPublic.secureStoreId</Name>
<Value>{secure_store_id}</Value>
</TokenEntry>
<TokenEntry>
<Name>otherInfoPrivate.secureStoreId</Name>
<Value>{secure_store_id}</Value>
</TokenEntry>
</Values>
</Claims>
</RequestSecurityToken>
</soap:Body>
</soap:Envelope>";
var actConfigId = Utils.XmlEscape($"actConfigId_byhook"); //我们hook到的那串字符串
var ProductKeyType = string.IsNullOrEmpty(actConfigId)? "msft:rm/algorithm/pkey/2009" : actConfigId.Contains("2009")? "msft:rm/algorithm/pkey/2009":"msft:rm/algorithm/pkey/2005";
var now = DateTime.Now;
var timestamp = Utils.FormatTimestamp(now);
var secureStoreId = Guid.NewGuid().ToString();
var binding = Utils.GenerateBinding();
// 检查 PL 是否已经转义过
string processedPl;
if (plXmlPublishLicense.StartsWith("<"))
{
// 如果已经转义过,直接使用,不要再调用 XmlEscape
processedPl = plXmlPublishLicense;
}
else
{
// 如果是原始 XML,则进行转义
processedPl = Utils.XmlEscape(plXmlPublishLicense);
}
var payload = AtoReqTemplate
.Replace("{plxml}", processedPl) //PublishLicense xml , 自己实机测试个密钥抓包提取,可采用固定值,注意同时配合服务器接口
.Replace("{binding}", binding) //硬件信息,可固定也可随机
.Replace("{pkey}", pkey) //密钥
.Replace("{act_config_id}", actConfigId) //我们hook到的那串字符串
.Replace("{systime}", timestamp) //本地时间(ISO 8601格式,带Z标识)
.Replace("{utctime}", timestamp) //utc时间(ISO 8601格式,带Z标识)
.Replace("{secure_store_id}", secureStoreId); //guid
.Replace("{ProductKeyType}", ProductKeyType); //actconfigid 类型2009或2005
// httpclient 请求接口和 请求参数,自己抓包
//随机硬件
public static string GenerateBinding()
{
// 16进制转字节数组
var fixedBytes = HexStringToBytes("2A0000000100020001000100000000000000010001000100");
// 生成18位随机字节(.NET 4.8 写法)
var randomBytes = new byte[18];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(randomBytes);
}
// 拼接固定字节和随机字节
var binding = new byte[fixedBytes.Length + randomBytes.Length];
Buffer.BlockCopy(fixedBytes, 0, binding, 0, fixedBytes.Length);
Buffer.BlockCopy(randomBytes, 0, binding, fixedBytes.Length, randomBytes.Length);
return Convert.ToBase64String(binding);
}
以下是msf2009 actconfigid算法
[C#] 纯文本查看 复制代码 using System;
using System.Collections.Generic;
using System.Numerics;
public class ProductKeyDecoder
{
public const string ALPHABET = "BCDFGHJKMPQRTVWXY2346789";
// 静态查找表:将字符直接映射到数值,避免 IndexOf 的 O(n) 搜索
private static readonly sbyte[] CharTable = new sbyte[128];
static ProductKeyDecoder()
{
for (int i = 0; i < 128; i++) CharTable[i] = -1;
for (int i = 0; i < ALPHABET.Length; i++) CharTable[ALPHABET[i]] = (sbyte)i;
}
public BigInteger Key { get; }
public long Group { get; }
public long Serial { get; }
public BigInteger Security { get; }
public int Upgrade { get; }
public ProductKeyDecoder(string key)
{
Key = Decode5x5(key);
// 位域解析(严格遵循 20, 30, 53, 1 的分布)
Group = (long)(Key & 0xFFFFF); // 20 bits
Serial = (long)((Key >> 20) & 0x3FFFFFFF); // 30 bits
Security = (Key >> 50) & ((BigInteger.One << 53) - 1); // 53 bits
Upgrade = (int)((Key >> 103) & 1); // 1 bit
}
public static BigInteger Decode5x5(string key)
{
string normalized = key.Replace("-", "").ToUpper();
if (normalized.Length != 25) throw new FormatException("Key must be 25 characters.");
// 必须严格保持顺序:N 对应的值作为第一个被计算的元素
int nIndex = normalized.IndexOf('N');
string dataPart = normalized.Replace("N", "");
BigInteger result = (BigInteger)nIndex; // N 的位置先入栈
foreach (char c in dataPart)
{
sbyte val = (c < 128) ? CharTable[c] : (sbyte)-1;
if (val == -1) throw new FormatException($"Invalid character: {c}");
// 核心算法:result = result * 24 + value
result = BigInteger.Add(BigInteger.Multiply(result, 24), (int)val);
}
return result;
}
public static string EncodeKeyData(long group, long serial, BigInteger security, int upgrade)
{
// 严格按照你原始逻辑中的位移重新拼装
// 1 (upgrade) | 30 (serial) | 20 (group) | 53 (security)
BigInteger actHash = (BigInteger)(upgrade & 1);
actHash |= (BigInteger)(serial & 0x3FFFFFFF) << 1;
actHash |= (BigInteger)(group & 0xFFFFF) << 31;
actHash |= (security & ((BigInteger.One << 53) - 1)) << 51;
byte[] bytes = actHash.ToByteArray();
// 修正:确保输出固定为 13 字节,且不丢失数据
byte[] result = new byte[13];
int copyLen = Math.Min(bytes.Length, 13);
Array.Copy(bytes, result, copyLen);
return Convert.ToBase64String(result);
}
}
public class ProductKeyDecoder2
{
public const string ALPHABET = "BCDFGHJKMPQRTVWXY2346789";
public BigInteger Key { get; }
public BigInteger Group { get; }
public BigInteger Serial { get; }
public BigInteger Security { get; }
public BigInteger Upgrade { get; }
public ProductKeyDecoder2(string key)
{
Key = Decode5x5(key, ALPHABET);
// 位域解析(实测正确)
Group = Key & ((BigInteger.One << 20) - 1);
Serial = (Key >> 20) & ((BigInteger.One << 30) - 1);
Security = (Key >> 50) & ((BigInteger.One << 53) - 1);
Upgrade = (Key >> 103) & 1;
}
/// <summary>
/// 修复后的5x5密钥解码逻辑(符合微软原版算法)
/// </summary>
public static BigInteger Decode5x5(string key, string alphabet)
{
key = key.Replace("-", "");
var dec = new List<int> { key.IndexOf('N') };
foreach (var l in key.Replace("N", ""))
{
dec.Add(alphabet.IndexOf(l));
}
BigInteger result = 0;
foreach (var x in dec)
{
result = (result * 24) + x;
}
return result;
}
/// <summary>
/// 修复后的密钥数据编码逻辑(修正字节序)
/// </summary>
public static string EncodeKeyData(BigInteger group, BigInteger serial, BigInteger security, BigInteger upgrade)
{
BigInteger actHash = upgrade & 1;
actHash |= (serial & ((1UL << 30) - 1)) << 1;
actHash |= (group & ((1UL << 20) - 1)) << 31;
actHash |= (security & ((1UL << 53) - 1)) << 51;
byte[] bytes = actHash.ToByteArray();
Array.Resize(ref bytes, 13);
return Convert.ToBase64String(bytes);
}
}
public class ProductKeyDecoder3
{
public const string ALPHABET = "BCDFGHJKMPQRTVWXY2346789";
private static readonly sbyte[] CharTable = new sbyte[128];
static ProductKeyDecoder3()
{
// 修复:手动循环初始化,兼容所有 .NET 版本
for (int i = 0; i < CharTable.Length; i++)
{
CharTable[i] = -1;
}
for (int i = 0; i < ALPHABET.Length; i++)
{
CharTable[ALPHABET[i]] = (sbyte)i;
}
}
public BigInteger Key { get; }
public int Group { get; }
public int Serial { get; }
public BigInteger Security { get; }
public int Upgrade { get; }
public ProductKeyDecoder3(string key)
{
if (string.IsNullOrEmpty(key)) throw new ArgumentNullException(nameof(key));
Key = Decode5x5(key);
// 位域解析
Group = (int)(Key & 0xFFFFF);
Serial = (int)((Key >> 20) & 0x3FFFFFFF);
Security = (Key >> 50) & ((BigInteger.One << 53) - 1);
Upgrade = (int)((Key >> 103) & 1);
}
public static BigInteger Decode5x5(string key)
{
// 兼容性优化:老版本 .NET 不支持 AsSpan,使用普通的字符串操作
string normalized = key.Replace("-", "").ToUpper();
if (normalized.Length != 25) throw new FormatException("密钥长度必须为 25 位");
int nIndex = normalized.IndexOf('N');
// 如果有 N,移除它以进行 Base24 转换
string dataPart = nIndex != -1 ? normalized.Replace("N", "") : normalized;
// N 的位置作为高位权重初始化
BigInteger result = nIndex != -1 ? (BigInteger)nIndex : BigInteger.Zero;
foreach (char c in dataPart)
{
sbyte val = (c < 128) ? CharTable[c] : (sbyte)-1;
if (val == -1) throw new FormatException($"密钥包含非法字符: {c}");
result = result * 24 + val;
}
return result;
}
public static string EncodeKeyData(int group, int serial, BigInteger security, int upgrade)
{
BigInteger actHash = (BigInteger)(upgrade & 1);
actHash |= (BigInteger)(serial & 0x3FFFFFFF) << 1;
actHash |= (BigInteger)(group & 0xFFFFF) << 31;
actHash |= (security & ((BigInteger.One << 53) - 1)) << 51;
byte[] rawBytes = actHash.ToByteArray();
// 确保输出 13 字节缓冲区
byte[] fixedBuffer = new byte[13];
int bytesToCopy = Math.Min(rawBytes.Length, 13);
Array.Copy(rawBytes, 0, fixedBuffer, 0, bytesToCopy);
return Convert.ToBase64String(fixedBuffer);
}
}
class Program
{
static void Main()
{
string key = "MT6QD-N6YPG-K7CG9-TCYFJ-HMH26";
var d = new ProductKeyDecoder(key);
Console.WriteLine("Key: " + d.Key);
Console.WriteLine("Group: " + d.Group); // 正确输出3308
Console.WriteLine("Serial: " + d.Serial);
Console.WriteLine("Security: " + d.Security);
Console.WriteLine("Upgrade: " + d.Upgrade);
string strbase64 = ProductKeyDecoder.EncodeKeyData(d.Group, d.Serial, d.Security, d.Upgrade);
Console.WriteLine("Base64: " + strbase64); // 正确输出hHe2EXYGGMG+BH8FWw==
Console.WriteLine();
//=============================
var d2 = new ProductKeyDecoder2(key);
Console.WriteLine("Key: " + d2.Key);
Console.WriteLine("Group: " + d2.Group); // 正确输出3308
Console.WriteLine("Serial: " + d2.Serial);
Console.WriteLine("Security: " + d2.Security);
Console.WriteLine("Upgrade: " + d2.Upgrade);
string strbase64_2 = ProductKeyDecoder2.EncodeKeyData(d2.Group, d2.Serial, d2.Security, d2.Upgrade);
Console.WriteLine("Base64: " + strbase64_2); // 正确输出hHe2EXYGGMG+BH8FWw==
Console.WriteLine();
//==============================
var d3 = new ProductKeyDecoder3(key);
Console.WriteLine("Key: " + d3.Key);
Console.WriteLine("Group: " + d3.Group); // 正确输出3308
Console.WriteLine("Serial: " + d3.Serial);
Console.WriteLine("Security: " + d3.Security);
Console.WriteLine("Upgrade: " + d3.Upgrade);
string strbase64_3 = ProductKeyDecoder3.EncodeKeyData(d3.Group, d3.Serial, d3.Security, d3.Upgrade);
Console.WriteLine("Base64: " + strbase64_3); // 正确输出hHe2EXYGGMG+BH8FWw==
Console.ReadKey();
}
}
以上则呢合并成能用的DLL或者NODE.JS,我传入一个格式为XXXXX-XXXXX-XXXXX-XXXXX-XXXXX获取返回值,返回信息例子如下
密钥: XXXXX-XXXXX-XXXXX-XXXXX-XXXXX类型: 密钥的版本PID: XXXXX-XXXXX-XXXXX-XXXXX
代码: 返回的代码次数: 返回的次数时间: 返回时的时间
|
|