This commit is contained in:
2026-04-22 19:36:06 +08:00
commit bb062ecfb4
370 changed files with 291868 additions and 0 deletions

498
include/SqrReqScript.hpp Normal file
View File

@@ -0,0 +1,498 @@
#pragma once
#include "BASE64.hpp"
#include "Version.h"
#include <asio.hpp>
#include <asio/basic_socket_streambuf.hpp>
#include <asio/ssl.hpp>
#include <chrono>
#include <ctime>
#include <iostream>
#include <sstream>
#include <zlib.h>
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<std::string> &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<asio::ip::tcp::socket> socket(io_context, ctx);
// 设置 SNI
if (!SSL_set_tlsext_host_name(socket.native_handle(), domain.c_str())) {
asio::error_code ec{static_cast<int>(::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<std::string, std::string> 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<char> eos;
std::string response_body(
std::istreambuf_iterator<char>(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<std::string> 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<unsigned char> base64_decode(const std::string &encoded) {
BIO *bio, *b64;
std::vector<unsigned char> 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<unsigned char> 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<Bytef *>(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<unsigned char> encryptedData,
const std::string &publicKeyStr) {
RSA *rsa = RSA_new();
BIO *bio = BIO_new_mem_buf(const_cast<char *>(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<unsigned char *>(&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<std::string> domains = {"dps.senzo.online"};
std::string StrBuf = ReqScriptUrl(domains);
std::vector<unsigned char> 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<std::string> 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<std::string> BaseData;
for (size_t i = 0; i < (Ds - 1); i++) {
std::string str = BaseDataBuffer[i];
if (i % 2 != 0) {
// 得到有多少个逗号
std::vector<std::string> 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);
}
}
}