diff --git a/WeChatFerry/com/log.hpp b/WeChatFerry/com/log.hpp index 4be5e76..380a8c6 100644 --- a/WeChatFerry/com/log.hpp +++ b/WeChatFerry/com/log.hpp @@ -3,13 +3,12 @@ #include #include #include -#include -#include -#include #include #include -#include "util.h" +#include +#include +#include #define LOG_DEBUG(...) SPDLOG_DEBUG(__VA_ARGS__) #define LOG_INFO(...) SPDLOG_INFO(__VA_ARGS__) @@ -48,7 +47,7 @@ inline void InitLogger(const std::string &path) logger = spdlog::rotating_logger_mt(DEFAULT_LOGGER_NAME, filename.string(), DEFAULT_LOGGER_MAX_SIZE, DEFAULT_LOGGER_MAX_FILES); } catch (const spdlog::spdlog_ex &ex) { - MessageBox(NULL, util::s2w(ex.what()).c_str(), L"Init LOGGER ERROR", MB_ICONERROR); + MessageBoxA(NULL, ex.what(), "Init LOGGER ERROR", MB_ICONERROR); return; } diff --git a/WeChatFerry/com/util.cpp b/WeChatFerry/com/util.cpp index ed2a302..2481124 100644 --- a/WeChatFerry/com/util.cpp +++ b/WeChatFerry/com/util.cpp @@ -18,6 +18,9 @@ namespace util { +constexpr std::wstring_view WECHATEXE = L"WeChat.exe"; +constexpr std::string_view WECHATWINDLL = "WeChatWin.dll"; + std::wstring s2w(const std::string &s) { if (s.empty()) return std::wstring(); @@ -60,7 +63,7 @@ static DWORD get_wechat_pid() PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) }; while (Process32Next(hSnapshot, &pe32)) { - if (w2s(pe32.szExeFile) == WECHATEXE) { + if (pe32.szExeFile == WECHATEXE) { pid = pe32.th32ProcessID; break; } diff --git a/WeChatFerry/com/util.h b/WeChatFerry/com/util.h index 71d0bd7..c4715cd 100644 --- a/WeChatFerry/com/util.h +++ b/WeChatFerry/com/util.h @@ -9,13 +9,6 @@ namespace util { - -inline constexpr char WECHATEXE[] = "WeChat.exe"; -inline constexpr char WECHATWINDLL[] = "WeChatWin.dll"; -inline constexpr wchar_t WCFSDKDLL[] = L"sdk.dll"; -inline constexpr wchar_t WCFSPYDLL[] = L"spy.dll"; -inline constexpr wchar_t WCFSPYDLL_DEBUG[] = L"spy_debug.dll"; - struct PortPath { int port; char path[MAX_PATH]; diff --git a/WeChatFerry/sdk/injector.cpp b/WeChatFerry/sdk/injector.cpp index 975faa9..d990854 100644 --- a/WeChatFerry/sdk/injector.cpp +++ b/WeChatFerry/sdk/injector.cpp @@ -1,112 +1,108 @@ -#include "framework.h" -#include "psapi.h" -#include -#include +#include "injector.h" -#include "injector.h" -#include "util.h" +#include + +#include "psapi.h" using namespace std; -HMODULE GetTargetModuleBase(HANDLE process, string dll) +static void handle_injection_error(HANDLE process, LPVOID remote_address, const std::string &error_msg) { - DWORD cbNeeded; - HMODULE moduleHandleList[512]; - BOOL ret = EnumProcessModulesEx(process, moduleHandleList, sizeof(moduleHandleList), &cbNeeded, LIST_MODULES_64BIT); - if (!ret) { - MessageBox(NULL, L"获取模块失败", L"GetTargetModuleBase", 0); + MessageBoxA(NULL, error_msg.c_str(), "Error", MB_ICONERROR); + if (remote_address) { + VirtualFreeEx(process, remote_address, 0, MEM_RELEASE); + } + if (process) { + CloseHandle(process); + } +} + +HMODULE get_target_module_base(HANDLE process, const string &dll) +{ + DWORD needed; + HMODULE modules[512]; + if (!EnumProcessModulesEx(process, modules, sizeof(modules), &needed, LIST_MODULES_64BIT)) { + MessageBoxA(NULL, "获取模块失败", "get_target_module_base", 0); return NULL; } - if (cbNeeded > sizeof(moduleHandleList)) { - MessageBox(NULL, L"模块数量过多", L"GetTargetModuleBase", 0); - return NULL; - } - DWORD processCount = cbNeeded / sizeof(HMODULE); - - char moduleName[32]; - for (DWORD i = 0; i < processCount; i++) { - GetModuleBaseNameA(process, moduleHandleList[i], moduleName, 32); - if (!strncmp(dll.c_str(), moduleName, dll.size())) { - return moduleHandleList[i]; + DWORD count = needed / sizeof(HMODULE); + char module_name[MAX_PATH]; + for (DWORD i = 0; i < count; i++) { + GetModuleBaseNameA(process, modules[i], module_name, sizeof(module_name)); + if (!strncmp(dll.c_str(), module_name, dll.size())) { + return modules[i]; } } return NULL; } -HANDLE InjectDll(DWORD pid, LPCWSTR dllPath, HMODULE *injectedBase) +HANDLE inject_dll(DWORD pid, const string &dll_path, HMODULE *injected_base) { - HANDLE hThread; - SIZE_T cszDLL = (wcslen(dllPath) + 1) * sizeof(WCHAR); + SIZE_T path_size = dll_path.size() + 1; // 1. 打开目标进程 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); - if (hProcess == NULL) { - MessageBox(NULL, L"打开进程失败", L"InjectDll", 0); + if (!hProcess) { + MessageBoxA(NULL, "打开进程失败", "inject_dll", 0); return NULL; } // 2. 在目标进程的内存里开辟空间 - LPVOID pRemoteAddress = VirtualAllocEx(hProcess, NULL, cszDLL, MEM_COMMIT, PAGE_READWRITE); - if (pRemoteAddress == NULL) { - MessageBox(NULL, L"DLL 路径写入失败", L"InjectDll", 0); + LPVOID pRemoteAddress = VirtualAllocEx(hProcess, NULL, path_size, MEM_COMMIT, PAGE_READWRITE); + if (!pRemoteAddress) { + handle_injection_error(hProcess, NULL, "DLL 路径写入失败"); return NULL; } // 3. 把 dll 的路径写入到目标进程的内存空间中 - WriteProcessMemory(hProcess, pRemoteAddress, dllPath, cszDLL, NULL); + WriteProcessMemory(hProcess, pRemoteAddress, dll_path.c_str(), path_size, NULL); - // 3. 创建一个远程线程,让目标进程调用 LoadLibrary - HMODULE k32 = GetModuleHandle(L"kernel32.dll"); - if (k32 == NULL) { - MessageBox(NULL, L"获取 kernel32 失败", L"InjectDll", 0); + // 4. 创建一个远程线程,让目标进程调用 LoadLibrary + HMODULE k32 = GetModuleHandleA("kernel32.dll"); + if (!k32) { + handle_injection_error(hProcess, pRemoteAddress, "获取 kernel32 失败"); return NULL; } - FARPROC libAddr = GetProcAddress(k32, "LoadLibraryW"); + FARPROC libAddr = GetProcAddress(k32, "LoadLibraryA"); if (!libAddr) { - MessageBox(NULL, L"获取 LoadLibrary 失败", L"InjectDll", 0); + handle_injection_error(hProcess, pRemoteAddress, "获取 LoadLibrary 失败"); return NULL; } - hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)libAddr, pRemoteAddress, 0, NULL); - if (hThread == NULL) { - VirtualFreeEx(hProcess, pRemoteAddress, 0, MEM_RELEASE); - CloseHandle(hProcess); - MessageBox(NULL, L"CreateRemoteThread 失败", L"InjectDll", 0); + HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)libAddr, pRemoteAddress, 0, NULL); + if (!hThread) { + handle_injection_error(hProcess, pRemoteAddress, "CreateRemoteThread 失败"); return NULL; } - WaitForSingleObject(hThread, -1); + WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); - *injectedBase = GetTargetModuleBase(hProcess, filesystem::path(util::w2s(dllPath)).filename().string()); + *injected_base = get_target_module_base(hProcess, filesystem::path(dll_path).filename().string()); VirtualFreeEx(hProcess, pRemoteAddress, 0, MEM_RELEASE); - // CloseHandle(hProcess); // Close when exit - return hProcess; } -bool EjectDll(HANDLE process, HMODULE dllBase) +bool eject_dll(HANDLE process, HMODULE dll_base) { - HANDLE hThread = NULL; - - // 使目标进程调用 FreeLibrary,卸载 DLL - HMODULE k32 = GetModuleHandle(L"kernel32.dll"); - if (k32 == NULL) { - MessageBox(NULL, L"获取 kernel32 失败", L"InjectDll", 0); - return NULL; + HMODULE k32 = GetModuleHandleA("kernel32.dll"); + if (!k32) { + MessageBoxA(NULL, "获取 kernel32 失败", "eject_dll", 0); + return false; } FARPROC libAddr = GetProcAddress(k32, "FreeLibraryAndExitThread"); if (!libAddr) { - MessageBox(NULL, L"获取 FreeLibrary 失败", L"InjectDll", 0); - return NULL; + MessageBoxA(NULL, "获取 FreeLibrary 失败", "eject_dll", 0); + return false; } - hThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)libAddr, (LPVOID)dllBase, 0, NULL); - if (hThread == NULL) { - MessageBox(NULL, L"FreeLibrary 调用失败!", L"EjectDll", 0); + + HANDLE hThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)libAddr, (LPVOID)dll_base, 0, NULL); + if (!hThread) { + MessageBoxA(NULL, "FreeLibrary 调用失败!", "eject_dll", 0); return false; } @@ -116,38 +112,34 @@ bool EjectDll(HANDLE process, HMODULE dllBase) return true; } -static UINT64 GetFuncOffset(LPCWSTR dllPath, LPCSTR funcName) +static uint64_t get_func_offset(const string &dll_path, const string &func_name) { - HMODULE dll = LoadLibrary(dllPath); - if (dll == NULL) { - MessageBox(NULL, L"获取 DLL 失败", L"GetFuncOffset", 0); + HMODULE dll = LoadLibraryA(dll_path.c_str()); + if (!dll) { + MessageBoxA(NULL, "获取 DLL 失败", "get_func_offset", 0); return 0; } - LPVOID absAddr = GetProcAddress(dll, funcName); - UINT64 offset = (UINT64)absAddr - (UINT64)dll; + LPVOID absAddr = GetProcAddress(dll, func_name.c_str()); + uint64_t offset = reinterpret_cast(absAddr) - reinterpret_cast(dll); FreeLibrary(dll); return offset; } -bool CallDllFunc(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, LPDWORD ret) +bool call_dll_func(HANDLE process, const string &dll_path, HMODULE dll_base, const string &func_name, DWORD *ret) { - UINT64 offset = GetFuncOffset(dllPath, funcName); - if (offset == 0) { - return false; + uint64_t offset = get_func_offset(dll_path, func_name); + if (offset == 0 || offset > (UINT64_MAX - reinterpret_cast(dll_base))) { + return false; // 避免溢出 } - UINT64 pFunc = (UINT64)dllBase + GetFuncOffset(dllPath, funcName); - if (pFunc <= (UINT64)dllBase) { - return false; - } - + uint64_t pFunc = reinterpret_cast(dll_base) + offset; HANDLE hThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, NULL, 0, NULL); - if (hThread == NULL) { + if (!hThread) { return false; } WaitForSingleObject(hThread, INFINITE); - if (ret != NULL) { + if (ret) { GetExitCodeThread(hThread, ret); } @@ -155,35 +147,32 @@ bool CallDllFunc(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcNa return true; } -bool CallDllFuncEx(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, LPVOID parameter, size_t sz, - LPDWORD ret) +bool call_dll_func_ex(HANDLE process, const string &dll_path, HMODULE dll_base, const string &func_name, + LPVOID parameter, size_t size, DWORD *ret) { - UINT64 offset = GetFuncOffset(dllPath, funcName); - if (offset == 0) { - return false; + uint64_t offset = get_func_offset(dll_path, func_name); + if (offset == 0 || offset > (UINT64_MAX - reinterpret_cast(dll_base))) { + return false; // 避免溢出 } - UINT64 pFunc = (UINT64)dllBase + GetFuncOffset(dllPath, funcName); - if (pFunc <= (UINT64)dllBase) { + uint64_t pFunc = reinterpret_cast(dll_base) + offset; + LPVOID pRemoteAddress = VirtualAllocEx(process, NULL, size, MEM_COMMIT, PAGE_READWRITE); + if (!pRemoteAddress) { + MessageBoxA(NULL, "申请内存失败", "call_dll_func_ex", 0); return false; } - LPVOID pRemoteAddress = VirtualAllocEx(process, NULL, sz, MEM_COMMIT, PAGE_READWRITE); - if (pRemoteAddress == NULL) { - MessageBox(NULL, L"申请内存失败", L"CallDllFuncEx", 0); - return NULL; - } - - WriteProcessMemory(process, pRemoteAddress, parameter, sz, NULL); + WriteProcessMemory(process, pRemoteAddress, parameter, size, NULL); HANDLE hThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, pRemoteAddress, 0, NULL); - if (hThread == NULL) { - VirtualFree(pRemoteAddress, 0, MEM_RELEASE); - MessageBox(NULL, L"远程调用失败", L"CallDllFuncEx", 0); + if (!hThread) { + VirtualFreeEx(process, pRemoteAddress, 0, MEM_RELEASE); + MessageBoxA(NULL, "远程调用失败", "call_dll_func_ex", 0); return false; } + WaitForSingleObject(hThread, INFINITE); - VirtualFree(pRemoteAddress, 0, MEM_RELEASE); - if (ret != NULL) { + VirtualFreeEx(process, pRemoteAddress, 0, MEM_RELEASE); + if (ret) { GetExitCodeThread(hThread, ret); } diff --git a/WeChatFerry/sdk/injector.h b/WeChatFerry/sdk/injector.h index 07b4a28..83988a6 100644 --- a/WeChatFerry/sdk/injector.h +++ b/WeChatFerry/sdk/injector.h @@ -1,9 +1,11 @@ #pragma once +#include + #include "framework.h" -HANDLE InjectDll(DWORD pid, LPCWSTR dllPath, HMODULE *injectedBase); -bool EjectDll(HANDLE process, HMODULE dllBase); -bool CallDllFunc(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, DWORD *ret); -bool CallDllFuncEx(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, LPVOID parameter, size_t sz, - DWORD *ret); +HANDLE inject_dll(DWORD pid, const std::string &dll_path, HMODULE *injected_base); +bool eject_dll(HANDLE process, HMODULE dll_base); +bool call_dll_func(HANDLE process, const std::string &dll_path, HMODULE dll_base, const std::string &func, DWORD *ret); +bool call_dll_func_ex(HANDLE process, const std::string &dll_path, HMODULE dll_base, const std::string &func, + LPVOID parameter, size_t size, DWORD *ret); diff --git a/WeChatFerry/sdk/sdk.cpp b/WeChatFerry/sdk/sdk.cpp index fca3b0f..69ff632 100644 --- a/WeChatFerry/sdk/sdk.cpp +++ b/WeChatFerry/sdk/sdk.cpp @@ -1,4 +1,5 @@ -#include "framework.h" +#include "sdk.h" + #include #include #include @@ -6,55 +7,56 @@ #include #include #include + +#include "framework.h" #include #include "injector.h" -#include "sdk.h" #include "util.h" -static BOOL injected = false; +static bool injected = false; static HANDLE wcProcess = NULL; static HMODULE spyBase = NULL; -static std::wstring spyDllPath; +static std::string spyDllPath; -constexpr char DISCLAIMER_FILE[] = ".license_accepted.flag"; -constexpr char DISCLAIMER_TEXT_FILE[] = "DISCLAIMER.md"; +constexpr std::string_view WCFSDKDLL = "sdk.dll"; +constexpr std::string_view WCFSPYDLL = "spy.dll"; +constexpr std::string_view WCFSPYDLL_DEBUG = "spy_debug.dll"; +constexpr std::string_view DISCLAIMER_FLAG = ".license_accepted.flag"; +constexpr std::string_view DISCLAIMER_TEXT_FILE = "DISCLAIMER.md"; -static std::optional ReadDisclaimerText(const char *filePath) +static std::optional read_disclaimer_text(const std::string &path) { - std::ifstream file(filePath, std::ios::binary); + std::ifstream file(path, std::ios::binary); if (!file.is_open()) { return std::nullopt; // 文件打开失败 } - std::string content((std::istreambuf_iterator(file)), std::istreambuf_iterator()); - return util::s2w(content); + return std::string((std::istreambuf_iterator(file)), std::istreambuf_iterator()); } -static bool ShowDisclaimer() +static bool show_disclaimer() { - if (std::filesystem::exists(DISCLAIMER_FILE)) { + if (std::filesystem::exists(DISCLAIMER_FLAG)) { return true; } - std::optional disclaimerTextOpt = ReadDisclaimerText(DISCLAIMER_TEXT_FILE); - if (!disclaimerTextOpt.has_value() || disclaimerTextOpt->empty()) { - MessageBox(NULL, L"免责声明文件为空或读取失败。", L"错误", MB_ICONERROR); + auto disclaimerTextOpt = read_disclaimer_text(std::string(DISCLAIMER_TEXT_FILE)); + if (!disclaimerTextOpt || disclaimerTextOpt->empty()) { + MessageBoxA(NULL, "免责声明文件为空或读取失败。", "错误", MB_ICONERROR); return false; } - std::wstring disclaimerText = *disclaimerTextOpt; - - int result = MessageBox(NULL, disclaimerText.c_str(), L"免责声明", MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON2); - + int result + = MessageBoxA(NULL, disclaimerTextOpt->c_str(), "免责声明", MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON2); if (result == IDCANCEL) { - MessageBox(NULL, L"您拒绝了免责声明,程序将退出。", L"提示", MB_ICONINFORMATION); + MessageBoxA(NULL, "您拒绝了免责声明,程序将退出。", "提示", MB_ICONINFORMATION); return false; } - std::ofstream flagFile(DISCLAIMER_FILE, std::ios::out | std::ios::trunc); + std::ofstream flagFile(std::string(DISCLAIMER_FLAG), std::ios::out | std::ios::trunc); if (!flagFile) { - MessageBox(NULL, L"无法创建协议标志文件。", L"错误", MB_ICONERROR); + MessageBoxA(NULL, "无法创建协议标志文件。", "错误", MB_ICONERROR); return false; } flagFile << "User accepted the license agreement."; @@ -62,62 +64,56 @@ static bool ShowDisclaimer() return true; } -static std::wstring GetDllPath(bool debug) +static std::string get_dll_path(bool debug) { - WCHAR buffer[MAX_PATH] = { 0 }; - GetModuleFileName(GetModuleHandle(WCFSDKDLL), buffer, MAX_PATH); + char buffer[MAX_PATH] = { 0 }; + GetModuleFileNameA(GetModuleHandleA(WCFSDKDLL), buffer, MAX_PATH); std::filesystem::path path(buffer); - path.remove_filename(); // 移除文件名,保留目录路径 - + path.remove_filename(); // 只保留目录路径 path /= debug ? WCFSPYDLL_DEBUG : WCFSPYDLL; if (!std::filesystem::exists(path)) { - MessageBox(NULL, path.c_str(), L"文件不存在", MB_ICONERROR); - return L""; + MessageBoxA(NULL, path.string().c_str(), "文件不存在", MB_ICONERROR); + return ""; } - return path.wstring(); + return path.string(); } int WxInitSDK(bool debug, int port) { - if (!ShowDisclaimer()) { + if (!show_disclaimer()) { exit(-1); // 用户拒绝协议,退出程序 } int status = 0; DWORD wcPid = 0; - spyDllPath = GetDllPath(debug); + spyDllPath = get_dll_path(debug); if (spyDllPath.empty()) { return ERROR_FILE_NOT_FOUND; // DLL 文件路径不存在 } status = util::open_wechat(&wcPid); if (status != 0) { - MessageBox(NULL, L"打开微信失败", L"WxInitSDK", 0); + MessageBoxA(NULL, "打开微信失败", "WxInitSDK", 0); return status; } - if (!IsProcessX64(wcPid)) { - MessageBox(NULL, L"只支持 64 位微信", L"WxInitSDK", 0); - return -1; - } - std::this_thread::sleep_for(std::chrono::seconds(2)); // 等待微信打开 - wcProcess = InjectDll(wcPid, spyDllPath.c_str(), &spyBase); + wcProcess = inject_dll(wcPid, spyDllPath, &spyBase); if (wcProcess == NULL) { - MessageBox(NULL, L"注入失败", L"WxInitSDK", 0); + MessageBoxA(NULL, "注入失败", "WxInitSDK", 0); return -1; } - PortPath_t pp = { 0 }; - pp.port = port; - sprintf_s(pp.path, MAX_PATH, "%s", std::filesystem::current_path().string().c_str()); + util::PortPath pp = { 0 }; + pp.port = port; + snprintf(pp.path, MAX_PATH, "%s", std::filesystem::current_path().string().c_str()); - if (!CallDllFuncEx(wcProcess, spyDllPath.c_str(), spyBase, "InitSpy", (LPVOID)&pp, sizeof(PortPath_t), NULL)) { - MessageBox(NULL, L"初始化失败", L"WxInitSDK", 0); + if (!call_dll_func_ex(wcProcess, spyDllPath, spyBase, "InitSpy", (LPVOID)&pp, sizeof(PortPath_t), NULL)) { + MessageBoxA(NULL, "初始化失败", "WxInitSDK", 0); return -1; } @@ -128,16 +124,16 @@ int WxInitSDK(bool debug, int port) int WxDestroySDK() { if (!injected) { + return 1; // 未注入 + } + + if (!call_dll_func(wcProcess, spyDllPath, spyBase, "CleanupSpy", NULL)) { return -1; } - if (!CallDllFunc(wcProcess, spyDllPath.c_str(), spyBase, "CleanupSpy", NULL)) { + if (!eject_dll(wcProcess, spyBase)) { return -2; } - if (!EjectDll(wcProcess, spyBase)) { - return -3; // TODO: Unify error codes - } - return 0; }