From b34cdfd38e5d3a5cddcfb927164343383ea33ec6 Mon Sep 17 00:00:00 2001 From: Changhua Date: Thu, 25 May 2023 00:18:10 +0800 Subject: [PATCH] Impl Functions_FUNC_GET_CONTACTS --- spy/get_contacts.cpp | 88 +++++++++++++++++++++++++++++++++++++------- spy/load_calls.cpp | 4 +- spy/rpc_server.cpp | 2 +- spy/util.cpp | 25 +++++++++++++ spy/util.h | 10 +++-- 5 files changed, 108 insertions(+), 21 deletions(-) diff --git a/spy/get_contacts.cpp b/spy/get_contacts.cpp index 0fbd5ce..68fd6a5 100644 --- a/spy/get_contacts.cpp +++ b/spy/get_contacts.cpp @@ -7,26 +7,86 @@ extern WxCalls_t g_WxCalls; extern DWORD g_WeChatWinDllAddr; +#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 DWORD FindMem(DWORD start, DWORD end, const void *target, size_t len) +{ + uint8_t *p = (uint8_t *)start; + while ((DWORD)p < end) { + if (memcmp((void *)p, target, len) == 0) { + return (DWORD)p; + } + p++; + } + + return 0; +} + +static string GetCntString(DWORD start, DWORD end, const uint8_t *feat, size_t len) +{ + DWORD pfeat = FindMem(start, end, feat, len); + if (pfeat == 0) { + return ""; + } + + DWORD lfeat = GET_DWORD(pfeat + len); + if (lfeat <= 2) { + return ""; + } + + // DbgMsg("pfeat: %08X, lfeat: %d", pfeat, lfeat); + return Wstring2String(wstring(GET_WSTRING_FROM_P(pfeat + FEAT_LEN + 4), lfeat)); +} + vector GetContacts() { vector contacts; - DWORD baseAddr = g_WeChatWinDllAddr + g_WxCalls.contact.base; - DWORD tempAddr = GET_DWORD(baseAddr); - DWORD head = GET_DWORD(tempAddr + g_WxCalls.contact.head); - DWORD node = GET_DWORD(head); + DWORD call1 = g_WeChatWinDllAddr + g_WxCalls.contact.base; + DWORD call2 = g_WeChatWinDllAddr + g_WxCalls.contact.head; - while (node != head) { + int success = 0; + DWORD *addr[3] = { 0, 0, 0 }; + __asm { + pushad + call call1 + lea ecx,addr + push ecx + mov ecx,eax + call call2 + mov success,eax + popad + } + + DWORD pstart = (DWORD)addr[0]; + DWORD pend = (DWORD)addr[2]; + + while (pstart < pend) { RpcContact_t cnt; - cnt.wxid = GetStringByAddress(node + g_WxCalls.contact.wxId); - cnt.code = GetStringByAddress(node + g_WxCalls.contact.wxCode); - cnt.remark = GetStringByAddress(node + g_WxCalls.contact.wxRemark); - cnt.name = GetStringByAddress(node + g_WxCalls.contact.wxName); - cnt.country = GetStringByAddress(node + g_WxCalls.contact.wxCountry); - cnt.province = GetStringByAddress(node + g_WxCalls.contact.wxProvince); - cnt.city = GetStringByAddress(node + g_WxCalls.contact.wxCity); - cnt.gender = GET_DWORD(node + g_WxCalls.contact.wxGender); + DWORD pbin = GET_DWORD(pstart + 0x150); + DWORD lenbin = GET_DWORD(pstart + 0x154); + // DbgMsg("pstart: %08X, pbin: %08X, lenbin: %d", pstart, pbin, lenbin); + + cnt.wxid = GetStringByAddress(pstart + g_WxCalls.contact.wxId); + cnt.code = GetStringByAddress(pstart + g_WxCalls.contact.wxCode); + cnt.remark = GetStringByAddress(pstart + g_WxCalls.contact.wxRemark); + cnt.name = GetStringByAddress(pstart + g_WxCalls.contact.wxName); + + 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 + g_WxCalls.contact.wxGender); + } + // DbgMsg("pstart: %08X, pbin: %08X, lenbin: %d, cnt.gender: %08X", pstart, pbin, lenbin, cnt.gender); + contacts.push_back(cnt); - node = GET_DWORD(node); + pstart += 0x438; } return contacts; diff --git a/spy/load_calls.cpp b/spy/load_calls.cpp index b23a544..07747a8 100644 --- a/spy/load_calls.cpp +++ b/spy/load_calls.cpp @@ -16,8 +16,8 @@ WxCalls_t wxCalls = { { 0xB8A70, 0x3ED5E0, 0x107F00, 0x3ED7B0, 0x2386FE4 }, // Send xml Message { 0x771980, 0x4777E0, 0x239E888 }, // Send Emotion Message /* Get Contacts: - Base, head, wxId, Code, Remark,Name, Gender, Country, Province, City*/ - { 0x23668F4, 0x4C, 0x30, 0x44, 0x78, 0x8C, 0x184, 0x1D0, 0x1E4, 0x1F8 }, + call1, call2, wxId, Code, Remark,Name, Gender, Country, Province, City*/ + { 0x75A4A0, 0xC089F0, 0x10, 0x24, 0x58, 0x6C, 0x0E, 0x00, 0x00, 0x00 }, /* Exec Sql: Exec, base, start, end, slot, name*/ { 0x141BDF0, 0x2366934, 0x1428, 0x142C, 0x3C, 0x50 }, diff --git a/spy/rpc_server.cpp b/spy/rpc_server.cpp index b86aaaf..0c4d635 100644 --- a/spy/rpc_server.cpp +++ b/spy/rpc_server.cpp @@ -559,12 +559,12 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len ret = func_get_msg_types(out, out_len); break; } -#if 0 case Functions_FUNC_GET_CONTACTS: { LOG_DEBUG("[Functions_FUNC_GET_CONTACTS]"); ret = func_get_contacts(out, out_len); break; } +#if 0 case Functions_FUNC_GET_DB_NAMES: { LOG_DEBUG("[Functions_FUNC_GET_DB_NAMES]"); ret = func_get_db_names(out, out_len); diff --git a/spy/util.cpp b/spy/util.cpp index 5604b34..66a831e 100644 --- a/spy/util.cpp +++ b/spy/util.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "util.h" @@ -244,3 +245,27 @@ wstring GetUnicodeInfoByAddress(HANDLE hProcess, DWORD address) return value; } + +void DbgMsg(const char *zcFormat, ...) +{ + // initialize use of the variable argument array + va_list vaArgs; + va_start(vaArgs, zcFormat); + + // reliably acquire the size + // from a copy of the variable argument array + // and a functionally reliable call to mock the formatting + va_list vaArgsCopy; + va_copy(vaArgsCopy, vaArgs); + const int iLen = std::vsnprintf(NULL, 0, zcFormat, vaArgsCopy); + va_end(vaArgsCopy); + + // return a formatted string without risking memory mismanagement + // and without assuming any compiler or platform specific behavior + std::vector zc(iLen + 1); + std::vsnprintf(zc.data(), zc.size(), zcFormat, vaArgs); + va_end(vaArgs); + std::string strText(zc.data(), iLen); + + OutputDebugStringA(strText.c_str()); +} diff --git a/spy/util.h b/spy/util.h index 5d5344e..b33c685 100644 --- a/spy/util.h +++ b/spy/util.h @@ -8,10 +8,11 @@ #define WECHATINJECTDLL L"spy.dll" #define WECHATINJECTDLL_DEBUG L"spy_debug.dll" -#define GET_DWORD(addr) ((DWORD) * (DWORD *)(addr)) -#define GET_STRING(addr) ((CHAR *)(*(DWORD *)(addr))) -#define GET_WSTRING(addr) ((WCHAR *)(*(DWORD *)(addr))) -#define GET_STRING_FROM_P(addr) ((CHAR *)(addr)) +#define GET_DWORD(addr) ((DWORD) * (DWORD *)(addr)) +#define GET_STRING(addr) ((CHAR *)(*(DWORD *)(addr))) +#define GET_WSTRING(addr) ((WCHAR *)(*(DWORD *)(addr))) +#define GET_STRING_FROM_P(addr) ((CHAR *)(addr)) +#define GET_WSTRING_FROM_P(addr) ((WCHAR *)(addr)) typedef struct PortPath { int port; @@ -27,3 +28,4 @@ std::wstring GetUnicodeInfoByAddress(HANDLE hProcess, DWORD address); std::wstring String2Wstring(std::string s); std::string Wstring2String(std::wstring ws); std::string GetStringByAddress(DWORD address); +void DbgMsg(const char *zcFormat, ...);