#include "pch.h" #include #include #include #include #pragma comment(lib, "ws2_32.lib") using namespace std; #define CLTIP "127.0.0.1" // 接收消息的HOOK地址偏移 #define ReceiveMessageHookOffset 0x78BF0F4C - 0x786A0000 // 接收消息HOOK的CALL偏移 #define ReceiveMessageNextCallOffset 0x79136350 - 0x786A0000 // 发送消息的HOOK地址偏移 #define SendMessageHookOffset 0x78B88E42 - 0x786A0000 // 发送消息HOOK的CALL偏移 #define SendMessageNextCallOffset 0x78AA8170 - 0x786A0000 #define READ_WSTRING(addr, offset) wstring((wchar_t *)(*(DWORD *)(addr + offset)), *(DWORD *)(addr + offset + 0x4)) 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前的字节码,用于恢复 char OldReceiveMessageAsmCode[5] = {0}; char OldSendMessageAsmCode[5] = {0}; static DWORD WeChatWinBase = GetWeChatWinBase(); // 接收消息HOOK地址 static DWORD ReceiveMessageHookAddress = WeChatWinBase + ReceiveMessageHookOffset; // 接收消息HOOK的CALL地址 static DWORD ReceiveMessageNextCall = WeChatWinBase + ReceiveMessageNextCallOffset; // 接收HOOK的跳转地址 static DWORD ReceiveMessageJmpBackAddress = ReceiveMessageHookAddress + 0x5; // 发送消息HOOK地址 static DWORD SendMessageHookAddress = WeChatWinBase + SendMessageHookOffset; // 发送消息HOOK的CALL地址 static DWORD SendMessageNextCall = WeChatWinBase + SendMessageNextCallOffset; // 发送HOOK的跳转地址 static DWORD SendMessageJmpBackAddress = SendMessageHookAddress + 0x5; // 通过socket将消息发送给服务端 BOOL SendSocketMessage(ReceiveMsgStruct *ms) { shared_ptr shared_ms(ms); if (SRVPORT == 0) { return false; } SOCKET clientsocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (clientsocket < 0) { #ifdef _DEBUG cout << "create socket error," << " errno:" << errno << endl; #endif return false; } BOOL status = false; sockaddr_in clientAddr; memset(&clientAddr, 0, sizeof(clientAddr)); clientAddr.sin_family = AF_INET; clientAddr.sin_port = htons((u_short)SRVPORT); InetPtonA(AF_INET, CLTIP, &clientAddr.sin_addr.s_addr); if (connect(clientsocket, reinterpret_cast(&clientAddr), sizeof(sockaddr)) < 0) { #ifdef _DEBUG cout << "connect error," << " errno:" << errno << endl; #endif return false; } char recvbuf[1024] = {0}; auto sms = std::make_shared(); 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); if (ret == -1 || ret == 0) { #ifdef _DEBUG cout << "send fail," << " errno:" << errno << endl; #endif closesocket(clientsocket); return false; } memset(recvbuf, 0, sizeof(recvbuf)); ret = recv(clientsocket, recvbuf, sizeof(recvbuf), 0); closesocket(clientsocket); if (ret == -1 || ret == 0) { #ifdef _DEBUG cout << "the server close" << endl; #endif return false; } return true; } // 创建广播消息数组 #ifndef USE_SOCKET static SAFEARRAY *CreateMessageArray(map msg) { HRESULT hr = S_OK; SAFEARRAY *psaValue; vector 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; } #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); 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); #ifdef USE_COM // 通过连接点,将消息广播给客户端 map 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); #endif HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SendSocketMessage, message, NULL, 0); if (hThread) { CloseHandle(hThread); } } /* * 消息处理函数,根据消息缓冲区组装结构并存入容器 * messageAddr:保存消息的缓冲区地址 * return:void */ VOID ReceiveMessage(DWORD messagesAddr) { // 此处用于区别是发送的还是接收的消息 DWORD *messages = (DWORD *)messagesAddr; for (DWORD messageAddr = messages[0]; messageAddr < messages[1]; messageAddr += 0x298) { dealMessage(messageAddr); } } /* * HOOK的具体实现,接收到消息后调用处理函数 */ _declspec(naked) void dealReceiveMessage() { __asm { pushad; pushfd; push edi; call ReceiveMessage; add esp, 0x4; popfd; popad; call ReceiveMessageNextCall; jmp ReceiveMessageJmpBackAddress; } } /* * HOOK的具体实现,发送消息后调用处理函数 */ _declspec(naked) void dealSendMessage() { __asm { pushad; pushfd; push edi; call dealMessage; add esp, 0x4; popfd; popad; call SendMessageNextCall; jmp SendMessageJmpBackAddress; } } /* * 开始接收消息HOOK * return:void */ VOID HookReceiveMessage(int port) { SRVPORT = port; WeChatWinBase = GetWeChatWinBase(); if (ReceiveMessageHooked || !WeChatWinBase) return; ReceiveMessageHookAddress = WeChatWinBase + ReceiveMessageHookOffset; ReceiveMessageNextCall = WeChatWinBase + ReceiveMessageNextCallOffset; ReceiveMessageJmpBackAddress = ReceiveMessageHookAddress + 0x5; SendMessageHookAddress = WeChatWinBase + SendMessageHookOffset; SendMessageNextCall = WeChatWinBase + SendMessageNextCallOffset; SendMessageJmpBackAddress = SendMessageHookAddress + 0x5; HookAnyAddress(ReceiveMessageHookAddress, (LPVOID)dealReceiveMessage, OldReceiveMessageAsmCode); HookAnyAddress(SendMessageHookAddress, (LPVOID)dealSendMessage, OldSendMessageAsmCode); ReceiveMessageHooked = TRUE; } /* * 停止接收消息HOOK * return:void */ VOID UnHookReceiveMessage() { SRVPORT = 0; if (!ReceiveMessageHooked) return; UnHookAnyAddress(ReceiveMessageHookAddress, OldReceiveMessageAsmCode); UnHookAnyAddress(SendMessageHookAddress, OldSendMessageAsmCode); ReceiveMessageHooked = FALSE; }