单码卡密登录
接口地址:
返回格式:
请求方式:
请求示例:
请求参数说明:
| 名称 | 变量 | 必填 | 类型 | 说明 |
|---|---|---|---|---|
| 接口 | api | 是 | GET | 填写kmlogon |
| 应用 | app | 是 | GET | 填写后台应用APPID |
| 卡密 | kami | 是 | GET/POST | 填写提交的卡密 |
| 设备码 | markcode | 是 | GET/POST | 如果开启了[验证设备]需提交此项 |
| 时间戳 | t | 否 | GET/POST | 如果开启了[时间差效验]需提交此项 |
| 数据签名 | sign | 否 | GET/POST | 如果开启了[数据签名]需提交此项 |
返回参数说明:
| 名称 | 类型 | 说明 |
|---|---|---|
| code | String | 返回状态 |
| kami | String | 提交的卡密 |
| vip | String | 卡密到期时长 |
返回示例:
{
"code": 200,
"msg": {
"kami": "2iPMrvyhqH",
"vip": "1614693232"
},
"time": 1614689800,
"check": "00e837c144a02a5ed3717647ee3f33da"
}
错误码格式说明:
| 名称 | 类型 | 说明 |
|---|---|---|
| 101 | String | 应用不存在 |
| 102 | String | 应用已关闭 |
| 171 | String | 接口维护中 |
| 172 | String | 接口未添加或不存在 |
| 104 | String | 签名为空 |
| 105 | String | 数据过期 |
| 106 | String | 签名有误 |
| 148 | String | 卡密为空 |
| 149 | String | 卡密不存在 |
| 151 | String | 卡密禁用 |
| 169 | String | IP不一致 |
代码示例:
---------------------------------------------------------------------------------------- 《按键精灵》对接代码 ----------------------------------------------------------------------------------------- Dim 返回值,签名,参数,时间戳,机器码,卡密 卡密 = ReadUIConfig("输入框1") 时间戳 = Time() 机器码 = GetDeviceID() 参数 = "kami=" & 卡密 & "&markcode=" & 机器码 & "&t=" & 时间戳 签名 = Encode.Md5(参数 & "&Y9rfFf99kYm79TFJ") 返回值 = URL.Post("http://175.24.40.137:882/api.php?api=kmlogon&app=10060", 参数 & "&sign=" & 签名) If 返回值 <> Null And 返回值 <> "" Then TracePrint 返回值 返回值 = Encode.JsonToTable(返回值) If 返回值["code"] = 200 Then TracePrint "登录成功" ElseIf 返回值["code"] <> 200 Then TracePrint "登录失败" & 返回值["msg"] End If End If ---------------------------------------------------------------------------------------- 《易语言》开启加密对接代码 ----------------------------------------------------------------------------------------- 请使用度大师卡密验证模块 模块下载地址: 点击网址即可下载 https://k.duds.cn/kami.ec 调用案例源码,直接复制使用,方便简单,替换自己的四个参数即可 《注意》记得后台应用安全里面开启RC4加密 -------------------------------以下代码复制使用------------------------------------------ .版本 2 .支持库 spec .子程序 卡密验证 .局部变量 json, 类_json .局部变量 code, 文本型 .局部变量 信息, 文本型 .局部变量 结果, 文本型 .局部变量 时间, 文本型 .局部变量 到期时间, 文本型 ' 卡密登录模块接受四个参数:1为卡密 2为APPKEY 3为RC4秘钥 4为APPID 结果 = 卡密登录 (编辑框1.内容, “E3tLytyebbyYp13z”, “6mFI7kLHLmf10265”, “10265”) 调试输出 (“返回码”, 结果) .如果 (json.解析 (结果, , )) code = json.取通用属性 (“code”, ) 信息 = json.取通用属性 (“msg”, ) .如果 (到整数 (code) = 200) 时间 = json.取通用属性 (“msg.vip”, ) 到期时间 = 时间_时间戳转文本 (时间, ) .否则 信息框 (信息, 0, , ) .如果结束 .否则 信息框 (结果, 0, , ) ---------------------------------------------------------------------------------------- 《懒人精灵》对接代码 ----------------------------------------------------------------------------------------- 点击下载插件:https://r.duds.cn/%E5%BA%A6%E5%A4%A7%E5%B8%88.luaej 里面包含 卡密验证 卡密解绑 文字识别 热更新,需要卡密心跳,看卡密心跳的开发文档 ------------------------------------------------------------------------------------------ 《C++》对接代码 ------------------------------------------------------------------------------------------ // by luckiest #include#include #include #include #include #include #include #include #include #include #include #include #pragma comment(lib, "winhttp.lib") #pragma comment(lib, "crypt32.lib") // ==================== RC4加密实现 ==================== class RC4 { private: std::vector S; void swap(BYTE& a, BYTE& b) { BYTE temp = a; a = b; b = temp; } public: RC4(const std::string& key) { S.resize(256); for (int i = 0; i < 256; i++) { S[i] = static_cast (i); } int j = 0; for (int i = 0; i < 256; i++) { j = (j + S[i] + key[i % key.length()]) % 256; swap(S[i], S[j]); } } std::string encrypt(const std::string& plaintext) { std::string result; int i = 0, j = 0; for (size_t k = 0; k < plaintext.length(); k++) { i = (i + 1) % 256; j = (j + S[i]) % 256; swap(S[i], S[j]); BYTE keystream = S[(S[i] + S[j]) % 256]; result += static_cast (plaintext[k] ^ keystream); } return result; } std::string decrypt(const std::string& ciphertext) { return encrypt(ciphertext); // RC4是对称的 } }; // ==================== Base64编码/解码 ==================== class Base64 { public: static std::string encode(const std::string& input) { static const std::string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; std::string result; int val = 0, valb = -6; for (unsigned char c : input) { val = (val << 8) + c; valb += 8; while (valb >= 0) { result.push_back(chars[(val >> valb) & 0x3F]); valb -= 6; } } if (valb > -6) { result.push_back(chars[((val << 8) >> (valb + 8)) & 0x3F]); } while (result.size() % 4) { result.push_back('='); } return result; } static std::string decode(const std::string& input) { static const int T[256] = { -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 }; std::string result; int val = 0, valb = -8; for (unsigned char c : input) { if (T[c] == -1) break; val = (val << 6) + T[c]; valb += 6; if (valb >= 0) { result.push_back(char((val >> valb) & 0xFF)); valb -= 8; } } return result; } }; // ==================== URL编码 ==================== class URL { public: static std::string encode(const std::string& input) { std::ostringstream escaped; escaped.fill('0'); escaped << std::hex; for (char c : input) { if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') { escaped << c; } else if (c == ' ') { escaped << '+'; } else { escaped << std::uppercase; escaped << '%' << std::setw(2) << int((unsigned char)c); escaped << std::nouppercase; } } return escaped.str(); } }; // ==================== 简单JSON解析器 ==================== class SimpleJSON { private: std::string json; size_t pos; void skipWhitespace() { while (pos < json.length() && (json[pos] == ' ' || json[pos] == '\t' || json[pos] == '\n' || json[pos] == '\r')) { pos++; } } std::string parseString() { pos++; // 跳过引号 std::string result; while (pos < json.length() && json[pos] != '"') { if (json[pos] == '\\' && pos + 1 < json.length()) { pos++; switch (json[pos]) { case '"': result += '"'; break; case '\\': result += '\\'; break; case '/': result += '/'; break; case 'b': result += '\b'; break; case 'f': result += '\f'; break; case 'n': result += '\n'; break; case 'r': result += '\r'; break; case 't': result += '\t'; break; default: result += json[pos]; break; } } else { result += json[pos]; } pos++; } pos++; // 跳过结束引号 return result; } public: SimpleJSON(const std::string& jsonStr) : json(jsonStr), pos(0) {} std::string getValue(const std::string& key) { pos = 0; skipWhitespace(); if (pos >= json.length() || json[pos] != '{') { return ""; } pos++; // 跳过 '{' while (pos < json.length()) { skipWhitespace(); if (json[pos] == '}') { break; } if (json[pos] == '"') { std::string currentKey = parseString(); skipWhitespace(); if (pos < json.length() && json[pos] == ':') { pos++; skipWhitespace(); if (currentKey == key) { if (json[pos] == '"') { return parseString(); } else if (json[pos] == '{') { // 返回对象内容 size_t start = pos; int depth = 1; pos++; while (pos < json.length() && depth > 0) { if (json[pos] == '{') depth++; if (json[pos] == '}') depth--; pos++; } return json.substr(start, pos - start); } else { // 数字或其他值 size_t start = pos; while (pos < json.length() && json[pos] != ',' && json[pos] != '}') { pos++; } return json.substr(start, pos - start); } } else { // 跳过值 if (json[pos] == '"') { parseString(); } else if (json[pos] == '{') { int depth = 1; pos++; while (pos < json.length() && depth > 0) { if (json[pos] == '{') depth++; if (json[pos] == '}') depth--; pos++; } } else { while (pos < json.length() && json[pos] != ',' && json[pos] != '}') { pos++; } } } } } skipWhitespace(); if (pos < json.length() && json[pos] == ',') { pos++; } } return ""; } std::string getNestedValue(const std::string& path) { size_t dotPos = path.find('.'); if (dotPos == std::string::npos) { return getValue(path); } std::string firstKey = path.substr(0, dotPos); std::string remainingPath = path.substr(dotPos + 1); std::string nestedJson = getValue(firstKey); if (nestedJson.empty() || nestedJson[0] != '{') { return ""; } SimpleJSON nestedParser(nestedJson); return nestedParser.getNestedValue(remainingPath); } }; // ==================== HTTP请求类 ==================== class HttpClient { public: static std::string get(const std::string& url) { HINTERNET hSession = NULL; HINTERNET hConnect = NULL; HINTERNET hRequest = NULL; std::string result; try { // 解析URL size_t protocolPos = url.find("://"); if (protocolPos == std::string::npos) { throw std::runtime_error("Invalid URL"); } std::string protocol = url.substr(0, protocolPos); std::string remaining = url.substr(protocolPos + 3); size_t pathPos = remaining.find('/'); std::string host = (pathPos == std::string::npos) ? remaining : remaining.substr(0, pathPos); std::string path = (pathPos == std::string::npos) ? "/" : remaining.substr(pathPos); size_t portPos = host.find(':'); int port = 443; // HTTPS默认端口 std::string hostname = host; if (portPos != std::string::npos) { hostname = host.substr(0, portPos); port = std::stoi(host.substr(portPos + 1)); } // 创建会话 hSession = WinHttpOpen(L"KamiLogin/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); if (!hSession) { DWORD err = GetLastError(); throw std::runtime_error("WinHttpOpen failed, error: " + std::to_string(err)); } // 连接服务器 hConnect = WinHttpConnect(hSession, std::wstring(hostname.begin(), hostname.end()).c_str(), port, 0); if (!hConnect) { DWORD err = GetLastError(); throw std::runtime_error("WinHttpConnect failed, error: " + std::to_string(err)); } // 创建请求 DWORD flags = (protocol == "https") ? WINHTTP_FLAG_SECURE : 0; hRequest = WinHttpOpenRequest(hConnect, L"GET", std::wstring(path.begin(), path.end()).c_str(), NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, flags); if (!hRequest) { DWORD err = GetLastError(); throw std::runtime_error("WinHttpOpenRequest failed, error: " + std::to_string(err)); } // 发送请求 if (!WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0)) { DWORD err = GetLastError(); throw std::runtime_error("WinHttpSendRequest failed, error: " + std::to_string(err)); } // 接收响应 if (!WinHttpReceiveResponse(hRequest, NULL)) { DWORD err = GetLastError(); throw std::runtime_error("WinHttpReceiveResponse failed, error: " + std::to_string(err)); } // 读取响应数据 DWORD bytesAvailable = 0; while (WinHttpQueryDataAvailable(hRequest, &bytesAvailable) && bytesAvailable > 0) { std::vector buffer(bytesAvailable + 1); DWORD bytesRead = 0; if (WinHttpReadData(hRequest, buffer.data(), bytesAvailable, &bytesRead)) { buffer[bytesRead] = '\0'; result += buffer.data(); } } } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; } // 清理 if (hRequest) WinHttpCloseHandle(hRequest); if (hConnect) WinHttpCloseHandle(hConnect); if (hSession) WinHttpCloseHandle(hSession); return result; } }; // ==================== 卡密验证类 ==================== class KamiLogin { private: std::string appId; std::string appKey; std::string rc4Key; std::string apiUrl; // 获取机器码(基于硬盘序列号) static std::string getMachineCode() { std::string machineCode; // 获取C盘序列号 DWORD serialNumber = 0; if (GetVolumeInformationA("C:\\", NULL, 0, &serialNumber, NULL, NULL, NULL, 0)) { machineCode = std::to_string(serialNumber); } // 获取CPU信息 int cpuInfo[4] = {0}; __cpuid(cpuInfo, 1); char cpuId[32]; sprintf_s(cpuId, "%08X%08X", cpuInfo[3], cpuInfo[0]); machineCode += cpuId; // 简单的哈希处理 DWORD hash = 0; for (char c : machineCode) { hash = hash * 31 + c; } return std::to_string(hash); } public: KamiLogin(const std::string& appId, const std::string& appKey, const std::string& rc4Key, const std::string& apiUrl = "https://k.duds.cn/api.php") : appId(appId), appKey(appKey), rc4Key(rc4Key), apiUrl(apiUrl) {} // 卡密验证 std::string verify(const std::string& kami, const std::string& markcode = "") { // 获取机器码 std::string machineCode = getMachineCode(); // 如果没有提供markcode,使用自动获取的机器码 std::string actualMarkcode = markcode.empty() ? machineCode : markcode; // 构建请求URL std::string url = apiUrl + "?api=kmlogon&app=" + appId + "&kami=" + URL::encode(kami); // 添加机器码 url += "&markcode=" + URL::encode(actualMarkcode); // 如果开启了时间差校验 time_t now = time(nullptr); url += "&t=" + std::to_string(now); // 如果开启了数据签名(这里简化处理,实际需要根据API文档实现签名算法) // url += "&sign=" + generateSign(kami, now); // 输出调试信息 std::cerr << "[DEBUG] Machine Code: " << actualMarkcode << std::endl; std::cerr << "[DEBUG] Request URL: " << url << std::endl; // 发送HTTP请求 std::string response = HttpClient::get(url); // 输出调试信息 std::cerr << "[DEBUG] Response length: " << response.length() << std::endl; if (!response.empty()) { std::cerr << "[DEBUG] Response: " << response << std::endl; } // 如果开启了RC4加密,需要解密响应 if (!rc4Key.empty()) { try { std::string decoded = Base64::decode(response); RC4 rc4(rc4Key); response = rc4.decrypt(decoded); std::cerr << "[DEBUG] Decrypted response: " << response << std::endl; } catch (...) { // 解密失败,返回原始响应 std::cerr << "[DEBUG] Decryption failed, using original response" << std::endl; } } return response; } // 解析验证结果 struct VerifyResult { int code; std::string kami; std::string vip; std::string msg; std::string rawResponse; }; VerifyResult parseResult(const std::string& response) { VerifyResult result; result.rawResponse = response; SimpleJSON json(response); std::string codeStr = json.getValue("code"); result.code = codeStr.empty() ? -1 : std::stoi(codeStr); result.kami = json.getNestedValue("msg.kami"); result.vip = json.getNestedValue("msg.vip"); result.msg = json.getValue("msg"); return result; } // 时间戳转文本 static std::string timestampToText(const std::string& timestamp) { try { time_t ts = std::stoll(timestamp); char buffer[100]; struct tm timeinfo; localtime_s(&timeinfo, &ts); strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &timeinfo); return std::string(buffer); } catch (...) { return "无效时间戳"; } } }; // by luckiest // ==================== 主程序 ==================== int main() { _setmode(_fileno(stdout), _O_U16TEXT); _setmode(_fileno(stdin), _O_U16TEXT); std::wcout << L"========================================" << std::endl; std::wcout << L" 卡密验证 " << std::endl; std::wcout << L"========================================" << std::endl; std::wcout << std::endl; // 配置参数 - 请替换为您的实际参数 const std::string APPID = "10472"; // 后台应用APPID const std::string APPKEY = "eA3AdELLsIqZd9E3"; // APPKEY const std::string RC4_KEY = ""; // RC4秘钥(如果后台开启了RC4加密) // 创建卡密验证实例 KamiLogin kamiLogin(APPID, APPKEY, RC4_KEY); while (true) { std::wcout << L"请输入卡密 (输入 q 退出): "; std::wstring kami; std::getline(std::wcin, kami); if (kami == L"q" || kami == L"Q") { break; } if (kami.empty()) { std::wcout << L"卡密不能为空!" << std::endl; continue; } std::wcout << L"正在验证..." << std::endl; // 将宽字符串转换为UTF-8字符串用于API请求 int size_needed = WideCharToMultiByte(CP_UTF8, 0, kami.c_str(), (int)kami.length(), NULL, 0, NULL, NULL); std::string kami_utf8(size_needed, 0); WideCharToMultiByte(CP_UTF8, 0, kami.c_str(), (int)kami.length(), &kami_utf8[0], size_needed, NULL, NULL); // 发送验证请求 std::string response = kamiLogin.verify(kami_utf8); // 将响应转换为宽字符串用于显示 int response_size = MultiByteToWideChar(CP_UTF8, 0, response.c_str(), (int)response.length(), NULL, 0); std::wstring response_w(response_size, 0); MultiByteToWideChar(CP_UTF8, 0, response.c_str(), (int)response.length(), &response_w[0], response_size); std::wcout << L"服务器响应: " << response_w << std::endl; // 解析结果 KamiLogin::VerifyResult result = kamiLogin.parseResult(response); std::wcout << L"----------------------------------------" << std::endl; std::wcout << L"返回码: " << result.code << std::endl; if (result.code == 200) { std::wcout << L"验证成功!" << std::endl; // 将结果转换为宽字符串显示 int kami_size = MultiByteToWideChar(CP_UTF8, 0, result.kami.c_str(), (int)result.kami.length(), NULL, 0); std::wstring kami_w(kami_size, 0); MultiByteToWideChar(CP_UTF8, 0, result.kami.c_str(), (int)result.kami.length(), &kami_w[0], kami_size); int vip_size = MultiByteToWideChar(CP_UTF8, 0, result.vip.c_str(), (int)result.vip.length(), NULL, 0); std::wstring vip_w(vip_size, 0); MultiByteToWideChar(CP_UTF8, 0, result.vip.c_str(), (int)result.vip.length(), &vip_w[0], vip_size); std::string timeText = KamiLogin::timestampToText(result.vip); int time_size = MultiByteToWideChar(CP_UTF8, 0, timeText.c_str(), (int)timeText.length(), NULL, 0); std::wstring time_w(time_size, 0); MultiByteToWideChar(CP_UTF8, 0, timeText.c_str(), (int)timeText.length(), &time_w[0], time_size); std::wcout << L"卡密: " << kami_w << std::endl; std::wcout << L"到期时间戳: " << vip_w << std::endl; std::wcout << L"到期时间: " << time_w << std::endl; } else { std::wcout << L"验证失败!" << std::endl; int msg_size = MultiByteToWideChar(CP_UTF8, 0, result.msg.c_str(), (int)result.msg.length(), NULL, 0); std::wstring msg_w(msg_size, 0); MultiByteToWideChar(CP_UTF8, 0, result.msg.c_str(), (int)result.msg.length(), &msg_w[0], msg_size); std::wcout << L"错误信息: " << msg_w << std::endl; } std::wcout << L"----------------------------------------" << std::endl; std::wcout << std::endl; } std::wcout << L"程序已退出。" << std::endl; return 0; }