未验证 提交 f68111cf 编写于 作者: J Jack Li 提交者: GitHub

Merge pull request #94 from ljc545w/add/msg-extrabuf

修改接收消息格式,消息内容添加扩展信息
......@@ -24,5 +24,6 @@ repos:
exclude: |
(?x)^(
.*?_i\.h|
.*?_p\.c
.*?_p\.c|
.*?\.md
)
......@@ -3,6 +3,8 @@
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <map>
#include "json/json.hpp"
using namespace nlohmann;
#pragma comment(lib, "ws2_32.lib")
......@@ -24,19 +26,6 @@ using namespace std;
static int SRVPORT = 0;
struct ScoketMsgStruct
{
DWORD pid;
int messagetype;
BOOL isSendMessage;
unsigned long long msgid;
wchar_t sender[80];
wchar_t wxid[80];
wchar_t message[0x1000B];
wchar_t filepath[MAX_PATH];
wchar_t time[30];
};
// 是否开启接收消息HOOK标志
BOOL ReceiveMessageHooked = false;
// 保存HOOK前的字节码,用于恢复
......@@ -56,10 +45,23 @@ static DWORD SendMessageNextCall = WeChatWinBase + SendMessageNextCallOffset;
// 发送HOOK的跳转地址
static DWORD SendMessageJmpBackAddress = SendMessageHookAddress + 0x5;
struct SocketMessageStruct
{
char *buffer;
int length;
~SocketMessageStruct()
{
if (this->buffer != NULL)
{
delete[] this->buffer;
this->buffer = NULL;
}
}
};
// 通过socket将消息发送给服务端
BOOL SendSocketMessage(ReceiveMsgStruct *ms)
BOOL SendSocketMessage(const char *buffer, size_t len)
{
shared_ptr<ReceiveMsgStruct> shared_ms(ms);
if (SRVPORT == 0)
{
return false;
......@@ -89,21 +91,7 @@ BOOL SendSocketMessage(ReceiveMsgStruct *ms)
return false;
}
char recvbuf[1024] = {0};
auto sms = std::make_shared<ScoketMsgStruct>();
ZeroMemory(sms.get(), sizeof(ScoketMsgStruct));
sms->pid = shared_ms->pid;
sms->messagetype = shared_ms->messagetype;
sms->isSendMessage = shared_ms->isSendMessage;
sms->msgid = shared_ms->msgid;
memcpy(sms->wxid, shared_ms->wxid.c_str(), shared_ms->wxid.length() * 2);
memcpy(sms->sender, shared_ms->sender.c_str(), shared_ms->sender.length() * 2);
memcpy(sms->message, shared_ms->message.c_str(), shared_ms->message.length() * 2);
memcpy(sms->filepath, shared_ms->filepath.c_str(), shared_ms->filepath.length() * 2);
memcpy(sms->time, shared_ms->time.c_str(), shared_ms->time.length() * 2);
#ifdef _DEBUG
wcout << sms->time << endl;
#endif
int ret = send(clientsocket, (char *)sms.get(), sizeof(ScoketMsgStruct), 0);
int ret = send(clientsocket, buffer, len, 0);
if (ret == -1 || ret == 0)
{
#ifdef _DEBUG
......@@ -126,83 +114,43 @@ BOOL SendSocketMessage(ReceiveMsgStruct *ms)
return true;
}
// 创建广播消息数组
#ifndef USE_SOCKET
static SAFEARRAY *CreateMessageArray(map<wstring, _variant_t> msg)
void SendSocketMessageInThread(SocketMessageStruct *param)
{
HRESULT hr = S_OK;
SAFEARRAY *psaValue;
vector<wstring> MessageInfoKey = {
L"pid",
L"type",
L"isSendMessage",
L"msgid",
msg[L"isSendMessage"].boolVal ? L"sendto" : L"from",
L"wxid",
L"message",
L"filepath",
L"time"};
SAFEARRAYBOUND rgsaBound[2] = {{MessageInfoKey.size(), 0}, {2, 0}};
psaValue = SafeArrayCreate(VT_VARIANT, 2, rgsaBound);
long keyIndex[2] = {0, 0};
keyIndex[0] = 0;
keyIndex[1] = 0;
for (unsigned int i = 0; i < MessageInfoKey.size(); i++)
{
keyIndex[0] = i;
keyIndex[1] = 0;
_variant_t key = MessageInfoKey[i].c_str();
hr = SafeArrayPutElement(psaValue, keyIndex, &key);
keyIndex[0] = i;
keyIndex[1] = 1;
hr = SafeArrayPutElement(psaValue, keyIndex, &msg[MessageInfoKey[i]]);
}
return psaValue;
if (param == NULL)
return;
unique_ptr<SocketMessageStruct> sms(param);
string jstr(param->buffer, param->length);
SendSocketMessage(jstr.c_str(), jstr.size());
}
#endif
static void dealMessage(DWORD messageAddr)
{
BOOL isSendMessage = *(BOOL *)(messageAddr + 0x3C);
ReceiveMsgStruct *message = new ReceiveMsgStruct;
ZeroMemory(message, sizeof(ReceiveMsgStruct));
message->pid = GetCurrentProcessId();
message->isSendMessage = isSendMessage;
message->time = GetTimeW(*(DWORD *)(messageAddr + 0x44));
message->messagetype = *(DWORD *)(messageAddr + 0x38);
message->msgid = *(unsigned long long *)(messageAddr + 0x30);
message->sender = READ_WSTRING(messageAddr, 0x48);
json jMsg;
unsigned long long msgid = *(unsigned long long *)(messageAddr + 0x30);
jMsg["pid"] = GetCurrentProcessId();
jMsg["type"] = *(DWORD *)(messageAddr + 0x38);
jMsg["isSendMsg"] = *(BOOL *)(messageAddr + 0x3C);
jMsg["msgid"] = msgid;
jMsg["sender"] = unicode_to_utf8((wchar_t *)READ_WSTRING(messageAddr, 0x48).c_str());
int length = *(DWORD *)(messageAddr + 0x170 + 0x4);
if (length == 0)
{
message->wxid = message->sender;
}
else
{
message->wxid = READ_WSTRING(messageAddr, 0x170);
}
message->message = READ_WSTRING(messageAddr, 0x70);
message->filepath = READ_WSTRING(messageAddr, 0x1AC);
jMsg["wxid"] = length == 0 ? jMsg["sender"].get<std::string>() : unicode_to_utf8((wchar_t *)READ_WSTRING(messageAddr, 0x170).c_str());
jMsg["message"] = unicode_to_utf8((wchar_t *)READ_WSTRING(messageAddr, 0x70).c_str());
jMsg["filepath"] = unicode_to_utf8((wchar_t *)READ_WSTRING(messageAddr, 0x1AC).c_str());
string extrabuf = base64_encode((BYTE *)(*(DWORD *)(messageAddr + 0x8C)), *(DWORD *)(messageAddr + 0x8C + 0x4));
jMsg["extrainfo"] = extrabuf;
jMsg["time"] = unicode_to_utf8((wchar_t *)GetTimeW(*(DWORD *)(messageAddr + 0x44)).c_str());
string jstr = jMsg.dump() + '\n';
#ifdef USE_COM
// 通过连接点,将消息广播给客户端
map<wstring, _variant_t> msg_map;
msg_map[L"pid"] = message->pid;
msg_map[L"isSendMessage"] = isSendMessage;
msg_map[L"time"] = message->time.c_str();
msg_map[L"type"] = message->messagetype;
msg_map[L"msgid"] = message->msgid;
msg_map[L"sendto"] = message->sender.c_str();
msg_map[L"from"] = message->sender.c_str();
msg_map[L"wxid"] = message->wxid.c_str();
msg_map[L"message"] = message->message.c_str();
msg_map[L"filepath"] = message->filepath.c_str();
SAFEARRAY *psaValue = CreateMessageArray(msg_map);
VARIANT vsaValue;
vsaValue.vt = VT_ARRAY | VT_VARIANT;
V_ARRAY(&vsaValue) = psaValue;
PostComMessage(message->pid, WX_MESSAGE, message->msgid, &vsaValue);
VARIANT vsaValue = (_variant_t)jstr.c_str();
PostComMessage(jMsg["pid"].get<int>(), WX_MESSAGE, msgid, &vsaValue);
#endif
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SendSocketMessage, message, NULL, 0);
// 为保证线程安全,需要手动管理内存
SocketMessageStruct *sms = new SocketMessageStruct;
sms->buffer = new char[jstr.size() + 1];
memcpy(sms->buffer, jstr.c_str(), jstr.size() + 1);
sms->length = jstr.size();
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SendSocketMessageInThread, sms, NULL, 0);
if (hThread)
{
CloseHandle(hThread);
......
......@@ -2,6 +2,9 @@
#include <typeinfo>
#include <string>
#include <vector>
#include <map>
#include "json/json.hpp"
using namespace nlohmann;
// 获取好友信息CALL1偏移
#define GetUserInfoCall1Offset 0x100BD5C0 - 0x10000000
......@@ -34,50 +37,29 @@ struct GetUserInfoStruct
*/
static wstring WxUserInfo(DWORD address)
{
wstring wUserInfo = L"";
vector<DWORD> InfoType{
address + 0x10,
address + 0x24,
address + 0x38,
address + 0x58,
address + 0x6C,
address + 0xFC,
address + 0x110,
address + 0x19C,
address + 0x1B0,
address + 0x1C4,
address + 0x1D8,
address + 0x27C};
vector<wchar_t *> InfoTypeName{
(WCHAR *)L"\"wxId\"",
(WCHAR *)L"\"wxNumber\"",
(WCHAR *)L"\"wxV3\"",
(WCHAR *)L"\"wxRemark\"",
(WCHAR *)L"\"wxNickName\"",
(WCHAR *)L"\"wxBigAvatar\"",
(WCHAR *)L"\"wxSmallAvatar\"",
(WCHAR *)L"\"wxSignature\"",
(WCHAR *)L"\"wxNation\"",
(WCHAR *)L"\"wxProvince\"",
(WCHAR *)L"\"wxCity\"",
(WCHAR *)L"\"wxBackground\"",
};
wUserInfo += L"{";
for (unsigned int i = 0; i < InfoType.size(); i++)
json jData;
map<string, DWORD> key_addr_map;
key_addr_map["wxId"] = address + 0x10;
key_addr_map["wxNumber"] = address + 0x24;
key_addr_map["wxV3"] = address + 0x38;
key_addr_map["wxRemark"] = address + 0x58;
key_addr_map["wxNickName"] = address + 0x6C;
key_addr_map["wxBigAvatar"] = address + 0xFC;
key_addr_map["wxSmallAvatar"] = address + 0x110;
key_addr_map["wxSignature"] = address + 0x19C;
key_addr_map["wxNation"] = address + 0x1B0;
key_addr_map["wxProvince"] = address + 0x1C4;
key_addr_map["wxCity"] = address + 0x1D8;
key_addr_map["wxBackground"] = address + 0x27C;
for (auto it = key_addr_map.begin(); it != key_addr_map.end(); it++)
{
wchar_t *wstemp = ((*((DWORD *)InfoType[i])) != 0) ? (WCHAR *)(*((LPVOID *)InfoType[i])) : (WCHAR *)L"null";
wstring wsrtemp = wreplace(wstemp, L'\"', L"\\\"");
wUserInfo = wUserInfo + InfoTypeName[i] + L":\"" + wsrtemp + L"\"";
if (i != InfoType.size() - 1)
{
wUserInfo += L",";
}
string key = it->first;
DWORD addr = it->second;
wstring wstemp = ((*((DWORD *)addr)) != 0) ? (wstring)(WCHAR *)(*((LPVOID *)addr)) : L"null";
string value = unicode_to_utf8((wchar_t *)wstemp.c_str());
jData[key] = value;
}
wUserInfo += L"}";
#ifdef _DEBUG
wcout.imbue(locale("chs"));
wcout << wUserInfo.c_str() << endl;
#endif
wstring wUserInfo = utf8_to_unicode(jData.dump().c_str());
return wUserInfo;
}
......
#include "pch.h"
#include <vector>
#include "json/json.hpp"
#include <map>
using namespace nlohmann;
#define CheckLoginOffset 0x2366538
// 个人WXID偏移
......@@ -11,159 +13,141 @@
* length:selfinfo字符串长度
*/
#ifndef USE_SOCKET
struct SelfInfoStruct {
DWORD message;
DWORD length;
struct SelfInfoStruct
{
DWORD message;
DWORD length;
} ret;
#endif // !USE_SOCKET
/*
* 供外部调用的获取个人信息接口
* return:DWORD,ret的首地址
*/
#ifndef USE_SOCKET
DWORD GetSelfInfoRemote() {
ZeroMemory(&ret, sizeof(SelfInfoStruct));
wstring selfinfo = GetSelfInfo();
wchar_t* message = new wchar_t[selfinfo.length() + 1];
memcpy(message,selfinfo.c_str(),(selfinfo.length() + 1) * 2);
ret.message = (DWORD)message;
ret.length = selfinfo.length();
return (DWORD)&ret;
DWORD GetSelfInfoRemote()
{
ZeroMemory(&ret, sizeof(SelfInfoStruct));
wstring selfinfo = GetSelfInfo();
wchar_t *message = new wchar_t[selfinfo.length() + 1];
memcpy(message, selfinfo.c_str(), (selfinfo.length() + 1) * 2);
ret.message = (DWORD)message;
ret.length = selfinfo.length();
return (DWORD)&ret;
}
#endif
wstring GetSelfWxid() {
DWORD baseAddr = GetWeChatWinBase() + SelfWxidAddrOffset;
char wxidbuffer[0x100] = { 0 };
DWORD SelfWxIdAddr = 0x0;
sprintf_s(wxidbuffer, "%s", (char*)baseAddr);
if (strlen(wxidbuffer) < 0x6 || strlen(wxidbuffer) > 0x14)
{
SelfWxIdAddr = *(DWORD*)baseAddr;
}
else
{
SelfWxIdAddr = baseAddr;
}
if (SelfWxIdAddr == 0) {
return L"";
}
char* sselfwxid = (char*)SelfWxIdAddr;
wchar_t* wselfwxid = new wchar_t[strlen(sselfwxid) + 1];
MultiByteToWideChar(CP_ACP, 0, sselfwxid, -1, wselfwxid, strlen(sselfwxid) + 1);
wstring wxid(wselfwxid);
delete[] wselfwxid;
return wxid;
wstring GetSelfWxid()
{
DWORD baseAddr = GetWeChatWinBase() + SelfWxidAddrOffset;
char wxidbuffer[0x100] = {0};
DWORD SelfWxIdAddr = 0x0;
sprintf_s(wxidbuffer, "%s", (char *)baseAddr);
if (strlen(wxidbuffer) < 0x6 || strlen(wxidbuffer) > 0x14)
{
SelfWxIdAddr = *(DWORD *)baseAddr;
}
else
{
SelfWxIdAddr = baseAddr;
}
if (SelfWxIdAddr == 0)
{
return L"";
}
char *sselfwxid = (char *)SelfWxIdAddr;
wchar_t *wselfwxid = new wchar_t[strlen(sselfwxid) + 1];
MultiByteToWideChar(CP_ACP, 0, sselfwxid, -1, wselfwxid, strlen(sselfwxid) + 1);
wstring wxid(wselfwxid);
delete[] wselfwxid;
return wxid;
}
/*
* 获取个人信息
*/
wstring GetSelfInfo() {
wstring selfinfo = L"";
DWORD WeChatWinBase = GetWeChatWinBase();
vector<DWORD> SelfInfoAddr = {
WeChatWinBase + 0x236607C,
WeChatWinBase + 0x2366548,
WeChatWinBase + 0x23660F4,
WeChatWinBase + 0x23661F8,
*(DWORD*)(WeChatWinBase + 0x236622C),
*(DWORD*)(WeChatWinBase + 0x23A111C),
*(DWORD*)(WeChatWinBase + 0x23663D4),
WeChatWinBase + 0x23662E8,
WeChatWinBase + 0x23661FC,
WeChatWinBase + 0x2366214,
WeChatWinBase + 0x2366128
};
vector<wstring> SelfInfoKey = {
L"\"wxId\"",
L"\"wxNumber\"",
L"\"wxNickName\"",
L"\"Sex\"",
L"\"wxSignature\"",
L"\"wxBigAvatar\"",
L"\"wxSmallAvatar\"",
L"\"wxNation\"",
L"\"wxProvince\"",
L"\"wxCity\"",
L"\"PhoneNumber\""
};
selfinfo = selfinfo + L"{";
for (unsigned int i = 0; i < SelfInfoAddr.size(); i++) {
selfinfo = selfinfo + SelfInfoKey[i] + L":";
selfinfo = selfinfo + L"\"";
char* temp = NULL;
if (!SelfInfoKey[i].compare(L"\"wxNickName\"")) {
if (*(DWORD*)(SelfInfoAddr[i] + 0x14) == 0xF) {
temp = (*((DWORD*)SelfInfoAddr[i]) != 0) ? (char*)SelfInfoAddr[i] : (char*)"null";
}
else {
temp = (*((DWORD*)SelfInfoAddr[i]) != 0) ? (char*)(*(DWORD*)SelfInfoAddr[i]) : (char*)"null";
}
}
else if (!SelfInfoKey[i].compare(L"\"wxId\"")) {
char wxidbuffer[0x100] = { 0 };
sprintf_s(wxidbuffer, "%s", (char*)SelfInfoAddr[i]);
if (strlen(wxidbuffer) < 0x6 || strlen(wxidbuffer) > 0x14)
{
//新的微信号 微信ID用地址保存
temp = (char*)(*(DWORD*)SelfInfoAddr[i]);
}
else
{
temp = (char*)SelfInfoAddr[i];
}
}
else if (!SelfInfoKey[i].compare(L"\"Sex\"")) {
int sex = *(int*)SelfInfoAddr[i];
switch (sex) {
case 1: {
selfinfo = selfinfo + L"男\",";
break;
}
case 2: {
selfinfo = selfinfo + L"女\",";
break;
}
default: {
selfinfo = selfinfo + L"未知\",";
break;
}
}
continue;
}
else {
temp = (char*)SelfInfoAddr[i];
if (temp == NULL || strlen(temp) == 0) {
temp = (char*)"null";
}
}
wchar_t* wtemp = new wchar_t[strlen(temp) + 1];
ZeroMemory(wtemp, (strlen(temp) + 1) * 2);
MultiByteToWideChar(CP_UTF8, 0, temp, -1, wtemp, strlen(temp) + 1);
wstring wrtemp = wreplace(wtemp,L'\"',L"\\\"");
selfinfo = selfinfo + wrtemp;
selfinfo = selfinfo + L"\"";
if(i!= SelfInfoAddr.size() - 1)
selfinfo = selfinfo + L",";
delete[] wtemp;
wtemp = NULL;
}
selfinfo = selfinfo + L"}";
#ifdef _DEBUG
wcout.imbue(locale("chs"));
wcout << selfinfo << endl;
#endif
return selfinfo;
wstring GetSelfInfo()
{
json jData;
map<string, DWORD> self_info_addr;
DWORD WeChatWinBase = GetWeChatWinBase();
self_info_addr["wxId"] = WeChatWinBase + 0x236607C;
self_info_addr["wxNumber"] = WeChatWinBase + 0x2366548;
self_info_addr["wxNickName"] = WeChatWinBase + 0x23660F4;
self_info_addr["Sex"] = WeChatWinBase + 0x23661F8;
self_info_addr["wxSignature"] = *(DWORD *)(WeChatWinBase + 0x236622C);
self_info_addr["wxBigAvatar"] = *(DWORD *)(WeChatWinBase + 0x23A111C);
self_info_addr["wxSmallAvatar"] = *(DWORD *)(WeChatWinBase + 0x23663D4);
self_info_addr["wxNation"] = WeChatWinBase + 0x23662E8;
self_info_addr["wxProvince"] = WeChatWinBase + 0x23661FC;
self_info_addr["wxCity"] = WeChatWinBase + 0x2366214;
self_info_addr["PhoneNumber"] = WeChatWinBase + 0x2366128;
for (auto it = self_info_addr.begin(); it != self_info_addr.end(); it++)
{
string key = it->first;
DWORD addr = it->second;
string temp;
if (!key.compare("wxNickName"))
{
if (*(DWORD *)(addr + 0x14) == 0xF)
{
temp = (*((DWORD *)addr) != 0) ? string((char *)addr) : gb2312_to_utf8("null");
}
else
{
temp = (*((DWORD *)addr) != 0) ? string((char *)(*(DWORD *)addr)) : gb2312_to_utf8("null");
}
}
else if (!key.compare("wxId"))
{
char wxidbuffer[0x100] = {0};
sprintf_s(wxidbuffer, "%s", (char *)addr);
if (strlen(wxidbuffer) < 0x6 || strlen(wxidbuffer) > 0x14)
{
//新的微信号 微信ID用地址保存
temp = string((char *)(*(DWORD *)addr));
}
else
{
temp = string((char *)addr);
}
}
else if (!key.compare("Sex"))
{
int sex = *(int *)addr;
switch (sex)
{
case 1:
{
temp = gb2312_to_utf8("男");
break;
}
case 2:
{
temp = gb2312_to_utf8("女");
break;
}
default:
{
temp = gb2312_to_utf8("未知");
break;
}
}
}
else
{
temp = addr != 0 ? string((char *)addr) : gb2312_to_utf8("null");
}
jData[key] = temp.c_str();
}
wstring selfinfo = utf8_to_unicode(jData.dump().c_str());
return selfinfo;
}
BOOL isWxLogin() {
DWORD CheckLoginAddr = GetWeChatWinBase() + CheckLoginOffset;
return *(BOOL*)CheckLoginAddr;
BOOL isWxLogin()
{
DWORD CheckLoginAddr = GetWeChatWinBase() + CheckLoginOffset;
return *(BOOL *)CheckLoginAddr;
}
/*
......@@ -171,10 +155,12 @@ BOOL isWxLogin() {
* return:void
*/
#ifndef USE_SOCKET
VOID DeleteSelfInfoCacheRemote() {
if (ret.length) {
delete[] (wchar_t*)ret.message;
ZeroMemory(&ret, sizeof(SelfInfoStruct));
}
VOID DeleteSelfInfoCacheRemote()
{
if (ret.length)
{
delete[](wchar_t *) ret.message;
ZeroMemory(&ret, sizeof(SelfInfoStruct));
}
}
#endif
\ No newline at end of file
#endif
......@@ -8,7 +8,7 @@
Version: 2.rc.08 (release candidate)
Copyright (C) 2004-2017, 2020, 2021 René Nyffenegger
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
......@@ -28,7 +28,7 @@
3. This notice may not be removed or altered from any source distribution.
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
Ren¨¦ Nyffenegger rene.nyffenegger@adp-gmbh.ch
*/
......@@ -182,7 +182,7 @@ 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&
// decode(¡­) is templated so that it can be used with String = const std::string&
// or std::string_view (requires at least C++17)
//
......
......@@ -87,6 +87,23 @@ string utf8_to_gb2312(const char *strUTF8)
return strTemp;
}
string gb2312_to_utf8(const char *strGB2312)
{
int len = MultiByteToWideChar(CP_ACP, 0, strGB2312, -1, NULL, 0);
wchar_t *wszGBK = new wchar_t[len + 1];
memset(wszGBK, 0, len * 2 + 2);
MultiByteToWideChar(CP_ACP, 0, strGB2312, -1, wszGBK, len);
len = WideCharToMultiByte(CP_UTF8, 0, wszGBK, -1, NULL, 0, NULL, NULL);
char *szGBK = new char[len + 1];
memset(szGBK, 0, len + 1);
WideCharToMultiByte(CP_UTF8, 0, wszGBK, -1, szGBK, len, NULL, NULL);
string strTemp(szGBK);
delete[] szGBK;
delete[] wszGBK;
return strTemp;
}
/*
* 将UTF8编码数据转换为GBK编码
*/
......
......@@ -15,6 +15,7 @@
#include <string>
#include "wxdata.h"
#include "wxapi.h"
#include "base64/base64.h"
#endif //PCH_H
#ifdef USE_SOCKET
......
......@@ -39,6 +39,7 @@ BOOL CreateConsole(void);
DWORD GetWeChatWinBase();
string unicode_to_gb2312(wchar_t *wchar);
string utf8_to_gb2312(const char *strUTF8);
string gb2312_to_utf8(const char *strGB2312);
string unicode_to_utf8(wchar_t *wstr);
wstring utf8_to_unicode(const char *buffer);
void HookAnyAddress(DWORD dwHookAddr, LPVOID dwJmpAddress, char *originalRecieveCode);
......
......@@ -65,6 +65,7 @@ struct ReceiveMsgStruct
wstring message;
wstring filepath;
wstring time;
wstring extrainfo;
~ReceiveMsgStruct()
{
}
......
......@@ -28,7 +28,7 @@ json methods = {{"GET", HTTP_METHOD_GET}, {"POST", HTTP_METHOD_POST}};
#endif
#define STOI_S(str) (is_digit_number(str) ? stoi(str) : 0)
#define POST_PARAM(jData, key) utf8_to_unicode(string(jData[key]).c_str())
#define POST_PARAM(jData, key) utf8_to_unicode(jData[key].get<string>().c_str())
#define GET_PARAM(hm, name) getMgVarW(hm, name)
bool is_digit_number(string str)
......@@ -94,11 +94,11 @@ static int get_http_param_int(mg_http_message *hm, json jData, string key, int m
{
try
{
result = jData[key];
result = jData[key].get<int>();
}
catch (json::exception)
{
result = STOI_S((string)jData[key]);
result = STOI_S(jData[key].get<string>());
}
break;
}
......@@ -153,8 +153,13 @@ void request_event(mg_http_message *hm, string &ret)
}
case WECHAT_GET_SELF_INFO:
{
wstring self_info = GetSelfInfo();
json ret_data = {{"self_info", unicode_to_utf8(WS2LW(self_info))}, {"result", "OK"}};
json ret_data;
string self_info = unicode_to_utf8(WS2LW(GetSelfInfo()));
json j_info = json::parse(self_info.c_str(), self_info.c_str() + self_info.size(), nullptr, false);
if (j_info.is_discarded() != true)
ret_data = {{"data", j_info}, {"result", "OK"}};
else
ret_data = {{"data", self_info}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
......@@ -308,8 +313,13 @@ void request_event(mg_http_message *hm, string &ret)
case WECHAT_CONTACT_SEARCH_BY_CACHE:
{
wstring wxid = get_http_param_str(hm, jData, "wxid", method);
wstring userinfo = GetUserInfoByWxId(wxid);
json ret_data = {{"userinfo", unicode_to_utf8(WS2LW(userinfo))}, {"result", "OK"}};
string userinfo = unicode_to_utf8(WS2LW(GetUserInfoByWxId(wxid)));
json ret_data;
json j_info = json::parse(userinfo.c_str(), userinfo.c_str() + userinfo.size(), nullptr, false);
if (j_info.is_discarded() != true)
ret_data = {{"data", j_info}, {"result", "OK"}};
else
ret_data = {{"data", userinfo}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
......
......@@ -3,7 +3,6 @@
#include <signal.h>
// mongoose: https://github.com/cesanta/mongoose
#include "mongoose/mongoose.h"
#include "base64/base64.h"
#pragma comment(lib, "ws2_32.lib")
extern "C" __declspec(dllexport) void http_start(int port);
extern "C" __declspec(dllexport) int http_close();
......
......@@ -88,5 +88,5 @@ if __name__ == '__main__':
wx = WeChatRobot(pid_list[0])
wx.StartService()
wx.StartReceiveMessage()
wxRobot.start_socket_server()
wxRobot.register_msg_event(pid_list[0])
wx.StopService()
......@@ -6,9 +6,10 @@ Created on Thu Feb 24 16:19:48 2022
"""
# Before use,execute `CWeChatRobot.exe /regserver` in cmd by admin user
import ast
import os
import ctypes
import json
import base64
import ctypes.wintypes
import socketserver
import threading
......@@ -51,6 +52,8 @@ class WeChatEventSink:
"""
def OnGetMessageEvent(self, msg):
msg = json.loads(msg)
msg['extrainfo'] = base64.b64decode(msg['extrainfo'])
print(msg)
......@@ -58,65 +61,41 @@ class ReceiveMsgBaseServer(socketserver.BaseRequestHandler):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
class ReceiveMsgStruct(ctypes.Structure):
_fields_ = [("pid", ctypes.wintypes.DWORD),
("type", ctypes.wintypes.DWORD),
("isSendMsg", ctypes.wintypes.DWORD),
("msgid", ctypes.c_ulonglong),
("sender", ctypes.c_wchar * 80),
("wxid", ctypes.c_wchar * 80),
("message", ctypes.c_wchar * 0x1000B),
("filepath", ctypes.c_wchar * 260),
("time", ctypes.c_wchar * 30)
]
def handle(self):
conn = self.request
comtypes.CoInitialize()
while True:
try:
ptr_data = conn.recv(1024)
try:
if ptr_data.decode() == 'bye':
break
except UnicodeDecodeError:
pass
while len(ptr_data) < ctypes.sizeof(self.ReceiveMsgStruct):
ptr_data = b""
while True:
data = conn.recv(1024)
if len(data) == 0:
break
ptr_data += data
if ptr_data:
ptr_receive_msg = ctypes.cast(ptr_data, ctypes.POINTER(self.ReceiveMsgStruct))
ReceiveMsgBaseServer.msg_callback(ptr_receive_msg.contents)
response = "200 OK"
conn.sendall(response.encode())
if len(data) == 0 or data[-1] == 0xA:
break
msg = json.loads(ptr_data.decode('utf-8'))
ReceiveMsgBaseServer.msg_callback(msg)
except OSError:
break
except Exception as e:
print(e)
conn.sendall("200 OK".encode())
except json.JSONDecodeError:
pass
conn.sendall("200 OK".encode())
conn.close()
comtypes.CoUninitialize()
@staticmethod
def msg_callback(data):
def msg_callback(msg):
msg['extrainfo'] = base64.b64decode(msg['extrainfo'])
# 主线程中已经注入,此处禁止调用StartService和StopService
msg = {'pid': data.pid, 'time': data.time, 'type': data.type,
'isSendMsg': data.isSendMsg, 'msgid': data.msgid,
'wxid': data.wxid,
'sendto' if data.isSendMsg else 'from': data.sender,
'message': data.message}
robot = comtypes.client.CreateObject("WeChatRobot.CWeChatRobot")
event = comtypes.client.CreateObject("WeChatRobot.RobotEvent")
wx = WeChatRobot(data.pid, robot, event)
userinfo = wx.GetWxUserInfo(data.wxid)
wx = WeChatRobot(msg['pid'], robot, event)
userinfo = wx.GetWxUserInfo(msg['wxid'])
msg['alias'] = userinfo['wxNumber']
if data.isSendMsg == 0:
if '@chatroom' in data.sender:
chatroom_info = wx.GetWxUserInfo(data.sender)
if msg['isSendMsg'] == 0:
if '@chatroom' in msg['sender']:
chatroom_info = wx.GetWxUserInfo(msg['sender'])
msg['chatroom_name'] = chatroom_info['wxNickName']
msg['nickname'] = wx.GetChatRoomMemberNickname(data.sender, data.wxid)
msg['nickname'] = wx.GetChatRoomMemberNickname(msg['sender'], msg['wxid'])
else:
msg['nickname'] = userinfo['wxNickName']
# TODO: 在这里写额外的消息处理逻辑
......@@ -330,12 +309,8 @@ class WeChatRobot:
调用成功返回个人信息,否则返回空字典.
"""
self_info = self.robot.CGetSelfInfo(self.pid).replace('\n', '\\n')
try:
self_info = ast.literal_eval(self_info)
except SyntaxError:
return {}
return self_info
self_info = self.robot.CGetSelfInfo(self.pid)
return json.loads(self_info)
def StopService(self) -> int:
"""
......@@ -519,8 +494,8 @@ class WeChatRobot:
联系人信息.
"""
userinfo = self.robot.CGetWxUserInfo(self.pid, wxid).replace('\n', '\\n')
return ast.literal_eval(userinfo)
userinfo = self.robot.CGetWxUserInfo(self.pid, wxid)
return json.loads(userinfo)
def GetChatRoomMembers(self, chatroom_id: str) -> dict or None:
"""
......
......@@ -49,11 +49,11 @@ CWeChatRobot.exe /unregserver
```
# 调用
**Python:**
参考[wxRobot.py](/Python/wxRobot.py)
**C#:**
参考[ComWechatRobotCsharp](https://github.com/RingoStudio/ComWechatRobotCsharp),感谢@RingoStudio 的贡献
**易语言:**
参考[ESDK](/ESDK),感谢@lovezm 的贡献
参考[wxRobot.py](/Python/wxRobot.py)
**C#:**
参考[ComWechatRobotCsharp](https://github.com/RingoStudio/ComWechatRobotCsharp),感谢@RingoStudio 的贡献
**易语言:**
参考[ESDK](/ESDK),感谢@lovezm 的贡献
# 更多功能
1. 尝试添加issue中的功能
......@@ -119,11 +119,13 @@ CWeChatRobot.exe /unregserver
## 2022.08.13
1. 现在消息HOOK内容包含消息ID
2. 完成发送消息的http接口,可参考[wxDriver.py](/Release/socket/wxDriver.py),其他接口还需要一点时间
3. 新增项目配置文件,感谢@amchii 提供的方法
3. 新增项目配置文件,感谢@amchii 提供的方法
## 2022.08.21
1. 所有功能http接口封装完成,可接受get、post请求
2. 提供http接口调用示例,参考[wxDriver.py](/Release/socket/wxDriver.py)
1. 所有功能http接口封装完成,可接受get、post请求
2. 提供http接口调用示例,参考[wxDriver.py](/Release/socket/wxDriver.py)
## 2022.08.25
1. 接收消息格式修改为json,现在也可以获取到扩展信息,可从扩展信息中获取到文件保存路径或被艾特人wxid
2. 优化获取个人信息,获取好友信息接口
# 打赏作者
请给作者一个star,感谢感谢
......
......@@ -3,6 +3,7 @@ import json
import copy
import threading
import requests
import base64
import socketserver
if ctypes.sizeof(ctypes.c_void_p) == ctypes.sizeof(ctypes.c_ulonglong):
......@@ -190,47 +191,29 @@ class ReceiveMsgSocketServer(socketserver.BaseRequestHandler):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
class ReceiveMsgStruct(ctypes.Structure):
_fields_ = [("pid", ctypes.wintypes.DWORD),
("type", ctypes.wintypes.DWORD),
("isSendMsg", ctypes.wintypes.DWORD),
("msgid", ctypes.c_ulonglong),
("sender", ctypes.c_wchar * 80),
("wxid", ctypes.c_wchar * 80),
("message", ctypes.c_wchar * 0x1000B),
("filepath", ctypes.c_wchar * 260),
("time", ctypes.c_wchar * 30)
]
def handle(self):
conn = self.request
while True:
try:
ptr_data = conn.recv(1024)
try:
if ptr_data.decode() == 'bye': break
except UnicodeDecodeError:
pass
while len(ptr_data) < ctypes.sizeof(self.ReceiveMsgStruct):
ptr_data = b""
while True:
data = conn.recv(1024)
if len(data) == 0: break
ptr_data += data
if ptr_data:
ptr_receive_msg = ctypes.cast(ptr_data, ctypes.POINTER(self.ReceiveMsgStruct))
ReceiveMsgSocketServer.msg_callback(ptr_receive_msg.contents)
if len(data) == 0 or data[-1] == 0xA:
break
msg = json.loads(ptr_data.decode('utf-8'))
ReceiveMsgSocketServer.msg_callback(msg)
except OSError:
break
except:
except json.JSONDecodeError:
pass
conn.sendall("200 OK".encode())
conn.close()
@staticmethod
def msg_callback(data):
msg = {'pid': data.pid, 'time': data.time, 'type': data.type,
'isSendMsg': data.isSendMsg, 'msgid': data.msgid,
'wxid': data.wxid,'message': data.message,
'sendto' if data.isSendMsg else 'from': data.sender}
def msg_callback(msg):
# 附加信息是protobuf格式,需要自行处理
msg['extrainfo'] = base64.b64decode(msg['extrainfo'])
# TODO: 在这里写额外的消息处理逻辑
print(msg)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册