This commit is contained in:
hugy 2023-03-31 21:21:35 +08:00
parent 384aade1a8
commit bfe5b0ee12
82 changed files with 11652 additions and 3978 deletions

View File

@ -18,6 +18,9 @@ include_directories(${VCPKG_INSTALLED_DIR}/x86-windows/include)
find_package(nlohmann_json CONFIG REQUIRED)
find_package(unofficial-mongoose CONFIG REQUIRED)
# find_package(spdlog CONFIG REQUIRED)
# find_package(minhook CONFIG REQUIRED)
add_library(wxhelper SHARED ${CPP_FILES} )
@ -26,6 +29,8 @@ add_library(wxhelper SHARED ${CPP_FILES} )
target_link_libraries(wxhelper PRIVATE nlohmann_json::nlohmann_json)
target_link_libraries(wxhelper PRIVATE unofficial::mongoose::mongoose)
# target_link_libraries(wxhelper PRIVATE spdlog::spdlog spdlog::spdlog_header_only)
# target_link_libraries(wxhelper PRIVATE minhook::minhook)
SET_TARGET_PROPERTIES(wxhelper PROPERTIES LINKER_LANGUAGE C
ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib

View File

@ -13,30 +13,30 @@
13.hook语音
14.取消hook语音
<!-- 17.删除好友 -->
<!-- 19.通过手机或qq查找微信 -->
19.通过手机或qq查找微信
<!-- 20.通过wxid添加好友 -->
25.获取群成员
<!-- 26.获取群成员昵称
26.获取群成员昵称
27.删除群成员
28.增加群成员
31.修改群昵称 -->
31.修改群昵称
32.获取数据库句柄
34.查询数据库
<!-- 35.hook日志
36.关闭hook日志 -->
35.hook日志
36.关闭hook日志
40.转发消息
44.退出登录
<!-- 45.确认收款 -->
46.联系人列表
<!-- 47.获取群详情 -->
47.获取群详情
48.获取解密图片
<!-- 49.图片提取文字ocr -->
50.拍一拍
<!-- 51.群消息置顶消息
52.群消息取消置顶 -->
51.群消息置顶消息
52.群消息取消置顶
53.朋友圈首页
54.朋友圈下一页
<!-- 55.获取联系人或者群名称 -->
55.获取联系人或者群名称
56.获取消息附件(图片,视频,文件)
57.获取消息语音文件
### 接口文档:

View File

@ -1,22 +1,22 @@
#include "pch.h"
#include "self_info.h"
#include "pch.h"
#include "account_mgr.h"
#include "easylogging++.h"
#include "common.h"
#include "wechat_data.h"
#include "wechat_function.h"
using namespace std;
namespace wxhelper {
AccountMgr::AccountMgr(DWORD base):BaseMgr(base){
}
AccountMgr::~AccountMgr(){
#define WX_LOGOUT_OFFSET 0xe58870
#define WX_ACCOUNT_SERVICE_OFFSET 0x768c80
#define WX_GET_APP_DATA_SAVE_PATH_OFFSET 0xf3a610
#define WX_GET_CURRENT_DATA_PATH_OFFSET 0xc872c0
int GetSelfInfo(SelfInfoInner &out) {
DWORD base = GetWeChatWinBase();
DWORD accout_service_addr = base + WX_ACCOUNT_SERVICE_OFFSET;
DWORD get_app_save_addr = base + WX_GET_APP_DATA_SAVE_PATH_OFFSET;
DWORD get_current_data_path_addr = base + WX_GET_CURRENT_DATA_PATH_OFFSET;
}
int AccountMgr::GetSelfInfo(SelfInfoInner &out) {
DWORD accout_service_addr = base_addr_ + WX_ACCOUNT_SERVICE_OFFSET;
DWORD get_app_save_addr = base_addr_ + WX_GET_APP_DATA_SAVE_PATH_OFFSET;
DWORD get_current_data_path_addr = base_addr_ + WX_GET_CURRENT_DATA_PATH_OFFSET;
DWORD service_addr = NULL;
__asm {
PUSHAD
@ -143,12 +143,12 @@ int GetSelfInfo(SelfInfoInner &out) {
}
if (*(DWORD *)(service_addr + 0x4CC) == 0 ||
*(DWORD *)(service_addr +0x4D0) == 0) {
*(DWORD *)(service_addr + 0x4D0) == 0) {
out.db_key = string();
} else {
DWORD byte_addr = *(DWORD *)(service_addr + 0x4CC);
DWORD len = *(DWORD *)(service_addr +0x4D0);
out.db_key = Bytes2Hex((BYTE *)byte_addr,len);
DWORD len = *(DWORD *)(service_addr + 0x4D0);
out.db_key = Utils::Bytes2Hex((BYTE *)byte_addr, len);
}
}
@ -165,15 +165,15 @@ int GetSelfInfo(SelfInfoInner &out) {
}
if (data_save_path.ptr) {
out.data_save_path =
Wstring2String(wstring(data_save_path.ptr, data_save_path.length));
out.data_save_path = Utils::WstringToUTF8(
wstring(data_save_path.ptr, data_save_path.length));
}
else {
out.data_save_path = string();
}
if (current_data_path.ptr) {
out.current_data_path = Wstring2String(
out.current_data_path = Utils::WstringToUTF8(
wstring(current_data_path.ptr, current_data_path.length));
} else {
out.current_data_path = string();
@ -181,9 +181,9 @@ int GetSelfInfo(SelfInfoInner &out) {
return 1;
}
int CheckLogin() {
DWORD base = GetWeChatWinBase();
DWORD accout_service_addr = base + WX_ACCOUNT_SERVICE_OFFSET;
int AccountMgr::CheckLogin() {
int success = -1;
DWORD accout_service_addr = base_addr_ + WX_ACCOUNT_SERVICE_OFFSET;
DWORD service_addr = NULL;
__asm {
PUSHAD
@ -192,21 +192,18 @@ int CheckLogin() {
POPAD
}
if (service_addr) {
return *(DWORD *)(service_addr + 0x4C8);
}
else {
return 0;
success = *(DWORD *)(service_addr + 0x4C8);
}
return success;
}
int Logout() {
int success = 0;
int AccountMgr::Logout() {
int success = -1;
if (!CheckLogin()) {
return success;
}
DWORD base = GetWeChatWinBase();
DWORD account_service_addr = base + WX_ACCOUNT_SERVICE_OFFSET;
DWORD logout_addr = base + WX_LOGOUT_OFFSET;
DWORD account_service_addr = base_addr_ + WX_ACCOUNT_SERVICE_OFFSET;
DWORD logout_addr = base_addr_ + WX_LOGOUT_OFFSET;
__asm {
PUSHAD
CALL account_service_addr
@ -218,3 +215,5 @@ int Logout() {
}
return success;
}
} // namespace wxhelper

19
src/account_mgr.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef WXHELPER_ACCOUNT_MGR_H_
#define WXHELPER_ACCOUNT_MGR_H_
#include "wechat_function.h"
#include"base_mgr.h"
namespace wxhelper{
class AccountMgr: public BaseMgr
{
public:
explicit AccountMgr(DWORD base);
~AccountMgr();
int GetSelfInfo(SelfInfoInner& out);
int CheckLogin();
int Logout();
};
}
#endif

View File

@ -1,782 +0,0 @@
#include "pch.h"
#include "api.h"
#include <mongoose.h>
#include <nlohmann/json.hpp>
#include "send_text.h"
#include "common.h"
#include "send_image.h"
#include "send_file.h"
#include "hook_recv_msg.h"
#include "get_db_handle.h"
#include "wechat_data.h"
#include "forward.h"
#include "db_operation.h"
#include "contact.h"
#include "chat_room.h"
#include "self_info.h"
#include "hook_img.h"
#include "ocr.h"
#include "pat.h"
#include "confirm_receipt.h"
#include "sns.h"
#include "search_contact.h"
#include "download.h"
#include "hook_log.h"
#include "hook_voice.h"
#pragma comment(lib, "ws2_32.lib")
using namespace std;
using namespace nlohmann;
// #define STR2INT(str) (is_digit(str) ? stoi(str) : 0)
#define WS2LW(wstr) (LPWSTR) wstr.c_str()
static bool kHttpRuning = false;
static HANDLE kHttpThread = NULL;
bool is_digit(string str) {
if (str.length() == 0) {
return false;
}
for (auto it : str) {
if (it < '0' || it > '9') {
return false;
}
}
return true;
}
string get_var(mg_http_message *hm, string name) {
string ret;
char *buffer = new char[hm->query.len + 1];
ZeroMemory(buffer, hm->query.len + 1);
int len = mg_http_get_var(&hm->query, name.c_str(), buffer, hm->query.len);
if (len > 0) ret = string(buffer, len);
delete[] buffer;
buffer = NULL;
return ret;
}
/// @brief 获取request中的请求参数int类型
/// @param hm 消息
/// @param data json数据
/// @param key key
/// @param method 是否是post暂时全部用post
/// @return int
static int get_http_req_param_int(mg_http_message *hm, json data, string key, int method){
int result;
switch (method) {
case 0: {
result = STR2INT(get_var(hm,key).c_str());
break;
}
case 1: {
try {
result = data[key].get<int>();
} catch (json::exception) {
result = STR2INT(data[key].get<string>());
}
break;
}
default:
break;
}
return result;
}
/// @brief 获取request中的请求参数
/// @param hm 消息
/// @param data json数据
/// @param key key
/// @param method 是否是post暂时全部用post
/// @return
static wstring get_http_req_param(mg_http_message *hm, json data, string key, int method){
wstring result;
switch (method) {
case 0: {
result = utf8_to_unicode(get_var(hm,key).c_str());
break;
}
case 1: {
result = utf8_to_unicode(data[key].get<string>().c_str());
break;
}
default:
break;
}
return result;
}
static unsigned long long get_http_param_ulong64(mg_http_message *hm,
json j_data, string key,
int method) {
unsigned long long result = 0;
switch (method) {
case 0: {
string value = get_var(hm, key);
istringstream is(value);
is >> result;
break;
}
case 1: {
try {
result = j_data[key].get<ULONG64>();
} catch (json::exception) {
string value = j_data[key].get<string>();
istringstream is(value);
is >> result;
}
break;
}
default:
break;
}
return result;
}
static int get_http_param_int(mg_http_message *hm, json j_data, string key,
int method) {
int result = 0;
switch (method) {
case 0: {
result = STR2INT(get_var(hm, key));
break;
}
case 1: {
try {
result = j_data[key].get<int>();
} catch (json::exception) {
result = STR2INT(j_data[key].get<string>());
}
break;
}
default:
break;
}
return result;
}
static vector<wstring> get_http_param_array(mg_http_message *hm, json j_data,
string key, int method) {
vector<wstring> result;
switch (method) {
case 0: {
result = split(utf8_to_unicode(get_var(hm, key).c_str()), L',');
break;
}
case 1: {
result = split(utf8_to_unicode(j_data[key].get<string>().c_str()), L',');
break;
}
default:
break;
}
return result;
}
/// @brief api接口入口解析
/// @param hm mg_http_message
/// @param c connection
/// @param ret json数据
void api_handle(mg_http_message *hm, struct mg_connection *c, string &ret) {
int is_post = 0;
if (mg_vcasecmp(&hm->method, "POST") == 0) {
is_post = 1;
}
#ifdef _DEBUG
printf("method:%s body: %s", hm->method.ptr,hm->body.ptr);
#endif
if (is_post == 0){
json ret_data = {{"result", "ERROR"}, {"msg", "not support method"}};
ret = ret_data.dump();
return;
}
json j_param =
json::parse(hm->body.ptr, hm->body.ptr + hm->body.len, nullptr, false);
if (hm->body.len != 0 && j_param.is_discarded() == true) {
json ret_data = {{"result", "ERROR"}, {"msg", "json string is invalid."}};
ret = ret_data.dump();
return;
}
int api_number = STR2INT(get_var(hm, "type"));
switch (api_number) {
case WECHAT_IS_LOGIN: {
int success = CheckLogin();
json ret_data = {{"result", "OK"}, {"code", success}};
ret = ret_data.dump();
break;
}
case WECHAT_GET_SELF_INFO: {
SelfInfoInner self_info;
int success = GetSelfInfo(self_info);
json ret_data = {{"result", "OK"}, {"code", success}};
if (success) {
json j_info = {
{"name", self_info.name},
{"city", self_info.city},
{"province", self_info.province},
{"country", self_info.country},
{"account", self_info.account},
{"wxid", self_info.wxid},
{"mobile", self_info.mobile},
{"headImage", self_info.head_img},
{"signature",self_info.signature},
{"dataSavePath",self_info.data_save_path},
{"currentDataPath",self_info.current_data_path},
{"dbKey",self_info.db_key},
};
ret_data["data"] = j_info;
}
ret = ret_data.dump();
break;
}
case WECHAT_MSG_SEND_TEXT: {
wstring wxid = get_http_req_param(hm, j_param, "wxid", is_post);
wstring msg = get_http_req_param(hm, j_param, "msg", is_post);
int success = SendText(WS2LW(wxid), WS2LW(msg));
json ret_data = {{"result", "OK"}, {"code", success}};
ret = ret_data.dump();
break;
}
case WECHAT_MSG_SEND_AT: {
break;
wstring chat_room_id = get_http_req_param(hm, j_param, "chatRoomId", is_post);
vector<wstring> wxids = get_http_param_array(hm, j_param, "wxids", is_post);
wstring msg = get_http_req_param(hm, j_param, "msg", is_post);
vector<wchar_t *> wxid_list;
for (unsigned int i = 0; i < wxids.size(); i++){
wxid_list.push_back(WS2LW(wxids[i]));
}
int success = SendAtText(WS2LW(chat_room_id), wxid_list.data(), wxid_list.size(),WS2LW(msg));
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_MSG_SEND_CARD: {
break;
}
case WECHAT_MSG_SEND_IMAGE: {
wstring receiver = get_http_req_param(hm, j_param, "wxid", is_post);
wstring img_path = get_http_req_param(hm, j_param, "imagePath", is_post);
int success = SendImage(WS2LW(receiver), WS2LW(img_path));
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_MSG_SEND_FILE: {
wstring receiver = get_http_req_param(hm, j_param, "wxid", is_post);
wstring file_path = get_http_req_param(hm, j_param, "filePath", is_post);
int success = SendFile(WS2LW(receiver), WS2LW(file_path));
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_MSG_SEND_ARTICLE: {
break;
}
case WECHAT_MSG_SEND_APP: {
break;
}
case WECHAT_MSG_START_HOOK: {
int port = get_http_req_param_int(hm, j_param, "port", is_post);
wstring ip = get_http_req_param(hm, j_param, "ip", is_post);
string client_ip = Wstring2String(ip);
char ip_cstr[16];
strcpy_s(ip_cstr,client_ip.c_str());
int success = HookRecvMsg(ip_cstr,port);
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_MSG_STOP_HOOK: {
int success = UnHookRecvMsg();
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_MSG_START_IMAGE_HOOK: {
break;
wstring img_dir = get_http_req_param(hm, j_param, "imgDir", is_post);
int success = HookImg(img_dir);
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_MSG_STOP_IMAGE_HOOK: {
break;
int success = UnHookImg();
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_MSG_START_VOICE_HOOK: {
wstring voice_dir = get_http_req_param(hm, j_param, "voiceDir", is_post);
int success = HookVoice(voice_dir);
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_MSG_STOP_VOICE_HOOK: {
int success = UnHookVoice();
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_CONTACT_GET_LIST: {
break;
}
case WECHAT_CONTACT_CHECK_STATUS: {
break;
}
case WECHAT_CONTACT_DEL: {
break;
wstring user_id = get_http_req_param(hm, j_param, "wxid", is_post);
int success = DelContact(WS2LW(user_id));
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_CONTACT_SEARCH_BY_CACHE: {
break;
}
case WECHAT_CONTACT_SEARCH_BY_NET: {
break;
wstring keyword = get_http_req_param(hm, j_param, "keyword", is_post);
UserInfo *user = nullptr;
int success = SearchContactNetScene(WS2LW(keyword), &user);
json ret_data = {{"code", success}, {"result", "OK"}};
if (user) {
json info = {
{"bigImage", unicode_to_utf8(user->big_image)},
{"smallImage", unicode_to_utf8(user->small_image)},
{"city", unicode_to_utf8(user->city)},
{"nation", unicode_to_utf8(user->nation)},
{"nickname", unicode_to_utf8(user->nickname)},
{"province", unicode_to_utf8(user->province)},
{"sex", user->sex},
{"signature", unicode_to_utf8(user->signature)},
{"v2", unicode_to_utf8(user->v2)},
{"v3", unicode_to_utf8(user->v3)},
};
ret_data["userInfo"] = info;
}
ret = ret_data.dump();
break;
}
case WECHAT_CONTACT_ADD_BY_WXID: {
break;
wstring user_id = get_http_req_param(hm, j_param, "wxid", is_post);
int success = AddFriendByWxid(WS2LW(user_id));
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_CONTACT_ADD_BY_V3: {
break;
}
case WECHAT_CONTACT_ADD_BY_PUBLIC_ID: {
break;
}
case WECHAT_CONTACT_VERIFY_APPLY: {
break;
}
case WECHAT_CONTACT_EDIT_REMARK: {
break;
}
case WECHAT_CHATROOM_GET_MEMBER_LIST: {
wstring room_id = get_http_req_param(hm, j_param, "chatRoomId", is_post);
ChatRoomInner out{0};
int success = GetMemberFromChatRoom(WS2LW(room_id),out);
json ret_data = {{"code", success}, {"result", "OK"}};
if (success){
json member_info ={
{"admin",unicode_to_utf8(out.admin)},
{"chatRoomId",unicode_to_utf8(out.chat_room)},
{"members",out.members},
};
ret_data["data"] = member_info;
}
ret = ret_data.dump();
break;
}
case WECHAT_CHATROOM_GET_MEMBER_NICKNAME: {
break;
wstring room_id = get_http_req_param(hm, j_param, "chatRoomId", is_post);
wstring member_id = get_http_req_param(hm, j_param, "memberId", is_post);
wstring nickname = GetChatRoomMemberNickname(WS2LW(room_id),WS2LW(member_id));
json ret_data = {{"code", 1}, {"result", "OK"},{"nickname",unicode_to_utf8(WS2LW(nickname))}};
ret = ret_data.dump();
break;
}
case WECHAT_CHATROOM_DEL_MEMBER: {
break;
wstring room_id = get_http_req_param(hm, j_param, "chatRoomId", is_post);
vector<wstring> wxids = get_http_param_array(hm, j_param, "memberIds", is_post);
vector<wchar_t *> wxid_list;
for (unsigned int i = 0; i < wxids.size(); i++){
wxid_list.push_back(WS2LW(wxids[i]));
}
int success = DelMemberFromChatRoom(WS2LW(room_id), wxid_list.data(),wxid_list.size());
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_CHATROOM_ADD_MEMBER: {
break;
wstring room_id = get_http_req_param(hm, j_param, "chatRoomId", is_post);
vector<wstring> wxids = get_http_param_array(hm, j_param, "memberIds", is_post);
vector<wchar_t *> wxid_list;
for (unsigned int i = 0; i < wxids.size(); i++){
wxid_list.push_back(WS2LW(wxids[i]));
}
int success = AddMemberToChatRoom(WS2LW(room_id), wxid_list.data(),wxid_list.size());
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_CHATROOM_SET_ANNOUNCEMENT: {
break;
}
case WECHAT_CHATROOM_SET_CHATROOM_NAME: {
break;
}
case WECHAT_CHATROOM_SET_SELF_NICKNAME: {
break;
wstring room_id = get_http_req_param(hm, j_param, "chatRoomId", is_post);
wstring wxid = get_http_req_param(hm, j_param, "wxid", is_post);
wstring nick = get_http_req_param(hm, j_param, "nickName", is_post);
int success = ModChatRoomMemberNickName(WS2LW(room_id),WS2LW(wxid),WS2LW(nick));
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_DATABASE_GET_HANDLES: {
vector<void *> v_ptr = GetDbHandles();
json ret_data = {{"data", json::array()}, {"result", "OK"}};
for (unsigned int i = 0; i < v_ptr.size(); i++) {
json db_info;
db_info["tables"] = json::array();
DatabaseInfo *db = reinterpret_cast<DatabaseInfo *>(v_ptr[i]);
db_info["handle"] = db->handle;
db_info["databaseName"] = unicode_to_utf8(db->db_name);
for (auto table : db->tables) {
json table_info = {{"name", table.name},
{"tableName", table.table_name},
{"sql", table.sql},
{"rootpage", table.rootpage}};
db_info["tables"].push_back(table_info);
}
ret_data["data"].push_back(db_info);
}
ret = ret_data.dump();
break;
}
case WECHAT_DATABASE_BACKUP: {
break;
}
case WECHAT_DATABASE_QUERY: {
DWORD db_handle = get_http_param_int(hm, j_param, "dbHandle", is_post);
wstring sql = get_http_req_param(hm, j_param, "sql", is_post);
string sql_str = unicode_to_utf8(WS2LW(sql));
vector<vector<string>> items;
int success = Select(db_handle, sql_str.c_str(),items);
json ret_data = {{"data", json::array()}, {"code",success},{"result", "OK"}};
if(success == 0){
ret = ret_data.dump();
break;
}
for (auto it : items) {
json temp_arr = json::array();
for (size_t i = 0; i < it.size(); i++) {
temp_arr.push_back(it[i]);
}
ret_data["data"].push_back(temp_arr);
}
ret = ret_data.dump();
break;
}
case WECHAT_SET_VERSION: {
break;
}
case WECHAT_LOG_START_HOOK: {
break;
int success = HookLog();
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_LOG_STOP_HOOK: {
break;
int success = UnHookLog();
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_BROWSER_OPEN_WITH_URL: {
break;
}
case WECHAT_GET_PUBLIC_MSG: {
break;
}
case WECHAT_MSG_FORWARD_MESSAGE: {
wstring wxid = get_http_req_param(hm, j_param, "wxid", is_post);
ULONG64 msgid = get_http_param_ulong64(hm, j_param, "msgid", is_post);
int success = ForwardMsg(WS2LW(wxid), msgid);
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_GET_QRCODE_IMAGE: {
break;
}
case WECHAT_GET_A8KEY: {
break;
}
case WECHAT_MSG_SEND_XML: {
break;
}
case WECHAT_LOGOUT: {
int success = Logout();
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_GET_TRANSFER: {
break;
wstring wxid = get_http_req_param(hm, j_param, "wxid", is_post);
wstring transcationid = get_http_req_param(hm, j_param, "transcationId", is_post);
wstring transferid = get_http_req_param(hm, j_param, "transferId", is_post);
BOOL response = DoConfirmReceipt(WS2LW(wxid), WS2LW(transcationid), WS2LW(transferid));
json ret_data = {{"msg", response}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_GET_CONTACT_ALL: {
vector<Contact> vec;
int success = GetAllContact(vec);
json ret_data = {
{"data", json::array()}, {"code", success}, {"result", "OK"}};
for (unsigned int i = 0; i < vec.size(); i++) {
#ifdef _DEBUG
cout << "vector :" <<i << endl;
cout<< "custom :" << vec[i].custom_account.ptr << endl;
cout<< "userName :" << vec[i].encrypt_name.ptr << endl;
cout<< "wxid :" << vec[i].wxid.ptr << endl;
#endif
json item = {
{"customAccount",
vec[i].custom_account.length > 0
? vec[i].custom_account.ptr != nullptr
? unicode_to_utf8(vec[i].custom_account.ptr)
: string()
: string()},
{"delFlag", vec[i].del_flag},
{"userName", vec[i].encrypt_name.length > 0
? vec[i].encrypt_name.ptr != nullptr
? unicode_to_utf8(vec[i].encrypt_name.ptr)
: string()
: string()},
{"type", vec[i].type},
{"verifyFlag", vec[i].verify_flag},
{"verifyFlag", vec[i].verify_flag},
{"wxid", vec[i].wxid.length > 0 ? unicode_to_utf8(vec[i].wxid.ptr)
: string()},
};
ret_data["data"].push_back(item);
}
ret = ret_data.dump();
break;
}
case WECHAT_GET_CHATROOM_INFO: {
break;
wstring room_id = get_http_req_param(hm, j_param, "chatRoomId", is_post);
ChatRoomInfoInner chat_room_detail{0};
int success = GetChatRoomDetailInfo(WS2LW(room_id), chat_room_detail);
json ret_data = {{"code", success}, {"result", "OK"}};
if(!success){
break;
}
json detail = {
{"chatRoomId",
chat_room_detail.chat_room_id.length > 0
? unicode_to_utf8(chat_room_detail.chat_room_id.ptr)
: string()},
{"notice", chat_room_detail.notice.length > 0
? unicode_to_utf8(chat_room_detail.notice.ptr)
: string()},
{"admin", chat_room_detail.admin.length > 0
? unicode_to_utf8(chat_room_detail.admin.ptr)
: string()},
{"xml", chat_room_detail.xml.length > 0
? unicode_to_utf8(chat_room_detail.xml.ptr)
: string()},
};
ret_data["data"]=detail;
ret = ret_data.dump();
break;
}
case WECHAT_GET_IMG_BY_NAME: {
wstring image_path = get_http_req_param(hm, j_param, "imagePath", is_post);
wstring save_path = get_http_req_param(hm, j_param, "savePath", is_post);
int success = GetImgByName(WS2LW(image_path),WS2LW(save_path));
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_DO_OCR:{
break;
wstring image_path = get_http_req_param(hm, j_param, "imagePath", is_post);
string text("");
int success = DoOCRTask(WS2LW(image_path),text);
json ret_data = {{"code", success}, {"result", "OK"},{"text",text}};
ret = ret_data.dump();
break;
}
case WECHAT_SEND_PAT_MSG:{
wstring room_id = get_http_req_param(hm, j_param, "chatRoomId", is_post);
wstring wxid = get_http_req_param(hm, j_param, "wxid", is_post);
int success = SendPatMsg(WS2LW(room_id),WS2LW(wxid));
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_SET_TOP_MSG:{
break;
wstring wxid = get_http_req_param(hm, j_param, "wxid", is_post);
ULONG64 msgid = get_http_param_ulong64(hm, j_param, "msgid", is_post);
int success = SetTopMsg(WS2LW(wxid),msgid);
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_REMOVE_TOP_MSG:{
break;
wstring room_id = get_http_req_param(hm, j_param, "chatRoomId", is_post);
ULONG64 msgid = get_http_param_ulong64(hm, j_param, "msgid", is_post);
int success = RemoveTopMsg(WS2LW(room_id),msgid);
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_SNS_GET_FIRST_PAGE:{
int success = GetFirstPage();
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_SNS_GET_NEXT_PAGE: {
ULONG64 snsid = get_http_param_ulong64(hm, j_param, "snsId", is_post);
int success = GetNextPage(snsid);
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_CONTACT_NAME:{
break;
wstring pri_id = get_http_req_param(hm, j_param, "id", is_post);
wstring name =GetContactOrChatRoomNickname(WS2LW(pri_id));
json ret_data = {{"code", 1}, {"result", "OK"},{"name",unicode_to_utf8(WS2LW(name))}};
ret = ret_data.dump();
break;
}
case WECHAT_ATTACH_DOWNLOAD:{
ULONG64 msg_id = get_http_param_ulong64(hm, j_param, "msgId", is_post);
int success = DoDownloadTask(msg_id);
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_GET_VOICE:{
ULONG64 msg_id = get_http_param_ulong64(hm, j_param, "msgId", is_post);
wstring voice_dir = get_http_req_param(hm, j_param, "voiceDir", is_post);
int success = GetVoice(msg_id,WS2LW(voice_dir));
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
default:
break;
}
}
/// @brief 事件回调函数
/// @param c 链接
/// @param ev 事件
/// @param ev_data 事件数据
/// @param fn_data 回调数据
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
struct mg_http_serve_opts opts = {0};
if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *)ev_data;
string ret = R"({"result":"OK"})";
if (mg_http_match_uri(hm, "/api/")) {
try {
api_handle(hm, c, ret);
} catch (json::exception &e) {
json res = {{"result", "ERROR"}, {"msg", e.what()}};
ret = res.dump();
}
if (ret != "") {
mg_http_reply(c, 200, "", ret.c_str(), 0, 0);
}
} else {
mg_http_reply(c, 500, NULL, "%s", "Invalid URI");
}
}
(void)fn_data;
}
/// @brief http server
/// @param port 端口
void http_server(int port) {
string lsten_addr = "http://0.0.0.0:" + to_string(port);
struct mg_mgr mgr;
// Init manager
mg_mgr_init(&mgr);
// Setup listener
mg_http_listen(&mgr, lsten_addr.c_str(), fn, &mgr);
// Event loop
for (;;) mg_mgr_poll(&mgr, 1000);
// Cleanup
mg_mgr_free(&mgr);
}
/// @brief 启动http服务
/// @param port 端口
/// @return 成功返回0
int http_start(int port) {
if (kHttpRuning) {
return 1;
}
#ifdef _DEBUG
CreateConsole();
#endif
kHttpRuning = true;
kHttpThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)http_server,
(LPVOID)port, NULL, 0);
return 0;
}
int http_close() {
if (!kHttpRuning) {
return 1;
}
kHttpRuning = false;
if (kHttpThread) {
WaitForSingleObject(kHttpThread, -1);
CloseHandle(kHttpThread);
kHttpThread = NULL;
}
UnHookRecvMsg();
UnHookImg();
UnHookSearchContact();
UnHookLog();
return 0;
}

View File

@ -1,81 +0,0 @@
#ifndef API_H_
#define API_H_
typedef enum WECHAT_HTTP_APISTag
{
// login check
WECHAT_IS_LOGIN = 0,
// self info
WECHAT_GET_SELF_INFO,
// send message
WECHAT_MSG_SEND_TEXT,
WECHAT_MSG_SEND_AT,
WECHAT_MSG_SEND_CARD,
WECHAT_MSG_SEND_IMAGE,
WECHAT_MSG_SEND_FILE,
WECHAT_MSG_SEND_ARTICLE,
WECHAT_MSG_SEND_APP,
// receive message
WECHAT_MSG_START_HOOK,
WECHAT_MSG_STOP_HOOK,
WECHAT_MSG_START_IMAGE_HOOK,
WECHAT_MSG_STOP_IMAGE_HOOK,
WECHAT_MSG_START_VOICE_HOOK,
WECHAT_MSG_STOP_VOICE_HOOK,
// contact
WECHAT_CONTACT_GET_LIST,
WECHAT_CONTACT_CHECK_STATUS,
WECHAT_CONTACT_DEL,
WECHAT_CONTACT_SEARCH_BY_CACHE,
WECHAT_CONTACT_SEARCH_BY_NET,
WECHAT_CONTACT_ADD_BY_WXID,
WECHAT_CONTACT_ADD_BY_V3,
WECHAT_CONTACT_ADD_BY_PUBLIC_ID,
WECHAT_CONTACT_VERIFY_APPLY,
WECHAT_CONTACT_EDIT_REMARK,
// chatroom
WECHAT_CHATROOM_GET_MEMBER_LIST,
WECHAT_CHATROOM_GET_MEMBER_NICKNAME,
WECHAT_CHATROOM_DEL_MEMBER,
WECHAT_CHATROOM_ADD_MEMBER,
WECHAT_CHATROOM_SET_ANNOUNCEMENT,
WECHAT_CHATROOM_SET_CHATROOM_NAME,
WECHAT_CHATROOM_SET_SELF_NICKNAME,
// database
WECHAT_DATABASE_GET_HANDLES,
WECHAT_DATABASE_BACKUP,
WECHAT_DATABASE_QUERY,
// version
WECHAT_SET_VERSION,
// log
WECHAT_LOG_START_HOOK,
WECHAT_LOG_STOP_HOOK,
// browser
WECHAT_BROWSER_OPEN_WITH_URL,
WECHAT_GET_PUBLIC_MSG,
WECHAT_MSG_FORWARD_MESSAGE,
WECHAT_GET_QRCODE_IMAGE,
WECHAT_GET_A8KEY,
WECHAT_MSG_SEND_XML,
WECHAT_LOGOUT,
WECHAT_GET_TRANSFER,
WECHAT_GET_CONTACT_ALL,
WECHAT_GET_CHATROOM_INFO,
WECHAT_GET_IMG_BY_NAME,
WECHAT_DO_OCR,
WECHAT_SEND_PAT_MSG,
WECHAT_SET_TOP_MSG,
WECHAT_REMOVE_TOP_MSG,
WECHAT_SNS_GET_FIRST_PAGE,
WECHAT_SNS_GET_NEXT_PAGE,
WECHAT_CONTACT_NAME,
WECHAT_ATTACH_DOWNLOAD,
WECHAT_GET_VOICE,
} WECHAT_HTTP_APIS,
*PWECHAT_HTTP_APIS;
extern "C" __declspec(dllexport) int http_start(int port);
extern "C" __declspec(dllexport) int http_close();
#endif

78
src/api_route.h Normal file
View File

@ -0,0 +1,78 @@
#ifndef WXHELPER_API_ROUTINES_H_
#define WXHELPER_API_ROUTINES_H_
namespace wxhelper {
typedef enum HTTP_API_ROUTE {
// login check
WECHAT_IS_LOGIN = 0,
// self info
WECHAT_GET_SELF_INFO,
// send message
WECHAT_MSG_SEND_TEXT,
WECHAT_MSG_SEND_AT,
WECHAT_MSG_SEND_CARD,
WECHAT_MSG_SEND_IMAGE,
WECHAT_MSG_SEND_FILE,
WECHAT_MSG_SEND_ARTICLE,
WECHAT_MSG_SEND_APP,
// receive message
WECHAT_MSG_START_HOOK,
WECHAT_MSG_STOP_HOOK,
WECHAT_MSG_START_IMAGE_HOOK,
WECHAT_MSG_STOP_IMAGE_HOOK,
WECHAT_MSG_START_VOICE_HOOK,
WECHAT_MSG_STOP_VOICE_HOOK,
// contact
WECHAT_CONTACT_GET_LIST,
WECHAT_CONTACT_CHECK_STATUS,
WECHAT_CONTACT_DEL,
WECHAT_CONTACT_SEARCH_BY_CACHE,
WECHAT_CONTACT_SEARCH_BY_NET,
WECHAT_CONTACT_ADD_BY_WXID,
WECHAT_CONTACT_ADD_BY_V3,
WECHAT_CONTACT_ADD_BY_PUBLIC_ID,
WECHAT_CONTACT_VERIFY_APPLY,
WECHAT_CONTACT_EDIT_REMARK,
// chatroom
WECHAT_CHATROOM_GET_MEMBER_LIST,
WECHAT_CHATROOM_GET_MEMBER_NICKNAME,
WECHAT_CHATROOM_DEL_MEMBER,
WECHAT_CHATROOM_ADD_MEMBER,
WECHAT_CHATROOM_SET_ANNOUNCEMENT,
WECHAT_CHATROOM_SET_CHATROOM_NAME,
WECHAT_CHATROOM_SET_SELF_NICKNAME,
// database
WECHAT_DATABASE_GET_HANDLES,
WECHAT_DATABASE_BACKUP,
WECHAT_DATABASE_QUERY,
// version
WECHAT_SET_VERSION,
// log
WECHAT_LOG_START_HOOK,
WECHAT_LOG_STOP_HOOK,
// browser
WECHAT_BROWSER_OPEN_WITH_URL,
WECHAT_GET_PUBLIC_MSG,
WECHAT_MSG_FORWARD_MESSAGE,
WECHAT_GET_QRCODE_IMAGE,
WECHAT_GET_A8KEY,
WECHAT_MSG_SEND_XML,
WECHAT_LOGOUT,
WECHAT_GET_TRANSFER,
WECHAT_GET_CONTACT_ALL,
WECHAT_GET_CHATROOM_INFO,
WECHAT_GET_IMG_BY_NAME,
WECHAT_DO_OCR,
WECHAT_SEND_PAT_MSG,
WECHAT_SET_TOP_MSG,
WECHAT_REMOVE_TOP_MSG,
WECHAT_SNS_GET_FIRST_PAGE,
WECHAT_SNS_GET_NEXT_PAGE,
WECHAT_CONTACT_NAME,
WECHAT_ATTACH_DOWNLOAD,
WECHAT_GET_VOICE,
} WECHAT_HTTP_APIS,
*PWECHAT_HTTP_APIS;
}
#endif

13
src/base_mgr.cc Normal file
View File

@ -0,0 +1,13 @@
#include "base_mgr.h"
namespace wxhelper{
BaseMgr::BaseMgr(DWORD base):base_addr_(base)
{
}
BaseMgr::~BaseMgr()
{
}
}

13
src/base_mgr.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef WXHELPER_BASE_MGR_H_
#define WXHELPER_BASE_MGR_H_
#include <Windows.h>
namespace wxhelper{
class BaseMgr{
public:
explicit BaseMgr(DWORD base);
~BaseMgr();
protected:
DWORD base_addr_;
};
}
#endif

View File

@ -1,16 +0,0 @@
#ifndef CHAT_ROOM_H_
#define CHAT_ROOM_H_
#include "wechat_data.h"
int GetChatRoomDetailInfo(wchar_t* chat_room_id, ChatRoomInfoInner& room_info);
int DelMemberFromChatRoom(wchar_t* chat_room_id,wchar_t** wxids,int len);
int AddMemberToChatRoom(wchar_t* chat_room_id, wchar_t** wxids,int len);
int GetMemberFromChatRoom(wchar_t* chat_room_id,ChatRoomInner & out);
int ModChatRoomMemberNickName(wchar_t* chat_room_id,wchar_t* wxid,wchar_t * nick);
int SetTopMsg(wchar_t* wxid,ULONG64 msg_id);
int RemoveTopMsg(wchar_t* chat_room_id,ULONG64 msg_id);
std::wstring GetChatRoomMemberNickname(wchar_t* chat_room_id,wchar_t* wxid);
#endif

View File

@ -1,41 +1,25 @@
#include "pch.h"
#include "chat_room.h"
#include "pch.h"
#include "chat_room_mgr.h"
#include "db.h"
#include "common.h"
#include "get_db_handle.h"
#include "wechat_data.h"
#include "base64.h"
using namespace std;
#define WX_CHAT_ROOM_MGR_OFFSET 0x78cf20
#define WX_GET_CHAT_ROOM_DETAIL_INFO_OFFSET 0xb6f260
#define WX_NEW_CHAT_ROOM_INFO_OFFSET 0xe15de0
#define WX_FREE_CHAT_ROOM_INFO_OFFSET 0xe160b0
#define WX_DEL_CHAT_ROOM_MEMBER_OFFSET 0xb64180
#define WX_INIT_CHAT_MSG_OFFSET 0xed3be0
#define WX_ADD_MEMBER_TO_CHAT_ROOM_OFFSET 0xb63c50
#define WX_GET_MEMBER_FROM_CHAT_ROOM_OFFSET 0xbdf260
#define WX_INIT_CHAT_ROOM_OFFSET 0xe97890
#define WX_FREE_CHAT_ROOM_OFFSET 0xe97ab0
#define WX_MOD_CHAT_ROOM_MEMBER_NICK_NAME_OFFSET 0xb6adf0
#define WX_NEW_CHAT_MSG_OFFSET 0x70e2a0
#define WX_FREE_CHAT_MSG_OFFSET 0x6f4ea0
#define WX_TOP_MSG_OFFSET 0xb727e0
#define WX_REMOVE_TOP_MSG_OFFSET 0xb725a0
#define WX_FREE_CHAT_MSG_INSTANCE_COUNTER_OFFSET 0x6f5370
#define WX_GET_MEMBER_NICKNAME_OFFSET 0xb703f0
#define WX_CONTACT_MGR_INSTANCE_OFFSET 0x6f8990
#define WX_GET_CONTACT_OFFSET 0xb93b20
#define WX_FREE_CONTACT_OFFSET 0xe23690
namespace wxhelper {
int GetChatRoomDetailInfo(wchar_t* chat_room_id, ChatRoomInfoInner& room_info) {
int success = 0;
ChatRoomMgr::ChatRoomMgr(DWORD base) : BaseMgr(base) {}
ChatRoomMgr::~ChatRoomMgr() {}
int ChatRoomMgr::GetChatRoomDetailInfo(wchar_t* chat_room_id,
ChatRoomInfoInner& room_info) {
int success = -1;
WeChatString chat_room(chat_room_id);
DWORD base = GetWeChatWinBase();
DWORD get_chat_room_mgr_addr = base + WX_CHAT_ROOM_MGR_OFFSET;
DWORD get_chat_room_detail_addr = base + WX_GET_CHAT_ROOM_DETAIL_INFO_OFFSET;
DWORD create_chat_room_info_addr = base + WX_NEW_CHAT_ROOM_INFO_OFFSET;
DWORD free_chat_room_info_addr = base + WX_FREE_CHAT_ROOM_INFO_OFFSET;
DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
DWORD get_chat_room_detail_addr =
base_addr_ + WX_GET_CHAT_ROOM_DETAIL_INFO_OFFSET;
DWORD create_chat_room_info_addr = base_addr_ + WX_NEW_CHAT_ROOM_INFO_OFFSET;
DWORD free_chat_room_info_addr = base_addr_ + WX_FREE_CHAT_ROOM_INFO_OFFSET;
char chat_room_info[0xDC] = {0};
__asm {
PUSHAD
@ -54,21 +38,20 @@ int GetChatRoomDetailInfo(wchar_t* chat_room_id, ChatRoomInfoInner& room_info) {
}
DWORD room_id_len = *(DWORD*)(chat_room_info + 0x8);
DWORD room_id_max_len = *(DWORD*)(chat_room_info + 0xC);
wchar_t * room_id = new wchar_t[room_id_len + 1];
wmemcpy(room_id,*(wchar_t**)(chat_room_info + 0x4),room_id_len + 1);
wchar_t* room_id = new wchar_t[room_id_len + 1];
wmemcpy(room_id, *(wchar_t**)(chat_room_info + 0x4), room_id_len + 1);
room_info.chat_room_id.ptr = room_id;
room_info.chat_room_id.length = room_id_len;
room_info.chat_room_id.max_length = room_id_max_len;
DWORD notice_len = *(DWORD*)(chat_room_info + 0x1C);
DWORD notice_max_len = *(DWORD*)(chat_room_info + 0x20);
wchar_t* notice_ptr = *(wchar_t**)(chat_room_info + 0x18);
if(notice_len <= 0){
if (notice_len <= 0) {
room_info.notice.ptr = nullptr;
}else{
wchar_t * notice = new wchar_t[notice_len + 1];
wmemcpy(notice,notice_ptr,notice_len+1);
} else {
wchar_t* notice = new wchar_t[notice_len + 1];
wmemcpy(notice, notice_ptr, notice_len + 1);
room_info.notice.ptr = notice;
}
room_info.notice.length = notice_len;
@ -77,11 +60,11 @@ int GetChatRoomDetailInfo(wchar_t* chat_room_id, ChatRoomInfoInner& room_info) {
DWORD admin_len = *(DWORD*)(chat_room_info + 0x30);
DWORD admin_max_len = *(DWORD*)(chat_room_info + 0x34);
wchar_t* admin_ptr = *(wchar_t**)(chat_room_info + 0x2C);
if(admin_len <= 0){
if (admin_len <= 0) {
room_info.admin.ptr = nullptr;
}else{
wchar_t * admin = new wchar_t[admin_len + 1];
wmemcpy(admin,admin_ptr,admin_len+1);
} else {
wchar_t* admin = new wchar_t[admin_len + 1];
wmemcpy(admin, admin_ptr, admin_len + 1);
room_info.admin.ptr = admin;
}
room_info.admin.length = admin_len;
@ -90,11 +73,11 @@ int GetChatRoomDetailInfo(wchar_t* chat_room_id, ChatRoomInfoInner& room_info) {
DWORD xml_len = *(DWORD*)(chat_room_info + 0x54);
DWORD xml_max_len = *(DWORD*)(chat_room_info + 0x58);
wchar_t* xml_ptr = *(wchar_t**)(chat_room_info + 0x50);
if (xml_len <= 0){
if (xml_len <= 0) {
room_info.xml.ptr = nullptr;
}else{
wchar_t * xml = new wchar_t[xml_len + 1];
wmemcpy(xml,xml_ptr,xml_len+1);
} else {
wchar_t* xml = new wchar_t[xml_len + 1];
wmemcpy(xml, xml_ptr, xml_len + 1);
room_info.xml.ptr = xml;
}
room_info.xml.length = xml_len;
@ -109,20 +92,20 @@ int GetChatRoomDetailInfo(wchar_t* chat_room_id, ChatRoomInfoInner& room_info) {
return success;
}
int DelMemberFromChatRoom(wchar_t* chat_room_id, wchar_t** wxids,int len) {
int ChatRoomMgr::DelMemberFromChatRoom(wchar_t* chat_room_id, wchar_t** wxids,
int len) {
int success = 0;
WeChatString chat_room(chat_room_id);
vector<WeChatString> members;
VectorInner *list = (VectorInner *)&members;
VectorInner* list = (VectorInner*)&members;
DWORD members_ptr = (DWORD)&list->start;
for (int i = 0; i < len; i++) {
WeChatString pwxid(wxids[i]);
members.push_back(pwxid);
}
DWORD base = GetWeChatWinBase();
DWORD get_chat_room_mgr_addr = base + WX_CHAT_ROOM_MGR_OFFSET;
DWORD del_member_addr = base + WX_DEL_CHAT_ROOM_MEMBER_OFFSET;
DWORD init_chat_msg_addr = base + WX_INIT_CHAT_MSG_OFFSET;
DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
DWORD del_member_addr = base_addr_ + WX_DEL_CHAT_ROOM_MEMBER_OFFSET;
DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET;
__asm {
PUSHAD
CALL get_chat_room_mgr_addr
@ -142,22 +125,21 @@ int DelMemberFromChatRoom(wchar_t* chat_room_id, wchar_t** wxids,int len) {
return success;
}
int AddMemberToChatRoom(wchar_t* chat_room_id, wchar_t** wxids,int len){
int success = 0;
int ChatRoomMgr::AddMemberToChatRoom(wchar_t* chat_room_id, wchar_t** wxids,
int len) {
int success = -1;
WeChatString chat_room(chat_room_id);
vector<WeChatString> members;
VectorInner *list = (VectorInner *)&members;
VectorInner* list = (VectorInner*)&members;
DWORD members_ptr = (DWORD)&list->start;
for (int i = 0; i < len; i++) {
WeChatString pwxid(wxids[i]);
members.push_back(pwxid);
}
DWORD base = GetWeChatWinBase();
DWORD get_chat_room_mgr_addr = base + WX_CHAT_ROOM_MGR_OFFSET;
DWORD add_member_addr = base + WX_ADD_MEMBER_TO_CHAT_ROOM_OFFSET;
DWORD init_chat_msg_addr = base + WX_INIT_CHAT_MSG_OFFSET;
DWORD temp=0;
DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
DWORD add_member_addr = base_addr_ + WX_ADD_MEMBER_TO_CHAT_ROOM_OFFSET;
DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET;
DWORD temp = 0;
__asm {
PUSHAD
PUSHFD
@ -184,17 +166,16 @@ int AddMemberToChatRoom(wchar_t* chat_room_id, wchar_t** wxids,int len){
return success;
}
int GetMemberFromChatRoom(wchar_t* chat_room_id,ChatRoomInner & out){
int success = 0;
int ChatRoomMgr::GetMemberFromChatRoom(wchar_t* chat_room_id,
ChatRoomInner& out) {
int success = -1;
WeChatString chat_room(chat_room_id);
DWORD chat_room_ptr = (DWORD) &chat_room;
DWORD chat_room_ptr = (DWORD)&chat_room;
char buffer[0x1D4] = {0};
DWORD base = GetWeChatWinBase();
DWORD get_member_addr = base + WX_GET_MEMBER_FROM_CHAT_ROOM_OFFSET;
DWORD get_chat_room_mgr_addr = base + WX_CHAT_ROOM_MGR_OFFSET;
DWORD create_chat_room_addr = base + WX_INIT_CHAT_ROOM_OFFSET;
DWORD free_chat_room_addr = base + WX_FREE_CHAT_ROOM_OFFSET;
DWORD get_member_addr = base_addr_ + WX_GET_MEMBER_FROM_CHAT_ROOM_OFFSET;
DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
DWORD create_chat_room_addr = base_addr_ + WX_INIT_CHAT_ROOM_OFFSET;
DWORD free_chat_room_addr = base_addr_ + WX_FREE_CHAT_ROOM_OFFSET;
__asm {
PUSHAD
LEA ECX,buffer
@ -208,36 +189,37 @@ int GetMemberFromChatRoom(wchar_t* chat_room_id,ChatRoomInner & out){
MOV success,EAX
POPAD
}
char* members = *(char **)(buffer +0x1c);
wchar_t* room = *(wchar_t **)(buffer +0x8);
wchar_t* admin = *(wchar_t **)(buffer +0x4c);
char* members = *(char**)(buffer + 0x1c);
wchar_t* room = *(wchar_t**)(buffer + 0x8);
wchar_t* admin = *(wchar_t**)(buffer + 0x4c);
out.members = new char[strlen(members) + 1];
memcpy(out.members, members, strlen(members) + 1);
out.chat_room = new wchar_t[wcslen(room)+1];
wmemcpy(out.chat_room ,room,wcslen(room)+1);
out.chat_room = new wchar_t[wcslen(room) + 1];
wmemcpy(out.chat_room, room, wcslen(room) + 1);
out.admin = new wchar_t[wcslen(admin)+1];
wmemcpy(out.admin ,admin,wcslen(admin)+1);
out.admin = new wchar_t[wcslen(admin) + 1];
wmemcpy(out.admin, admin, wcslen(admin) + 1);
__asm{
__asm {
LEA ECX,buffer
CALL free_chat_room_addr
}
return success;
}
int ModChatRoomMemberNickName(wchar_t* chat_room_id,wchar_t* wxid,wchar_t * nick){
int success = 0;
int ChatRoomMgr::ModChatRoomMemberNickName(wchar_t* chat_room_id, wchar_t* wxid,
wchar_t* nick) {
int success = -1;
WeChatString chat_room(chat_room_id);
WeChatString self_wxid(wxid);
WeChatString new_nick(nick);
DWORD base = GetWeChatWinBase();
DWORD get_chat_room_mgr_addr = base + WX_CHAT_ROOM_MGR_OFFSET;
DWORD mod_member_nick_name_addr = base + WX_MOD_CHAT_ROOM_MEMBER_NICK_NAME_OFFSET;
DWORD init_chat_msg_addr = base + WX_INIT_CHAT_MSG_OFFSET;
__asm{
DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
DWORD mod_member_nick_name_addr =
base_addr_ + WX_MOD_CHAT_ROOM_MEMBER_NICK_NAME_OFFSET;
DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET;
__asm {
PUSHAD
CALL get_chat_room_mgr_addr
SUB ESP,0x14
@ -263,56 +245,33 @@ int ModChatRoomMemberNickName(wchar_t* chat_room_id,wchar_t* wxid,wchar_t * nick
return success;
}
int SetTopMsg(wchar_t* wxid,ULONG64 msg_id){
int ChatRoomMgr::SetTopMsg(wchar_t* wxid, ULONG64 msg_id) {
int success = -1;
char chat_msg[0x2C4] ={0};
DWORD base = GetWeChatWinBase();
DWORD new_chat_msg_addr = base + WX_NEW_CHAT_MSG_OFFSET;
DWORD get_chat_room_mgr_addr = base + WX_CHAT_ROOM_MGR_OFFSET;
DWORD handle_top_msg_addr = base + WX_TOP_MSG_OFFSET;
// DWORD free_addr = base + WX_FREE_CHAT_MSG_OFFSET;
DWORD free_addr = base + WX_FREE_CHAT_MSG_INSTANCE_COUNTER_OFFSET;
vector<string> local_msg = GetChatMsgByMsgId(msg_id);
if(local_msg.empty()){
char chat_msg[0x2D8] = {0};
DWORD new_chat_msg_addr = base_addr_ + WX_NEW_CHAT_MSG_OFFSET;
DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
DWORD handle_top_msg_addr = base_addr_ + WX_TOP_MSG_OFFSET;
DWORD free_addr = base_addr_ + WX_FREE_CHAT_MSG_INSTANCE_COUNTER_OFFSET;
DWORD get_chat_mgr_addr = base_addr_ + WX_CHAT_MGR_OFFSET;
DWORD get_by_local_Id_addr = base_addr_ + WX_GET_MGR_BY_PREFIX_LOCAL_ID_OFFSET;
int db_index = 0;
int local_id = DB::GetInstance().GetLocalIdByMsgId(msg_id, db_index);
if (local_id < 1) {
return -2;
}
string type = local_msg[3];
string status = local_msg[10];
string talker = local_msg[13];
string content = local_msg[14];
wstring w_talker = String2Wstring(talker);
wstring w_content = String2Wstring(content);
int msg_type =stoi(type);
int msg_status =stoi(status);
#ifdef _DEBUG
wcout << "w_talker:" <<w_talker <<endl;
wcout << "w_content:" <<w_content <<endl;
#endif
WeChatString chat_room(w_talker);
WeChatString msg_content(w_content);
WeChatString user_id(wxid);
__asm{
PUSHAD
PUSHFD
LEA ECX,chat_msg
CALL new_chat_msg_addr
POPAD
}
memcpy(&chat_msg[0x30],&msg_id,sizeof(msg_id));
memcpy(&chat_msg[0x38],&msg_type,sizeof(msg_type));
memcpy(&chat_msg[0x40],&msg_status,sizeof(msg_status));
memcpy(&chat_msg[0x48],&chat_room,sizeof(chat_room));
memcpy(&chat_msg[0x70],&msg_content,sizeof(msg_content));
memcpy(&chat_msg[0x174],&user_id,sizeof(user_id));
__asm{
PUSHAD
CALL get_chat_mgr_addr
PUSH dword ptr [db_index]
LEA ECX,chat_msg
PUSH dword ptr [local_id]
CALL get_by_local_Id_addr
ADD ESP,0x8
CALL get_chat_room_mgr_addr
PUSH 0x0
LEA EAX,chat_msg
@ -322,23 +281,22 @@ int SetTopMsg(wchar_t* wxid,ULONG64 msg_id){
LEA ECX,chat_msg
PUSH 0x0
CALL free_addr
POPFD
POPAD
}
return success;
}
int RemoveTopMsg(wchar_t* chat_room_id,ULONG64 msg_id){
int ChatRoomMgr::RemoveTopMsg(wchar_t* chat_room_id, ULONG64 msg_id) {
int success = -1;
WeChatString chat_room(chat_room_id);
DWORD base = GetWeChatWinBase();
DWORD get_chat_room_mgr_addr = base + WX_CHAT_ROOM_MGR_OFFSET;
DWORD new_chat_msg_addr = base + WX_NEW_CHAT_MSG_OFFSET;
DWORD init_chat_msg_addr = base + WX_INIT_CHAT_MSG_OFFSET;
DWORD remove_top_msg_addr = base + WX_REMOVE_TOP_MSG_OFFSET;
DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
DWORD new_chat_msg_addr = base_addr_ + WX_NEW_CHAT_MSG_OFFSET;
DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET;
DWORD remove_top_msg_addr = base_addr_ + WX_REMOVE_TOP_MSG_OFFSET;
__asm{
__asm {
PUSHAD
CALL get_chat_room_mgr_addr
MOV EDI,dword ptr [msg_id]
@ -358,19 +316,17 @@ int RemoveTopMsg(wchar_t* chat_room_id,ULONG64 msg_id){
return success;
}
std::wstring GetChatRoomMemberNickname(wchar_t* chat_room_id,wchar_t* wxid){
std::wstring ChatRoomMgr::GetChatRoomMemberNickname(wchar_t* chat_room_id,
wchar_t* wxid) {
WeChatString chat_room(chat_room_id);
WeChatString member_id(wxid);
WeChatString nickname(NULL);
DWORD base = GetWeChatWinBase();
DWORD get_chat_room_mgr_addr = base + WX_CHAT_ROOM_MGR_OFFSET;
DWORD get_nickname_addr = base + WX_GET_MEMBER_NICKNAME_OFFSET;
DWORD contact_mgr_addr = base + WX_CONTACT_MGR_INSTANCE_OFFSET;
DWORD get_contact_addr = base + WX_GET_CONTACT_OFFSET;
DWORD free_contact_addr = base + WX_FREE_CONTACT_OFFSET;
__asm{
DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
DWORD get_nickname_addr = base_addr_ + WX_GET_MEMBER_NICKNAME_OFFSET;
DWORD contact_mgr_addr = base_addr_ + WX_CONTACT_MGR_OFFSET;
DWORD get_contact_addr = base_addr_ + WX_GET_CONTACT_OFFSET;
DWORD free_contact_addr = base_addr_ + WX_FREE_CONTACT_OFFSET;
__asm {
PUSHAD
PUSHFD
CALL get_chat_room_mgr_addr
@ -388,7 +344,7 @@ std::wstring GetChatRoomMemberNickname(wchar_t* chat_room_id,wchar_t* wxid){
wstring name = L"";
if (nickname.ptr) {
name += wstring(nickname.ptr);
}else {
} else {
char buff[0x440] = {0};
__asm {
PUSHAD
@ -405,7 +361,7 @@ std::wstring GetChatRoomMemberNickname(wchar_t* chat_room_id,wchar_t* wxid){
}
name += READ_WSTRING(buff, 0x6C);
__asm{
__asm {
PUSHAD
PUSHFD
LEA ECX,buff
@ -416,3 +372,4 @@ std::wstring GetChatRoomMemberNickname(wchar_t* chat_room_id,wchar_t* wxid){
}
return name;
}
} // namespace wxhelper

28
src/chat_room_mgr.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef WXHELPER_CHAT_ROOM_MGR_H_
#define WXHELPER_CHAT_ROOM_MGR_H_
#include "wechat_function.h"
#include "base_mgr.h"
namespace wxhelper {
class ChatRoomMgr:public BaseMgr {
public:
explicit ChatRoomMgr(DWORD base);
~ChatRoomMgr();
int GetChatRoomDetailInfo(wchar_t* chat_room_id,
ChatRoomInfoInner& room_info);
int DelMemberFromChatRoom(wchar_t* chat_room_id, wchar_t** wxids,
int len);
int AddMemberToChatRoom(wchar_t* chat_room_id, wchar_t** wxids,
int len);
int GetMemberFromChatRoom(wchar_t* chat_room_id, ChatRoomInner& out);
int ModChatRoomMemberNickName(wchar_t* chat_room_id, wchar_t* wxid,
wchar_t* nick);
int SetTopMsg(wchar_t* wxid, ULONG64 msg_id);
int RemoveTopMsg(wchar_t* chat_room_id, ULONG64 msg_id);
std::wstring GetChatRoomMemberNickname(wchar_t* chat_room_id,
wchar_t* wxid);
};
} // namespace wxhelper
#endif

View File

@ -1,93 +0,0 @@
#ifndef COMMON_H_
#define COMMON_H_
#include <string>
#define READ_WSTRING(addr, offset) ((*(DWORD *)(addr + offset + 0x4) == 0) ? std::wstring(L"") : std::wstring((wchar_t *)(*(DWORD *)(addr + offset)), *(DWORD *)(addr + offset + 0x4)))
#define STR2INT(str) (IsDigit(str) ? stoi(str) : 0)
/// @brief utf8 转换成unicode
/// @param buffer utf8
/// @return unicode
std::wstring utf8_to_unicode(const char *buffer);
/// @brief unicode转换utf8
/// @param wstr unicode
/// @return utf8
std::string unicode_to_utf8(wchar_t *wstr);
/// @brief 获取WeChatWin.dll基址
/// @return 基址
DWORD GetWeChatWinBase();
/// @brief 创建窗口
/// @param void
/// @return 创建结果
BOOL CreateConsole(void);
/// @brief hook任意地址
/// @param hook_addr 被hook的地址
/// @param jmp_addr 被hook的函数的地址
/// @param origin 原始code
void HookAnyAddress(DWORD hook_addr, LPVOID jmp_addr, char *origin);
/// @brief 取消hook
/// @param hook_addr 被hook的地址
/// @param origin 原始code
void UnHookAnyAddress(DWORD hook_addr, char *origin);
/// @brief get timeW
/// @param timestamp timestamp
/// @return str
std::wstring GetTimeW(long long timestamp);
/// @brief unicode trans utf8
/// @param str unicode str
/// @return utf8 str
std::string UnicodeToUtf8(const wchar_t *str);
/// @brief string convert wstring
/// @param str
/// @return
std::wstring String2Wstring(std::string str);
/// @brief wstring convert string
/// @param str
/// @return
std::string Wstring2String(std::wstring wstr);
/// @brief create dir
/// @param path
/// @return
BOOL FindOrCreateDirectoryW(const wchar_t *path);
void CloseConsole();
std::string EncodeHexString(const std::string &str);
std::string Hex2String(const std::string &hex_str);
std::string Bytes2Hex(const BYTE *bytes, const int length);
void Hex2Bytes(const std::string &hex, BYTE *bytes);
bool IsDigit(std::string str);
template <typename T1, typename T2>
std::vector<T1> split(T1 str, T2 letter) {
vector<T1> arr;
size_t pos;
while ((pos = str.find_first_of(letter)) != T1::npos) {
T1 str1 = str.substr(0, pos);
arr.push_back(str1);
str = str.substr(pos + 1, str.length() - pos - 1);
}
arr.push_back(str);
return arr;
}
template <typename T1, typename T2>
T1 replace(T1 source, T2 replaced, T1 replaceto) {
vector<T1> v_arr = split(source, replaced);
if (v_arr.size() < 2) return source;
T1 temp;
for (unsigned int i = 0; i < v_arr.size() - 1; i++) {
temp += v_arr[i];
temp += replaceto;
}
temp += v_arr[v_arr.size() - 1];
return temp;
}
#endif

6
src/config.cc Normal file
View File

@ -0,0 +1,6 @@
#include "config.h"
namespace wxhelper {
Config::Config(/* args */) {}
Config::~Config() {}
} // namespace wxhelper

15
src/config.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef WXHELPER_CONFIG_H_
#define WXHELPER_CONFIG_H_
namespace wxhelper{
class Config
{
private:
/* data */
public:
Config(/* args */);
~Config();
};
}
#endif

View File

@ -1,49 +0,0 @@
#include "pch.h"
#include "confirm_receipt.h"
#include "common.h"
#include "wechat_data.h"
#define WX_NEW_WCPAYINFO_OFFSET 0x756340
#define WX_FREE_WCPAYINFO_OFFSET 0x73c170
#define WX_CONFIRM_RECEIPT_OFFSET 0x15287a0
int DoConfirmReceipt(wchar_t *wxid, wchar_t *transcationid,
wchar_t *transferid) {
int success = -1;
WeChatString recv_id(wxid);
WeChatString transcation_id(transcationid);
WeChatString transfer_id(transferid);
char pay_info[0x134] = {0};
DWORD base = GetWeChatWinBase();
DWORD new_pay_info_addr = base + WX_NEW_WCPAYINFO_OFFSET;
DWORD free_pay_info_addr = base + WX_FREE_WCPAYINFO_OFFSET;
DWORD do_confirm_addr = base + WX_CONFIRM_RECEIPT_OFFSET;
__asm {
PUSHAD
LEA ECX,pay_info
CALL new_pay_info_addr
MOV dword ptr [pay_info + 0x4], 0x1
MOV dword ptr [pay_info + 0x4C], 0x1
POPAD
}
memcpy(&pay_info[0x1c], &transcation_id, sizeof(transcation_id));
memcpy(&pay_info[0x38], &transfer_id, sizeof(transfer_id));
__asm {
PUSHAD
PUSH 0x1
SUB ESP,0x8
LEA EDX,recv_id
LEA ECX,pay_info
CALL do_confirm_addr
MOV success,EAX
ADD ESP,0xC
PUSH 0x0
LEA ECX,pay_info
CALL free_pay_info_addr
POPAD
}
return success;
}

View File

@ -1,6 +0,0 @@
#ifndef CONFIRM_RECEIPT_H
#define CONFIRM_RECEIPT_H
int DoConfirmReceipt(wchar_t* wxid,wchar_t *transcationid, wchar_t *transferid);
#endif

View File

@ -1,192 +0,0 @@
#include "pch.h"
#include "contact.h"
#include "common.h"
#include "wechat_data.h"
using namespace std;
#define WX_CONTACT_MGR_INSTANCE_OFFSET 0x75a4a0
#define WX_CONTACT_GET_LIST_OFFSET 0xc089f0
#define WX_CONTACT_DEL_OFFSET 0xb9b3b0
#define WX_INIT_CHAT_MSG_OFFSET 0xed3be0
#define WX_SYNC_MGR_OFFSET 0xa87fd0
#define WX_SET_VALUE_OFFSET 0x1f80900
#define WX_DO_DEL_CONTACT_OFFSET 0xca6480
#define WX_FREE_CONTACT_OFFSET 0xe23690
#define WX_GET_CONTACT_OFFSET 0xb93b20
#define WX_DO_VERIFY_USER_OFFSET 0xB91160
int GetAllContact(vector<Contact> &vec) {
DWORD base = GetWeChatWinBase();
DWORD get_instance = base + WX_CONTACT_MGR_INSTANCE_OFFSET;
DWORD contact_get_list = base + WX_CONTACT_GET_LIST_OFFSET;
// char contact[0xc] = {0};
DWORD* contact[3] = {0, 0, 0};
int success = 0;
__asm {
PUSHAD
CALL get_instance
LEA ECX,contact
PUSH ECX
MOV ECX,EAX
CALL contact_get_list
MOVZX EAX,AL
MOV success,EAX
POPAD
}
DWORD start = (DWORD)contact[0];
DWORD end = (DWORD)contact[2];
#ifdef _DEBUG
cout << "address = " << &contact << endl;
cout << "refresh contact = " << success << endl;
cout << "start = " << start << endl;
cout << "end = " << end << endl;
#endif
while (start < end) {
Contact temp{0};
temp.wxid.ptr = *(wchar_t **)(start + 0x10);
temp.wxid.length = *(DWORD *)(start + 0x14);
temp.wxid.max_length = *(DWORD *)(start + 0x18);
temp.custom_account.ptr = *(wchar_t **)(start + 0x24);
temp.custom_account.length = *(DWORD *)(start + 0x28);
temp.custom_account.max_length = *(DWORD *)(start + 0x2C);
temp.encrypt_name.ptr = *(wchar_t **)(start + 0x6c);
temp.encrypt_name.length = *(DWORD *)(start + 0x70);
temp.encrypt_name.max_length = *(DWORD *)(start + 0x74);
temp.pinyin.ptr = *(wchar_t **)(start + 0xAC);
temp.pinyin.length = *(DWORD *)(start + 0xB0);
temp.pinyin.max_length = *(DWORD *)(start + 0xB4);
temp.pinyin_all.ptr = *(wchar_t **)(start + 0xC0);
temp.pinyin_all.length = *(DWORD *)(start + 0xC4);
temp.pinyin_all.max_length = *(DWORD *)(start + 0xC8);
temp.del_flag = *(DWORD *)(start + 0x4c);
temp.type = *(DWORD *)(start + 0x50);
temp.verify_flag = *(DWORD *)(start + 0x54);
vec.push_back(temp);
start += 0x438;
}
return success;
}
// note maybe not delete
int DelContact(wchar_t *wxid) {
int success = -1;
WeChatString user_id(wxid);
DWORD id_ptr = (DWORD) &user_id;
DWORD base = GetWeChatWinBase();
DWORD sync_mgr_addr = base + WX_SYNC_MGR_OFFSET;
DWORD set_id_addr = base + WX_SET_VALUE_OFFSET;
DWORD del_contact_addr = base + WX_DO_DEL_CONTACT_OFFSET;
int len = user_id.length;
string id_cstr = unicode_to_utf8(wxid);
char id_[0x20]={0};
memcpy(id_,id_cstr.c_str(),id_cstr.size()+1);
char buff[0x10]={0};
__asm{
PUSHAD
PUSHFD
CALL sync_mgr_addr
MOV ECX,EAX
LEA EAX,buff
MOV [ECX + 4],EAX
LEA EAX,id_
Mov dword ptr[buff +0x4],EAX
CALL del_contact_addr
MOV success,EAX
POPFD
POPAD
}
return success;
}
std::wstring GetContactOrChatRoomNickname(wchar_t *id) {
int success = -1;
char buff[0x440] = {0};
WeChatString pri(id);
DWORD base = GetWeChatWinBase();
DWORD contact_mgr_addr = base + WX_CONTACT_MGR_INSTANCE_OFFSET;
DWORD get_contact_addr = base + WX_GET_CONTACT_OFFSET;
DWORD free_contact_addr = base + WX_FREE_CONTACT_OFFSET;
wstring name = L"";
__asm {
PUSHAD
PUSHFD
CALL contact_mgr_addr
LEA ECX,buff
PUSH ECX
LEA ECX,pri
PUSH ECX
MOV ECX,EAX
CALL get_contact_addr
POPFD
POPAD
}
name += READ_WSTRING(buff, 0x6C);
__asm {
PUSHAD
PUSHFD
LEA ECX,buff
CALL free_contact_addr
POPFD
POPAD
}
return name;
}
int AddFriendByWxid(wchar_t *wxid){
int success = -1;
DWORD base = GetWeChatWinBase();
DWORD contact_mgr_addr = base + WX_CONTACT_MGR_INSTANCE_OFFSET;
DWORD set_group_addr = base + 0x746E20;
DWORD fn2_addr = base + 0x285D968;
DWORD fn3_addr = base + 0x6F6050;
DWORD fn4_addr = base + 0xED3BE0;
DWORD do_verify_user_addr = base + WX_DO_VERIFY_USER_OFFSET;
DWORD instance =0;
WeChatString chat_room(NULL);
WeChatString user_id(wxid);
__asm{
PUSHAD
PUSHFD
CALL contact_mgr_addr
SUB ESP,0x18
MOV dword ptr [instance],EAX
MOV ECX,ESP
PUSH ECX
LEA ECX,chat_room
CALL set_group_addr
MOV EAX,fn2_addr
SUB ESP,0x18
MOV ECX,ESP
PUSH EAX
CALL fn3_addr
PUSH 0x0
PUSH 0XE
SUB ESP,0x14
MOV ESI,ESP
MOV dword ptr [ESI],0x0
MOV dword ptr [ESI+0x4],0x0
MOV dword ptr [ESI+0x8],0x0
MOV dword ptr [ESI+0xC],0x0
MOV dword ptr [ESI+0x10],0x0
PUSH 0x1
SUB ESP,0x14
MOV ECX,ESP
LEA EAX,user_id
PUSH EAX
CALL fn4_addr
MOV ECX,dword ptr [instance]
CALL do_verify_user_addr
MOV success,EAX
POPFD
POPAD
}
return success;
}

View File

@ -1,15 +0,0 @@
#ifndef CONTACT_H_
#define CONTACT_H_
#include <vector>
#include "wechat_data.h"
int GetAllContact(std::vector<Contact> &vec);
int DelContact(wchar_t* wxid);
std::wstring GetContactOrChatRoomNickname(wchar_t* id);
int AddFriendByWxid(wchar_t *wxid);
#endif

193
src/contact_mgr.cc Normal file
View File

@ -0,0 +1,193 @@
#include "pch.h"
#include "contact_mgr.h"
#include "wechat_function.h"
using namespace std;
namespace wxhelper {
ContactMgr::ContactMgr(DWORD base) : BaseMgr(base) {}
ContactMgr::~ContactMgr() {}
int ContactMgr::GetAllContact(vector<Contact> &vec) {
DWORD get_instance = base_addr_ + WX_CONTACT_MGR_OFFSET;
DWORD contact_get_list = base_addr_ + WX_CONTACT_GET_LIST_OFFSET;
DWORD *contact[3] = {0, 0, 0};
int success = 0;
__asm {
PUSHAD
CALL get_instance
LEA ECX,contact
PUSH ECX
MOV ECX,EAX
CALL contact_get_list
MOVZX EAX,AL
MOV success,EAX
POPAD
}
DWORD start = (DWORD)contact[0];
DWORD end = (DWORD)contact[2];
while (start < end) {
Contact temp{0};
temp.wxid.ptr = *(wchar_t **)(start + 0x10);
temp.wxid.length = *(DWORD *)(start + 0x14);
temp.wxid.max_length = *(DWORD *)(start + 0x18);
temp.custom_account.ptr = *(wchar_t **)(start + 0x24);
temp.custom_account.length = *(DWORD *)(start + 0x28);
temp.custom_account.max_length = *(DWORD *)(start + 0x2C);
temp.encrypt_name.ptr = *(wchar_t **)(start + 0x6c);
temp.encrypt_name.length = *(DWORD *)(start + 0x70);
temp.encrypt_name.max_length = *(DWORD *)(start + 0x74);
temp.pinyin.ptr = *(wchar_t **)(start + 0xAC);
temp.pinyin.length = *(DWORD *)(start + 0xB0);
temp.pinyin.max_length = *(DWORD *)(start + 0xB4);
temp.pinyin_all.ptr = *(wchar_t **)(start + 0xC0);
temp.pinyin_all.length = *(DWORD *)(start + 0xC4);
temp.pinyin_all.max_length = *(DWORD *)(start + 0xC8);
temp.del_flag = *(DWORD *)(start + 0x4c);
temp.type = *(DWORD *)(start + 0x50);
temp.verify_flag = *(DWORD *)(start + 0x54);
vec.push_back(temp);
start += 0x438;
}
return success;
}
int ContactMgr::DelContact(wchar_t *wxid) {
int success = -1;
WeChatString user_id(wxid);
DWORD id_ptr = (DWORD)&user_id;
DWORD sync_mgr_addr = base_addr_ + WX_SYNC_MGR_OFFSET;
DWORD set_id_addr = base_addr_ + WX_SET_VALUE_OFFSET;
DWORD del_contact_addr = base_addr_ + WX_DO_DEL_CONTACT_OFFSET;
int len = user_id.length;
wstring ws_wxid(wxid);
string id_cstr = Utils::WstringToUTF8(ws_wxid);
char id_[0x20] = {0};
memcpy(id_, id_cstr.c_str(), id_cstr.size() + 1);
char buff[0x10] = {0};
__asm {
PUSHAD
PUSHFD
CALL sync_mgr_addr
MOV ECX,EAX
LEA EAX,buff
MOV [ECX + 4],EAX
LEA EAX,id_
Mov dword ptr[buff +0x4],EAX
CALL del_contact_addr
MOV success,EAX
POPFD
POPAD
}
return success;
}
wstring ContactMgr::GetContactOrChatRoomNickname(wchar_t *id) {
int success = -1;
char buff[0x440] = {0};
WeChatString pri(id);
DWORD contact_mgr_addr = base_addr_ + WX_CONTACT_MGR_OFFSET;
DWORD get_contact_addr = base_addr_ + WX_GET_CONTACT_OFFSET;
DWORD free_contact_addr = base_addr_ + WX_FREE_CONTACT_OFFSET;
wstring name = L"";
__asm {
PUSHAD
PUSHFD
CALL contact_mgr_addr
LEA ECX,buff
PUSH ECX
LEA ECX,pri
PUSH ECX
MOV ECX,EAX
CALL get_contact_addr
POPFD
POPAD
}
name += READ_WSTRING(buff, 0x6C);
__asm {
PUSHAD
PUSHFD
LEA ECX,buff
CALL free_contact_addr
POPFD
POPAD
}
return name;
}
int ContactMgr::AddFriendByWxid(wchar_t *wxid,wchar_t* msg) {
int success = -1;
DWORD contact_mgr_addr = base_addr_ + WX_CONTACT_MGR_OFFSET;
DWORD verify_msg_addr = base_addr_ + WX_VERIFY_MSG_OFFSET;
DWORD set_value_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET;
DWORD do_verify_user_addr = base_addr_ + WX_DO_VERIFY_USER_OFFSET;
DWORD fn1_addr = base_addr_ + 0x758720;
WeChatString user_id(wxid);
WeChatString w_msg(msg);
DWORD null_ptr = 0;
DWORD instance =0;
Unkown null_obj={};
null_obj.field6 = 0xF;
__asm{
PUSHAD
PUSHFD
CALL contact_mgr_addr
MOV dword ptr [instance],EAX
SUB ESP,0x18
MOV EAX,ESP
SUB ESP,0x18
LEA EAX,null_obj
MOV ECX,ESP
PUSH EAX
CALL fn1_addr
PUSH 0x0
PUSH 0x6
MOV EAX,w_msg
SUB ESP,0x14
MOV ECX,ESP
PUSH -0x1
PUSH EAX
CALL verify_msg_addr
PUSH 0x2
LEA EAX,user_id
SUB ESP,0x14
MOV ECX,ESP
PUSH EAX
CALL set_value_addr
MOV ECX,dword ptr [instance]
CALL do_verify_user_addr
MOV success,EAX
POPFD
POPAD
}
// __asm {
// PUSHAD
// PUSHFD
// SUB ESP,0x14
// MOV ECX,ESP
// PUSH -0x1
// PUSH w_msg
// CALL verify_msg_addr
// PUSH 0x2
// LEA EAX,user_id
// SUB ESP,0x14
// MOV ECX,ESP
// PUSH EAX
// CALL set_value_addr
// CALL contact_mgr_addr
// MOV ECX,EAX
// CALL do_verify_user_addr
// MOV success,EAX
// POPFD
// POPAD
// }
return success;
}
} // namespace wxhelper

20
src/contact_mgr.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef WXHELPER_CONTACT_MGR_H_
#define WXHELPER_CONTACT_MGR_H_
#include <string>
#include <vector>
#include "base_mgr.h"
#include "wechat_function.h"
namespace wxhelper {
class ContactMgr : public BaseMgr {
public:
explicit ContactMgr(DWORD base);
~ContactMgr();
int GetAllContact(std::vector<Contact>& vec);
int DelContact(wchar_t* wxid);
std::wstring GetContactOrChatRoomNickname(wchar_t* id);
int AddFriendByWxid(wchar_t* wxid,wchar_t* msg);
};
} // namespace wxhelper
#endif;

View File

@ -1,57 +1,163 @@
#include "get_db_handle.h"
#include "pch.h"
#include "db.h"
#include "common.h"
#include "db_operation.h"
#include "new_sqlite3.h"
#include "pch.h"
#include "wechat_data.h"
#define CONTACT_G_PINSTANCE_OFFSET 0x2ffddc8
#define DB_MICRO_MSG_OFFSET 0x68
#define DB_CHAT_MSG_OFFSET 0x1C0
#define DB_MISC_OFFSET 0x3D8
#define DB_EMOTION_OFFSET 0x558
#define DB_MEDIA_OFFSET 0x9B8
#define DB_BIZCHAT_MSG_OFFSET 0x1120
#define DB_FUNCTION_MSG_OFFSET 0x11B0
#define DB_NAME_OFFSET 0x14
#define STORAGE_START_OFFSET 0x13f8
#define STORAGE_END_OFFSET 0x13fc
#define PUBLIC_MSG_MGR_OFFSET 0x303df74
#define MULTI_DB_MSG_MGR_OFFSET 0x30403b8
#define FAVORITE_STORAGE_MGR_OFFSET 0x303fd40
#define FTS_FAVORITE_MGR_OFFSET 0x2ffe908
#define OP_LOG_STORAGE_VFTABLE 0x2AD3A20
#define CHAT_MSG_STORAGE_VFTABLE 0x2AC10F0
#define CHAT_CR_MSG_STORAGE_VFTABLE 0x2ABEF14
#define SESSION_STORAGE_VFTABLE 0x2AD3578
#define APP_INFO_STORAGE_VFTABLE 0x2ABCC58
#define HEAD_IMG_STORAGE_VFTABLE 0x2ACD9DC
#define HEAD_IMG_URL_STORAGE_VFTABLE 0x2ACDF70
#define BIZ_INFO_STORAGE_VFTABLE 0x2ABD718
#define TICKET_INFO_STORAGE_VFTABLE 0x2AD5400
#define CHAT_ROOM_STORAGE_VFTABLE 0x2AC299C
#define CHAT_ROOM_INFO_STORAGE_VFTABLE 0x2AC245C
#define MEDIA_STORAGE_VFTABLE 0x2ACE998
#define NAME_2_ID_STORAGE_VFTABLE 0x2AD222C
#define EMOTION_PACKAGE_STORAGE_VFTABLE 0x2AC6400
#define EMOTION_STORAGE_VFTABLE 0x2AC7018
#define BUFINFO_STORAGE_VFTABLE 0x2AC3178
#define CUSTOM_EMOTION_STORAGE_VFTABLE 0x2AC4E90
#define DEL_SESSIONINFO_STORAGE_VFTABLE 0x2AC5F98
#define FUNCTION_MSG_STORAGE_VFTABLE 0x2ACD10C
#define FUNCTION_MSG_TASK_STORAGE_VFTABLE 0x2ACC5C8
#define REVOKE_MSG_STORAGE_VFTABLE 0x2AD27BC
#include "base64.h"
#include "easylogging++.h"
#include "wechat_function.h"
using namespace std;
map<wstring, DatabaseInfo> dbmap;
std::vector<DatabaseInfo> dbs;
namespace wxhelper {
void DB::init(DWORD base) {
base_addr_ = base;
dbmap_ = {};
dbs_ = {};
}
void FreeResult(vector<vector<SqlResult>> &data) {
if (data.size() == 0) {
return;
}
for (unsigned int i = 0; i < data.size(); i++) {
for (unsigned j = 0; j < data[i].size(); j++) {
SqlResult *sr = (SqlResult *)&data[i][j];
if (sr->column_name) {
delete[] sr->column_name;
sr->column_name = NULL;
}
if (sr->content) {
delete[] sr->content;
sr->content = NULL;
}
}
data[i].clear();
}
data.clear();
}
int DB::SelectDataInner(DWORD db, const char *sql,
vector<vector<SqlResult>> &data) {
Sqlite3_prepare p_Sqlite3_prepare =
(Sqlite3_prepare)(base_addr_ + SQLITE3_PREPARE_OFFSET);
Sqlite3_step p_Sqlite3_step =
(Sqlite3_step)(base_addr_ + SQLITE3_STEP_OFFSET);
Sqlite3_column_count p_Sqlite3_column_count =
(Sqlite3_column_count)(base_addr_ + SQLITE3_COLUMN_COUNT_OFFSET);
Sqlite3_column_name p_Sqlite3_column_name =
(Sqlite3_column_name)(base_addr_ + SQLITE3_COLUMN_NAME_OFFSET);
Sqlite3_column_type p_Sqlite3_column_type =
(Sqlite3_column_type)(base_addr_ + SQLITE3_COLUMN_TYPE_OFFSET);
Sqlite3_column_blob p_Sqlite3_column_blob =
(Sqlite3_column_blob)(base_addr_ + SQLITE3_COLUMN_BLOB_OFFSET);
Sqlite3_column_bytes p_Sqlite3_column_bytes =
(Sqlite3_column_bytes)(base_addr_ + SQLITE3_COLUMN_BYTES_OFFSET);
Sqlite3_finalize p_Sqlite3_finalize =
(Sqlite3_finalize)(base_addr_ + SQLITE3_FINALIZE_OFFSET);
DWORD *stmt;
int rc = p_Sqlite3_prepare(db, sql, -1, &stmt, 0);
if (rc != SQLITE_OK) return NULL;
while (p_Sqlite3_step(stmt) == SQLITE_ROW) {
int col_count = p_Sqlite3_column_count(stmt);
vector<SqlResult> tempStruct;
for (int i = 0; i < col_count; i++) {
SqlResult temp = {0};
const char *ColName = p_Sqlite3_column_name(stmt, i);
int nType = p_Sqlite3_column_type(stmt, i);
const void *pReadBlobData = p_Sqlite3_column_blob(stmt, i);
int nLength = p_Sqlite3_column_bytes(stmt, i);
temp.column_name = new char[strlen(ColName) + 1];
memcpy(temp.column_name, ColName, strlen(ColName) + 1);
temp.column_name_len = strlen(ColName);
temp.content_len = nLength;
switch (nType) {
case SQLITE_BLOB: {
temp.content = new char[nLength];
memcpy(temp.content, pReadBlobData, nLength);
temp.is_blob = true;
break;
}
default: {
if (nLength != 0) {
temp.content = new char[nLength + 1];
memcpy(temp.content, pReadBlobData, nLength + 1);
} else {
temp.content = new char[2];
ZeroMemory(temp.content, 2);
}
temp.is_blob = false;
break;
}
}
tempStruct.push_back(temp);
}
data.push_back(tempStruct);
}
p_Sqlite3_finalize(stmt);
return 1;
}
int DB::Select(DWORD db_hanle, const char *sql,
vector<vector<string>> &query_result) {
vector<vector<SqlResult>> data;
int status = SelectDataInner(db_hanle, sql, data);
if (status == 0) {
return 0;
}
if (data.size() == 0) {
return 1;
}
vector<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) {
vector<string> item;
for (size_t i = 0; i < it.size(); i++) {
if (!it[i].is_blob) {
string content(it[i].content);
item.push_back(content);
} else {
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;
}
int SelectDbInfo(void *data, int argc, char **argv, char **name) {
vector<SqlResult> result;
for (int i = 0; i < argc; i++) {
SqlResult temp = {0};
temp.column_name = new char[strlen(name[i]) + 1];
memcpy(temp.column_name, name[i], strlen(name[i]) + 1);
temp.column_name_len = strlen(name[i]);
if (argv[i]) {
temp.content = new char[strlen(argv[i]) + 1];
memcpy(temp.content, argv[i], strlen(argv[i]) + 1);
temp.content_len = strlen(argv[i]);
} else {
temp.content = new char[2];
ZeroMemory(temp.content, 2);
temp.content_len = 0;
}
result.push_back(temp);
}
return 1;
}
int DB::ExecuteSQL(DWORD db, const char *sql, DWORD callback, void *data) {
DWORD sqlite3_exec_addr = base_addr_ + SQLITE3_EXEC_OFFSET;
Sqlite3_exec fn_sqlite3_exec = (Sqlite3_exec)sqlite3_exec_addr;
int status = fn_sqlite3_exec(db, sql, (Sqlite3_callback)callback, data, 0);
return status;
}
int GetDbInfo(void *data, int argc, char **argv, char **name) {
DatabaseInfo *pdata = (DatabaseInfo *)data;
@ -89,11 +195,10 @@ int GetDbInfo(void *data, int argc, char **argv, char **name) {
return 0;
}
std::vector<void *> GetDbHandles() {
dbs.clear();
dbmap.clear();
DWORD base = GetWeChatWinBase();
DWORD p_contact_addr = *(DWORD *)(base + CONTACT_G_PINSTANCE_OFFSET);
std::vector<void *> DB::GetDbHandles() {
dbs_.clear();
dbmap_.clear();
DWORD p_contact_addr = *(DWORD *)(base_addr_ + CONTACT_G_PINSTANCE_OFFSET);
DWORD micro_msg_db_addr = *(DWORD *)(p_contact_addr + DB_MICRO_MSG_OFFSET);
DWORD chat_msg_db_addr = *(DWORD *)(p_contact_addr + DB_CHAT_MSG_OFFSET);
DWORD misc_db_addr = *(DWORD *)(p_contact_addr + DB_MISC_OFFSET);
@ -114,10 +219,10 @@ std::vector<void *> GetDbHandles() {
ExecuteSQL(micro_msg_db_addr,
"select * from sqlite_master where type=\"table\";",
(DWORD)GetDbInfo, &micro_msg_db);
dbs.push_back(micro_msg_db);
dbs_.push_back(micro_msg_db);
wstring micro_msg_name = wstring((wchar_t *)(*(
DWORD *)(p_contact_addr + DB_MICRO_MSG_OFFSET + DB_NAME_OFFSET)));
dbmap[micro_msg_name] = micro_msg_db;
dbmap_[micro_msg_name] = micro_msg_db;
// chatMsg.db
DatabaseInfo chat_msg_db{0};
@ -129,10 +234,10 @@ std::vector<void *> GetDbHandles() {
ExecuteSQL(chat_msg_db_addr,
"select * from sqlite_master where type=\"table\";",
(DWORD)GetDbInfo, &chat_msg_db);
dbs.push_back(chat_msg_db);
dbs_.push_back(chat_msg_db);
wstring chat_msg_name = wstring((wchar_t *)(*(
DWORD *)(p_contact_addr + DB_CHAT_MSG_OFFSET + DB_NAME_OFFSET)));
dbmap[chat_msg_name] = chat_msg_db;
dbmap_[chat_msg_name] = chat_msg_db;
// misc.db
DatabaseInfo misc_db{0};
@ -143,10 +248,10 @@ std::vector<void *> GetDbHandles() {
misc_db.handle = misc_db_addr;
ExecuteSQL(misc_db_addr, "select * from sqlite_master where type=\"table\";",
(DWORD)GetDbInfo, &misc_db);
dbs.push_back(misc_db);
dbs_.push_back(misc_db);
wstring misc_name = wstring((
wchar_t *)(*(DWORD *)(p_contact_addr + DB_MISC_OFFSET + DB_NAME_OFFSET)));
dbmap[misc_name] = misc_db;
dbmap_[misc_name] = misc_db;
// emotion.db
DatabaseInfo emotion_db{0};
@ -158,10 +263,10 @@ std::vector<void *> GetDbHandles() {
ExecuteSQL(emotion_db_addr,
"select * from sqlite_master where type=\"table\";",
(DWORD)GetDbInfo, &emotion_db);
dbs.push_back(emotion_db);
dbs_.push_back(emotion_db);
wstring emotion_name = wstring((wchar_t *)(*(
DWORD *)(p_contact_addr + DB_EMOTION_OFFSET + DB_NAME_OFFSET)));
dbmap[emotion_name] = emotion_db;
dbmap_[emotion_name] = emotion_db;
// media.db
DatabaseInfo media_db{0};
@ -172,10 +277,10 @@ std::vector<void *> GetDbHandles() {
media_db.handle = media_db_addr;
ExecuteSQL(media_db_addr, "select * from sqlite_master where type=\"table\";",
(DWORD)GetDbInfo, &media_db);
dbs.push_back(media_db);
dbs_.push_back(media_db);
wstring media_name = wstring((wchar_t *)(*(
DWORD *)(p_contact_addr + DB_MEDIA_OFFSET + DB_NAME_OFFSET)));
dbmap[media_name] = media_db;
dbmap_[media_name] = media_db;
// functionMsg.db
DatabaseInfo function_msg_db{0};
@ -187,10 +292,10 @@ std::vector<void *> GetDbHandles() {
ExecuteSQL(function_msg_db_addr,
"select * from sqlite_master where type=\"table\";",
(DWORD)GetDbInfo, &function_msg_db);
dbs.push_back(function_msg_db);
dbs_.push_back(function_msg_db);
wstring function_msg_name = wstring((wchar_t *)(*(
DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET)));
dbmap[function_msg_name] = function_msg_db;
dbmap_[function_msg_name] = function_msg_db;
if (bizchat_msg_db_addr) {
// functionMsg.db maybe null
@ -204,10 +309,10 @@ std::vector<void *> GetDbHandles() {
ExecuteSQL(bizchat_msg_db_addr,
"select * from sqlite_master where type=\"table\";",
(DWORD)GetDbInfo, &bizchat_msg_db);
dbs.push_back(bizchat_msg_db);
dbs_.push_back(bizchat_msg_db);
wstring bizchat_msg_name = wstring((wchar_t *)(*(
DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET)));
dbmap[bizchat_msg_name] = bizchat_msg_db;
dbmap_[bizchat_msg_name] = bizchat_msg_db;
}
// Storage
DWORD storage_start = *(DWORD *)(p_contact_addr + STORAGE_START_OFFSET);
@ -263,33 +368,33 @@ std::vector<void *> GetDbHandles() {
// storage_start = storage_start + 0x4;
// } while (storage_start != storage_end);
DWORD multi_db_mgr_addr = base + MULTI_DB_MSG_MGR_OFFSET;
DWORD public_msg_mgr_addr = base + PUBLIC_MSG_MGR_OFFSET;
DWORD favorite_storage_mgr_addr = base + FAVORITE_STORAGE_MGR_OFFSET;
DWORD fts_favorite_mgr_addr = base + FTS_FAVORITE_MGR_OFFSET;
DWORD multi_db_mgr_addr = base_addr_ + MULTI_DB_MSG_MGR_OFFSET;
DWORD public_msg_mgr_addr = base_addr_ + PUBLIC_MSG_MGR_OFFSET;
DWORD favorite_storage_mgr_addr = base_addr_ + FAVORITE_STORAGE_MGR_OFFSET;
DWORD fts_favorite_mgr_addr = base_addr_ + FTS_FAVORITE_MGR_OFFSET;
// MsgX.db
DWORD wrap_ptr = *(DWORD *)(multi_db_mgr_addr);
DWORD db_num = *(DWORD *)(wrap_ptr+0x30);
DWORD current_db_num = *(DWORD *)(wrap_ptr+0x38);
DWORD db_num = *(DWORD *)(wrap_ptr + 0x30);
DWORD current_db_num = *(DWORD *)(wrap_ptr + 0x38);
DWORD begin_ptr = *(DWORD *)(wrap_ptr + 0x2c);
for (unsigned int i = 0; i < current_db_num; i++) {
DWORD next_addr = begin_ptr + i * 0x4;
DWORD db_addr = *(DWORD *) next_addr;
DWORD db_addr = *(DWORD *)next_addr;
if (db_addr) {
DWORD msg0_db_addr = *(DWORD *)(db_addr + 0x60);
DatabaseInfo msg0_db{0};
msg0_db.db_name = (wchar_t *)(*(DWORD *)(db_addr));
msg0_db.db_name_len = *(DWORD *)(db_addr + 0x4);
msg0_db.handle = msg0_db_addr;
msg0_db.extrainfo = *(DWORD *) (*(DWORD *)(db_addr + 0x18) +0x144);
ExecuteSQL(
msg0_db_addr, "select * from sqlite_master where type=\"table\";",
msg0_db.extrainfo = *(DWORD *)(*(DWORD *)(db_addr + 0x18) + 0x144);
ExecuteSQL(msg0_db_addr,
"select * from sqlite_master where type=\"table\";",
(DWORD)GetDbInfo, &msg0_db);
dbs.push_back(msg0_db);
dbs_.push_back(msg0_db);
wstring msg_db_name = wstring((wchar_t *)(*(DWORD *)(db_addr)));
dbmap[msg_db_name] = msg0_db;
dbmap_[msg_db_name] = msg0_db;
// BufInfoStorage
DWORD buf_info_addr = *(DWORD *)(db_addr + 0x14);
@ -302,137 +407,134 @@ std::vector<void *> GetDbHandles() {
ExecuteSQL(buf_info_handle,
"select * from sqlite_master where type=\"table\";",
(DWORD)GetDbInfo, &media_msg0_db);
dbs.push_back(media_msg0_db);
wstring media_msg_db_name = wstring((wchar_t *)(*(DWORD *)(buf_info_addr + 0x4C)));
dbmap[media_msg_db_name] = media_msg0_db;
dbs_.push_back(media_msg0_db);
wstring media_msg_db_name =
wstring((wchar_t *)(*(DWORD *)(buf_info_addr + 0x4C)));
dbmap_[media_msg_db_name] = media_msg0_db;
}
}
// publicMsg.db
DWORD public_msg_ptr = *(DWORD *) (*(DWORD *)(public_msg_mgr_addr) + 0x8);
DWORD public_msg_ptr = *(DWORD *)(*(DWORD *)(public_msg_mgr_addr) + 0x8);
if (public_msg_ptr) {
DWORD public_msg_db_addr = *(DWORD *)(public_msg_ptr + 0x38);
DatabaseInfo public_msg_db{0};
public_msg_db.db_name = (wchar_t *)(*(DWORD *)(public_msg_ptr + 0x4C));
public_msg_db.db_name_len =*(DWORD *)(public_msg_ptr + 0x50);
public_msg_db.db_name_len = *(DWORD *)(public_msg_ptr + 0x50);
public_msg_db.handle = public_msg_db_addr;
ExecuteSQL(public_msg_db_addr,
"select * from sqlite_master where type=\"table\";",
(DWORD)GetDbInfo, &public_msg_db);
dbs.push_back(public_msg_db);
wstring public_msg_db_name =wstring((wchar_t *)(*(DWORD *)(public_msg_ptr + 0x4C)));
dbmap[public_msg_db_name] = public_msg_db;
dbs_.push_back(public_msg_db);
wstring public_msg_db_name =
wstring((wchar_t *)(*(DWORD *)(public_msg_ptr + 0x4C)));
dbmap_[public_msg_db_name] = public_msg_db;
}
// Favorite.db
DWORD favItems_ptr = *(DWORD *)(*(DWORD *)(*(DWORD *)(favorite_storage_mgr_addr) + 0x8) + 0x4);
DWORD favItems_ptr =
*(DWORD *)(*(DWORD *)(*(DWORD *)(favorite_storage_mgr_addr) + 0x8) + 0x4);
if (favItems_ptr) {
DWORD favorite_db_addr = *(DWORD *)(favItems_ptr + 0x38);
DatabaseInfo favorite_db{0};
favorite_db.db_name =(wchar_t *)(*(DWORD *)(favItems_ptr + 0x4C));
favorite_db.db_name = (wchar_t *)(*(DWORD *)(favItems_ptr + 0x4C));
favorite_db.db_name_len = *(DWORD *)(favItems_ptr + 0x50);
favorite_db.handle = favorite_db_addr;
ExecuteSQL(favorite_db_addr,
"select * from sqlite_master where type=\"table\";",
(DWORD)GetDbInfo, &favorite_db);
dbs.push_back(favorite_db);
wstring public_msg_db_name =wstring((wchar_t *)(*(DWORD *)(favItems_ptr + 0x4C)));
dbmap[public_msg_db_name] = favorite_db;
dbs_.push_back(favorite_db);
wstring public_msg_db_name =
wstring((wchar_t *)(*(DWORD *)(favItems_ptr + 0x4C)));
dbmap_[public_msg_db_name] = favorite_db;
}
DatabaseInfo db_end = {0};
dbs.push_back(db_end);
dbs_.push_back(db_end);
#ifdef _DEBUG
for (unsigned int i = 0; i < dbs.size() - 1; i++) {
printf("dbname = %ws,handle = 0x%08X,table_count:%d\n", dbs[i].db_name,
dbs[i].handle, dbs[i].tables.size());
for (unsigned int j = 0; j < dbs[i].tables.size(); j++) {
cout << "name = " << dbs[i].tables[j].name << endl;
cout << "tbl_name = " << dbs[i].tables[j].table_name << endl;
cout << "rootpage = " << dbs[i].tables[j].rootpage << endl;
cout << "sql = " << dbs[i].tables[j].sql << endl;
cout << endl;
}
cout << endl;
for (unsigned int i = 0; i < dbs_.size() - 1; i++) {
LOG(INFO) << "dbname =" << dbs_[i].db_name;
LOG(INFO) << "handle =" << dbs_[i].handle;
LOG(INFO) << "table_count =" << dbs_[i].tables.size();
}
#endif
vector<void *> ret_array;
for (unsigned int i = 0; i < dbs.size() - 1; i++)
ret_array.push_back(&dbs[i]);
for (unsigned int i = 0; i < dbs_.size() - 1; i++)
ret_array.push_back(&dbs_[i]);
return ret_array;
}
DWORD GetDbHandleByDbName(wchar_t *dbname) {
if (dbmap.size() == 0) {
DWORD DB::GetDbHandleByDbName(wchar_t *dbname) {
if (dbmap_.size() == 0) {
GetDbHandles();
}
if (dbmap.find(dbname) != dbmap.end()) {
return dbmap[dbname].handle;
if (dbmap_.find(dbname) != dbmap_.end()) {
return dbmap_[dbname].handle;
}
return 0;
}
unsigned int GetLocalIdByMsgId(ULONG64 msgid, int &dbIndex) {
unsigned int DB::GetLocalIdByMsgId(ULONG64 msgid, int &dbIndex) {
char sql[260] = {0};
sprintf_s(sql, "select localId from MSG where MsgSvrID=%llu;", msgid);
wchar_t dbname[20] = {0};
for (int i = 0;; i++) {
swprintf_s(dbname, L"MSG%d.db", i);
DWORD handle = GetDbHandleByDbName(dbname);
#ifdef _DEBUG
cout <<" handle =" <<handle<<endl;
#endif
if (handle == 0) return 0;
if (handle == 0) {
LOG(INFO) << "MSG db handle is null";
return 0;
}
vector<vector<string>> result;
int ret = Select(handle, (const char *)sql, result);
#ifdef _DEBUG
cout <<" size =" <<result.size()<<endl;
#endif
if (result.size() == 0) continue;
dbIndex = dbmap[dbname].extrainfo;
dbIndex = dbmap_[dbname].extrainfo;
return stoi(result[1][0]);
}
return 0;
}
vector<string> GetChatMsgByMsgId(ULONG64 msgid){
vector<string> DB::GetChatMsgByMsgId(ULONG64 msgid) {
char sql[260] = {0};
sprintf_s(sql, "select localId,TalkerId,MsgSvrID,Type,SubType,IsSender,CreateTime,Sequence,StatusEx,FlagEx,Status,MsgServerSeq,MsgSequence,StrTalker,StrContent,BytesExtra from MSG where MsgSvrID=%llu;", msgid);
sprintf_s(sql,
"select "
"localId,TalkerId,MsgSvrID,Type,SubType,IsSender,CreateTime,"
"Sequence,StatusEx,FlagEx,Status,MsgServerSeq,MsgSequence,"
"StrTalker,StrContent,BytesExtra from MSG where MsgSvrID=%llu;",
msgid);
wchar_t dbname[20] = {0};
for (int i = 0;; i++) {
swprintf_s(dbname, L"MSG%d.db", i);
DWORD handle = GetDbHandleByDbName(dbname);
if (handle == 0) return {};
if (handle == 0) {
LOG(INFO) << "MSG db handle is null";
return {};
}
vector<vector<string>> result;
int ret = Select(handle, (const char *)sql, result);
#ifdef _DEBUG
cout <<" size =" <<result.size()<<endl;
#endif
if (result.size() == 0) continue;
return result[1];
}
return {};
}
std::string GetVoiceBuffByMsgId(ULONG64 msgid) {
std::string DB::GetVoiceBuffByMsgId(ULONG64 msgid) {
char sql[260] = {0};
sprintf_s(sql, "SELECT Buf from Media WHERE Reserved0=%llu;", msgid);
wchar_t dbname[20] = {0};
for (int i = 0;; i++) {
swprintf_s(dbname, L"MediaMSG%d.db", i);
DWORD handle = GetDbHandleByDbName(dbname);
#ifdef _DEBUG
cout <<" handle =" <<handle<<endl;
#endif
if (handle == 0) return "";
if (handle == 0) {
LOG(INFO) << "Media db handle is null";
return "";
}
vector<vector<string>> result;
int ret = Select(handle, (const char *)sql, result);
#ifdef _DEBUG
cout <<" size =" <<result.size()<<endl;
#endif
if (result.size() == 0) continue;
return result[1][0];
}
return "";
}
} // namespace wxhelper

38
src/db.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef WXHELPER_DB_H_
#define WXHELPER_DB_H_
#include <string>
#include <vector>
#include "base_mgr.h"
#include "wechat_function.h"
#include "windows.h"
#include "singleton.h"
namespace wxhelper {
class DB :public Singleton<DB>{
public:
void init(DWORD base);
int ExecuteSQL(DWORD db, const char *sql, DWORD callback, void *data);
int Select(DWORD db_hanle, const char *sql,
std::vector<std::vector<std::string>> &query_result);
std::vector<void *> GetDbHandles();
DWORD GetDbHandleByDbName(wchar_t *dbname);
unsigned int GetLocalIdByMsgId(ULONG64 msgid, int &dbIndex);
std::vector<std::string> GetChatMsgByMsgId(ULONG64 msgid);
std::string GetVoiceBuffByMsgId(ULONG64 msgid);
private:
int SelectDataInner(DWORD db, const char *sql,
std::vector<std::vector<SqlResult>> &data);
private:
std::map<std::wstring, DatabaseInfo> dbmap_;
std::vector<DatabaseInfo> dbs_;
DWORD base_addr_;
};
} // namespace wxhelper
#endif

View File

@ -1,160 +0,0 @@
#include "pch.h"
#include "db_operation.h"
#include "base64.h"
#include "common.h"
#include "new_sqlite3.h"
using namespace std;
/// @brief free data
void FreeResult(vector<vector<SqlResult>> &data) {
if (data.size() == 0) {
return;
}
for (unsigned int i = 0; i < data.size(); i++) {
for (unsigned j = 0; j < data[i].size(); j++) {
SqlResult *sr = (SqlResult *)&data[i][j];
if (sr->column_name) {
delete[] sr->column_name;
sr->column_name = NULL;
}
if (sr->content) {
delete[] sr->content;
sr->content = NULL;
}
}
data[i].clear();
}
data.clear();
}
int SelectDataInner(DWORD db, const char *sql,
vector<vector<SqlResult>> &data) {
DWORD wxBaseAddress = GetWeChatWinBase();
Sqlite3_prepare p_Sqlite3_prepare =
(Sqlite3_prepare)(wxBaseAddress + SQLITE3_PREPARE_OFFSET);
Sqlite3_step p_Sqlite3_step =
(Sqlite3_step)(wxBaseAddress + SQLITE3_STEP_OFFSET);
Sqlite3_column_count p_Sqlite3_column_count =
(Sqlite3_column_count)(wxBaseAddress + SQLITE3_COLUMN_COUNT_OFFSET);
Sqlite3_column_name p_Sqlite3_column_name =
(Sqlite3_column_name)(wxBaseAddress + SQLITE3_COLUMN_NAME_OFFSET);
Sqlite3_column_type p_Sqlite3_column_type =
(Sqlite3_column_type)(wxBaseAddress + SQLITE3_COLUMN_TYPE_OFFSET);
Sqlite3_column_blob p_Sqlite3_column_blob =
(Sqlite3_column_blob)(wxBaseAddress + SQLITE3_COLUMN_BLOB_OFFSET);
Sqlite3_column_bytes p_Sqlite3_column_bytes =
(Sqlite3_column_bytes)(wxBaseAddress + SQLITE3_COLUMN_BYTES_OFFSET);
Sqlite3_finalize p_Sqlite3_finalize =
(Sqlite3_finalize)(wxBaseAddress + SQLITE3_FINALIZE_OFFSET);
DWORD *stmt;
int rc = p_Sqlite3_prepare(db, sql, -1, &stmt, 0);
if (rc != SQLITE_OK) return NULL;
while (p_Sqlite3_step(stmt) == SQLITE_ROW) {
int col_count = p_Sqlite3_column_count(stmt);
vector<SqlResult> tempStruct;
for (int i = 0; i < col_count; i++) {
SqlResult temp = {0};
const char *ColName = p_Sqlite3_column_name(stmt, i);
int nType = p_Sqlite3_column_type(stmt, i);
const void *pReadBlobData = p_Sqlite3_column_blob(stmt, i);
int nLength = p_Sqlite3_column_bytes(stmt, i);
temp.column_name = new char[strlen(ColName) + 1];
memcpy(temp.column_name, ColName, strlen(ColName) + 1);
temp.column_name_len = strlen(ColName);
temp.content_len = nLength;
switch (nType) {
case SQLITE_BLOB: {
temp.content = new char[nLength];
memcpy(temp.content, pReadBlobData, nLength);
temp.is_blob = true;
break;
}
default: {
if (nLength != 0) {
temp.content = new char[nLength + 1];
memcpy(temp.content, pReadBlobData, nLength + 1);
} else {
temp.content = new char[2];
ZeroMemory(temp.content, 2);
}
temp.is_blob = false;
break;
}
}
tempStruct.push_back(temp);
}
data.push_back(tempStruct);
}
p_Sqlite3_finalize(stmt);
return 1;
}
int Select(DWORD db_hanle, const char *sql,
vector<vector<string>> &query_result) {
vector<vector<SqlResult>> data;
int status = SelectDataInner(db_hanle, sql, data);
if (status == 0) {
return 0;
}
if(data.size() == 0){
return 1;
}
vector<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) {
vector<string> item;
for (size_t i = 0; i < it.size(); i++) {
if (!it[i].is_blob) {
string content(it[i].content);
item.push_back(content);
} else {
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;
}
int SelectDbInfo(void *data, int argc, char **argv, char **name) {
vector<SqlResult> result;
for (int i = 0; i < argc; i++) {
SqlResult temp = {0};
temp.column_name = new char[strlen(name[i]) + 1];
memcpy(temp.column_name, name[i], strlen(name[i]) + 1);
temp.column_name_len = strlen(name[i]);
if (argv[i]) {
temp.content = new char[strlen(argv[i]) + 1];
memcpy(temp.content, argv[i], strlen(argv[i]) + 1);
temp.content_len = strlen(argv[i]);
} else {
temp.content = new char[2];
ZeroMemory(temp.content, 2);
temp.content_len = 0;
}
result.push_back(temp);
}
return 1;
}
/// @brief sqlite3_exec
/// @param db
/// @param sql
/// @param callback
/// @param data
/// @return
int ExecuteSQL(DWORD db, const char *sql, DWORD callback, void *data) {
DWORD base = GetWeChatWinBase();
DWORD sqlite3_exec_addr = base + SQLITE3_EXEC_OFFSET;
Sqlite3_exec fn_sqlite3_exec = (Sqlite3_exec)sqlite3_exec_addr;
int status = fn_sqlite3_exec(db, sql, (Sqlite3_callback)callback, data, 0);
return status;
}

View File

@ -1,22 +0,0 @@
#ifndef DB_OPERATION_H_
#define DB_OPERATION_H_
#include <windows.h>
#include <vector>
struct SqlResult {
char *column_name;
DWORD column_name_len;
char *content;
DWORD content_len;
BOOL is_blob;
};
/// @brief exec sql
/// @param db opened db
/// @param sql sql
/// @param callback callback func
/// @param data data
/// @return
int ExecuteSQL(DWORD db, const char *sql, DWORD callback, void *data);
int Select(DWORD db_hanle, const char *sql,std::vector<std::vector<std::string>> &query_result);
#endif

View File

@ -1,14 +1,20 @@
#include "pch.h"
#include "api.h"
#include "common.h"
#include "wxhelper.h"
#include "pch.h"
#include "hide_module.h"
#include "global_context.h"
using namespace wxhelper;
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call,
LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH: {
// http_start(19088);
wxhelper::WXHelper::GetInstance().http_start(19088);
DisableThreadLibraryCalls(hModule);
GlobalContext::GetInstance().initialize(hModule);
break;
}
case DLL_THREAD_ATTACH: {
@ -18,9 +24,7 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call,
break;
}
case DLL_PROCESS_DETACH: {
CloseConsole();
// http_close();
wxhelper::WXHelper::GetInstance().http_close();
GlobalContext::GetInstance().finally();
break;
}
}

View File

@ -1,213 +0,0 @@
#include "pch.h"
#include "download.h"
#include "common.h"
#include "get_db_handle.h"
#include "wechat_data.h"
#include "base64.h"
#define WX_NEW_CHAT_MSG_OFFSET 0x76f010
#define WX_GET_PRE_DOWNLOAD_MGR_OFFSET 0x80f110
#define WX_PUSH_ATTACH_TASK_OFFSET 0x82bb40
#define WX_FREE_CHAT_MSG_INSTANCE_COUNTER_OFFSET 0x756e30
#define WX_FREE_CHAT_MSG_OFFSET 0x756960
#define WX_CHAT_MGR_OFFSET 0x792700
#define WX_GET_MGR_BY_PREFIX_LOCAL_ID_OFFSET 0xbc0370
#define WX_GET_CURRENT_DATA_PATH_OFFSET 0xc872c0
#define WX_APP_MSG_INFO_OFFSET 0x7b3d20
#define WX_GET_APP_MSG_XML_OFFSET 0xe628a0
#define WX_FREE_APP_MSG_INFO_OFFSET 0x79d900
#define WX_PUSH_THUMB_TASK_OFFSET 0x82ba40
#define WX_VIDEO_MGR_OFFSET 0x829820
#define WX_DOWNLOAD_VIDEO_IMG_OFFSET 0xd46c30
using namespace std;
int DoDownloadTask(ULONG64 msg_id) {
int success = -1;
int db_index = 0;
int local_id = GetLocalIdByMsgId(msg_id, db_index);
if (local_id < 1) {
return -2;
}
char chat_msg[0x2D8] = {0};
DWORD base = GetWeChatWinBase();
DWORD new_chat_msg_addr = base + WX_NEW_CHAT_MSG_OFFSET;
DWORD get_chat_mgr_addr = base + WX_CHAT_MGR_OFFSET;
DWORD pre_download_mgr_addr = base + WX_GET_PRE_DOWNLOAD_MGR_OFFSET;
DWORD push_attach_task_addr = base + WX_PUSH_ATTACH_TASK_OFFSET;
DWORD free_addr = base + WX_FREE_CHAT_MSG_INSTANCE_COUNTER_OFFSET;
DWORD get_by_local_Id_addr = base + WX_GET_MGR_BY_PREFIX_LOCAL_ID_OFFSET;
DWORD get_current_data_path_addr = base + WX_GET_CURRENT_DATA_PATH_OFFSET;
DWORD free_app_msg_info_addr = base + WX_FREE_APP_MSG_INFO_OFFSET;
DWORD push_thumb_task_addr = base + WX_PUSH_THUMB_TASK_OFFSET;
DWORD video_mgr_addr = base + WX_VIDEO_MGR_OFFSET;
DWORD download_video_image_addr = base + WX_VIDEO_MGR_OFFSET;
WeChatString current_data_path;
__asm {
PUSHAD
PUSHFD
LEA ECX,current_data_path
CALL get_current_data_path_addr
LEA ECX,chat_msg
CALL new_chat_msg_addr
CALL get_chat_mgr_addr
PUSH dword ptr [db_index]
LEA ECX,chat_msg
PUSH dword ptr [local_id]
CALL get_by_local_Id_addr
ADD ESP,0x8
POPFD
POPAD
}
wstring save_path = L"";
wstring thumb_path = L"";
if (current_data_path.length > 0) {
save_path += current_data_path.ptr;
save_path += L"wxhelper";
} else {
return -1;
}
if (!FindOrCreateDirectoryW(save_path.c_str())) {
return -3;
}
DWORD type = *(DWORD *)(chat_msg + 0x38);
wchar_t *content = *(wchar_t **)(chat_msg + 0x70);
switch (type) {
case 0x3: {
save_path += L"\\image";
if (!FindOrCreateDirectoryW(save_path.c_str())) {
return -3;
}
save_path = save_path +L"\\"+ to_wstring(msg_id) + L".png";
break;
}
case 0x3E:
case 0x2B: {
save_path += L"\\video";
if (!FindOrCreateDirectoryW(save_path.c_str())) {
return -3;
}
thumb_path = save_path + L"\\"+ to_wstring(msg_id) + L".jpg";
save_path = save_path + L"\\"+ to_wstring(msg_id) + L".mp4";
break;
}
case 0x31: {
save_path += L"\\file";
wcout << save_path << endl;
if (!FindOrCreateDirectoryW(save_path.c_str())) {
return -3;
}
char xml_app_msg[0xC80] = {0};
DWORD new_app_msg_addr = base + WX_APP_MSG_INFO_OFFSET;
DWORD get_xml_addr = base + WX_GET_APP_MSG_XML_OFFSET;
WeChatString w_content(content);
__asm {
PUSHAD
PUSHFD
LEA ECX,xml_app_msg
CALL new_app_msg_addr
PUSH 0x1
LEA EAX,w_content
PUSH EAX
LEA ECX,xml_app_msg
CALL get_xml_addr
MOV success,EAX
LEA ECX,xml_app_msg
CALL free_app_msg_info_addr
POPFD
POPAD
}
if (success != 1) {
return -4;
}
WeChatString *file_name = (WeChatString *)((DWORD)xml_app_msg + 0x44);
save_path = save_path +L"\\" + to_wstring(msg_id) + L"_" +
wstring(file_name->ptr, file_name->length);
break;
}
default:
break;
}
WeChatString w_save_path(save_path);
WeChatString w_thumb_path(thumb_path);
int temp =1;
memcpy(&chat_msg[0x19C], &w_thumb_path, sizeof(w_thumb_path));
memcpy(&chat_msg[0x1B0], &w_save_path, sizeof(w_save_path));
memcpy(&chat_msg[0x29C], &temp, sizeof(temp));
// note the image has been downloaded and will not be downloaded again
// use low-level method
// this function does not work, need to modify chatmsg.
// if (type == 0x3E || type == 0x2B){
// __asm{
// PUSHAD
// PUSHFD
// CALL video_mgr_addr
// LEA ECX,chat_msg
// PUSH ECX
// MOV ECX,EAX
// CALL download_video_image_addr
// POPFD
// POPAD
// }
// }
__asm {
PUSHAD
PUSHFD
CALL pre_download_mgr_addr
PUSH 0x1
PUSH 0x0
LEA ECX,chat_msg
PUSH ECX
MOV ECX,EAX
CALL push_attach_task_addr
MOV success,EAX
LEA ECX,chat_msg
PUSH 0x0
CALL free_addr
POPFD
POPAD
}
return success;
}
int GetVoice(ULONG64 msg_id, wchar_t *dir) {
int success = -1;
string buff = GetVoiceBuffByMsgId(msg_id);
if (buff.size() == 0) {
success = 0;
return success;
}
wstring save_path = wstring(dir);
if (!FindOrCreateDirectoryW(save_path.c_str())) {
success = -2;
return success;
}
save_path = save_path + L"\\" + to_wstring(msg_id) + L".amr";
HANDLE file_handle = CreateFileW(save_path.c_str(), GENERIC_ALL, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (file_handle == INVALID_HANDLE_VALUE) {
#ifdef _DEBUG
wcout <<" save_path =" <<save_path<<endl;
#endif
return success;
}
DWORD bytes_write = 0;
string decode = base64_decode(buff);
WriteFile(file_handle, (LPCVOID)decode.c_str(), decode.size(), &bytes_write, 0);
CloseHandle(file_handle);
success = 1;
return success;
}

View File

@ -1,7 +0,0 @@
#ifndef DOWNLOAD_H_
#define DOWNLOAD_H_
int DoDownloadTask(ULONG64 msg_id);
int GetVoice(ULONG64 msg_id,wchar_t * dir);
#endif

3120
src/easylogging++.cc Normal file

File diff suppressed because it is too large Load Diff

4576
src/easylogging++.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,42 +0,0 @@
#include "pch.h"
#include "forward.h"
#include "common.h"
#include "get_db_handle.h"
#include "wechat_data.h"
#define WX_FORWARD_MSG_OFFSET 0xce6730
#define WX_INIT_CHAT_MSG_OFFSET 0xf59e40
int ForwardMsg(wchar_t *wxid, unsigned long long msgid) {
int success = 0;
int db_index = 0;
int localid = GetLocalIdByMsgId(msgid, db_index);
if (localid == 0) return 0;
WeChatString to_user(wxid);
DWORD base = GetWeChatWinBase();
DWORD forward_msg_addr = base + WX_FORWARD_MSG_OFFSET;
DWORD init_chat_msg_addr = base + WX_INIT_CHAT_MSG_OFFSET;
__asm {
PUSHAD
PUSHFD
MOV EDX, DWORD PTR [db_index]
PUSH EDX
MOV EAX, DWORD PTR [localid]
PUSH EAX
SUB ESP,0x14
MOV ECX,ESP
LEA ESI,to_user
PUSH ESI
CALL init_chat_msg_addr
XOR ECX,ECX
CALL forward_msg_addr
MOVZX EAX,AL
MOV success,EAX
ADD ESP,0x1c
POPFD
POPAD
}
return success;
}

View File

@ -1,5 +0,0 @@
#ifndef FORWARD_H_
#define FORWARD_H_
int ForwardMsg(wchar_t *wxid, unsigned long long msgid);
#endif

View File

@ -1,13 +0,0 @@
#ifndef GET_DB_HANDLE_H_
#define GET_DB_HANDLE_H_
#include "windows.h"
#include <vector>
#include <string>
std::vector<void *> GetDbHandles();
DWORD GetDbHandleByDbName(wchar_t *dbname);
unsigned int GetLocalIdByMsgId(ULONG64 msgid, int &dbIndex);
std::vector<std::string> GetChatMsgByMsgId(ULONG64 msgid);
std::string GetVoiceBuffByMsgId(ULONG64 msgid);
#endif

38
src/global_context.cc Normal file
View File

@ -0,0 +1,38 @@
#include "pch.h"
#include "global_context.h"
#include "http_server.h"
#include "easylogging++.h"
#include "hooks.h"
namespace wxhelper {
void GlobalContext::initialize(HMODULE module) {
module_ = module;
DWORD base = Utils::GetWeChatWinBase();
config.emplace();
log.emplace();
log->initialize();
hide_module.emplace();
#ifndef _DEBUG
hide_module->Hide(module_);
#endif
HttpServer::GetInstance().Init(19088);
HttpServer::GetInstance().HttpStart();
DB::GetInstance().init(base);
contact_mgr.emplace(ContactMgr{base});
misc_mgr.emplace(MiscMgr{base});
send_mgr.emplace(SendMessageMgr{base});
account_mgr.emplace(AccountMgr{base});
chat_room_mgr.emplace(ChatRoomMgr{base});
sns_mgr.emplace(SNSMgr{base});
}
void GlobalContext::finally() {
HttpServer::GetInstance().HttpClose();
hooks::UnHookLog();
hooks::UnHookRecvMsg();
hooks::UnHookSearchContact();
}
} // namespace wxhelper

43
src/global_context.h Normal file
View File

@ -0,0 +1,43 @@
#ifndef GLOBAL_CONTEXT_H_
#define GLOBAL_CONTEXT_H_
#include "account_mgr.h"
#include "config.h"
#include "contact_mgr.h"
#include "db.h"
#include "hide_module.h"
#include "http_server.h"
#include "log.h"
#include "misc_mgr.h"
#include "send_message_mgr.h"
#include "chat_room_mgr.h"
#include "sns_mgr.h"
#include "singleton.h"
namespace wxhelper {
enum class GlobalContextState { NOT_INITIALIZED, INITIALIZING, INITIALIZED };
class GlobalContext :public Singleton<GlobalContext>{
public:
void initialize(HMODULE module);
void finally();
public:
std::optional<Config> config;
std::optional<HideModule> hide_module;
std::optional<Log> log;
std::optional<ContactMgr> contact_mgr;
std::optional<MiscMgr> misc_mgr;
std::optional<SendMessageMgr> send_mgr;
std::optional<AccountMgr> account_mgr;
std::optional<ChatRoomMgr> chat_room_mgr;
std::optional<SNSMgr> sns_mgr;
GlobalContextState state = GlobalContextState::INITIALIZED;
private:
HMODULE module_;
};
} // namespace wxhelper
#endif

10
src/handler.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef WXHELPER_HANDLER_H_
#define WXHELPER_HANDLER_H_
#include <mongoose.h>
namespace wxhelper {
class Handler {
public:
virtual void HandlerRequest(struct mg_connection *c, void *ev_data) = 0;
};
} // namespace wxhelper
#endif

64
src/hide_module.cc Normal file
View File

@ -0,0 +1,64 @@
#include "pch.h"
#include "hide_module.h"
namespace wxhelper {
void HideModule::Hide(const char* module_name) {
HMODULE hMod = ::GetModuleHandleA(module_name);
PLIST_ENTRY Head, Cur;
PPEB_LDR_DATA ldr;
PLDR_MODULE ldm;
__asm {
mov eax, fs: [0x30]
mov ecx, [eax + 0x0c]
mov ldr, ecx
}
Head = &(ldr->InLoadOrderModuleList);
Cur = Head->Flink;
do {
ldm = CONTAINING_RECORD(Cur, LDR_MODULE, InLoadOrderModuleList);
if (hMod == ldm->BaseAddress) {
ldm->InLoadOrderModuleList.Blink->Flink =
ldm->InLoadOrderModuleList.Flink;
ldm->InLoadOrderModuleList.Flink->Blink =
ldm->InLoadOrderModuleList.Blink;
ldm->InInitializationOrderModuleList.Blink->Flink =
ldm->InInitializationOrderModuleList.Flink;
ldm->InInitializationOrderModuleList.Flink->Blink =
ldm->InInitializationOrderModuleList.Blink;
ldm->InMemoryOrderModuleList.Blink->Flink =
ldm->InMemoryOrderModuleList.Flink;
ldm->InMemoryOrderModuleList.Flink->Blink =
ldm->InMemoryOrderModuleList.Blink;
break;
}
Cur = Cur->Flink;
} while (Head != Cur);
}
void HideModule::Hide(HMODULE module) {
void* peb_ptr = nullptr;
_asm {
PUSH EAX
MOV EAX, FS:[0x30]
MOV peb_ptr, EAX
POP EAX
}
void* ldr_ptr = *((void**)((unsigned char*)peb_ptr + 0xc));
void* cur_ptr = *((void**)((unsigned char*)ldr_ptr + 0x0c));
void* next_ptr = cur_ptr;
do {
void* next = *((void**)((unsigned char*)next_ptr));
void* last = *((void**)((unsigned char*)next_ptr + 0x4));
void* base_addr = *((void**)((unsigned char*)next_ptr + 0x18));
if (base_addr == module) {
*((void**)((unsigned char*)last)) = next;
*((void**)((unsigned char*)next + 0x4)) = last;
cur_ptr = next;
}
next_ptr = *((void**)next_ptr);
} while (cur_ptr != next_ptr);
}
} // namespace wxhelper

48
src/hide_module.h Normal file
View File

@ -0,0 +1,48 @@
#ifndef WXHELEPER_HIDE_MODULE_H_
#define WXHELEPER_HIDE_MODULE_H_
#include <Windows.h>
namespace wxhelper {
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
typedef struct _PEB_LDR_DATA {
ULONG Length;
BOOLEAN Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
typedef struct _LDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
void* BaseAddress;
void* EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
SHORT LoadCount;
SHORT TlsIndex;
HANDLE SectionHandle;
ULONG CheckSum;
ULONG TimeDateStamp;
} LDR_MODULE, *PLDR_MODULE;
class HideModule {
private:
/* data */
public:
static void Hide(const char* module_name);
static void Hide(HMODULE module);
};
} // namespace wxhelper
#endif

View File

@ -1,231 +0,0 @@
#include "pch.h"
#include "hook_img.h"
#include "common.h"
using namespace std;
// #define WX_HOOK_IMG_OFFSET 0xd7eaa5
// #define WX_HOOK_IMG_NEXT_OFFSET 0xda56e0
#define WX_HOOK_IMG_OFFSET 0xd723dc
#define WX_HOOK_IMG_NEXT_OFFSET 0xe91d90
#define WX_SELF_ID_OFFSET 0x2E2CD3C
#define BUFSIZE 1024
#define JPEG0 0xFF
#define JPEG1 0xD8
#define JPEG2 0xFF
#define PNG0 0x89
#define PNG1 0x50
#define PNG2 0x4E
#define BMP0 0x42
#define BMP1 0x4D
#define GIF0 0x47
#define GIF1 0x49
#define GIF2 0x46
static wstring kImgStorePath = L"";
static int kImgHooked = FALSE;
static DWORD kWeChatWinBase = GetWeChatWinBase();
static char kOriginImgAsmCode[5] = {0};
static DWORD kHookImgNextAddress = kWeChatWinBase + WX_HOOK_IMG_NEXT_OFFSET;
static DWORD kHookImgJmpBackAddress = kWeChatWinBase + WX_HOOK_IMG_OFFSET + 0x5;
void OnHookImg(DWORD obj_addr) {
DWORD wxid_addr = GetWeChatWinBase() + WX_SELF_ID_OFFSET;
string wxid = string(*(char **)wxid_addr, *(DWORD *)(wxid_addr + 0x10));
wstring self_id = String2Wstring(wxid);
wstring save_path = kImgStorePath + self_id;
if (!FindOrCreateDirectoryW(save_path.c_str())) {
return;
}
wchar_t *origin_file_path = *(wchar_t **)obj_addr;
wstring img_path(origin_file_path);
if (img_path.find(L"_t.dat") != wstring::npos) {
return;
}
int pos_begin = img_path.find_last_of(L"\\") + 1;
int pos_end = img_path.find_last_of(L".");
wstring file_name = img_path.substr(pos_begin, pos_end - pos_begin);
char buffer[BUFSIZE] = {0};
DWORD bytes_read = 0;
DWORD bytes_write = 0;
unsigned char magic_head[4] = {0};
wchar_t suffix[5] = {0};
HANDLE h_origin_file =
CreateFileW(origin_file_path, GENERIC_READ, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (h_origin_file == INVALID_HANDLE_VALUE) {
return;
}
if (ReadFile(h_origin_file, buffer, BUFSIZE, &bytes_read, NULL)) {
memcpy(magic_head, buffer, 3);
}
if (magic_head[0] == PNG0 && magic_head[1] == PNG1 && magic_head[2] == PNG2) {
lstrcpyW(suffix, L".png");
} else if (magic_head[0] == GIF0 && magic_head[1] == GIF1 &&
magic_head[2] == GIF2) {
lstrcpyW(suffix, L".gif");
} else if (magic_head[0] == JPEG0 && magic_head[1] == JPEG1 &&
magic_head[2] == JPEG2) {
lstrcpyW(suffix, L".jpg");
} else {
lstrcpyW(suffix, L"");
}
wstring save_img_path = save_path + L"\\" + file_name + suffix;
HANDLE save_file = CreateFileW(save_img_path.c_str(), GENERIC_ALL, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (save_file == INVALID_HANDLE_VALUE) {
return;
}
if (!WriteFile(save_file, (LPCVOID)buffer, bytes_read, &bytes_write, 0)) {
CloseHandle(h_origin_file);
CloseHandle(save_file);
return;
}
do {
if (ReadFile(h_origin_file, buffer, BUFSIZE, &bytes_read, NULL)) {
if (!WriteFile(save_file, (LPCVOID)buffer, bytes_read, &bytes_write, 0)) {
CloseHandle(h_origin_file);
CloseHandle(save_file);
return;
}
}
} while (bytes_read == BUFSIZE);
CloseHandle(h_origin_file);
CloseHandle(save_file);
}
/// @brief hook img implement
_declspec(naked) void handle_img() {
__asm {
PUSHAD
PUSHFD
PUSH ECX
CALL OnHookImg
ADD ESP, 0x4
POPFD
POPAD
CALL kHookImgNextAddress
JMP kHookImgJmpBackAddress
}
}
/// @brief hook image
/// @param save_path image save dir
/// @return
int HookImg(wstring save_path) {
kWeChatWinBase = GetWeChatWinBase();
if (!kWeChatWinBase) {
return -1;
}
if (kImgHooked) {
return 2;
}
kImgStorePath = save_path;
if (kImgStorePath.back() != '\\') {
kImgStorePath += L"\\";
}
wstring createpath = kImgStorePath.substr(0, kImgStorePath.length() - 1);
if (!FindOrCreateDirectoryW(createpath.c_str())) {
return -2;
}
DWORD hook_img_addr = kWeChatWinBase + WX_HOOK_IMG_OFFSET;
kHookImgNextAddress = kWeChatWinBase + WX_HOOK_IMG_NEXT_OFFSET;
static DWORD kHookImgJmpBackAddress = hook_img_addr + 0x5;
HookAnyAddress(hook_img_addr, (LPVOID)handle_img, kOriginImgAsmCode);
kImgHooked = TRUE;
return 1;
}
int UnHookImg() {
if (!kImgHooked) return 1;
DWORD hook_img_addr = kWeChatWinBase + WX_HOOK_IMG_OFFSET;
UnHookAnyAddress(hook_img_addr, kOriginImgAsmCode);
kImgHooked = FALSE;
return 1;
}
int GetImgByName(wchar_t* file_path,wchar_t* save_dir) {
wstring save_path(save_dir);
wstring orign_file_path(file_path);
if (!FindOrCreateDirectoryW(save_path.c_str())) {
return 0;
}
int pos_begin = orign_file_path.find_last_of(L"\\") + 1;
int pos_end = orign_file_path.find_last_of(L".");
wstring file_name = orign_file_path.substr(pos_begin, pos_end - pos_begin);
HANDLE h_origin_file =
CreateFileW(file_path, GENERIC_READ, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
char buffer[BUFSIZE] = {0};
DWORD bytes_read = 0;
DWORD bytes_write = 0;
unsigned char magic_head[4] = {0};
wstring suffix;
short key = 0;
if (ReadFile(h_origin_file, buffer, BUFSIZE, &bytes_read, NULL)) {
memcpy(magic_head, buffer, 3);
} else {
CloseHandle(h_origin_file);
return 0;
}
if ((magic_head[0] ^ JPEG0) == (magic_head[1] ^ JPEG1)) {
key = magic_head[0] ^ JPEG0;
suffix = L".jpg";
} else if ((magic_head[0] ^ PNG1) == (magic_head[1] ^ PNG2)) {
key = magic_head[0] ^ PNG1;
suffix = L".png";
} else if ((magic_head[0] ^ GIF0) == (magic_head[1] ^ GIF1)) {
key = magic_head[0] ^ GIF0;
suffix = L".gif";
} else if ((magic_head[0] ^ BMP0) == (magic_head[1] ^ BMP1)) {
key = magic_head[0] ^ BMP0;
suffix = L".bmp";
} else {
key = -1;
suffix = L".dat";
}
wstring save_img_path = save_path + L"\\" + file_name + suffix;
HANDLE save_img = CreateFileW(save_img_path.c_str(), GENERIC_ALL, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (save_img == INVALID_HANDLE_VALUE) {
return 0;
}
if (key > 0) {
for (unsigned int i = 0; i < bytes_read; i++) {
buffer[i]^=key;
}
}
if (!WriteFile(save_img, (LPCVOID)buffer, bytes_read, &bytes_write, 0)) {
CloseHandle(h_origin_file);
CloseHandle(save_img);
return 0;
}
do {
if (ReadFile(h_origin_file, buffer, BUFSIZE, &bytes_read, NULL)) {
if (key > 0) {
for (unsigned int i = 0; i < bytes_read; i++) {
buffer[i] ^= key;
}
}
if (!WriteFile(save_img, (LPCVOID)buffer, bytes_read, &bytes_write, 0)) {
CloseHandle(h_origin_file);
CloseHandle(save_img);
return 0;
}
}
} while (bytes_read == BUFSIZE);
CloseHandle(h_origin_file);
CloseHandle(save_img);
return 1;
}

View File

@ -1,9 +0,0 @@
#ifndef HOOK_IMG_H_
#define HOOK_IMG_H_
#include "windows.h"
int HookImg(std::wstring save_path);
int UnHookImg();
int GetImgByName(wchar_t* file_path,wchar_t* save_dir);
#endif

View File

@ -1,78 +0,0 @@
#include "pch.h"
#include "hook_log.h"
#include "common.h"
using namespace std;
#define WX_HOOK_LOG_OFFSET 0xed1675
#define WX_HOOK_LOG_NEXT_OFFSET 0x2344832
static int kLogHooked = FALSE;
static DWORD kWeChatWinBase = GetWeChatWinBase();
static char kOriginLogAsmCode[5] = {0};
static DWORD kHookLogAddress = kWeChatWinBase + WX_HOOK_LOG_OFFSET;
static DWORD kHookLogNextAddress = kWeChatWinBase + WX_HOOK_LOG_NEXT_OFFSET;
static DWORD kHookLogJmpBackAddress = kWeChatWinBase + WX_HOOK_LOG_OFFSET + 0x5;
void log_print(DWORD addr) {
if (!addr) {
return;
}
DWORD dwId = 0;
char *msg = (char *)addr;
int size = MultiByteToWideChar(CP_UTF8, 0, msg, -1, 0, 0);
wchar_t *w_msg = new wchar_t[size + 1];
memset(w_msg, 0, (size + 1) * 2);
MultiByteToWideChar(CP_UTF8, 0, msg, -1, w_msg, size);
size = WideCharToMultiByte(CP_ACP, 0, w_msg, -1, 0, 0, 0, 0);
char *ansi_message = new char[size + 1];
memset(ansi_message, 0, size + 1);
WideCharToMultiByte(CP_ACP, 0, w_msg, -1, ansi_message, size, 0, 0);
delete[] w_msg;
w_msg = NULL;
cout << ansi_message;
delete[] ansi_message;
ansi_message = NULL;
}
_declspec(naked) void handle_log() {
__asm {
PUSHAD
PUSHFD
PUSH EAX
CALL log_print
ADD ESP, 0x4
POPFD
POPAD
CALL kHookLogNextAddress
JMP kHookLogJmpBackAddress
}
}
int HookLog() {
kWeChatWinBase = GetWeChatWinBase();
if (!kWeChatWinBase) {
return -1;
}
if (kLogHooked) {
return 2;
}
kHookLogAddress = kWeChatWinBase + WX_HOOK_LOG_OFFSET;
kHookLogNextAddress = kWeChatWinBase + WX_HOOK_LOG_NEXT_OFFSET;
kHookLogJmpBackAddress = kHookLogAddress + 0x5;
HookAnyAddress(kHookLogAddress, (LPVOID)handle_log, kOriginLogAsmCode);
kLogHooked = TRUE;
return 1;
}
int UnHookLog() {
if (!kLogHooked) {
return 1;
}
DWORD hook_img_addr = kWeChatWinBase + WX_HOOK_LOG_OFFSET;
UnHookAnyAddress(hook_img_addr, kOriginLogAsmCode);
kLogHooked = FALSE;
return 1;
}

View File

@ -1,8 +0,0 @@
#ifndef HOOK_LOG_H_
#define HOOK_LOG_H_
#include "windows.h"
int HookLog();
int UnHookLog();
#endif

View File

@ -1,301 +0,0 @@
#include "hook_recv_msg.h"
#include <Ws2tcpip.h>
#include <winsock2.h>
#include <nlohmann/json.hpp>
#include "common.h"
#include "pch.h"
using namespace nlohmann;
using namespace std;
#define WX_RECV_MSG_HOOK_OFFSET 0xd19a0b
#define WX_RECV_MSG_HOOK_NEXT_OFFSET 0x756960
#define WX_SNS_HOOK_OFFSET 0x14f9e15
#define WX_SNS_HOOK_NEXT_OFFSET 0x14fa0a0
// SyncMgr::addMsgListToDB
// #define WX_RECV_MSG_HOOK_OFFSET 0xB9C919
// #define WX_RECV_MSG_HOOK_NEXT_OFFSET 0x722FF0
#define CLIENT_IP "127.0.0.1"
static int kServerPort = 0;
static int kMessageHooked = FALSE;
static char kServerIp[16]= "127.0.0.1";
static DWORD kWeChatWinBase = GetWeChatWinBase();
static char kOriginReceMsgAsmCode[5] = {0};
static DWORD kReceMsgJmpBackAddress =
kWeChatWinBase + WX_RECV_MSG_HOOK_OFFSET + 0x5;
static DWORD kReceMsgNextAddress =
kWeChatWinBase + WX_RECV_MSG_HOOK_NEXT_OFFSET;
static char kOriginSnsMsgAsmCode[5] = {0};
static DWORD kSnsMsgJmpBackAddress =
kWeChatWinBase + WX_SNS_HOOK_OFFSET + 0x5;
static DWORD kSnsMsgNextAddress =
kWeChatWinBase + WX_SNS_HOOK_NEXT_OFFSET;
struct InnerMessageStruct {
char *buffer;
int length;
~InnerMessageStruct() {
if (this->buffer != NULL) {
delete[] this->buffer;
this->buffer = NULL;
}
}
};
/// @brief send message by socket
/// @param buffer content
/// @param len len
/// @return true/false
BOOL SendBySocket(const char *buffer, size_t len) {
if (kServerPort == 0) {
return false;
}
SOCKET client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (client_socket < 0) {
#ifdef _DEBUG
cout << "create socket error,"
<< " errno:" << errno << endl;
#endif
return false;
}
BOOL status = false;
sockaddr_in client_addr;
memset(&client_addr, 0, sizeof(client_addr));
client_addr.sin_family = AF_INET;
client_addr.sin_port = htons((u_short)kServerPort);
InetPtonA(AF_INET, kServerIp, &client_addr.sin_addr.s_addr);
if (connect(client_socket, reinterpret_cast<sockaddr *>(&client_addr),
sizeof(sockaddr)) < 0) {
#ifdef _DEBUG
cout << "kServerIp:" << kServerIp <<endl;
cout << "port:" << kServerPort <<endl;
cout << "connect error,"
<< " errno:" << errno << endl;
#endif
return false;
}
char recv_buf[1024] = {0};
int ret = send(client_socket, buffer, len, 0);
if (ret == -1 || ret == 0) {
#ifdef _DEBUG
cout << "send fail,"
<< " errno:" << errno << endl;
#endif
closesocket(client_socket);
return false;
}
memset(recv_buf, 0, sizeof(recv_buf));
ret = recv(client_socket, recv_buf, sizeof(recv_buf), 0);
closesocket(client_socket);
if (ret == -1 || ret == 0) {
#ifdef _DEBUG
cout << "the server close" << endl;
#endif
return false;
}
return true;
}
/// @brief send wrap
/// @param msg msg
void SendSocketMessage(InnerMessageStruct *msg) {
if (msg == NULL) {
return;
}
unique_ptr<InnerMessageStruct> sms(msg);
json j_msg =
json::parse(msg->buffer, msg->buffer + msg->length, nullptr, false);
if (j_msg.is_discarded() == true) {
return;
}
string jstr = j_msg.dump() + "\n";
#ifdef _DEBUG
cout << "json:" + jstr << endl;
#endif
SendBySocket(jstr.c_str(), jstr.size());
}
/// @brief msg handle
/// @param msg_addr msg address in memory
void __cdecl OnRecvMsg(DWORD msg_addr) {
json j_msg;
unsigned long long msgid = *(unsigned long long *)(msg_addr + 0x30);
j_msg["msgId"] = msgid;
j_msg["pid"] = GetCurrentProcessId();
j_msg["type"] = *(DWORD *)(msg_addr + 0x38);
j_msg["isSendMsg"] = *(BOOL *)(msg_addr + 0x3C);
if (j_msg["isSendMsg"].get<BOOL>()) {
j_msg["isSendByPhone"] = (int)(*(BYTE *)(msg_addr + 0xD8));
}
j_msg["time"] =
unicode_to_utf8((wchar_t *)GetTimeW(*(DWORD *)(msg_addr + 0x44)).c_str());
j_msg["timestamp"] = *(DWORD *)(msg_addr + 0x44);
j_msg["fromGroup"] =
unicode_to_utf8((wchar_t *)READ_WSTRING(msg_addr, 0x48).c_str());
int length = *(DWORD *)(msg_addr + 0x178);
if (length == 0) {
j_msg["fromUser"] = j_msg["fromGroup"].get<std::string>();
} else {
j_msg["fromUser"] =
unicode_to_utf8((wchar_t *)READ_WSTRING(msg_addr, 0x174).c_str());
}
int content_len = *(DWORD *)(msg_addr + 0x74);
if (content_len > 0) {
j_msg["content"] =
unicode_to_utf8((wchar_t *)READ_WSTRING(msg_addr, 0x70).c_str());
}
int sign_len = *(DWORD *)(msg_addr + 0x18C);
if (sign_len > 0) {
j_msg["sign"] =
unicode_to_utf8((wchar_t *)READ_WSTRING(msg_addr, 0x188).c_str());
}
int thumb_len = *(DWORD *)(msg_addr + 0x1A0);
if (thumb_len > 0) {
j_msg["thumbPath"] =
unicode_to_utf8((wchar_t *)READ_WSTRING(msg_addr, 0x19C).c_str());
}
int path_len = *(DWORD *)(msg_addr + 0x1B4);
if (path_len > 0) {
j_msg["path"] =
unicode_to_utf8((wchar_t *)READ_WSTRING(msg_addr, 0x1B0).c_str());
}
int signature_len = *(DWORD *)(msg_addr + 0x1F4);
if (signature_len > 0) {
j_msg["signature"] =
unicode_to_utf8((wchar_t *)READ_WSTRING(msg_addr, 0x1F0).c_str());
}
string jstr = j_msg.dump() + '\n';
InnerMessageStruct *inner_msg = new InnerMessageStruct;
inner_msg->buffer = new char[jstr.size() + 1];
memcpy(inner_msg->buffer, jstr.c_str(), jstr.size() + 1);
inner_msg->length = jstr.size();
HANDLE thread = CreateThread(
NULL, 0, (LPTHREAD_START_ROUTINE)SendSocketMessage, inner_msg, NULL, 0);
if (thread) {
CloseHandle(thread);
}
}
void __cdecl OnSnsTimeLineMsg(DWORD msg_addr) {
json j_sns;
DWORD begin_addr = *(DWORD *)(msg_addr + 0x20);
DWORD end_addr = *(DWORD *)(msg_addr + 0x24);
#ifdef _DEBUG
cout << "begin" <<begin_addr<<endl;
cout << "end" <<end_addr<<endl;
#endif
if (begin_addr == 0) {
j_sns = {{"data", json::array()}};
} else {
while (begin_addr < end_addr) {
json j_item;
j_item["snsId"] = *(unsigned long long *)(begin_addr);
j_item["createTime"] = *(DWORD *)(begin_addr + 0x2C);
j_item["senderId"] =
unicode_to_utf8((wchar_t *)READ_WSTRING(begin_addr, 0x18).c_str());
j_item["content"] =
unicode_to_utf8((wchar_t *)READ_WSTRING(begin_addr, 0x3c).c_str());
j_item["xml"] =
unicode_to_utf8((wchar_t *)READ_WSTRING(begin_addr, 0x384).c_str());
j_sns["data"].push_back(j_item);
begin_addr += 0xB48;
}
}
string jstr = j_sns.dump() + '\n';
InnerMessageStruct *inner_msg = new InnerMessageStruct;
inner_msg->buffer = new char[jstr.size() + 1];
memcpy(inner_msg->buffer, jstr.c_str(), jstr.size() + 1);
inner_msg->length = jstr.size();
HANDLE thread = CreateThread(
NULL, 0, (LPTHREAD_START_ROUTINE)SendSocketMessage, inner_msg, NULL, 0);
if (thread) {
CloseHandle(thread);
}
}
/// @brief hook implement
_declspec(naked) void handle_sync_msg() {
__asm {
PUSHAD
PUSHFD
PUSH ECX
CALL OnRecvMsg
ADD ESP, 0x4
POPFD
POPAD
CALL kReceMsgNextAddress
JMP kReceMsgJmpBackAddress
}
}
/// @brief hook sns msg implement
_declspec(naked) void handle_sns_msg() {
__asm {
PUSHAD
PUSHFD
PUSH [ESP + 0x24]
CALL OnSnsTimeLineMsg
ADD ESP, 0x4
POPFD
POPAD
CALL kSnsMsgNextAddress
JMP kSnsMsgJmpBackAddress
}
}
/// @brief hook any address address+0x5
/// @param port 端口
/// @return 成功返回1,已经hook返回2,失败返回-1
int HookRecvMsg(char* client_ip,int port) {
kServerPort = port;
strcpy_s(kServerIp,client_ip);
kWeChatWinBase = GetWeChatWinBase();
if (!kWeChatWinBase) {
return -1;
}
if (kMessageHooked) {
return 2;
}
kWeChatWinBase = GetWeChatWinBase();
DWORD hook_recv_msg_addr = kWeChatWinBase + WX_RECV_MSG_HOOK_OFFSET;
kReceMsgNextAddress = kWeChatWinBase + WX_RECV_MSG_HOOK_NEXT_OFFSET;
kReceMsgJmpBackAddress = hook_recv_msg_addr + 0x5;
HookAnyAddress(hook_recv_msg_addr, (LPVOID)handle_sync_msg,
kOriginReceMsgAsmCode);
DWORD hook_sns_msg_addr = kWeChatWinBase + WX_SNS_HOOK_OFFSET;
kSnsMsgNextAddress = kWeChatWinBase + WX_SNS_HOOK_NEXT_OFFSET;
kSnsMsgJmpBackAddress = hook_sns_msg_addr + 0x5;
HookAnyAddress(hook_sns_msg_addr, (LPVOID)handle_sns_msg,
kOriginSnsMsgAsmCode);
kMessageHooked = TRUE;
return 1;
}
int UnHookRecvMsg() {
kServerPort = 0;
if (!kMessageHooked) return 2;
DWORD hook_recv_msg_addr = kWeChatWinBase + WX_RECV_MSG_HOOK_OFFSET;
DWORD hook_sns_addr = kWeChatWinBase + WX_SNS_HOOK_OFFSET;
UnHookAnyAddress(hook_recv_msg_addr, kOriginReceMsgAsmCode);
UnHookAnyAddress(hook_sns_addr, kOriginSnsMsgAsmCode);
kMessageHooked = FALSE;
return 1;
}

View File

@ -1,10 +0,0 @@
#ifndef HOOK_RECV_MSG_H_
#define HOOK_RECV_MSG_H_
/// @brief hook any address address+0x5
/// @param port 端口
/// @return 成功返回1,已经hook返回2
int HookRecvMsg(char* client_ip,int port);
int UnHookRecvMsg();
#endif

View File

@ -1,88 +0,0 @@
#include "pch.h"
#include "hook_voice.h"
#include "common.h"
using namespace std;
#define WX_HOOK_VOICE_OFFSET 0xd4d8d8
#define WX_HOOK_VOICE_NEXT_OFFSET 0x203d130
#define WX_SELF_ID_OFFSET 0x2FFD484
static wstring kVoiceStorePath = L"";
static int kVoiceHooked = FALSE;
static DWORD kWeChatWinBase = GetWeChatWinBase();
static char kOriginVoiceAsmCode[5] = {0};
static DWORD kHookVoiceNextAddress = kWeChatWinBase + WX_HOOK_VOICE_NEXT_OFFSET;
static DWORD kHookVoiceJmpBackAddress =
kWeChatWinBase + WX_HOOK_VOICE_OFFSET + 0x5;
void OnHookVoice(DWORD buff,int len , DWORD msg_addr) {
DWORD wxid_addr = GetWeChatWinBase() + WX_SELF_ID_OFFSET;
string wxid = string(*(char **)wxid_addr, *(DWORD *)(wxid_addr + 0x10));
wstring self_id = utf8_to_unicode(wxid.c_str());
wstring save_path = kVoiceStorePath + self_id;
if (!FindOrCreateDirectoryW(save_path.c_str())) {
return;
}
unsigned long long msgid = *(unsigned long long *)(msg_addr + 0x30);
save_path = save_path + L"\\" + to_wstring(msgid) + L".amr";
HANDLE file_handle = CreateFileW(save_path.c_str(), GENERIC_ALL, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (file_handle == INVALID_HANDLE_VALUE) {
return;
}
DWORD bytes_write = 0;
WriteFile(file_handle, (LPCVOID)buff, len, &bytes_write, 0);
CloseHandle(file_handle);
}
/// @brief hook voice implement
_declspec(naked) void handle_voice() {
__asm {
PUSHAD
PUSHFD
PUSH EDI
PUSH EDX
PUSH EAX
CALL OnHookVoice
ADD ESP, 0xC
POPFD
POPAD
CALL kHookVoiceNextAddress
JMP kHookVoiceJmpBackAddress
}
}
int HookVoice(std::wstring save_path) {
kWeChatWinBase = GetWeChatWinBase();
if (!kWeChatWinBase) {
return -1;
}
if (kVoiceHooked) {
return 2;
}
kVoiceStorePath = save_path;
if (kVoiceStorePath.back() != '\\') {
kVoiceStorePath += L"\\";
}
wstring createpath = kVoiceStorePath.substr(0, kVoiceStorePath.length() - 1);
if (!FindOrCreateDirectoryW(createpath.c_str())) {
return -2;
}
DWORD hook_voice_addr = kWeChatWinBase + WX_HOOK_VOICE_OFFSET;
kHookVoiceNextAddress = kWeChatWinBase + WX_HOOK_VOICE_NEXT_OFFSET;
static DWORD kHookVoiceJmpBackAddress = hook_voice_addr + 0x5;
HookAnyAddress(hook_voice_addr, (LPVOID)handle_voice, kOriginVoiceAsmCode);
kVoiceHooked = TRUE;
return 1;
}
int UnHookVoice() {
if (!kVoiceHooked) return 1;
DWORD hook_voice_addr = kWeChatWinBase + WX_HOOK_VOICE_OFFSET;
UnHookAnyAddress(hook_voice_addr, kOriginVoiceAsmCode);
kVoiceHooked = FALSE;
return 1;
}

View File

@ -1,8 +0,0 @@
#ifndef HOOK_VOICE_H_
#define HOOK_VOICE_H_
#include <string>
int HookVoice(std::wstring save_path);
int UnHookVoice();
#endif

533
src/hooks.cc Normal file
View File

@ -0,0 +1,533 @@
#include <Ws2tcpip.h>
#include <winsock2.h>
#include <nlohmann/json.hpp>
#include "easylogging++.h"
#include "pch.h"
#include "wechat_function.h"
using namespace nlohmann;
using namespace std;
namespace wxhelper {
namespace hooks {
static int server_port_ = 0;
static bool msg_hook_flag_ = false;
static char server_ip_[16] = "127.0.0.1";
static char msg_asm_code_[5] = {0};
static DWORD msg_back_addr_ = 0;
static DWORD msg_next_addr_ = 0;
static char sns_asm_code_[5] = {0};
static DWORD sns_back_addr_ = 0;
static DWORD sns_next_addr_ = 0;
static bool log_hook_flag_ = false;
static char log_asm_code_[5] = {0};
static DWORD log_back_addr_ = 0;
static DWORD log_next_addr_ = 0;
static bool search_contact_flag_ = false;
static char search_contact_asm_code_[5] = {0};
static DWORD search_contact_back_addr_ = 0;
static DWORD search_contact_next_addr_ = 0;
static bool error_code_flag_ = false;
static char error_code_asm_code_[5] = {0};
static DWORD error_code_back_addr_ = 0;
static DWORD error_code_next_addr_ = 0;
bool user_info_flag_ = false;
static char user_info_asm_code_[5] = {0};
static DWORD user_info_back_addr_ = 0;
static DWORD user_info_next_addr_ = 0;
UserInfo userinfo = {};
void SendSocketMessage(InnerMessageStruct *msg) {
if (msg == NULL) {
return;
}
unique_ptr<InnerMessageStruct> sms(msg);
json j_msg =
json::parse(msg->buffer, msg->buffer + msg->length, nullptr, false);
if (j_msg.is_discarded() == true) {
return;
}
string jstr = j_msg.dump() + "\n";
if (server_port_ == 0) {
LOG(INFO) << "http server port error :" << server_port_;
return;
}
SOCKET client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (client_socket < 0) {
LOG(INFO) << "socket init fail";
return;
}
BOOL status = false;
sockaddr_in client_addr;
memset(&client_addr, 0, sizeof(client_addr));
client_addr.sin_family = AF_INET;
client_addr.sin_port = htons((u_short)server_port_);
InetPtonA(AF_INET, server_ip_, &client_addr.sin_addr.s_addr);
if (connect(client_socket, reinterpret_cast<sockaddr *>(&client_addr),
sizeof(sockaddr)) < 0) {
LOG(INFO) << "socket connect fail";
return;
}
char recv_buf[1024] = {0};
int ret = send(client_socket, jstr.c_str(), jstr.size(), 0);
if (ret == -1 || ret == 0) {
LOG(INFO) << "socket send fail ,ret:" << ret;
closesocket(client_socket);
return;
}
memset(recv_buf, 0, sizeof(recv_buf));
ret = recv(client_socket, recv_buf, sizeof(recv_buf), 0);
closesocket(client_socket);
if (ret == -1 || ret == 0) {
LOG(INFO) << "socket recv fail ,ret:" << ret;
}
}
void __cdecl OnRecvMsg(DWORD msg_addr) {
json j_msg;
unsigned long long msgid = *(unsigned long long *)(msg_addr + 0x30);
j_msg["msgId"] = msgid;
j_msg["pid"] = GetCurrentProcessId();
j_msg["type"] = *(DWORD *)(msg_addr + 0x38);
j_msg["isSendMsg"] = *(BOOL *)(msg_addr + 0x3C);
if (j_msg["isSendMsg"].get<BOOL>()) {
j_msg["isSendByPhone"] = (int)(*(BYTE *)(msg_addr + 0xD8));
}
j_msg["time"] =
Utils::WstringToUTF8(Utils::GetTimeW(*(DWORD *)(msg_addr + 0x44)));
j_msg["timestamp"] = *(DWORD *)(msg_addr + 0x44);
j_msg["fromGroup"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x48));
int length = *(DWORD *)(msg_addr + 0x178);
if (length == 0) {
j_msg["fromUser"] = j_msg["fromGroup"].get<std::string>();
} else {
j_msg["fromUser"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x174));
}
int content_len = *(DWORD *)(msg_addr + 0x74);
if (content_len > 0) {
j_msg["content"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x70));
}
int sign_len = *(DWORD *)(msg_addr + 0x18C);
if (sign_len > 0) {
j_msg["sign"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x188));
}
int thumb_len = *(DWORD *)(msg_addr + 0x1A0);
if (thumb_len > 0) {
j_msg["thumbPath"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x19C));
}
int path_len = *(DWORD *)(msg_addr + 0x1B4);
if (path_len > 0) {
j_msg["path"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x1B0));
}
int signature_len = *(DWORD *)(msg_addr + 0x1F4);
if (signature_len > 0) {
j_msg["signature"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x1F0));
}
string jstr = j_msg.dump() + '\n';
InnerMessageStruct *inner_msg = new InnerMessageStruct;
inner_msg->buffer = new char[jstr.size() + 1];
memcpy(inner_msg->buffer, jstr.c_str(), jstr.size() + 1);
inner_msg->length = jstr.size();
HANDLE thread = CreateThread(
NULL, 0, (LPTHREAD_START_ROUTINE)SendSocketMessage, inner_msg, NULL, 0);
if (thread) {
CloseHandle(thread);
}
}
/// @brief hook msg implement
_declspec(naked) void HandleSyncMsg() {
__asm {
PUSHAD
PUSHFD
PUSH ECX
CALL OnRecvMsg
ADD ESP, 0x4
POPFD
POPAD
CALL msg_next_addr_
JMP msg_back_addr_
}
}
void __cdecl OnSnsTimeLineMsg(DWORD msg_addr) {
json j_sns;
DWORD begin_addr = *(DWORD *)(msg_addr + 0x20);
DWORD end_addr = *(DWORD *)(msg_addr + 0x24);
if (begin_addr == 0) {
j_sns = {{"data", json::array()}};
} else {
while (begin_addr < end_addr) {
json j_item;
j_item["snsId"] = *(unsigned long long *)(begin_addr);
j_item["createTime"] = *(DWORD *)(begin_addr + 0x2C);
j_item["senderId"] = Utils::WstringToUTF8(READ_WSTRING(begin_addr, 0x18));
j_item["content"] = Utils::WstringToUTF8(READ_WSTRING(begin_addr, 0x3c));
j_item["xml"] = Utils::WstringToUTF8(READ_WSTRING(begin_addr, 0x384));
j_sns["data"].push_back(j_item);
begin_addr += 0xB48;
}
}
string jstr = j_sns.dump() + '\n';
InnerMessageStruct *inner_msg = new InnerMessageStruct;
inner_msg->buffer = new char[jstr.size() + 1];
memcpy(inner_msg->buffer, jstr.c_str(), jstr.size() + 1);
inner_msg->length = jstr.size();
HANDLE thread = CreateThread(
NULL, 0, (LPTHREAD_START_ROUTINE)SendSocketMessage, inner_msg, NULL, 0);
if (thread) {
CloseHandle(thread);
}
}
/// @brief hook sns msg implement
_declspec(naked) void HandleSNSMsg() {
__asm {
PUSHAD
PUSHFD
PUSH [ESP + 0x24]
CALL OnSnsTimeLineMsg
ADD ESP, 0x4
POPFD
POPAD
CALL sns_next_addr_
JMP sns_back_addr_
}
}
int HookRecvMsg(char *client_ip, int port) {
server_port_ = port;
strcpy_s(server_ip_, client_ip);
DWORD base = Utils::GetWeChatWinBase();
if (!base) {
return -1;
}
if (msg_hook_flag_) {
return 2;
}
DWORD hook_recv_msg_addr = base + WX_RECV_MSG_HOOK_OFFSET;
msg_next_addr_ = base + WX_RECV_MSG_HOOK_NEXT_OFFSET;
msg_back_addr_ = hook_recv_msg_addr + 0x5;
LOG(INFO) << "base" << base;
LOG(INFO) << "msg_next_addr_" << msg_next_addr_;
LOG(INFO) << "msg_back_addr_" << msg_back_addr_;
Utils::HookAnyAddress(hook_recv_msg_addr, (LPVOID)HandleSyncMsg,
msg_asm_code_);
DWORD hook_sns_msg_addr = base + WX_SNS_HOOK_OFFSET;
sns_next_addr_ = base + WX_SNS_HOOK_NEXT_OFFSET;
sns_back_addr_ = hook_sns_msg_addr + 0x5;
LOG(INFO) << "base" << base;
LOG(INFO) << "sns_next_addr_" << sns_next_addr_;
LOG(INFO) << "sns_back_addr_" << sns_back_addr_;
Utils::HookAnyAddress(hook_sns_msg_addr, (LPVOID)HandleSNSMsg, sns_asm_code_);
msg_hook_flag_ = true;
return 1;
}
int UnHookRecvMsg() {
server_port_ = 0;
if (!msg_hook_flag_) {
LOG(INFO) << "this port already hooked";
return 2;
}
DWORD base = Utils::GetWeChatWinBase();
DWORD hook_recv_msg_addr = base + WX_RECV_MSG_HOOK_OFFSET;
DWORD hook_sns_addr = base + WX_SNS_HOOK_OFFSET;
Utils::UnHookAnyAddress(hook_recv_msg_addr, msg_asm_code_);
Utils::UnHookAnyAddress(hook_sns_addr, sns_asm_code_);
msg_hook_flag_ = false;
return 1;
}
void PrintLog(DWORD addr) {
if (!addr) {
return;
}
DWORD dwId = 0;
char *msg = (char *)addr;
int size = MultiByteToWideChar(CP_UTF8, 0, msg, -1, 0, 0);
wchar_t *w_msg = new wchar_t[size + 1];
memset(w_msg, 0, (size + 1) * 2);
MultiByteToWideChar(CP_UTF8, 0, msg, -1, w_msg, size);
size = WideCharToMultiByte(CP_ACP, 0, w_msg, -1, 0, 0, 0, 0);
char *ansi_message = new char[size + 1];
memset(ansi_message, 0, size + 1);
WideCharToMultiByte(CP_ACP, 0, w_msg, -1, ansi_message, size, 0, 0);
delete[] w_msg;
w_msg = NULL;
LOG(INFO) << ansi_message;
delete[] ansi_message;
ansi_message = NULL;
}
_declspec(naked) void HandleLog() {
__asm {
PUSHAD
PUSHFD
PUSH EAX
CALL PrintLog
ADD ESP, 0x4
POPFD
POPAD
CALL log_next_addr_
JMP log_back_addr_
}
}
int HookLog() {
DWORD base = Utils::GetWeChatWinBase();
if (!base) {
return -1;
}
if (log_hook_flag_) {
return 2;
}
DWORD hook_log_addr = base + WX_HOOK_LOG_OFFSET;
log_next_addr_ = base + WX_HOOK_LOG_NEXT_OFFSET;
log_back_addr_ = hook_log_addr + 0x5;
Utils::HookAnyAddress(hook_log_addr, (LPVOID)HandleLog, log_asm_code_);
log_hook_flag_ = true;
return 1;
}
int UnHookLog() {
if (!log_hook_flag_) {
return 1;
}
DWORD base = Utils::GetWeChatWinBase();
DWORD hook_log_addr = base + WX_HOOK_LOG_OFFSET;
Utils::UnHookAnyAddress(hook_log_addr, log_asm_code_);
log_hook_flag_ = FALSE;
return 1;
}
void SetErrorCode(int code) { userinfo.error_code = code; }
void SetUserInfoDetail(DWORD address) {
LOG(INFO) << "hook userinfo addr" <<&userinfo;
DWORD length = *(DWORD *)(address + 0x8);
userinfo.keyword = new wchar_t[length + 1];
userinfo.keyword_len = length;
if (length) {
memcpy(userinfo.keyword, (wchar_t *)(*(DWORD *)(address + 0x4)),
(length + 1) * sizeof(wchar_t));
} else {
ZeroMemory(userinfo.keyword, (length + 1) * sizeof(wchar_t));
}
length = *(DWORD *)(address + 0x1C);
userinfo.v3 = new wchar_t[length + 1];
userinfo.v3_len = length;
if (length) {
memcpy(userinfo.v3, (wchar_t *)(*(DWORD *)(address + 0x18)),
(length + 1) * sizeof(wchar_t));
} else {
ZeroMemory(userinfo.v3, (length + 1) * sizeof(wchar_t));
}
length = *(DWORD *)(address + 0x30);
userinfo.big_image = new wchar_t[length + 1];
userinfo.big_image_len = length;
if (length) {
memcpy(userinfo.big_image, (wchar_t *)(*(DWORD *)(address + 0x2C)),
(length + 1) * sizeof(wchar_t));
} else {
ZeroMemory(userinfo.big_image, (length + 1) * sizeof(wchar_t));
}
length = *(DWORD *)(address + 0xC8);
userinfo.nickname = new wchar_t[length + 1];
userinfo.nickname_len = length;
if (length) {
memcpy(userinfo.nickname, (wchar_t *)(*(DWORD *)(address + 0xC4)),
(length + 1) * sizeof(wchar_t));
} else {
ZeroMemory(userinfo.nickname, (length + 1) * sizeof(wchar_t));
}
length = *(DWORD *)(address + 0x108);
userinfo.v2 = new wchar_t[length + 1];
userinfo.v2_len = length;
if (length) {
memcpy(userinfo.v2, (wchar_t *)(*(DWORD *)(address + 0x104)),
(length + 1) * sizeof(wchar_t));
} else {
ZeroMemory(userinfo.v2, (length + 1) * sizeof(wchar_t));
}
length = *(DWORD *)(address + 0x16C);
userinfo.small_image = new wchar_t[length + 1];
userinfo.small_image_len = length;
if (length) {
memcpy(userinfo.small_image, (wchar_t *)(*(DWORD *)(address + 0x168)),
(length + 1) * sizeof(wchar_t));
} else {
ZeroMemory(userinfo.small_image, (length + 1) * sizeof(wchar_t));
}
length = *(DWORD *)(address + 0x1F8);
userinfo.signature = new wchar_t[length + 1];
userinfo.signature_len = length;
if (length) {
memcpy(userinfo.signature, (wchar_t *)(*(DWORD *)(address + 0x1F4)),
(length + 1) * sizeof(wchar_t));
} else {
ZeroMemory(userinfo.signature, (length + 1) * sizeof(wchar_t));
}
length = *(DWORD *)(address + 0x20C);
userinfo.nation = new wchar_t[length + 1];
userinfo.nation_len = length;
if (length) {
memcpy(userinfo.nation, (wchar_t *)(*(DWORD *)(address + 0x208)),
(length + 1) * sizeof(wchar_t));
} else {
ZeroMemory(userinfo.nation, (length + 1) * sizeof(wchar_t));
}
length = *(DWORD *)(address + 0x220);
userinfo.province = new wchar_t[length + 1];
userinfo.province_len = length;
if (length) {
memcpy(userinfo.province, (wchar_t *)(*(DWORD *)(address + 0x21C)),
(length + 1) * sizeof(wchar_t));
} else {
ZeroMemory(userinfo.province, (length + 1) * sizeof(wchar_t));
}
length = *(DWORD *)(address + 0x234);
userinfo.city = new wchar_t[length + 1];
userinfo.city_len = length;
if (length) {
memcpy(userinfo.city, (wchar_t *)(*(DWORD *)(address + 0x230)),
(length + 1) * sizeof(wchar_t));
} else {
ZeroMemory(userinfo.city, (length + 1) * sizeof(wchar_t));
}
userinfo.sex = *(DWORD *)(address + 0x1BC);
userinfo.over = true;
}
void DeleteUserInfoCache() {
if (userinfo.keyword) {
delete userinfo.keyword;
}
if (userinfo.v2) {
delete userinfo.v2;
}
if (userinfo.v3) {
delete userinfo.v3;
}
if (userinfo.nickname) {
delete userinfo.nickname;
}
if (userinfo.nation) {
delete userinfo.nation;
}
if (userinfo.province) {
delete userinfo.province;
}
if (userinfo.city) {
delete userinfo.city;
}
if (userinfo.signature) {
delete userinfo.signature;
}
if (userinfo.small_image) {
delete userinfo.small_image;
}
if (userinfo.big_image) {
delete userinfo.big_image;
}
ZeroMemory(&userinfo, sizeof(UserInfo));
userinfo.error_code = 1;
}
__declspec(naked) void HandleErrorCode() {
__asm {
PUSHAD;
PUSHFD;
PUSH ESI;
CALL SetErrorCode;
ADD ESP, 0x4;
POPFD;
POPAD;
CALL error_code_next_addr_;
JMP error_code_back_addr_;
}
}
__declspec(naked) void HandleUserInfoDetail() {
__asm {
PUSHAD;
PUSHFD;
PUSH dword ptr [EBP + 0x14];
CALL SetUserInfoDetail;
ADD ESP, 0x4;
POPFD;
POPAD;
CALL user_info_next_addr_;
JMP user_info_back_addr_;
}
}
int HookSearchContact() {
DWORD base = Utils::GetWeChatWinBase();
if (!base) {
return -1;
}
if (search_contact_flag_) {
return 2;
}
DWORD hook_error_code_addr = base + WX_SEARCH_CONTACT_ERROR_CODE_HOOK_OFFSET;
error_code_next_addr_ = base + WX_SEARCH_CONTACT_ERROR_CODE_HOOK_NEXT_OFFSET;
error_code_back_addr_ = hook_error_code_addr + 0x5;
Utils::HookAnyAddress(hook_error_code_addr, (LPVOID)HandleErrorCode,
error_code_asm_code_);
DWORD hook_user_info_addr = base + WX_SEARCH_CONTACT_DETAIL_HOOK_OFFSET;
user_info_next_addr_ = base + WX_SEARCH_CONTACT_DETAIL_HOOK_NEXT_OFFSET;
user_info_back_addr_ = hook_user_info_addr + 0x5;
Utils::HookAnyAddress(hook_user_info_addr, (LPVOID)HandleUserInfoDetail,
user_info_asm_code_);
error_code_flag_ = true;
user_info_flag_ = true;
return 1;
}
int UnHookSearchContact() {
DWORD base = Utils::GetWeChatWinBase();
DWORD hook_user_info_addr = base + WX_SEARCH_CONTACT_DETAIL_HOOK_OFFSET;
DWORD hook_error_code_addr = base + WX_SEARCH_CONTACT_ERROR_CODE_HOOK_OFFSET;
if (!user_info_flag_) return 2;
Utils::UnHookAnyAddress(hook_user_info_addr, user_info_asm_code_);
user_info_flag_ = false;
if (!error_code_flag_) return 2;
Utils::UnHookAnyAddress(hook_error_code_addr, error_code_asm_code_);
error_code_flag_ = false;
return 1;
}
} // namespace hooks
} // namespace wxhelper

23
src/hooks.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef WXHELPER_HOOKS_H_
#define WXHELPER_HOOKS_H_
#include "Windows.h"
#include "wechat_function.h"
namespace wxhelper {
namespace hooks {
extern UserInfo userinfo;
extern bool user_info_flag_ ;
int HookRecvMsg(char* client_ip, int port);
int UnHookRecvMsg();
void SendSocketMessage(InnerMessageStruct* msg);
int HookLog();
int UnHookLog();
int HookSearchContact();
int UnHookSearchContact();
void DeleteUserInfoCache();
} // namespace hooks
} // namespace wxhelper
#endif

594
src/http_handler.cc Normal file
View File

@ -0,0 +1,594 @@
#include "pch.h"
#include "http_handler.h"
#include <nlohmann/json.hpp>
#include "utils.h"
#include "account_mgr.h"
#include "api_route.h"
#include "chat_room_mgr.h"
#include "contact_mgr.h"
#include "db.h"
#include "easylogging++.h"
#include "hooks.h"
#include "misc_mgr.h"
#include "send_message_mgr.h"
#include "sns_mgr.h"
#include "global_context.h"
#include "hooks.h"
using namespace std;
using namespace nlohmann;
namespace wxhelper {
string GetParamOfGetReq(mg_http_message *hm, string name) {
string ret;
char *buffer = new char[hm->query.len + 1];
ZeroMemory(buffer, hm->query.len + 1);
int len = mg_http_get_var(&hm->query, name.c_str(), buffer, hm->query.len);
if (len > 0) ret = string(buffer, len);
delete[] buffer;
buffer = NULL;
return ret;
}
int GetIntParam(json data, string key) {
int result;
try {
result = data[key].get<int>();
} catch (json::exception) {
result = STRING2INT(data[key].get<string>());
}
return result;
}
wstring GetWStringParam(json data, string key) {
return Utils::UTF8ToWstring(data[key].get<string>());
}
unsigned long long GetULong64Param(json j_data, string key) {
unsigned long long result = 0;
try {
result = j_data[key].get<ULONG64>();
} catch (json::exception) {
string value = j_data[key].get<string>();
istringstream is(value);
is >> result;
}
return result;
}
static vector<wstring> getArrayParam(json j_data, string key) {
vector<wstring> result;
wstring param = GetWStringParam(j_data, key);
result = Utils::split(param, L',');
return result;
}
string Dispatch(struct mg_connection *c, struct mg_http_message *hm) {
int is_post = 0;
string ret;
if (mg_vcasecmp(&hm->method, "POST") == 0) {
is_post = 1;
}
el::Logger *defaultLogger = el::Loggers::getLogger("default");
defaultLogger->info("method: %v body: %v", hm->method.ptr, hm->body.ptr);
LOG_IF(is_post != 1, INFO) << "request method is not post";
if (is_post == 0) {
json ret_data = {{"result", "ERROR"}, {"msg", "not support method"}};
ret = ret_data.dump();
return ret;
}
json j_param =
json::parse(hm->body.ptr, hm->body.ptr + hm->body.len, nullptr, false);
if (hm->body.len != 0 && j_param.is_discarded() == true) {
json ret_data = {{"result", "ERROR"}, {"msg", "json string is invalid."}};
ret = ret_data.dump();
return ret;
}
int api_number = STRING2INT(GetParamOfGetReq(hm, "type"));
GlobalContext& g_context = GlobalContext::GetInstance();
switch (api_number) {
case WECHAT_IS_LOGIN: {
int success = -1;
success = g_context.account_mgr->CheckLogin();
json ret_data = {{"result", "OK"}, {"code", success}};
ret = ret_data.dump();
break;
}
case WECHAT_GET_SELF_INFO: {
SelfInfoInner self_info;
int success = g_context.account_mgr->GetSelfInfo(self_info);
json ret_data = {{"result", "OK"}, {"code", success}};
if (success) {
json j_info = {
{"name", self_info.name},
{"city", self_info.city},
{"province", self_info.province},
{"country", self_info.country},
{"account", self_info.account},
{"wxid", self_info.wxid},
{"mobile", self_info.mobile},
{"headImage", self_info.head_img},
{"signature", self_info.signature},
{"dataSavePath", self_info.data_save_path},
{"currentDataPath", self_info.current_data_path},
{"dbKey", self_info.db_key},
};
ret_data["data"] = j_info;
}
ret = ret_data.dump();
break;
}
case WECHAT_MSG_SEND_TEXT: {
wstring wxid = GetWStringParam(j_param, "wxid");
wstring msg = GetWStringParam(j_param, "msg");
int success = g_context.send_mgr->SendText(WS2LPWS(wxid), WS2LPWS(msg));
json ret_data = {{"result", "OK"}, {"code", success}};
ret = ret_data.dump();
break;
}
case WECHAT_MSG_SEND_AT: {
break;
wstring chat_room_id = GetWStringParam(j_param, "chatRoomId");
vector<wstring> wxids = getArrayParam(j_param, "wxids");
wstring msg = GetWStringParam(j_param, "msg");
vector<wchar_t *> wxid_list;
for (unsigned int i = 0; i < wxids.size(); i++) {
wxid_list.push_back(WS2LPWS(wxids[i]));
}
int success = g_context.send_mgr->SendAtText(WS2LPWS(chat_room_id), wxid_list.data(),
wxid_list.size(), WS2LPWS(msg));
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_MSG_SEND_CARD: {
break;
}
case WECHAT_MSG_SEND_IMAGE: {
wstring receiver = GetWStringParam(j_param, "wxid");
wstring img_path = GetWStringParam(j_param, "imagePath");
int success =
g_context.send_mgr->SendImage(WS2LPWS(receiver), WS2LPWS(img_path));
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_MSG_SEND_FILE: {
wstring receiver = GetWStringParam(j_param, "wxid");
wstring file_path = GetWStringParam(j_param, "filePath");
int success =
g_context.send_mgr->SendFile(WS2LPWS(receiver), WS2LPWS(file_path));
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_MSG_SEND_ARTICLE: {
break;
}
case WECHAT_MSG_SEND_APP: {
break;
}
case WECHAT_MSG_START_HOOK: {
int port = GetIntParam(j_param, "port");
wstring ip = GetWStringParam(j_param, "ip");
string client_ip = Utils::WstringToUTF8(ip);
char ip_cstr[16];
strcpy_s(ip_cstr, client_ip.c_str());
int success = hooks::HookRecvMsg(ip_cstr, port);
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_MSG_STOP_HOOK: {
int success = hooks::UnHookRecvMsg();
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_MSG_START_IMAGE_HOOK: {
break;
}
case WECHAT_MSG_STOP_IMAGE_HOOK: {
break;
}
case WECHAT_MSG_START_VOICE_HOOK: {
break;
}
case WECHAT_MSG_STOP_VOICE_HOOK: {
break;
}
case WECHAT_CONTACT_GET_LIST: {
break;
}
case WECHAT_CONTACT_CHECK_STATUS: {
break;
}
case WECHAT_CONTACT_DEL: {
break;
}
case WECHAT_CONTACT_SEARCH_BY_CACHE: {
break;
}
case WECHAT_CONTACT_SEARCH_BY_NET: {
wstring keyword = GetWStringParam(j_param, "keyword");
UserInfo *user = nullptr;
int success = g_context.misc_mgr->SearchContactNetScene(WS2LPWS(keyword), &user);
json ret_data = {{"code", success}, {"result", "OK"}};
if (user) {
json info = {
{"bigImage", Utils::WCharToUTF8(user->big_image)},
{"smallImage", Utils::WCharToUTF8(user->small_image)},
{"city", Utils::WCharToUTF8(user->city)},
{"nation", Utils::WCharToUTF8(user->nation)},
{"nickname", Utils::WCharToUTF8(user->nickname)},
{"province", Utils::WCharToUTF8(user->province)},
{"sex", user->sex},
{"signature", Utils::WCharToUTF8(user->signature)},
{"v2", Utils::WCharToUTF8(user->v2)},
{"v3", Utils::WCharToUTF8(user->v3)},
};
ret_data["userInfo"] = info;
}
ret = ret_data.dump();
break;
}
case WECHAT_CONTACT_ADD_BY_WXID: {
// wstring user_id = GetWStringParam(j_param, "wxid");
// wstring msg = GetWStringParam(j_param, "msg");
// int success = g_context.contact_mgr->AddFriendByWxid(WS2LPWS(user_id),WS2LPWS(msg));
// json ret_data = {{"code", success}, {"result", "OK"}};
// ret = ret_data.dump();
break;
}
case WECHAT_CONTACT_ADD_BY_V3: {
break;
}
case WECHAT_CONTACT_ADD_BY_PUBLIC_ID: {
break;
}
case WECHAT_CONTACT_VERIFY_APPLY: {
break;
}
case WECHAT_CONTACT_EDIT_REMARK: {
break;
}
case WECHAT_CHATROOM_GET_MEMBER_LIST: {
wstring room_id = GetWStringParam(j_param, "chatRoomId");
ChatRoomInner out{0};
int success = g_context.chat_room_mgr->GetMemberFromChatRoom(WS2LPWS(room_id), out);
json ret_data = {{"code", success}, {"result", "OK"}};
if (success) {
json member_info = {
{"admin", Utils::WstringToUTF8(out.admin)},
{"chatRoomId", Utils::WstringToUTF8(out.chat_room)},
{"members", out.members},
};
ret_data["data"] = member_info;
}
ret = ret_data.dump();
break;
}
case WECHAT_CHATROOM_GET_MEMBER_NICKNAME: {
wstring room_id = GetWStringParam(j_param, "chatRoomId");
wstring member_id = GetWStringParam(j_param, "memberId");
wstring nickname =g_context.chat_room_mgr->GetChatRoomMemberNickname(
WS2LPWS(room_id), WS2LPWS(member_id));
json ret_data = {{"code", 1},
{"result", "OK"},
{"nickname", Utils::WstringToUTF8(nickname)}};
ret = ret_data.dump();
break;
}
case WECHAT_CHATROOM_DEL_MEMBER: {
wstring room_id = GetWStringParam(j_param, "chatRoomId");
vector<wstring> wxids = getArrayParam(j_param, "memberIds");
vector<wchar_t *> wxid_list;
for (unsigned int i = 0; i < wxids.size(); i++) {
wxid_list.push_back(WS2LPWS(wxids[i]));
}
int success = g_context.chat_room_mgr->DelMemberFromChatRoom(
WS2LPWS(room_id), wxid_list.data(), wxid_list.size());
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_CHATROOM_ADD_MEMBER: {
wstring room_id = GetWStringParam(j_param, "chatRoomId");
vector<wstring> wxids = getArrayParam(j_param, "memberIds");
vector<wchar_t *> wxid_list;
for (unsigned int i = 0; i < wxids.size(); i++) {
wxid_list.push_back(WS2LPWS(wxids[i]));
}
int success = g_context.chat_room_mgr->AddMemberToChatRoom(
WS2LPWS(room_id), wxid_list.data(), wxid_list.size());
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_CHATROOM_SET_ANNOUNCEMENT: {
break;
}
case WECHAT_CHATROOM_SET_CHATROOM_NAME: {
break;
}
case WECHAT_CHATROOM_SET_SELF_NICKNAME: {
wstring room_id = GetWStringParam(j_param, "chatRoomId");
wstring wxid = GetWStringParam(j_param, "wxid");
wstring nick = GetWStringParam(j_param, "nickName");
int success = g_context.chat_room_mgr->ModChatRoomMemberNickName(
WS2LPWS(room_id), WS2LPWS(wxid), WS2LPWS(nick));
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_DATABASE_GET_HANDLES: {
vector<void *> v_ptr = DB::GetInstance().GetDbHandles();
json ret_data = {{"data", json::array()}, {"result", "OK"}};
for (unsigned int i = 0; i < v_ptr.size(); i++) {
json db_info;
db_info["tables"] = json::array();
DatabaseInfo *db = reinterpret_cast<DatabaseInfo *>(v_ptr[i]);
db_info["handle"] = db->handle;
wstring dbname(db->db_name);
db_info["databaseName"] = Utils::WstringToUTF8(dbname);
for (auto table : db->tables) {
json table_info = {{"name", table.name},
{"tableName", table.table_name},
{"sql", table.sql},
{"rootpage", table.rootpage}};
db_info["tables"].push_back(table_info);
}
ret_data["data"].push_back(db_info);
}
ret = ret_data.dump();
break;
}
case WECHAT_DATABASE_BACKUP: {
break;
}
case WECHAT_DATABASE_QUERY: {
DWORD db_handle = GetIntParam(j_param, "dbHandle");
wstring sql = GetWStringParam(j_param, "sql");
string sql_str = Utils::WstringToUTF8(sql);
vector<vector<string>> items;
int success = DB::GetInstance().Select(db_handle, sql_str.c_str(), items);
json ret_data = {
{"data", json::array()}, {"code", success}, {"result", "OK"}};
if (success == 0) {
ret = ret_data.dump();
break;
}
for (auto it : items) {
json temp_arr = json::array();
for (size_t i = 0; i < it.size(); i++) {
temp_arr.push_back(it[i]);
}
ret_data["data"].push_back(temp_arr);
}
ret = ret_data.dump();
break;
}
case WECHAT_SET_VERSION: {
break;
}
case WECHAT_LOG_START_HOOK: {
int success = hooks::HookLog();
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_LOG_STOP_HOOK: {
int success = hooks::UnHookLog();
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_BROWSER_OPEN_WITH_URL: {
break;
}
case WECHAT_GET_PUBLIC_MSG: {
break;
}
case WECHAT_MSG_FORWARD_MESSAGE: {
wstring wxid = GetWStringParam(j_param, "wxid");
ULONG64 msgid = GetULong64Param(j_param, "msgid");
int success =g_context.send_mgr->ForwardMsg(WS2LPWS(wxid), msgid);
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_GET_QRCODE_IMAGE: {
break;
}
case WECHAT_GET_A8KEY: {
break;
}
case WECHAT_MSG_SEND_XML: {
break;
}
case WECHAT_LOGOUT: {
int success = g_context.account_mgr->Logout();
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_GET_TRANSFER: {
wstring wxid = GetWStringParam(j_param, "wxid");
wstring transcationid = GetWStringParam(j_param, "transcationId");
wstring transferid = GetWStringParam(j_param, "transferId");
BOOL response =g_context.misc_mgr->DoConfirmReceipt(
WS2LPWS(wxid), WS2LPWS(transcationid), WS2LPWS(transferid));
json ret_data = {{"msg", response}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_GET_CONTACT_ALL: {
vector<Contact> vec;
int success = g_context.contact_mgr->GetAllContact(vec);
json ret_data = {
{"data", json::array()}, {"code", success}, {"result", "OK"}};
for (unsigned int i = 0; i < vec.size(); i++) {
json item = {
{"customAccount",
vec[i].custom_account.length > 0
? vec[i].custom_account.ptr != nullptr
? Utils::WCharToUTF8(vec[i].custom_account.ptr)
: string()
: string()},
{"delFlag", vec[i].del_flag},
{"userName", vec[i].encrypt_name.length > 0
? vec[i].encrypt_name.ptr != nullptr
? Utils::WCharToUTF8(vec[i].encrypt_name.ptr)
: string()
: string()},
{"type", vec[i].type},
{"verifyFlag", vec[i].verify_flag},
{"verifyFlag", vec[i].verify_flag},
{"wxid", vec[i].wxid.length > 0
? Utils::WCharToUTF8(vec[i].wxid.ptr)
: string()},
};
ret_data["data"].push_back(item);
}
ret = ret_data.dump();
break;
}
case WECHAT_GET_CHATROOM_INFO: {
wstring room_id = GetWStringParam(j_param, "chatRoomId");
ChatRoomInfoInner chat_room_detail{0};
int success = g_context.chat_room_mgr->GetChatRoomDetailInfo(WS2LPWS(room_id),
chat_room_detail);
json ret_data = {{"code", success}, {"result", "OK"}};
if (!success) {
break;
}
json detail = {
{"chatRoomId",
chat_room_detail.chat_room_id.length > 0
? Utils::WCharToUTF8(chat_room_detail.chat_room_id.ptr)
: string()},
{"notice", chat_room_detail.notice.length > 0
? Utils::WCharToUTF8(chat_room_detail.notice.ptr)
: string()},
{"admin", chat_room_detail.admin.length > 0
? Utils::WCharToUTF8(chat_room_detail.admin.ptr)
: string()},
{"xml", chat_room_detail.xml.length > 0
? Utils::WCharToUTF8(chat_room_detail.xml.ptr)
: string()},
};
ret_data["data"] = detail;
ret = ret_data.dump();
break;
}
case WECHAT_GET_IMG_BY_NAME: {
wstring image_path = GetWStringParam( j_param, "imagePath");
wstring save_path = GetWStringParam( j_param, "savePath");
int success =
g_context.misc_mgr->GetImgByName(WS2LPWS(image_path),WS2LPWS(save_path)); json
ret_data = {{"code", success}, {"result", "OK"}}; ret =
ret_data.dump();
break;
}
case WECHAT_DO_OCR: {
// wstring image_path = GetWStringParam(j_param, "imagePath");
// string text("");
// int success = g_context.misc_mgr->DoOCRTask(WS2LPWS(image_path), text);
// json ret_data = {{"code", success}, {"result", "OK"}, {"text", text}};
// ret = ret_data.dump();
break;
}
case WECHAT_SEND_PAT_MSG: {
wstring room_id = GetWStringParam(j_param, "chatRoomId");
wstring wxid = GetWStringParam(j_param, "wxid");
int success = g_context.misc_mgr->SendPatMsg(WS2LPWS(room_id), WS2LPWS(wxid));
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_SET_TOP_MSG: {
wstring wxid = GetWStringParam(j_param, "wxid");
ULONG64 msgid = GetULong64Param(j_param, "msgid");
int success = g_context.chat_room_mgr->SetTopMsg(WS2LPWS(wxid), msgid);
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_REMOVE_TOP_MSG: {
wstring room_id = GetWStringParam(j_param, "chatRoomId");
ULONG64 msgid = GetULong64Param(j_param, "msgid");
int success = g_context.chat_room_mgr->RemoveTopMsg(WS2LPWS(room_id), msgid);
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_SNS_GET_FIRST_PAGE: {
int success = g_context.sns_mgr->GetFirstPage();
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_SNS_GET_NEXT_PAGE: {
ULONG64 snsid = GetULong64Param(j_param, "snsId");
int success = g_context.sns_mgr->GetNextPage(snsid);
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_CONTACT_NAME: {
wstring pri_id = GetWStringParam(j_param, "id");
wstring name = g_context.contact_mgr->GetContactOrChatRoomNickname(WS2LPWS(pri_id));
json ret_data = {
{"code", 1}, {"result", "OK"}, {"name", Utils::WstringToUTF8(name)}};
ret = ret_data.dump();
break;
}
case WECHAT_ATTACH_DOWNLOAD: {
ULONG64 msg_id = GetULong64Param(j_param, "msgId");
int success = g_context.misc_mgr->DoDownloadTask(msg_id);
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_GET_VOICE: {
ULONG64 msg_id = GetULong64Param(j_param, "msgId");
wstring voice_dir = GetWStringParam(j_param, "voiceDir");
int success = g_context.misc_mgr->GetVoice(msg_id, WS2LPWS(voice_dir));
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
default:
break;
}
return ret;
}
HttpHandler::HttpHandler() {}
HttpHandler::~HttpHandler() {}
void HttpHandler::HandlerRequest(struct mg_connection *c, void *ev_data) {
struct mg_http_message *hm = (struct mg_http_message *)ev_data;
string ret = R"({"result":"OK"})";
if (mg_http_match_uri(hm, "/api/")) {
try {
ret = Dispatch(c, hm);
} catch (json::exception &e) {
json res = {{"result", "ERROR"}, {"msg", e.what()}};
ret = res.dump();
}
if (ret != "") {
mg_http_reply(c, 200, "", ret.c_str(), 0, 0);
}
} else {
mg_http_reply(c, 500, NULL, "%s", "Invalid URI");
}
}
} // namespace wxhelper

17
src/http_handler.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef WXHELPER_HTTP_HANDLER_H_
#define WXHELPER_HTTP_HANDLER_H_
#include "handler.h"
#include "mongoose.h"
#include <vector>
#include <string>
#include <nlohmann/json.hpp>
namespace wxhelper {
class HttpHandler : public Handler {
public:
HttpHandler();
~HttpHandler();
void HandlerRequest(struct mg_connection *c, void *ev_data);
};
} // namespace wxhelper
#endif

View File

@ -1,10 +1,10 @@
#include "pch.h"
#include "http_server.h"
#include <nlohmann/json.hpp>
#include "api_route.h"
#include "common.h"
#include "pch.h"
#pragma comment(lib, "ws2_32.lib")
using namespace std;
using namespace nlohmann;
@ -33,12 +33,12 @@ bool HttpServer::HttpStart() {
return true;
}
#ifdef _DEBUG
CreateConsole();
Utils::CreateConsole();
#endif
running_ = true;
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)StartHttpServer, NULL,
thread_ = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)StartHttpServer, NULL,
NULL, 0);
return false;
return true;
}
void HttpServer::StartHttpServer() {
@ -81,6 +81,20 @@ void HttpServer::HandleWebsocketRequest(struct mg_connection *c,
mg_ws_send(c, wm->data.ptr, wm->data.len, WEBSOCKET_OP_TEXT);
}
bool HttpServer::HttpClose() { return false; }
bool HttpServer::HttpClose() {
if (!running_) {
return true;
}
#ifdef _DEBUG
Utils::CloseConsole();
#endif
running_ = false;
if (thread_) {
WaitForSingleObject(thread_, -1);
CloseHandle(thread_);
thread_ = NULL;
}
return true;
}
} // namespace wxhelper

View File

@ -2,34 +2,33 @@
#define WXHELPER_HTTP_SERVER_H_
#include <mongoose.h>
#include "http_handler.h"
namespace wxhelper {
class HttpServer {
public:
static HttpServer &GetInstance();
bool HttpStart();
bool HttpClose();
void Init(int port);
private:
HttpServer(){}
private:
HttpServer(){};
HttpServer(const HttpServer &) = delete;
HttpServer &operator=(const HttpServer &) = delete;
~HttpServer();
static void StartHttpServer();
static void EventHandler(struct mg_connection *c, int ev, void *ev_data, void *fn_data);
static void EventHandler(struct mg_connection *c, int ev, void *ev_data,
void *fn_data);
void HandleHttpRequest(struct mg_connection *c, void *ev_data);
void HandleWebsocketRequest(struct mg_connection *c, void *ev_data);
private:
int port_;
bool running_;
struct mg_mgr mgr_;
HttpHandler* http_handler_;
HttpHandler *http_handler_;
HANDLE thread_;
};
} // namespace wxhelper

37
src/log.cc Normal file
View File

@ -0,0 +1,37 @@
#include "log.h"
#include "easylogging++.h"
INITIALIZE_EASYLOGGINGPP
namespace wxhelper {
Log::Log(/* args */) {}
Log::~Log() {}
void Log::initialize() {
el::Configurations conf;
// 启用日志
conf.setGlobally(el::ConfigurationType::Enabled, "true");
// 设置日志文件目录以及文件名
conf.setGlobally(el::ConfigurationType::Filename,
"log\\log_%datetime{%Y%M%d %H%m%s}.log");
// 设置日志文件最大文件大小
conf.setGlobally(el::ConfigurationType::MaxLogFileSize, "20971520");
// 是否写入文件
conf.setGlobally(el::ConfigurationType::ToFile, "true");
// 是否输出控制台
conf.setGlobally(el::ConfigurationType::ToStandardOutput, "true");
// 设置日志输出格式
conf.setGlobally(el::ConfigurationType::Format,
"[%datetime] [%thread] [%loc] [%level] : %msg");
// 设置日志文件写入周期如下每100条刷新到输出流中
#ifdef _DEBUG
conf.setGlobally(el::ConfigurationType::LogFlushThreshold, "1");
#else
conf.setGlobally(el::ConfigurationType::LogFlushThreshold, "100");
#endif
// 设置配置文件
el::Loggers::reconfigureAllLoggers(conf);
}
} // namespace wxhelper

18
src/log.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef WXHELPER_LOG_H_
#define WXHELPER_LOG_H_
namespace wxhelper{
class Log
{
private:
/* data */
public:
Log(/* args */);
~Log();
void initialize();
};
}
#endif

436
src/misc_mgr.cc Normal file
View File

@ -0,0 +1,436 @@
#include "misc_mgr.h"
#include "pch.h"
#include "wechat_function.h"
#include "base64.h"
#include "db.h"
#include "hooks.h"
#include "easylogging++.h"
#define BUFSIZE 1024
#define JPEG0 0xFF
#define JPEG1 0xD8
#define JPEG2 0xFF
#define PNG0 0x89
#define PNG1 0x50
#define PNG2 0x4E
#define BMP0 0x42
#define BMP1 0x4D
#define GIF0 0x47
#define GIF1 0x49
#define GIF2 0x46
using namespace std;
namespace wxhelper {
MiscMgr::MiscMgr(DWORD base) : BaseMgr::BaseMgr(base) {}
MiscMgr::~MiscMgr() {}
int MiscMgr::SendPatMsg(wchar_t *chat_room_id, wchar_t *wxid) {
int success = -1;
WeChatString chat_room(chat_room_id);
WeChatString self_wxid(wxid);
DWORD get_pat_mgr_addr = base_addr_ + WX_PAT_MGR_OFFSET;
DWORD send_pat_msg_addr = base_addr_ + WX_SEND_PAT_MSG_OFFSET;
DWORD ret_addr = base_addr_ + WX_RET_OFFSET;
__asm {
PUSHAD
CALL get_pat_mgr_addr
PUSH ret_addr
PUSH 0x0
PUSH EAX
LEA ECX,chat_room
LEA EDX,self_wxid
CALL send_pat_msg_addr
ADD ESP,0xc
MOVZX EAX,AL
MOV success,EAX
POPAD
}
return success;
}
int MiscMgr::DoOCRTask(wchar_t *img_path, std::string &result) {
int success = -1;
WeChatString path(img_path);
WeChatString null_obj = {0};
WeChatString ocr_result = {0};
DWORD ocr_manager_addr = base_addr_ + WX_OCR_MANAGER_OFFSET;
DWORD do_ocr_task_addr = base_addr_ + WX_DO_OCR_TASK_OFFSET;
DWORD init_addr = base_addr_ + WX_INIT_OBJ_OFFSET;
DWORD flag = 0;
__asm {
PUSHAD
PUSHFD
LEA ECX,ocr_result
CALL init_addr
CALL ocr_manager_addr
LEA ECX,null_obj
PUSH ECX
LEA ECX,flag
PUSH ECX
LEA ECX,ocr_result
PUSH ECX
PUSH 0x0
LEA ECX,path
PUSH ECX
MOV ECX,EAX
CALL do_ocr_task_addr
MOV success,EAX
POPFD
POPAD
}
if (success == 0) {
DWORD addr = (DWORD)&ocr_result;
DWORD ptr = *(DWORD *)addr;
DWORD num = *(DWORD *)(addr + 0x4);
if (num <= 0) {
return success;
}
DWORD header = *(DWORD *)ptr;
for (unsigned int i = 0; i < num - 1; i++) {
DWORD content = *(DWORD *)header;
result += Utils::WstringToUTF8(READ_WSTRING(content, 0x14));
header = content;
}
}
return success;
}
int MiscMgr::DoConfirmReceipt(wchar_t *wxid, wchar_t *transcationid,
wchar_t *transferid) {
int success = -1;
WeChatString recv_id(wxid);
WeChatString transcation_id(transcationid);
WeChatString transfer_id(transferid);
char pay_info[0x134] = {0};
DWORD new_pay_info_addr = base_addr_ + WX_NEW_WCPAYINFO_OFFSET;
DWORD free_pay_info_addr = base_addr_ + WX_FREE_WCPAYINFO_OFFSET;
DWORD do_confirm_addr = base_addr_ + WX_CONFIRM_RECEIPT_OFFSET;
__asm {
PUSHAD
LEA ECX,pay_info
CALL new_pay_info_addr
MOV dword ptr [pay_info + 0x4], 0x1
MOV dword ptr [pay_info + 0x4C], 0x1
POPAD
}
memcpy(&pay_info[0x1c], &transcation_id, sizeof(transcation_id));
memcpy(&pay_info[0x38], &transfer_id, sizeof(transfer_id));
__asm {
PUSHAD
PUSH 0x1
SUB ESP,0x8
LEA EDX,recv_id
LEA ECX,pay_info
CALL do_confirm_addr
MOV success,EAX
ADD ESP,0xC
PUSH 0x0
LEA ECX,pay_info
CALL free_pay_info_addr
POPAD
}
return success;
}
int MiscMgr::DoDownloadTask(ULONG64 msg_id) {
int success = -1;
int db_index = 0;
int local_id = DB::GetInstance().GetLocalIdByMsgId(msg_id, db_index);
if (local_id < 1) {
return -2;
}
char chat_msg[0x2D8] = {0};
DWORD new_chat_msg_addr = base_addr_ + WX_NEW_CHAT_MSG_OFFSET;
DWORD get_chat_mgr_addr = base_addr_ + WX_CHAT_MGR_OFFSET;
DWORD pre_download_mgr_addr = base_addr_ + WX_GET_PRE_DOWNLOAD_MGR_OFFSET;
DWORD push_attach_task_addr = base_addr_ + WX_PUSH_ATTACH_TASK_OFFSET;
DWORD free_addr = base_addr_ + WX_FREE_CHAT_MSG_INSTANCE_COUNTER_OFFSET;
DWORD get_by_local_Id_addr = base_addr_ + WX_GET_MGR_BY_PREFIX_LOCAL_ID_OFFSET;
DWORD get_current_data_path_addr = base_addr_ + WX_GET_CURRENT_DATA_PATH_OFFSET;
DWORD free_app_msg_info_addr = base_addr_ + WX_FREE_APP_MSG_INFO_OFFSET;
DWORD push_thumb_task_addr = base_addr_ + WX_PUSH_THUMB_TASK_OFFSET;
DWORD video_mgr_addr = base_addr_ + WX_VIDEO_MGR_OFFSET;
DWORD download_video_image_addr = base_addr_ + WX_VIDEO_MGR_OFFSET;
WeChatString current_data_path;
__asm {
PUSHAD
PUSHFD
LEA ECX,current_data_path
CALL get_current_data_path_addr
LEA ECX,chat_msg
CALL new_chat_msg_addr
CALL get_chat_mgr_addr
PUSH dword ptr [db_index]
LEA ECX,chat_msg
PUSH dword ptr [local_id]
CALL get_by_local_Id_addr
ADD ESP,0x8
POPFD
POPAD
}
wstring save_path = L"";
wstring thumb_path = L"";
if (current_data_path.length > 0) {
save_path += current_data_path.ptr;
save_path += L"wxhelper";
} else {
return -1;
}
if (!Utils::FindOrCreateDirectoryW(save_path.c_str())) {
return -3;
}
DWORD type = *(DWORD *)(chat_msg + 0x38);
wchar_t *content = *(wchar_t **)(chat_msg + 0x70);
switch (type) {
case 0x3: {
save_path += L"\\image";
if (!Utils::FindOrCreateDirectoryW(save_path.c_str())) {
return -3;
}
save_path = save_path +L"\\"+ to_wstring(msg_id) + L".png";
break;
}
case 0x3E:
case 0x2B: {
save_path += L"\\video";
if (!Utils::FindOrCreateDirectoryW(save_path.c_str())) {
return -3;
}
thumb_path = save_path + L"\\"+ to_wstring(msg_id) + L".jpg";
save_path = save_path + L"\\"+ to_wstring(msg_id) + L".mp4";
break;
}
case 0x31: {
save_path += L"\\file";
wcout << save_path << endl;
if (!Utils::FindOrCreateDirectoryW(save_path.c_str())) {
return -3;
}
char xml_app_msg[0xC80] = {0};
DWORD new_app_msg_addr = base_addr_ + WX_APP_MSG_INFO_OFFSET;
DWORD get_xml_addr = base_addr_ + WX_GET_APP_MSG_XML_OFFSET;
WeChatString w_content(content);
__asm {
PUSHAD
PUSHFD
LEA ECX,xml_app_msg
CALL new_app_msg_addr
PUSH 0x1
LEA EAX,w_content
PUSH EAX
LEA ECX,xml_app_msg
CALL get_xml_addr
MOV success,EAX
LEA ECX,xml_app_msg
CALL free_app_msg_info_addr
POPFD
POPAD
}
if (success != 1) {
return -4;
}
WeChatString *file_name = (WeChatString *)((DWORD)xml_app_msg + 0x44);
save_path = save_path +L"\\" + to_wstring(msg_id) + L"_" +
wstring(file_name->ptr, file_name->length);
break;
}
default:
break;
}
WeChatString w_save_path(save_path);
WeChatString w_thumb_path(thumb_path);
int temp =1;
memcpy(&chat_msg[0x19C], &w_thumb_path, sizeof(w_thumb_path));
memcpy(&chat_msg[0x1B0], &w_save_path, sizeof(w_save_path));
memcpy(&chat_msg[0x29C], &temp, sizeof(temp));
// note the image has been downloaded and will not be downloaded again
// use low-level method
// this function does not work, need to modify chatmsg.
// if (type == 0x3E || type == 0x2B){
// __asm{
// PUSHAD
// PUSHFD
// CALL video_mgr_addr
// LEA ECX,chat_msg
// PUSH ECX
// MOV ECX,EAX
// CALL download_video_image_addr
// POPFD
// POPAD
// }
// }
__asm {
PUSHAD
PUSHFD
CALL pre_download_mgr_addr
PUSH 0x1
PUSH 0x0
LEA ECX,chat_msg
PUSH ECX
MOV ECX,EAX
CALL push_attach_task_addr
MOV success,EAX
LEA ECX,chat_msg
PUSH 0x0
CALL free_addr
POPFD
POPAD
}
return success;
}
int MiscMgr::GetVoice(ULONG64 msg_id, wchar_t *dir) {
int success = -1;
string buff = DB::GetInstance().GetVoiceBuffByMsgId(msg_id);
if (buff.size() == 0) {
success = 0;
return success;
}
wstring save_path = wstring(dir);
if (!Utils::FindOrCreateDirectoryW(save_path.c_str())) {
success = -2;
return success;
}
save_path = save_path + L"\\" + to_wstring(msg_id) + L".amr";
HANDLE file_handle = CreateFileW(save_path.c_str(), GENERIC_ALL, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (file_handle == INVALID_HANDLE_VALUE) {
#ifdef _DEBUG
wcout <<" save_path =" <<save_path<<endl;
#endif
return success;
}
DWORD bytes_write = 0;
string decode = base64_decode(buff);
WriteFile(file_handle, (LPCVOID)decode.c_str(), decode.size(), &bytes_write, 0);
CloseHandle(file_handle);
success = 1;
return success;
}
int MiscMgr::GetImgByName(wchar_t* file_path,wchar_t* save_dir) {
wstring save_path(save_dir);
wstring orign_file_path(file_path);
if (!Utils::FindOrCreateDirectoryW(save_path.c_str())) {
return 0;
}
int pos_begin = orign_file_path.find_last_of(L"\\") + 1;
int pos_end = orign_file_path.find_last_of(L".");
wstring file_name = orign_file_path.substr(pos_begin, pos_end - pos_begin);
HANDLE h_origin_file =
CreateFileW(file_path, GENERIC_READ, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
char buffer[BUFSIZE] = {0};
DWORD bytes_read = 0;
DWORD bytes_write = 0;
unsigned char magic_head[4] = {0};
wstring suffix;
short key = 0;
if (ReadFile(h_origin_file, buffer, BUFSIZE, &bytes_read, NULL)) {
memcpy(magic_head, buffer, 3);
} else {
CloseHandle(h_origin_file);
return 0;
}
if ((magic_head[0] ^ JPEG0) == (magic_head[1] ^ JPEG1)) {
key = magic_head[0] ^ JPEG0;
suffix = L".jpg";
} else if ((magic_head[0] ^ PNG1) == (magic_head[1] ^ PNG2)) {
key = magic_head[0] ^ PNG1;
suffix = L".png";
} else if ((magic_head[0] ^ GIF0) == (magic_head[1] ^ GIF1)) {
key = magic_head[0] ^ GIF0;
suffix = L".gif";
} else if ((magic_head[0] ^ BMP0) == (magic_head[1] ^ BMP1)) {
key = magic_head[0] ^ BMP0;
suffix = L".bmp";
} else {
key = -1;
suffix = L".dat";
}
wstring save_img_path = save_path + L"\\" + file_name + suffix;
HANDLE save_img = CreateFileW(save_img_path.c_str(), GENERIC_ALL, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (save_img == INVALID_HANDLE_VALUE) {
return 0;
}
if (key > 0) {
for (unsigned int i = 0; i < bytes_read; i++) {
buffer[i]^=key;
}
}
if (!WriteFile(save_img, (LPCVOID)buffer, bytes_read, &bytes_write, 0)) {
CloseHandle(h_origin_file);
CloseHandle(save_img);
return 0;
}
do {
if (ReadFile(h_origin_file, buffer, BUFSIZE, &bytes_read, NULL)) {
if (key > 0) {
for (unsigned int i = 0; i < bytes_read; i++) {
buffer[i] ^= key;
}
}
if (!WriteFile(save_img, (LPCVOID)buffer, bytes_read, &bytes_write, 0)) {
CloseHandle(h_origin_file);
CloseHandle(save_img);
return 0;
}
}
} while (bytes_read == BUFSIZE);
CloseHandle(h_origin_file);
CloseHandle(save_img);
return 1;
}
int MiscMgr::SearchContactNetScene(wchar_t *keyword,UserInfo ** user) {
int success = -1;
hooks::HookSearchContact();
hooks::DeleteUserInfoCache();
DWORD search_contact_mgr_addr = base_addr_ + WX_SEARCH_CONTACT_MGR_OFFSET;
DWORD search_contact_addr = base_addr_ + WX_SEARCH_CONTACT_OFFSET;
WeChatString key(keyword);
__asm {
pushad;
pushfd;
call search_contact_mgr_addr;
lea ebx, key;
push ebx;
mov ecx, eax;
call search_contact_addr;
popfd;
popad;
}
success = 1;
while (hooks::userinfo.error_code == 1 && hooks::user_info_flag_) {
Sleep(20);
}
if (hooks::userinfo.error_code == 0) {
while (hooks::userinfo.over == false && hooks::user_info_flag_) {
Sleep(20);
}
}
*user= &hooks::userinfo;
LOG(INFO)<<"user:" <<user;
return success;
}
} // namespace wxhelper

24
src/misc_mgr.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef WXHELPER_MISC_MGR_H_
#define WXHELPER_MISC_MGR_H_
#include <string>
#include "Windows.h"
#include "base_mgr.h"
#include "wechat_function.h"
namespace wxhelper {
class MiscMgr :public BaseMgr{
public:
MiscMgr(DWORD base);
~MiscMgr();
int SendPatMsg(wchar_t* chat_room_id, wchar_t* wxid);
int DoOCRTask(wchar_t* img_path, std::string& result);
int DoConfirmReceipt(wchar_t* wxid, wchar_t* transcationid,
wchar_t* transferid);
int DoDownloadTask(ULONG64 msg_id);
int GetVoice(ULONG64 msg_id, wchar_t* dir);
int GetImgByName(wchar_t* file_path,wchar_t* save_dir);
int SearchContactNetScene(wchar_t *keyword,UserInfo ** user);
};
} // namespace wxhelper
#endif

View File

@ -1,64 +0,0 @@
#include "pch.h"
#include "ocr.h"
#include "common.h"
#include "wechat_data.h"
#define WX_INIT_OBJ_OFFSET 0x7a98f0
#define WX_OCR_MANAGER_OFFSET 0x7ae470
#define WX_DO_OCR_TASK_OFFSET 0x13230c0
using namespace std;
int DoOCRTask(wchar_t *img_path, std::string &result) {
int success = -1;
WeChatString path(img_path);
WeChatString null_obj = {0};
WeChatString ocr_result = {0};
DWORD base = GetWeChatWinBase();
DWORD ocr_manager_addr = base + WX_OCR_MANAGER_OFFSET;
DWORD do_ocr_task_addr = base + WX_DO_OCR_TASK_OFFSET;
DWORD init_addr = base + WX_INIT_OBJ_OFFSET;
DWORD flag = 0;
__asm {
PUSHAD
PUSHFD
LEA ECX,ocr_result
CALL init_addr
CALL ocr_manager_addr
LEA ECX,null_obj
PUSH ECX
LEA ECX,flag
PUSH ECX
LEA ECX,ocr_result
PUSH ECX
PUSH 0x0
LEA ECX,path
PUSH ECX
MOV ECX,EAX
CALL do_ocr_task_addr
MOV success,EAX
POPFD
POPAD
}
if (success == 0) {
DWORD addr = (DWORD)&ocr_result;
DWORD ptr = *(DWORD *)addr;
DWORD num = *(DWORD *)(addr + 0x4);
if (num <= 0) {
return success;
}
DWORD header = *(DWORD *)ptr;
for (unsigned int i = 0; i < num -1; i++) {
DWORD content = *(DWORD *)header;
result += unicode_to_utf8((wchar_t *)READ_WSTRING(content, 0x14).c_str());
header = content;
}
#ifdef _DEBUG
cout << "num:" << num << endl;
cout << "all:" << result << endl;
#endif
}
return success;
}

View File

@ -1,5 +0,0 @@
#ifndef OCR_H_
#define OCR_H_
#include <string>
int DoOCRTask(wchar_t* img_path,std::string &result);
#endif

View File

@ -1,34 +0,0 @@
#include "pch.h"
#include "pat.h"
#include "common.h"
#include "wechat_data.h"
#define WX_PAT_MGR_OFFSET 0x931730
#define WX_SEND_PAT_MSG_OFFSET 0x1421940
#define WX_RET_OFFSET 0x1D58751
int SendPatMsg(wchar_t* chat_room_id, wchar_t* wxid) {
int success = -1;
WeChatString chat_room(chat_room_id);
WeChatString self_wxid(wxid);
DWORD base = GetWeChatWinBase();
DWORD get_pat_mgr_addr = base + WX_PAT_MGR_OFFSET;
DWORD send_pat_msg_addr = base + WX_SEND_PAT_MSG_OFFSET;
DWORD ret_addr = base + WX_RET_OFFSET;
__asm {
PUSHAD
CALL get_pat_mgr_addr
PUSH ret_addr
PUSH 0x0
PUSH EAX
LEA ECX,chat_room
LEA EDX,self_wxid
CALL send_pat_msg_addr
ADD ESP,0xc
MOVZX EAX,AL
MOV success,EAX
POPAD
}
return success;
}

View File

@ -1,4 +0,0 @@
#ifndef PAT_H_
#define PAT_H_
int SendPatMsg(wchar_t* chat_room_id,wchar_t* wxid);
#endif

View File

@ -9,10 +9,14 @@
#include <map>
#include <strstream>
#include <string>
#include <optional>
#include <sstream>
#include <fstream>
#include <time.h>
#include <fcntl.h>
#include "Windows.h"
#include "utils.h"
#endif // PCH_H

View File

@ -1,275 +0,0 @@
#include "pch.h"
#include "search_contact.h"
#include "common.h"
#include "wechat_data.h"
#define WX_SEARCH_CONTACT_ERROR_CODE_HOOK_OFFSeT 0xd94d1e
#define WX_SEARCH_CONTACT_ERROR_CODE_HOOK_NEXT_OFFSeT 0xed13a0
#define WX_SEARCH_CONTACT_DETAIL_HOOK_OFFSeT 0xa2a260
#define WX_SEARCH_CONTACT_DETAIL_HOOK_NEXT_OFFSeT 0xa2a4c0
#define WX_SEARCH_CONTACT_OFFSeT 0xc5bb00
#define WX_SEARCH_CONTACT_MGR_OFFSeT 0xa0d550
static BOOL kSearchContactHooked = false;
static char kHookSearchContactErrcodeOldAsm[5] = {0};
static char kHookUserInfoOldAsm[5] = {0};
static DWORD kWeChatWinBase = GetWeChatWinBase();
static DWORD kHookSearchContactErrcodeNextAddr =
kWeChatWinBase + WX_SEARCH_CONTACT_ERROR_CODE_HOOK_NEXT_OFFSeT;
static DWORD kHookSearchContactErrcodeAddr =
kWeChatWinBase + WX_SEARCH_CONTACT_ERROR_CODE_HOOK_OFFSeT;
static DWORD kHookSearchContactErrcodeJmpBackAddr =
kHookSearchContactErrcodeAddr + 0x5;
static DWORD kHookUserInfoNextAddr =
kWeChatWinBase + WX_SEARCH_CONTACT_DETAIL_HOOK_NEXT_OFFSeT;
static DWORD kHookUserInfoAddr =
kWeChatWinBase + WX_SEARCH_CONTACT_DETAIL_HOOK_OFFSeT;
static DWORD kHookUserInfoJmpBackAddr = kHookUserInfoAddr + 0x5;
static UserInfo userinfo;
void SetErrorCode(int code) { userinfo.error_code = code; }
void SetUserInfoDetail(DWORD address) {
DWORD length = *(DWORD *)(address + 0x8);
userinfo.keyword = new wchar_t[length + 1];
userinfo.keyword_len = length;
if (length) {
memcpy(userinfo.keyword, (wchar_t *)(*(DWORD *)(address + 0x4)),
(length + 1) * sizeof(wchar_t));
} else {
ZeroMemory(userinfo.keyword, (length + 1) * sizeof(wchar_t));
}
length = *(DWORD *)(address + 0x1C);
userinfo.v3 = new wchar_t[length + 1];
userinfo.v3_len = length;
if (length) {
memcpy(userinfo.v3, (wchar_t *)(*(DWORD *)(address + 0x18)),
(length + 1) * sizeof(wchar_t));
}else {
ZeroMemory(userinfo.v3, (length + 1) * sizeof(wchar_t));
}
length = *(DWORD *)(address + 0x30);
userinfo.big_image = new wchar_t[length + 1];
userinfo.big_image_len = length;
if (length) {
memcpy(userinfo.big_image, (wchar_t *)(*(DWORD *)(address + 0x2C)),
(length + 1) * sizeof(wchar_t));
} else {
ZeroMemory(userinfo.big_image, (length + 1) * sizeof(wchar_t));
}
length = *(DWORD *)(address + 0xC8);
userinfo.nickname = new wchar_t[length + 1];
userinfo.nickname_len = length;
if (length) {
memcpy(userinfo.nickname, (wchar_t *)(*(DWORD *)(address + 0xC4)),
(length + 1) * sizeof(wchar_t));
}else {
ZeroMemory(userinfo.nickname, (length + 1) * sizeof(wchar_t));
}
length = *(DWORD *)(address + 0x108);
userinfo.v2 = new wchar_t[length + 1];
userinfo.v2_len = length;
if (length) {
memcpy(userinfo.v2, (wchar_t *)(*(DWORD *)(address + 0x104)),
(length + 1) * sizeof(wchar_t));
}else {
ZeroMemory(userinfo.v2, (length + 1) * sizeof(wchar_t));
}
length = *(DWORD *)(address + 0x16C);
userinfo.small_image = new wchar_t[length + 1];
userinfo.small_image_len = length;
if (length) {
memcpy(userinfo.small_image, (wchar_t *)(*(DWORD *)(address + 0x168)),
(length + 1) * sizeof(wchar_t));
}else {
ZeroMemory(userinfo.small_image, (length + 1) * sizeof(wchar_t));
}
length = *(DWORD *)(address + 0x1F8);
userinfo.signature = new wchar_t[length + 1];
userinfo.signature_len = length;
if (length) {
memcpy(userinfo.signature, (wchar_t *)(*(DWORD *)(address + 0x1F4)),
(length + 1) * sizeof(wchar_t));
} else {
ZeroMemory(userinfo.signature, (length + 1) * sizeof(wchar_t));
}
length = *(DWORD *)(address + 0x20C);
userinfo.nation = new wchar_t[length + 1];
userinfo.nation_len = length;
if (length) {
memcpy(userinfo.nation, (wchar_t *)(*(DWORD *)(address + 0x208)),
(length + 1) * sizeof(wchar_t));
} else {
ZeroMemory(userinfo.nation, (length + 1) * sizeof(wchar_t));
}
length = *(DWORD *)(address + 0x220);
userinfo.province = new wchar_t[length + 1];
userinfo.province_len = length;
if (length) {
memcpy(userinfo.province, (wchar_t *)(*(DWORD *)(address + 0x21C)),
(length + 1) * sizeof(wchar_t));
} else {
ZeroMemory(userinfo.province, (length + 1) * sizeof(wchar_t));
}
length = *(DWORD *)(address + 0x234);
userinfo.city = new wchar_t[length + 1];
userinfo.city_len = length;
if (length) {
memcpy(userinfo.city, (wchar_t *)(*(DWORD *)(address + 0x230)),
(length + 1) * sizeof(wchar_t));
} else {
ZeroMemory(userinfo.city, (length + 1) * sizeof(wchar_t));
}
userinfo.sex = *(DWORD *)(address + 0x1BC);
userinfo.over = true;
}
static void DeleteUserInfoCache() {
if (userinfo.keyword) {
delete userinfo.keyword;
}
if (userinfo.v2) {
delete userinfo.v2;
}
if (userinfo.v3) {
delete userinfo.v3;
}
if (userinfo.nickname) {
delete userinfo.nickname;
}
if (userinfo.nation) {
delete userinfo.nation;
}
if (userinfo.province) {
delete userinfo.province;
}
if (userinfo.city) {
delete userinfo.city;
}
if (userinfo.signature) {
delete userinfo.signature;
}
if (userinfo.small_image) {
delete userinfo.small_image;
}
if (userinfo.big_image) {
delete userinfo.big_image;
}
ZeroMemory(&userinfo, sizeof(UserInfo));
userinfo.error_code = 1;
}
__declspec(naked) void HandleErrorCode() {
__asm {
pushad;
pushfd;
push edi;
call SetErrorCode;
add esp, 0x4;
popfd;
popad;
call kHookSearchContactErrcodeNextAddr;
jmp kHookSearchContactErrcodeJmpBackAddr;
}
}
__declspec(naked) void HandleUserInfoDetail() {
__asm {
pushad;
pushfd;
push dword ptr [ebp + 0x14];
call SetUserInfoDetail;
add esp, 0x4;
popfd;
popad;
call kHookUserInfoNextAddr;
jmp kHookUserInfoJmpBackAddr;
}
}
int SearchContactNetScene(wchar_t *keyword,UserInfo ** user) {
int success = -1;
HookSearchContact();
DeleteUserInfoCache();
DWORD base = GetWeChatWinBase();
DWORD search_contact_mgr_addr = base + WX_SEARCH_CONTACT_MGR_OFFSeT;
DWORD search_contact_addr = base + WX_SEARCH_CONTACT_OFFSeT;
WeChatString key(keyword);
__asm {
pushad;
pushfd;
call search_contact_mgr_addr;
lea ebx, key;
push ebx;
mov ecx, eax;
call search_contact_addr;
popfd;
popad;
}
success = 1;
while (userinfo.error_code == 1 && kSearchContactHooked) {
Sleep(20);
}
if (userinfo.error_code == 0) {
while (userinfo.over == false && kSearchContactHooked) {
Sleep(20);
}
}
*user= &userinfo;
return success;
}
int HookSearchContact() {
kWeChatWinBase = GetWeChatWinBase();
if (!kWeChatWinBase) {
return -1;
}
if (kSearchContactHooked) {
return 2;
}
kHookSearchContactErrcodeNextAddr =
kWeChatWinBase + WX_SEARCH_CONTACT_ERROR_CODE_HOOK_NEXT_OFFSeT;
kHookSearchContactErrcodeAddr =
kWeChatWinBase + WX_SEARCH_CONTACT_ERROR_CODE_HOOK_OFFSeT;
kHookSearchContactErrcodeJmpBackAddr = kHookSearchContactErrcodeAddr + 0x5;
kHookUserInfoNextAddr =
kWeChatWinBase + WX_SEARCH_CONTACT_DETAIL_HOOK_NEXT_OFFSeT;
kHookUserInfoAddr = kWeChatWinBase + WX_SEARCH_CONTACT_DETAIL_HOOK_OFFSeT;
kHookUserInfoJmpBackAddr = kHookUserInfoAddr + 0x5;
HookAnyAddress(kHookSearchContactErrcodeAddr,
(LPVOID)HandleErrorCode,
kHookSearchContactErrcodeOldAsm);
HookAnyAddress(kHookUserInfoAddr, (LPVOID)HandleUserInfoDetail, kHookUserInfoOldAsm);
kSearchContactHooked = true;
return 1;
}
int UnHookSearchContact() {
if (!kSearchContactHooked) return 2;
UnHookAnyAddress(kHookSearchContactErrcodeAddr,
kHookSearchContactErrcodeOldAsm);
UnHookAnyAddress(kHookUserInfoAddr, kHookUserInfoOldAsm);
kSearchContactHooked = false;
return 1;
}

View File

@ -1,8 +0,0 @@
#ifndef SEARCH_CONTACT_H_
#define SEARCH_CONTACT_H_
#include "wechat_data.h"
int SearchContactNetScene(wchar_t *keyword,UserInfo ** user);
int HookSearchContact();
int UnHookSearchContact();
#endif

View File

@ -1,9 +0,0 @@
#ifndef SELF_INFO_H_
#define SELF_INFO_H_
#include "wechat_data.h"
int GetSelfInfo(SelfInfoInner& out);
int CheckLogin();
int Logout();
#endif

View File

@ -1,67 +0,0 @@
#include "pch.h"
#include "send_file.h"
#include "common.h"
#include "wechat_data.h"
#define WX_APP_MSG_MGR_OFFSET 0x76ae20
#define WX_SEND_FILE_OFFSET 0xb6d1f0
#define WX_INIT_CHAT_MSG_OFFSET 0xf59e40
#define WX_FREE_CHAT_MSG_OFFSET 0x756960
int SendFile(wchar_t *wxid, wchar_t *file_path){
int success = 0;
WeChatString to_user(wxid);
WeChatString path(file_path);
char chat_msg[0x2D8] = {0};
DWORD base = GetWeChatWinBase();
DWORD app_msg_mgr_addr = base + WX_APP_MSG_MGR_OFFSET;
DWORD init_chat_msg_addr = base + WX_INIT_CHAT_MSG_OFFSET;
DWORD send_file_addr = base + WX_SEND_FILE_OFFSET;
DWORD free_msg_addr = base + WX_FREE_CHAT_MSG_OFFSET;
DWORD temp = 0;
WeChatString null_obj = {0};
__asm{
PUSHAD
PUSHFD
CALL app_msg_mgr_addr
SUB ESP,0x14
MOV temp,EAX
LEA EAX,null_obj
MOV ECX,ESP
PUSH EAX
CALL init_chat_msg_addr
PUSH 0x0
SUB ESP,0x14
MOV EDI,ESP
MOV dword ptr [EDI],0
MOV dword ptr [EDI + 0x4],0
MOV dword ptr [EDI + 0x8],0
MOV dword ptr [EDI + 0xc],0
MOV dword ptr [EDI + 0x10],0
SUB ESP,0x14
LEA EAX,path
MOV ECX,ESP
PUSH EAX
CALL init_chat_msg_addr
SUB ESP,0x14
LEA EAX,to_user
MOV ECX,ESP
PUSH EAX
CALL init_chat_msg_addr
MOV ECX,dword ptr [temp]
LEA EAX,chat_msg
PUSH EAX
CALL send_file_addr
MOV AL,byte ptr [eax + 0x38]
MOVZX EAX,AL
MOV success,EAX
LEA ECX,chat_msg
CALL free_msg_addr
POPFD
POPAD
}
if (success == 0x31){
return 1;
}
return 0;
}

View File

@ -1,5 +0,0 @@
#ifndef SEND_FILE_H_
#define SEND_FILE_H_
int SendFile(wchar_t *wxid, wchar_t *file_path);
#endif

View File

@ -1,46 +0,0 @@
#include "pch.h"
#include "send_image.h"
#include "common.h"
#include "wechat_data.h"
#define WX_SEND_IMAGE_OFFSET 0xce6640
#define WX_SEND_MESSAGE_MGR_OFFSET 0x768140
#define WX_INIT_CHAT_MSG_OFFSET 0xf59e40
#define WX_FREE_CHAT_MSG_OFFSET 0x756960
int SendImage(wchar_t *wxid, wchar_t *image_path){
int success = 0;
WeChatString to_user(wxid);
WeChatString path(image_path);
char chat_msg[0x2D8] ={0};
DWORD base = GetWeChatWinBase();
DWORD send_message_mgr_addr = base + WX_SEND_MESSAGE_MGR_OFFSET;
DWORD init_chat_msg_addr = base + WX_INIT_CHAT_MSG_OFFSET;
DWORD send_image_msg_addr = base + WX_SEND_IMAGE_OFFSET;
DWORD free_msg_addr = base + WX_FREE_CHAT_MSG_OFFSET;
DWORD temp = 0;
WeChatString null_obj = {0};
__asm{
PUSHAD
CALL send_message_mgr_addr
SUB ESP,0x14
MOV temp,EAX
LEA EAX,null_obj
MOV ECX,ESP
LEA EDI,path
PUSH EAX
CALL init_chat_msg_addr
MOV ECX,dword ptr [temp]
LEA EAX,to_user
PUSH EDI
PUSH EAX
LEA EAX,chat_msg
PUSH EAX
CALL send_image_msg_addr
MOV success,EAX
LEA ECX,chat_msg
CALL free_msg_addr
POPAD
}
return success;
}

View File

@ -1,5 +0,0 @@
#ifndef SEND_IMAGE_H_
#define SEND_IMAGE_H_
int SendImage(wchar_t *wxid, wchar_t *image_path);
#endif

178
src/send_message_mgr.cc Normal file
View File

@ -0,0 +1,178 @@
#include "pch.h"
#include "send_message_mgr.h"
#include "easylogging++.h"
#include "wechat_function.h"
#include "db.h"
namespace wxhelper {
SendMessageMgr::SendMessageMgr(DWORD base):BaseMgr(base) {}
SendMessageMgr::~SendMessageMgr() {}
int SendMessageMgr::SendText(wchar_t* wxid, wchar_t* msg) {
int success = -1;
WeChatString to_user(wxid);
WeChatString text_msg(msg);
wchar_t** msg_pptr = &text_msg.ptr;
DWORD base = Utils::GetWeChatWinBase();
DWORD send_message_mgr_addr = base + WX_SEND_MESSAGE_MGR_OFFSET;
DWORD send_text_msg_addr = base + WX_SEND_TEXT_OFFSET;
DWORD free_chat_msg_addr = base + WX_FREE_CHAT_MSG_OFFSET;
char chat_msg[0x2D8] = {0};
__asm {
PUSHAD
CALL send_message_mgr_addr
PUSH 0x0
PUSH 0x0
PUSH 0x0
PUSH 0x1
PUSH 0x0
MOV EAX,msg_pptr
PUSH EAX
LEA EDX,to_user
LEA ECX,chat_msg
CALL send_text_msg_addr
MOV success,EAX
ADD ESP,0x18
LEA ECX,chat_msg
CALL free_chat_msg_addr
POPAD
}
LOG_IF((success == -1), ERROR) << "SendText fail";
return success;
}
int SendMessageMgr::SendAtText(wchar_t* chat_room_id, wchar_t** wxids, int len,
wchar_t* msg) {
int success = -1;
return success;
}
int SendMessageMgr::SendImage(wchar_t* wxid, wchar_t* image_path) {
int success = -1;
WeChatString to_user(wxid);
WeChatString path(image_path);
char chat_msg[0x2D8] = {0};
DWORD base = Utils::GetWeChatWinBase();
DWORD send_message_mgr_addr = base + WX_SEND_MESSAGE_MGR_OFFSET;
DWORD init_chat_msg_addr = base + WX_INIT_CHAT_MSG_OFFSET;
DWORD send_image_msg_addr = base + WX_SEND_IMAGE_OFFSET;
DWORD free_msg_addr = base + WX_FREE_CHAT_MSG_OFFSET;
DWORD temp = 0;
WeChatString null_obj = {0};
__asm {
PUSHAD
CALL send_message_mgr_addr
SUB ESP,0x14
MOV temp,EAX
LEA EAX,null_obj
MOV ECX,ESP
LEA EDI,path
PUSH EAX
CALL init_chat_msg_addr
MOV ECX,dword ptr [temp]
LEA EAX,to_user
PUSH EDI
PUSH EAX
LEA EAX,chat_msg
PUSH EAX
CALL send_image_msg_addr
MOV success,EAX
LEA ECX,chat_msg
CALL free_msg_addr
POPAD
}
LOG_IF((success == -1), ERROR) << "SendImage fail";
return success;
}
int SendMessageMgr::SendFile(wchar_t* wxid, wchar_t* file_path) {
int success = -1;
WeChatString to_user(wxid);
WeChatString path(file_path);
char chat_msg[0x2D8] = {0};
DWORD base = Utils::GetWeChatWinBase();
DWORD app_msg_mgr_addr = base + WX_APP_MSG_MGR_OFFSET;
DWORD init_chat_msg_addr = base + WX_INIT_CHAT_MSG_OFFSET;
DWORD send_file_addr = base + WX_SEND_FILE_OFFSET;
DWORD free_msg_addr = base + WX_FREE_CHAT_MSG_OFFSET;
DWORD temp = 0;
WeChatString null_obj = {0};
__asm {
PUSHAD
PUSHFD
CALL app_msg_mgr_addr
SUB ESP,0x14
MOV temp,EAX
LEA EAX,null_obj
MOV ECX,ESP
PUSH EAX
CALL init_chat_msg_addr
PUSH 0x0
SUB ESP,0x14
MOV EDI,ESP
MOV dword ptr [EDI],0
MOV dword ptr [EDI + 0x4],0
MOV dword ptr [EDI + 0x8],0
MOV dword ptr [EDI + 0xc],0
MOV dword ptr [EDI + 0x10],0
SUB ESP,0x14
LEA EAX,path
MOV ECX,ESP
PUSH EAX
CALL init_chat_msg_addr
SUB ESP,0x14
LEA EAX,to_user
MOV ECX,ESP
PUSH EAX
CALL init_chat_msg_addr
MOV ECX,dword ptr [temp]
LEA EAX,chat_msg
PUSH EAX
CALL send_file_addr
MOV AL,byte ptr [eax + 0x38]
MOVZX EAX,AL
MOV success,EAX
LEA ECX,chat_msg
CALL free_msg_addr
POPFD
POPAD
}
if (success == 0x31) {
return 1;
}
LOG_IF((success == -1), ERROR) << "SendFile fail";
return success;
}
int SendMessageMgr::ForwardMsg(wchar_t* wxid, unsigned long long msgid) {
int success = 0;
int db_index = 0;
int localid = DB::GetInstance().GetLocalIdByMsgId(msgid, db_index);
if (localid == 0) return 0;
WeChatString to_user(wxid);
DWORD base = Utils::GetWeChatWinBase();
DWORD forward_msg_addr = base + WX_FORWARD_MSG_OFFSET;
DWORD init_chat_msg_addr = base + WX_INIT_CHAT_MSG_OFFSET;
__asm {
PUSHAD
PUSHFD
MOV EDX, DWORD PTR [db_index]
PUSH EDX
MOV EAX, DWORD PTR [localid]
PUSH EAX
SUB ESP,0x14
MOV ECX,ESP
LEA ESI,to_user
PUSH ESI
CALL init_chat_msg_addr
XOR ECX,ECX
CALL forward_msg_addr
MOVZX EAX,AL
MOV success,EAX
ADD ESP,0x1c
POPFD
POPAD
}
return success;
}
} // namespace wxhelper

18
src/send_message_mgr.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef WXHELPER_SEND_MESSAGE_MGR_H_
#define WXHELPER_SEND_MESSAGE_MGR_H_
#include "base_mgr.h"
namespace wxhelper {
class SendMessageMgr:public BaseMgr {
public:
explicit SendMessageMgr(DWORD base);
~SendMessageMgr();
int SendText(wchar_t* wxid, wchar_t* msg);
int SendAtText(wchar_t* chat_room_id, wchar_t** wxids, int len, wchar_t* msg);
int SendImage(wchar_t *wxid, wchar_t *image_path);
int SendFile(wchar_t *wxid, wchar_t *file_path);
int ForwardMsg(wchar_t *wxid, unsigned long long msgid);
private:
};
} // namespace wxhelper
#endif

View File

@ -1,118 +0,0 @@
#include "pch.h"
#include "send_text.h"
#include "common.h"
#include "wechat_data.h"
#include "contact.h"
#define WX_SEND_TEXT_OFFSET 0xce6c80
#define WX_SEND_MESSAGE_MGR_OFFSET 0x768140
#define WX_FREE_CHAT_MSG_OFFSET 0x756960
using namespace std;
/// @brief 发生文本消息
/// @param wxid wxid
/// @param msg 文本消息
/// @return 成功返回1
int SendText(wchar_t* wxid, wchar_t* msg) {
int success = 0;
WeChatString to_user(wxid);
WeChatString text_msg(msg);
wchar_t **msg_pptr = &text_msg.ptr;
DWORD base = GetWeChatWinBase();
DWORD send_message_mgr_addr = base + WX_SEND_MESSAGE_MGR_OFFSET;
DWORD send_text_msg_addr = base + WX_SEND_TEXT_OFFSET;
DWORD free_chat_msg_addr = base + WX_FREE_CHAT_MSG_OFFSET;
char chat_msg[0x2D8] ={0};
__asm{
PUSHAD
CALL send_message_mgr_addr
PUSH 0x0
PUSH 0x0
PUSH 0x0
PUSH 0x1
PUSH 0x0
MOV EAX,msg_pptr
PUSH EAX
LEA EDX,to_user
LEA ECX,chat_msg
CALL send_text_msg_addr
MOV success,EAX
ADD ESP,0x18
LEA ECX,chat_msg
CALL free_chat_msg_addr
POPAD
}
return success;
}
int SendAtText(wchar_t* chat_room_id,wchar_t** wxids,int len,wchar_t* msg){
int success = -1;
WeChatString * at_users = new WeChatString[len+1];
wstring at_msg = L"";
int number =0;
for (int i = 0; i < len; i++) {
wstring nickname;
if (!lstrcmpiW((wchar_t *)wxids[i], (wchar_t *)L"notify@all")) {
nickname = L"<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>";
} else {
nickname = GetContactOrChatRoomNickname(wxids[i]);
}
if (nickname.length() == 0) {
continue;
}
WeChatString temp = {0};
temp.ptr = (wchar_t *)wxids[i];
temp.length = wcslen((wchar_t *)wxids[i]);
temp.max_length = wcslen((wchar_t *)wxids[i]) * 2;
memcpy(&at_users[number], &temp, sizeof(WeChatString));
at_msg = at_msg + L"@" + nickname + L" ";
number++;
}
if (number < 1){
return success;
}
wstring origin(msg);
at_msg += origin;
AtInner at_list = {0};
at_list.start = (DWORD)at_users;
at_list.finsh = (DWORD)&at_users[number];
at_list.end = (DWORD)&at_users[number];
WeChatString to_user(chat_room_id);
WeChatString text_msg((wchar_t *)at_msg.c_str());
wchar_t **msg_pptr = &text_msg.ptr;
DWORD base = GetWeChatWinBase();
DWORD send_message_mgr_addr = base + WX_SEND_MESSAGE_MGR_OFFSET;
DWORD send_text_msg_addr = base + WX_SEND_TEXT_OFFSET;
DWORD free_chat_msg_addr = base + WX_FREE_CHAT_MSG_OFFSET;
char chat_msg[0x2C4] ={0};
__asm{
PUSHAD
CALL send_message_mgr_addr
PUSH 0x0
PUSH 0x0
PUSH 0x0
PUSH 0x1
LEA EAX,at_list
PUSH EAX
MOV EAX,msg_pptr
PUSH EAX
LEA EDX,to_user
LEA ECX,chat_msg
CALL send_text_msg_addr
MOV success,EAX
ADD ESP,0x18
LEA ECX,chat_msg
CALL free_chat_msg_addr
POPAD
}
return success;
}

View File

@ -1,6 +0,0 @@
#ifndef SEND_TEXT_H_
#define SEND_TEXT_H_
int SendText(wchar_t* wxid, wchar_t* msg);
int SendAtText(wchar_t* chat_room_id,wchar_t** wxids,int len,wchar_t* msg);
#endif

21
src/singleton.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef WXHELPER_SINGLETON_H_
#define WXHELPER_SINGLETON_H_
template <typename T>
class Singleton {
protected:
Singleton() {}
~Singleton() {}
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
Singleton(Singleton&&) = delete;
Singleton& operator=(Singleton&&) = delete;
public:
static T& GetInstance() {
static T instance{};
return instance;
}
};
#endif

View File

@ -1,6 +0,0 @@
#ifndef SNS_H_
#define SNS_H_
int GetFirstPage();
int GetNextPage(ULONG64 sns_id);
#endif

View File

@ -1,18 +1,17 @@
#include "pch.h"
#include "sns.h"
#include "pch.h"
#include "sns_mgr.h"
#include "common.h"
#include "wechat_data.h"
using namespace std;
#define WX_SNS_DATA_MGR_OFFSET 0xc39680
#define WX_SNS_GET_FIRST_PAGE_OFFSET 0x14e2140
#define WX_SNS_GET_NEXT_PAGE_OFFSET 0x14e21e0
int GetFirstPage() {
#include "wechat_function.h"
namespace wxhelper {
SNSMgr::SNSMgr(DWORD base):BaseMgr(base) {}
SNSMgr::~SNSMgr() {}
int SNSMgr::GetFirstPage() {
int success = -1;
DWORD base = GetWeChatWinBase();
DWORD sns_data_mgr_addr = base + WX_SNS_DATA_MGR_OFFSET;
DWORD get_first_page_addr = base + WX_SNS_GET_FIRST_PAGE_OFFSET;
DWORD sns_data_mgr_addr = base_addr_ + WX_SNS_DATA_MGR_OFFSET;
DWORD get_first_page_addr = base_addr_ + WX_SNS_GET_FIRST_PAGE_OFFSET;
char buff[0xB44] = {};
__asm {
@ -29,15 +28,12 @@ int GetFirstPage() {
return success;
}
int GetNextPage(ULONG64 sns_id) {
int SNSMgr::GetNextPage(ULONG64 sns_id) {
int success = -1;
DWORD base = GetWeChatWinBase();
DWORD sns_data_mgr_addr = base + WX_SNS_DATA_MGR_OFFSET;
DWORD get_next_page_addr = base + WX_SNS_GET_NEXT_PAGE_OFFSET;
DWORD sns_data_mgr_addr = base_addr_ + WX_SNS_DATA_MGR_OFFSET;
DWORD get_next_page_addr = base_addr_ + WX_SNS_GET_NEXT_PAGE_OFFSET;
VectorInner temp = {};
__asm{
__asm {
PUSHAD
CALL sns_data_mgr_addr
LEA ECX,temp
@ -53,3 +49,4 @@ int GetNextPage(ULONG64 sns_id) {
}
return success;
}
} // namespace wxhelper

14
src/sns_mgr.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef WXHELPER_SNS_MGR_H_
#define WXHELPER_SNS_MGR_H_
#include "Windows.h"
#include "base_mgr.h"
namespace wxhelper{
class SNSMgr:public BaseMgr{
public:
explicit SNSMgr(DWORD base);
~SNSMgr();
int GetFirstPage();
int GetNextPage(ULONG64 sns_id);
};
}
#endif

View File

@ -1,51 +1,43 @@
#include "pch.h"
#include "common.h"
#include "pch.h"
#include "utils.h"
using namespace std;
/// @brief utf8 转换成unicode
/// @param buffer utf8
/// @return unicode
wstring utf8_to_unicode(const char *buffer) {
int c_size = MultiByteToWideChar(CP_UTF8, 0, buffer, -1, NULL, 0);
if (c_size > 0) {
wchar_t *temp = new wchar_t[c_size + 1];
MultiByteToWideChar(CP_UTF8, 0, buffer, -1, temp, c_size);
temp[c_size] = L'\0';
wstring ret(temp);
delete[] temp;
temp = NULL;
return ret;
}
return wstring();
namespace wxhelper {
std::wstring Utils::UTF8ToWstring(const std::string &str) {
return Utils::AnsiToWstring(str, CP_UTF8);
}
/// @brief unicode转换utf8
/// @param wstr unicode
/// @return string utf8
string unicode_to_utf8(wchar_t *wstr) {
int c_size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, FALSE);
if (c_size > 0) {
char *buffer = new char[c_size + 1];
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, buffer, c_size, NULL, FALSE);
buffer[c_size] = '\0';
string str(buffer);
delete[] buffer;
buffer = NULL;
return str;
}
return string();
std::string Utils::WstringToUTF8(const std::wstring &str) {
return Utils::WstringToAnsi(str, CP_UTF8);
}
/// @brief 获取WeChatWin.dll基址
/// @return 基址
DWORD GetWeChatWinBase() { return (DWORD)GetModuleHandleA("WeChatWin.dll"); }
std::wstring Utils::AnsiToWstring(const std::string &input, DWORD locale) {
int wchar_len = MultiByteToWideChar(locale, 0, input.c_str(), -1, NULL, 0);
if (wchar_len > 0) {
std::vector<wchar_t> temp(wchar_len);
MultiByteToWideChar(CP_UTF8, 0, input.c_str(), -1, &temp[0], wchar_len);
return std::wstring(&temp[0]);
}
/// @brief 创建窗口
/// @param void
/// @return 创建结果
BOOL CreateConsole(void) {
return std::wstring();
}
std::string Utils::WstringToAnsi(const std::wstring &input, DWORD locale) {
int char_len = WideCharToMultiByte(locale, 0, input.c_str(), -1, 0, 0, 0, 0);
if (char_len > 0) {
std::vector<char> temp(char_len);
WideCharToMultiByte(locale, 0, input.c_str(), -1, &temp[0], char_len, 0, 0);
return std::string(&temp[0]);
}
return std::string();
}
DWORD Utils::GetWeChatWinBase() {
return (DWORD)GetModuleHandleA("WeChatWin.dll");
}
bool Utils::CreateConsole() {
if (AllocConsole()) {
AttachConsole(GetCurrentProcessId());
FILE *retStream;
@ -53,100 +45,21 @@ BOOL CreateConsole(void) {
if (!retStream) throw std::runtime_error("Stdout redirection failed.");
freopen_s(&retStream, "CONOUT$", "w", stderr);
if (!retStream) throw std::runtime_error("Stderr redirection failed.");
return 0;
}
return 1;
}
/// @brief hook any addr
/// @param hook_addr need hook of addr
/// @param jmp_addr hook function addr
/// @param origin origin code
void HookAnyAddress(DWORD hook_addr, LPVOID jmp_addr, char *origin) {
BYTE jmp_code[5] = {0};
jmp_code[0] = 0xE9;
*(DWORD *)&jmp_code[1] = (DWORD)jmp_addr - hook_addr - 5;
DWORD old_protext = 0;
VirtualProtect((LPVOID)hook_addr, 5, PAGE_EXECUTE_READWRITE, &old_protext);
ReadProcessMemory(GetCurrentProcess(), (LPVOID)hook_addr, origin, 5, 0);
memcpy((void *)hook_addr, jmp_code, 5);
VirtualProtect((LPVOID)hook_addr, 5, old_protext, &old_protext);
}
/// @brief unhook
/// @param hook_addr hook addr
/// @param origin origin addr code
void UnHookAnyAddress(DWORD hook_addr, char *origin) {
DWORD old_protext = 0;
VirtualProtect((LPVOID)hook_addr, 5, PAGE_EXECUTE_READWRITE, &old_protext);
WriteProcessMemory(GetCurrentProcess(), (LPVOID)hook_addr, origin, 5, 0);
VirtualProtect((LPVOID)hook_addr, 5, old_protext, &old_protext);
}
/// @brief get timeW
/// @param timestamp timestamp
/// @return str
wstring GetTimeW(long long timestamp) {
wchar_t *wstr = new wchar_t[20];
memset(wstr, 0, 20 * 2);
tm tm_out;
localtime_s(&tm_out, &timestamp);
swprintf_s(wstr, 20, L"%04d-%02d-%02d %02d:%02d:%02d", 1900 + tm_out.tm_year,
tm_out.tm_mon + 1, tm_out.tm_mday, tm_out.tm_hour, tm_out.tm_min,
tm_out.tm_sec);
wstring strTimeW(wstr);
delete[] wstr;
return strTimeW;
}
wstring String2Wstring(string str) {
wstring result;
int len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), NULL, 0);
wchar_t *buffer = new wchar_t[len + 1];
MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), buffer, len);
buffer[len] = '\0';
result.append(buffer);
delete[] buffer;
return result;
}
string Wstring2String(wstring wstr) {
string result;
int len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), NULL, 0,
NULL, NULL);
char *buffer = new char[len + 1];
WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), buffer, len, NULL,
NULL);
buffer[len] = '\0';
result.append(buffer);
delete[] buffer;
return result;
}
BOOL FindOrCreateDirectoryW(const wchar_t *path) {
WIN32_FIND_DATAW fd;
HANDLE hFind = ::FindFirstFileW(path, &fd);
if (hFind != INVALID_HANDLE_VALUE && (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
FindClose(hFind);
return true;
}
if (!::CreateDirectoryW(path, NULL)) {
return false;
}
return true;
}
void CloseConsole(){
void Utils::CloseConsole() {
fclose(stdin);
fclose(stdout);
fclose(stderr);
FreeConsole();
}
std::string EncodeHexString(const std::string &str) {
std::string Utils::EncodeHexString(const std::string &str) {
const std::string hex_table = "0123456789abcdef";
string sb;
std::string sb;
for (int i = 0; i < str.length(); i++) {
sb += hex_table.at((str[i] & 0xf0) >> 4);
sb += hex_table.at((str[i] & 0x0f) >> 0);
@ -154,7 +67,7 @@ std::string EncodeHexString(const std::string &str) {
return sb;
}
std::string Hex2String(const std::string &hex_str) {
std::string Utils::Hex2String(const std::string &hex_str) {
std::string ret;
const std::string hex_table = "0123456789abcdef";
for (int i = 0; i < hex_str.length(); i += 2) {
@ -164,7 +77,7 @@ std::string Hex2String(const std::string &hex_str) {
return ret;
}
std::string Bytes2Hex(const BYTE *bytes, const int length) {
std::string Utils::Bytes2Hex(const BYTE *bytes, const int length) {
if (bytes == NULL) {
return "";
}
@ -178,7 +91,7 @@ std::string Bytes2Hex(const BYTE *bytes, const int length) {
return buff;
}
void Hex2Bytes(const std::string &hex, BYTE *bytes) {
void Utils::Hex2Bytes(const std::string &hex, BYTE *bytes) {
int byte_len = hex.length() / 2;
std::string str;
unsigned int n;
@ -190,7 +103,8 @@ void Hex2Bytes(const std::string &hex, BYTE *bytes) {
}
bool IsDigit(string str) {
bool Utils::IsDigit(std::string str) {
if (str.length() == 0) {
return false;
}
@ -201,3 +115,63 @@ bool IsDigit(string str) {
}
return true;
}
bool Utils::FindOrCreateDirectoryW(const wchar_t *path) {
WIN32_FIND_DATAW fd;
HANDLE hFind = ::FindFirstFileW(path, &fd);
if (hFind != INVALID_HANDLE_VALUE && (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
FindClose(hFind);
return true;
}
if (!::CreateDirectoryW(path, NULL)) {
return false;
}
return true;
}
void Utils::HookAnyAddress(DWORD hook_addr, LPVOID jmp_addr, char *origin) {
BYTE jmp_code[5] = {0};
jmp_code[0] = 0xE9;
*(DWORD *)&jmp_code[1] = (DWORD)jmp_addr - hook_addr - 5;
DWORD old_protext = 0;
VirtualProtect((LPVOID)hook_addr, 5, PAGE_EXECUTE_READWRITE, &old_protext);
ReadProcessMemory(GetCurrentProcess(), (LPVOID)hook_addr, origin, 5, 0);
memcpy((void *)hook_addr, jmp_code, 5);
VirtualProtect((LPVOID)hook_addr, 5, old_protext, &old_protext);
}
void Utils::UnHookAnyAddress(DWORD hook_addr, char *origin) {
DWORD old_protext = 0;
VirtualProtect((LPVOID)hook_addr, 5, PAGE_EXECUTE_READWRITE, &old_protext);
WriteProcessMemory(GetCurrentProcess(), (LPVOID)hook_addr, origin, 5, 0);
VirtualProtect((LPVOID)hook_addr, 5, old_protext, &old_protext);
}
std::wstring Utils::GetTimeW(long long timestamp) {
wchar_t *wstr = new wchar_t[20];
memset(wstr, 0, 20 * 2);
tm tm_out;
localtime_s(&tm_out, &timestamp);
swprintf_s(wstr, 20, L"%04d-%02d-%02d %02d:%02d:%02d", 1900 + tm_out.tm_year,
tm_out.tm_mon + 1, tm_out.tm_mday, tm_out.tm_hour, tm_out.tm_min,
tm_out.tm_sec);
std::wstring str_time(wstr);
delete[] wstr;
return str_time;
}
std::string Utils::WCharToUTF8(wchar_t *wstr) {
int c_size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, FALSE);
if (c_size > 0) {
char *buffer = new char[c_size];
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, buffer, c_size, NULL, FALSE);
std::string str(buffer);
delete[] buffer;
buffer = NULL;
return str;
}
return std::string();
}
} // namespace wxhelper

77
src/utils.h Normal file
View File

@ -0,0 +1,77 @@
#ifndef WXHELPER_UTILS_H_
#define WXHELPER_UTILS_H_
#include <windows.h>
#include <string>
#include <vector>
#define STRING2INT(str) (Utils::IsDigit(str) ? stoi(str) : 0)
#define WS2LPWS(wstr) (LPWSTR) wstr.c_str()
#define READ_WSTRING(addr, offset) ((*(DWORD *)(addr + offset + 0x4) == 0) ? std::wstring(L"") : std::wstring((wchar_t *)(*(DWORD *)(addr + offset)), *(DWORD *)(addr + offset + 0x4)))
namespace wxhelper {
class Utils {
public:
static std::wstring UTF8ToWstring(const std::string &str);
static std::string WstringToUTF8(const std::wstring &str);
static std::wstring AnsiToWstring(const std::string &input,
DWORD locale = CP_ACP);
static std::string WstringToAnsi(const std::wstring &input,
DWORD locale = CP_ACP);
static DWORD GetWeChatWinBase();
static bool CreateConsole();
static void CloseConsole();
static std::string EncodeHexString(const std::string &str);
static std::string Hex2String(const std::string &hex_str);
static std::string Bytes2Hex(const BYTE *bytes, const int length);
static void Hex2Bytes(const std::string &hex, BYTE *bytes);
static bool IsDigit(std::string str);
static bool FindOrCreateDirectoryW(const wchar_t *path);
static void HookAnyAddress(DWORD hook_addr, LPVOID jmp_addr, char *origin);
static void UnHookAnyAddress(DWORD hook_addr, char *origin);
static std::wstring GetTimeW(long long timestamp);
static std::string WCharToUTF8(wchar_t *wstr);
template <typename T1, typename T2>
static std::vector<T1> split(T1 str, T2 letter) {
std::vector<T1> arr;
size_t pos;
while ((pos = str.find_first_of(letter)) != T1::npos) {
T1 str1 = str.substr(0, pos);
arr.push_back(str1);
str = str.substr(pos + 1, str.length() - pos - 1);
}
arr.push_back(str);
return arr;
}
template <typename T1, typename T2>
static T1 replace(T1 source, T2 replaced, T1 replaceto) {
std::vector<T1> v_arr = split(source, replaced);
if (v_arr.size() < 2) return source;
T1 temp;
for (unsigned int i = 0; i < v_arr.size() - 1; i++) {
temp += v_arr[i];
temp += replaceto;
}
temp += v_arr[v_arr.size() - 1];
return temp;
}
};
} // namespace wxhelper
#endif

View File

@ -1,337 +0,0 @@
#ifndef WECHAT_DATA_H_
#define WECHAT_DATA_H_
// #include <windows.h>
#include <vector>
struct WeChatString {
wchar_t *ptr;
DWORD length;
DWORD max_length;
DWORD c_ptr = 0;
DWORD c_len = 0;
WeChatString() { WeChatString(NULL); }
WeChatString(std::wstring &s) {
ptr = (wchar_t *)(s.c_str());
length = s.length();
max_length = s.length() * 2;
}
WeChatString(const wchar_t *pStr) { WeChatString((wchar_t *)pStr); }
WeChatString(int tmp) {
ptr = NULL;
length = 0x0;
max_length = 0x0;
}
WeChatString(wchar_t *pStr) {
ptr = pStr;
length = wcslen(pStr);
max_length = wcslen(pStr) * 2;
}
void set_value(const wchar_t *pStr) {
ptr = (wchar_t *)pStr;
length = wcslen(pStr);
max_length = wcslen(pStr) * 2;
}
};
struct TableInfo {
char *name;
DWORD name_len;
char *table_name;
DWORD table_name_len;
char *sql;
DWORD sql_len;
char *rootpage;
DWORD rootpage_len;
};
struct DatabaseInfo {
DWORD handle = 0;
wchar_t *db_name = NULL;
DWORD db_name_len = 0;
std::vector<TableInfo> tables;
DWORD count = 0;
DWORD extrainfo = 0;
};
struct Contact {
WeChatString wxid;
WeChatString custom_account;
WeChatString encrypt_name;
WeChatString nick_name;
WeChatString pinyin;
WeChatString pinyin_all;
int del_flag;
int type;
int verify_flag;
};
struct ChatRoomInfo {
DWORD vftable;
WeChatString chat_room_id;
WeChatString notice;
WeChatString admin;
DWORD filed_40;
DWORD filed_44;
DWORD filed_48;
DWORD filed_4C;
WeChatString xml;
DWORD filed_64;
DWORD filed_68;
DWORD filed_6C;
DWORD filed_70;
DWORD filed_74;
DWORD filed_78;
DWORD filed_7C;
DWORD filed_80;
DWORD filed_84;
DWORD filed_88;
DWORD filed_8c;
DWORD filed_90;
DWORD filed_94;
DWORD filed_98;
DWORD filed_9C;
DWORD filed_A0;
};
struct ChatRoomInfoInner {
WeChatString chat_room_id;
WeChatString notice;
WeChatString admin;
WeChatString xml;
~ChatRoomInfoInner(){
if(chat_room_id.ptr){
delete []chat_room_id.ptr;
chat_room_id.ptr = nullptr;
}
if(notice.ptr){
delete []notice.ptr;
notice.ptr = nullptr;
}
if(admin.ptr){
delete []admin.ptr;
admin.ptr = nullptr;
}
if(xml.ptr){
delete []xml.ptr;
xml.ptr = nullptr;
}
}
};
struct VectorInner {
#ifdef _DEBUG
DWORD head;
#endif
DWORD start;
DWORD finsh;
DWORD end;
};
struct ChatRoomInner{
char* members;
wchar_t* chat_room;
wchar_t* admin;
~ChatRoomInner(){
delete []members;
delete []chat_room;
delete []admin;
}
};
struct SelfInfoInner{
std::string name;
std::string city;
std::string province;
std::string country;
std::string account;
std::string wxid;
std::string mobile;
std::string head_img;
std::string data_save_path;
std::string signature;
std::string current_data_path;
std::string db_key;
};
struct UserInfo {
int error_code;
wchar_t *keyword;
int keyword_len;
wchar_t *v3;
int v3_len;
wchar_t *nickname;
int nickname_len;
wchar_t *signature;
int signature_len;
wchar_t *v2;
int v2_len;
wchar_t *nation;
int nation_len;
wchar_t *province;
int province_len;
wchar_t *city;
int city_len;
wchar_t *big_image;
int big_image_len;
wchar_t *small_image;
int small_image_len;
DWORD sex;
BOOL over;
};
struct AtInner{
DWORD start;
DWORD finsh;
DWORD end;
};
struct ChatMsg {
DWORD **field0_0x0;
DWORD field1_0x4;
ULONG64 sequence;
DWORD field3_0x10;
DWORD field4_0x14;
ULONG64 msgSequence;
DWORD localId;
DWORD field7_0x24;
DWORD field8_0x28;
DWORD field9_0x2c;
ULONG64 msgId;
DWORD type;
DWORD isSendMsg;
DWORD msgStatus;
DWORD timestamp;
WeChatString talker;
DWORD field16_0x5c;
DWORD field17_0x60;
DWORD field18_0x64;
DWORD field19_0x68;
DWORD field20_0x6c;
WeChatString content;
DWORD field22_0x84;
DWORD field23_0x88;
DWORD field24_0x8c;
DWORD field25_0x90;
DWORD field26_0x94;
DWORD field27_0x98;
DWORD field28_0x9c;
DWORD field29_0xa0;
DWORD field30_0xa4;
DWORD field31_0xa8;
DWORD field32_0xac;
DWORD field33_0xb0;
DWORD field34_0xb4;
DWORD field35_0xb8;
DWORD field36_0xbc;
DWORD field37_0xc0;
DWORD field38_0xc4;
DWORD field39_0xc8;
DWORD field40_0xcc;
DWORD field41_0xd0;
DWORD field42_0xd4;
DWORD field43_0xd8;
DWORD field44_0xdc;
DWORD field45_0xe0;
DWORD field46_0xe4;
DWORD field47_0xe8;
DWORD field48_0xec;
DWORD field49_0xf0;
DWORD field50_0xf4;
DWORD field51_0xf8;
DWORD field52_0xfc;
DWORD field53_0x100;
DWORD field54_0x104;
DWORD field55_0x108;
DWORD field56_0x10c;
DWORD field57_0x110;
DWORD field58_0x114;
DWORD field59_0x118;
DWORD field60_0x11c;
DWORD field61_0x120;
DWORD field62_0x124;
DWORD field63_0x128;
DWORD field64_0x12c;
DWORD field65_0x130;
DWORD field66_0x134;
DWORD field67_0x138;
DWORD field68_0x13c;
DWORD field69_0x140;
DWORD field70_0x144;
DWORD field71_0x148;
DWORD field72_0x14c;
DWORD field73_0x150;
DWORD field74_0x154;
DWORD field75_0x158;
DWORD field76_0x15c;
DWORD field77_0x160;
DWORD field78_0x164;
DWORD field79_0x168;
DWORD field80_0x16c;
DWORD field81_0x170;
WeChatString fromGroup;
WeChatString sign;
WeChatString thumbPath;
WeChatString path;
DWORD field86_0x1c4;
DWORD field87_0x1c8;
DWORD field88_0x1cc;
DWORD field89_0x1d0;
DWORD field90_0x1d4;
DWORD field91_0x1d8;
DWORD field92_0x1dc;
DWORD field93_0x1e0;
DWORD field94_0x1e4;
DWORD field95_0x1e8;
DWORD field96_0x1ec;
WeChatString signature;
DWORD field98_0x204;
DWORD field99_0x208;
DWORD field100_0x20c;
DWORD field101_0x210;
DWORD field102_0x214;
DWORD field103_0x218;
DWORD field104_0x21c;
DWORD field105_0x220;
DWORD field106_0x224;
DWORD field107_0x228;
DWORD field108_0x22c;
DWORD field109_0x230;
DWORD field110_0x234;
DWORD field111_0x238;
DWORD field112_0x23c;
DWORD field113_0x240;
DWORD field114_0x244;
DWORD field115_0x248;
DWORD field116_0x24c;
DWORD field117_0x250;
DWORD field118_0x254;
DWORD field119_0x258;
DWORD field120_0x25c;
DWORD field121_0x260;
DWORD field122_0x264;
DWORD field123_0x268;
DWORD field124_0x26c;
DWORD field125_0x270;
DWORD field126_0x274;
DWORD field127_0x278;
DWORD field128_0x27c;
DWORD field129_0x280;
DWORD field130_0x284;
DWORD field131_0x288;
DWORD field132_0x28c;
DWORD field133_0x290;
DWORD field134_0x294;
DWORD field135_0x298;
DWORD field136_0x29c;
DWORD field137_0x2a0;
DWORD field138_0x2a4;
DWORD field139_0x2a8;
DWORD field140_0x2ac;
DWORD field141_0x2b0;
int field142_0x2b4;
};
#endif

770
src/wechat_function.h Normal file
View File

@ -0,0 +1,770 @@
#ifndef WXHELPER_WECHAT_FUNCTION_H_
#define WXHELPER_WECHAT_FUNCTION_H_
#include <vector>
#include <string>
// snsDataMgr
#define WX_SNS_DATA_MGR_OFFSET 0xc39680
// chatRoomMgr
#define WX_CHAT_ROOM_MGR_OFFSET 0x78cf20
// contactMgr
#define WX_CONTACT_MGR_OFFSET 0x75a4a0
// syncMgr
#define WX_SYNC_MGR_OFFSET 0xa87fd0
// preDownloadMgr
#define WX_GET_PRE_DOWNLOAD_MGR_OFFSET 0x80f110
// chatMgr
#define WX_CHAT_MGR_OFFSET 0x792700
// videoMgr
#define WX_VIDEO_MGR_OFFSET 0x829820
// patMgr
#define WX_PAT_MGR_OFFSET 0x931730
// searchContactMgr
#define WX_SEARCH_CONTACT_MGR_OFFSET 0xa6cb00
// appMsgMgr
#define WX_APP_MSG_MGR_OFFSET 0x76ae20
// sendMessageMgr
#define WX_SEND_MESSAGE_MGR_OFFSET 0x768140
// setChatMsgValue
#define WX_INIT_CHAT_MSG_OFFSET 0xf59e40
// chatMsg
#define WX_NEW_CHAT_MSG_OFFSET 0x76f010
#define WX_FREE_CHAT_MSG_OFFSET 0x756960
#define WX_FREE_CHAT_MSG_2_OFFSET 0x6f4ea0
#define WX_FREE_CHAT_MSG_INSTANCE_COUNTER_OFFSET 0x756e30
//sns
#define WX_SNS_GET_FIRST_PAGE_OFFSET 0x14e2140
#define WX_SNS_GET_NEXT_PAGE_OFFSET 0x14e21e0
//chat room
#define WX_GET_CHAT_ROOM_DETAIL_INFO_OFFSET 0xbde090
// chatRoomInfo
#define WX_NEW_CHAT_ROOM_INFO_OFFSET 0xe99c40
#define WX_FREE_CHAT_ROOM_INFO_OFFSET 0xe99f40
#define WX_DEL_CHAT_ROOM_MEMBER_OFFSET 0xbd22a0
#define WX_ADD_MEMBER_TO_CHAT_ROOM_OFFSET 0xbd1dc0
// chatRoom
#define WX_INIT_CHAT_ROOM_OFFSET 0xe97890
#define WX_FREE_CHAT_ROOM_OFFSET 0xe97ab0
#define WX_GET_MEMBER_FROM_CHAT_ROOM_OFFSET 0xbdf260
#define WX_MOD_CHAT_ROOM_MEMBER_NICK_NAME_OFFSET 0xbd9680
#define WX_TOP_MSG_OFFSET 0xbe1840
#define WX_REMOVE_TOP_MSG_OFFSET 0xbe1620
#define WX_GET_MEMBER_NICKNAME_OFFSET 0xbdf3f0
#define WX_FREE_CONTACT_OFFSET 0xea7880
// wcpayinfo
#define WX_NEW_WCPAYINFO_OFFSET 0x7b2e60
#define WX_FREE_WCPAYINFO_OFFSET 0x79c250
#define WX_CONFIRM_RECEIPT_OFFSET 0x15e2c20
//contact
#define WX_CONTACT_GET_LIST_OFFSET 0xc089f0
#define WX_CONTACT_DEL_OFFSET 0xb9b3b0
#define WX_SET_VALUE_OFFSET 0x1f80900
#define WX_DO_DEL_CONTACT_OFFSET 0xca6480
#define WX_GET_CONTACT_OFFSET 0xc04e00
#define WX_DO_VERIFY_USER_OFFSET 0xc02100
#define WX_VERIFY_MSG_OFFSET 0xf59d40
// pushAttachTask
#define WX_PUSH_ATTACH_TASK_OFFSET 0x82bb40
#define WX_FREE_CHAT_MSG_OFFSET 0x756960
#define WX_GET_MGR_BY_PREFIX_LOCAL_ID_OFFSET 0xbc0370
#define WX_GET_CURRENT_DATA_PATH_OFFSET 0xc872c0
#define WX_APP_MSG_INFO_OFFSET 0x7b3d20
#define WX_GET_APP_MSG_XML_OFFSET 0xe628a0
#define WX_FREE_APP_MSG_INFO_OFFSET 0x79d900
#define WX_PUSH_THUMB_TASK_OFFSET 0x82ba40
#define WX_DOWNLOAD_VIDEO_IMG_OFFSET 0xd46c30
// pat
#define WX_SEND_PAT_MSG_OFFSET 0x1421940
#define WX_RET_OFFSET 0x1D58751
//search hook
#define WX_SEARCH_CONTACT_ERROR_CODE_HOOK_OFFSET 0xe17054
#define WX_SEARCH_CONTACT_ERROR_CODE_HOOK_NEXT_OFFSET 0xf57a20
#define WX_SEARCH_CONTACT_DETAIL_HOOK_OFFSET 0xa8ceb0
#define WX_SEARCH_CONTACT_DETAIL_HOOK_NEXT_OFFSET 0xa8d100
#define WX_SEARCH_CONTACT_OFFSET 0xcd1510
//login
#define WX_LOGOUT_OFFSET 0xe58870
#define WX_ACCOUNT_SERVICE_OFFSET 0x768c80
#define WX_GET_APP_DATA_SAVE_PATH_OFFSET 0xf3a610
#define WX_GET_CURRENT_DATA_PATH_OFFSET 0xc872c0
//forward
#define WX_FORWARD_MSG_OFFSET 0xce6730
// send file
#define WX_SEND_FILE_OFFSET 0xb6d1f0
// send image
#define WX_SEND_IMAGE_OFFSET 0xce6640
// send text
#define WX_SEND_TEXT_OFFSET 0xce6c80
//ocr
#define WX_INIT_OBJ_OFFSET 0x7a98f0
#define WX_OCR_MANAGER_OFFSET 0x7ae470
#define WX_DO_OCR_TASK_OFFSET 0x13230c0
//storage
#define CONTACT_G_PINSTANCE_OFFSET 0x2ffddc8
#define DB_MICRO_MSG_OFFSET 0x68
#define DB_CHAT_MSG_OFFSET 0x1C0
#define DB_MISC_OFFSET 0x3D8
#define DB_EMOTION_OFFSET 0x558
#define DB_MEDIA_OFFSET 0x9B8
#define DB_BIZCHAT_MSG_OFFSET 0x1120
#define DB_FUNCTION_MSG_OFFSET 0x11B0
#define DB_NAME_OFFSET 0x14
#define STORAGE_START_OFFSET 0x13f8
#define STORAGE_END_OFFSET 0x13fc
#define PUBLIC_MSG_MGR_OFFSET 0x303df74
#define MULTI_DB_MSG_MGR_OFFSET 0x30403b8
#define FAVORITE_STORAGE_MGR_OFFSET 0x303fd40
#define FTS_FAVORITE_MGR_OFFSET 0x2ffe908
#define OP_LOG_STORAGE_VFTABLE 0x2AD3A20
#define CHAT_MSG_STORAGE_VFTABLE 0x2AC10F0
#define CHAT_CR_MSG_STORAGE_VFTABLE 0x2ABEF14
#define SESSION_STORAGE_VFTABLE 0x2AD3578
#define APP_INFO_STORAGE_VFTABLE 0x2ABCC58
#define HEAD_IMG_STORAGE_VFTABLE 0x2ACD9DC
#define HEAD_IMG_URL_STORAGE_VFTABLE 0x2ACDF70
#define BIZ_INFO_STORAGE_VFTABLE 0x2ABD718
#define TICKET_INFO_STORAGE_VFTABLE 0x2AD5400
#define CHAT_ROOM_STORAGE_VFTABLE 0x2AC299C
#define CHAT_ROOM_INFO_STORAGE_VFTABLE 0x2AC245C
#define MEDIA_STORAGE_VFTABLE 0x2ACE998
#define NAME_2_ID_STORAGE_VFTABLE 0x2AD222C
#define EMOTION_PACKAGE_STORAGE_VFTABLE 0x2AC6400
#define EMOTION_STORAGE_VFTABLE 0x2AC7018
#define BUFINFO_STORAGE_VFTABLE 0x2AC3178
#define CUSTOM_EMOTION_STORAGE_VFTABLE 0x2AC4E90
#define DEL_SESSIONINFO_STORAGE_VFTABLE 0x2AC5F98
#define FUNCTION_MSG_STORAGE_VFTABLE 0x2ACD10C
#define FUNCTION_MSG_TASK_STORAGE_VFTABLE 0x2ACC5C8
#define REVOKE_MSG_STORAGE_VFTABLE 0x2AD27BC
/*******************hook*********************************************/
// hook image
#define WX_HOOK_IMG_OFFSET 0xd723dc
#define WX_HOOK_IMG_NEXT_OFFSET 0xe91d90
// hook log
#define WX_HOOK_LOG_OFFSET 0xf57d67
#define WX_HOOK_LOG_NEXT_OFFSET 0x240ea71
// hook msg
#define WX_RECV_MSG_HOOK_OFFSET 0xd19a0b
#define WX_RECV_MSG_HOOK_NEXT_OFFSET 0x756960
#define WX_SNS_HOOK_OFFSET 0x14f9e15
#define WX_SNS_HOOK_NEXT_OFFSET 0x14fa0a0
// hook voice
#define WX_HOOK_VOICE_OFFSET 0xd4d8d8
#define WX_HOOK_VOICE_NEXT_OFFSET 0x203d130
#define WX_SELF_ID_OFFSET 0x2FFD484
/*******************hook end*********************************************/
/***************************sqlite3***************************************/
#define SQLITE_OK 0 /* Successful result */
/* beginning-of-error-codes */
#define SQLITE_ERROR 1 /* Generic error */
#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */
#define SQLITE_PERM 3 /* Access permission denied */
#define SQLITE_ABORT 4 /* Callback routine requested an abort */
#define SQLITE_BUSY 5 /* The database file is locked */
#define SQLITE_LOCKED 6 /* A table in the database is locked */
#define SQLITE_NOMEM 7 /* A malloc() failed */
#define SQLITE_READONLY 8 /* Attempt to write a readonly database */
#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/
#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */
#define SQLITE_CORRUPT 11 /* The database disk image is malformed */
#define SQLITE_NOTFOUND 12 /* Unknown opcode in sqlite3_file_control() */
#define SQLITE_FULL 13 /* Insertion failed because database is full */
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
#define SQLITE_EMPTY 16 /* Internal use only */
#define SQLITE_SCHEMA 17 /* The database schema changed */
#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */
#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */
#define SQLITE_MISMATCH 20 /* Data type mismatch */
#define SQLITE_MISUSE 21 /* Library used incorrectly */
#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
#define SQLITE_AUTH 23 /* Authorization denied */
#define SQLITE_FORMAT 24 /* Not used */
#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */
#define SQLITE_NOTADB 26 /* File opened that is not a database file */
#define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */
#define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */
#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */
#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
/* end-of-error-codes */
/*
** CAPI3REF: Extended Result Codes
** KEYWORDS: {extended result code definitions}
**
** In its default configuration, SQLite API routines return one of 30 integer
** [result codes]. However, experience has shown that many of
** these result codes are too coarse-grained. They do not provide as
** much information about problems as programmers might like. In an effort to
** address this, newer versions of SQLite (version 3.3.8 [dateof:3.3.8]
** and later) include
** support for additional result codes that provide more detailed information
** about errors. These [extended result codes] are enabled or disabled
** on a per database connection basis using the
** [sqlite3_extended_result_codes()] API. Or, the extended code for
** the most recent error can be obtained using
** [sqlite3_extended_errcode()].
*/
#define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1 << 8))
#define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2 << 8))
#define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3 << 8))
#define SQLITE_IOERR_READ (SQLITE_IOERR | (1 << 8))
#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2 << 8))
#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3 << 8))
#define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4 << 8))
#define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5 << 8))
#define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6 << 8))
#define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7 << 8))
#define SQLITE_IOERR_UNLOCK (SQLITE_IOERR | (8 << 8))
#define SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9 << 8))
#define SQLITE_IOERR_DELETE (SQLITE_IOERR | (10 << 8))
#define SQLITE_IOERR_BLOCKED (SQLITE_IOERR | (11 << 8))
#define SQLITE_IOERR_NOMEM (SQLITE_IOERR | (12 << 8))
#define SQLITE_IOERR_ACCESS (SQLITE_IOERR | (13 << 8))
#define SQLITE_IOERR_CHECKRESERVEDLOCK (SQLITE_IOERR | (14 << 8))
#define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15 << 8))
#define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16 << 8))
#define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17 << 8))
#define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18 << 8))
#define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19 << 8))
#define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20 << 8))
#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21 << 8))
#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22 << 8))
#define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23 << 8))
#define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24 << 8))
#define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25 << 8))
#define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26 << 8))
#define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27 << 8))
#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28 << 8))
#define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29 << 8))
#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30 << 8))
#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31 << 8))
#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32 << 8))
#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33 << 8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1 << 8))
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2 << 8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1 << 8))
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2 << 8))
#define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3 << 8))
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1 << 8))
#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2 << 8))
#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3 << 8))
#define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4 << 8))
#define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5 << 8)) /* Not Used */
#define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6 << 8))
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1 << 8))
#define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2 << 8))
#define SQLITE_CORRUPT_INDEX (SQLITE_CORRUPT | (3 << 8))
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1 << 8))
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2 << 8))
#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3 << 8))
#define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4 << 8))
#define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5 << 8))
#define SQLITE_READONLY_DIRECTORY (SQLITE_READONLY | (6 << 8))
#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2 << 8))
#define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1 << 8))
#define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2 << 8))
#define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3 << 8))
#define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4 << 8))
#define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5 << 8))
#define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6 << 8))
#define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7 << 8))
#define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8 << 8))
#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9 << 8))
#define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT | (10 << 8))
#define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT | (11 << 8))
#define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT | (12 << 8))
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1 << 8))
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2 << 8))
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1 << 8))
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1 << 8))
#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1 << 8))
#define SQLITE_OK_SYMLINK (SQLITE_OK | (2 << 8)) /* internal use only */
#define SQLITE_INTEGER 1
#define SQLITE_FLOAT 2
#define SQLITE_BLOB 4
#define SQLITE_NULL 5
#define SQLITE_TEXT 3
#define SQLITE3_EXEC_OFFSET 0x1e24f70
#define SQLITE3_BACKUP_INIT_OFFSET 0x1dea900
#define SQLITE3_PREPARE_OFFSET 0x1e2b8c0
#define SQLITE3_OPEN_OFFSET 0x1e598b0
#define SQLITE3_BACKUP_STEP_OFFSET 0x1dead00
#define SQLITE3_BACKUP_REMAINING_OFFSET 0x1deb440
#define SQLITE3_BACKUP_PAGECOUNT_OFFSET 0x1deb450
#define SQLITE3_BACKUP_FINISH_OFFSET 0x1deb340
#define SQLITE3_SLEEP_OFFSET 0x1e5a0f0
#define SQLITE3_ERRCODE_OFFSET 0x1e58550
#define SQLITE3_CLOSE_OFFSET 0x1e56cd0
#define SQLITE3_STEP_OFFSET 0x1df3770
#define SQLITE3_COLUMN_COUNT_OFFSET 0x1df3c80
#define SQLITE3_COLUMN_NAME_OFFSET 0x1df4570
#define SQLITE3_COLUMN_TYPE_OFFSET 0x1df4410
#define SQLITE3_COLUMN_BLOB_OFFSET 0x1df3cc0
#define SQLITE3_COLUMN_BYTES_OFFSET 0x1df3da0
#define SQLITE3_FINALIZE_OFFSET 0x1df2740
typedef int (*Sqlite3_callback)(void*, int, char**, char**);
typedef int(__cdecl* Sqlite3_exec)(DWORD, /* An open database */
const char* sql, /* SQL to be evaluated */
Sqlite3_callback, /* Callback function */
void*, /* 1st argument to callback */
char** errmsg /* Error msg written here */
);
typedef DWORD(__cdecl* Sqlite3_backup_init)(
DWORD* pDest, /* Destination database handle */
const char* zDestName, /* Destination database name */
DWORD* pSource, /* Source database handle */
const char* zSourceName /* Source database name */
);
typedef int(__cdecl* Sqlite3_prepare)(
DWORD db, /* Database handle */
const char* zSql, /* SQL statement, UTF-8 encoded */
int nByte, /* Maximum length of zSql in bytes. */
DWORD** ppStmt, /* OUT: Statement handle */
const char** pzTail /* OUT: Pointer to unused portion of zSql */
);
typedef int(__cdecl* Sqlite3_open)(const char* filename, DWORD** ppDb);
typedef int(__cdecl* Sqlite3_backup_step)(DWORD* p, int nPage);
typedef int(__cdecl* Sqlite3_backup_remaining)(DWORD* p);
typedef int(__cdecl* Sqlite3_backup_pagecount)(DWORD* p);
typedef int(__cdecl* Sqlite3_backup_finish)(DWORD* p);
typedef int(__cdecl* Sqlite3_sleep)(int);
typedef int(__cdecl* Sqlite3_errcode)(DWORD* db);
typedef int(__cdecl* Sqlite3_close)(DWORD*);
typedef int(__cdecl* Sqlite3_step)(DWORD*);
typedef int(__cdecl* Sqlite3_column_count)(DWORD* pStmt);
typedef const char*(__cdecl* Sqlite3_column_name)(DWORD*, int N);
typedef int(__cdecl* Sqlite3_column_type)(DWORD*, int iCol);
typedef const void*(__cdecl* Sqlite3_column_blob)(DWORD*, int iCol);
typedef int(__cdecl* Sqlite3_column_bytes)(DWORD*, int iCol);
typedef int(__cdecl* Sqlite3_finalize)(DWORD* pStmt);
/***************************sqlite3 end*************************************/
struct SqlResult {
char *column_name;
DWORD column_name_len;
char *content;
DWORD content_len;
BOOL is_blob;
};
struct WeChatString {
wchar_t *ptr;
DWORD length;
DWORD max_length;
DWORD c_ptr = 0;
DWORD c_len = 0;
WeChatString() { WeChatString(NULL); }
WeChatString(std::wstring &s) {
ptr = (wchar_t *)(s.c_str());
length = s.length();
max_length = s.length() * 2;
}
WeChatString(const wchar_t *pStr) { WeChatString((wchar_t *)pStr); }
WeChatString(int tmp) {
ptr = NULL;
length = 0x0;
max_length = 0x0;
}
WeChatString(wchar_t *pStr) {
ptr = pStr;
length = wcslen(pStr);
max_length = wcslen(pStr) * 2;
}
void set_value(const wchar_t *pStr) {
ptr = (wchar_t *)pStr;
length = wcslen(pStr);
max_length = wcslen(pStr) * 2;
}
};
struct SelfInfoInner{
std::string name;
std::string city;
std::string province;
std::string country;
std::string account;
std::string wxid;
std::string mobile;
std::string head_img;
std::string data_save_path;
std::string signature;
std::string current_data_path;
std::string db_key;
};
struct VectorInner {
#ifdef _DEBUG
DWORD head;
#endif
DWORD start;
DWORD finsh;
DWORD end;
};
struct TableInfo {
char *name;
DWORD name_len;
char *table_name;
DWORD table_name_len;
char *sql;
DWORD sql_len;
char *rootpage;
DWORD rootpage_len;
};
struct DatabaseInfo {
DWORD handle = 0;
wchar_t *db_name = NULL;
DWORD db_name_len = 0;
std::vector<TableInfo> tables;
DWORD count = 0;
DWORD extrainfo = 0;
};
struct Contact {
WeChatString wxid;
WeChatString custom_account;
WeChatString encrypt_name;
WeChatString nick_name;
WeChatString pinyin;
WeChatString pinyin_all;
int del_flag;
int type;
int verify_flag;
};
struct ChatRoomInfo {
DWORD vftable;
WeChatString chat_room_id;
WeChatString notice;
WeChatString admin;
DWORD filed_40;
DWORD filed_44;
DWORD filed_48;
DWORD filed_4C;
WeChatString xml;
DWORD filed_64;
DWORD filed_68;
DWORD filed_6C;
DWORD filed_70;
DWORD filed_74;
DWORD filed_78;
DWORD filed_7C;
DWORD filed_80;
DWORD filed_84;
DWORD filed_88;
DWORD filed_8c;
DWORD filed_90;
DWORD filed_94;
DWORD filed_98;
DWORD filed_9C;
DWORD filed_A0;
};
struct ChatRoomInfoInner {
WeChatString chat_room_id;
WeChatString notice;
WeChatString admin;
WeChatString xml;
~ChatRoomInfoInner(){
if(chat_room_id.ptr){
delete []chat_room_id.ptr;
chat_room_id.ptr = nullptr;
}
if(notice.ptr){
delete []notice.ptr;
notice.ptr = nullptr;
}
if(admin.ptr){
delete []admin.ptr;
admin.ptr = nullptr;
}
if(xml.ptr){
delete []xml.ptr;
xml.ptr = nullptr;
}
}
};
struct ChatRoomInner{
char* members;
wchar_t* chat_room;
wchar_t* admin;
~ChatRoomInner(){
delete []members;
delete []chat_room;
delete []admin;
}
};
struct UserInfo {
int error_code;
wchar_t *keyword;
int keyword_len;
wchar_t *v3;
int v3_len;
wchar_t *nickname;
int nickname_len;
wchar_t *signature;
int signature_len;
wchar_t *v2;
int v2_len;
wchar_t *nation;
int nation_len;
wchar_t *province;
int province_len;
wchar_t *city;
int city_len;
wchar_t *big_image;
int big_image_len;
wchar_t *small_image;
int small_image_len;
DWORD sex;
BOOL over;
};
struct AtInner{
DWORD start;
DWORD finsh;
DWORD end;
};
struct ChatMsg {
DWORD **field0_0x0;
DWORD field1_0x4;
ULONG64 sequence;
DWORD field3_0x10;
DWORD field4_0x14;
ULONG64 msgSequence;
DWORD localId;
DWORD field7_0x24;
DWORD field8_0x28;
DWORD field9_0x2c;
ULONG64 msgId;
DWORD type;
DWORD isSendMsg;
DWORD msgStatus;
DWORD timestamp;
WeChatString talker;
DWORD field16_0x5c;
DWORD field17_0x60;
DWORD field18_0x64;
DWORD field19_0x68;
DWORD field20_0x6c;
WeChatString content;
DWORD field22_0x84;
DWORD field23_0x88;
DWORD field24_0x8c;
DWORD field25_0x90;
DWORD field26_0x94;
DWORD field27_0x98;
DWORD field28_0x9c;
DWORD field29_0xa0;
DWORD field30_0xa4;
DWORD field31_0xa8;
DWORD field32_0xac;
DWORD field33_0xb0;
DWORD field34_0xb4;
DWORD field35_0xb8;
DWORD field36_0xbc;
DWORD field37_0xc0;
DWORD field38_0xc4;
DWORD field39_0xc8;
DWORD field40_0xcc;
DWORD field41_0xd0;
DWORD field42_0xd4;
DWORD field43_0xd8;
DWORD field44_0xdc;
DWORD field45_0xe0;
DWORD field46_0xe4;
DWORD field47_0xe8;
DWORD field48_0xec;
DWORD field49_0xf0;
DWORD field50_0xf4;
DWORD field51_0xf8;
DWORD field52_0xfc;
DWORD field53_0x100;
DWORD field54_0x104;
DWORD field55_0x108;
DWORD field56_0x10c;
DWORD field57_0x110;
DWORD field58_0x114;
DWORD field59_0x118;
DWORD field60_0x11c;
DWORD field61_0x120;
DWORD field62_0x124;
DWORD field63_0x128;
DWORD field64_0x12c;
DWORD field65_0x130;
DWORD field66_0x134;
DWORD field67_0x138;
DWORD field68_0x13c;
DWORD field69_0x140;
DWORD field70_0x144;
DWORD field71_0x148;
DWORD field72_0x14c;
DWORD field73_0x150;
DWORD field74_0x154;
DWORD field75_0x158;
DWORD field76_0x15c;
DWORD field77_0x160;
DWORD field78_0x164;
DWORD field79_0x168;
DWORD field80_0x16c;
DWORD field81_0x170;
WeChatString fromGroup;
WeChatString sign;
WeChatString thumbPath;
WeChatString path;
DWORD field86_0x1c4;
DWORD field87_0x1c8;
DWORD field88_0x1cc;
DWORD field89_0x1d0;
DWORD field90_0x1d4;
DWORD field91_0x1d8;
DWORD field92_0x1dc;
DWORD field93_0x1e0;
DWORD field94_0x1e4;
DWORD field95_0x1e8;
DWORD field96_0x1ec;
WeChatString signature;
DWORD field98_0x204;
DWORD field99_0x208;
DWORD field100_0x20c;
DWORD field101_0x210;
DWORD field102_0x214;
DWORD field103_0x218;
DWORD field104_0x21c;
DWORD field105_0x220;
DWORD field106_0x224;
DWORD field107_0x228;
DWORD field108_0x22c;
DWORD field109_0x230;
DWORD field110_0x234;
DWORD field111_0x238;
DWORD field112_0x23c;
DWORD field113_0x240;
DWORD field114_0x244;
DWORD field115_0x248;
DWORD field116_0x24c;
DWORD field117_0x250;
DWORD field118_0x254;
DWORD field119_0x258;
DWORD field120_0x25c;
DWORD field121_0x260;
DWORD field122_0x264;
DWORD field123_0x268;
DWORD field124_0x26c;
DWORD field125_0x270;
DWORD field126_0x274;
DWORD field127_0x278;
DWORD field128_0x27c;
DWORD field129_0x280;
DWORD field130_0x284;
DWORD field131_0x288;
DWORD field132_0x28c;
DWORD field133_0x290;
DWORD field134_0x294;
DWORD field135_0x298;
DWORD field136_0x29c;
DWORD field137_0x2a0;
DWORD field138_0x2a4;
DWORD field139_0x2a8;
DWORD field140_0x2ac;
DWORD field141_0x2b0;
int field142_0x2b4;
};
struct InnerMessageStruct {
char *buffer;
int length;
~InnerMessageStruct() {
if (this->buffer != NULL) {
delete[] this->buffer;
this->buffer = NULL;
}
}
};
struct Unkown{
DWORD field1 = 0;
DWORD field2= 0;
DWORD field3= 0;
DWORD field4= 0;
DWORD field5= 0;
DWORD field6= 0;
};
#endif

View File

@ -1,24 +0,0 @@
#include "wxhelper.h"
#include <mongoose.h>
#include "pch.h"
namespace wxhelper {
WXHelper& WXHelper::GetInstance() {
static WXHelper p;
return p;
}
int WXHelper::http_start(int port) {
HttpServer::GetInstance().Init(port);
bool ret = HttpServer::GetInstance().HttpStart();
return ret == true ? 1 : 0;
}
int WXHelper::http_close() {
bool ret = HttpServer::GetInstance().HttpClose();
return ret == true ? 1 : 0;
}
} // namespace wxhelper

View File

@ -1,21 +0,0 @@
#ifndef WXHELPER_WXHELPER_H_
#define WXHELPER_WXHELPER_H_
#include "http_server.h"
namespace wxhelper {
class WXHelper {
public:
static WXHelper &GetInstance();
int http_start(int port);
int http_close();
private:
WXHelper(){};
WXHelper(const WXHelper &) = delete;
WXHelper &operator=(const WXHelper &) = delete;
~WXHelper(){};
};
} // namespace wxhelper
#endif