feat:增加3.9.9.43空实现

This commit is contained in:
ttttupup 2024-04-08 16:06:59 +08:00
parent 9836771ef7
commit 493d8aa0c8
34 changed files with 962 additions and 91 deletions

View File

@ -4,7 +4,7 @@ wechat hook 。PC端微信逆向学习。
本仓库发布的内容,仅用于学习研究,请勿用于非法用途和商业用途!如因此产生任何法律纠纷,均与作者无关!
#### 项目说明:
<font color= "#dd0000">本项目是逆向习项目,可能会造成封号等后果。请自行承担风险。仅用于学习研究,请勿于非法用途。</font>
<font color= "#dd0000">本项目是逆向习项目,可能会造成封号等后果。请自行承担风险。仅用于学习研究,请勿于非法用途。</font>
#### 实现原理:
逆向分析PC端微信客户端定位相关功能关键Call编写dll调用关键Call。然后将该dll文件注入到微信进程。
@ -38,7 +38,7 @@ curl --location --request POST '127.0.0.1:19088/api/userInfo'
#### 参与项目
个人精力和水平有限,项目还有许多不足,欢迎提出 issues 或 pr。期待你的贡献。
个人精力和水平有限,项目还有许多不足,欢迎提出 issues 或 pr。
@ -46,7 +46,7 @@ curl --location --request POST '127.0.0.1:19088/api/userInfo'
个人常用的方法请参考https://github.com/ttttupup/wxhelper/wiki
使用上的问题可查询https://github.com/ttttupup/wxhelper/discussions
数据库解密请参考https://github.com/ttttupup/wxhelper/wiki
个人精力有限,只维护最新版本旧版本的bug会在新版本中修复不维护旧版本。
个人精力有限,该项目随缘更新。
#### 编译环境
@ -59,18 +59,34 @@ cmake
vcpkg
#### 编译构建
```
cd wxhelper/app/3rdparty
git clone https://github.com/microsoft/Detours.git
git clone https://github.com/gabime/spdlog.git
git clone https://github.com/nlohmann/json.git
或者使用vcpkg 安装相应库
vcpkg install detours:x64-windows
vcpkg install nlohmann-json:x64-windows
vcpkg install spdlog:x64-windows
cd wxhelper/cmake
copy detours.cmake wxhelper/app/3rdparty/Detours/CMakeLists.txt
cd wxhelper
mkdir build
cd build
cmake -DCMAKE_C_COMPILER=cl.exe \
-DCMAKE_CXX_COMPILER=cl.exe \
-DCMAKE_ASM_MASM_COMPILER=ml64.exe \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${vcpkg install dir}/scripts/buildsystems/vcpkg.cmake \
-SC:/wxhelper \
-BC:/wxhelper/build/x64-debug\
-DCMAKE_INSTALL_PREFIX=${SOURCE_DIR}/wxhelper/install/x64-debug \
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${VCPKG_INSTALL_DIR}/scripts/buildsystems/vcpkg.cmake \
-SC:${SOURCE_DIR}/wxhelper \
-BC:${SOURCE_DIR}/wxhelper/build/x64-debug\
-G Ninja
cmake --build ..
```
如果有错误按错误提示修正即可。
#### 讨论组

View File

@ -1,4 +1,4 @@
#include "chat_controller.h"
#include "chat_controller.h"
#include "json_utils.h"
#include "nlohmann/json.hpp"
@ -41,22 +41,70 @@ std::string ChatController::SendTextMsg(std::string params) {
reinterpret_cast<UINT64>(&temp), 1, 1, 0, 0);
free(reinterpret_cast<UINT64>(&chat_msg));
nlohmann::json ret_data = {{"code", success}, {"data", {}}, {"msg", "success"}};
nlohmann::json ret_data = {
{"code", success}, {"data", {}}, {"msg", "success"}};
return ret_data.dump();
}
std::string ChatController::SendImageMsg(std::string params) {
return std::string();
nlohmann::json ret = {
{"code", 200}, {"data", {}}, {"msg", "Not Implemented"}};
return ret.dump();
}
std::string ChatController::SendFileMsg(std::string params) {
return std::string();
nlohmann::json ret = {
{"code", 200}, {"data", {}}, {"msg", "Not Implemented"}};
return ret.dump();
}
std::string ChatController::SendAtText(std::string params) {
return std::string();
nlohmann::json ret = {
{"code", 200}, {"data", {}}, {"msg", "Not Implemented"}};
return ret.dump();
}
std::string ChatController::SendMultiAtText(std::string params) {
return std::string();
nlohmann::json ret = {
{"code", 200}, {"data", {}}, {"msg", "Not Implemented"}};
return ret.dump();
}
std::string ChatController::SendCustomEmotion(std::string params) {
nlohmann::json ret = {
{"code", 200}, {"data", {}}, {"msg", "Not Implemented"}};
return ret.dump();
}
std::string ChatController::SendApplet(std::string params) {
nlohmann::json ret = {
{"code", 200}, {"data", {}}, {"msg", "Not Implemented"}};
return ret.dump();
}
std::string ChatController::SendPatMsg(std::string params) {
nlohmann::json ret = {
{"code", 200}, {"data", {}}, {"msg", "Not Implemented"}};
return ret.dump();
}
std::string ChatController::ForwardMsg(std::string params) {
return std::string();
nlohmann::json ret = {
{"code", 200}, {"data", {}}, {"msg", "Not Implemented"}};
return ret.dump();
}
std::string ChatController::ForwardPublicMsgByMsgId(std::string params) {
nlohmann::json ret = {
{"code", 200}, {"data", {}}, {"msg", "Not Implemented"}};
return ret.dump();
}
std::string ChatController::ForwardPublicMsg(std::string params) {
nlohmann::json ret = {
{"code", 200}, {"data", {}}, {"msg", "Not Implemented"}};
return ret.dump();
}
} // namespace wxhelper

