This commit is contained in:
MelodyMaster
2025-07-16 22:36:15 +08:00
parent 31e3da7671
commit 7c3a774234
14 changed files with 671 additions and 104 deletions

View File

@ -0,0 +1,125 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Win32;
using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
namespace Testcaonimabi.Controllers
{
[ApiController]
[Route("/api/load-plugins")]
public class LoadPluginsApiController : ControllerBase
{
private const string RegKeyPath = @"Software\Nebulamist";
private const string KamiValueName = "Kami";
private const string HwidValueName = "Hwid";
private const string PLUGIN_LIST_URL = "https://gitee.com/livelyxuan/nebulamist/raw/master/ver.txt";
private const string DEPENDENCIES_LIST_URL = "https://gitee.com/livelyxuan/nebulamist/raw/master/dep.txt ";
private readonly IHttpClientFactory _httpClientFactory;
public LoadPluginsApiController(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
[HttpGet]
public async Task<IActionResult> Get()
{
try
{
string kami = ReadRegistryValue(KamiValueName);
string hwid = ReadRegistryValue(HwidValueName);
if (string.IsNullOrEmpty(kami) || string.IsNullOrEmpty(hwid))
{
return Ok(new { success = false, message = <>ҵ<EFBFBD>ע<EFBFBD><D7A2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>" });
}
bool isValid = await ValidateKamiAsync(kami, hwid);
if (!isValid)
{
return Ok(new { success = false, message = "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֤ʧ<D6A4><CAA7>" });
}
await DownloadPluginsAsync();
return Ok(new { success = true, message = "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɣ<EFBFBD>" });
}
catch (Exception ex)
{
return StatusCode(500, new { success = false, message = "<22><><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>: " + ex.Message });
}
}
private string ReadRegistryValue(string valueName)
{
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(RegKeyPath))
{
return key?.GetValue(valueName) as string;
}
}
private async Task<bool> ValidateKamiAsync(string kami, string hwid)
{
var client = _httpClientFactory.CreateClient();
var url = $"http://127.0.0.1:5678/login?kami={Uri.EscapeDataString(kami)}&hwid={Uri.EscapeDataString(hwid)}";
var response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var json = await response.Content.ReadFromJsonAsync<ApiResponse>();
return json?.Success == true;
}
return false;
}
private async Task DownloadPluginsAsync()
{
var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
var pluginsDir = Path.Combine(appData, "EXILED", "Plugins");
var dependenciesDir = Path.Combine(pluginsDir, "dependencies");
Directory.CreateDirectory(pluginsDir);
Directory.CreateDirectory(dependenciesDir);
var client = _httpClientFactory.CreateClient();
// <20><><EFBFBD>ز<EFBFBD><D8B2><EFBFBD><EFBFBD>б<EFBFBD>
var pluginList = await client.GetStringAsync(PLUGIN_LIST_URL);
var lines = pluginList.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
if (lines.Length < 2)
throw new Exception("<22><><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD><D0B1><EFBFBD>ʽ<EFBFBD><CABD><EFBFBD><EFBFBD>");
var pluginUrl = lines[1];
var pluginName = Path.GetFileName(new Uri(pluginUrl).LocalPath);
var pluginPath = Path.Combine(pluginsDir, pluginName);
var pluginBytes = await client.GetByteArrayAsync(pluginUrl);
await System.IO.File.WriteAllBytesAsync(pluginPath, pluginBytes);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD>
var dependenciesList = await client.GetStringAsync(DEPENDENCIES_LIST_URL);
var dependencyUrls = dependenciesList.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var depUrl in dependencyUrls)
{
var depName = Path.GetFileName(new Uri(depUrl).LocalPath);
var depPath = Path.Combine(dependenciesDir, depName);
var depBytes = await client.GetByteArrayAsync(depUrl);
await System.IO.File.WriteAllBytesAsync(depPath, depBytes);
}
}
private class ApiResponse
{
public bool Success { get; set; }
public string Message { get; set; }
}
}
}

