SendAtText.cpp 3.2 KB
Newer Older
L
ljc545w 已提交
1 2
#include "pch.h"

L
ljc545w 已提交
3
// 发送艾特消息CALL偏移
L
ljc545w 已提交
4
#define SendAtTextCallOffset 0x6782E7B0 - 0x67370000
L
ljc545w 已提交
5
// 清空缓存CALL偏移
L
ljc545w 已提交
6 7
#define DeleteAtTextCacheCallOffset 0x67404200 - 0x67370000

L
ljc545w 已提交
8 9 10 11 12 13 14
/*
* 外部调用时传递的参数结构
* chatroomid:群聊ID的保存地址
* wxidlist:艾特列表的保存地址,真实类型应当是`wchar_t**`
* wxmsg:发送的内容保存地址
* length:艾特的人数量,用于指示wxidlist长度
*/
L
ljc545w 已提交
15 16 17
struct SendAtTextStruct
{
    DWORD chatroomid;
L
ljc545w 已提交
18
    DWORD wxidlist;
L
ljc545w 已提交
19
    DWORD wxmsg;
20
    DWORD length;
L
ljc545w 已提交
21 22
};

L
ljc545w 已提交
23 24 25 26 27 28 29 30
/*
* 内存中使用的参数结构
* 构造与Release版本vector动态数组相仿
* 成员类型:`WxString`
* AtUser:类似`vector`的`data`方法,保存数组首个成员的地址
* addr_end1:数组尾地址
* addr_end2:数组尾地址
*/
L
ljc545w 已提交
31
struct AtStruct {
32
    DWORD AtUser;
L
ljc545w 已提交
33 34 35 36
    DWORD addr_end1;
    DWORD addr_end2;
};

L
ljc545w 已提交
37 38 39 40 41
/*
* 供外部调用的发送艾特消息接口
* lpParameter:SendAtTextStruct类型结构体指针
* return:void
*/
L
ljc545w 已提交
42 43 44 45
void SendAtTextRemote(LPVOID lpParameter) {
    SendAtTextStruct* rp = (SendAtTextStruct*)lpParameter;
    wchar_t* wsChatRoomId = (WCHAR*)rp->chatroomid;
    wchar_t* wsTextMsg = (WCHAR*)rp->wxmsg;
46 47 48
    if (rp->length == 0)
        return;
    else if(rp->length == 1)
L
ljc545w 已提交
49
        SendAtText(wsChatRoomId, (DWORD*)&rp->wxidlist, wsTextMsg,rp->length);
50
    else
L
ljc545w 已提交
51
        SendAtText(wsChatRoomId, (DWORD*)rp->wxidlist, wsTextMsg, rp->length);
L
ljc545w 已提交
52 53
}

L
ljc545w 已提交
54 55 56 57 58 59 60 61
/*
* 发送艾特消息的具体实现
* wsChatRoomId:群聊ID
* wsWxId:艾特的人列表
* wsTextMsg:发送的消息内容
* length:艾特的人数量
* return:void
*/
62
void __stdcall SendAtText(wchar_t* wsChatRoomId, DWORD wsWxId[], wchar_t* wsTextMsg,int length) {
L
ljc545w 已提交
63
    // +1的作用是补充一个空结构体,将`AtStruct`尾地址设定为空结构的首地址即可
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
    WxString* AtUsers = new WxString[length + 1];
    wstring AtMessage = L"";
    int querySuccess = 0;
    for (int i = 0; i < length; i++) {
        wchar_t* nickname = NULL;
        if (!lstrcmpW((wchar_t*)wsWxId[i], (wchar_t*)L"notify@all")) {
            nickname = (wchar_t*)L"所有人";
        }
        else
            nickname = GetUserNickNameByWxId((wchar_t*)wsWxId[i]);
        if (!nickname)
            continue;
        WxString temp = { 0 };
        temp.buffer = (wchar_t*)wsWxId[i];
        temp.length = wcslen((wchar_t*)wsWxId[i]);
        temp.maxLength = wcslen((wchar_t*)wsWxId[i]) * 2;
        memcpy(&AtUsers[querySuccess],&temp,sizeof(WxString));
        AtMessage = AtMessage + L"@" + nickname + L" ";
        querySuccess++;
    }
    AtMessage += wsTextMsg;
    if (!querySuccess)
L
ljc545w 已提交
86 87
        return;
    WxBaseStruct wxChatRoomId(wsChatRoomId);
88
    WxBaseStruct wxTextMsg((wchar_t*)AtMessage.c_str());
L
ljc545w 已提交
89
    AtStruct at = { 0 };
90 91 92
    at.AtUser = (DWORD)AtUsers;
    at.addr_end1 = (DWORD)&AtUsers[querySuccess];
    at.addr_end2 = (DWORD)&AtUsers[querySuccess];
L
ljc545w 已提交
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113

    wchar_t** pWxmsg = &wxTextMsg.buffer;
    char buffer[0x3B0] = { 0 };

    DWORD dllBaseAddress = GetWeChatWinBase();
    DWORD callAddress = dllBaseAddress + SendAtTextCallOffset;
    DWORD DeleteTextCacheCall = dllBaseAddress + DeleteAtTextCacheCallOffset;

    __asm {
        lea eax, at;
        push 0x1;
        push eax;
        mov edi, pWxmsg;
        push edi;
        lea edx, wxChatRoomId;
        lea ecx, buffer;
        call callAddress;
        add esp, 0xC;
        lea ecx, buffer;
        call DeleteTextCacheCall;
    }
114 115
    delete[] AtUsers;
    AtUsers = NULL;
L
ljc545w 已提交
116
}