mirror of
https://github.com/ttttupup/wxhelper.git
synced 2024-11-26 12:19:23 +08:00
新增hook语音文档更新
This commit is contained in:
parent
75ca6f9477
commit
055adf5eab
@ -126,6 +126,8 @@ vcpkg
|
|||||||
|
|
||||||
2023-03-04 : 新增消息附件下载
|
2023-03-04 : 新增消息附件下载
|
||||||
|
|
||||||
|
2023-03-21 : 新增hook语音
|
||||||
|
|
||||||
#### 功能预览:
|
#### 功能预览:
|
||||||
0.检查是否登录
|
0.检查是否登录
|
||||||
1.获取登录微信信息
|
1.获取登录微信信息
|
||||||
@ -137,6 +139,8 @@ vcpkg
|
|||||||
10.取消hook消息
|
10.取消hook消息
|
||||||
11.hook图片
|
11.hook图片
|
||||||
12.取消hook图片
|
12.取消hook图片
|
||||||
|
13.hook语音
|
||||||
|
14.取消hook语音
|
||||||
17.删除好友
|
17.删除好友
|
||||||
19.通过手机或qq查找微信
|
19.通过手机或qq查找微信
|
||||||
20.通过wxid添加好友
|
20.通过wxid添加好友
|
||||||
|
599
src/api.cc
599
src/api.cc
@ -1,599 +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"
|
|
||||||
|
|
||||||
#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},
|
|
||||||
{"smallImage", self_info.small_img},
|
|
||||||
{"bigImage", self_info.big_img},
|
|
||||||
{"dataRootPath",self_info.data_root_path},
|
|
||||||
{"dataSavePath",self_info.data_save_path},
|
|
||||||
{"currentDataPath",self_info.current_data_path},
|
|
||||||
};
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
int success = HookRecvMsg(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: {
|
|
||||||
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: {
|
|
||||||
int success = UnHookImg();
|
|
||||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
|
||||||
ret = ret_data.dump();
|
|
||||||
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: {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
case WECHAT_CONTACT_ADD_BY_WXID: {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
case WECHAT_CHATROOM_DEL_MEMBER: {
|
|
||||||
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: {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
case WECHAT_LOG_STOP_HOOK: {
|
|
||||||
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: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case WECHAT_GET_TRANSFER: {
|
|
||||||
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: {
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
71
src/api.h
71
src/api.h
@ -1,71 +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_HTTP_APIS,
|
|
||||||
*PWECHAT_HTTP_APIS;
|
|
||||||
|
|
||||||
|
|
||||||
int http_start(int port);
|
|
||||||
#endif
|
|
312
src/base64.cpp
312
src/base64.cpp
@ -1,312 +0,0 @@
|
|||||||
#include "pch.h"
|
|
||||||
/*
|
|
||||||
base64.cpp and base64.h
|
|
||||||
|
|
||||||
base64 encoding and decoding with C++.
|
|
||||||
More information at
|
|
||||||
https://renenyffenegger.ch/notes/development/Base64/Encoding-and-decoding-base-64-with-cpp
|
|
||||||
|
|
||||||
Version: 2.rc.08 (release candidate)
|
|
||||||
|
|
||||||
Copyright (C) 2004-2017, 2020, 2021 Ren¨¦ Nyffenegger
|
|
||||||
|
|
||||||
This source code is provided 'as-is', without any express or implied
|
|
||||||
warranty. In no event will the author be held liable for any damages
|
|
||||||
arising from the use of this software.
|
|
||||||
|
|
||||||
Permission is granted to anyone to use this software for any purpose,
|
|
||||||
including commercial applications, and to alter it and redistribute it
|
|
||||||
freely, subject to the following restrictions:
|
|
||||||
|
|
||||||
1. The origin of this source code must not be misrepresented; you must not
|
|
||||||
claim that you wrote the original source code. If you use this source code
|
|
||||||
in a product, an acknowledgment in the product documentation would be
|
|
||||||
appreciated but is not required.
|
|
||||||
|
|
||||||
2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
misrepresented as being the original source code.
|
|
||||||
|
|
||||||
3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
Ren¨¦ Nyffenegger rene.nyffenegger@adp-gmbh.ch
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "base64.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
//
|
|
||||||
// Depending on the url parameter in base64_chars, one of
|
|
||||||
// two sets of base64 characters needs to be chosen.
|
|
||||||
// They differ in their last two characters.
|
|
||||||
//
|
|
||||||
static const char *base64_chars[2] = {
|
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
||||||
"abcdefghijklmnopqrstuvwxyz"
|
|
||||||
"0123456789"
|
|
||||||
"+/",
|
|
||||||
|
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
||||||
"abcdefghijklmnopqrstuvwxyz"
|
|
||||||
"0123456789"
|
|
||||||
"-_"};
|
|
||||||
|
|
||||||
static unsigned int pos_of_char(const unsigned char chr)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// Return the position of chr within base64_encode()
|
|
||||||
//
|
|
||||||
|
|
||||||
if (chr >= 'A' && chr <= 'Z')
|
|
||||||
return chr - 'A';
|
|
||||||
else if (chr >= 'a' && chr <= 'z')
|
|
||||||
return chr - 'a' + ('Z' - 'A') + 1;
|
|
||||||
else if (chr >= '0' && chr <= '9')
|
|
||||||
return chr - '0' + ('Z' - 'A') + ('z' - 'a') + 2;
|
|
||||||
else if (chr == '+' || chr == '-')
|
|
||||||
return 62; // Be liberal with input and accept both url ('-') and non-url ('+') base 64 characters (
|
|
||||||
else if (chr == '/' || chr == '_')
|
|
||||||
return 63; // Ditto for '/' and '_'
|
|
||||||
else
|
|
||||||
//
|
|
||||||
// 2020-10-23: Throw std::exception rather than const char*
|
|
||||||
//(Pablo Martin-Gomez, https://github.com/Bouska)
|
|
||||||
//
|
|
||||||
throw std::runtime_error("Input is not valid base64-encoded data.");
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string insert_linebreaks(std::string str, size_t distance)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// Provided by https://github.com/JomaCorpFX, adapted by me.
|
|
||||||
//
|
|
||||||
if (!str.length())
|
|
||||||
{
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t pos = distance;
|
|
||||||
|
|
||||||
while (pos < str.size())
|
|
||||||
{
|
|
||||||
str.insert(pos, "\n");
|
|
||||||
pos += distance + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename String, unsigned int line_length>
|
|
||||||
static std::string encode_with_line_breaks(String s)
|
|
||||||
{
|
|
||||||
return insert_linebreaks(base64_encode(s, false), line_length);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename String>
|
|
||||||
static std::string encode_pem(String s)
|
|
||||||
{
|
|
||||||
return encode_with_line_breaks<String, 64>(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename String>
|
|
||||||
static std::string encode_mime(String s)
|
|
||||||
{
|
|
||||||
return encode_with_line_breaks<String, 76>(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename String>
|
|
||||||
static std::string encode(String s, bool url)
|
|
||||||
{
|
|
||||||
return base64_encode(reinterpret_cast<const unsigned char *>(s.data()), s.length(), url);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string base64_encode(unsigned char const *bytes_to_encode, size_t in_len, bool url)
|
|
||||||
{
|
|
||||||
|
|
||||||
size_t len_encoded = (in_len + 2) / 3 * 4;
|
|
||||||
|
|
||||||
unsigned char trailing_char = url ? '.' : '=';
|
|
||||||
|
|
||||||
//
|
|
||||||
// Choose set of base64 characters. They differ
|
|
||||||
// for the last two positions, depending on the url
|
|
||||||
// parameter.
|
|
||||||
// A bool (as is the parameter url) is guaranteed
|
|
||||||
// to evaluate to either 0 or 1 in C++ therefore,
|
|
||||||
// the correct character set is chosen by subscripting
|
|
||||||
// base64_chars with url.
|
|
||||||
//
|
|
||||||
const char *base64_chars_ = base64_chars[url];
|
|
||||||
|
|
||||||
std::string ret;
|
|
||||||
ret.reserve(len_encoded);
|
|
||||||
|
|
||||||
unsigned int pos = 0;
|
|
||||||
|
|
||||||
while (pos < in_len)
|
|
||||||
{
|
|
||||||
ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0xfc) >> 2]);
|
|
||||||
|
|
||||||
if (pos + 1 < in_len)
|
|
||||||
{
|
|
||||||
ret.push_back(base64_chars_[((bytes_to_encode[pos + 0] & 0x03) << 4) + ((bytes_to_encode[pos + 1] & 0xf0) >> 4)]);
|
|
||||||
|
|
||||||
if (pos + 2 < in_len)
|
|
||||||
{
|
|
||||||
ret.push_back(base64_chars_[((bytes_to_encode[pos + 1] & 0x0f) << 2) + ((bytes_to_encode[pos + 2] & 0xc0) >> 6)]);
|
|
||||||
ret.push_back(base64_chars_[bytes_to_encode[pos + 2] & 0x3f]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ret.push_back(base64_chars_[(bytes_to_encode[pos + 1] & 0x0f) << 2]);
|
|
||||||
ret.push_back(trailing_char);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0x03) << 4]);
|
|
||||||
ret.push_back(trailing_char);
|
|
||||||
ret.push_back(trailing_char);
|
|
||||||
}
|
|
||||||
|
|
||||||
pos += 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename String>
|
|
||||||
static std::string decode(String encoded_string, bool remove_linebreaks)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// decode(¡) is templated so that it can be used with String = const std::string&
|
|
||||||
// or std::string_view (requires at least C++17)
|
|
||||||
//
|
|
||||||
|
|
||||||
if (encoded_string.empty())
|
|
||||||
return std::string();
|
|
||||||
|
|
||||||
if (remove_linebreaks)
|
|
||||||
{
|
|
||||||
|
|
||||||
std::string copy(encoded_string);
|
|
||||||
|
|
||||||
copy.erase(std::remove(copy.begin(), copy.end(), '\n'), copy.end());
|
|
||||||
|
|
||||||
return base64_decode(copy, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t length_of_string = encoded_string.length();
|
|
||||||
size_t pos = 0;
|
|
||||||
|
|
||||||
//
|
|
||||||
// The approximate length (bytes) of the decoded string might be one or
|
|
||||||
// two bytes smaller, depending on the amount of trailing equal signs
|
|
||||||
// in the encoded string. This approximation is needed to reserve
|
|
||||||
// enough space in the string to be returned.
|
|
||||||
//
|
|
||||||
size_t approx_length_of_decoded_string = length_of_string / 4 * 3;
|
|
||||||
std::string ret;
|
|
||||||
ret.reserve(approx_length_of_decoded_string);
|
|
||||||
|
|
||||||
while (pos < length_of_string)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// Iterate over encoded input string in chunks. The size of all
|
|
||||||
// chunks except the last one is 4 bytes.
|
|
||||||
//
|
|
||||||
// The last chunk might be padded with equal signs or dots
|
|
||||||
// in order to make it 4 bytes in size as well, but this
|
|
||||||
// is not required as per RFC 2045.
|
|
||||||
//
|
|
||||||
// All chunks except the last one produce three output bytes.
|
|
||||||
//
|
|
||||||
// The last chunk produces at least one and up to three bytes.
|
|
||||||
//
|
|
||||||
|
|
||||||
size_t pos_of_char_1 = pos_of_char(encoded_string[pos + 1]);
|
|
||||||
|
|
||||||
//
|
|
||||||
// Emit the first output byte that is produced in each chunk:
|
|
||||||
//
|
|
||||||
ret.push_back(static_cast<std::string::value_type>(((pos_of_char(encoded_string[pos + 0])) << 2) + ((pos_of_char_1 & 0x30) >> 4)));
|
|
||||||
|
|
||||||
if ((pos + 2 < length_of_string) && // Check for data that is not padded with equal signs (which is allowed by RFC 2045)
|
|
||||||
encoded_string[pos + 2] != '=' &&
|
|
||||||
encoded_string[pos + 2] != '.' // accept URL-safe base 64 strings, too, so check for '.' also.
|
|
||||||
)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// Emit a chunk's second byte (which might not be produced in the last chunk).
|
|
||||||
//
|
|
||||||
unsigned int pos_of_char_2 = pos_of_char(encoded_string[pos + 2]);
|
|
||||||
ret.push_back(static_cast<std::string::value_type>(((pos_of_char_1 & 0x0f) << 4) + ((pos_of_char_2 & 0x3c) >> 2)));
|
|
||||||
|
|
||||||
if ((pos + 3 < length_of_string) &&
|
|
||||||
encoded_string[pos + 3] != '=' &&
|
|
||||||
encoded_string[pos + 3] != '.')
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// Emit a chunk's third byte (which might not be produced in the last chunk).
|
|
||||||
//
|
|
||||||
ret.push_back(static_cast<std::string::value_type>(((pos_of_char_2 & 0x03) << 6) + pos_of_char(encoded_string[pos + 3])));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pos += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string base64_decode(std::string const &s, bool remove_linebreaks)
|
|
||||||
{
|
|
||||||
return decode(s, remove_linebreaks);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string base64_encode(std::string const &s, bool url)
|
|
||||||
{
|
|
||||||
return encode(s, url);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string base64_encode_pem(std::string const &s)
|
|
||||||
{
|
|
||||||
return encode_pem(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string base64_encode_mime(std::string const &s)
|
|
||||||
{
|
|
||||||
return encode_mime(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if __cplusplus >= 201703L
|
|
||||||
//
|
|
||||||
// Interface with std::string_view rather than const std::string&
|
|
||||||
// Requires C++17
|
|
||||||
// Provided by Yannic Bonenberger (https://github.com/Yannic)
|
|
||||||
//
|
|
||||||
|
|
||||||
std::string base64_encode(std::string_view s, bool url)
|
|
||||||
{
|
|
||||||
return encode(s, url);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string base64_encode_pem(std::string_view s)
|
|
||||||
{
|
|
||||||
return encode_pem(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string base64_encode_mime(std::string_view s)
|
|
||||||
{
|
|
||||||
return encode_mime(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string base64_decode(std::string_view s, bool remove_linebreaks)
|
|
||||||
{
|
|
||||||
return decode(s, remove_linebreaks);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // __cplusplus >= 201703L
|
|
35
src/base64.h
35
src/base64.h
@ -1,35 +0,0 @@
|
|||||||
//
|
|
||||||
// base64 encoding and decoding with C++.
|
|
||||||
// Version: 2.rc.08 (release candidate)
|
|
||||||
//
|
|
||||||
#pragma once
|
|
||||||
#ifndef BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A
|
|
||||||
#define BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#if __cplusplus >= 201703L
|
|
||||||
#include <string_view>
|
|
||||||
#endif // __cplusplus >= 201703L
|
|
||||||
|
|
||||||
std::string base64_encode(std::string const &s, bool url = false);
|
|
||||||
std::string base64_encode_pem(std::string const &s);
|
|
||||||
std::string base64_encode_mime(std::string const &s);
|
|
||||||
|
|
||||||
std::string base64_decode(std::string const &s, bool remove_linebreaks = false);
|
|
||||||
std::string base64_encode(unsigned char const *, size_t len, bool url = false);
|
|
||||||
|
|
||||||
#if __cplusplus >= 201703L
|
|
||||||
//
|
|
||||||
// Interface with std::string_view rather than const std::string&
|
|
||||||
// Requires C++17
|
|
||||||
// Provided by Yannic Bonenberger (https://github.com/Yannic)
|
|
||||||
//
|
|
||||||
std::string base64_encode(std::string_view s, bool url = false);
|
|
||||||
std::string base64_encode_pem(std::string_view s);
|
|
||||||
std::string base64_encode_mime(std::string_view s);
|
|
||||||
|
|
||||||
std::string base64_decode(std::string_view s, bool remove_linebreaks = false);
|
|
||||||
#endif // __cplusplus >= 201703L
|
|
||||||
|
|
||||||
#endif /* BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A */
|
|
184
src/chat_room.cc
184
src/chat_room.cc
@ -1,184 +0,0 @@
|
|||||||
#include "pch.h"
|
|
||||||
#include "chat_room.h"
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
#include "wechat_data.h"
|
|
||||||
#define WX_CHAT_ROOM_MGR_OFFSET 0x686e40
|
|
||||||
#define WX_GET_CHAT_ROOM_DETAIL_INFO_OFFSET 0xa70920
|
|
||||||
#define WX_NEW_CHAT_ROOM_INFO_OFFSET 0xd03ec0
|
|
||||||
#define WX_FREE_CHAT_ROOM_INFO_OFFSET 0x7226e0
|
|
||||||
#define WX_DEL_CHAT_ROOM_MEMBER_OFFSET 0xa668f0
|
|
||||||
#define WX_INIT_CHAT_MSG_OFFSET 0xdbcc40
|
|
||||||
#define WX_FREE_CHAT_MSG_OFFSET 0x651c40
|
|
||||||
#define WX_ADD_MEMBER_TO_CHAT_ROOM_OFFSET 0xa66400
|
|
||||||
#define WX_GET_MEMBER_FROM_CHAT_ROOM_OFFSET 0xa71650
|
|
||||||
#define WX_INIT_CHAT_ROOM_OFFSET 0xd01c30
|
|
||||||
#define WX_FREE_CHAT_ROOM_OFFSET 0xa79310
|
|
||||||
|
|
||||||
int GetChatRoomDetailInfo(wchar_t* chat_room_id, ChatRoomInfoInner& room_info) {
|
|
||||||
int success = 0;
|
|
||||||
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;
|
|
||||||
char chat_room_info[0xA4] = {0};
|
|
||||||
__asm {
|
|
||||||
PUSHAD
|
|
||||||
LEA ECX,chat_room_info
|
|
||||||
CALL create_chat_room_info_addr
|
|
||||||
CALL get_chat_room_mgr_addr
|
|
||||||
PUSH 0x0
|
|
||||||
LEA ECX,chat_room_info
|
|
||||||
PUSH ECX
|
|
||||||
LEA ECX,chat_room
|
|
||||||
PUSH ECX
|
|
||||||
MOV ECX,EAX
|
|
||||||
CALL get_chat_room_detail_addr
|
|
||||||
MOV success,EAX
|
|
||||||
POPAD
|
|
||||||
}
|
|
||||||
room_info.chat_room_id.ptr = *(wchar_t**)(chat_room_info + 0x4);
|
|
||||||
room_info.chat_room_id.length = *(DWORD*)(chat_room_info + 0x8);
|
|
||||||
room_info.chat_room_id.max_length = *(DWORD*)(chat_room_info + 0xC);
|
|
||||||
|
|
||||||
room_info.notice.ptr = *(wchar_t**)(chat_room_info + 0x18);
|
|
||||||
room_info.notice.length = *(DWORD*)(chat_room_info + 0x1C);
|
|
||||||
room_info.notice.max_length = *(DWORD*)(chat_room_info + 0x20);
|
|
||||||
|
|
||||||
room_info.admin.ptr = *(wchar_t**)(chat_room_info + 0x2C);
|
|
||||||
room_info.admin.length = *(DWORD*)(chat_room_info + 0x30);
|
|
||||||
room_info.admin.max_length = *(DWORD*)(chat_room_info + 0x34);
|
|
||||||
|
|
||||||
room_info.xml.ptr = *(wchar_t**)(chat_room_info + 0x50);
|
|
||||||
room_info.xml.length = *(DWORD*)(chat_room_info + 0x54);
|
|
||||||
room_info.xml.max_length = *(DWORD*)(chat_room_info + 0x58);
|
|
||||||
__asm {
|
|
||||||
PUSHAD
|
|
||||||
LEA ECX,chat_room_info
|
|
||||||
CALL free_chat_room_info_addr
|
|
||||||
POPAD
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
int 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;
|
|
||||||
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;
|
|
||||||
__asm {
|
|
||||||
PUSHAD
|
|
||||||
CALL get_chat_room_mgr_addr
|
|
||||||
SUB ESP,0x14
|
|
||||||
MOV ESI,EAX
|
|
||||||
MOV ECX,ESP
|
|
||||||
LEA EDI,chat_room
|
|
||||||
PUSH EDI
|
|
||||||
CALL init_chat_msg_addr
|
|
||||||
MOV ECX,ESI
|
|
||||||
MOV EAX,dword ptr[members_ptr]
|
|
||||||
PUSH EAX
|
|
||||||
CALL del_member_addr
|
|
||||||
MOV success,EAX
|
|
||||||
POPAD
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int AddMemberToChatRoom(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;
|
|
||||||
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;
|
|
||||||
__asm {
|
|
||||||
PUSHAD
|
|
||||||
PUSHFD
|
|
||||||
CALL get_chat_room_mgr_addr
|
|
||||||
SUB ESP,0x8
|
|
||||||
MOV temp,EAX
|
|
||||||
MOV ECX,ESP
|
|
||||||
MOV dword ptr [ECX],0x0
|
|
||||||
MOV dword ptr [ECX + 4],0x0
|
|
||||||
TEST ESI,ESI
|
|
||||||
SUB ESP,0x14
|
|
||||||
MOV ECX,ESP
|
|
||||||
LEA EAX,chat_room
|
|
||||||
PUSH EAX
|
|
||||||
CALL init_chat_msg_addr
|
|
||||||
MOV ECX,temp
|
|
||||||
MOV EAX,dword ptr[members_ptr]
|
|
||||||
PUSH EAX
|
|
||||||
CALL add_member_addr
|
|
||||||
MOV success,EAX
|
|
||||||
POPFD
|
|
||||||
POPAD
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int GetMemberFromChatRoom(wchar_t* chat_room_id,ChatRoomInner & out){
|
|
||||||
int success = 0;
|
|
||||||
WeChatString chat_room(chat_room_id);
|
|
||||||
DWORD chat_room_ptr = (DWORD) &chat_room;
|
|
||||||
char buffer[0x1A0] = {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;
|
|
||||||
__asm {
|
|
||||||
PUSHAD
|
|
||||||
LEA ECX,buffer
|
|
||||||
CALL create_chat_room_addr
|
|
||||||
CALL get_chat_room_mgr_addr
|
|
||||||
LEA EAX, buffer
|
|
||||||
PUSH EAX
|
|
||||||
PUSH chat_room_ptr
|
|
||||||
CALL get_member_addr
|
|
||||||
MOVZX EAX,AL
|
|
||||||
MOV success,EAX
|
|
||||||
POPAD
|
|
||||||
}
|
|
||||||
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.admin = new wchar_t[wcslen(admin)+1];
|
|
||||||
wmemcpy(out.admin ,admin,wcslen(admin)+1);
|
|
||||||
|
|
||||||
__asm{
|
|
||||||
LEA ECX,buffer
|
|
||||||
CALL free_chat_room_addr
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
|
@ -1,10 +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);
|
|
||||||
#endif
|
|
138
src/common.cc
138
src/common.cc
@ -1,138 +0,0 @@
|
|||||||
#include "pch.h"
|
|
||||||
#include "common.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();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @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();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief 获取WeChatWin.dll基址
|
|
||||||
/// @return 基址
|
|
||||||
DWORD GetWeChatWinBase() { return (DWORD)GetModuleHandleA("WeChatWin.dll"); }
|
|
||||||
|
|
||||||
/// @brief 创建窗口
|
|
||||||
/// @param void
|
|
||||||
/// @return 创建结果
|
|
||||||
BOOL CreateConsole(void) {
|
|
||||||
if (AllocConsole()) {
|
|
||||||
AttachConsole(GetCurrentProcessId());
|
|
||||||
FILE *retStream;
|
|
||||||
freopen_s(&retStream, "CONOUT$", "w", stdout);
|
|
||||||
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, ×tamp);
|
|
||||||
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) {
|
|
||||||
FindClose(hFind);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!::CreateDirectoryW(path, NULL)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
83
src/common.h
83
src/common.h
@ -1,83 +0,0 @@
|
|||||||
#ifndef COMMON_H_
|
|
||||||
#define COMMON_H_
|
|
||||||
#include <string>
|
|
||||||
using namespace std;
|
|
||||||
#define READ_WSTRING(addr, offset) ((*(DWORD *)(addr + offset + 0x4) == 0) ? wstring(L"") : wstring((wchar_t *)(*(DWORD *)(addr + offset)), *(DWORD *)(addr + offset + 0x4)))
|
|
||||||
|
|
||||||
/// @brief utf8 转换成unicode
|
|
||||||
/// @param buffer utf8
|
|
||||||
/// @return unicode
|
|
||||||
wstring utf8_to_unicode(const char *buffer);
|
|
||||||
|
|
||||||
/// @brief unicode转换utf8
|
|
||||||
/// @param wstr unicode
|
|
||||||
/// @return utf8
|
|
||||||
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
|
|
||||||
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
|
|
||||||
wstring String2Wstring(string str);
|
|
||||||
/// @brief wstring convert string
|
|
||||||
/// @param str
|
|
||||||
/// @return
|
|
||||||
string Wstring2String(wstring wstr);
|
|
||||||
|
|
||||||
/// @brief create dir
|
|
||||||
/// @param path
|
|
||||||
/// @return
|
|
||||||
BOOL FindOrCreateDirectoryW(const wchar_t *path);
|
|
||||||
|
|
||||||
|
|
||||||
template <typename T1, typename T2>
|
|
||||||
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
|
|
106
src/contact.cc
106
src/contact.cc
@ -1,106 +0,0 @@
|
|||||||
#include "pch.h"
|
|
||||||
#include "contact.h"
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "wechat_data.h"
|
|
||||||
|
|
||||||
#define WX_CONTACT_MGR_INSTANCE_OFFSET 0x655d60
|
|
||||||
#define WX_CONTACT_GET_LIST_OFFSET 0xa97da0
|
|
||||||
#define WX_CONTACT_DEL_OFFSET 0xa9bd10
|
|
||||||
#define WX_INIT_CHAT_MSG_OFFSET 0xdbcc40
|
|
||||||
#define WX_DB_QUERY_OFFSET 0xa9ba20
|
|
||||||
#define WX_SYNC_MGR_OFFSET 0x993fa0
|
|
||||||
#define WX_SYNC_MGR_OFFSET 0x993fa0
|
|
||||||
#define WX_DO_DEL_CONTACT_OFFSET 0xb9a750
|
|
||||||
#define WX_DEL_CONTACT_VTABLE_OFFSET 0x2886990
|
|
||||||
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 += 0x3E8;
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
// todo
|
|
||||||
int DelContact(wchar_t *wxid) {
|
|
||||||
int success = 0;
|
|
||||||
WeChatString user_id(wxid);
|
|
||||||
DWORD id_ptr = (DWORD) &user_id;
|
|
||||||
DWORD base = GetWeChatWinBase();
|
|
||||||
DWORD get_instance_addr = base + WX_CONTACT_MGR_INSTANCE_OFFSET;
|
|
||||||
DWORD init_chat_msg_addr = base + WX_INIT_CHAT_MSG_OFFSET;
|
|
||||||
DWORD del_addr = base + WX_CONTACT_DEL_OFFSET;
|
|
||||||
DWORD db_op_addr = base + WX_DB_QUERY_OFFSET;
|
|
||||||
__asm{
|
|
||||||
PUSHAD
|
|
||||||
PUSHFD
|
|
||||||
CALL get_instance_addr
|
|
||||||
MOV ECX,dword ptr[id_ptr]
|
|
||||||
PUSH ECX
|
|
||||||
MOV ECX,EAX
|
|
||||||
MOV ESI,EAX
|
|
||||||
CALL db_op_addr
|
|
||||||
SUB ESP,0x14
|
|
||||||
MOV EAX,dword ptr[id_ptr]
|
|
||||||
MOV ECX,ESP
|
|
||||||
PUSH EAX
|
|
||||||
CALL init_chat_msg_addr
|
|
||||||
MOV ECX,ESI
|
|
||||||
CALL del_addr
|
|
||||||
MOV success,EAX
|
|
||||||
POPFD
|
|
||||||
POPAD
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
|||||||
#ifndef CONTACT_H_
|
|
||||||
#define CONTACT_H_
|
|
||||||
#include <vector>
|
|
||||||
#include "wechat_data.h"
|
|
||||||
|
|
||||||
int GetAllContact(vector<Contact> &vec);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int DelContact(wchar_t* wxid);
|
|
||||||
#endif
|
|
@ -1,155 +0,0 @@
|
|||||||
#include "pch.h"
|
|
||||||
#include "db_operation.h"
|
|
||||||
|
|
||||||
#include "base64.h"
|
|
||||||
#include "common.h"
|
|
||||||
#include "new_sqlite3.h"
|
|
||||||
|
|
||||||
|
|
||||||
/// @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;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
#ifndef DB_OPERATION_H_
|
|
||||||
#define DB_OPERATION_H_
|
|
||||||
#include <windows.h>
|
|
||||||
#include <vector>
|
|
||||||
using namespace std;
|
|
||||||
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,vector<vector<string>> &query_result);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,23 +0,0 @@
|
|||||||
#include "pch.h"
|
|
||||||
#include "api.h"
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call,
|
|
||||||
LPVOID lpReserved) {
|
|
||||||
switch (ul_reason_for_call) {
|
|
||||||
case DLL_PROCESS_ATTACH: {
|
|
||||||
http_start(19088);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DLL_THREAD_ATTACH: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DLL_THREAD_DETACH: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DLL_PROCESS_DETACH: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
@ -1,41 +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 0xb68c80
|
|
||||||
#define WX_INIT_CHAT_MSG_OFFSET 0xdbcc40
|
|
||||||
|
|
||||||
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
|
|
||||||
CALL forward_msg_addr
|
|
||||||
MOVZX EAX,AL;
|
|
||||||
MOV success,EAX
|
|
||||||
ADD ESP,0x1c
|
|
||||||
POPFD
|
|
||||||
POPAD
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
#ifndef FORWARD_H_
|
|
||||||
#define FORWARD_H_
|
|
||||||
|
|
||||||
int ForwardMsg(wchar_t *wxid, unsigned long long msgid);
|
|
||||||
#endif
|
|
@ -1,7 +0,0 @@
|
|||||||
#ifndef FRAMEWORK_H_
|
|
||||||
#define FRAMEWORK_H_
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,299 +0,0 @@
|
|||||||
#include "get_db_handle.h"
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "db_operation.h"
|
|
||||||
#include "new_sqlite3.h"
|
|
||||||
#include "pch.h"
|
|
||||||
#include "wechat_data.h"
|
|
||||||
#define CONTACT_G_PINSTANCE 0x2bee928
|
|
||||||
#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 PUBLIC_MSG_MGR_OFFSET 0x2c294c0
|
|
||||||
#define MULTI_DB_MSG_MGR_OFFSET 0x2c2aff4
|
|
||||||
#define FAVORITE_STORAGE_MGR_OFFSET 0x2c2aa14
|
|
||||||
#define FTS_FAVORITE_MGR_OFFSET 0x2bef468
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
map<wstring, DatabaseInfo> dbmap;
|
|
||||||
std::vector<DatabaseInfo> dbs;
|
|
||||||
|
|
||||||
int GetDbInfo(void *data, int argc, char **argv, char **name) {
|
|
||||||
DatabaseInfo *pdata = (DatabaseInfo *)data;
|
|
||||||
TableInfo tb = {0};
|
|
||||||
if (argv[1]) {
|
|
||||||
tb.name = new char[strlen(argv[1]) + 1];
|
|
||||||
memcpy(tb.name, argv[1], strlen(argv[1]) + 1);
|
|
||||||
} else {
|
|
||||||
tb.name = (char *)"NULL";
|
|
||||||
}
|
|
||||||
if (argv[2]) {
|
|
||||||
tb.table_name = new char[strlen(argv[2]) + 1];
|
|
||||||
memcpy(tb.table_name, argv[2], strlen(argv[2]) + 1);
|
|
||||||
} else {
|
|
||||||
tb.table_name = (char *)"NULL";
|
|
||||||
}
|
|
||||||
if (argv[3]) {
|
|
||||||
tb.rootpage = new char[strlen(argv[3]) + 1];
|
|
||||||
memcpy(tb.rootpage, argv[3], strlen(argv[3]) + 1);
|
|
||||||
} else {
|
|
||||||
tb.rootpage = (char *)"NULL";
|
|
||||||
}
|
|
||||||
if (argv[4]) {
|
|
||||||
tb.sql = new char[strlen(argv[4]) + 1];
|
|
||||||
memcpy(tb.sql, argv[4], strlen(argv[4]) + 1);
|
|
||||||
} else {
|
|
||||||
tb.sql = (char *)"NULL";
|
|
||||||
}
|
|
||||||
tb.name_len = strlen(tb.name);
|
|
||||||
tb.table_name_len = strlen(tb.table_name);
|
|
||||||
tb.sql_len = strlen(tb.sql);
|
|
||||||
tb.rootpage_len = strlen(tb.rootpage);
|
|
||||||
pdata->tables.push_back(tb);
|
|
||||||
pdata->count = pdata->tables.size();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<void *> GetDbHandles() {
|
|
||||||
dbs.clear();
|
|
||||||
dbmap.clear();
|
|
||||||
DWORD base = GetWeChatWinBase();
|
|
||||||
DWORD p_contact_addr = *(DWORD *)(base + CONTACT_G_PINSTANCE);
|
|
||||||
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);
|
|
||||||
DWORD emotion_db_addr = *(DWORD *)(p_contact_addr + DB_EMOTION_OFFSET);
|
|
||||||
DWORD media_db_addr = *(DWORD *)(p_contact_addr + DB_MEDIA_OFFSET);
|
|
||||||
DWORD bizchat_msg_db_addr =
|
|
||||||
*(DWORD *)(p_contact_addr + DB_BIZCHAT_MSG_OFFSET);
|
|
||||||
DWORD function_msg_db_addr =
|
|
||||||
*(DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET);
|
|
||||||
|
|
||||||
// microMsg.db
|
|
||||||
DatabaseInfo micro_msg_db{0};
|
|
||||||
micro_msg_db.db_name = (wchar_t *)(*(
|
|
||||||
DWORD *)(p_contact_addr + DB_MICRO_MSG_OFFSET + DB_NAME_OFFSET));
|
|
||||||
micro_msg_db.db_name_len =
|
|
||||||
*(DWORD *)(p_contact_addr + DB_MICRO_MSG_OFFSET + DB_NAME_OFFSET + 0x4);
|
|
||||||
micro_msg_db.handle = micro_msg_db_addr;
|
|
||||||
ExecuteSQL(micro_msg_db_addr,
|
|
||||||
"select * from sqlite_master where type=\"table\";",
|
|
||||||
(DWORD)GetDbInfo, µ_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;
|
|
||||||
|
|
||||||
// chatMsg.db
|
|
||||||
DatabaseInfo chat_msg_db{0};
|
|
||||||
chat_msg_db.db_name = (wchar_t *)(*(
|
|
||||||
DWORD *)(p_contact_addr + DB_CHAT_MSG_OFFSET + DB_NAME_OFFSET));
|
|
||||||
chat_msg_db.db_name_len =
|
|
||||||
*(DWORD *)(p_contact_addr + DB_CHAT_MSG_OFFSET + DB_NAME_OFFSET + 0x4);
|
|
||||||
chat_msg_db.handle = chat_msg_db_addr;
|
|
||||||
ExecuteSQL(chat_msg_db_addr,
|
|
||||||
"select * from sqlite_master where type=\"table\";",
|
|
||||||
(DWORD)GetDbInfo, &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;
|
|
||||||
|
|
||||||
// misc.db
|
|
||||||
DatabaseInfo misc_db{0};
|
|
||||||
misc_db.db_name =
|
|
||||||
(wchar_t *)(*(DWORD *)(p_contact_addr + DB_MISC_OFFSET + DB_NAME_OFFSET));
|
|
||||||
misc_db.db_name_len =
|
|
||||||
*(DWORD *)(p_contact_addr + DB_MISC_OFFSET + DB_NAME_OFFSET + 0x4);
|
|
||||||
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);
|
|
||||||
wstring misc_name = wstring((
|
|
||||||
wchar_t *)(*(DWORD *)(p_contact_addr + DB_MISC_OFFSET + DB_NAME_OFFSET)));
|
|
||||||
dbmap[misc_name] = misc_db;
|
|
||||||
|
|
||||||
// emotion.db
|
|
||||||
DatabaseInfo emotion_db{0};
|
|
||||||
emotion_db.db_name = (wchar_t *)(*(
|
|
||||||
DWORD *)(p_contact_addr + DB_EMOTION_OFFSET + DB_NAME_OFFSET));
|
|
||||||
emotion_db.db_name_len =
|
|
||||||
*(DWORD *)(p_contact_addr + DB_EMOTION_OFFSET + DB_NAME_OFFSET + 0x4);
|
|
||||||
emotion_db.handle = emotion_db_addr;
|
|
||||||
ExecuteSQL(emotion_db_addr,
|
|
||||||
"select * from sqlite_master where type=\"table\";",
|
|
||||||
(DWORD)GetDbInfo, &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;
|
|
||||||
|
|
||||||
// media.db
|
|
||||||
DatabaseInfo media_db{0};
|
|
||||||
media_db.db_name = (wchar_t *)(*(DWORD *)(p_contact_addr + DB_MEDIA_OFFSET +
|
|
||||||
DB_NAME_OFFSET));
|
|
||||||
media_db.db_name_len =
|
|
||||||
*(DWORD *)(p_contact_addr + DB_MEDIA_OFFSET + DB_NAME_OFFSET + 0x4);
|
|
||||||
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);
|
|
||||||
wstring media_name = wstring((wchar_t *)(*(
|
|
||||||
DWORD *)(p_contact_addr + DB_MEDIA_OFFSET + DB_NAME_OFFSET)));
|
|
||||||
dbmap[media_name] = media_db;
|
|
||||||
|
|
||||||
// functionMsg.db
|
|
||||||
DatabaseInfo function_msg_db{0};
|
|
||||||
function_msg_db.db_name = (wchar_t *)(*(
|
|
||||||
DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET));
|
|
||||||
function_msg_db.db_name_len = *(
|
|
||||||
DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET + 0x4);
|
|
||||||
function_msg_db.handle = function_msg_db_addr;
|
|
||||||
ExecuteSQL(function_msg_db_addr,
|
|
||||||
"select * from sqlite_master where type=\"table\";",
|
|
||||||
(DWORD)GetDbInfo, &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;
|
|
||||||
|
|
||||||
if (bizchat_msg_db_addr) {
|
|
||||||
// functionMsg.db maybe null
|
|
||||||
DatabaseInfo bizchat_msg_db{0};
|
|
||||||
bizchat_msg_db.db_name = (wchar_t *)(*(
|
|
||||||
DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET));
|
|
||||||
bizchat_msg_db.db_name_len =
|
|
||||||
*(DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET +
|
|
||||||
0x4);
|
|
||||||
bizchat_msg_db.handle = bizchat_msg_db_addr;
|
|
||||||
ExecuteSQL(bizchat_msg_db_addr,
|
|
||||||
"select * from sqlite_master where type=\"table\";",
|
|
||||||
(DWORD)GetDbInfo, &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;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
|
|
||||||
// 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 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;
|
|
||||||
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\";",
|
|
||||||
(DWORD)GetDbInfo, &msg0_db);
|
|
||||||
dbs.push_back(msg0_db);
|
|
||||||
wstring msg_db_name = wstring((wchar_t *)(*(DWORD *)(db_addr)));
|
|
||||||
dbmap[msg_db_name] = msg0_db;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// publicMsg.db
|
|
||||||
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.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Favorite.db
|
|
||||||
DWORD favItems_ptr = *(DWORD *)(*(DWORD *)(favorite_storage_mgr_addr) + 0x8);
|
|
||||||
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_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;
|
|
||||||
}
|
|
||||||
|
|
||||||
DatabaseInfo db_end = {0};
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
vector<void *> ret_array;
|
|
||||||
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) {
|
|
||||||
GetDbHandles();
|
|
||||||
}
|
|
||||||
if (dbmap.find(dbname) != dbmap.end()) {
|
|
||||||
return dbmap[dbname].handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int 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;
|
|
||||||
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;
|
|
||||||
return stoi(result[1][0]);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
#ifndef GET_DB_HANDLE_H_
|
|
||||||
#define GET_DB_HANDLE_H_
|
|
||||||
#include "windows.h"
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
std::vector<void *> GetDbHandles();
|
|
||||||
DWORD GetDbHandleByDbName(wchar_t *dbname);
|
|
||||||
unsigned int GetLocalIdByMsgId(ULONG64 msgid, int &dbIndex);
|
|
||||||
#endif
|
|
231
src/hook_img.cc
231
src/hook_img.cc
@ -1,231 +0,0 @@
|
|||||||
#include "pch.h"
|
|
||||||
#include "hook_img.h"
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
|
|
||||||
// #define WX_HOOK_IMG_OFFSET 0xd7eaa5
|
|
||||||
// #define WX_HOOK_IMG_NEXT_OFFSET 0xda56e0
|
|
||||||
#define WX_HOOK_IMG_OFFSET 0xc63ebc
|
|
||||||
#define WX_HOOK_IMG_NEXT_OFFSET 0xd7e9e0
|
|
||||||
#define WX_SELF_ID_OFFSET 0x2BEE08C
|
|
||||||
#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;
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
#ifndef HOOK_IMG_H_
|
|
||||||
#define HOOK_IMG_H_
|
|
||||||
#include "windows.h"
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int HookImg(wstring save_path);
|
|
||||||
int UnHookImg();
|
|
||||||
|
|
||||||
int GetImgByName(wchar_t* file_path,wchar_t* save_dir);
|
|
||||||
#endif
|
|
@ -1,220 +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 0xb94796
|
|
||||||
#define WX_RECV_MSG_HOOK_NEXT_OFFSET 0x6fe2c0
|
|
||||||
|
|
||||||
// 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 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;
|
|
||||||
|
|
||||||
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, CLIENT_IP, &client_addr.sin_addr.s_addr);
|
|
||||||
if (connect(client_socket, reinterpret_cast<sockaddr *>(&client_addr),
|
|
||||||
sizeof(sockaddr)) < 0) {
|
|
||||||
#ifdef _DEBUG
|
|
||||||
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 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());
|
|
||||||
#ifdef _DEBUG
|
|
||||||
printf("%s", j_msg["content"].get<std::string>().c_str());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// @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 any address address+0x5
|
|
||||||
/// @param port 端口
|
|
||||||
/// @return 成功返回1,已经hook返回2,失败返回-1
|
|
||||||
int HookRecvMsg(int port) {
|
|
||||||
kServerPort = port;
|
|
||||||
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);
|
|
||||||
kMessageHooked = TRUE;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int UnHookRecvMsg() {
|
|
||||||
kServerPort = 0;
|
|
||||||
if (!kMessageHooked) return 2;
|
|
||||||
DWORD hook_recv_msg_addr = kWeChatWinBase + WX_RECV_MSG_HOOK_OFFSET;
|
|
||||||
UnHookAnyAddress(hook_recv_msg_addr, kOriginReceMsgAsmCode);
|
|
||||||
kMessageHooked = FALSE;
|
|
||||||
return 1;
|
|
||||||
}
|
|
@ -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(int port);
|
|
||||||
|
|
||||||
int UnHookRecvMsg();
|
|
||||||
#endif
|
|
@ -1,195 +0,0 @@
|
|||||||
#ifndef NEW_SQLITE3_H_
|
|
||||||
#define NEW_SQLITE3_H_
|
|
||||||
#include "Windows.h"
|
|
||||||
#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 0x1b623b0
|
|
||||||
#define SQLITE3_BACKUP_INIT_OFFSET 0x1b27d50
|
|
||||||
#define SQLITE3_PREPARE_OFFSET 0x1b68d00
|
|
||||||
#define SQLITE3_OPEN_OFFSET 0x1b96cf0
|
|
||||||
#define SQLITE3_BACKUP_STEP_OFFSET 0x1b28150
|
|
||||||
#define SQLITE3_BACKUP_REMAINING_OFFSET 0x1b28890
|
|
||||||
#define SQLITE3_BACKUP_PAGECOUNT_OFFSET 0x1b288a0
|
|
||||||
#define SQLITE3_BACKUP_FINISH_OFFSET 0x1b28790
|
|
||||||
#define SQLITE3_SLEEP_OFFSET 0x1b97530
|
|
||||||
#define SQLITE3_ERRCODE_OFFSET 0x1b95990
|
|
||||||
#define SQLITE3_CLOSE_OFFSET 0x1b94110
|
|
||||||
#define SQLITE3_STEP_OFFSET 0x1b30bc0
|
|
||||||
#define SQLITE3_COLUMN_COUNT_OFFSET 0x1b310d0
|
|
||||||
#define SQLITE3_COLUMN_NAME_OFFSET 0x1b319c0
|
|
||||||
#define SQLITE3_COLUMN_TYPE_OFFSET 0x1b31860
|
|
||||||
#define SQLITE3_COLUMN_BLOB_OFFSET 0x1b31110
|
|
||||||
#define SQLITE3_COLUMN_BYTES_OFFSET 0x1b311f0
|
|
||||||
#define SQLITE3_FINALIZE_OFFSET 0x1b2fb90
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
#endif
|
|
18
src/pch.h
18
src/pch.h
@ -1,18 +0,0 @@
|
|||||||
#ifndef PCH_H
|
|
||||||
#define PCH_H
|
|
||||||
|
|
||||||
|
|
||||||
#define GLOG_NO_ABBREVIATED_SEVERITIES
|
|
||||||
#include "framework.h"
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
#include <strstream>
|
|
||||||
#include <string>
|
|
||||||
#include <sstream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <time.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#endif // PCH_H
|
|
||||||
|
|
||||||
|
|
139
src/self_info.cc
139
src/self_info.cc
@ -1,139 +0,0 @@
|
|||||||
#include "pch.h"
|
|
||||||
#include "self_info.h"
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
#include "wechat_data.h"
|
|
||||||
|
|
||||||
#define WX_SELF_NAME_OFFSET 0x2bee198
|
|
||||||
#define WX_SELF_MOBILE_OFFSET 0x2BEE108
|
|
||||||
#define WX_SELF_CITY_OFFSET 0x2BEE168
|
|
||||||
#define WX_SELF_PROVINCE_OFFSET 0x2BEE150
|
|
||||||
#define WX_SELF_COUNTRY_OFFSET 0x2BEE138
|
|
||||||
#define WX_SELF_ACCOUNT_OFFSET 0x2BEE0F0
|
|
||||||
#define WX_SELF_ID_OFFSET 0x2BEE08C
|
|
||||||
#define WX_SELF_SMALL_IMG_OFFSET 0x2BEE34C
|
|
||||||
#define WX_SELF_BIG_IMG_OFFSET 0x2BEE364
|
|
||||||
#define WX_LOGIN_STATUS_OFFSET 0x2BEE4C0
|
|
||||||
#define WX_APP_DATA_ROOT_PATH_OFFSET 0x2c2f478
|
|
||||||
#define WX_APP_DATA_SAVE_PATH_OFFSET 0x2C10D04
|
|
||||||
#define WX_CURRENT_DATA_PATH_OFFSET 0x2C0EC38
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int GetSelfInfo(SelfInfoInner &out) {
|
|
||||||
DWORD base = GetWeChatWinBase();
|
|
||||||
#ifdef _DEBUG
|
|
||||||
cout << "mobile:" << (char *)(base + WX_SELF_MOBILE_OFFSET) << endl;
|
|
||||||
cout << "name:" << (char *)(base + WX_SELF_NAME_OFFSET) << endl;
|
|
||||||
cout << "city:" << (char *)(base + WX_SELF_CITY_OFFSET) << endl;
|
|
||||||
cout << "city:" << (char *)(base + WX_SELF_CITY_OFFSET) << endl;
|
|
||||||
cout << "province:" << (char *)(base + WX_SELF_PROVINCE_OFFSET) << endl;
|
|
||||||
cout << "country:" << (char *)(base + WX_SELF_COUNTRY_OFFSET) << endl;
|
|
||||||
cout << "account:" << (char *)(base + WX_SELF_ACCOUNT_OFFSET) << endl;
|
|
||||||
cout << "wxid:" << (char *)(base + WX_SELF_ID_OFFSET) << endl;
|
|
||||||
cout << "small_img:" << (char *)(base + WX_SELF_SMALL_IMG_OFFSET) << endl;
|
|
||||||
cout << "big_img:" << (char *)(base + WX_SELF_BIG_IMG_OFFSET) << endl;
|
|
||||||
#endif
|
|
||||||
if (*(DWORD *)(base + WX_SELF_NAME_OFFSET) == 0 ||
|
|
||||||
*(DWORD *)(base + WX_SELF_NAME_OFFSET + 0x10) == 0) {
|
|
||||||
out.name = string();
|
|
||||||
} else {
|
|
||||||
out.name = string((char *)(base + WX_SELF_NAME_OFFSET),
|
|
||||||
*(DWORD *)(base + WX_SELF_NAME_OFFSET + 0x10));
|
|
||||||
}
|
|
||||||
if (*(DWORD *)(base + WX_SELF_MOBILE_OFFSET) == 0 ||
|
|
||||||
*(DWORD *)(base + WX_SELF_MOBILE_OFFSET + 0x10) == 0) {
|
|
||||||
out.mobile = string();
|
|
||||||
} else {
|
|
||||||
out.mobile = string((char *)(base + WX_SELF_MOBILE_OFFSET),
|
|
||||||
*(DWORD *)(base + WX_SELF_MOBILE_OFFSET + 0x10));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*(DWORD *)(base + WX_SELF_CITY_OFFSET) == 0 ||
|
|
||||||
*(DWORD *)(base + WX_SELF_CITY_OFFSET + 0x10) == 0) {
|
|
||||||
out.city = string();
|
|
||||||
} else {
|
|
||||||
out.city = string((char *)(base + WX_SELF_CITY_OFFSET),
|
|
||||||
*(DWORD *)(base + WX_SELF_CITY_OFFSET + 0x10));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*(DWORD *)(base + WX_SELF_PROVINCE_OFFSET) == 0 ||
|
|
||||||
*(DWORD *)(base + WX_SELF_PROVINCE_OFFSET + 0x10) == 0) {
|
|
||||||
out.province = string();
|
|
||||||
} else {
|
|
||||||
out.province = string((char *)(base + WX_SELF_PROVINCE_OFFSET),
|
|
||||||
*(DWORD *)(base + WX_SELF_PROVINCE_OFFSET + 0x10));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*(DWORD *)(base + WX_SELF_COUNTRY_OFFSET) == 0 ||
|
|
||||||
*(DWORD *)(base + WX_SELF_COUNTRY_OFFSET + 0x10) == 0) {
|
|
||||||
out.country = string();
|
|
||||||
} else {
|
|
||||||
out.country = string((char *)(base + WX_SELF_COUNTRY_OFFSET),
|
|
||||||
*(DWORD *)(base + WX_SELF_COUNTRY_OFFSET + 0x10));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*(DWORD *)(base + WX_SELF_ACCOUNT_OFFSET) == 0 ||
|
|
||||||
*(DWORD *)(base + WX_SELF_ACCOUNT_OFFSET + 0x10) == 0) {
|
|
||||||
out.account = string();
|
|
||||||
} else {
|
|
||||||
out.account = string(*(char **)(base + WX_SELF_ACCOUNT_OFFSET),
|
|
||||||
*(DWORD *)(base + WX_SELF_ACCOUNT_OFFSET + 0x10));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*(DWORD *)(base + WX_SELF_ID_OFFSET) == 0 ||
|
|
||||||
*(DWORD *)(base + WX_SELF_ID_OFFSET + 0x10) == 0) {
|
|
||||||
out.wxid = string();
|
|
||||||
} else {
|
|
||||||
out.wxid = string(*(char **)(base + WX_SELF_ID_OFFSET),
|
|
||||||
*(DWORD *)(base + WX_SELF_ID_OFFSET + 0x10));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*(DWORD *)(base + WX_SELF_SMALL_IMG_OFFSET) == 0 ||
|
|
||||||
*(DWORD *)(base + WX_SELF_SMALL_IMG_OFFSET + 0x10) == 0) {
|
|
||||||
out.small_img = string();
|
|
||||||
} else {
|
|
||||||
out.small_img = string(*(char **)(base + WX_SELF_SMALL_IMG_OFFSET),
|
|
||||||
*(DWORD *)(base + WX_SELF_SMALL_IMG_OFFSET + 0x10));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*(DWORD *)(base + WX_SELF_BIG_IMG_OFFSET) == 0 ||
|
|
||||||
*(DWORD *)(base + WX_SELF_BIG_IMG_OFFSET + 0x10) == 0) {
|
|
||||||
out.big_img = string();
|
|
||||||
} else {
|
|
||||||
out.big_img = string(*(char **)(base + WX_SELF_BIG_IMG_OFFSET),
|
|
||||||
*(DWORD *)(base + WX_SELF_BIG_IMG_OFFSET + 0x10));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*(DWORD *)(base + WX_APP_DATA_ROOT_PATH_OFFSET) == 0 ||
|
|
||||||
*(DWORD *)(base + WX_APP_DATA_ROOT_PATH_OFFSET + 0x4) == 0) {
|
|
||||||
out.data_root_path = string();
|
|
||||||
} else {
|
|
||||||
out.data_root_path = Wstring2String(wstring(*(wchar_t **)(base + WX_APP_DATA_ROOT_PATH_OFFSET),
|
|
||||||
*(DWORD *)(base + WX_APP_DATA_ROOT_PATH_OFFSET + 0x4)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*(DWORD *)(base + WX_APP_DATA_SAVE_PATH_OFFSET) == 0 ||
|
|
||||||
*(DWORD *)(base + WX_APP_DATA_SAVE_PATH_OFFSET + 0x4) == 0) {
|
|
||||||
out.data_save_path = string();
|
|
||||||
} else {
|
|
||||||
out.data_save_path = Wstring2String(wstring(*(wchar_t **)(base + WX_APP_DATA_SAVE_PATH_OFFSET),
|
|
||||||
*(DWORD *)(base + WX_APP_DATA_SAVE_PATH_OFFSET + 0x4)));
|
|
||||||
}
|
|
||||||
if (*(DWORD *)(base + WX_CURRENT_DATA_PATH_OFFSET) == 0 ||
|
|
||||||
*(DWORD *)(base + WX_CURRENT_DATA_PATH_OFFSET + 0x4) == 0) {
|
|
||||||
out.current_data_path = string();
|
|
||||||
} else {
|
|
||||||
out.current_data_path = Wstring2String(wstring(*(wchar_t **)(base + WX_CURRENT_DATA_PATH_OFFSET),
|
|
||||||
*(DWORD *)(base + WX_CURRENT_DATA_PATH_OFFSET + 0x4)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int CheckLogin(){
|
|
||||||
DWORD base = GetWeChatWinBase();
|
|
||||||
return *(DWORD*) (base + WX_LOGIN_STATUS_OFFSET);
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
#ifndef SELF_INFO_H_
|
|
||||||
#define SELF_INFO_H_
|
|
||||||
#include "wechat_data.h"
|
|
||||||
int GetSelfInfo(SelfInfoInner& out);
|
|
||||||
|
|
||||||
int CheckLogin();
|
|
||||||
#endif
|
|
@ -1,67 +0,0 @@
|
|||||||
#include "pch.h"
|
|
||||||
#include "send_file.h"
|
|
||||||
#include "common.h"
|
|
||||||
#include "wechat_data.h"
|
|
||||||
|
|
||||||
#define WX_APP_MSG_MGR_OFFSET 0x665f60
|
|
||||||
#define WX_SEND_FILE_OFFSET 0xa0ce20
|
|
||||||
#define WX_INIT_CHAT_MSG_OFFSET 0xdbcc40
|
|
||||||
#define WX_FREE_CHAT_MSG_OFFSET 0x651c40
|
|
||||||
|
|
||||||
int SendFile(wchar_t *wxid, wchar_t *file_path){
|
|
||||||
int success = 0;
|
|
||||||
WeChatString to_user(wxid);
|
|
||||||
WeChatString path(file_path);
|
|
||||||
char chat_msg[0x2A8] = {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;
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
#ifndef SEND_FILE_H_
|
|
||||||
#define SEND_FILE_H_
|
|
||||||
|
|
||||||
int SendFile(wchar_t *wxid, wchar_t *file_path);
|
|
||||||
#endif
|
|
@ -1,47 +0,0 @@
|
|||||||
#include "pch.h"
|
|
||||||
#include "send_image.h"
|
|
||||||
#include "common.h"
|
|
||||||
#include "wechat_data.h"
|
|
||||||
|
|
||||||
#define WX_SEND_IMAGE_OFFSET 0xb68b90
|
|
||||||
#define WX_SEND_MESSAGE_MGR_OFFSET 0x663320
|
|
||||||
#define WX_INIT_CHAT_MSG_OFFSET 0xdbcc40
|
|
||||||
#define WX_FREE_CHAT_MSG_OFFSET 0x651c40
|
|
||||||
|
|
||||||
int SendImage(wchar_t *wxid, wchar_t *image_path){
|
|
||||||
|
|
||||||
int success = 0;
|
|
||||||
WeChatString to_user(wxid);
|
|
||||||
WeChatString path(image_path);
|
|
||||||
char chat_msg[0x2A8] ={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;
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
#ifndef SEND_IMAGE_H_
|
|
||||||
#define SEND_IMAGE_H_
|
|
||||||
|
|
||||||
int SendImage(wchar_t *wxid, wchar_t *image_path);
|
|
||||||
#endif
|
|
@ -1,45 +0,0 @@
|
|||||||
#include "pch.h"
|
|
||||||
#include "send_text.h"
|
|
||||||
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "wechat_data.h"
|
|
||||||
|
|
||||||
#define WX_SEND_TEXT_OFFSET 0xb690a0
|
|
||||||
|
|
||||||
#define WX_SEND_MESSAGE_MGR_OFFSET 0x663320
|
|
||||||
|
|
||||||
#define WX_FREE_CHAT_MSG_OFFSET 0x651c40
|
|
||||||
/// @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;
|
|
||||||
char chat_msg[0x2A8] ={0};
|
|
||||||
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_msg_addr = base + WX_FREE_CHAT_MSG_OFFSET;
|
|
||||||
__asm{
|
|
||||||
PUSHAD
|
|
||||||
PUSH 0x0
|
|
||||||
PUSH 0x0
|
|
||||||
PUSH 0x1
|
|
||||||
PUSH 0x0
|
|
||||||
MOV EDI,msg_pptr
|
|
||||||
PUSH EDI
|
|
||||||
LEA EDX,to_user
|
|
||||||
LEA ECX,chat_msg
|
|
||||||
CALL send_text_msg_addr
|
|
||||||
ADD ESP,0x14
|
|
||||||
MOV success,EAX
|
|
||||||
LEA ECX,chat_msg
|
|
||||||
CALL free_msg_addr
|
|
||||||
POPAD
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
#ifndef SEND_TEXT_H_
|
|
||||||
#define SEND_TEXT_H_
|
|
||||||
|
|
||||||
int SendText(wchar_t* wxid, wchar_t* msg);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,140 +0,0 @@
|
|||||||
#ifndef WECHAT_DATA_H_
|
|
||||||
#define WECHAT_DATA_H_
|
|
||||||
|
|
||||||
// #include <windows.h>
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
using namespace std;
|
|
||||||
struct WeChatString {
|
|
||||||
wchar_t *ptr;
|
|
||||||
DWORD length;
|
|
||||||
DWORD max_length;
|
|
||||||
DWORD c_ptr = 0;
|
|
||||||
DWORD c_len = 0;
|
|
||||||
WeChatString() { WeChatString(NULL); }
|
|
||||||
|
|
||||||
WeChatString(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;
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
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{
|
|
||||||
string name;
|
|
||||||
string city;
|
|
||||||
string province;
|
|
||||||
string country;
|
|
||||||
string account;
|
|
||||||
string wxid;
|
|
||||||
string mobile;
|
|
||||||
string small_img;
|
|
||||||
string big_img;
|
|
||||||
string data_root_path;
|
|
||||||
string data_save_path;
|
|
||||||
string current_data_path;
|
|
||||||
};
|
|
||||||
#endif
|
|
Loading…
Reference in New Issue
Block a user