View File

@ -0,0 +1,105 @@
@page
@model Testcaonimabi.Pages.DashboardModel
@{
Layout = null;
ViewData["Title"] = "仪表盘";
}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewData["Title"]</title>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;500;700&display=swap" rel="stylesheet">
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: 'Poppins', sans-serif;
}
body {
background: linear-gradient(135deg, #4e54c8, #8f94fb);
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
color: white;
}
.dashboard-card {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border-radius: 16px;
padding: 40px;
width: 100%;
max-width: 400px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
text-align: center;
}
h2 {
font-size: 24px;
margin-bottom: 20px;
font-weight: 600;
}
button {
width: 100%;
padding: 12px;
background-color: rgba(255, 255, 255, 0.3);
color: white;
border: none;
border-radius: 8px;
font-size: 16px;
cursor: pointer;
transition: background 0.3s ease;
}
button:hover {
background-color: rgba(255, 255, 255, 0.4);
}
.status {
margin-top: 20px;
font-size: 14px;
color: #ccc;
}
</style>
</head>
<body>
<div class="dashboard-card">
<h2>✅ 欢迎使用 Nebulamist</h2>
<button onclick="loadPlugins()">加载插件</button>
<div class="status" id="status">等待操作...</div>
</div>
<script>
async function loadPlugins() {
const status = document.getElementById('status');
status.textContent = '正在验证注册表...';
try {
const res = await fetch('/api/load-plugins');
const data = await res.json();
if (data.success) {
status.textContent = data.message || '插件加载完成!';
} else {
status.textContent = '验证失败,即将跳转登录页...';
setTimeout(() => {
window.location.href = '/Index';
}, 1500);
}
} catch (err) {
status.textContent = '请求失败: ' + err.message;
console.error(err);
}
}
</script>
</body>
</html>

View File

@ -0,0 +1,71 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Win32;
using System.Net.Http;
using System.Threading.Tasks;
namespace Testcaonimabi.Pages
{
public class DashboardModel : PageModel
{
private const string RegKeyPath = @"Software\Nebulamist";
private const string KamiValueName = "Kami";
private const string HwidValueName = "Hwid";
private readonly IHttpClientFactory _httpClientFactory;
public DashboardModel(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public async Task<IActionResult> OnGet()
{
string kami = ReadRegistryValue(KamiValueName);
string hwid = ReadRegistryValue(HwidValueName);
if (string.IsNullOrEmpty(kami) || string.IsNullOrEmpty(hwid))
{
return RedirectToPage("/Index");
}
bool isValid = await ValidateKamiAsync(kami, hwid);
if (!isValid)
{
return RedirectToPage("/Index");
}
return Page();
}
private string ReadRegistryValue(string valueName)
{
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(RegKeyPath))
{
return key?.GetValue(valueName) as string;
}
}
private async Task<bool> ValidateKamiAsync(string kami, string hwid)
{
var client = _httpClientFactory.CreateClient();
var url = $"http://127.0.0.1:5678/login?kami={Uri.EscapeDataString(kami)}&hwid={Uri.EscapeDataString(hwid)}";
var response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var json = await response.Content.ReadFromJsonAsync<ApiResponse>();
return json?.Success == true;
}
return false;
}
private class ApiResponse
{
public bool Success { get; set; }
public string Message { get; set; }
}
}
}

View File

@ -1,26 +0,0 @@
@page
@model ErrorModel
@{
ViewData["Title"] = "Error";
}
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
@if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}
<h3>Development Mode</h3>
<p>
Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>

View File

@ -1,28 +0,0 @@
using System.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace Testcaonimabi.Pages
{
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
private readonly ILogger<ErrorModel> _logger;
public ErrorModel(ILogger<ErrorModel> logger)
{
_logger = logger;
}
public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
}
}
}

View File