View File

@ -1,4 +1,4 @@
#ifndef WXHELPER_CHAT_CONTROLLER_H_
#ifndef WXHELPER_CHAT_CONTROLLER_H_
#define WXHELPER_CHAT_CONTROLLER_H_
#include "http_controller.h"
@ -10,18 +10,67 @@ class ChatController : public http::HttpController<ChatController> {
ADD_PATH("/api/sendTextMsg", SendTextMsg);
ADD_PATH("/api/sendImagesMsg", SendImageMsg);
ADD_PATH("/api/sendFileMsg", SendFileMsg);
ADD_PATH("/api/sendAtText", SendAtText);
ADD_PATH("/api/sendMultiAtText", SendMultiAtText);
ADD_PATH("/api/sendCustomEmotion", SendCustomEmotion);
ADD_PATH("/api/sendApplet", SendApplet);
ADD_PATH("/api/sendPatMsg", SendPatMsg);
ADD_PATH("/api/forwardMsg", ForwardMsg);
ADD_PATH("/api/forwardPublicMsgByMsgId", ForwardPublicMsgByMsgId);
ADD_PATH("/api/forwardPublicMsg", ForwardPublicMsg);
PATHS_END
public:
/// @brief 发送文本
/// @param params json
/// @return json
static std::string SendTextMsg(std::string params);
/// @brief 发送图片
/// @param params json
/// @return json
static std::string SendImageMsg(std::string params);
/// @brief 发送文件
/// @param params json
/// @return json
static std::string SendFileMsg(std::string params);
/// @brief 发送@文本
/// @param params json
/// @return json
static std::string SendAtText(std::string params);
/// @brief 发送多个@文本
/// @param params json
/// @return json
static std::string SendMultiAtText(std::string params);
/// @brief 发送自定义表情
/// @param params json
/// @return json
static std::string SendCustomEmotion(std::string params);
/// @brief 发送小程序
/// @param params json
/// @return json
static std::string SendApplet(std::string params);
/// @brief 拍一拍
/// @param params json
/// @return json
static std::string SendPatMsg(std::string params);
/// @brief 转发消息
/// @param params json
/// @return json
static std::string ForwardMsg(std::string params);
/// @brief 转发公众号消息
/// @param params json
/// @return json
static std::string ForwardPublicMsgByMsgId(std::string params);
/// @brief 发送公众号消息
/// @param params json
/// @return json
static std::string ForwardPublicMsg(std::string params);
};
} // namespace wxhelper

View File

@ -1,4 +1,4 @@
#include "client_socket.h"
#include "client_socket.h"
#include <WS2tcpip.h>
#include <Winsock2.h>

View File

@ -1,4 +1,4 @@
#ifndef WXHELPER_CLIENT_SOCKET_H_
#ifndef WXHELPER_CLIENT_SOCKET_H_
#define WXHELPER_CLIENT_SOCKET_H_
#include <string>

View File

