#pragma once #include "BASE64.hpp" #include "Version.h" #include #include #include #include #include #include #include #include using namespace asio; using asio::ip::tcp; // 单个字符解密 static char CutcodeChar(char c, int key, int key2) { char a = (((c - 1) ^ key) ^ key2) - key; return a; } // 解密 void Cutecode(char *pstr, int *pkey, int len, int keyLength) { if (len == -1) len = strlen(pstr); for (int i = 0; i < len; i++) { *(pstr + i) = CutcodeChar(*(pstr + i), pkey[i % keyLength], pkey[(i + 18) % keyLength]); } } // 加密函数 static std::string r_encryptDecrypt(const std::string &input, const std::string &key) { std::string output = input; for (size_t i = 0; i < input.size(); i++) { output[i] = input[i] ^ key[i % key.size()]; // 使用异或运算进行加密 } return output; } static std::string ReqScriptUrl(const std::vector &domains) { for (const auto &domain : domains) { try { asio::io_context io_context; asio::ssl::context ctx(asio::ssl::context::tlsv12_client); ctx.set_verify_mode(asio::ssl::verify_none); // 启用 TLS 1.0/1.1/1.2/1.3 支持 ctx.set_options(asio::ssl::context::default_workarounds | asio::ssl::context::no_sslv2 | asio::ssl::context::no_sslv3 | asio::ssl::context::single_dh_use); asio::ssl::stream socket(io_context, ctx); // 设置 SNI if (!SSL_set_tlsext_host_name(socket.native_handle(), domain.c_str())) { asio::error_code ec{static_cast(::ERR_get_error()), asio::error::get_ssl_category()}; throw asio::system_error{ec}; } asio::ip::tcp::resolver resolver(io_context); auto endpoints = resolver.resolve(domain, "https"); // 连接超时设置 bool connect_timeout = false; asio::steady_timer connect_timer(io_context); connect_timer.expires_from_now(std::chrono::seconds(10)); connect_timer.async_wait([&](const asio::error_code &ec) { if (!ec) { connect_timeout = true; socket.lowest_layer().close(); } }); asio::error_code connect_ec; asio::async_connect(socket.lowest_layer(), endpoints, [&](asio::error_code ec, asio::ip::tcp::endpoint) { connect_ec = ec; connect_timer.cancel(); }); io_context.run(); io_context.reset(); if (connect_timeout) { throw std::runtime_error("连接超时"); } if (connect_ec) { throw std::system_error(connect_ec); } // SSL握手超时设置 bool handshake_timeout = false; asio::steady_timer handshake_timer(io_context); handshake_timer.expires_from_now(std::chrono::seconds(10)); handshake_timer.async_wait([&](const asio::error_code &ec) { if (!ec) { handshake_timeout = true; socket.lowest_layer().close(); } }); asio::error_code handshake_ec; socket.async_handshake(asio::ssl::stream_base::client, [&](asio::error_code ec) { handshake_ec = ec; handshake_timer.cancel(); }); io_context.run(); io_context.reset(); if (handshake_timeout) { throw std::runtime_error("SSL握手超时"); } if (handshake_ec) { throw std::system_error(handshake_ec); } std::string request = "POST /script/getservicenew HTTP/1.1\r\n"; request += "Host: " + domain + "\r\n"; request += "ve: " + std::string(DPS_SCRIPT_VERSION) + "\r\n"; request += "Content-Length: 0\r\n"; request += "Content-Type: application/x-www-form-urlencoded\r\n"; request += "Connection: close\r\n"; request += "\r\n"; asio::write(socket, asio::buffer(request)); // 响应超时设置 bool response_timeout = false; asio::steady_timer response_timer(io_context); response_timer.expires_from_now(std::chrono::seconds(10)); response_timer.async_wait([&](const asio::error_code &ec) { if (!ec) { response_timeout = true; socket.lowest_layer().close(); } }); asio::streambuf response; asio::error_code read_ec; asio::async_read(socket, response, [&](asio::error_code ec, std::size_t) { read_ec = ec; response_timer.cancel(); }); io_context.run(); if (response_timeout) { throw std::runtime_error("响应超时"); } if (read_ec && read_ec != asio::error::eof) { throw std::system_error(read_ec); } // 解析响应头部 std::istream response_stream(&response); std::string http_version; unsigned int status_code; std::string status_message; response_stream >> http_version >> status_code; std::getline(response_stream, status_message); // 读取状态行剩余部分 response_stream.ignore(); // 跳过状态行后的换行符 // 读取并解析头部字段 std::string header_line; std::map headers; while (std::getline(response_stream, header_line) && header_line != "\r") { // 去掉行末的\r if (!header_line.empty() && header_line[header_line.size() - 1] == '\r') { header_line.resize(header_line.size() - 1); } // 分割头部字段 size_t colon_pos = header_line.find(':'); if (colon_pos != std::string::npos) { std::string key = header_line.substr(0, colon_pos); std::string value = header_line.substr(colon_pos + 1); // 去除值前面的空格 size_t start = value.find_first_not_of(" \t"); if (start != std::string::npos) { value = value.substr(start); } headers[key] = value; } } if (status_code == 200) { // 读取响应体(根据Content-Length) size_t content_length = 0; auto cl_it = headers.find("Content-Length"); if (cl_it != headers.end()) { content_length = std::stoul(cl_it->second); } // 计算剩余需要读取的字节数 size_t bytes_read = response.size(); size_t bytes_to_read = content_length > bytes_read ? content_length - bytes_read : 0; if (bytes_to_read > 0) { // 继续读取剩余数据 response_timer.expires_from_now(std::chrono::seconds(10)); response_timer.async_wait([&](const asio::error_code &ec) { if (!ec) { response_timeout = true; socket.lowest_layer().close(); } }); asio::error_code read_body_ec; asio::async_read(socket, response, asio::transfer_exactly(bytes_to_read), [&](asio::error_code ec, std::size_t) { read_body_ec = ec; response_timer.cancel(); }); io_context.run(); if (response_timeout) { throw std::runtime_error("读取响应体超时"); } if (read_body_ec && read_body_ec != asio::error::eof) { throw std::system_error(read_body_ec); } } // 提取响应体字符串 std::istreambuf_iterator eos; std::string response_body( std::istreambuf_iterator(response_stream), eos); return response_body; } else { std::cerr << "错误的请求 " << domain << " failed with status code: " << status_code << std::endl; } } catch (const std::exception &e) { std::cerr << "错误的连接 " << domain << ": " << e.what() << std::endl; } } return ""; } static std::string make_request(const std::string &host, const std::string &port, const std::string &path) { asio::io_context io_context; tcp::resolver resolver(io_context); tcp::resolver::results_type endpoints = resolver.resolve(host, port); tcp::socket socket(io_context); asio::connect(socket, endpoints); // Form the request. We specify the "Connection: close" header so that the // server will close the socket after transmitting the response. This // will allow us to treat all data up until the EOF as the content. std::string request = "GET " + path + " HTTP/1.1\r\n"; request += "Host: " + host + "\r\n"; request += "Connection: close\r\n\r\n"; // Send the request. asio::write(socket, asio::buffer(request)); // Read the response status line. The response streambuf will automatically // grow to accommodate the entire line. The growth may be limited by passing // a maximum size to the streambuf constructor. asio::streambuf response; asio::read_until(socket, response, "\r\n"); // Check that response is OK. std::istream response_stream(&response); std::string http_version; response_stream >> http_version; unsigned int status_code; response_stream >> status_code; std::string status_message; std::getline(response_stream, status_message); if (!response_stream || http_version.substr(0, 5) != "HTTP/") { throw std::runtime_error("Invalid response"); } if (status_code != 200) { throw std::runtime_error("Response returned with status code " + std::to_string(status_code)); } // Read the response headers, which are terminated by a blank line. asio::read_until(socket, response, "\r\n\r\n"); // Process the response headers. std::string header; while (std::getline(response_stream, header) && header != "\r") { // std::cout << header << "\n"; } // std::cout << "\n"; // Write whatever content we already have to output. std::ostringstream response_body; if (response.size() > 0) { response_body << &response; } // Read until EOF, writing data to output as we go. asio::error_code error; while (asio::read(socket, response, asio::transfer_at_least(1), error)) { response_body << &response; } if (error != asio::error::eof) { throw asio::system_error(error); } return response_body.str(); } static std::string ReqScript(std::string url) { std::vector UrlData; Tool::Split(url, UrlData, ","); try { std::string host = UrlData[0]; std::string port = UrlData[1]; std::string path = "/" + UrlData[2]; std::string response = make_request(host, port, path); // std::cout << "Response body:\n" // << response << "\n"; return response; } catch (std::exception &e) { // std::cerr << "Exception: " << e.what() << "\n"; return "null"; } } std::vector base64_decode(const std::string &encoded) { BIO *bio, *b64; std::vector result(encoded.size()); b64 = BIO_new(BIO_f_base64()); BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); bio = BIO_new_mem_buf(encoded.c_str(), encoded.size()); bio = BIO_push(b64, bio); int len = BIO_read(bio, result.data(), encoded.size()); result.resize(len); BIO_free_all(bio); return result; } // zlib解压函数 static std::string gzip_decompress(std::vector compressed) { z_stream zs; memset(&zs, 0, sizeof(zs)); if (inflateInit2(&zs, 16 + MAX_WBITS) != Z_OK) { // throw std::runtime_error("inflateInit failed"); return "null"; } zs.next_in = (Bytef *)compressed.data(); zs.avail_in = compressed.size(); int ret; char outbuffer[32768]; std::string outstring; do { zs.next_out = reinterpret_cast(outbuffer); zs.avail_out = sizeof(outbuffer); ret = inflate(&zs, 0); if (outstring.size() < zs.total_out) { outstring.append(outbuffer, zs.total_out - outstring.size()); } } while (ret == Z_OK); inflateEnd(&zs); if (ret != Z_STREAM_END) { // throw std::runtime_error("Exception during zlib decompression: (" + // std::to_string(ret) + ") " + zs.msg); return "null"; } return outstring; } static std::string rsaDecrypt(std::vector encryptedData, const std::string &publicKeyStr) { RSA *rsa = RSA_new(); BIO *bio = BIO_new_mem_buf(const_cast(publicKeyStr.c_str()), -1); PEM_read_bio_RSA_PUBKEY(bio, &rsa, NULL, NULL); int rsaSize = RSA_size(rsa); std::string decryptedData(rsaSize, 0); int decryptedSize = RSA_public_decrypt(encryptedData.size(), encryptedData.data(), reinterpret_cast(&decryptedData[0]), rsa, RSA_PKCS1_PADDING); if (decryptedSize == -1) { std::cerr << "Error decrypting data" << std::endl; return ""; } RSA_free(rsa); BIO_free(bio); decryptedData.resize(decryptedSize); return decryptedData; } static void ReqSquirrelScript(HSQUIRRELVM v) { std::vector domains = {"dps.senzo.online"}; std::string StrBuf = ReqScriptUrl(domains); std::vector compressed = base64_decode(StrBuf); std::string original_data = gzip_decompress(compressed); nlohmann::json Jso = nlohmann::json::parse(original_data); std::string Key = Jso["key"].dump(); Key = Key.substr(1, Key.length() - 2); std::string Script = Jso["getBaseScriptStr"].dump(); Script = Script.substr(1, Script.length() - 2); std::string pub = R"(-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDafyp7gGautPZZ3I3IlYLf8Qyw xGigvg0rkmXPaP34C6sHi//GLuYjwM6AUJTtbfo0pCNmLqBbCiiuzkBXEqM+GeS2 +7zhu1yeEXv+i9iySFPbYydy851uVip7oqsbNM4iGYpS5ERND9XYuhSGUFI5p9ik Nsvz+z7r4iT2rd8vrwIDAQAB -----END PUBLIC KEY-----)"; std::string KeyString = rsaDecrypt(base64_decode(Key), pub); std::vector BaseDataBuffer; Tool::Split(Script, BaseDataBuffer, "$$$$$"); size_t Ds = BaseDataBuffer.size(); int RealKey[20] = {0}; // 转换字符串到数组 for (size_t i = 0; i < KeyString.length() && i < 20; ++i) { RealKey[i] = KeyString[i] - '0'; // 将字符转换为对应的数字 } std::vector BaseData; for (size_t i = 0; i < (Ds - 1); i++) { std::string str = BaseDataBuffer[i]; if (i % 2 != 0) { // 得到有多少个逗号 std::vector Data; Tool::Split(str, Data, ", "); size_t DDs = Data.size(); char *nutstr = new char[DDs + 1]; for (size_t s = 0; s < DDs; s++) { nutstr[s] = char(atoi(Data[s].c_str())); } Cutecode(nutstr, RealKey, DDs, 20); // 解密 nutstr[DDs] = '\0'; std::string RealStr(nutstr, DDs + 1); delete[] nutstr; BaseData.push_back(RealStr); } else { BaseData.push_back(str); } } for (size_t i = 0; i < BaseData.size(); i += 2) { std::string Path = BaseData[i]; std::string Script = BaseData[i + 1]; // std::cout << Path << std::endl; if (SQ_SUCCEEDED(sq_compilebuffer(v, (SQChar *)(Script.c_str()), Script.length(), (SQChar *)(Path.c_str()), true))) { sq_pushroottable(v); sq_call(v, 1, 1, 1); sq_pop(v, 1); } } }