WeChatFerry/WeChatFerry/com/util.cpp

270 lines
7.5 KiB
C++
Raw Normal View History

2025-02-04 15:35:09 +08:00
#include "util.h"
2022-10-15 20:25:42 +08:00
#include <codecvt>
#include <locale>
2025-02-04 17:27:35 +08:00
#include <optional>
2022-10-15 20:25:42 +08:00
#include <strsafe.h>
#include <wchar.h>
2025-02-04 15:35:09 +08:00
#include "framework.h"
2025-02-04 17:27:35 +08:00
#include <Shlwapi.h>
#include <tlhelp32.h>
2025-02-04 15:35:09 +08:00
2025-01-27 12:11:41 +08:00
#include "log.hpp"
2022-10-15 20:25:42 +08:00
#pragma comment(lib, "shlwapi")
#pragma comment(lib, "Version.lib")
2025-02-04 15:35:09 +08:00
namespace util
{
2022-10-15 20:25:42 +08:00
2025-02-04 21:00:29 +08:00
constexpr char WECHATEXE[] = "WeChat.exe";
constexpr char WECHATWINDLL[] = "WeChatWin.dll";
2025-02-04 20:40:46 +08:00
2025-02-04 15:35:09 +08:00
std::wstring s2w(const std::string &s)
2022-10-15 20:25:42 +08:00
{
2025-02-04 15:35:09 +08:00
if (s.empty()) return std::wstring();
int size_needed = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), static_cast<int>(s.size()), nullptr, 0);
std::wstring ws(size_needed, 0);
MultiByteToWideChar(CP_UTF8, 0, s.c_str(), static_cast<int>(s.size()), &ws[0], size_needed);
2022-10-15 20:25:42 +08:00
return ws;
}
2022-10-16 22:39:16 +08:00
2025-02-04 15:35:09 +08:00
std::string w2s(const std::wstring &ws)
2022-10-15 20:25:42 +08:00
{
2025-02-04 15:35:09 +08:00
if (ws.empty()) return std::string();
int size_needed
= WideCharToMultiByte(CP_UTF8, 0, ws.c_str(), static_cast<int>(ws.size()), nullptr, 0, nullptr, nullptr);
std::string s(size_needed, 0);
WideCharToMultiByte(CP_UTF8, 0, ws.c_str(), static_cast<int>(ws.size()), &s[0], size_needed, nullptr, nullptr);
2022-10-15 20:25:42 +08:00
return s;
}
2025-02-04 15:35:09 +08:00
std::string gb2312_to_utf8(const char *gb2312)
2023-11-22 22:35:00 +08:00
{
2025-02-04 15:35:09 +08:00
if (!gb2312) return "";
2023-11-22 22:35:00 +08:00
2025-02-04 15:35:09 +08:00
int size_needed = MultiByteToWideChar(CP_ACP, 0, gb2312, -1, nullptr, 0);
std::wstring ws(size_needed, 0);
2023-11-22 22:35:00 +08:00
MultiByteToWideChar(CP_ACP, 0, gb2312, -1, &ws[0], size_needed);
2025-02-04 15:35:09 +08:00
size_needed = WideCharToMultiByte(CP_UTF8, 0, ws.c_str(), -1, nullptr, 0, nullptr, nullptr);
std::string s(size_needed, 0);
WideCharToMultiByte(CP_UTF8, 0, ws.c_str(), -1, &s[0], size_needed, nullptr, nullptr);
2023-11-22 22:35:00 +08:00
return s;
}
2025-02-04 17:34:48 +08:00
static DWORD get_wechat_pid()
2022-10-15 20:25:42 +08:00
{
2025-02-04 15:35:09 +08:00
DWORD pid = 0;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE) return 0;
2022-10-15 20:25:42 +08:00
PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) };
while (Process32Next(hSnapshot, &pe32)) {
2025-02-04 21:00:29 +08:00
if (pe32.szExeFile == s2w(WECHATEXE)) {
2022-10-15 20:25:42 +08:00
pid = pe32.th32ProcessID;
break;
}
}
CloseHandle(hSnapshot);
return pid;
}
2025-02-04 17:34:48 +08:00
static std::optional<std::string> get_wechat_path()
2022-10-15 20:25:42 +08:00
{
2025-02-04 17:27:35 +08:00
HKEY hKey;
if (RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\Tencent\\WeChat", 0, KEY_READ, &hKey) != ERROR_SUCCESS) {
LOG_ERROR("无法打开注册表项");
return std::nullopt;
}
2025-02-04 15:35:09 +08:00
char path[MAX_PATH] = { 0 };
2025-02-04 17:27:35 +08:00
DWORD type = REG_SZ;
DWORD size = sizeof(path);
if (RegQueryValueExA(hKey, "InstallPath", nullptr, &type, reinterpret_cast<LPBYTE>(path), &size) != ERROR_SUCCESS) {
RegCloseKey(hKey);
LOG_ERROR("无法读取注册表中的 InstallPath");
2025-02-04 15:35:09 +08:00
return std::nullopt;
2022-10-15 20:25:42 +08:00
}
2025-02-04 17:27:35 +08:00
RegCloseKey(hKey);
2022-10-15 20:25:42 +08:00
2025-02-04 17:27:35 +08:00
PathAppendA(path, WECHATEXE);
return std::string(path);
}
2022-10-15 20:25:42 +08:00
2025-02-04 17:34:48 +08:00
static std::optional<std::string> get_wechat_win_dll_path()
2025-02-04 17:27:35 +08:00
{
auto wechat_path = get_wechat_path();
if (!wechat_path) {
return std::nullopt;
}
2022-10-15 20:25:42 +08:00
2025-02-04 17:27:35 +08:00
std::string dll_path = *wechat_path;
PathRemoveFileSpecA(dll_path.data());
PathAppendA(dll_path.data(), WECHATWINDLL);
if (PathFileExistsA(dll_path.c_str())) {
return dll_path;
2025-02-04 15:35:09 +08:00
}
2025-02-04 17:27:35 +08:00
// 微信从大约3.7开始,增加了一层版本目录: [3.7.0.29]
PathRemoveFileSpecA(dll_path.data());
WIN32_FIND_DATAA find_data;
HANDLE hFind = FindFirstFileA((dll_path + "\\*.*").c_str(), &find_data);
if (hFind == INVALID_HANDLE_VALUE) {
return std::nullopt;
}
FindClose(hFind);
std::string versioned_path = dll_path + "\\" + find_data.cFileName + WECHATWINDLL;
return PathFileExistsA(versioned_path.c_str()) ? std::optional<std::string>(versioned_path) : std::nullopt;
2022-10-15 20:25:42 +08:00
}
2025-02-04 17:34:48 +08:00
static std::optional<std::string> get_file_version(const std::string &file_path)
2023-06-08 16:23:21 +08:00
{
2025-02-04 17:27:35 +08:00
if (!PathFileExistsA(file_path.c_str())) {
2025-02-04 15:35:09 +08:00
return std::nullopt;
}
2025-02-04 17:27:35 +08:00
DWORD dummy = 0;
DWORD size = GetFileVersionInfoSizeA(file_path.c_str(), &dummy);
2025-02-04 15:35:09 +08:00
if (size == 0) {
return std::nullopt;
}
2025-02-04 17:27:35 +08:00
std::vector<BYTE> buffer(size);
if (!GetFileVersionInfoA(file_path.c_str(), 0, size, buffer.data())) {
2025-02-04 15:35:09 +08:00
return std::nullopt;
}
2025-02-04 17:27:35 +08:00
VS_FIXEDFILEINFO *ver_info = nullptr;
UINT ver_size = 0;
if (!VerQueryValueA(buffer.data(), "\\", reinterpret_cast<LPVOID *>(&ver_info), &ver_size)) {
2025-02-04 15:35:09 +08:00
return std::nullopt;
}
2025-02-04 17:27:35 +08:00
return fmt::format("{}.{}.{}.{}", HIWORD(ver_info->dwFileVersionMS), LOWORD(ver_info->dwFileVersionMS),
HIWORD(ver_info->dwFileVersionLS), LOWORD(ver_info->dwFileVersionLS));
2023-06-08 16:23:21 +08:00
}
2025-02-04 15:35:09 +08:00
std::string get_wechat_version()
2023-06-08 16:23:21 +08:00
{
2025-02-04 17:27:35 +08:00
auto dll_path = get_wechat_win_dll_path();
if (!dll_path) {
LOG_ERROR("无法获取 WeChatWin.dll 路径");
return "";
}
2025-02-04 15:35:09 +08:00
2025-02-04 17:27:35 +08:00
auto version = get_file_version(*dll_path);
if (!version) {
LOG_ERROR("无法获取 WeChat 版本信息");
return "";
2025-02-04 15:35:09 +08:00
}
2025-02-04 17:27:35 +08:00
return *version;
2023-06-08 16:23:21 +08:00
}
2025-02-04 17:34:48 +08:00
int open_wechat(DWORD &pid)
{
pid = get_wechat_pid();
if (pid != 0) {
return ERROR_SUCCESS;
}
auto wechat_path = util::get_wechat_path();
if (!wechat_path) {
LOG_ERROR("获取 WeChat 安装路径失败");
return ERROR_FILE_NOT_FOUND;
}
STARTUPINFOA si = { sizeof(si) };
PROCESS_INFORMATION pi = {};
std::string command_line = *wechat_path;
if (!CreateProcessA(nullptr, command_line.data(), nullptr, nullptr, FALSE, CREATE_NEW_CONSOLE, nullptr, nullptr,
&si, &pi)) {
return GetLastError();
}
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
pid = pi.dwProcessId;
return ERROR_SUCCESS;
}
2025-02-04 15:35:09 +08:00
uint32_t get_memory_int_by_address(HANDLE hProcess, uint64_t addr)
2022-10-15 20:25:42 +08:00
{
2025-02-04 15:35:09 +08:00
uint32_t value = 0;
if (!addr || !hProcess) return value;
2022-10-15 20:25:42 +08:00
2025-02-04 17:27:35 +08:00
ReadProcessMemory(hProcess, reinterpret_cast<LPCVOID>(addr), &value, sizeof(value), nullptr);
2022-10-15 20:25:42 +08:00
return value;
}
2025-02-04 15:35:09 +08:00
std::wstring get_unicode_info_by_address(HANDLE hProcess, uint64_t address)
2022-10-15 20:25:42 +08:00
{
2025-02-04 15:35:09 +08:00
if (!hProcess || !address) return L"";
2022-10-15 20:25:42 +08:00
2025-02-04 15:35:09 +08:00
uint64_t str_address = get_memory_int_by_address(hProcess, address);
uint64_t str_len = get_memory_int_by_address(hProcess, address + 0x4);
if (str_len > 500) return L"";
2022-10-15 20:25:42 +08:00
wchar_t cValue[500] = { 0 };
2025-02-04 15:35:09 +08:00
if (ReadProcessMemory(hProcess, reinterpret_cast<LPCVOID>(str_address), cValue, (str_len + 1) * sizeof(wchar_t),
nullptr)) {
return std::wstring(cValue);
2022-10-15 20:25:42 +08:00
}
2025-02-04 15:35:09 +08:00
return L"";
2022-10-15 20:25:42 +08:00
}
2023-05-25 00:18:10 +08:00
2025-02-04 15:35:09 +08:00
void dbg_msg(const char *format, ...)
2023-05-25 00:18:10 +08:00
{
2025-02-04 15:35:09 +08:00
if (!format) return;
va_list args;
va_start(args, format);
va_list args_copy;
va_copy(args_copy, args);
int len = vsnprintf(nullptr, 0, format, args_copy);
va_end(args_copy);
std::vector<char> buffer(len + 1);
vsnprintf(buffer.data(), buffer.size(), format, args);
va_end(args);
OutputDebugStringA(buffer.data());
2023-05-25 00:18:10 +08:00
}
2025-02-04 15:35:09 +08:00
std::unique_ptr<WxString> new_wx_string(const char *str)
{
return new_wx_string(str ? std::string(str) : std::string());
}
2025-02-04 15:35:09 +08:00
std::unique_ptr<WxString> new_wx_string(const std::string &str) { return std::make_unique<WxString>(s2w(str)); }
std::unique_ptr<WxString> new_wx_string(const wchar_t *wstr)
{
2025-02-04 15:35:09 +08:00
return new_wx_string(wstr ? std::wstring(wstr) : std::wstring());
}
std::unique_ptr<WxString> new_wx_string(const std::wstring &wstr) { return std::make_unique<WxString>(wstr); }
2025-02-04 15:35:09 +08:00
std::vector<WxString> parse_wxids(const std::string &wxids)
{
std::vector<WxString> wx_members;
std::wstringstream wss(s2w(wxids));
std::wstring wstr;
while (getline(wss, wstr, L',')) {
wx_members.emplace_back(wstr);
}
return wx_members;
}
2025-02-04 15:35:09 +08:00
} // namespace util