@ -1,4 +1,4 @@
#include "config.h"
#include "config.h"
#include <Windows.h>
@ -20,7 +20,7 @@ void Config::init() {
spdlog::set_pattern("%Y-%m-%d %H:%M:%S [%l] [%t] - <%s>|<%#>|<%!>,%v");
http_server_port_ =
GetPrivateProfileInt("config", "HttpServerPort", 19088, "./config.ini");
hidden_dll_ = GetPrivateProfileInt("config", "HiddenDll", 1, "./config.ini");
hidden_dll_ = GetPrivateProfileInt("config", "HiddenDll", 0, "./config.ini");
TCHAR host[MAX_PATH];
GetPrivateProfileStringA("config", "HttpServerHost", "http://0.0.0.0", host,
sizeof(host), "./config.ini");

View File

@ -1,4 +1,4 @@
#ifndef WXHELPER_CONFIG_H_
#ifndef WXHELPER_CONFIG_H_
#define WXHELPER_CONFIG_H_
#include <string>

View File

@ -1,4 +1,4 @@

#include "wxhelper.h"
BOOL APIENTRY DllMain(HMODULE module, DWORD ul_reason_for_call,

View File

@ -1,4 +1,4 @@
#include <WinSock2.h>
#include <WinSock2.h>
#include "hook.h"

View File

@ -1,4 +1,4 @@
#ifndef WXHELPER_HOOK_H_
#ifndef WXHELPER_HOOK_H_
#define WXHELPER_HOOK_H_
#include <Windows.h>
#include <stdint.h>

View File

@ -1,4 +1,4 @@
#include "hook_controller.h"
#include "hook_controller.h"
#include "json_utils.h"
#include "nlohmann/json.hpp"
@ -7,10 +7,25 @@
namespace jsonutils = wxhelper::jsonutils;
namespace wxhelper {
std::string HookController::HookSyncMsg(std::string params) {
SyncMsgHook::GetInstance().Init();
int success = SyncMsgHook::GetInstance().Hook();
nlohmann::json ret_data = {
{"code", success}, {"data", {}}, {"msg", "success"}};
return ret_data.dump();
}
std::string HookController::UnHookSyncMsg(std::string params) {
int success = SyncMsgHook::GetInstance().Unhook();
nlohmann::json ret_data = {
{"code", success}, {"data", {}}, {"msg", "success"}};
return ret_data.dump();
}
std::string HookController::HookLog(std::string params) {
nlohmann::json ret = {
{"code", 200}, {"data", {}}, {"msg", "Not Implemented"}};
return ret.dump();
}
std::string HookController::UnHookLog(std::string params) {
nlohmann::json ret = {
{"code", 200}, {"data", {}}, {"msg", "Not Implemented"}};
return ret.dump();
}
} // namespace wxhelper

View File

@ -1,4 +1,4 @@
#ifndef WXHELPER_HOOK_CONTROLLER_H_
#ifndef WXHELPER_HOOK_CONTROLLER_H_
#define WXHELPER_HOOK_CONTROLLER_H_
#include "http_controller.h"
@ -8,10 +8,28 @@ class HookController : public http::HttpController<HookController> {
public:
PATHS_BEGIN
ADD_PATH("/api/hookSyncMsg", HookSyncMsg);
ADD_PATH("/api/unhookSyncMsg", UnHookSyncMsg);
ADD_PATH("/api/hookLog", HookLog);
ADD_PATH("/api/unhookLog", UnHookLog);
PATHS_END
public:
/// @brief hook消息
/// @param params json
/// @return json
static std::string HookSyncMsg(std::string params);
/// @brief 取消hook消息
/// @param params json
/// @return json
static std::string UnHookSyncMsg(std::string params);
/// @brief hook日志消息
/// @param params json
/// @return json
static std::string HookLog(std::string params);
/// @brief 取消hook日志消息
/// @param params json
/// @return json
static std::string UnHookLog(std::string params);
};
} // namespace wxhelper

View File

@ -1,4 +1,4 @@
#include "http_client.h"
#include "http_client.h"
namespace http {

View File

@ -1,4 +1,4 @@
#ifndef WXHELPER_HTTP_CLIENT_H_
#ifndef WXHELPER_HTTP_CLIENT_H_
#define WXHELPER_HTTP_CLIENT_H_
#include <string>

View File

@ -1,4 +1,4 @@

#ifndef WXHELPER_HTTP_CONTROLLER_H_
#define WXHELPER_HTTP_CONTROLLER_H_

View File

@ -1,4 +1,4 @@
#include "http_router.h"
#include "http_router.h"
#include <iostream>

View File

@ -1,4 +1,4 @@
#ifndef WXHELPER_HTTP_ROUTER_H_
#ifndef WXHELPER_HTTP_ROUTER_H_
#define WXHELPER_HTTP_ROUTER_H_
#include <functional>
#include <map>

View File

@ -1,4 +1,4 @@
#include "http_server.h"
#include "http_server.h"
#include "http_router.h"
#include "nlohmann/json.hpp"
@ -105,9 +105,12 @@ void HttpServer::HandleHttpRequest(struct mg_connection *c, void *ev_data,
ret = ret_data.dump();
} else if (mg_vcasecmp(&hm->method, "POST") == 0) {
std::string url(hm->uri.ptr, hm->uri.len);
std::string p = "{}";
if (hm->body.len > 0){
nlohmann::json params =
nlohmann::json::parse(hm->body.ptr, hm->body.ptr + hm->body.len);
std::string p = params.dump();
p = params.dump();
}
ret = HttpRouter::GetInstance().HandleHttpRequest(url, p);
}
} catch (nlohmann::json::exception &e) {
@ -121,11 +124,17 @@ void HttpServer::HandleHttpRequest(struct mg_connection *c, void *ev_data,
void HttpServer::HandleWebsocketRequest(struct mg_connection *c, void *ev_data,
void *fn_data) {
struct mg_ws_message *wm = (struct mg_ws_message *)ev_data;
std::string ret = R"({"code":200,"msg":"success"})";
try {
nlohmann::json params =
nlohmann::json::parse(wm->data.ptr, wm->data.ptr + wm->data.len);
std::string cmd = params["cmd"];
std::string p = params.dump();
std::string ret = HttpRouter::GetInstance().HandleHttpRequest(cmd, p);
ret = HttpRouter::GetInstance().HandleHttpRequest(cmd, p);
} catch (nlohmann::json::exception &e) {
nlohmann::json res = {{"code", "500"}, {"msg", e.what()}, {"data", NULL}};
ret = res.dump();
}
mg_ws_send(c, ret.c_str(), ret.size(), WEBSOCKET_OP_TEXT);
}

View File

@ -1,4 +1,4 @@
#ifndef WXHELPER_HTTP_SERVER_H_
#ifndef WXHELPER_HTTP_SERVER_H_
#define WXHELPER_HTTP_SERVER_H_
#include <atomic>
#include <functional>

View File

@ -1,4 +1,4 @@
#include "json_utils.h"
#include "json_utils.h"
#include "utils.h"
#define STR2ULL(str) (base::utils::IsDigit(str) ? stoull(str) : 0)
#define STR2LL(str) (base::utils::IsDigit(str) ? stoll(str) : 0)

View File

@ -1,4 +1,4 @@
#ifndef WXHELPER_JSON_UTILS_H_
#ifndef WXHELPER_JSON_UTILS_H_
#define WXHELPER_JSON_UTILS_H_
#include "nlohmann/json.hpp"
namespace wxhelper {

View File

@ -1,4 +1,4 @@
#ifndef WXHELPER_OFFSET_H_
#ifndef WXHELPER_OFFSET_H_
#define WXHELPER_OFFSET_H_
#include <cstdint>
namespace wechat {
@ -142,18 +142,18 @@ const uint64_t kGetAppMsgMgr = 0x951cb0;
const uint64_t kGetContactMgr = 0x93a570;
const uint64_t kGetContactList = 0xf6cb70;
const uint64_t k_sqlite3_exec = 0x26e4f20;
const uint64_t k_sqlite3_prepare = 0x26ecaa0;
const uint64_t k_sqlite3_open = 0x27242a0;
const uint64_t k_sqlite3_step = 0x26a8f30;
const uint64_t k_sqlite3_column_count = 0x26a9750;
const uint64_t k_sqlite3_column_name = 0x26aa150;
const uint64_t k_sqlite3_column_type = 0x26a9fa0;
const uint64_t k_sqlite3_column_blob = 0x26a9780;
const uint64_t k_sqlite3_column_bytes = 0x26a9870;
const uint64_t k_sqlite3_finalize = 0x26a7fe0;
const uint64_t k_sqlite3_exec = 0x288ea10;
const uint64_t k_sqlite3_prepare = 0x2896590;
const uint64_t k_sqlite3_open = 0x28cdd90;
const uint64_t k_sqlite3_step = 0x2852a20;
const uint64_t k_sqlite3_column_count = 0x2853240;
const uint64_t k_sqlite3_column_name = 0x2853c40;
const uint64_t k_sqlite3_column_type = 0x2853a90;
const uint64_t k_sqlite3_column_blob = 0x2853270;
const uint64_t k_sqlite3_column_bytes = 0x2853360;
const uint64_t k_sqlite3_finalize = 0x2851ad0;
const uint64_t kGPInstance = 0x3d8b4f8;
const uint64_t kGPInstance = 0x4076558;
const uint64_t kMicroMsgDB = 0xb8;
const uint64_t kChatMsgDB = 0x2c8;
const uint64_t kMiscDB = 0x5f0;
@ -164,9 +164,10 @@ const uint64_t kFunctionMsgDB = 0x1b98;
const uint64_t kDBName = 0x28;
const uint64_t kStorageStart = 0x0;
const uint64_t kStorageEnd = 0x0;
const uint64_t kMultiDBMgr = 0x3e00910;
const uint64_t kPublicMsgMgr = 0x3dfe098;
const uint64_t kFavoriteStorageMgr = 0x3e01478;
const uint64_t kMultiDBMgr = 0x40ecf98;
const uint64_t kPublicMsgMgr = 0x40ea558;
const uint64_t kFavoriteStorageMgr = 0x40edb28;
const uint64_t kHardLinkMgr = 0x40ecec0;
const uint64_t kChatRoomMgr = 0x8e9d30;
const uint64_t kGetChatRoomDetailInfo = 0xe73590;

View File

@ -1,4 +1,4 @@
#ifndef WXHELPER_SQLITE_FUNCTION_H_
#ifndef WXHELPER_SQLITE_FUNCTION_H_
#define WXHELPER_SQLITE_FUNCTION_H_
#include <cstdint>
#include "offset.h"
@ -79,6 +79,7 @@ typedef int(__cdecl *sqlite3_finalize)(uint64_t *pStmt);
struct SqliteFunction {
SqliteFunction(){}
SqliteFunction(uint64_t base_addr) {
sqlite3_exec =
reinterpret_cast<sqlite3::sqlite3_exec>(base_addr + offset::k_sqlite3_exec);

View File

@ -1,4 +1,4 @@
#include "sync_msg_hook.h"
#include "sync_msg_hook.h"
#include "base64.h"
#include "config.h"

View File

@ -1,4 +1,4 @@
#ifndef WXHELPER_SYNC_MSG_HOOK_H_
#ifndef WXHELPER_SYNC_MSG_HOOK_H_
#define WXHELPER_SYNC_MSG_HOOK_H_
#include "hook.h"
#include "singleton.h"

View File

@ -1,27 +1,284 @@
#include "wechat_db.h"
#include "wechat_db.h"
#include "base64.h"
#include "spdlog/spdlog.h"
#include "utils.h"
#include "wechat_interface.h"
#include "wxutils.h"
namespace wechat {
void WeChatDb::init(uint64_t base) {
base_addr_ = base;
func_ = sqlite3::SqliteFunction(base);
dbmap_ = {};
dbs_ = {};
void FreeResult(std::vector<std::vector<wechat::SqlResult>> &data) {
if (data.empty()) {
return;
}
for (auto &row : data) {
for (auto &item : row) {
if (item.column_name) {
delete[] item.column_name;
item.column_name = nullptr;
}
if (item.content) {
delete[] item.content;
item.content = nullptr;
}
}
std::vector<wechat::SqlResult>().swap(row);
}
std::vector<std::vector<wechat::SqlResult>>().swap(data);
}
int GetDbInfoCallback(void *data, int argc, char **argv, char **name) {
DatabaseInfo *pdata = (DatabaseInfo *)data;
TableInfo tb = {0};
if (argv[1]) {
tb.name = new char[strlen(argv[1]) + 1];
memcpy(tb.name, argv[1], strlen(argv[1]) + 1);
} else {
tb.name = (char *)"NULL";
}
if (argv[2]) {
tb.table_name = new char[strlen(argv[2]) + 1];
memcpy(tb.table_name, argv[2], strlen(argv[2]) + 1);
} else {
tb.table_name = (char *)"NULL";
}
if (argv[3]) {
tb.rootpage = new char[strlen(argv[3]) + 1];
memcpy(tb.rootpage, argv[3], strlen(argv[3]) + 1);
} else {
tb.rootpage = (char *)"NULL";
}
if (argv[4]) {
tb.sql = new char[strlen(argv[4]) + 1];
memcpy(tb.sql, argv[4], strlen(argv[4]) + 1);
} else {
tb.sql = (char *)"NULL";
}
tb.name_len = strlen(tb.name);
tb.table_name_len = strlen(tb.table_name);
tb.sql_len = strlen(tb.sql);
tb.rootpage_len = strlen(tb.rootpage);
pdata->tables.push_back(tb);
pdata->count = pdata->tables.size();
return 0;
}
void WeChatDb::Init() {
base_addr_ = wxhelper::wxutils::GetWeChatWinBase();
func_ = sqlite3::SqliteFunction(base_addr_);
dbmap_ = {};
dbs_ = {};
}
int WeChatDb::ExecuteSQL(uint64_t db, const char *sql,
sqlite3::sqlite3_callback callback, void *data) {
return func_.sqlite3_exec(db, sql, callback, data, 0);
}
std::vector<void *> WeChatDb::GetWeChatDbHandles() {
std::lock_guard<std::mutex> lock(m);
dbs_.clear();
dbmap_.clear();
uint64_t p_contact_addr = *(uint64_t *)(base_addr_ + offset::kGPInstance);
std::vector<uint64_t> addr_vector{
0x180, 0x278, 0x3a0, 0x4c8, 0x5a0, 0x6e0, 0x838, 0x958, 0xa40,
0xb28, 0xd00, 0xe10, 0xef8, 0xfd0, 0x10e8, 0x1200, 0x13d0, 0x15a0,
0x1678, 0x17a8, 0x18c0, 0x1998, 0x1a70, 0x1b48, 0x1c48, 0x1d60, 0x1e38};
for (uint64_t elem : addr_vector) {
uint64_t db_addr = *(uint64_t *)(p_contact_addr + elem + 0x50);
if (db_addr == 0) {
continue;
}
std::wstring name =
std::wstring((wchar_t *)(*(uint64_t *)(p_contact_addr + elem + 0x78)),
*(uint32_t *)(p_contact_addr + elem + 0x80));
auto it = dbmap_.find(name);
if (it != dbmap_.end()) {
continue;
} else {
DatabaseInfo db{0};
db.db_name = (wchar_t *)(*(uint64_t *)(p_contact_addr + elem + 0x78));
db.db_name_len = *(int32_t *)(p_contact_addr + elem + 0x80);
db.handle = db_addr;
ExecuteSQL(db_addr, "select * from sqlite_master where type=\"table\";",
GetDbInfoCallback, &db);
dbs_.push_back(db);
dbmap_[name] = db;
}
}
// MsgX.db
uint64_t multi_db_mgr_addr = base_addr_ + offset::kMultiDBMgr;
uint64_t wrap_ptr = *(uint64_t *)(multi_db_mgr_addr);
uint64_t current_db_num = *(uint64_t *)(wrap_ptr + 0x68);
uint64_t begin_ptr = *(uint64_t *)(wrap_ptr + 0x50);
for (unsigned int i = 0; i < current_db_num; ++i) {
uint64_t next_addr = begin_ptr + i * 0x8;
uint64_t db_addr = *(uint64_t *)next_addr;
if (db_addr) {
uint64_t msg0_db_addr = *(uint64_t *)(db_addr + 0x78);
DatabaseInfo msg0_db{0};
msg0_db.db_name = (wchar_t *)(*(uint64_t *)(db_addr));
msg0_db.db_name_len = *(int32_t *)(db_addr + 0x8);
msg0_db.handle = msg0_db_addr;
msg0_db.extrainfo = *(uint64_t *)(*(uint64_t *)(db_addr + 0x28) + 0x1E8);
ExecuteSQL(msg0_db_addr,
"select * from sqlite_master where type=\"table\";",
GetDbInfoCallback, &msg0_db);
dbs_.push_back(msg0_db);
std::wstring msg_db_name =
std::wstring(msg0_db.db_name, msg0_db.db_name_len);
dbmap_[msg_db_name] = msg0_db;
// BufInfoStorage
uint64_t buf_info_addr = *(uint64_t *)(db_addr + 0x20);
if (buf_info_addr) {
AddDatebaseInfo(buf_info_addr);
}
}
}
// publicMsg.db
uint64_t public_msg_mgr_addr = base_addr_ + offset::kPublicMsgMgr;
uint64_t public_msg_mgr_ptr = *(uint64_t *)(public_msg_mgr_addr);
for (unsigned int i = 1; i < 4; ++i) {
uint64_t public_msg_ptr = *(uint64_t *)(public_msg_mgr_ptr + i * 0x8);
if (public_msg_ptr) {
AddDatebaseInfo(public_msg_ptr);
}
}
// Favorite.db
uint64_t favoite = base_addr_ + offset::kFavoriteStorageMgr;
uint64_t item_ptr =
*(uint64_t *)(*(uint64_t *)(*(uint64_t *)(favoite) + 0x10) + 0x8);
if (item_ptr) {
AddDatebaseInfo(item_ptr);
}
// HardLinkMgr
uint64_t link = base_addr_ + offset::kHardLinkMgr;
uint64_t link_ptr = *(uint64_t *)(*(uint64_t *)(link) + 0x158);
for (unsigned int i = 0; i < 6; ++i) {
uint64_t hard_link_ptr = *(uint64_t *)(link_ptr + i * 0x8);
SPDLOG_INFO("hardlinkxxxdb :{}", hard_link_ptr);
if (hard_link_ptr) {
AddDatebaseInfo(hard_link_ptr);
}
}
SPDLOG_INFO("db number:{}", dbs_.size());
std::vector<void *> ret;
for (unsigned int i = 0; i < dbs_.size(); ++i) {
ret.push_back(&dbs_[i]);
}
return ret;
}
int WeChatDb::Select(uint64_t db_hanle, const std::string &sql,
std::vector<std::vector<std::string>> &query_result) {
std::vector<std::vector<wechat::SqlResult>> data;
int status = ExecSelect(db_hanle, sql, data);
if (status != SQLITE_OK) {
return 0;
}
if (data.size() == 0) {
return 1;
}
std::vector<std::string> index;
for (size_t i = 0; i < data[0].size(); i++) {
index.push_back(data[0][i].column_name);
}
query_result.push_back(index);
for (auto it : data) {
std::vector<std::string> item;
for (size_t i = 0; i < it.size(); i++) {
if (!it[i].is_blob) {
bool is_utf8 =
base::utils::IsTextUtf8(it[i].content, it[i].content_len);
if (is_utf8) {
std::string content(it[i].content);
item.push_back(content);
} else {
std::string base64_str =
base64_encode((BYTE *)it[i].content, it[i].content_len);
item.push_back(base64_str);
}
} else {
std::string b64_str =
base64_encode((BYTE *)it[i].content, it[i].content_len);
item.push_back(b64_str);
}
}
query_result.push_back(item);
}
FreeResult(data);
return 1;
}
void WeChatDb::AddDatebaseInfo(uint64_t storage) {
uint64_t storage_addr = *(uint64_t *)(storage + 0x50);
std::wstring name = std::wstring((wchar_t *)(*(uint64_t *)(storage + 0x78)),
*(int32_t *)(storage + 0x80));
auto it = dbmap_.find(name);
if (it == dbmap_.end()) {
DatabaseInfo db{0};
db.db_name = (wchar_t *)(*(uint64_t *)(storage + 0x78));
db.db_name_len = *(int32_t *)(storage + 0x80);
db.handle = storage_addr;
ExecuteSQL(storage_addr,
"select * from sqlite_master where type=\"table\";",
GetDbInfoCallback, &db);
dbs_.push_back(db);
dbmap_[name] = db;
}
}
int WeChatDb::ExecSelect(uint64_t db, const std::string &sql,
std::vector<std::vector<wechat::SqlResult>> &data) {
uint64_t *stmt;
int rc = func_.sqlite3_prepare(db, sql.c_str(), -1, &stmt, 0);
if (rc != SQLITE_OK) {
return rc;
}
while (func_.sqlite3_step(stmt) == SQLITE_ROW) {
int col_count = func_.sqlite3_column_count(stmt);
std::vector<wechat::SqlResult> res;
for (unsigned int i = 0; i < col_count; ++i) {
wechat::SqlResult temp = {0};
const char *col_name = func_.sqlite3_column_name(stmt, i);
int ntype = func_.sqlite3_column_type(stmt, i);
const void *p_blob_data = func_.sqlite3_column_blob(stmt, i);
int nlength = func_.sqlite3_column_bytes(stmt, i);
temp.column_name = new char[strlen(col_name) + 1];
memcpy(temp.column_name, col_name, strlen(col_name) + 1);
temp.column_name_len = strlen(col_name);
temp.content_len = nlength;
switch (ntype) {
case SQLITE_BLOB: {
temp.content = new char[nlength];
memcpy(temp.content, p_blob_data, nlength);
temp.is_blob = true;
break;
}
default: {
if (nlength != 0) {
temp.content = new char[nlength + 1];
memcpy(temp.content, p_blob_data, nlength + 1);
} else {
temp.content = new char[2];
ZeroMemory(temp.content, 2);
}
temp.is_blob = false;
break;
}
}
res.push_back(temp);
}
data.push_back(res);
}
func_.sqlite3_finalize(stmt);
return SQLITE_OK;
}
} // namespace wechat

View File

@ -1,7 +1,8 @@
#ifndef WXHELPER_WECHAT_DB_H_
#ifndef WXHELPER_WECHAT_DB_H_
#define WXHELPER_WECHAT_DB_H_
#include <map>
#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>
#include "singleton.h"
@ -12,16 +13,24 @@ namespace wechat {
class WeChatDb : public base::Singleton<WeChatDb> {
public:
void init(uint64_t base);
void Init();
std::vector<void *> GetWeChatDbHandles();
int Select(uint64_t db_hanle, const std::string &sql,
std::vector<std::vector<std::string>> &query_result);
private:
void AddDatebaseInfo(uint64_t storage);
int ExecSelect(uint64_t db, const std::string &sql,
std::vector<std::vector<wechat::SqlResult>> &data);
int ExecuteSQL(uint64_t db, const char *sql,
sqlite3::sqlite3_callback callback, void *data);
private:
std::map<std::wstring,DatabaseInfo> dbmap_;
std::unordered_map<std::wstring, DatabaseInfo> dbmap_;
std::vector<DatabaseInfo> dbs_;
sqlite3::SqliteFunction func_;
uint64_t base_addr_;
mutable std::mutex m;
};
} // namespace wechat

View File

@ -1,4 +1,4 @@
#ifndef WXHELPER_WECHAT_INNER_H_
#ifndef WXHELPER_WECHAT_INNER_H_
#define WXHELPER_WECHAT_INNER_H_
#include <string>
#include <vector>

View File

@ -1,23 +1,22 @@
#include <winsock2.h>
#include <winsock2.h>
#include "wxhelper.h"
#include "config.h"
#include "http_server.h"
#include "thread_pool.h"
#include "utils.h"
#include "wxutils.h"
#include "chat_controller.h"
#include "wechat_db.h"
#include "sync_msg_hook.h"
namespace wxhelper {
void WxHelper::init(HMODULE module) {
Config::GetInstance().init();
if (Config::GetInstance().GetHideDll()) {
// base::utils::HideModule(module);
base::utils::HideModule(module);
}
// ChatController chatController;
// http::HttpRouter::GetInstance().init();
wechat::WeChatDb::GetInstance().Init();
SyncMsgHook::GetInstance().Init();
http::HttpServer::GetInstance().init(
Config::GetInstance().GetHttpServerHost(),
Config::GetInstance().GetHttpServerPort());

View File

@ -1,4 +1,4 @@

#ifndef WXHELPER_WXHELPER_H_
#define WXHELPER_WXHELPER_H_
#include <Windows.h>

View File

@ -1,4 +1,4 @@
#include "wxutils.h"
#include "wxutils.h"
#include "utils.h"
#define BUFSIZE 1024

View File

@ -1,4 +1,4 @@
#ifndef WXHELPER_WXUTILS_H_
#ifndef WXHELPER_WXUTILS_H_
#define WXHELPER_WXUTILS_H_
#include <windows.h>

108
cmake/detours.cmake Normal file
View File

@ -0,0 +1,108 @@
cmake_minimum_required(VERSION 3.10...3.27)
#
project(detours VERSION 4.0.1 LANGUAGES C CXX)
MACRO(GET_WIN32_WINNT version)
IF(WIN32 AND CMAKE_SYSTEM_VERSION)
SET(ver ${CMAKE_SYSTEM_VERSION})
STRING(REGEX MATCH "^([0-9]+).([0-9])" ver ${ver})
STRING(REGEX MATCH "^([0-9]+)" verMajor ${ver})
# Check for Windows 10, b/c we'll need to convert to hex 'A'.
IF("${verMajor}" MATCHES "10")
SET(verMajor "A")
STRING(REGEX REPLACE "^([0-9]+)" ${verMajor} ver ${ver})
ENDIF("${verMajor}" MATCHES "10")
# Remove all remaining '.' characters.
STRING(REPLACE "." "" ver ${ver})
# Prepend each digit with a zero.
STRING(REGEX REPLACE "([0-9A-Z])" "0\\1" ver ${ver})
SET(${version} "0x${ver}")
ENDIF()
ENDMACRO()
# DEBUG
set(DETOURS_CONFIG ${CMAKE_BUILD_TYPE})
if("${DETOURS_CONFIG}" STREQUAL "Debug")
set(DETOURS_DEBUG 1)
else()
set(DETOURS_DEBUG 0)
endif()
####################################################
#
set(CMAKE_CXX_FLAGS "/nologo /W4 /WX /we4777 /we4800 /Zi /MT /Gy /Gm- /Zl /Od /DDETOUR_DEBUG=${DETOURS_DEBUG}")
if(WIN32)
IF(MSVC_VERSION GREATER_EQUAL 1700)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D DETOURS_CL_17_OR_NEWER")
ENDIF()
GET_WIN32_WINNT(ver)
message(STATUS "Windows OS Version: ${ver}")
if(ver EQUAL 0x0700)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D _USING_V110_SDK71_ /D DETOURS_WIN_7")
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D _WIN32_WINNT=${ver}")
else()
message(FATAL_ERROR "Only Win32 platforms are supported.")
endif()
if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "i386")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D _X86_ ")
elseif(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "i686")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D _AMD64_ ")
elseif(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "IA64")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D _IA64_ ")
elseif(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "x86")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D _X86_ ")
elseif(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "x86_64")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D _AMD64_ ")
elseif(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "AMD64")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D _AMD64_ ")
else()
message("Unknown architecture (x86, amd64, ia64, arm, arm64)")
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D DETOURS_VERSION=0x4c0c1 /D WIN32_LEAN_AND_MEAN")
if(MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D _CRT_SECURE_NO_WARNINGS /EHsc")
else()
# TODO: Shall we support gcc with MinGW, Cygwin or Clang based building system on Windows?
endif()
if(ENABLE_VERBOSELOG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D ENABLE_VERBOSELOG")
endif()
#
set(SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/detours.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/modules.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/disasm.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/image.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/creatwth.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/disolx86.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/disolx64.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/disolia64.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/disolarm.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/disolarm64.cpp
)
#
add_library(detours ${SOURCES})
target_include_directories(detours INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/src)

341
doc/3.9.9.43.md Normal file
View File

@ -0,0 +1,341 @@
#### 编译构建
环境:
cl.exe目录= c:/cl.exe
ml64.exe目录 =c:/ml64.exe
vcpkg目录 = c:/vcpkg
wxhelper目录 = c:/wxhelper
```
cd wxhelper/app/3rdparty
git clone https://github.com/microsoft/Detours.git
git clone https://github.com/gabime/spdlog.git
git clone https://github.com/nlohmann/json.git
或者使用vcpkg 安装相应库
vcpkg install detours:x64-windows
vcpkg install nlohmann-json:x64-windows
vcpkg install spdlog:x64-windows
cd wxhelper/cmake
copy detours.cmake wxhelper/app/3rdparty/Detours/CMakeLists.txt
cd wxhelper
mkdir build
cd build
cmake -DCMAKE_C_COMPILER=cl.exe \
-DCMAKE_CXX_COMPILER=cl.exe \
-DCMAKE_ASM_MASM_COMPILER=ml64.exe \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_INSTALL_PREFIX=C:/wxhelper/install/x64-debug \
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=C:/vcpkg/scripts/buildsystems/vcpkg.cmake \
-SC:c:/wxhelper \
-BC:c:/wxhelper/build/x64-debug\
-G Ninja
cmake --build ..
```
如果有错误按错误提示修正即可。
## 3.9.9.43版本http接口文档文档仅供参考。
### 简单说明:
所有接口只支持post方法。
全部使用json格式。
格式: http://host:port/api/xxxx
host: 绑定的host
port: 监听的端口
xxxx: 对应的功能路径
返回结构的json格式
``` javascript
{
"code": 1,
"data": {},
"msg": "success"
}
```
code 错误码
msg 成功/错误信息
data 接口返回的数据
### 配置文件
wechat目录下config.ini 配置文件的默认配置
// HiddenDll 0.不隐藏注入dll 1.隐藏dll
// HttpServerPort dll自身提供的http服务的端口
// HttpServerHost dll自身提供的http服务的监听地址
// RecvMessageMode开启消息hook时使用接收消息的方式. tcp | http
// tcp模式下通过tcp连接发送消息,http模式下通过http发送消息
// RecvTcpIp 接收消息绑定的ip
// RecvTcpPorttcp模式下绑定的端口
// RecvHttpUrlhttp模式下推送的接口地址
// RecvHttpTimeout http模式下的超时时间
HiddenDll=0,
HttpServerPort=80,
HttpServerHost=http://0.0.0.0,
RecvMessageMode=tcp,
RecvTcpIp=127.0.0.1,
RecvTcpPort=19099,
RecvHttpUrl=127.0.0.1,
RecvHttpTimeout=3000,
#### 1.hook消息**
###### 接口功能
> hook接收文本消息图片消息群消息.该接口将hook的消息通过tcp回传给本地的端口。
enableHttp=1时使用urltimeout参数配置服务端的接收地址。请求为postContent-Type 为json。
enableHttp=0时使用ipport的tcp服务回传消息。
###### 接口地址
> [/api/hookSyncMsg](/api/hookSyncMsg)
###### HTTP请求方式
> POST JSON
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
###### 返回字段
|返回字段|字段类型|说明 |
|---|---|---|
|code|int|返回状态,0成功, 非0失败|
|data|object|null|
|msg|string|成功提示|
###### 接口示例
入参:
``` javascript
```
响应:
``` javascript
{"code":0,"msg":"success","data":null}
```
#### 2.取消hook消息**
###### 接口功能
> 取消hook消息
###### 接口地址
> [/api/unhookSyncMsg](/api/unhookSyncMsg)
###### HTTP请求方式
> POST JSON
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
###### 返回字段
|返回字段|字段类型|说明 |
|---|---|---|
|code|int|返回状态,0成功, 非0失败|
|data|object|null|
|msg|string|成功提示|
###### 接口示例
入参:
``` javascript
```
响应:
``` javascript
{"code":0,"msg":"success","data":null}
```
#### 3.获取数据库信息**
###### 接口功能
> 获取数据库信息和句柄
###### 接口地址
> [/api/getDBInfo](/api/getDBInfo)
###### HTTP请求方式
> POST JSON
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
###### 返回字段
|返回字段|字段类型|说明 |
|---|---|---|
|code|int|返回状态,0成功, 非0失败|
|msg|string|返回信息|
|data|array|好友信息|
|&#8194;&#8194;databaseName|string|数据库名称|
|&#8194;&#8194;handle|number|句柄|
|&#8194;&#8194;tables|array|表信息|
|&#8194;&#8194;&#8194;&#8194;name|string|表名|
|&#8194;&#8194;&#8194;&#8194;rootpage|string|rootpage|
|&#8194;&#8194;&#8194;&#8194;sql|string|ddl语句|
|&#8194;&#8194;&#8194;&#8194;tableName|string|表名|
###### 接口示例
入参:
``` javascript
```
响应:
``` javascript
{
"code": 1,
"data": [
{
"databaseName": "MicroMsg.db",
"handle": 1755003930784,
"tables": [
{
"name": "Contact",
"rootpage": "2",
"sql": "CREATE TABLE Contact(UserName TEXT PRIMARY KEY ,Alias TEXT,EncryptUserName TEXT,DelFlag INTEGER DEFAULT 0,Type INTEGER DEFAULT 0,VerifyFlag INTEGER DEFAULT 0,Reserved1 INTEGER DEFAULT 0,Reserved2 INTEGER DEFAULT 0,Reserved3 TEXT,Reserved4 TEXT,Remark TEXT,NickName TEXT,LabelIDList TEXT,DomainList TEXT,ChatRoomType int,PYInitial TEXT,QuanPin TEXT,RemarkPYInitial TEXT,RemarkQuanPin TEXT,BigHeadImgUrl TEXT,SmallHeadImgUrl TEXT,HeadImgMd5 TEXT,ChatRoomNotify INTEGER DEFAULT 0,Reserved5 INTEGER DEFAULT 0,Reserved6 TEXT,Reserved7 TEXT,ExtraBuf BLOB,Reserved8 INTEGER DEFAULT 0,Reserved9 INTEGER DEFAULT 0,Reserved10 TEXT,Reserved11 TEXT)",
"tableName": "Contact"
}
]
}
],
"msg":"success"
}
```
#### 4.查询数据库**
###### 接口功能
> 查询数据库
###### 接口地址
> [/api/execSql](/api/execSql)
###### HTTP请求方式
> POST JSON
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
|dbHandle |true |number| |
|sql |true |string| 执行的sql |
###### 返回字段
|返回字段|字段类型|说明 |
|---|---|---|
|code|int|返回状态,0成功, 非0失败|
|msg|string|返回信息|
|data|array|sqlite返回的结果|
###### 接口示例
入参:
``` javascript
{
"dbHandle":2006119800400,
"sql":"select * from MSG where localId =301;"
}
```
响应:
``` javascript
{
"code": 1,
"data": [
[
"localId",
"TalkerId",
"MsgSvrID",
"Type",
"SubType",
"IsSender",
"CreateTime",
"Sequence",
"StatusEx",
"FlagEx",
"Status",
"MsgServerSeq",
"MsgSequence",
"StrTalker",
"StrContent",
"DisplayContent",
"Reserved0",
"Reserved1",
"Reserved2",
"Reserved3",
"Reserved4",
"Reserved5",
"Reserved6",
"CompressContent",
"BytesExtra",
"BytesTrans"
],
[
"301",
"1",
"8824834301214701891",
"1",
"0",
"0",
"1685401473",
"1685401473000",
"0",
"0",
"2",
"1",
"795781866",
"wxid_123",
"testtest",
"",
"0",
"2",
"",
"",
"",
"",
"",
"",
"CgQIEBAAGo0BCAcSiAE8bXNnc291cmNlPJPHNpZ25hdHVyZT52MV9wd12bTZyRzwvc2lnbmF0dXJPgoJPHRtcF9ub2RlPgoJCTxwsaXNoZXItaWQ+Jmx0OyFbQ0RBVEFbXV0mZ3Q7PC9wdWJsaXNoZXItaWQ+Cgk8L3RtcF9ub2RlPgo8L21zZ3NvdXJjZT4KGiQIAhIgNDE1MDA0NjRhZTRmMjk2NjhjMzY2ZjFkOTdmMjAwNDg=",
""
]
],
"msg": "success"
}
```
#### 5.发送文本消息**
###### 接口功能
> 发送文本消息
###### 接口地址
> [/api/sendTextMsg](/api/sendTextMsg)
###### HTTP请求方式
> POST JSON
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
|wxid |true |string| 接收人wxid |
|msg|true |string|消息文本内容|
###### 返回字段
|返回字段|字段类型|说明 |
|---|---|---|
|code|int|返回状态,不为0成功, 0失败|
|msg|string|成功提示|
|data|object|null|
###### 接口示例
入参:
``` javascript
{
"wxid": "filehelper",
"msg": "1112222"
}
```
响应:
``` javascript
{"code":345686720,"msg":"success","data":null}
```