Refactoring

This commit is contained in:
Changhua 2025-02-04 20:40:46 +08:00
parent 1bec8ce8a2
commit e012efc682
6 changed files with 146 additions and 164 deletions

View File

@ -3,13 +3,12 @@
#include <filesystem>
#include <iomanip>
#include <memory>
#include <spdlog/sinks/rotating_file_sink.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/spdlog.h>
#include <sstream>
#include <string>
#include "util.h"
#include <spdlog/sinks/rotating_file_sink.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/spdlog.h>
#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;
}

View File

@ -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;
}

View File

@ -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];

View File

@ -1,112 +1,108 @@
#include "framework.h"
#include "psapi.h"
#include <filesystem>
#include <string>
#include "injector.h"
#include "injector.h"
#include "util.h"
#include <filesystem>
#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<uint64_t>(absAddr) - reinterpret_cast<uint64_t>(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<uint64_t>(dll_base))) {
return false; // 避免溢出
}
UINT64 pFunc = (UINT64)dllBase + GetFuncOffset(dllPath, funcName);
if (pFunc <= (UINT64)dllBase) {
return false;
}
uint64_t pFunc = reinterpret_cast<uint64_t>(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<uint64_t>(dll_base))) {
return false; // 避免溢出
}
UINT64 pFunc = (UINT64)dllBase + GetFuncOffset(dllPath, funcName);
if (pFunc <= (UINT64)dllBase) {
uint64_t pFunc = reinterpret_cast<uint64_t>(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);
}

View File

@ -1,9 +1,11 @@
#pragma once
#include <string>
#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);

View File

@ -1,4 +1,5 @@
#include "framework.h"
#include "sdk.h"
#include <chrono>
#include <filesystem>
#include <fstream>
@ -6,55 +7,56 @@
#include <process.h>
#include <sstream>
#include <thread>
#include "framework.h"
#include <tlhelp32.h>
#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<std::wstring> ReadDisclaimerText(const char *filePath)
static std::optional<std::string> 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<char>(file)), std::istreambuf_iterator<char>());
return util::s2w(content);
return std::string((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
}
static bool ShowDisclaimer()
static bool show_disclaimer()
{
if (std::filesystem::exists(DISCLAIMER_FILE)) {
if (std::filesystem::exists(DISCLAIMER_FLAG)) {
return true;
}
std::optional<std::wstring> 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;
}