diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 980d5db..458585d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,6 @@ # https://docs.github.com/en/actions/learn-github-actions/contexts -name: SignerServer +name: build on: push: branches: diff --git a/CMakeLists.txt b/CMakeLists.txt index cfd8612..098e8bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,8 +7,6 @@ project(SignerServer) if("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") add_definitions(-D _WIN_PLATFORM_) - enable_language(ASM_MASM) - link_libraries(ws2_32) elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin") add_definitions(-D _MAC_PLATFORM_) @@ -24,12 +22,6 @@ elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64") add_definitions(-D _ARM64_ARCH_) endif() -file(GLOB SOURCE_FILES "./src/*.cpp" "./src/*.asm") +file(GLOB SOURCE_FILES "./src/*.cpp") -add_library(SignerServer SHARED ${SOURCE_FILES}) - -if(MSVC) - target_link_options(SignerServer PRIVATE - /DEF:${CMAKE_CURRENT_SOURCE_DIR}/version.def - ) -endif() \ No newline at end of file +add_library(SignerServer SHARED ${SOURCE_FILES}) \ No newline at end of file diff --git a/include/cpp-httplib/httplib.h b/include/cpp-httplib/httplib.h index ba6e666..616b914 100644 --- a/include/cpp-httplib/httplib.h +++ b/include/cpp-httplib/httplib.h @@ -8,7 +8,7 @@ #ifndef CPPHTTPLIB_HTTPLIB_H #define CPPHTTPLIB_HTTPLIB_H -#define CPPHTTPLIB_VERSION "0.15.3" +#define CPPHTTPLIB_VERSION "0.16.0" /* * Configuration @@ -726,6 +726,10 @@ private: assert(true == static_cast(fn)); fn(); } + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + OPENSSL_thread_stop (); +#endif } ThreadPool &pool_; @@ -1819,6 +1823,9 @@ public: bool is_valid() const override; SSL_CTX *ssl_context() const; + + void update_certs (X509 *cert, EVP_PKEY *private_key, + X509_STORE *client_ca_cert_store = nullptr); private: bool process_and_close_socket(socket_t sock) override; @@ -2825,15 +2832,25 @@ inline bool mmap::open(const char *path) { if (!::GetFileSizeEx(hFile_, &size)) { return false; } size_ = static_cast(size.QuadPart); +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) hMapping_ = ::CreateFileMappingFromApp(hFile_, NULL, PAGE_READONLY, size_, NULL); +#else + hMapping_ = + ::CreateFileMappingW(hFile_, NULL, PAGE_READONLY, size.HighPart, + size.LowPart, NULL); +#endif if (hMapping_ == NULL) { close(); return false; } +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) addr_ = ::MapViewOfFileFromApp(hMapping_, FILE_MAP_READ, 0, 0); +#else + addr_ = ::MapViewOfFile(hMapping_, FILE_MAP_READ, 0, 0, 0); +#endif #else fd_ = ::open(path, O_RDONLY); if (fd_ == -1) { return false; } @@ -7268,7 +7285,7 @@ inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) { if (location.empty()) { return false; } const static std::regex re( - R"((?:(https?):)?(?://(?:\[([\d:]+)\]|([^:/?#]+))(?::(\d+))?)?([^?#]*)(\?[^#]*)?(?:#.*)?)"); + R"((?:(https?):)?(?://(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)?([^?#]*)(\?[^#]*)?(?:#.*)?)"); std::smatch m; if (!std::regex_match(location, m, re)) { return false; } @@ -8753,6 +8770,19 @@ inline bool SSLServer::is_valid() const { return ctx_; } inline SSL_CTX *SSLServer::ssl_context() const { return ctx_; } +inline void SSLServer::update_certs (X509 *cert, EVP_PKEY *private_key, + X509_STORE *client_ca_cert_store) { + + std::lock_guard guard(ctx_mutex_); + + SSL_CTX_use_certificate (ctx_, cert); + SSL_CTX_use_PrivateKey (ctx_, private_key); + + if (client_ca_cert_store != nullptr) { + SSL_CTX_set_cert_store (ctx_, client_ca_cert_store); + } +} + inline bool SSLServer::process_and_close_socket(socket_t sock) { auto ssl = detail::ssl_new( sock, ctx_, ctx_mutex_, @@ -9213,7 +9243,7 @@ inline Client::Client(const std::string &scheme_host_port, const std::string &client_cert_path, const std::string &client_key_path) { const static std::regex re( - R"((?:([a-z]+):\/\/)?(?:\[([\d:]+)\]|([^:/?#]+))(?::(\d+))?)"); + R"((?:([a-z]+):\/\/)?(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)"); std::smatch m; if (std::regex_match(scheme_host_port, m, re)) { @@ -9250,6 +9280,8 @@ inline Client::Client(const std::string &scheme_host_port, client_key_path); } } else { + // NOTE: Update TEST(UniversalClientImplTest, Ipv6LiteralAddress) + // if port param below changes. cli_ = detail::make_unique(scheme_host_port, 80, client_cert_path, client_key_path); } diff --git a/include/moehoo/hook.h b/include/moehoo/hook.h new file mode 100644 index 0000000..0579be7 --- /dev/null +++ b/include/moehoo/hook.h @@ -0,0 +1,201 @@ +#ifndef _HOOK_H_ +#define _HOOK_H_ +#include +#include + +#if defined(_WIN_PLATFORM_) +#include +#elif defined(_LINUX_PLATFORM_) +#include +#include +#include +#endif + +namespace moehoo +{ + void *get_call_address(uint8_t *ptr); + void *search_and_fill_jump(uint64_t baseAddress, void *targetAddress); + bool hook(uint8_t *callAddr, void *lpFunction); +} // namespace moehoo + +inline void *moehoo::get_call_address(uint8_t *ptr) +{ + // 读取操作码 + if (ptr[0] != 0xE8) + { + printf("Not a call instruction!\n"); + return 0; + } + + // 读取相对偏移量 + int32_t relativeOffset = *reinterpret_cast(ptr + 1); + + // 计算函数地址 + uint8_t *callAddress = ptr + 5; // call 指令占 5 个字节 + void *functionAddress = callAddress + relativeOffset; + + return reinterpret_cast(functionAddress); +} + +inline void *moehoo::search_and_fill_jump(uint64_t baseAddress, void *targetAddress) +{ + uint8_t jumpInstruction[] = { + 0x49, 0xBB, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x41, 0xFF, 0xE3}; + + memcpy(jumpInstruction + 2, &targetAddress, 8); + + // Iterate through memory regions + uint64_t searchStart = baseAddress - 0x7fffffff; + uint64_t searchEnd = baseAddress + 0x7fffffff; + +#if defined(_WIN_PLATFORM_) + while (searchStart < searchEnd - sizeof(jumpInstruction)) + { + MEMORY_BASIC_INFORMATION mbi; + if (VirtualQuery(reinterpret_cast(searchStart), &mbi, sizeof(mbi)) == 0) + break; + if (mbi.State == MEM_COMMIT) + { + for (char *addr = static_cast(mbi.BaseAddress); addr < static_cast(mbi.BaseAddress) + mbi.RegionSize - 1024 * 5; ++addr) + { + + bool isFree = true; + for (int i = 0; i < 1024 * 5; ++i) + { + if (addr[i] != 0) + { + isFree = false; + break; + } + } + if (isFree) + { + DWORD oldProtect; + addr += 0x200; + // printf("addr: %p\n", addr); + + if (!VirtualProtect(addr, sizeof(jumpInstruction), PAGE_EXECUTE_READWRITE, &oldProtect)) + break; + memcpy(addr, jumpInstruction, sizeof(jumpInstruction)); + if (!VirtualProtect(addr, sizeof(jumpInstruction), PAGE_EXECUTE_READ, &oldProtect)) + break; + + return addr; + } + } + } + searchStart += mbi.RegionSize; + } +#elif defined(_LINUX_PLATFORM_) + // 保证地址对齐 + searchStart &= 0xfffffffffffff000; + searchStart += 0x1000; + searchEnd &= 0xfffffffffffff000; + + auto pmap = hak::get_maps(); + do + { + auto fpmap = pmap; + pmap = fpmap->next(); + if (std::min(pmap->start(), searchEnd) - std::max(fpmap->end(), searchStart) > 0x2000) // 搜索一片 0x2000 大小的空区域 + { + void *addr = mmap(reinterpret_cast(std::max(fpmap->end(), searchStart)), 0x2000, PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + // printf("addr: %p\n", addr); + if (addr == MAP_FAILED) + { + printf("mmap failed\n"); + continue; + } + if (reinterpret_cast(addr) > searchEnd - sizeof(jumpInstruction)) + { + munmap(addr, 0x2000); + printf("addr > searchEnd\n"); + continue; + } + memcpy(addr, jumpInstruction, sizeof(jumpInstruction)); + if (mprotect(addr, 0x2000, PROT_READ | PROT_EXEC) == -1) // 设置内存 r-w + { + munmap(addr, 0x2000); + printf("mprotect failed\n"); + continue; + } + return addr; + } + } while (pmap->next() != nullptr); + +#endif + return nullptr; +} + +inline bool moehoo::hook(uint8_t *callAddr, void *lpFunction) +{ + uint64_t startAddr = reinterpret_cast(callAddr) + 5; + int64_t distance = reinterpret_cast(lpFunction) - startAddr; +#if defined(_WIN_PLATFORM_) + // printf("Hooking %p to %p, distance: %lld\n", callAddr, lpFunction, distance); + + DWORD oldProtect; + DWORD reProtect; + if (!VirtualProtect(callAddr, 10, PAGE_EXECUTE_READWRITE, &oldProtect)) + { + printf("VirtualProtect failed\n"); + return false; + } + if (distance < INT32_MIN || distance > INT32_MAX) + { + void *new_ret = search_and_fill_jump(startAddr, lpFunction); + if (new_ret == nullptr) + { + printf("Can't find a place to jump\n"); + return false; + } + distance = reinterpret_cast(new_ret) - startAddr; + // printf("new_ret: %p, new_distance: %lld\n", new_ret, distance); + } + // 直接进行小跳转 + memcpy(callAddr + 1, reinterpret_cast(&distance), 4); // 修改 call 地址 + if (!VirtualProtect(callAddr, 10, oldProtect, &reProtect)) // 恢复原来的内存保护属性 + { + std::cout << GetLastError() << "/" << callAddr << "/" << oldProtect << "/" << reProtect; + printf("VirtualProtect failed\n"); + return false; + } + return true; +#elif defined(_LINUX_PLATFORM_) + // printf("Hooking %p to %p, distance: %ld\n", callAddr, lpFunction, distance); + + auto get_page_addr = [](void *addr) -> void * + { + return (void *)((uintptr_t)addr & ~(getpagesize() - 1)); + }; + + if (mprotect(get_page_addr(callAddr), 2 * getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC) == -1) // 设置内存可写 两倍 pagesize 防止处于页边界 + { + printf("mprotect failed\n"); + return false; + } + if (distance < INT32_MIN || distance > INT32_MAX) + { + void *new_ret = search_and_fill_jump(startAddr, lpFunction); + if (new_ret == nullptr) + { + printf("Can't find a place to jump\n"); + return false; + } + distance = reinterpret_cast(new_ret) - startAddr; + // printf("new_ret: %p, new_distance: %ld\n", new_ret, distance); + } + + memcpy(callAddr + 1, reinterpret_cast(&distance), 4); // 修改 call 地址 + if (mprotect(get_page_addr(callAddr), 2 * getpagesize(), PROT_READ | PROT_EXEC) == -1) // 还原内存保护属性 + { + printf("mprotect failed\n"); + return false; + } + return true; +#endif +} + +#endif // _HOOK_H_ \ No newline at end of file diff --git a/src/exports.cpp b/src/exports.cpp deleted file mode 100644 index 91819ac..0000000 --- a/src/exports.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#if defined(_WIN_PLATFORM_) - -#include "exports.h" -#include - -FARPROC OriginalFuncs_version[17]; - -void Exports::Load() { - char szSystemDirectory[MAX_PATH]{}; - GetSystemDirectoryA(szSystemDirectory, MAX_PATH); - - std::string OriginalPath = szSystemDirectory; - OriginalPath += "\\version.dll"; - - HMODULE version = LoadLibraryA(OriginalPath.c_str()); - // load version.dll from system32 - if (!version) { - throw std::runtime_error("Failed to load version.dll from system32\n"); - } - - std::vector ExportNames_version = { - "GetFileVersionInfoA", - "GetFileVersionInfoByHandle", - "GetFileVersionInfoExA", - "GetFileVersionInfoExW", - "GetFileVersionInfoSizeA", - "GetFileVersionInfoSizeExA", - "GetFileVersionInfoSizeExW", - "GetFileVersionInfoSizeW", - "GetFileVersionInfoW", - "VerFindFileA", - "VerFindFileW", - "VerInstallFileA", - "VerInstallFileW", - "VerLanguageNameA", - "VerLanguageNameW", - "VerQueryValueA", - "VerQueryValueW" - }; - - // get addresses of original functions - for (int i = 0; i < 17; i++) { - OriginalFuncs_version[i] = GetProcAddress(version, ExportNames_version[i].c_str()); - if (!OriginalFuncs_version[i]) { - throw std::runtime_error("Failed to get address of " + ExportNames_version[i] + "\n"); - } - } -} -#endif \ No newline at end of file diff --git a/src/exports.h b/src/exports.h deleted file mode 100644 index 467ca2c..0000000 --- a/src/exports.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include -#include -#include - -extern "C" FARPROC OriginalFuncs_version[17]; - -namespace Exports { - void Load(); -} \ No newline at end of file diff --git a/src/hijacker.cpp b/src/hijacker.cpp index 05e4851..d406125 100644 --- a/src/hijacker.cpp +++ b/src/hijacker.cpp @@ -1,25 +1,62 @@ +#include "run_as_node.h" + #if defined(_WIN_PLATFORM_) - -#include "exports.h" - bool TlsOnce = false; // this runs way before dllmain -void __stdcall TlsCallback(PVOID hModule, DWORD fdwReason, PVOID pContext) { - if (!TlsOnce) { - // for version.dll proxy - // load exports as early as possible - try { - Exports::Load(); - } catch (std::exception &e) { - printf("Failed to load exports: %s\n", e.what()); - } - TlsOnce = true; - } +void __stdcall TlsCallback(PVOID hModule, DWORD fdwReason, PVOID pContext) +{ + if (!TlsOnce) + { + try + { + RunAsNode::Init(); + } + catch (std::exception &e) + { + printf("Failed to Init RunAsNode: %s\n", e.what()); + } + TlsOnce = true; + } } -#pragma comment (linker, "/INCLUDE:_tls_used") -#pragma comment (linker, "/INCLUDE:tls_callback_func") +#pragma comment(linker, "/INCLUDE:_tls_used") +#pragma comment(linker, "/INCLUDE:tls_callback_func") #pragma const_seg(".CRT$XLF") EXTERN_C const PIMAGE_TLS_CALLBACK tls_callback_func = TlsCallback; +// // version.dll DLLHijack +// extern "C" __declspec(dllexport) void GetFileVersionInfoA() {} +// extern "C" __declspec(dllexport) void GetFileVersionInfoByHandle() {} +// extern "C" __declspec(dllexport) void GetFileVersionInfoExA() {} +// extern "C" __declspec(dllexport) void GetFileVersionInfoExW() {} +// extern "C" __declspec(dllexport) void GetFileVersionInfoSizeA() {} +// extern "C" __declspec(dllexport) void GetFileVersionInfoSizeExA() {} +// extern "C" __declspec(dllexport) void GetFileVersionInfoSizeExW() {} +// extern "C" __declspec(dllexport) void GetFileVersionInfoSizeW() {} +// extern "C" __declspec(dllexport) void GetFileVersionInfoW() {} +// extern "C" __declspec(dllexport) void VerFindFileA() {} +// extern "C" __declspec(dllexport) void VerFindFileW() {} +// extern "C" __declspec(dllexport) void VerInstallFileA() {} +// extern "C" __declspec(dllexport) void VerInstallFileW() {} +// extern "C" __declspec(dllexport) void VerLanguageNameA() {} +// extern "C" __declspec(dllexport) void VerLanguageNameW() {} +// extern "C" __declspec(dllexport) void VerQueryValueA() {} +// extern "C" __declspec(dllexport) void VerQueryValueW() {} + +// dbghelp.dll DLLHijack +extern "C" __declspec(dllexport) void StackWalk64() {} +extern "C" __declspec(dllexport) void SymCleanup() {} +extern "C" __declspec(dllexport) void SymFromAddr() {} +extern "C" __declspec(dllexport) void SymFunctionTableAccess64() {} +extern "C" __declspec(dllexport) void SymGetLineFromAddr64() {} +extern "C" __declspec(dllexport) void SymGetModuleBase64() {} +extern "C" __declspec(dllexport) void SymGetModuleInfo64() {} +extern "C" __declspec(dllexport) void SymGetSymFromAddr64() {} +extern "C" __declspec(dllexport) void SymGetSearchPathW() {} +extern "C" __declspec(dllexport) void SymInitialize() {} +extern "C" __declspec(dllexport) void SymSetOptions() {} +extern "C" __declspec(dllexport) void SymGetOptions() {} +extern "C" __declspec(dllexport) void SymSetSearchPathW() {} +extern "C" __declspec(dllexport) void UnDecorateSymbolName() {} +extern "C" __declspec(dllexport) void MiniDumpWriteDump() {} #endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 46ea20f..978ae95 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,3 +1,60 @@ #include "server.h" -Server server(1145); \ No newline at end of file +Server *server = nullptr; + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) +{ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + { + try + { + std::string ip = "0.0.0.0"; + int port = 8080; + printf("Start Init server\n"); + server = new Server(); + server->Init(); + + printf("Start Init sign\n"); + std::thread([=] { // Cannot use & capture!!!!! will cause crash + for (int i = 0; i < 10; i++) + { + try + { + if (Sign::Init()) + { + if (!server->Run(ip, port)) + printf("Server run failed\n"); + break; + } + } + catch (const std::exception &e) + { + printf("Init failed: %s\n", e.what()); + } + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + }) + .detach(); + } + catch (const std::exception &e) + { + printf("Init failed: %s\n", e.what()); + } + break; + } + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + case DLL_PROCESS_DETACH: + if (server != nullptr) + { + delete server; + server = nullptr; + } + break; + } + return TRUE; +} \ No newline at end of file diff --git a/src/run_as_node.cpp b/src/run_as_node.cpp new file mode 100644 index 0000000..2cdabd5 --- /dev/null +++ b/src/run_as_node.cpp @@ -0,0 +1,64 @@ +#include "run_as_node.h" + +#include + +#if defined(_WIN_PLATFORM_) +#define CURRENT_VERSION "9.9.12-25234" +#if defined(_X64_ARCH_) // {call winmain, check run as node function} +std::map> mainAddrMap = { + {"9.9.12-25234", {0x457A76D, 0x3A5D70}}}; +#endif +#endif + +int(__stdcall *oriWinMain)(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd); + +void(__fastcall *checkRunAsNode)(void *a1); + +int __stdcall fakeWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) +{ + checkRunAsNode(nullptr); + return oriWinMain(hInstance, hPrevInstance, lpCmdLine, nShowCmd); +} + +bool RunAsNode::Init() +{ + uint64_t baseAddr = 0; +#if defined(_WIN_PLATFORM_) + HMODULE wrapperModule = GetModuleHandleW(NULL); + if (wrapperModule == NULL) + throw std::runtime_error("Can't GetModuleHandle"); + baseAddr = reinterpret_cast(wrapperModule); + printf("baseAddr: %llx\n", baseAddr); +#elif defined(_MAC_PLATFORM_) + auto pmap = hak::get_maps(); + do + { + if (pmap->module_name.find("QQ") != std::string::npos && pmap->offset == 0) + { + baseAddr = pmap->start(); + printf("baseAddr: %llx\n", baseAddr); + break; + } + } while ((pmap = pmap->next()) != nullptr); +#elif defined(_LINUX_PLATFORM_) + auto pmap = hak::get_maps(); + do + { + if (pmap->module_name.find("QQ") != std::string::npos && pmap->offset == 0) + { + baseAddr = pmap->start(); + printf("baseAddr: %lx\n", baseAddr); + break; + } + } while ((pmap = pmap->next()) != nullptr); +#endif + if (baseAddr == 0) + throw std::runtime_error("Can't find hook address"); + + auto [callptr, funcptr] = mainAddrMap[CURRENT_VERSION]; + + uint8_t *abscallptr = reinterpret_cast(baseAddr + callptr); + oriWinMain = reinterpret_cast(moehoo::get_call_address(abscallptr)); + checkRunAsNode = reinterpret_cast(baseAddr + funcptr); + return moehoo::hook(abscallptr, &fakeWinMain); +} \ No newline at end of file diff --git a/src/run_as_node.h b/src/run_as_node.h new file mode 100644 index 0000000..3a1f597 --- /dev/null +++ b/src/run_as_node.h @@ -0,0 +1,8 @@ +#pragma once + +#include "../include/moehoo/hook.h" + +namespace RunAsNode +{ + bool Init(); +} \ No newline at end of file diff --git a/src/server.cpp b/src/server.cpp index 90f3bc1..ae5da20 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -4,7 +4,11 @@ #include -std::string ConstructResponse(const std::string &sign, const std::string &extra, const std::string &token) { +std::string Server::GetSign(const std::string_view &cmd, const std::string_view &src, const int seq) +{ + auto [signDataHex, extraDataHex, tokenDataHex] = Sign::Call(cmd, src, seq); + counter++; + rapidjson::StringBuffer buffer; rapidjson::Writer writer(buffer); @@ -12,26 +16,21 @@ std::string ConstructResponse(const std::string &sign, const std::string &extra, writer.Key("value"); writer.StartObject(); writer.Key("sign"); - writer.String(sign.c_str()); + writer.String(signDataHex.c_str()); writer.Key("extra"); - writer.String(extra.c_str()); + writer.String(extraDataHex.c_str()); writer.Key("token"); - writer.String(token.c_str()); + writer.String(tokenDataHex.c_str()); writer.EndObject(); writer.EndObject(); return buffer.GetString(); } -Server::Server(int port) { - printf("Start server on port: %d\n", port); - std::thread(&Server::Init, this, port) - .detach(); -} - -void Server::Init(int port) { - try { - svr.Post("/sign", [this](const httplib::Request &req, httplib::Response &res) { +void Server::Init() +{ + svr.Post("/sign", [this](const httplib::Request &req, httplib::Response &res) + { try { rapidjson::Document doc; doc.Parse(req.body.c_str(), req.body.size()); @@ -40,37 +39,31 @@ void Server::Init(int port) { std::string_view src = doc["src"].GetString(); int seq = doc["seq"].GetInt(); - auto [signDataHex, extraDataHex, tokenDataHex] = sign.Call(cmd, src, seq); - std::string buffer = ConstructResponse(signDataHex, extraDataHex, tokenDataHex); - counter++; + std::string buffer = GetSign(cmd, src, seq); res.set_content(buffer, "application/json"); } catch (...) { res.set_content("Bad Request", "text/plain"); res.status = httplib::StatusCode::BadRequest_400; - } - }); - - svr.Get("/sign", [this](const httplib::Request &req, httplib::Response &res) { + } }) + .Get("/sign", [this](const httplib::Request &req, httplib::Response &res) + { try { - std::string cmd = req.get_param_value("cmd"); - std::string src = req.get_param_value("src"); + std::string_view cmd = req.get_param_value("cmd"); + std::string_view src = req.get_param_value("src"); int seq = std::stoi(req.get_param_value("seq")); - auto [signDataHex, extraDataHex, tokenDataHex] = sign.Call(cmd, src, seq); - std::string buffer = ConstructResponse(signDataHex, extraDataHex, tokenDataHex); - counter++; + std::string buffer = GetSign(cmd, src, seq); res.set_content(buffer, "application/json"); } catch (...) { res.set_content("Bad Request", "text/plain"); res.status = httplib::StatusCode::BadRequest_400; - } - }); - - svr.Get("/ping", [](const httplib::Request &req, httplib::Response &res) { + } }) + .Get("/ping", [](const httplib::Request &req, httplib::Response &res) + { rapidjson::StringBuffer buffer; rapidjson::Writer writer(buffer); @@ -79,10 +72,9 @@ void Server::Init(int port) { writer.Int(0); writer.EndObject(); - res.set_content(buffer.GetString(), "application/json"); - }); - - svr.Get("/count", [this](const httplib::Request &req, httplib::Response &res) { + res.set_content(buffer.GetString(), "application/json"); }) + .Get("/count", [this](const httplib::Request &req, httplib::Response &res) + { rapidjson::StringBuffer buffer; rapidjson::Writer writer(buffer); @@ -91,12 +83,10 @@ void Server::Init(int port) { writer.String(std::to_string(counter.load()).c_str()); writer.EndObject(); - res.set_content(buffer.GetString(), "application/json"); - }); - - bool ret = svr.listen("0.0.0.0", port); - } - catch(std::exception &e) { - printf("Server init failed: %s\n", e.what()); - } + res.set_content(buffer.GetString(), "application/json"); }); +} + +bool Server::Run(const std::string &ip, int port) +{ + return svr.listen(ip.c_str(), port); } diff --git a/src/server.h b/src/server.h index 977a048..666ff9f 100644 --- a/src/server.h +++ b/src/server.h @@ -1,16 +1,18 @@ +#pragma once + #include "sign.h" #include "../include/cpp-httplib/httplib.h" class Server { -public: - Server(int port); - private: - Sign sign; httplib::Server svr; std::atomic counter = 0; private: - void Init(int port); + std::string Server::GetSign(const std::string_view &cmd, const std::string_view &src, const int seq); + +public: + void Init(); + bool Server::Run(const std::string &ip, int port); }; \ No newline at end of file diff --git a/src/sign.cpp b/src/sign.cpp index 313399c..54481f3 100644 --- a/src/sign.cpp +++ b/src/sign.cpp @@ -19,9 +19,12 @@ #include #endif +typedef int (*SignFunctionType)(const char *cmd, const unsigned char *src, size_t src_len, int seq, unsigned char *result); +SignFunctionType SignFunction = nullptr; + // 签名函数定义 #if defined(_WIN_PLATFORM_) -#define CURRENT_VERSION "9.9.10-24108" +#define CURRENT_VERSION "9.9.12-25234" #if defined(_X64_ARCH_) std::map addrMap = { {"9.9.2-16183", 0x2E0D0}, @@ -29,24 +32,22 @@ std::map addrMap = { {"9.9.9-23424", 0x2EB50}, {"9.9.9-23424", 0x2EB50}, {"9.9.10-24108", 0x2EB50}, - {"9.9.11-24568", 0xAA1A20} -}; + {"9.9.11-24568", 0xAA1A20}, + {"9.9.11-24815", 0xAB5510}, + {"9.9.12-25234", 0xA84980}}; #elif defined(_X86_ARCH_) std::map addrMap = { {"9.9.2-15962", 0x2BD70}, - {"9.9.2-16183", 0x2BD70} -}; + {"9.9.2-16183", 0x2BD70}}; #endif #elif defined(_MAC_PLATFORM_) #define CURRENT_VERSION "6.9.20-17153" #if defined(_X64_ARCH_) std::map addrMap = { - {"6.9.19-16183", 0x1B29469} -}; + {"6.9.19-16183", 0x1B29469}}; #elif defined(_ARM64_ARCH_) std::map addrMap = { - {"6.9.20-17153", 0x1c73dd0} -}; + {"6.9.20-17153", 0x1c73dd0}}; #endif #elif defined(_LINUX_PLATFORM_) #define CURRENT_VERSION "3.2.7-23361" @@ -54,12 +55,10 @@ std::map addrMap = { std::map addrMap = { {"3.1.2-12912", 0x33C38E0}, {"3.1.2-13107", 0x33C3920}, - {"3.2.7-23361", 0x4C93C57} -}; + {"3.2.7-23361", 0x4C93C57}}; #elif defined(_ARM64_ARCH_) std::map addrMap = { - {"3.2.7-23361", 0x351EC98} -}; + {"3.2.7-23361", 0x351EC98}}; #endif #endif @@ -67,13 +66,16 @@ int SignOffsets = 767; // 562 before 3.1.2-13107, 767 in others int ExtraOffsets = 511; int TokenOffsets = 255; -std::vector Hex2Bin(std::string_view str) { - if (str.length() % 2 != 0) { - throw std::invalid_argument("Hex string length must be even"); - } +std::vector Hex2Bin(std::string_view str) +{ + if (str.length() % 2 != 0) + { + throw std::invalid_argument("Hex string length must be even"); + } std::vector bin(str.size() / 2); std::string extract("00"); - for (size_t i = 0; i < str.size() / 2; i++) { + for (size_t i = 0; i < str.size() / 2; i++) + { extract[0] = str[2 * i]; extract[1] = str[2 * i + 1]; bin[i] = std::stoi(extract, nullptr, 16); @@ -81,45 +83,36 @@ std::vector Hex2Bin(std::string_view str) { return bin; } -std::string Bin2Hex(const uint8_t *ptr, size_t length) { +std::string Bin2Hex(const uint8_t *ptr, size_t length) +{ const char table[] = "0123456789ABCDEF"; std::string str; str.resize(length * 2); - for (size_t i = 0; i < length; ++i) { + for (size_t i = 0; i < length; ++i) + { str[2 * i] = table[ptr[i] / 16]; str[2 * i + 1] = table[ptr[i] % 16]; } return str; } -Sign::Sign() { - printf("Start init sign\n"); - std::thread([this]{ - while (true) { - try { - Init(); - break; - } - catch (const std::exception &e) { - printf("Init sign failed: %s\n", e.what()); - } - std::this_thread::sleep_for(std::chrono::seconds(1)); - } }).detach(); -} - -void Sign::Init() { +bool Sign::Init() +{ uint64_t HookAddress = 0; #if defined(_WIN_PLATFORM_) HMODULE wrapperModule = GetModuleHandleW(L"wrapper.node"); - if (wrapperModule == NULL) { - throw std::runtime_error("Can't find wrapper.node module"); - } + if (wrapperModule == NULL) + { + throw std::runtime_error("Can't find wrapper.node module"); + } HookAddress = reinterpret_cast(wrapperModule) + addrMap[CURRENT_VERSION]; printf("HookAddress: %llx\n", HookAddress); #elif defined(_MAC_PLATFORM_) auto pmap = hak::get_maps(); - do { - if (pmap->module_name.find("wrapper.node") != std::string::npos && pmap->offset == 0) { + do + { + if (pmap->module_name.find("wrapper.node") != std::string::npos && pmap->offset == 0) + { HookAddress = pmap->start() + addrMap[CURRENT_VERSION]; printf("HookAddress: %llx\n", HookAddress); break; @@ -127,29 +120,35 @@ void Sign::Init() { } while ((pmap = pmap->next()) != nullptr); #elif defined(_LINUX_PLATFORM_) auto pmap = hak::get_maps(); - do { - if (pmap->module_name.find("wrapper.node") != std::string::npos && pmap->offset == 0) { + do + { + if (pmap->module_name.find("wrapper.node") != std::string::npos && pmap->offset == 0) + { HookAddress = pmap->start() + addrMap[CURRENT_VERSION]; printf("HookAddress: %lx\n", HookAddress); break; } } while ((pmap = pmap->next()) != nullptr); #endif - if (HookAddress == 0) { - throw std::runtime_error("Can't find hook address"); - } + if (HookAddress == 0) + { + throw std::runtime_error("Can't find hook address"); + } SignFunction = reinterpret_cast(HookAddress); + return true; } -std::tuple Sign::Call(const std::string_view cmd, const std::string_view src, int seq) { - if (SignFunction == nullptr) { - throw std::runtime_error("Sign function not initialized"); - } +std::tuple Sign::Call(const std::string_view cmd, const std::string_view src, int seq) +{ + if (SignFunction == nullptr) + { + throw std::runtime_error("Sign function not initialized"); + } const std::vector signArgSrc = Hex2Bin(src); size_t resultSize = 1024; - auto *signResult = new uint8_t[resultSize]; + uint8_t *signResult = new uint8_t[resultSize]; SignFunction(cmd.data(), signArgSrc.data(), signArgSrc.size(), seq, signResult); diff --git a/src/sign.h b/src/sign.h index 408ea93..34fcd84 100644 --- a/src/sign.h +++ b/src/sign.h @@ -1,18 +1,10 @@ +#pragma once + #include #include -class Sign +namespace Sign { -public: - Sign(); - -private: - typedef int (*SignFunctionType)(const char *cmd, const unsigned char *src, size_t src_len, int seq, unsigned char *result); - SignFunctionType SignFunction = nullptr; - -private: - void Init(); - -public: + bool Init(); std::tuple Call(const std::string_view cmd, const std::string_view src, int seq); -}; \ No newline at end of file +} \ No newline at end of file diff --git a/src/version.asm b/src/version.asm deleted file mode 100644 index 0bbeb61..0000000 --- a/src/version.asm +++ /dev/null @@ -1,114 +0,0 @@ -ifdef _WIN_PLATFORM_ - ifdef RAX - .code - extern OriginalFuncs_version:QWORD - GetFileVersionInfoA proc - jmp QWORD ptr OriginalFuncs_version[0 * 8] - GetFileVersionInfoA endp - GetFileVersionInfoByHandle proc - jmp QWORD ptr OriginalFuncs_version[1 * 8] - GetFileVersionInfoByHandle endp - GetFileVersionInfoExA proc - jmp QWORD ptr OriginalFuncs_version[2 * 8] - GetFileVersionInfoExA endp - GetFileVersionInfoExW proc - jmp QWORD ptr OriginalFuncs_version[3 * 8] - GetFileVersionInfoExW endp - GetFileVersionInfoSizeA proc - jmp QWORD ptr OriginalFuncs_version[4 * 8] - GetFileVersionInfoSizeA endp - GetFileVersionInfoSizeExA proc - jmp QWORD ptr OriginalFuncs_version[5 * 8] - GetFileVersionInfoSizeExA endp - GetFileVersionInfoSizeExW proc - jmp QWORD ptr OriginalFuncs_version[6 * 8] - GetFileVersionInfoSizeExW endp - GetFileVersionInfoSizeW proc - jmp QWORD ptr OriginalFuncs_version[7 * 8] - GetFileVersionInfoSizeW endp - GetFileVersionInfoW proc - jmp QWORD ptr OriginalFuncs_version[8 * 8] - GetFileVersionInfoW endp - VerFindFileA proc - jmp QWORD ptr OriginalFuncs_version[9 * 8] - VerFindFileA endp - VerFindFileW proc - jmp QWORD ptr OriginalFuncs_version[10 * 8] - VerFindFileW endp - VerInstallFileA proc - jmp QWORD ptr OriginalFuncs_version[11 * 8] - VerInstallFileA endp - VerInstallFileW proc - jmp QWORD ptr OriginalFuncs_version[12 * 8] - VerInstallFileW endp - VerLanguageNameA proc - jmp QWORD ptr OriginalFuncs_version[13 * 8] - VerLanguageNameA endp - VerLanguageNameW proc - jmp QWORD ptr OriginalFuncs_version[14 * 8] - VerLanguageNameW endp - VerQueryValueA proc - jmp QWORD ptr OriginalFuncs_version[15 * 8] - VerQueryValueA endp - VerQueryValueW proc - jmp QWORD ptr OriginalFuncs_version[16 * 8] - VerQueryValueW endp - else - .model flat, C - .stack 4096 - .code - extern OriginalFuncs_version:DWORD - GetFileVersionInfoA proc - jmp DWORD ptr OriginalFuncs_version[0 * 4] - GetFileVersionInfoA endp - GetFileVersionInfoByHandle proc - jmp DWORD ptr OriginalFuncs_version[1 * 4] - GetFileVersionInfoByHandle endp - GetFileVersionInfoExA proc - jmp DWORD ptr OriginalFuncs_version[2 * 4] - GetFileVersionInfoExA endp - GetFileVersionInfoExW proc - jmp DWORD ptr OriginalFuncs_version[3 * 4] - GetFileVersionInfoExW endp - GetFileVersionInfoSizeA proc - jmp DWORD ptr OriginalFuncs_version[4 * 4] - GetFileVersionInfoSizeA endp - GetFileVersionInfoSizeExA proc - jmp DWORD ptr OriginalFuncs_version[5 * 4] - GetFileVersionInfoSizeExA endp - GetFileVersionInfoSizeExW proc - jmp DWORD ptr OriginalFuncs_version[6 * 4] - GetFileVersionInfoSizeExW endp - GetFileVersionInfoSizeW proc - jmp DWORD ptr OriginalFuncs_version[7 * 4] - GetFileVersionInfoSizeW endp - GetFileVersionInfoW proc - jmp DWORD ptr OriginalFuncs_version[8 * 4] - GetFileVersionInfoW endp - VerFindFileA proc - jmp DWORD ptr OriginalFuncs_version[9 * 4] - VerFindFileA endp - VerFindFileW proc - jmp DWORD ptr OriginalFuncs_version[10 * 4] - VerFindFileW endp - VerInstallFileA proc - jmp DWORD ptr OriginalFuncs_version[11 * 4] - VerInstallFileA endp - VerInstallFileW proc - jmp DWORD ptr OriginalFuncs_version[12 * 4] - VerInstallFileW endp - VerLanguageNameA proc - jmp DWORD ptr OriginalFuncs_version[13 * 4] - VerLanguageNameA endp - VerLanguageNameW proc - jmp DWORD ptr OriginalFuncs_version[14 * 4] - VerLanguageNameW endp - VerQueryValueA proc - jmp DWORD ptr OriginalFuncs_version[15 * 4] - VerQueryValueA endp - VerQueryValueW proc - jmp DWORD ptr OriginalFuncs_version[16 * 4] - VerQueryValueW endp - endif -endif -end \ No newline at end of file diff --git a/start.bat b/start.bat index adf1262..7ca2eee 100644 --- a/start.bat +++ b/start.bat @@ -22,15 +22,9 @@ if not exist "%pathWithoutUninstall%version.dll" ( set /p Choice="version.dll already exists, do you want to replace it?(Y/N):" if /i "!Choice!"=="Y" goto copydll if /i "!Choice!"=="y" goto copydll + goto launch ) -:launch -set "QQPath=!pathWithoutUninstall!QQ.exe" -set ELECTRON_RUN_AS_NODE=1 - -echo Launching QQ -"!QQPath!" "%~dp0load.js" %* - :copydll copy /y "%~dp0SignerServer.dll" "%pathWithoutUninstall%version.dll" if errorlevel 1 ( @@ -42,4 +36,11 @@ if errorlevel 1 ( goto launch :restart - powershell Start-Process -FilePath cmd.exe -ArgumentList """/c pushd %~dp0 && %~s0 %*""" -Verb RunAs \ No newline at end of file + powershell Start-Process -FilePath cmd.exe -ArgumentList """/c pushd %~dp0 && %~s0 %*""" -Verb RunAs + +:launch +set "QQPath=!pathWithoutUninstall!QQ.exe" +set ELECTRON_RUN_AS_NODE=1 + +echo Launching QQ +"!QQPath!" "%~dp0load.js" %* \ No newline at end of file diff --git a/version.def b/version.def deleted file mode 100644 index 23859ab..0000000 --- a/version.def +++ /dev/null @@ -1,18 +0,0 @@ -EXPORTS - GetFileVersionInfoA - GetFileVersionInfoByHandle - GetFileVersionInfoExA - GetFileVersionInfoExW - GetFileVersionInfoSizeA - GetFileVersionInfoSizeExA - GetFileVersionInfoSizeExW - GetFileVersionInfoSizeW - GetFileVersionInfoW - VerFindFileA - VerFindFileW - VerInstallFileA - VerInstallFileW - VerLanguageNameA - VerLanguageNameW - VerQueryValueA - VerQueryValueW \ No newline at end of file