@ -1,10 +1,154 @@
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
Layout = null; // 隐藏默认布局Home / Privacy 等链接)
ViewData["Title"] = "卡密登录";
}
<div class="text-center">
<h1 class="display-4">你好</h1>
<p>您的机器码 @IndexModel.HwidOK</p>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewData["Title"]</title>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;500;700&display=swap" rel="stylesheet">
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: 'Poppins', sans-serif;
}
body {
background: linear-gradient(135deg, #4e54c8, #8f94fb);
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
color: white;
}
.login-card {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border-radius: 16px;
padding: 40px 30px;
width: 100%;
max-width: 400px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
text-align: center;
}
h2 {
font-size: 24px;
margin-bottom: 20px;
font-weight: 600;
}
input[type="text"] {
width: 100%;
padding: 12px 15px;
margin: 15px 0;
border: none;
border-radius: 8px;
outline: none;
font-size: 16px;
background: rgba(255, 255, 255, 0.2);
color: white;
transition: all 0.3s ease;
}
input[type="text"]:focus {
background: rgba(255, 255, 255, 0.3);
box-shadow: 0 0 8px rgba(255, 255, 255, 0.4);
}
button {
width: 100%;
padding: 12px;
background-color: rgba(255, 255, 255, 0.3);
color: white;
border: none;
border-radius: 8px;
font-size: 16px;
cursor: pointer;
transition: background 0.3s ease;
}
button:hover {
background-color: rgba(255, 255, 255, 0.4);
}
.result {
margin-top: 20px;
font-size: 15px;
font-weight: 500;
}
.success {
color: #a8e6cf;
}
.error {
color: #ffaaa5;
}
</style>
</head>
<body>
<div class="login-card">
<h2>卡密登录</h2>
<input type="text" id="kamiInput" placeholder="请输入卡密" />
<button onclick="login()">登录</button>
<div class="result" id="resultMessage"></div>
</div>
<script>
// 混淆变量名,增加阅读难度
const _k = 'kamiInput';
const _r = 'resultMessage';
const _s = 'success';
const _e = 'error';
function login() {
const k = document.getElementById(_k).value.trim();
const hwid = '@IndexModel.HwidOK';
const resultDiv = document.getElementById(_r);
if (!k) {
resultDiv.textContent = '卡密不能为空';
resultDiv.className = 'result ' + _e;
return;
}
const url = `http://127.0.0.1:5678/login?kami=${encodeURIComponent(k)}&hwid=${encodeURIComponent(hwid)}`;
fetch(url)
.then(res => {
if (!res.ok) throw new Error('网络异常');
return res.json();
})
.then(data => {
if (data[_s]) {
resultDiv.textContent = data.message || '登录成功';
resultDiv.className = 'result ' + _s;
setTimeout(() => {
window.location.href = `/LoginSuccessModel?kami=${encodeURIComponent(k)}`; // 登录成功后跳转页面
}, 1500);
} else {
resultDiv.textContent = data.message || '登录失败';
resultDiv.className = 'result ' + _e;
}
})
.catch(err => {
console.error(err);
resultDiv.textContent = '请求失败,请检查网络或重试';
resultDiv.className = 'result ' + _e;
});
}
</script>
</body>
</html>

View File

@ -1,24 +1,81 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Win32;
using System.Net.Http;
using System.Threading.Tasks;
namespace Testcaonimabi.Pages
{
public class IndexModel : PageModel
{
public static string HwidOK { get; private set; }
private readonly ILogger<IndexModel> _logger;
private const string RegKeyPath = @"Software\Nebulamist";
private const string KamiValueName = "Kami";
private const string HwidValueName = "Hwid";
public IndexModel(ILogger<IndexModel> logger)
private readonly IHttpClientFactory _httpClientFactory;
public IndexModel(IHttpClientFactory httpClientFactory)
{
_logger = logger;
_httpClientFactory = httpClientFactory;
}
public void OnGet()
public static string HwidOK { get; private set; }
public async Task<IActionResult> OnGet()
{
// <20><>ע<EFBFBD><D7A2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ kami <20><> hwid
string kami = ReadRegistryValue(KamiValueName);
string hwid = ReadRegistryValue(HwidValueName);
HwidOK = Melody.Start.Start.Hwid;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڿ<EFBFBD><DABF>ܺ<EFBFBD> hwid<69><64><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD>¼
if (!string.IsNullOrEmpty(kami) && !string.IsNullOrEmpty(hwid))
{
bool isValid = await ValidateKamiAsync(kami, hwid);
if (isValid)
{
// <20><>֤<EFBFBD>ɹ<EFBFBD><C9B9><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><D7AA><EFBFBD>DZ<EFBFBD><C7B1><EFBFBD>
return RedirectToPage("/Dashboard");
}
}
// ע<><D7A2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><C3BB><EFBFBD><EFBFBD>Ч<EFBFBD><D0A7><EFBFBD>ܣ<EFBFBD><DCA3><EFBFBD>ʾ<EFBFBD><CABE>¼ҳ<C2BC><D2B3>
return Page();
}
private string ReadRegistryValue(string valueName)
{
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(RegKeyPath))
{
return key?.GetValue(valueName) as string;
}
}
private async Task<bool> ValidateKamiAsync(string kami, string hwid)
{
try
{
var client = _httpClientFactory.CreateClient();
var url = $"http://127.0.0.1:5678/login?kami={Uri.EscapeDataString(kami)}&hwid={Uri.EscapeDataString(hwid)}";
var response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var json = await response.Content.ReadFromJsonAsync<ApiResponse>();
return json?.Success == true;
}
}
catch
{
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><ECB3A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>
}
return false;
}
private class ApiResponse
{
public bool Success { get; set; }
public string Message { get; set; }
}
}
}
}

