diff --git a/CMakeLists.txt b/CMakeLists.txt index efffcd4..1b7f492 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,17 +7,24 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") add_definitions(-D _WIN_PLATFORM_) link_libraries(ws2_32) + + enable_language(ASM) + SET(CMAKE_ASM_FLAGS "${CFLAGS} -x assembler-with-cpp") elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin") add_definitions(-D _MAC_PLATFORM_) elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") add_definitions(-D _LINUX_PLATFORM_) endif() - - # 设置CPP标准 set(CMAKE_CXX_STANDARD 17) -file(GLOB SOURCE_FILES "./src/*.cpp") +file(GLOB SOURCE_FILES "./src/*.cpp" "./src/*.asm") -add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} "./include/mongoose/mongoose.c") \ No newline at end of file +add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} "./include/mongoose/mongoose.c") + +if(MSVC) + target_link_options(SignerServer PRIVATE + /DEF:${CMAKE_CURRENT_SOURCE_DIR}/version.def + ) +endif() \ No newline at end of file diff --git a/load.js b/load.js new file mode 100644 index 0000000..b8ec99e --- /dev/null +++ b/load.js @@ -0,0 +1 @@ +require("/opt/QQ/resources/app/wrapper.node"); \ No newline at end of file diff --git a/signserver.sh b/signserver.sh new file mode 100644 index 0000000..e8de087 --- /dev/null +++ b/signserver.sh @@ -0,0 +1,4 @@ +#!/bin/bash +SCRIPT_DIR=$(realpath $(dirname "${BASH_SOURCE[0]}")) +export ELECTRON_RUN_AS_NODE=1 +LD_PRELOAD=./libSignerServer.so /opt/QQ/qq ${SCRIPT_DIR}/load.js $@ diff --git a/src/exports.cpp b/src/exports.cpp new file mode 100644 index 0000000..2479184 --- /dev/null +++ b/src/exports.cpp @@ -0,0 +1,29 @@ +#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"); + + // 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 new file mode 100644 index 0000000..bf04db2 --- /dev/null +++ b/src/exports.h @@ -0,0 +1,31 @@ +#pragma once +#include +#include +#include + +extern "C" FARPROC OriginalFuncs_version[17]; + +inline std::vector ExportNames_version = { + "GetFileVersionInfoA", + "GetFileVersionInfoByHandle", + "GetFileVersionInfoExA", + "GetFileVersionInfoExW", + "GetFileVersionInfoSizeA", + "GetFileVersionInfoSizeExA", + "GetFileVersionInfoSizeExW", + "GetFileVersionInfoSizeW", + "GetFileVersionInfoW", + "VerFindFileA", + "VerFindFileW", + "VerInstallFileA", + "VerInstallFileW", + "VerLanguageNameA", + "VerLanguageNameW", + "VerQueryValueA", + "VerQueryValueW" +}; + +namespace Exports +{ + void Load(); +} \ No newline at end of file diff --git a/src/hijacker.cpp b/src/hijacker.cpp new file mode 100644 index 0000000..89691ba --- /dev/null +++ b/src/hijacker.cpp @@ -0,0 +1,23 @@ +#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 + Exports::Load(); + TlsOnce = true; + } +} + +#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; + +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 08276b4..81796d1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,17 +1,3 @@ -#include "sign.h" #include "server.h" -#include - -int main() -{ - try - { - sign::InitSignCall(); - server::init(8080); - } - catch (const std::exception &e) - { - std::cerr << e.what() << std::endl; - } -} \ No newline at end of file +Server server(8080); \ No newline at end of file diff --git a/src/server.cpp b/src/server.cpp index 86cd7ab..f48692a 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1,9 +1,12 @@ -#include "server.h" #include "sign.h" -#include "../include/mongoose/mongoose.h" +#include "server.h" #include "../include/rapidjson/document.h" #include "../include/rapidjson/writer.h" +#include + +Sign sign; + // HTTP server event handler function void ev_handler(struct mg_connection *c, int ev, void *ev_data) { @@ -21,7 +24,7 @@ void ev_handler(struct mg_connection *c, int ev, void *ev_data) std::string_view src = doc["src"].GetString(); int seq = doc["seq"].GetInt64(); - auto [signDataHex, extraDataHex, tokenDataHex] = sign::CallSign(cmd, src, seq); + auto [signDataHex, extraDataHex, tokenDataHex] = sign.Call(cmd, src, seq); // Construct response rapidjson::StringBuffer buffer; @@ -55,14 +58,21 @@ void ev_handler(struct mg_connection *c, int ev, void *ev_data) } } -void server::init(int port) +Server::Server(int port) { char url[32]; snprintf(url, sizeof(url), "http://0.0.0.0:%d", port); - struct mg_mgr mgr; // Declare event manager - mg_mgr_init(&mgr); // Initialise event manager + mg_mgr_init(&mgr); // Initialise event manager mg_http_listen(&mgr, url, ev_handler, NULL); // Setup listener + + // new thread to loop + std::thread t(&Server::Loop, this); + t.detach(); +} + +void Server::Loop() +{ for (;;) { // Run an infinite event loop mg_mgr_poll(&mgr, 1000); diff --git a/src/server.h b/src/server.h index a205293..25bd94d 100644 --- a/src/server.h +++ b/src/server.h @@ -1,5 +1,13 @@ +#include "../include/mongoose/mongoose.h" -namespace server +class Server { - void init(const int port); -} \ No newline at end of file +public: + Server(int port); + +private: + struct mg_mgr mgr; // Declare event manager + +private: + void Loop(); +}; \ No newline at end of file diff --git a/src/sign.cpp b/src/sign.cpp index 79900b7..f4f2019 100644 --- a/src/sign.cpp +++ b/src/sign.cpp @@ -6,8 +6,10 @@ #include #include -// #define _LINUX_PLATFORM_ -#define _WIN_PLATFORM_ +#include + +#define _LINUX_PLATFORM_ +// #define _WIN_PLATFORM_ #define _X64_ARCH_ @@ -60,11 +62,12 @@ 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++) { - std::stringstream ss; - ss << std::hex << str.substr(i * 2, 2); - ss >> bin[i]; + extract[0] = str[2 * i]; + extract[1] = str[2 * i + 1]; + bin[i] = std::stoi(extract, nullptr, 16); } return bin; } @@ -82,10 +85,13 @@ std::string Bin2Hex(const uint8_t *ptr, size_t length) return str; } -typedef int (*SignFunctionType)(const char *cmd, const unsigned char *src, size_t src_len, int seq, unsigned char *result); -SignFunctionType SignFunction = nullptr; +Sign::Sign() +{ + std::thread t(&Sign::InitEx, this); + t.detach(); +} -void sign::InitSignCall() +void Sign::Init() { uint64_t HookAddress = 0; #if defined(_WIN_PLATFORM_) @@ -124,7 +130,22 @@ void sign::InitSignCall() SignFunction = reinterpret_cast(HookAddress); } -std::tuple sign::CallSign(const std::string_view cmd, const std::string_view src, int seq) +void Sign::InitEx() +{ + while (true) + try + { + Init(); + break; + } + catch (const std::exception &e) + { + std::cerr << e.what() << '\n'; + std::this_thread::sleep_for(std::chrono::seconds(1)); + } +} + +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"); diff --git a/src/sign.h b/src/sign.h index ee938fc..c748c86 100644 --- a/src/sign.h +++ b/src/sign.h @@ -1,8 +1,17 @@ #include #include -namespace sign +class Sign { - void InitSignCall(); - std::tuple CallSign(const std::string_view cmd, const std::string_view src, int seq); -} \ No newline at end of file +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; + void Init(); + void InitEx(); + +public: + std::tuple Call(const std::string_view cmd, const std::string_view src, int seq); +}; \ No newline at end of file diff --git a/src/version.asm b/src/version.asm new file mode 100644 index 0000000..0bbeb61 --- /dev/null +++ b/src/version.asm @@ -0,0 +1,114 @@ +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/version.def b/version.def new file mode 100644 index 0000000..23859ab --- /dev/null +++ b/version.def @@ -0,0 +1,18 @@ +EXPORTS + GetFileVersionInfoA + GetFileVersionInfoByHandle + GetFileVersionInfoExA + GetFileVersionInfoExW + GetFileVersionInfoSizeA + GetFileVersionInfoSizeExA + GetFileVersionInfoSizeExW + GetFileVersionInfoSizeW + GetFileVersionInfoW + VerFindFileA + VerFindFileW + VerInstallFileA + VerInstallFileW + VerLanguageNameA + VerLanguageNameW + VerQueryValueA + VerQueryValueW \ No newline at end of file