Refacoring

This commit is contained in:
Changhua 2025-02-05 23:07:46 +08:00
parent 505eefd03c
commit d4707997ba
3 changed files with 139 additions and 168 deletions

View File

@ -18,6 +18,8 @@ namespace fs = std::filesystem;
extern QWORD g_WeChatWinDllAddr;
namespace misc
{
#define HEADER_PNG1 0x89
#define HEADER_PNG2 0x50
#define HEADER_JPG1 0xFF
@ -38,117 +40,73 @@ extern QWORD g_WeChatWinDllAddr;
#define OS_PUSH_ATTACH_TASK 0x1CDF4E0
#define OS_LOGIN_QR_CODE 0x59620D8
typedef QWORD (*GetSNSDataMgr_t)();
typedef QWORD (*GetSnsTimeLineMgr_t)();
typedef QWORD (*GetSNSFirstPage_t)(QWORD, QWORD, QWORD);
typedef QWORD (*GetSNSNextPageScene_t)(QWORD, QWORD);
typedef QWORD (*GetChatMgr_t)();
typedef QWORD (*NewChatMsg_t)(QWORD);
typedef QWORD (*FreeChatMsg_t)(QWORD);
typedef QWORD (*GetPreDownLoadMgr_t)();
typedef QWORD (*GetMgrByPrefixLocalId_t)(QWORD, QWORD);
typedef QWORD (*PushAttachTask_t)(QWORD, QWORD, QWORD, QWORD);
typedef QWORD (*GetOCRManager_t)();
typedef QWORD (*DoOCRTask_t)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD);
using get_sns_data_mgr_t = QWORD (*)();
using get_sns_timeline_mgr_t = QWORD (*)();
using get_sns_first_page_t = QWORD (*)(QWORD, QWORD, QWORD);
using get_sns_next_page_scene_t = QWORD (*)(QWORD, QWORD);
using get_chat_mgr_t = QWORD (*)();
using new_chat_msg_t = QWORD (*)(QWORD);
using free_chat_msg_t = QWORD (*)(QWORD);
using get_pre_download_mgr_t = QWORD (*)();
using get_mgr_by_prefix_localid_t = QWORD (*)(QWORD, QWORD);
using push_attach_task_t = QWORD (*)(QWORD, QWORD, QWORD, QWORD);
using get_ocr_manager_t = QWORD (*)();
using do_ocr_task_t = QWORD (*)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD);
int IsLogin(void) { return (int)util::get_qword(g_WeChatWinDllAddr + OS_LOGIN_STATUS); }
bool is_logged_in() { return util::get_qword(g_WeChatWinDllAddr + OS_LOGIN_STATUS) != 0; }
static string get_key(uint8_t header1, uint8_t header2, uint8_t *key)
static std::string detect_image_extension(uint8_t header1, uint8_t header2, uint8_t &key)
{
// PNG?
*key = HEADER_PNG1 ^ header1;
if ((HEADER_PNG2 ^ *key) == header2) {
return ".png";
}
// JPG?
*key = HEADER_JPG1 ^ header1;
if ((HEADER_JPG2 ^ *key) == header2) {
return ".jpg";
}
// GIF?
*key = HEADER_GIF1 ^ header1;
if ((HEADER_GIF2 ^ *key) == header2) {
return ".gif";
}
return ""; // 错误
if ((key = HEADER_PNG1 ^ header1) && (HEADER_PNG2 ^ key) == header2) return ".png";
if ((key = HEADER_JPG1 ^ header1) && (HEADER_JPG2 ^ key) == header2) return ".jpg";
if ((key = HEADER_GIF1 ^ header1) && (HEADER_GIF2 ^ key) == header2) return ".gif";
return "";
}
string DecryptImage(string src, string dir)
std::string decrypt_image(const fs::path &src, const fs::path &dst_dir)
{
if (!fs::exists(src)) {
LOG_ERROR("File not exists: {}", src);
LOG_ERROR("文件不存在: {}", src.string());
return "";
}
ifstream in(src.c_str(), ios::binary);
if (!in.is_open()) {
LOG_ERROR("Failed to read file {}", src);
std::ifstream in(src, std::ios::binary);
if (!in) {
LOG_ERROR("无法打开文件: {}", src.string());
return "";
}
filebuf *pfb = in.rdbuf();
size_t size = pfb->pubseekoff(0, ios::end, ios::in);
pfb->pubseekpos(0, ios::in);
vector<char> buff;
buff.reserve(size);
char *pBuf = buff.data();
pfb->sgetn(pBuf, size);
in.close();
std::vector<char> buffer(std::istreambuf_iterator<char>(in), {});
if (buffer.size() < 2) return "";
uint8_t key = 0x00;
string ext = get_key(pBuf[0], pBuf[1], &key);
if (ext.empty()) {
LOG_ERROR("Failed to get key.");
auto ext = detect_image_extension(buffer[0], buffer[1], key);
if (!ext) {
LOG_ERROR("无法检测文件类型.");
return "";
}
for (size_t i = 0; i < size; i++) {
pBuf[i] ^= key;
}
std::for_each(buffer.begin(), buffer.end(), [key](char &c) { c ^= key; });
string dst = "";
fs::path dst_path = dst_dir / (src.stem().string() + *ext);
if (!fs::exists(dst_dir)) fs::create_directories(dst_dir);
if (dir.empty()) {
dst = fs::path(src).replace_extension(ext).string();
} else {
dst = (dir.back() == '\\' || dir.back() == '/') ? dir : (dir + "/");
// 判断dir文件夹是否存在若不存在则创建否则将无法创建出文件
if (!fs::exists(dst)) { // 判断该文件夹是否存在
bool success = fs::create_directories(dst); // Windows创建文件夹
if (!success) { // 创建失败
LOG_ERROR("Failed to mkdir:{}", dst);
return "";
}
}
dst += fs::path(src).stem().string() + ext;
}
replace(dst.begin(), dst.end(), '\\', '/');
ofstream out(dst.c_str(), ios::binary);
if (!out.is_open()) {
LOG_ERROR("Failed to write file {}", dst);
std::ofstream out(dst_path, std::ios::binary);
if (!out) {
LOG_ERROR("写入文件失败: {}", dst_path.string());
return "";
}
out.write(pBuf, size);
out.close();
return dst;
out.write(buffer.data(), buffer.size());
return dst_path.string();
}
static int GetFirstPage()
static int get_first_page()
{
int status = -1;
GetSNSDataMgr_t GetSNSDataMgr = (GetSNSDataMgr_t)(g_WeChatWinDllAddr + OS_GET_SNS_DATA_MGR);
GetSNSFirstPage_t GetSNSFirstPage = (GetSNSFirstPage_t)(g_WeChatWinDllAddr + OS_GET_SNS_FIRST_PAGE);
get_sns_data_mgr_t GetSNSDataMgr = (get_sns_data_mgr_t)(g_WeChatWinDllAddr + OS_GET_SNS_DATA_MGR);
get_sns_first_page_t GetSNSFirstPage = (get_sns_first_page_t)(g_WeChatWinDllAddr + OS_GET_SNS_FIRST_PAGE);
QWORD buff[16] = { 0 };
QWORD mgr = GetSNSDataMgr();
@ -157,12 +115,13 @@ static int GetFirstPage()
return status;
}
static int GetNextPage(QWORD id)
static int get_next_page(QWORD id)
{
int status = -1;
GetSnsTimeLineMgr_t GetSnsTimeLineMgr = (GetSnsTimeLineMgr_t)(g_WeChatWinDllAddr + OS_GET_SNS_TIMELINE_MGR);
GetSNSNextPageScene_t GetSNSNextPageScene = (GetSNSNextPageScene_t)(g_WeChatWinDllAddr + OS_GET_SNS_NEXT_PAGE);
get_sns_timeline_mgr_t GetSnsTimeLineMgr = (get_sns_timeline_mgr_t)(g_WeChatWinDllAddr + OS_GET_SNS_TIMELINE_MGR);
get_sns_next_page_scene_t GetSNSNextPageScene
= (get_sns_next_page_scene_t)(g_WeChatWinDllAddr + OS_GET_SNS_NEXT_PAGE);
QWORD mgr = GetSnsTimeLineMgr();
status = (int)GetSNSNextPageScene(mgr, id);
@ -170,7 +129,7 @@ static int GetNextPage(QWORD id)
return status;
}
int RefreshPyq(QWORD id)
int refresh_pyq(uint64_t id)
{
auto &msgHandler = message::Handler::getInstance();
if (!msgHandler.isPyqListening()) {
@ -179,10 +138,10 @@ int RefreshPyq(QWORD id)
}
if (id == 0) {
return GetFirstPage();
return get_first_page();
}
return GetNextPage(id);
return get_next_page(id);
}
/*******************************************************************************
@ -193,7 +152,7 @@ int RefreshPyq(QWORD id)
* thumb mp4
* extra
*******************************************************************************/
int DownloadAttach(QWORD id, string thumb, string extra)
int download_attachment(uint64_t id, const fs::path &thumb, const fs::path &extra)
{
int status = -1;
QWORD localId;
@ -208,13 +167,13 @@ int DownloadAttach(QWORD id, string thumb, string extra)
return status;
}
NewChatMsg_t NewChatMsg = (NewChatMsg_t)(g_WeChatWinDllAddr + OS_NEW_CHAT_MSG);
FreeChatMsg_t FreeChatMsg = (FreeChatMsg_t)(g_WeChatWinDllAddr + OS_FREE_CHAT_MSG);
GetChatMgr_t GetChatMgr = (GetChatMgr_t)(g_WeChatWinDllAddr + OS_GET_CHAT_MGR);
GetPreDownLoadMgr_t GetPreDownLoadMgr = (GetPreDownLoadMgr_t)(g_WeChatWinDllAddr + OS_GET_PRE_DOWNLOAD_MGR);
PushAttachTask_t PushAttachTask = (PushAttachTask_t)(g_WeChatWinDllAddr + OS_PUSH_ATTACH_TASK);
GetMgrByPrefixLocalId_t GetMgrByPrefixLocalId
= (GetMgrByPrefixLocalId_t)(g_WeChatWinDllAddr + OS_GET_MGR_BY_PREFIX_LOCAL_ID);
new_chat_msg_t NewChatMsg = (new_chat_msg_t)(g_WeChatWinDllAddr + OS_NEW_CHAT_MSG);
free_chat_msg_t FreeChatMsg = (free_chat_msg_t)(g_WeChatWinDllAddr + OS_FREE_CHAT_MSG);
get_chat_mgr_t GetChatMgr = (get_chat_mgr_t)(g_WeChatWinDllAddr + OS_GET_CHAT_MGR);
get_pre_download_mgr_t GetPreDownLoadMgr = (get_pre_download_mgr_t)(g_WeChatWinDllAddr + OS_GET_PRE_DOWNLOAD_MGR);
push_attach_task_t PushAttachTask = (push_attach_task_t)(g_WeChatWinDllAddr + OS_PUSH_ATTACH_TASK);
get_mgr_by_prefix_localid_t GetMgrByPrefixLocalId
= (get_mgr_by_prefix_localid_t)(g_WeChatWinDllAddr + OS_GET_MGR_BY_PREFIX_LOCAL_ID);
LARGE_INTEGER l;
l.HighPart = dbIdx;
@ -260,7 +219,7 @@ int DownloadAttach(QWORD id, string thumb, string extra)
LOG_DEBUG("path: {}", save_path);
// 创建父目录,由于路径来源于微信,不做检查
fs::create_directory(fs::path(save_path).parent_path().string());
fs::create_directory(fs::path(save_path).parent_path());
int temp = 1;
auto wx_save_path = util::new_wx_string(save_path);
@ -277,57 +236,50 @@ int DownloadAttach(QWORD id, string thumb, string extra)
return status;
}
string GetAudio(QWORD id, string dir)
std::string get_audio(uint64_t id, const fs::path &dir)
{
string mp3path = (dir.back() == '\\' || dir.back() == '/') ? dir : (dir + "/");
mp3path += to_string(id) + ".mp3";
replace(mp3path.begin(), mp3path.end(), '\\', '/');
if (fs::exists(mp3path)) { // 不重复下载
return mp3path;
}
if (!fs::exists(dir)) fs::create_directories(dir);
vector<uint8_t> silk = db::get_audio_data(id);
if (silk.size() == 0) {
fs::path mp3path = dir / (std::to_string(id) + ".mp3");
if (fs::exists(mp3path)) return mp3path.string();
auto silk = db::get_audio_data(id);
if (silk.empty()) {
LOG_ERROR("Empty audio data.");
return "";
}
Silk2Mp3(silk, mp3path, 24000);
return mp3path;
Silk2Mp3(silk, mp3path.string(), 24000);
return mp3path.string();
}
string GetPCMAudio(uint64_t id, string dir, int32_t sr)
std::string get_pcm_audio(uint64_t id, const fs::path &dir, int32_t sr)
{
string pcmpath = (dir.back() == '\\' || dir.back() == '/') ? dir : (dir + "/");
pcmpath += to_string(id) + ".pcm";
replace(pcmpath.begin(), pcmpath.end(), '\\', '/');
if (fs::exists(pcmpath)) { // 不重复下载
return pcmpath;
}
vector<uint8_t> pcm;
vector<uint8_t> silk = db::get_audio_data(id);
if (silk.size() == 0) {
if (!fs::exists(dir)) fs::create_directories(dir);
fs::path pcmpath = dir / (std::to_string(id) + ".pcm");
if (fs::exists(pcmpath)) return pcmpath.string();
auto silk = db::get_audio_data(id);
if (silk.empty()) {
LOG_ERROR("Empty audio data.");
return "";
return std::nullopt;
}
std::vector<uint8_t> pcm;
SilkDecode(silk, pcm, sr);
errno_t err;
FILE *fPCM;
err = fopen_s(&fPCM, pcmpath.c_str(), "wb");
if (err != 0) {
printf("Error: could not open input file %s\n", pcmpath.c_str());
exit(0);
std::ofstream out(pcmpath, std::ios::binary);
if (!out) {
LOG_ERROR("Failed to write file: {}", pcmpath.string());
return std::nullopt;
}
fwrite(pcm.data(), sizeof(uint8_t), pcm.size(), fPCM);
fclose(fPCM);
return pcmpath;
out.write(reinterpret_cast<char *>(pcm.data()), pcm.size());
return pcmpath.string();
}
OcrResult_t GetOcrResult(string path)
OcrResult_t get_ocr_result(const std::filesystem::path &path)
{
OcrResult_t ret = { -1, "" };
#if 0 // 参数没调好,会抛异常,看看有没有好心人来修复
@ -336,8 +288,8 @@ OcrResult_t GetOcrResult(string path)
return ret;
}
GetOCRManager_t GetOCRManager = (GetOCRManager_t)(g_WeChatWinDllAddr + 0x1D6C3C0);
DoOCRTask_t DoOCRTask = (DoOCRTask_t)(g_WeChatWinDllAddr + 0x2D10BC0);
get_ocr_manager_t GetOCRManager = (get_ocr_manager_t)(g_WeChatWinDllAddr + 0x1D6C3C0);
do_ocr_task_t DoOCRTask = (do_ocr_task_t)(g_WeChatWinDllAddr + 0x2D10BC0);
QWORD unk1 = 0, unk2 = 0, unused = 0;
QWORD *pUnk1 = &unk1;
@ -368,7 +320,7 @@ OcrResult_t GetOcrResult(string path)
return ret;
}
int RevokeMsg(QWORD id)
int revoke_message(uint64_t id)
{
int status = -1;
#if 0 // 这个挺鸡肋的,因为自己发的消息没法直接获得 msgid就这样吧
@ -382,23 +334,20 @@ int RevokeMsg(QWORD id)
return status;
}
string GetLoginUrl()
std::string get_login_url()
{
LPVOID targetAddress = reinterpret_cast<LPBYTE>(g_WeChatWinDllAddr) + OS_LOGIN_QR_CODE;
char *dataPtr = *reinterpret_cast<char **>(targetAddress); // 读取指针内容
char *dataPtr = *reinterpret_cast<char **>(targetAddress);
if (!dataPtr) {
LOG_ERROR("Failed to get login url");
return "error";
LOG_ERROR("Failed to get login URL.");
return "";
}
// 读取字符串内容
std::string data(dataPtr, 22);
return "http://weixin.qq.com/x/" + data;
return "http://weixin.qq.com/x/" + std::string(dataPtr, 22);
}
int ReceiveTransfer(string wxid, string transferid, string transactionid)
int receive_transfer(const std::string &wxid, const std::string &transferid, const std::string &transactionid)
{
// 别想了,这个不实现了
return -1;
}
} // namespace misc

View File

@ -1,17 +1,39 @@
#pragma once
#include "stdint.h"
#include <cstdint>
#include <filesystem>
#include <optional>
#include <string>
#include <vector>
#include "pb_types.h"
int IsLogin(void);
std::string GetAudio(uint64_t id, std::string dir);
std::string GetPCMAudio(uint64_t id, std::string dir, int32_t sr);
std::string DecryptImage(std::string src, std::string dst);
int RefreshPyq(uint64_t id);
int DownloadAttach(uint64_t id, std::string thumb, std::string extra);
int RevokeMsg(uint64_t id);
OcrResult_t GetOcrResult(std::string path);
std::string GetLoginUrl();
int ReceiveTransfer(std::string wxid, std::string transferid, std::string transactionid);
namespace misc
{
bool is_logged_in();
std::string get_audio(uint64_t id, const std::filesystem::path &dir);
std::string get_pcm_audio(uint64_t id, const std::filesystem::path &dir, int32_t sr);
std::string decrypt_image(const std::filesystem::path &src, const std::filesystem::path &dst);
std::string get_login_url();
int refresh_pyq(uint64_t id);
int download_attachment(uint64_t id, const std::filesystem::path &thumb, const std::filesystem::path &extra);
int revoke_message(uint64_t id);
OcrResult_t get_ocr_result(const std::filesystem::path &path);
int receive_transfer(const std::string &wxid, const std::string &transferid, const std::string &transactionid);
// RPC
bool rpc_is_logged_in(uint8_t *out, size_t *len);
bool rpc_get_audio(uint64_t id, const std::filesystem::path &dir, uint8_t *out, size_t *len);
bool rpc_get_pcm_audio(uint64_t id, const std::filesystem::path &dir, int32_t sr, uint8_t *out, size_t *len);
bool rpc_decrypt_image(const DecPath &dec, uint8_t *out, size_t *len);
bool rpc_get_login_url(uint8_t *out, size_t *len);
bool rpc_refresh_pyq(uint64_t id, uint8_t *out, size_t *len);
bool rpc_download_attachment(uint64_t id, const std::filesystem::path &thumb, const std::filesystem::path &extra, uint8_t *out, size_t *len);
bool rpc_revoke_message(uint64_t id, uint8_t *out, size_t *len);
bool rpc_get_ocr_result(const std::filesystem::path &path, uint8_t *out, size_t *len);
bool rpc_receive_transfer(const std::string &wxid, const std::string &transferid, const std::string &transactionid, uint8_t *out, size_t *len);
} // namespace misc

View File

@ -23,12 +23,12 @@
#include "chatroom_manager.h"
#include "contact_manager.h"
#include "database_executor.h"
#include "misc_manager.h"
#include "log.hpp"
#include "pb_types.h"
#include "pb_util.h"
#include "message_handler.h"
#include "message_sender.h"
#include "misc_manager.h"
#include "pb_types.h"
#include "pb_util.h"
#include "spy.h"
#include "spy_types.h"
#include "userinfo_manager.h"
@ -71,7 +71,7 @@ static bool FillResponse(int which_msg, uint8_t *out, size_t *len, AssignFunc as
static bool func_is_login(uint8_t *out, size_t *len)
{
return FillResponse<Functions_FUNC_IS_LOGIN>(Response_status_tag, out, len,
[](Response &rsp) { rsp.msg.status = IsLogin(); });
[](Response &rsp) { rsp.msg.status = misc::is_logged_in(); });
}
static bool func_get_self_wxid(uint8_t *out, size_t *len)
@ -132,7 +132,7 @@ static bool func_get_db_tables(char *db, uint8_t *out, size_t *len)
static bool func_get_audio_msg(uint64_t id, char *dir, uint8_t *out, size_t *len)
{
return FillResponse<Functions_FUNC_GET_AUDIO_MSG>(Response_str_tag, out, len, [id, dir](Response &rsp) {
std::string path = (dir == nullptr) ? "" : GetAudio(id, dir);
std::string path = (dir == nullptr) ? "" : misc::get_audio(id, dir);
rsp.msg.str = path.empty() ? nullptr : (char *)path.c_str();
});
}
@ -365,7 +365,7 @@ static bool func_exec_db_query(char *db, char *sql, uint8_t *out, size_t *len)
static bool func_refresh_pyq(uint64_t id, uint8_t *out, size_t *len)
{
return FillResponse<Functions_FUNC_REFRESH_PYQ>(Response_status_tag, out, len,
[id](Response &rsp) { rsp.msg.status = RefreshPyq(id); });
[id](Response &rsp) { rsp.msg.status = misc::refresh_pyq(id); });
}
static bool func_download_attach(AttachMsg att, uint8_t *out, size_t *len)
@ -373,20 +373,20 @@ static bool func_download_attach(AttachMsg att, uint8_t *out, size_t *len)
return FillResponse<Functions_FUNC_DOWNLOAD_ATTACH>(Response_status_tag, out, len, [att](Response &rsp) {
std::string thumb = att.thumb ? att.thumb : "";
std::string extra = att.extra ? att.extra : "";
rsp.msg.status = DownloadAttach(att.id, thumb, extra);
rsp.msg.status = misc::download_attachment(att.id, thumb, extra);
});
}
static bool func_revoke_msg(uint64_t id, uint8_t *out, size_t *len)
{
return FillResponse<Functions_FUNC_REVOKE_MSG>(Response_status_tag, out, len,
[id](Response &rsp) { rsp.msg.status = RevokeMsg(id); });
[id](Response &rsp) { rsp.msg.status = misc::revoke_message(id); });
}
static bool func_refresh_qrcode(uint8_t *out, size_t *len)
{
return FillResponse<Functions_FUNC_REFRESH_QRCODE>(Response_str_tag, out, len, [](Response &rsp) {
std::string url = GetLoginUrl();
std::string url = misc::get_login_url();
rsp.msg.str = url.empty() ? nullptr : (char *)url.c_str();
});
}
@ -398,7 +398,7 @@ static bool func_receive_transfer(char *wxid, char *tfid, char *taid, uint8_t *o
LOG_ERROR("Empty wxid, tfid, or taid.");
rsp.msg.status = -1;
} else {
rsp.msg.status = ReceiveTransfer(wxid, tfid, taid);
rsp.msg.status = misc::receive_transfer(wxid, tfid, taid);
}
});
}
@ -431,7 +431,7 @@ static bool func_decrypt_image(DecPath dec, uint8_t *out, size_t *len)
if ((dec.src == nullptr) || (dec.dst == nullptr)) {
LOG_ERROR("Empty src or dst.");
} else {
path = DecryptImage(dec.src, dec.dst);
path = misc::decrypt_image(dec.src, dec.dst);
}
rsp.msg.str = path.empty() ? nullptr : (char *)path.c_str();
});
@ -444,7 +444,7 @@ static bool func_exec_ocr(char *path, uint8_t *out, size_t *len)
if (path == nullptr) {
LOG_ERROR("Empty path.");
} else {
ret = GetOcrResult(path);
ret = misc::get_ocr_result(path);
}
rsp.msg.ocr.status = ret.status;
rsp.msg.ocr.result = ret.result.empty() ? nullptr : (char *)ret.result.c_str();