View File

@ -0,0 +1,82 @@
@page
@model Testcaonimabi.Pages.LoginSuccessModel
@{
Layout = null; // 不使用默认布局
ViewData["Title"] = "验证已完成";
}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewData["Title"]</title>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;500;700&display=swap" rel="stylesheet">
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: 'Poppins', sans-serif;
}
body {
background: linear-gradient(135deg, #4e54c8, #8f94fb);
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
color: white;
text-align: center;
}
.success-box {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border-radius: 16px;
padding: 40px;
max-width: 400px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
}
.success-box h1 {
font-size: 28px;
margin-bottom: 20px;
}
.success-box p {
font-size: 16px;
margin-bottom: 10px;
}
.countdown {
font-weight: bold;
margin-top: 20px;
color: #a8e6cf;
}
</style>
</head>
<body>
<div class="success-box">
<h1>✅ 验证已完成</h1>
<p>卡密:<strong>@ViewData["Kami"]</strong></p>
<p>即将跳转到仪表盘...</p>
<div class="countdown" id="countdown">3 秒后跳转</div>
</div>
<script>
let timeLeft = 10;
const countdown = document.getElementById('countdown');
const timer = setInterval(() => {
timeLeft--;
if (timeLeft <= 0) {
clearInterval(timer);
window.location.href = '/Dashboard';
} else {
countdown.textContent = `${timeLeft} 秒后跳转`;
}
}, 1000);
</script>
</body>
</html>

View File

@ -0,0 +1,27 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace Testcaonimabi.Pages
{
public class LoginSuccessModel : PageModel
{
[BindProperty(SupportsGet = true)]
public string Kami { get; set; }
public IActionResult OnGet()
{
if (string.IsNullOrEmpty(Kami))
{
return Page(); // <20><>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ
}
// ִ<><D6B4><EFBFBD><EFBFBD><EFBFBD>ķ<EFBFBD><C4B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߼<EFBFBD>
VerifyOK.OK(Kami);
// <20><><EFBFBD><EFBFBD> ViewData <20><>ҳ<EFBFBD><D2B3>ʹ<EFBFBD><CAB9>
ViewData["Kami"] = Kami;
return Page();
}
}
}

View File

@ -1,8 +0,0 @@
@page
@model PrivacyModel
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>

View File

@ -1,20 +0,0 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace Testcaonimabi.Pages
{
public class PrivacyModel : PageModel
{
private readonly ILogger<PrivacyModel> _logger;
public PrivacyModel(ILogger<PrivacyModel> logger)
{
_logger = logger;
}
public void OnGet()
{
}
}
}

View File

@ -8,7 +8,8 @@ var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddHttpClient();
builder.Services.AddControllers(); // <20><><EFBFBD>ڲ<EFBFBD><DAB2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> API
var app = builder.Build();
// Configure the HTTP request pipeline.
@ -21,7 +22,7 @@ if (!app.Environment.IsDevelopment())
app.UseHttpsRedirection();
app.UseStaticFiles();
app.MapControllers(); //
app.UseRouting();
app.UseAuthorization();

View File

@ -1,5 +1,6 @@
using Hardware.Info;
using Microsoft.Win32;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Text;
@ -25,6 +26,8 @@ static class Mysql
}
}
@ -33,8 +36,8 @@ static class Mysql
static class Start
{
private const string RegKeyPath = @"Software\hwid";
private const string RegValueName = "hwid";
private const string RegKeyPath = @"Software\Nebulamist";
private const string RegValueName = "Hwid";
// AES 密钥和 IV请自行更换为安全的值
private static readonly byte[] AesKey = Encoding.UTF8.GetBytes("NipjYde7wp4iCFW7Mfdw0PwdHR4CURpQ");
@ -54,7 +57,7 @@ static class Start
//Console.WriteLine("硬盘序列号: " + diskSerial);
// 拼接 HWID
string hwid = $"CPU ID{cpuId}|Motherboard:{motherboardSerial}|Bios:{biosUuid}|Disk:{diskSerial}128Code:{ReadRegistryValue()}";
string hwid = $"32Code:{ReadRegistryValue()}";
byte[] hwidBytes = Encoding.UTF8.GetBytes(hwid);
string hwidHex = BitConverter.ToString(hwidBytes).Replace("-", "");
@ -70,7 +73,7 @@ static class Start
if (!string.IsNullOrEmpty(existingFingerprint))
{
Console.WriteLine("随机128位字符(来自注册表): " + existingFingerprint);
//Console.WriteLine("随机32位字符(来自注册表): " + existingFingerprint);
return;
}
@ -80,10 +83,15 @@ static class Start
// 写入注册表
WriteRegistryValue(random128);
//Console.WriteLine("指纹已写入注册表HKEY_CURRENT_USER\\" + RegKeyPath);
}
Console.WriteLine("检测到程序第一次打开 请重新启动");
//重启程序
Environment.Exit(2333);
static string GetCpuId()
//Console.WriteLine("指纹已写入注册表HKEY_CURRENT_USER\\" + RegKeyPath);
}
static string GetCpuId()
{
var info = new HardwareInfo();
info.RefreshAll();

29
Testcaonimabi/VerifyOK.cs Normal file
View File

@ -0,0 +1,29 @@
using Microsoft.Win32;
using System;
namespace Testcaonimabi
{
public class VerifyOK
{
private const string RegKeyPath = @"Software\Nebulamist";
private const string KamiValueName = "Kami";
public static void OK(string kami)
{
try
{
// 打开或创建注册表项
using (RegistryKey key = Registry.CurrentUser.CreateSubKey(RegKeyPath))
{
// 设置卡密值
key.SetValue(KamiValueName, kami, RegistryValueKind.String);
Console.WriteLine($"✅ 卡密已保存到注册表: {kami}");
}
}
catch (Exception ex)
{
Console.WriteLine($"❌ 保存卡密到注册表失败: {ex.Message}");
}
}
}
}