chore(spy): remove unsed files
This commit is contained in:
parent
e2620e5ea0
commit
ce0fb49956
@ -1,193 +0,0 @@
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
#include "contact_mgmt.h"
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
|
||||
using namespace std;
|
||||
extern QWORD g_WeChatWinDllAddr;
|
||||
|
||||
#define OS_GET_CONTACT_MGR 0x1B470B0
|
||||
#define OS_GET_CONTACT_LIST 0x21A49D0
|
||||
#define OS_CONTACT_BIN 0x200
|
||||
#define OS_CONTACT_BIN_LEN 0x208
|
||||
#define OS_CONTACT_WXID 0x10
|
||||
#define OS_CONTACT_CODE 0x30
|
||||
#define OS_CONTACT_REMARK 0x80
|
||||
#define OS_CONTACT_NAME 0xA0
|
||||
#define OS_CONTACT_GENDER 0x0E
|
||||
#define OS_CONTACT_STEP 0x6A8
|
||||
|
||||
typedef QWORD (*GetContactMgr_t)();
|
||||
typedef QWORD (*GetContactList_t)(QWORD, QWORD);
|
||||
|
||||
#define FEAT_LEN 5
|
||||
static const uint8_t FEAT_COUNTRY[FEAT_LEN] = { 0xA4, 0xD9, 0x02, 0x4A, 0x18 };
|
||||
static const uint8_t FEAT_PROVINCE[FEAT_LEN] = { 0xE2, 0xEA, 0xA8, 0xD1, 0x18 };
|
||||
static const uint8_t FEAT_CITY[FEAT_LEN] = { 0x1D, 0x02, 0x5B, 0xBF, 0x18 };
|
||||
|
||||
static QWORD FindMem(QWORD start, QWORD end, const void *target, size_t len)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)start;
|
||||
while ((QWORD)p < end) {
|
||||
if (memcmp((void *)p, target, len) == 0) {
|
||||
return (QWORD)p;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static string GetCntString(QWORD start, QWORD end, const uint8_t *feat, size_t len)
|
||||
{
|
||||
QWORD pfeat = FindMem(start, end, feat, len);
|
||||
if (pfeat == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
DWORD lfeat = GET_DWORD(pfeat + len);
|
||||
if (lfeat <= 2) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return Wstring2String(wstring(GET_WSTRING_FROM_P(pfeat + FEAT_LEN + 4), lfeat));
|
||||
}
|
||||
|
||||
vector<RpcContact_t> GetContacts()
|
||||
{
|
||||
vector<RpcContact_t> contacts;
|
||||
GetContactMgr_t funcGetContactMgr = (GetContactMgr_t)(g_WeChatWinDllAddr + OS_GET_CONTACT_MGR);
|
||||
GetContactList_t funcGetContactList = (GetContactList_t)(g_WeChatWinDllAddr + OS_GET_CONTACT_LIST);
|
||||
|
||||
QWORD mgr = funcGetContactMgr();
|
||||
QWORD addr[3] = { 0 };
|
||||
if (funcGetContactList(mgr, (QWORD)addr) != 1) {
|
||||
LOG_ERROR("GetContacts failed");
|
||||
return contacts;
|
||||
}
|
||||
|
||||
QWORD pstart = (QWORD)addr[0];
|
||||
QWORD pend = (QWORD)addr[2];
|
||||
while (pstart < pend) {
|
||||
RpcContact_t cnt;
|
||||
QWORD pbin = GET_QWORD(pstart + OS_CONTACT_BIN);
|
||||
QWORD lenbin = GET_DWORD(pstart + OS_CONTACT_BIN_LEN);
|
||||
|
||||
cnt.wxid = GetStringByWstrAddr(pstart + OS_CONTACT_WXID);
|
||||
cnt.code = GetStringByWstrAddr(pstart + OS_CONTACT_CODE);
|
||||
cnt.remark = GetStringByWstrAddr(pstart + OS_CONTACT_REMARK);
|
||||
cnt.name = GetStringByWstrAddr(pstart + OS_CONTACT_NAME);
|
||||
|
||||
cnt.country = GetCntString(pbin, pbin + lenbin, FEAT_COUNTRY, FEAT_LEN);
|
||||
cnt.province = GetCntString(pbin, pbin + lenbin, FEAT_PROVINCE, FEAT_LEN);
|
||||
cnt.city = GetCntString(pbin, pbin + lenbin, FEAT_CITY, FEAT_LEN);
|
||||
|
||||
if (pbin == 0) {
|
||||
cnt.gender = 0;
|
||||
} else {
|
||||
cnt.gender = (DWORD) * (uint8_t *)(pbin + OS_CONTACT_GENDER);
|
||||
}
|
||||
|
||||
contacts.push_back(cnt);
|
||||
pstart += OS_CONTACT_STEP;
|
||||
}
|
||||
|
||||
return contacts;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int AcceptNewFriend(string v3, string v4, int scene)
|
||||
{
|
||||
int success = 0;
|
||||
|
||||
DWORD acceptNewFriendCall1 = g_WeChatWinDllAddr + g_WxCalls.anf.call1;
|
||||
DWORD acceptNewFriendCall2 = g_WeChatWinDllAddr + g_WxCalls.anf.call2;
|
||||
DWORD acceptNewFriendCall3 = g_WeChatWinDllAddr + g_WxCalls.anf.call3;
|
||||
DWORD acceptNewFriendCall4 = g_WeChatWinDllAddr + g_WxCalls.anf.call4;
|
||||
|
||||
char buffer[0x40] = { 0 };
|
||||
char nullbuffer[0x3CC] = { 0 };
|
||||
|
||||
LOG_DEBUG("\nv3: {}\nv4: {}\nscene: {}", v3, v4, scene);
|
||||
|
||||
wstring wsV3 = String2Wstring(v3);
|
||||
wstring wsV4 = String2Wstring(v4);
|
||||
WxString wxV3(wsV3);
|
||||
WxString wxV4(wsV4);
|
||||
|
||||
__asm {
|
||||
pushad;
|
||||
pushfd;
|
||||
lea ecx, buffer;
|
||||
call acceptNewFriendCall1;
|
||||
mov esi, 0x0;
|
||||
mov edi, scene;
|
||||
push esi;
|
||||
push edi;
|
||||
sub esp, 0x14;
|
||||
mov ecx, esp;
|
||||
lea eax, wxV4;
|
||||
push eax;
|
||||
call acceptNewFriendCall2;
|
||||
sub esp, 0x8;
|
||||
push 0x0;
|
||||
lea eax, nullbuffer;
|
||||
push eax;
|
||||
lea eax, wxV3;
|
||||
push eax;
|
||||
lea ecx, buffer;
|
||||
call acceptNewFriendCall3;
|
||||
mov success, eax;
|
||||
lea ecx, buffer;
|
||||
call acceptNewFriendCall4;
|
||||
popfd;
|
||||
popad;
|
||||
}
|
||||
|
||||
return success; // 成功返回 1
|
||||
}
|
||||
|
||||
/*没啥用,非好友获取不到*/
|
||||
RpcContact_t GetContactByWxid(string wxid)
|
||||
{
|
||||
RpcContact_t contact;
|
||||
char buff[0x440] = { 0 };
|
||||
wstring wsWxid = String2Wstring(wxid);
|
||||
WxString pri(wsWxid);
|
||||
DWORD contact_mgr_addr = g_WeChatWinDllAddr + 0x75A4A0;
|
||||
DWORD get_contact_addr = g_WeChatWinDllAddr + 0xC04E00;
|
||||
DWORD free_contact_addr = g_WeChatWinDllAddr + 0xEA7880;
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
CALL contact_mgr_addr
|
||||
LEA ECX,buff
|
||||
PUSH ECX
|
||||
LEA ECX,pri
|
||||
PUSH ECX
|
||||
MOV ECX,EAX
|
||||
CALL get_contact_addr
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
|
||||
contact.wxid = wxid;
|
||||
contact.code = GetStringByWstrAddr((DWORD)buff + g_WxCalls.contact.wxCode);
|
||||
contact.remark = GetStringByWstrAddr((DWORD)buff + g_WxCalls.contact.wxRemark);
|
||||
contact.name = GetStringByWstrAddr((DWORD)buff + g_WxCalls.contact.wxName);
|
||||
contact.gender = GET_DWORD((DWORD)buff + 0x148);
|
||||
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
LEA ECX,buff
|
||||
CALL free_contact_addr
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
|
||||
return contact;
|
||||
}
|
||||
#endif
|
||||
|
@ -1,233 +0,0 @@
|
||||
#include <iterator>
|
||||
|
||||
#include "exec_sql.h"
|
||||
#include "log.h"
|
||||
#include "sqlite3.h"
|
||||
#include "util.h"
|
||||
|
||||
#define OFFSET_DB_INSTANCE 0x59C5B48
|
||||
#define OFFSET_DB_MICROMSG 0xB8
|
||||
#define OFFSET_DB_CHAT_MSG 0x2C8
|
||||
#define OFFSET_DB_MISC 0x5F0
|
||||
#define OFFSET_DB_EMOTION 0x15F0
|
||||
#define OFFSET_DB_MEDIA 0xF48
|
||||
#define OFFSET_DB_BIZCHAT_MSG 0x1A70
|
||||
#define OFFSET_DB_FUNCTION_MSG 0x1B98
|
||||
#define OFFSET_DB_NAME 0x28
|
||||
#define OFFSET_DB_MSG_MGR 0x5A23888
|
||||
|
||||
extern UINT64 g_WeChatWinDllAddr;
|
||||
|
||||
typedef map<string, QWORD> dbMap_t;
|
||||
static dbMap_t dbMap;
|
||||
|
||||
static void GetDbHandle(QWORD base, QWORD offset)
|
||||
{
|
||||
wchar_t *wsp = (wchar_t *)(*(QWORD *)(base + offset + OFFSET_DB_NAME));
|
||||
string dbname = Wstring2String(wstring(wsp));
|
||||
dbMap[dbname] = GET_QWORD(base + offset);
|
||||
}
|
||||
|
||||
static void GetMsgDbHandle(QWORD msgMgrAddr)
|
||||
{
|
||||
QWORD dbIndex = GET_QWORD(msgMgrAddr + 0x68);
|
||||
QWORD pStart = GET_QWORD(msgMgrAddr + 0x50);
|
||||
for (uint32_t i = 0; i < dbIndex; i++) {
|
||||
QWORD dbAddr = GET_QWORD(pStart + i * 0x08);
|
||||
if (dbAddr) {
|
||||
// MSGi.db
|
||||
string dbname = Wstring2String(GET_WSTRING(dbAddr));
|
||||
dbMap[dbname] = GET_QWORD(dbAddr + 0x78);
|
||||
|
||||
// MediaMsgi.db
|
||||
QWORD mmdbAddr = GET_QWORD(dbAddr + 0x20);
|
||||
string mmdbname = Wstring2String(GET_WSTRING(mmdbAddr + 0x78));
|
||||
dbMap[mmdbname] = GET_QWORD(mmdbAddr + 0x50);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dbMap_t GetDbHandles()
|
||||
{
|
||||
dbMap.clear();
|
||||
|
||||
QWORD dbInstanceAddr = GET_QWORD(g_WeChatWinDllAddr + OFFSET_DB_INSTANCE);
|
||||
|
||||
GetDbHandle(dbInstanceAddr, OFFSET_DB_MICROMSG); // MicroMsg.db
|
||||
GetDbHandle(dbInstanceAddr, OFFSET_DB_CHAT_MSG); // ChatMsg.db
|
||||
GetDbHandle(dbInstanceAddr, OFFSET_DB_MISC); // Misc.db
|
||||
GetDbHandle(dbInstanceAddr, OFFSET_DB_EMOTION); // Emotion.db
|
||||
GetDbHandle(dbInstanceAddr, OFFSET_DB_MEDIA); // Media.db
|
||||
GetDbHandle(dbInstanceAddr, OFFSET_DB_FUNCTION_MSG); // Function.db
|
||||
|
||||
GetMsgDbHandle(GET_QWORD(g_WeChatWinDllAddr + OFFSET_DB_MSG_MGR)); // MSGi.db & MediaMsgi.db
|
||||
|
||||
return dbMap;
|
||||
}
|
||||
|
||||
DbNames_t GetDbNames()
|
||||
{
|
||||
DbNames_t names;
|
||||
if (dbMap.empty()) {
|
||||
dbMap = GetDbHandles();
|
||||
}
|
||||
|
||||
for (auto &[k, v] : dbMap) {
|
||||
names.push_back(k);
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
static int cbGetTables(void *ret, int argc, char **argv, char **azColName)
|
||||
{
|
||||
DbTables_t *tbls = (DbTables_t *)ret;
|
||||
DbTable_t tbl;
|
||||
for (int i = 0; i < argc; i++) {
|
||||
if (strcmp(azColName[i], "name") == 0) {
|
||||
tbl.name = argv[i] ? argv[i] : "";
|
||||
} else if (strcmp(azColName[i], "sql") == 0) {
|
||||
string sql(argv[i]);
|
||||
sql.erase(std::remove(sql.begin(), sql.end(), '\t'), sql.end());
|
||||
tbl.sql = sql.c_str();
|
||||
}
|
||||
}
|
||||
tbls->push_back(tbl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DbTables_t GetDbTables(const string db)
|
||||
{
|
||||
DbTables_t tables;
|
||||
if (dbMap.empty()) {
|
||||
dbMap = GetDbHandles();
|
||||
}
|
||||
|
||||
auto it = dbMap.find(db);
|
||||
if (it == dbMap.end()) {
|
||||
return tables; // DB not found
|
||||
}
|
||||
|
||||
const char *sql = "select name, sql from sqlite_master where type=\"table\";";
|
||||
Sqlite3_exec p_Sqlite3_exec = (Sqlite3_exec)(g_WeChatWinDllAddr + SQLITE3_EXEC_OFFSET);
|
||||
|
||||
p_Sqlite3_exec(it->second, sql, (Sqlite3_callback)cbGetTables, (void *)&tables, 0);
|
||||
|
||||
return tables;
|
||||
}
|
||||
|
||||
DbRows_t ExecDbQuery(const string db, const string sql)
|
||||
{
|
||||
DbRows_t rows;
|
||||
Sqlite3_prepare func_prepare = (Sqlite3_prepare)(g_WeChatWinDllAddr + SQLITE3_PREPARE_OFFSET);
|
||||
Sqlite3_step func_step = (Sqlite3_step)(g_WeChatWinDllAddr + SQLITE3_STEP_OFFSET);
|
||||
Sqlite3_column_count func_column_count = (Sqlite3_column_count)(g_WeChatWinDllAddr + SQLITE3_COLUMN_COUNT_OFFSET);
|
||||
Sqlite3_column_name func_column_name = (Sqlite3_column_name)(g_WeChatWinDllAddr + SQLITE3_COLUMN_NAME_OFFSET);
|
||||
Sqlite3_column_type func_column_type = (Sqlite3_column_type)(g_WeChatWinDllAddr + SQLITE3_COLUMN_TYPE_OFFSET);
|
||||
Sqlite3_column_blob func_column_blob = (Sqlite3_column_blob)(g_WeChatWinDllAddr + SQLITE3_COLUMN_BLOB_OFFSET);
|
||||
Sqlite3_column_bytes func_column_bytes = (Sqlite3_column_bytes)(g_WeChatWinDllAddr + SQLITE3_COLUMN_BYTES_OFFSET);
|
||||
Sqlite3_finalize func_finalize = (Sqlite3_finalize)(g_WeChatWinDllAddr + SQLITE3_FINALIZE_OFFSET);
|
||||
|
||||
if (dbMap.empty()) {
|
||||
dbMap = GetDbHandles();
|
||||
}
|
||||
|
||||
QWORD *stmt;
|
||||
QWORD handle = dbMap[db];
|
||||
if (handle == 0) {
|
||||
LOG_WARN("Empty handle, retrying...");
|
||||
dbMap = GetDbHandles();
|
||||
}
|
||||
|
||||
int rc = func_prepare(dbMap[db], sql.c_str(), -1, &stmt, 0);
|
||||
if (rc != SQLITE_OK) {
|
||||
return rows;
|
||||
}
|
||||
|
||||
while (func_step(stmt) == SQLITE_ROW) {
|
||||
DbRow_t row;
|
||||
int col_count = func_column_count(stmt);
|
||||
for (int i = 0; i < col_count; i++) {
|
||||
DbField_t field;
|
||||
field.type = func_column_type(stmt, i);
|
||||
field.column = func_column_name(stmt, i);
|
||||
|
||||
int length = func_column_bytes(stmt, i);
|
||||
const void *blob = func_column_blob(stmt, i);
|
||||
if (length && (field.type != 5)) {
|
||||
field.content.reserve(length);
|
||||
copy((uint8_t *)blob, (uint8_t *)blob + length, back_inserter(field.content));
|
||||
}
|
||||
row.push_back(field);
|
||||
}
|
||||
rows.push_back(row);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
int GetLocalIdandDbidx(uint64_t id, uint64_t *localId, uint32_t *dbIdx)
|
||||
{
|
||||
QWORD msgMgrAddr = GET_QWORD(g_WeChatWinDllAddr + OFFSET_DB_MSG_MGR);
|
||||
int dbIndex = (int)GET_QWORD(msgMgrAddr + 0x68); // 总不能 int 还不够吧?
|
||||
QWORD pStart = GET_QWORD(msgMgrAddr + 0x50);
|
||||
|
||||
*dbIdx = 0;
|
||||
for (int i = dbIndex - 1; i >= 0; i--) { // 从后往前遍历
|
||||
QWORD dbAddr = GET_QWORD(pStart + i * 0x08);
|
||||
if (dbAddr) {
|
||||
string dbname = Wstring2String(GET_WSTRING(dbAddr));
|
||||
dbMap[dbname] = GET_QWORD(dbAddr + 0x78);
|
||||
string sql = "SELECT localId FROM MSG WHERE MsgSvrID=" + to_string(id) + ";";
|
||||
DbRows_t rows = ExecDbQuery(dbname, sql);
|
||||
if (rows.empty()) {
|
||||
continue;
|
||||
}
|
||||
DbRow_t row = rows.front();
|
||||
if (row.empty()) {
|
||||
continue;
|
||||
}
|
||||
DbField_t field = row.front();
|
||||
if ((field.column.compare("localId") != 0) && (field.type != 1)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
*localId = strtoull((const char *)(field.content.data()), NULL, 10);
|
||||
*dbIdx = (uint32_t)(GET_QWORD(GET_QWORD(dbAddr + 0x28) + 0x1E8) >> 32);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
vector<uint8_t> GetAudioData(uint64_t id)
|
||||
{
|
||||
QWORD msgMgrAddr = GET_QWORD(g_WeChatWinDllAddr + OFFSET_DB_MSG_MGR);
|
||||
int dbIndex = (int)GET_QWORD(msgMgrAddr + 0x68);
|
||||
|
||||
string sql = "SELECT Buf FROM Media WHERE Reserved0=" + to_string(id) + ";";
|
||||
for (int i = dbIndex - 1; i >= 0; i--) {
|
||||
string dbname = "MediaMSG" + to_string(i) + ".db";
|
||||
DbRows_t rows = ExecDbQuery(dbname, sql);
|
||||
if (rows.empty()) {
|
||||
continue;
|
||||
}
|
||||
DbRow_t row = rows.front();
|
||||
if (row.empty()) {
|
||||
continue;
|
||||
}
|
||||
DbField_t field = row.front();
|
||||
if (field.column.compare("Buf") != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 首字节为 0x02,估计是混淆用的?去掉。
|
||||
vector<uint8_t> rv(field.content.begin() + 1, field.content.end());
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
return vector<uint8_t>();
|
||||
}
|
||||
|
@ -1,445 +0,0 @@
|
||||
#pragma warning(disable : 4244)
|
||||
|
||||
#include "framework.h"
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <io.h>
|
||||
#include <direct.h>
|
||||
|
||||
#include "codec.h"
|
||||
#include "exec_sql.h"
|
||||
#include "funcs.h"
|
||||
#include "log.h"
|
||||
#include "spy_types.h"
|
||||
#include "util.h"
|
||||
|
||||
using namespace std;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
extern bool gIsListeningPyq;
|
||||
extern QWORD g_WeChatWinDllAddr;
|
||||
|
||||
#define HEADER_PNG1 0x89
|
||||
#define HEADER_PNG2 0x50
|
||||
#define HEADER_JPG1 0xFF
|
||||
#define HEADER_JPG2 0xD8
|
||||
#define HEADER_GIF1 0x47
|
||||
#define HEADER_GIF2 0x49
|
||||
|
||||
#define OS_LOGIN_STATUS 0x5A20978
|
||||
#define OS_GET_SNS_DATA_MGR 0x21E7EC0
|
||||
#define OS_GET_SNS_FIRST_PAGE 0x2E37960
|
||||
#define OS_GET_SNS_TIMELINE_MGR 0x2DC9470
|
||||
#define OS_GET_SNS_NEXT_PAGE 0x2EDF4D0
|
||||
#define OS_NEW_CHAT_MSG 0x1B63A50
|
||||
#define OS_FREE_CHAT_MSG 0x1B5B160
|
||||
#define OS_GET_CHAT_MGR 0x1B8CFD0
|
||||
#define OS_GET_MGR_BY_PREFIX_LOCAL_ID 0x2145220
|
||||
#define OS_GET_PRE_DOWNLOAD_MGR 0x1C14930
|
||||
#define OS_PUSH_ATTACH_TASK 0x1CE57B0
|
||||
#define OS_LOGIN_QR_CODE 0x5A26440
|
||||
|
||||
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);
|
||||
|
||||
int IsLogin(void) { return (int)GET_QWORD(g_WeChatWinDllAddr + OS_LOGIN_STATUS); }
|
||||
|
||||
static string get_key(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 ""; // 错误
|
||||
}
|
||||
|
||||
// 创建多级目录
|
||||
bool CreateDir(const char* dir)
|
||||
{
|
||||
int m = 0, n;
|
||||
string str1, str2;
|
||||
str1 = dir;
|
||||
str2 = str1.substr(0, 2);
|
||||
str1 = str1.substr(3, str1.size());
|
||||
while (m >= 0)
|
||||
{
|
||||
m = str1.find('/');
|
||||
|
||||
str2 += '/' + str1.substr(0, m);
|
||||
//判断该目录是否存在
|
||||
n = _access(str2.c_str(), 0);
|
||||
if (n == -1)
|
||||
{
|
||||
//创建目录文件
|
||||
int flag = _mkdir(str2.c_str());
|
||||
if (flag != 0) { //创建失败
|
||||
LOG_ERROR("Failed to CreateDir:{}", dir);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
str1 = str1.substr(m + 1, str1.size());
|
||||
}
|
||||
LOG_DEBUG("CreateDir {} success.", dir);
|
||||
return true;
|
||||
}
|
||||
|
||||
string DecryptImage(string src, string dir)
|
||||
{
|
||||
if (!fs::exists(src)) {
|
||||
LOG_ERROR("File not exists: {}", src);
|
||||
return "";
|
||||
}
|
||||
|
||||
ifstream in(src.c_str(), ios::binary);
|
||||
if (!in.is_open()) {
|
||||
LOG_ERROR("Failed to read file {}", src);
|
||||
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();
|
||||
|
||||
uint8_t key = 0x00;
|
||||
string ext = get_key(pBuf[0], pBuf[1], &key);
|
||||
if (ext.empty()) {
|
||||
LOG_ERROR("Failed to get key.");
|
||||
return "";
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
pBuf[i] ^= key;
|
||||
}
|
||||
|
||||
string dst = "";
|
||||
|
||||
try {
|
||||
if (dir.empty()) {
|
||||
dst = fs::path(src).replace_extension(ext).string();
|
||||
} else {
|
||||
dst = (dir.back() == '\\' || dir.back() == '/') ? dir : (dir + "/");
|
||||
replace(dst.begin(), dst.end(), '\\', '/');
|
||||
|
||||
// 判断dir文件夹是否存在,若不存在则创建(否则将无法创建出文件)
|
||||
if (_access(dst.c_str(), 0) == -1) {//判断该文件夹是否存在
|
||||
bool success = CreateDir(dst.c_str()); //Windows创建文件夹
|
||||
if (!success) { //创建失败
|
||||
LOG_ERROR("Failed to mkdir:{}", dst);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
dst += fs::path(src).stem().string() + ext;
|
||||
}
|
||||
|
||||
replace(dst.begin(), dst.end(), '\\', '/');
|
||||
} catch (const std::exception &e) {
|
||||
LOG_ERROR(GB2312ToUtf8(e.what()));
|
||||
} catch (...) {
|
||||
LOG_ERROR("Unknow exception.");
|
||||
return "";
|
||||
}
|
||||
|
||||
ofstream out(dst.c_str(), ios::binary);
|
||||
if (!out.is_open()) {
|
||||
LOG_ERROR("Failed to write file {}", dst);
|
||||
return "";
|
||||
}
|
||||
|
||||
out.write(pBuf, size);
|
||||
out.close();
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
static int GetFirstPage()
|
||||
{
|
||||
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);
|
||||
|
||||
QWORD buff[16] = { 0 };
|
||||
QWORD mgr = GetSNSDataMgr();
|
||||
status = (int)GetSNSFirstPage(mgr, (QWORD)buff, 1);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int GetNextPage(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);
|
||||
|
||||
QWORD mgr = GetSnsTimeLineMgr();
|
||||
status = (int)GetSNSNextPageScene(mgr, id);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int RefreshPyq(QWORD id)
|
||||
{
|
||||
if (!gIsListeningPyq) {
|
||||
LOG_ERROR("没有启动朋友圈消息接收,参考:enable_receiving_msg");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (id == 0) {
|
||||
return GetFirstPage();
|
||||
}
|
||||
|
||||
return GetNextPage(id);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* 都说我不写注释,写一下吧
|
||||
* 其实也没啥好写的,就是下载资源
|
||||
* 主要介绍一下几个参数:
|
||||
* id:好理解,消息 id
|
||||
* thumb:图片或者视频的缩略图路径;如果是视频,后缀为 mp4 后就是存在路径了
|
||||
* extra:图片、文件的路径
|
||||
*******************************************************************************/
|
||||
int DownloadAttach(QWORD id, string thumb, string extra)
|
||||
{
|
||||
int status = -1;
|
||||
QWORD localId;
|
||||
uint32_t dbIdx;
|
||||
|
||||
if (fs::exists(extra)) { // 第一道,不重复下载。TODO: 通过文件大小来判断
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (GetLocalIdandDbidx(id, &localId, &dbIdx) != 0) {
|
||||
LOG_ERROR("Failed to get localId, Please check id: {}", to_string(id));
|
||||
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);
|
||||
|
||||
LARGE_INTEGER l;
|
||||
l.HighPart = dbIdx;
|
||||
l.LowPart = (DWORD)localId;
|
||||
|
||||
char *buff = (char *)HeapAlloc(GetProcessHeap(), 0, 0x460);
|
||||
if (buff == nullptr) {
|
||||
LOG_ERROR("Failed to allocate memory.");
|
||||
return status;
|
||||
}
|
||||
|
||||
QWORD pChatMsg = NewChatMsg((QWORD)buff);
|
||||
GetChatMgr();
|
||||
GetMgrByPrefixLocalId(l.QuadPart, pChatMsg);
|
||||
|
||||
QWORD type = GET_QWORD(buff + 0x38);
|
||||
|
||||
string save_path = "";
|
||||
string thumb_path = "";
|
||||
|
||||
switch (type) {
|
||||
case 0x03: { // Image: extra
|
||||
save_path = extra;
|
||||
break;
|
||||
}
|
||||
case 0x3E:
|
||||
case 0x2B: { // Video: thumb
|
||||
thumb_path = thumb;
|
||||
save_path = fs::path(thumb).replace_extension("mp4").string();
|
||||
break;
|
||||
}
|
||||
case 0x31: { // File: extra
|
||||
save_path = extra;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (fs::exists(save_path)) { // 不重复下载。TODO: 通过文件大小来判断
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOG_DEBUG("path: {}", save_path);
|
||||
// 创建父目录,由于路径来源于微信,不做检查
|
||||
fs::create_directory(fs::path(save_path).parent_path().string());
|
||||
|
||||
int temp = 1;
|
||||
WxString *pSavePath = NewWxStringFromStr(save_path);
|
||||
WxString *pThumbPath = NewWxStringFromStr(thumb_path);
|
||||
|
||||
memcpy(&buff[0x280], pThumbPath, sizeof(WxString));
|
||||
memcpy(&buff[0x2A0], pSavePath, sizeof(WxString));
|
||||
memcpy(&buff[0x40C], &temp, sizeof(temp));
|
||||
|
||||
QWORD mgr = GetPreDownLoadMgr();
|
||||
status = (int)PushAttachTask(mgr, pChatMsg, 0, 1);
|
||||
FreeChatMsg(pChatMsg);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
string GetAudio(QWORD id, string 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;
|
||||
}
|
||||
|
||||
vector<uint8_t> silk = GetAudioData(id);
|
||||
if (silk.size() == 0) {
|
||||
LOG_ERROR("Empty audio data.");
|
||||
return "";
|
||||
}
|
||||
|
||||
Silk2Mp3(silk, mp3path, 24000);
|
||||
|
||||
return mp3path;
|
||||
}
|
||||
|
||||
string GetPCMAudio(uint64_t id, string 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 = GetAudioData(id);
|
||||
if (silk.size() == 0) {
|
||||
LOG_ERROR("Empty audio data.");
|
||||
return "";
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
fwrite(pcm.data(), sizeof(uint8_t), pcm.size(), fPCM);
|
||||
fclose(fPCM);
|
||||
|
||||
return pcmpath;
|
||||
}
|
||||
|
||||
|
||||
OcrResult_t GetOcrResult(string path)
|
||||
{
|
||||
OcrResult_t ret = { -1, "" };
|
||||
#if 0 // 参数没调好,会抛异常,看看有没有好心人来修复
|
||||
if (!fs::exists(path)) {
|
||||
LOG_ERROR("Can not find: {}", path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
GetOCRManager_t GetOCRManager = (GetOCRManager_t)(g_WeChatWinDllAddr + 0x1D6C3C0);
|
||||
DoOCRTask_t DoOCRTask = (DoOCRTask_t)(g_WeChatWinDllAddr + 0x2D10BC0);
|
||||
|
||||
QWORD unk1 = 0, unk2 = 0, unused = 0;
|
||||
QWORD *pUnk1 = &unk1;
|
||||
QWORD *pUnk2 = &unk2;
|
||||
// 路径分隔符有要求,必须为 `\`
|
||||
wstring wsPath = String2Wstring(fs::path(path).make_preferred().string());
|
||||
WxString wxPath(wsPath);
|
||||
vector<QWORD> *pv = (vector<QWORD> *)HeapAlloc(GetProcessHeap(), 0, 0x20);
|
||||
RawVector_t *pRv = (RawVector_t *)pv;
|
||||
pRv->finish = pRv->start;
|
||||
char buff[0x98] = { 0 };
|
||||
memcpy(buff, &pRv->start, sizeof(QWORD));
|
||||
|
||||
QWORD mgr = GetOCRManager();
|
||||
ret.status = (int)DoOCRTask(mgr, (QWORD)&wxPath, unused, (QWORD)buff, (QWORD)&pUnk1, (QWORD)&pUnk2);
|
||||
|
||||
QWORD count = GET_QWORD(buff + 0x8);
|
||||
if (count > 0) {
|
||||
QWORD header = GET_QWORD(buff);
|
||||
for (QWORD i = 0; i < count; i++) {
|
||||
QWORD content = GET_QWORD(header);
|
||||
ret.result += Wstring2String(GET_WSTRING(content + 0x28));
|
||||
ret.result += "\n";
|
||||
header = content;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
int RevokeMsg(QWORD id)
|
||||
{
|
||||
int status = -1;
|
||||
#if 0 // 这个挺鸡肋的,因为自己发的消息没法直接获得 msgid,就这样吧
|
||||
QWORD localId;
|
||||
uint32_t dbIdx;
|
||||
if (GetLocalIdandDbidx(id, &localId, &dbIdx) != 0) {
|
||||
LOG_ERROR("Failed to get localId, Please check id: {}", to_string(id));
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
string GetLoginUrl()
|
||||
{
|
||||
LPVOID targetAddress = reinterpret_cast<LPBYTE>(g_WeChatWinDllAddr) + OS_LOGIN_QR_CODE;
|
||||
|
||||
char *dataPtr = *reinterpret_cast<char **>(targetAddress); // 读取指针内容
|
||||
if (!dataPtr) {
|
||||
LOG_ERROR("Failed to get login url");
|
||||
return "error";
|
||||
}
|
||||
|
||||
// 读取字符串内容
|
||||
std::string data(dataPtr, 22);
|
||||
return "http://weixin.qq.com/x/" + data;
|
||||
}
|
||||
|
||||
int ReceiveTransfer(string wxid, string transferid, string transactionid)
|
||||
{
|
||||
// 别想了,这个不实现了
|
||||
return -1;
|
||||
}
|
||||
|
@ -1,379 +0,0 @@
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
#include "MinHook.h"
|
||||
#include "framework.h"
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
#include "log.h"
|
||||
#include "receive_msg.h"
|
||||
#include "user_info.h"
|
||||
#include "util.h"
|
||||
|
||||
// Defined in rpc_server.cpp
|
||||
extern bool gIsLogging, gIsListening, gIsListeningPyq;
|
||||
extern mutex gMutex;
|
||||
extern condition_variable gCV;
|
||||
extern queue<WxMsg_t> gMsgQueue;
|
||||
|
||||
// Defined in spy.cpp
|
||||
extern QWORD g_WeChatWinDllAddr;
|
||||
|
||||
#define OS_RECV_MSG_ID 0x30
|
||||
#define OS_RECV_MSG_TYPE 0x38
|
||||
#define OS_RECV_MSG_SELF 0x3C
|
||||
#define OS_RECV_MSG_TS 0x44
|
||||
#define OS_RECV_MSG_ROOMID 0x48
|
||||
#define OS_RECV_MSG_CONTENT 0x88
|
||||
#define OS_RECV_MSG_WXID 0x240
|
||||
#define OS_RECV_MSG_SIGN 0x260
|
||||
#define OS_RECV_MSG_THUMB 0x280
|
||||
#define OS_RECV_MSG_EXTRA 0x2A0
|
||||
#define OS_RECV_MSG_XML 0x308
|
||||
#define OS_RECV_MSG_CALL 0x21444B0
|
||||
#define OS_PYQ_MSG_START 0x30
|
||||
#define OS_PYQ_MSG_END 0x38
|
||||
#define OS_PYQ_MSG_TS 0x38
|
||||
#define OS_PYQ_MSG_XML 0x9B8
|
||||
#define OS_PYQ_MSG_SENDER 0x18
|
||||
#define OS_PYQ_MSG_CONTENT 0x48
|
||||
#define OS_PYQ_MSG_CALL 0x2E59320
|
||||
#define OS_WXLOG 0x261E760
|
||||
|
||||
typedef QWORD (*RecvMsg_t)(QWORD, QWORD);
|
||||
typedef QWORD (*WxLog_t)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD);
|
||||
typedef QWORD (*RecvPyq_t)(QWORD, QWORD, QWORD);
|
||||
|
||||
static RecvMsg_t funcRecvMsg = nullptr;
|
||||
static RecvMsg_t realRecvMsg = nullptr;
|
||||
static WxLog_t funcWxLog = nullptr;
|
||||
static WxLog_t realWxLog = nullptr;
|
||||
static RecvPyq_t funcRecvPyq = nullptr;
|
||||
static RecvPyq_t realRecvPyq = nullptr;
|
||||
static bool isMH_Initialized = false;
|
||||
|
||||
MsgTypes_t GetMsgTypes()
|
||||
{
|
||||
const MsgTypes_t m = {
|
||||
{ 0x00, "朋友圈消息" },
|
||||
{ 0x01, "文字" },
|
||||
{ 0x03, "图片" },
|
||||
{ 0x22, "语音" },
|
||||
{ 0x25, "好友确认" },
|
||||
{ 0x28, "POSSIBLEFRIEND_MSG" },
|
||||
{ 0x2A, "名片" },
|
||||
{ 0x2B, "视频" },
|
||||
{ 0x2F, "石头剪刀布 | 表情图片" },
|
||||
{ 0x30, "位置" },
|
||||
{ 0x31, "共享实时位置、文件、转账、链接" },
|
||||
{ 0x32, "VOIPMSG" },
|
||||
{ 0x33, "微信初始化" },
|
||||
{ 0x34, "VOIPNOTIFY" },
|
||||
{ 0x35, "VOIPINVITE" },
|
||||
{ 0x3E, "小视频" },
|
||||
{ 0x42, "微信红包" },
|
||||
{ 0x270F, "SYSNOTICE" },
|
||||
{ 0x2710, "红包、系统消息" },
|
||||
{ 0x2712, "撤回消息" },
|
||||
{ 0x100031, "搜狗表情" },
|
||||
{ 0x1000031, "链接" },
|
||||
{ 0x1A000031, "微信红包" },
|
||||
{ 0x20010031, "红包封面" },
|
||||
{ 0x2D000031, "视频号视频" },
|
||||
{ 0x2E000031, "视频号名片" },
|
||||
{ 0x31000031, "引用消息" },
|
||||
{ 0x37000031, "拍一拍" },
|
||||
{ 0x3A000031, "视频号直播" },
|
||||
{ 0x3A100031, "商品链接" },
|
||||
{ 0x3A200031, "视频号直播" },
|
||||
{ 0x3E000031, "音乐链接" },
|
||||
{ 0x41000031, "文件" },
|
||||
};
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
static QWORD DispatchMsg(QWORD arg1, QWORD arg2)
|
||||
{
|
||||
WxMsg_t wxMsg = { 0 };
|
||||
try {
|
||||
wxMsg.id = GET_QWORD(arg2 + OS_RECV_MSG_ID);
|
||||
wxMsg.type = GET_DWORD(arg2 + OS_RECV_MSG_TYPE);
|
||||
wxMsg.is_self = GET_DWORD(arg2 + OS_RECV_MSG_SELF);
|
||||
wxMsg.ts = GET_DWORD(arg2 + OS_RECV_MSG_TS);
|
||||
wxMsg.content = GetStringByWstrAddr(arg2 + OS_RECV_MSG_CONTENT);
|
||||
wxMsg.sign = GetStringByWstrAddr(arg2 + OS_RECV_MSG_SIGN);
|
||||
wxMsg.xml = GetStringByWstrAddr(arg2 + OS_RECV_MSG_XML);
|
||||
|
||||
string roomid = GetStringByWstrAddr(arg2 + OS_RECV_MSG_ROOMID);
|
||||
wxMsg.roomid = roomid;
|
||||
if (roomid.find("@chatroom") != string::npos) { // 群 ID 的格式为 xxxxxxxxxxx@chatroom
|
||||
wxMsg.is_group = true;
|
||||
if (wxMsg.is_self) {
|
||||
wxMsg.sender = GetSelfWxid();
|
||||
} else {
|
||||
wxMsg.sender = GetStringByWstrAddr(arg2 + OS_RECV_MSG_WXID);
|
||||
}
|
||||
} else {
|
||||
wxMsg.is_group = false;
|
||||
if (wxMsg.is_self) {
|
||||
wxMsg.sender = GetSelfWxid();
|
||||
} else {
|
||||
wxMsg.sender = roomid;
|
||||
}
|
||||
}
|
||||
|
||||
wxMsg.thumb = GetStringByWstrAddr(arg2 + OS_RECV_MSG_THUMB);
|
||||
if (!wxMsg.thumb.empty()) {
|
||||
wxMsg.thumb = GetHomePath() + wxMsg.thumb;
|
||||
replace(wxMsg.thumb.begin(), wxMsg.thumb.end(), '\\', '/');
|
||||
}
|
||||
|
||||
wxMsg.extra = GetStringByWstrAddr(arg2 + OS_RECV_MSG_EXTRA);
|
||||
if (!wxMsg.extra.empty()) {
|
||||
wxMsg.extra = GetHomePath() + wxMsg.extra;
|
||||
replace(wxMsg.extra.begin(), wxMsg.extra.end(), '\\', '/');
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
LOG_ERROR(GB2312ToUtf8(e.what()));
|
||||
} catch (...) {
|
||||
LOG_ERROR("Unknow exception.");
|
||||
}
|
||||
|
||||
{
|
||||
unique_lock<mutex> lock(gMutex);
|
||||
gMsgQueue.push(wxMsg); // 推送到队列
|
||||
}
|
||||
|
||||
gCV.notify_all(); // 通知各方消息就绪
|
||||
return realRecvMsg(arg1, arg2);
|
||||
}
|
||||
|
||||
static QWORD PrintWxLog(QWORD a1, QWORD a2, QWORD a3, QWORD a4, QWORD a5, QWORD a6, QWORD a7, QWORD a8, QWORD a9,
|
||||
QWORD a10, QWORD a11, QWORD a12)
|
||||
{
|
||||
QWORD p = realWxLog(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
|
||||
if (p == 0 || p == 1) {
|
||||
return p;
|
||||
}
|
||||
|
||||
LOG_INFO("【WX】\n{}", GB2312ToUtf8((char *)p));
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static void DispatchPyq(QWORD arg1, QWORD arg2, QWORD arg3)
|
||||
{
|
||||
QWORD startAddr = *(QWORD *)(arg2 + OS_PYQ_MSG_START);
|
||||
QWORD endAddr = *(QWORD *)(arg2 + OS_PYQ_MSG_END);
|
||||
|
||||
if (startAddr == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (startAddr < endAddr) {
|
||||
WxMsg_t wxMsg;
|
||||
|
||||
wxMsg.type = 0x00; // 朋友圈消息
|
||||
wxMsg.is_self = false;
|
||||
wxMsg.is_group = false;
|
||||
wxMsg.id = GET_QWORD(startAddr);
|
||||
wxMsg.ts = GET_DWORD(startAddr + OS_PYQ_MSG_TS);
|
||||
wxMsg.xml = GetStringByWstrAddr(startAddr + OS_PYQ_MSG_XML);
|
||||
wxMsg.sender = GetStringByWstrAddr(startAddr + OS_PYQ_MSG_SENDER);
|
||||
wxMsg.content = GetStringByWstrAddr(startAddr + OS_PYQ_MSG_CONTENT);
|
||||
|
||||
{
|
||||
unique_lock<mutex> lock(gMutex);
|
||||
gMsgQueue.push(wxMsg); // 推送到队列
|
||||
}
|
||||
|
||||
gCV.notify_all(); // 通知各方消息就绪
|
||||
|
||||
startAddr += 0x1618;
|
||||
}
|
||||
}
|
||||
|
||||
static MH_STATUS InitializeHook()
|
||||
{
|
||||
if (isMH_Initialized) {
|
||||
return MH_OK;
|
||||
}
|
||||
MH_STATUS status = MH_Initialize();
|
||||
if (status == MH_OK) {
|
||||
isMH_Initialized = true;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static MH_STATUS UninitializeHook()
|
||||
{
|
||||
if (!isMH_Initialized) {
|
||||
return MH_OK;
|
||||
}
|
||||
if (gIsLogging || gIsListening || gIsListeningPyq) {
|
||||
return MH_OK;
|
||||
}
|
||||
MH_STATUS status = MH_Uninitialize();
|
||||
if (status == MH_OK) {
|
||||
isMH_Initialized = false;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
void EnableLog()
|
||||
{
|
||||
MH_STATUS status = MH_UNKNOWN;
|
||||
if (gIsLogging) {
|
||||
LOG_WARN("gIsLogging");
|
||||
return;
|
||||
}
|
||||
WxLog_t funcWxLog = (WxLog_t)(g_WeChatWinDllAddr + OS_WXLOG);
|
||||
|
||||
status = InitializeHook();
|
||||
if (status != MH_OK) {
|
||||
LOG_ERROR("MH_Initialize failed: {}", to_string(status));
|
||||
return;
|
||||
}
|
||||
|
||||
status = MH_CreateHook(funcWxLog, &PrintWxLog, reinterpret_cast<LPVOID *>(&realWxLog));
|
||||
if (status != MH_OK) {
|
||||
LOG_ERROR("MH_CreateHook failed: {}", to_string(status));
|
||||
return;
|
||||
}
|
||||
|
||||
status = MH_EnableHook(funcWxLog);
|
||||
if (status != MH_OK) {
|
||||
LOG_ERROR("MH_EnableHook failed: {}", to_string(status));
|
||||
return;
|
||||
}
|
||||
gIsLogging = true;
|
||||
}
|
||||
|
||||
void DisableLog()
|
||||
{
|
||||
MH_STATUS status = MH_UNKNOWN;
|
||||
if (!gIsLogging) {
|
||||
return;
|
||||
}
|
||||
|
||||
status = MH_DisableHook(funcWxLog);
|
||||
if (status != MH_OK) {
|
||||
LOG_ERROR("MH_DisableHook failed: {}", to_string(status));
|
||||
return;
|
||||
}
|
||||
|
||||
gIsLogging = false;
|
||||
|
||||
status = UninitializeHook();
|
||||
if (status != MH_OK) {
|
||||
LOG_ERROR("MH_Uninitialize failed: {}", to_string(status));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ListenMessage()
|
||||
{
|
||||
MH_STATUS status = MH_UNKNOWN;
|
||||
if (gIsListening) {
|
||||
LOG_WARN("gIsListening");
|
||||
return;
|
||||
}
|
||||
funcRecvMsg = (RecvMsg_t)(g_WeChatWinDllAddr + OS_RECV_MSG_CALL);
|
||||
|
||||
status = InitializeHook();
|
||||
if (status != MH_OK) {
|
||||
LOG_ERROR("MH_Initialize failed: {}", to_string(status));
|
||||
return;
|
||||
}
|
||||
|
||||
status = MH_CreateHook(funcRecvMsg, &DispatchMsg, reinterpret_cast<LPVOID *>(&realRecvMsg));
|
||||
if (status != MH_OK) {
|
||||
LOG_ERROR("MH_CreateHook failed: {}", to_string(status));
|
||||
return;
|
||||
}
|
||||
|
||||
status = MH_EnableHook(funcRecvMsg);
|
||||
if (status != MH_OK) {
|
||||
LOG_ERROR("MH_EnableHook failed: {}", to_string(status));
|
||||
return;
|
||||
}
|
||||
|
||||
gIsListening = true;
|
||||
}
|
||||
|
||||
void UnListenMessage()
|
||||
{
|
||||
MH_STATUS status = MH_UNKNOWN;
|
||||
if (!gIsListening) {
|
||||
return;
|
||||
}
|
||||
|
||||
status = MH_DisableHook(funcRecvMsg);
|
||||
if (status != MH_OK) {
|
||||
LOG_ERROR("MH_DisableHook failed: {}", to_string(status));
|
||||
return;
|
||||
}
|
||||
|
||||
gIsListening = false;
|
||||
|
||||
status = UninitializeHook();
|
||||
if (status != MH_OK) {
|
||||
LOG_ERROR("MH_Uninitialize failed: {}", to_string(status));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ListenPyq()
|
||||
{
|
||||
MH_STATUS status = MH_UNKNOWN;
|
||||
if (gIsListeningPyq) {
|
||||
LOG_WARN("gIsListeningPyq");
|
||||
return;
|
||||
}
|
||||
funcRecvPyq = (RecvPyq_t)(g_WeChatWinDllAddr + OS_PYQ_MSG_CALL);
|
||||
|
||||
status = InitializeHook();
|
||||
if (status != MH_OK) {
|
||||
LOG_ERROR("MH_Initialize failed: {}", to_string(status));
|
||||
return;
|
||||
}
|
||||
|
||||
status = MH_CreateHook(funcRecvPyq, &DispatchPyq, reinterpret_cast<LPVOID *>(&realRecvPyq));
|
||||
if (status != MH_OK) {
|
||||
LOG_ERROR("MH_CreateHook failed: {}", to_string(status));
|
||||
return;
|
||||
}
|
||||
|
||||
status = MH_EnableHook(funcRecvPyq);
|
||||
if (status != MH_OK) {
|
||||
LOG_ERROR("MH_EnableHook failed: {}", to_string(status));
|
||||
return;
|
||||
}
|
||||
|
||||
gIsListeningPyq = true;
|
||||
}
|
||||
|
||||
void UnListenPyq()
|
||||
{
|
||||
MH_STATUS status = MH_UNKNOWN;
|
||||
if (!gIsListeningPyq) {
|
||||
return;
|
||||
}
|
||||
|
||||
status = MH_DisableHook(funcRecvPyq);
|
||||
if (status != MH_OK) {
|
||||
LOG_ERROR("MH_DisableHook failed: {}", to_string(status));
|
||||
return;
|
||||
}
|
||||
|
||||
gIsListeningPyq = false;
|
||||
|
||||
status = UninitializeHook();
|
||||
if (status != MH_OK) {
|
||||
LOG_ERROR("MH_Uninitialize failed: {}", to_string(status));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1,274 +0,0 @@
|
||||
|
||||
#include "framework.h"
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include "exec_sql.h"
|
||||
#include "log.h"
|
||||
#include "send_msg.h"
|
||||
#include "spy_types.h"
|
||||
#include "util.h"
|
||||
|
||||
extern HANDLE g_hEvent;
|
||||
extern QWORD g_WeChatWinDllAddr;
|
||||
extern string GetSelfWxid(); // Defined in spy.cpp
|
||||
|
||||
#define SRTM_SIZE 0x3F0
|
||||
|
||||
#define OS_NEW 0x1B63A50
|
||||
#define OS_FREE 0x1B5B160
|
||||
#define OS_SEND_MSG_MGR 0x1B598E0
|
||||
#define OS_SEND_TEXT 0x22CC660
|
||||
#define OS_SEND_IMAGE 0x22C1E70
|
||||
#define OS_GET_APP_MSG_MGR 0x1B5E880
|
||||
#define OS_SEND_FILE 0x20D5FF0
|
||||
#define OS_RTM_NEW 0x1B62FA0
|
||||
#define OS_RTM_FREE 0x1B62370
|
||||
#define OS_SEND_RICH_TEXT 0x20DFFD0
|
||||
#define OS_SEND_PAT_MSG 0x2CC4F10
|
||||
#define OS_FORWARD_MSG 0x22CBBE0
|
||||
#define OS_GET_EMOTION_MGR 0x1BD49A0
|
||||
#define OS_SEND_EMOTION 0x21BACD0
|
||||
#define OS_XML_BUFSIGN 0x24FB330
|
||||
#define OS_SEND_XML 0x20D5120
|
||||
|
||||
typedef QWORD (*New_t)(QWORD);
|
||||
typedef QWORD (*Free_t)(QWORD);
|
||||
typedef QWORD (*SendMsgMgr_t)();
|
||||
typedef QWORD (*GetAppMsgMgr_t)();
|
||||
typedef QWORD (*SendTextMsg_t)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD);
|
||||
typedef QWORD (*SendImageMsg_t)(QWORD, QWORD, QWORD, QWORD, QWORD);
|
||||
typedef QWORD (*SendFileMsg_t)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD *, QWORD, QWORD *, QWORD, QWORD *, QWORD,
|
||||
QWORD);
|
||||
typedef QWORD (*SendRichTextMsg_t)(QWORD, QWORD, QWORD);
|
||||
typedef QWORD (*SendPatMsg_t)(QWORD, QWORD);
|
||||
typedef QWORD (*ForwardMsg_t)(QWORD, QWORD, QWORD, QWORD);
|
||||
typedef QWORD (*GetEmotionMgr_t)();
|
||||
typedef QWORD (*SendEmotion_t)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD);
|
||||
|
||||
typedef QWORD (*XmlBufSign_t)(QWORD, QWORD, QWORD);
|
||||
typedef QWORD (*SendXmlMsg_t)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD);
|
||||
|
||||
void SendTextMessage(string wxid, string msg, string atWxids)
|
||||
{
|
||||
QWORD success = 0;
|
||||
wstring wsWxid = String2Wstring(wxid);
|
||||
wstring wsMsg = String2Wstring(msg);
|
||||
WxString wxMsg(wsMsg);
|
||||
WxString wxWxid(wsWxid);
|
||||
|
||||
vector<wstring> vAtWxids;
|
||||
vector<WxString> vWxAtWxids;
|
||||
if (!atWxids.empty()) {
|
||||
wstringstream wss(String2Wstring(atWxids));
|
||||
while (wss.good()) {
|
||||
wstring wstr;
|
||||
getline(wss, wstr, L',');
|
||||
vAtWxids.push_back(wstr);
|
||||
WxString wxAtWxid(vAtWxids.back());
|
||||
vWxAtWxids.push_back(wxAtWxid);
|
||||
}
|
||||
} else {
|
||||
WxString wxEmpty = WxString();
|
||||
vWxAtWxids.push_back(wxEmpty);
|
||||
}
|
||||
|
||||
QWORD wxAters = (QWORD) & ((RawVector_t *)&vWxAtWxids)->start;
|
||||
|
||||
char buffer[0x460] = { 0 };
|
||||
SendMsgMgr_t funcSendMsgMgr = (SendMsgMgr_t)(g_WeChatWinDllAddr + OS_SEND_MSG_MGR);
|
||||
SendTextMsg_t funcSendTextMsg = (SendTextMsg_t)(g_WeChatWinDllAddr + OS_SEND_TEXT);
|
||||
Free_t funcFree = (Free_t)(g_WeChatWinDllAddr + OS_FREE);
|
||||
funcSendMsgMgr();
|
||||
success = funcSendTextMsg((QWORD)(&buffer), (QWORD)(&wxWxid), (QWORD)(&wxMsg), wxAters, 1, 1, 0, 0);
|
||||
funcFree((QWORD)(&buffer));
|
||||
}
|
||||
|
||||
void SendImageMessage(string wxid, string path)
|
||||
{
|
||||
wstring wsWxid = String2Wstring(wxid);
|
||||
wstring wsPath = String2Wstring(path);
|
||||
|
||||
WxString wxWxid(wsWxid);
|
||||
WxString wxPath(wsPath);
|
||||
|
||||
New_t funcNew = (New_t)(g_WeChatWinDllAddr + OS_NEW);
|
||||
Free_t funcFree = (Free_t)(g_WeChatWinDllAddr + OS_FREE);
|
||||
SendMsgMgr_t funcSendMsgMgr = (SendMsgMgr_t)(g_WeChatWinDllAddr + OS_SEND_MSG_MGR);
|
||||
SendImageMsg_t funcSendImage = (SendImageMsg_t)(g_WeChatWinDllAddr + OS_SEND_IMAGE);
|
||||
|
||||
char msg[0x460] = { 0 };
|
||||
char msgTmp[0x460] = { 0 };
|
||||
QWORD *flag[10] = { 0 };
|
||||
|
||||
QWORD tmp1 = 0, tmp2 = 0;
|
||||
QWORD pMsgTmp = funcNew((QWORD)(&msgTmp));
|
||||
flag[8] = &tmp1;
|
||||
flag[9] = &tmp2;
|
||||
flag[1] = (QWORD *)(pMsgTmp);
|
||||
|
||||
QWORD pMsg = funcNew((QWORD)(&msg));
|
||||
QWORD sendMgr = funcSendMsgMgr();
|
||||
funcSendImage(sendMgr, pMsg, (QWORD)(&wxWxid), (QWORD)(&wxPath), (QWORD)(&flag));
|
||||
funcFree(pMsg);
|
||||
funcFree(pMsgTmp);
|
||||
}
|
||||
|
||||
void SendFileMessage(string wxid, string path)
|
||||
{
|
||||
wstring wsWxid = String2Wstring(wxid);
|
||||
wstring wsPath = String2Wstring(path);
|
||||
|
||||
WxString wxWxid(wsWxid);
|
||||
WxString wxPath(wsPath);
|
||||
|
||||
New_t funcNew = (New_t)(g_WeChatWinDllAddr + OS_NEW);
|
||||
Free_t funcFree = (Free_t)(g_WeChatWinDllAddr + OS_FREE);
|
||||
GetAppMsgMgr_t funcGetAppMsgMgr = (GetAppMsgMgr_t)(g_WeChatWinDllAddr + OS_GET_APP_MSG_MGR);
|
||||
SendFileMsg_t funcSendFile = (SendFileMsg_t)(g_WeChatWinDllAddr + OS_SEND_FILE);
|
||||
|
||||
char msg[0x460] = { 0 };
|
||||
QWORD tmp1[4] = { 0 };
|
||||
QWORD tmp2[4] = { 0 };
|
||||
QWORD tmp3[4] = { 0 };
|
||||
|
||||
QWORD pMsg = funcNew((QWORD)(&msg));
|
||||
QWORD appMgr = funcGetAppMsgMgr();
|
||||
funcSendFile(appMgr, pMsg, (QWORD)(&wxWxid), (QWORD)(&wxPath), 1, tmp1, 0, tmp2, 0, tmp3, 0, 0);
|
||||
funcFree(pMsg);
|
||||
}
|
||||
|
||||
int SendRichTextMessage(RichText_t &rt)
|
||||
{ // TODO: Fix memory leak
|
||||
QWORD status = -1;
|
||||
|
||||
New_t funcNew = (New_t)(g_WeChatWinDllAddr + OS_RTM_NEW);
|
||||
Free_t funcFree = (Free_t)(g_WeChatWinDllAddr + OS_RTM_FREE);
|
||||
GetAppMsgMgr_t funcGetAppMsgMgr = (GetAppMsgMgr_t)(g_WeChatWinDllAddr + OS_GET_APP_MSG_MGR);
|
||||
SendRichTextMsg_t funcForwordPublicMsg = (SendRichTextMsg_t)(g_WeChatWinDllAddr + OS_SEND_RICH_TEXT);
|
||||
|
||||
char *buff = (char *)HeapAlloc(GetProcessHeap(), 0, SRTM_SIZE);
|
||||
if (buff == NULL) {
|
||||
LOG_ERROR("Out of Memory...");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(buff, 0, SRTM_SIZE);
|
||||
funcNew((QWORD)buff);
|
||||
WxString *pReceiver = NewWxStringFromStr(rt.receiver);
|
||||
WxString *pTitle = NewWxStringFromStr(rt.title);
|
||||
WxString *pUrl = NewWxStringFromStr(rt.url);
|
||||
WxString *pThumburl = NewWxStringFromStr(rt.thumburl);
|
||||
WxString *pDigest = NewWxStringFromStr(rt.digest);
|
||||
WxString *pAccount = NewWxStringFromStr(rt.account);
|
||||
WxString *pName = NewWxStringFromStr(rt.name);
|
||||
|
||||
memcpy(buff + 0x8, pTitle, sizeof(WxString));
|
||||
memcpy(buff + 0x48, pUrl, sizeof(WxString));
|
||||
memcpy(buff + 0xB0, pThumburl, sizeof(WxString));
|
||||
memcpy(buff + 0xF0, pDigest, sizeof(WxString));
|
||||
memcpy(buff + 0x2C0, pAccount, sizeof(WxString));
|
||||
memcpy(buff + 0x2E0, pName, sizeof(WxString));
|
||||
|
||||
QWORD mgr = funcGetAppMsgMgr();
|
||||
status = funcForwordPublicMsg(mgr, (QWORD)(pReceiver), (QWORD)(buff));
|
||||
funcFree((QWORD)buff);
|
||||
|
||||
return (int)status;
|
||||
}
|
||||
|
||||
int SendPatMessage(string roomid, string wxid)
|
||||
{
|
||||
QWORD status = -1;
|
||||
|
||||
wstring wsRoomid = String2Wstring(roomid);
|
||||
wstring wsWxid = String2Wstring(wxid);
|
||||
WxString wxRoomid(wsRoomid);
|
||||
WxString wxWxid(wsWxid);
|
||||
|
||||
SendPatMsg_t funcSendPatMsg = (SendPatMsg_t)(g_WeChatWinDllAddr + OS_SEND_PAT_MSG);
|
||||
|
||||
status = funcSendPatMsg((QWORD)(&wxRoomid), (QWORD)(&wxWxid));
|
||||
return (int)status;
|
||||
}
|
||||
|
||||
int ForwardMessage(QWORD msgid, string receiver)
|
||||
{
|
||||
int status = -1;
|
||||
uint32_t dbIdx = 0;
|
||||
QWORD localId = 0;
|
||||
|
||||
ForwardMsg_t funcForwardMsg = (ForwardMsg_t)(g_WeChatWinDllAddr + OS_FORWARD_MSG);
|
||||
if (GetLocalIdandDbidx(msgid, &localId, &dbIdx) != 0) {
|
||||
LOG_ERROR("Failed to get localId, Please check id: {}", to_string(msgid));
|
||||
return status;
|
||||
}
|
||||
|
||||
WxString *pReceiver = NewWxStringFromStr(receiver);
|
||||
|
||||
LARGE_INTEGER l;
|
||||
l.HighPart = dbIdx;
|
||||
l.LowPart = (DWORD)localId;
|
||||
|
||||
status = (int)funcForwardMsg((QWORD)pReceiver, l.QuadPart, 0x4, 0x0);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void SendEmotionMessage(string wxid, string path)
|
||||
{
|
||||
GetEmotionMgr_t GetEmotionMgr = (GetEmotionMgr_t)(g_WeChatWinDllAddr + OS_GET_EMOTION_MGR);
|
||||
SendEmotion_t SendEmotion = (SendEmotion_t)(g_WeChatWinDllAddr + OS_SEND_EMOTION);
|
||||
|
||||
WxString *pWxPath = NewWxStringFromStr(path);
|
||||
WxString *pWxWxid = NewWxStringFromStr(wxid);
|
||||
|
||||
QWORD *buff = (QWORD *)HeapAlloc(GetProcessHeap(), 0, 0x20);
|
||||
if (buff == NULL) {
|
||||
LOG_ERROR("Out of Memory...");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(buff, 0, 0x20);
|
||||
QWORD mgr = GetEmotionMgr();
|
||||
SendEmotion(mgr, (QWORD)pWxPath, (QWORD)buff, (QWORD)pWxWxid, 2, (QWORD)buff, 0, (QWORD)buff);
|
||||
}
|
||||
|
||||
void SendXmlMessage(string receiver, string xml, string path, QWORD type)
|
||||
{
|
||||
if (g_WeChatWinDllAddr == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
New_t funcNew = (New_t)(g_WeChatWinDllAddr + OS_NEW);
|
||||
Free_t funcFree = (Free_t)(g_WeChatWinDllAddr + OS_FREE);
|
||||
|
||||
XmlBufSign_t xmlBufSign = (XmlBufSign_t)(g_WeChatWinDllAddr + OS_XML_BUFSIGN);
|
||||
SendXmlMsg_t sendXmlMsg = (SendXmlMsg_t)(g_WeChatWinDllAddr + OS_SEND_XML);
|
||||
|
||||
char buff[0x500] = { 0 };
|
||||
char buff2[0x500] = { 0 };
|
||||
char nullBuf[0x1C] = { 0 };
|
||||
|
||||
QWORD pBuf = (QWORD)(&buff);
|
||||
QWORD pBuf2 = (QWORD)(&buff2);
|
||||
|
||||
funcNew(pBuf);
|
||||
funcNew(pBuf2);
|
||||
|
||||
QWORD sbuf[4] = { 0, 0, 0, 0 };
|
||||
|
||||
QWORD sign = xmlBufSign(pBuf2, (QWORD)(&sbuf), 0x1);
|
||||
|
||||
WxString *pReceiver = NewWxStringFromStr(receiver);
|
||||
WxString *pXml = NewWxStringFromStr(xml);
|
||||
WxString *pPath = NewWxStringFromStr(path);
|
||||
WxString *pSender = NewWxStringFromStr(GetSelfWxid());
|
||||
|
||||
sendXmlMsg(pBuf, (QWORD)pSender, (QWORD)pReceiver, (QWORD)pXml, (QWORD)pPath, (QWORD)(&nullBuf), type, 0x4, sign,
|
||||
pBuf2);
|
||||
|
||||
funcFree((QWORD)&buff);
|
||||
funcFree((QWORD)&buff2);
|
||||
}
|
||||
|
@ -1,59 +0,0 @@
|
||||
#include "user_info.h"
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
|
||||
extern UINT64 g_WeChatWinDllAddr;
|
||||
|
||||
#define OS_USER_HOME 0x59F6330
|
||||
#define OS_USER_WXID 0x5A20200
|
||||
#define OS_USER_NAME 0x5A20368
|
||||
#define OS_USER_MOBILE 0x595C318
|
||||
|
||||
static char home[MAX_PATH] = { 0 };
|
||||
|
||||
string GetHomePath()
|
||||
{
|
||||
if (home[0] == 0) {
|
||||
string path = Wstring2String(GET_WSTRING(g_WeChatWinDllAddr + OS_USER_HOME)) + "\\WeChat Files\\";
|
||||
strncpy_s(home, path.c_str(), path.size());
|
||||
}
|
||||
|
||||
return string(home);
|
||||
}
|
||||
|
||||
string GetSelfWxid()
|
||||
{
|
||||
UINT64 wxidType = 0;
|
||||
try {
|
||||
wxidType = GET_UINT64(g_WeChatWinDllAddr + OS_USER_WXID + 0x18);
|
||||
if (wxidType == 0xF) {
|
||||
return GET_STRING_FROM_P(g_WeChatWinDllAddr + OS_USER_WXID);
|
||||
} else {
|
||||
return GET_STRING(g_WeChatWinDllAddr + OS_USER_WXID);
|
||||
}
|
||||
} catch (...) {
|
||||
LOG_ERROR("wxid type: {:#x}", wxidType);
|
||||
LOG_BUFFER((uint8_t *)(g_WeChatWinDllAddr + OS_USER_WXID), 20);
|
||||
return "empty_wxid";
|
||||
}
|
||||
}
|
||||
|
||||
UserInfo_t GetUserInfo()
|
||||
{
|
||||
UserInfo_t ui;
|
||||
|
||||
ui.wxid = GetSelfWxid();
|
||||
|
||||
UINT64 nameType = GET_UINT64(g_WeChatWinDllAddr + OS_USER_NAME + 0x18);
|
||||
if (nameType == 0xF) {
|
||||
ui.name = GET_STRING_FROM_P(g_WeChatWinDllAddr + OS_USER_NAME);
|
||||
} else { // 0x1F
|
||||
ui.name = GET_STRING(g_WeChatWinDllAddr + OS_USER_NAME);
|
||||
}
|
||||
|
||||
ui.mobile = GET_STRING_FROM_P(g_WeChatWinDllAddr + OS_USER_MOBILE);
|
||||
ui.home = GetHomePath();
|
||||
|
||||
return ui;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user