diff --git a/DWeChatRobot/CheckFriendStatus.cpp b/DWeChatRobot/CheckFriendStatus.cpp index 1a4e6bb7c3135ac5a61fc46ae638501c9d7dcb3d..656cf0f30021570ff14de8657005c27e6b487beb 100644 --- a/DWeChatRobot/CheckFriendStatus.cpp +++ b/DWeChatRobot/CheckFriendStatus.cpp @@ -1,23 +1,38 @@ #include "pch.h" +// 检查好友状态CALL1偏移 #define CheckFriendStatusCall1Offset 0x78861210 - 0x787A0000 +// 检查好友状态CALL2偏移 #define CheckFriendStatusCall2Offset 0x03521CD0 - 0x02E20000 +// 检查好友状态CALL3偏移 #define CheckFriendStatusCall3Offset 0x03521DC0 - 0x02E20000 +// 检查好友状态CALL4偏移 #define CheckFriendStatusCall4Offset 0x0321FB90 - 0x02E20000 - +// 检查好友状态参数偏移 #define CheckFriendStatusParamOffset 0x0504F3BC - 0x02E20000 +// 好友状态码HOOK地址偏移 #define CheckFriendStatusHookOffset 0x5E0830B3 - 0x5DB60000 +// HOOK的CALL偏移 #define CheckFriendStatusNextCallOffset 0x5E083150 - 0x5DB60000 +// HOOK跳转的地址偏移 #define CheckFriendStatusHookJmpBackOffset 0x5E0830B8 - 0x5DB60000 +// HOOK的CALL地址 DWORD CheckFriendStatusNextCallAddress = GetWeChatWinBase() + CheckFriendStatusNextCallOffset; +// HOOK跳转的地址 DWORD CheckFriendStatusHookJmpBackAddress = GetWeChatWinBase() + CheckFriendStatusHookJmpBackOffset; +// 保存HOOK前的字节码,用于恢复 char OldAsmCode[5] = { 0 }; +// 是否HOOK标志 BOOL CheckFriendStatusHooked = false; +// 保存好友状态码并作为调用返回 DWORD LocalFriendStatus = 0x0; +/* +* 用于内存中平衡堆栈 +*/ struct FriendStatusParamStruct { DWORD fill0 = 0x0; DWORD fill1 = 0x0; @@ -28,12 +43,20 @@ struct FriendStatusParamStruct { char nullbuffer[0xC] = { 0 }; }; +/* +* 处理函数,参数不在状态码范围则不处理 +* result:好友状态码 +* return:void +*/ void dealVerifyUserResult(DWORD result) { if (result < 0xB0 || result > 0xB5) return; LocalFriendStatus = result; } +/* +* HOOK的具体实现,记录状态码并跳转到处理函数 +*/ __declspec(naked) void doHookVerifyUserResult() { __asm { pushfd; @@ -49,6 +72,10 @@ __declspec(naked) void doHookVerifyUserResult() { } } +/* +* 开始HOOK好友状态 +* return:void +*/ VOID HookFriendStatusCode(){ if (CheckFriendStatusHooked) return; @@ -58,6 +85,10 @@ VOID HookFriendStatusCode(){ CheckFriendStatusHooked = true; } +/* +* 取消HOOK好友状态 +* return:void +*/ VOID UnHookFriendStatusCode() { if (!CheckFriendStatusHooked) return; @@ -67,19 +98,37 @@ VOID UnHookFriendStatusCode() { CheckFriendStatusHooked = false; } +/* +* 供外部调用的检查好友状态接口1,启动HOOK +* return:void +*/ VOID CheckFriendStatusInitRemote() { HookFriendStatusCode(); } +/* +* 供外部调用的检查好友状态接口2,检查并返回状态码 +* lparameter:要检查的联系人wxid保存地址 +* return:DWORD,好友状态码 +*/ DWORD CheckFriendStatusRemote(LPVOID lparameter) { CheckFriendStatus((wchar_t*)lparameter); return LocalFriendStatus; } +/* +* 供外部调用的检查好友状态接口3,取消HOOK +* return:void +*/ VOID CheckFriendStatusFinishRemote() { UnHookFriendStatusCode(); } +/* +* 检查好友状态的具体实现 +* wxid:要检查的联系人wxid +* return:void +*/ VOID __stdcall CheckFriendStatus(wchar_t* wxid) { LocalFriendStatus = 0x0; DWORD WeChatWinBase = GetWeChatWinBase(); diff --git a/DWeChatRobot/DbBackup.cpp b/DWeChatRobot/DbBackup.cpp index ce389d3303937bcf06d90fad36588bfce5846b0a..abd032d3319faf99cc88607fc8aadf41ad0254ad 100644 --- a/DWeChatRobot/DbBackup.cpp +++ b/DWeChatRobot/DbBackup.cpp @@ -34,7 +34,6 @@ #define IDA_BASE 0x10000000 BOOL SQLite3_Backup_Init_Patched = FALSE; -DWORD lpAddressBackupDB = 0x0; typedef int(__cdecl* Sqlite3_open)(const char*, DWORD*); typedef DWORD(__cdecl* Sqlite3_backup_init)(DWORD, const char*, DWORD, const char*); @@ -50,6 +49,10 @@ DWORD OffsetFromIdaAddr(DWORD idaAddr) { return idaAddr - IDA_BASE; } +/* +* 数据库备份函数 +* return:int,无异常返回`0`,有异常返回非0值 +*/ int __cdecl backupDb( DWORD pDb, /* Database to back up */ const char* zFilename, /* Name of file to back up to */ @@ -102,6 +105,9 @@ int __cdecl backupDb( return rc; } +/* +* 绕过加密数据库备份限制 +*/ VOID PatchSQLite3_Backup_Init() { if (SQLite3_Backup_Init_Patched) return; @@ -118,6 +124,9 @@ VOID PatchSQLite3_Backup_Init() { return; } +/* +* 备份回调函数 +*/ void XProgress(int a, int b) { #ifdef _DEBUG @@ -126,6 +135,12 @@ void XProgress(int a, int b) return; } +/* +* 数据库在线备份入口 +* DbHandle:要备份的数据库句柄 +* BackupFile:备份保存位置 +* return:int,无异常返回`0`,有异常返回非0值 +*/ int BackupSQLiteDB(DWORD DbHandle,const char* BackupFile) { DWORD wxBaseAddress = GetWeChatWinBase(); @@ -163,7 +178,12 @@ int BackupSQLiteDB(DWORD DbHandle,const char* BackupFile) return rc; } -BOOL BackupSQLiteDBRemote(LPVOID lpParameter) { +/* +* 供外部调用的数据库在线备份接口 +* lpParameter:`BackupStruct`类型结构体指针 +* return:int,无异常返回`0`,有异常返回非0值 +*/ +int BackupSQLiteDBRemote(LPVOID lpParameter) { BackupStruct* param = (BackupStruct*)lpParameter; int rc = BackupSQLiteDB(param->DbHandle,(const char*)param->BackupFile); return rc; diff --git a/DWeChatRobot/DbBackup.h b/DWeChatRobot/DbBackup.h index 31f72e7f30e976872c2aea5e3a0158e24883cdc7..75296bbf7e59dd9666c7649a786f2d459b77eb8e 100644 --- a/DWeChatRobot/DbBackup.h +++ b/DWeChatRobot/DbBackup.h @@ -1,8 +1,13 @@ #pragma once #include +/* +* 外部调用时传递的参数类型 +* DbHandle:要备份的数据库句柄 +* BackupFile:备份的保存位置 +*/ struct BackupStruct { DWORD DbHandle; char* BackupFile; }; int BackupSQLiteDB(DWORD DbHandle, const char* BackupFile); -extern "C" __declspec(dllexport) BOOL BackupSQLiteDBRemote(LPVOID lpParameter); \ No newline at end of file +extern "C" __declspec(dllexport) int BackupSQLiteDBRemote(LPVOID lpParameter); \ No newline at end of file diff --git a/DWeChatRobot/DbExecuteSql.cpp b/DWeChatRobot/DbExecuteSql.cpp index 0dc94adba000394c3eb08511f7b1f192ef542096..a853e91097842627befffe7827677338ae7a384e 100644 --- a/DWeChatRobot/DbExecuteSql.cpp +++ b/DWeChatRobot/DbExecuteSql.cpp @@ -1,7 +1,9 @@ #include "pch.h" +// sqlite3_exec函数偏移 #define sqlite3_execOffset 0x66176570 - 0x64E20000 +// sqlite3_callback函数指针 typedef int(*sqlite3_callback)( void*, int, @@ -9,6 +11,7 @@ typedef int(*sqlite3_callback)( char** ); +// sqlite3_exec函数指针 typedef int(__cdecl* Sqlite3_exec)( DWORD, /* The database on which the SQL executes */ const char*, /* The SQL to be executed */ @@ -18,13 +21,24 @@ typedef int(__cdecl* Sqlite3_exec)( ); DWORD WeChatWinBase = GetWeChatWinBase(); +// sqlite3_exec函数地址 DWORD sqlite3_execAddr = WeChatWinBase + sqlite3_execOffset; +/* +* 外部调用时传递的参数结构 +* ptrDb:数据库句柄 +* ptrSql:保存sql的地址 +*/ struct executeParams { DWORD ptrDb; DWORD ptrSql; }; +/* +* 保存查询结果的结构 +* ColName:字段名;l_ColName:`ColName`字符数 +* content:字段值;l_content:`content`字符数 +*/ struct SQLResultStruct { char* ColName; DWORD l_ColName; @@ -32,14 +46,24 @@ struct SQLResultStruct { DWORD l_content; }; +/* +* 外部调用时的返回类型 +* SQLResultAddr:`SQLResult`首成员地址 +* length:查询结果条数 +*/ struct executeResult { DWORD SQLResultAddr; DWORD length; }; +// 外部调用时的具体返回对象 executeResult result = { 0 }; +// 保存查询结果的二维动态数组 vector > SQLResult; +/* +* 获取数据库信息的回调函数 +*/ int GetDbInfo(void* data,int argc,char** argv,char** azColName) { DbInfoStruct* pdata = (DbInfoStruct*)data; TableInfoStruct tb = { 0 }; @@ -84,6 +108,9 @@ int GetDbInfo(void* data,int argc,char** argv,char** azColName) { return 0; } +/* +* DLL内部查询用的回调函数,直接显示查询结果,用处不大 +*/ int query(void* data, int argc, char** argv, char** azColName) { for (int i = 0; i < argc; i++) { string content = argv[i] ? UTF8ToGBK(argv[i]) : "NULL"; @@ -93,6 +120,10 @@ int query(void* data, int argc, char** argv, char** azColName) { return 0; } +/* +* 外部调用时使用的回调函数,将结果存入`SQLResult`中 +* return:int,执行成功返回`0`,执行失败返回非0值 +*/ int select(void* data, int argc, char** argv, char** azColName) { executeResult* pdata = (executeResult*)data; vector tempStruct; @@ -118,6 +149,10 @@ int select(void* data, int argc, char** argv, char** azColName) { return 0; } +/* +* 清空查询结果,释放内存 +* return:void +*/ void ClearResultArray() { if (SQLResult.size() == 0) return; @@ -140,12 +175,25 @@ void ClearResultArray() { result.length = 0; } +/* +* 执行SQL的入口函数 +* ptrDb:数据库句柄 +* sql:要执行的SQL +* callback:回调函数地址 +* data:传递给回调函数的参数 +* return:BOOL,执行成功返回`1`,执行失败返回`0` +*/ BOOL ExecuteSQL(DWORD ptrDb,const char* sql,DWORD callback,void* data) { Sqlite3_exec p_Sqlite3_exec = (Sqlite3_exec)sqlite3_execAddr; int status = p_Sqlite3_exec(ptrDb,sql, (sqlite3_callback)callback,data,0); return status == 0; } +/* +* 供外部调用的执行SQL接口 +* lpParameter:`executeParams`类型结构体指针 +* return:DWORD,如果SQL执行成功,返回`SQLResult`首成员地址,否则返回0 +*/ DWORD ExecuteSQLRemote(LPVOID lpParameter){ ClearResultArray(); executeParams* sqlparam = (executeParams*)lpParameter; diff --git a/DWeChatRobot/DbExecuteSql.h b/DWeChatRobot/DbExecuteSql.h index dad14b01a4e149f2fed45175824075a33b29abb3..0e8ed1992767086b9dec8e7f923ddf6663dc624a 100644 --- a/DWeChatRobot/DbExecuteSql.h +++ b/DWeChatRobot/DbExecuteSql.h @@ -6,4 +6,4 @@ int select(void* data, int argc, char** argv, char** azColName); int query(void* data, int argc, char** argv, char** azColName); extern "C" __declspec(dllexport) DWORD ExecuteSQLRemote(LPVOID lpParameter); -BOOL ExecuteSQL(DWORD ptrDb, const char* sql, DWORD callback, void* data); +BOOL ExecuteSQL(DWORD ptrDb, const char* sql, DWORD callback, void* data); \ No newline at end of file diff --git a/DWeChatRobot/FriendList.cpp b/DWeChatRobot/FriendList.cpp index a01c294df2587e023ea124153326690ad87170e6..8c9444257bde9432d5666ce7662ca32fb1befbfe 100644 --- a/DWeChatRobot/FriendList.cpp +++ b/DWeChatRobot/FriendList.cpp @@ -1,9 +1,17 @@ #include "pch.h" #include -using namespace std; -#define LeftTreeOffset 0x222F3BC +// 通讯录左树偏移 +#define LeftTreeOffset 0x222F3BC +/* +* 保存单个好友信息的结构体 +* wxIdAddr:wxid保存地址 +* wxNumberAddr:微信号保存地址 +* wxNickNameAddr:昵称保存地址 +* wxRemarkAddr:备注保存地址 +* WxFriendStructW:默认构造函数 +*/ struct WxFriendStructW { DWORD wxIdAddr; DWORD wxNumberAddr; @@ -17,8 +25,13 @@ struct WxFriendStructW { } }; +// 保存所有好友信息的动态数组 vector WxFriendList; +/* +* 供外部调用的获取好友列表接口1 +* return:int,联系人数量 +*/ int GetFriendListInit() { GetFriendList(); #ifdef _DEBUG @@ -27,6 +40,10 @@ int GetFriendListInit() { return WxFriendList.size(); } +/* +* 供外部调用的获取好友列表接口2 +* return:DWORD,WxFriendList第一个成员地址 +*/ DWORD GetFriendListRemote() { if (WxFriendList.size() == 0) return 0; @@ -37,11 +54,19 @@ DWORD GetFriendListRemote() { return (DWORD)&WxFriendList[0].wxIdAddr; } +/* +* 供外部调用的获取好友列表接口3,清空缓存 +* return:void +*/ void GetFriendListFinish() { WxFriendList.clear(); cout << WxFriendList.size() << endl; } +/* +* 获取好友列表的具体实现 +* return:void +*/ void __stdcall GetFriendList() { #ifdef _DEBUG wcout.imbue(locale("chs")); diff --git a/DWeChatRobot/GetChatRoomMemebers.cpp b/DWeChatRobot/GetChatRoomMemebers.cpp index 9f9fbb87081038e9c978f9ab87d78f9414ec61bb..77ed2c66a2eeb84f3959491316cb80b674ca4f25 100644 --- a/DWeChatRobot/GetChatRoomMemebers.cpp +++ b/DWeChatRobot/GetChatRoomMemebers.cpp @@ -1,17 +1,34 @@ #include "pch.h" +// 获取群成员CALL1偏移 #define GetChatRoomMembersCall1Offset 0x6246BBB0 - 0x61E20000 +// 获取群成员CALL2偏移 #define GetChatRoomMembersCall2Offset 0x61EDF550 - 0x61E20000 +// 获取群成员CALL3偏移 #define GetChatRoomMembersCall3Offset 0x622046D0 - 0x61E20000 +// 清空缓存CALL偏移 #define DeleteGetChatRoomMembersCacheCallOffset 0x6246BDD0 - 0x61E20000 +/* +* 外部调用的返回类型 +* members:群成员wxid字符串,以`^`分隔 +* length:members字符串长度 +*/ struct ChatRoomInfoStruct { wchar_t* members = NULL; DWORD length = 0; }; +/* +* 外部调用时的具体返回对象 +*/ ChatRoomInfoStruct chatroominfo = { 0 }; +/* +* 供外部调用的获取群成员列表接口 +* lparameter:保存群聊ID的地址 +* return:DWORD,调用成功且群成员数量不为0,返回`chatroominfo`首地址,否则返回0 +*/ DWORD GetChatRoomMembersRemote(LPVOID lparameter) { wchar_t* chatroomid = (WCHAR*)lparameter; if (chatroominfo.members != NULL) { @@ -31,6 +48,11 @@ DWORD GetChatRoomMembersRemote(LPVOID lparameter) { return 0; } +/* +* 获取群成员列表的具体实现 +* chatroomid:群聊ID +* return:BOOL,成功返回`1`,失败返回`0` +*/ BOOL __stdcall GetChatRoomMembers(wchar_t* chatroomid) { DWORD WeChatWinBase = GetWeChatWinBase(); DWORD GetChatRoomMembersCall1 = WeChatWinBase + GetChatRoomMembersCall1Offset; diff --git a/DWeChatRobot/GetDbHandles.cpp b/DWeChatRobot/GetDbHandles.cpp index b19647c69a3cbeeb7cef7680682f4f49d7515423..adcd67813d3690e1cb5b453cf261674d20a95b2e 100644 --- a/DWeChatRobot/GetDbHandles.cpp +++ b/DWeChatRobot/GetDbHandles.cpp @@ -1,12 +1,18 @@ #include "pch.h" -// 联系人相关库 +// 联系人相关库偏移 #define SqlHandleMicroMsgOffset 0x222F3FC -// 公众号相关库 +// 公众号相关库偏移 #define SqlHandlePublicMsgOffset 0x22553D0 +// 保存数据库信息的容器 vector dbs; +/* +* 根据数据库名从`dbs`中检索数据库句柄 +* dbname:数据库名 +* return:DWORD,如果检索成功,返回数据库句柄,否则返回`0` +*/ DWORD GetDbHandleByDbName(wchar_t* dbname) { if (dbs.size() == 0) GetDbHandles(); @@ -17,12 +23,20 @@ DWORD GetDbHandleByDbName(wchar_t* dbname) { return 0; } +/* +* 供外部调用的获取数据库信息接口 +* return:DWORD,`dbs`首个成员地址 +*/ DWORD GetDbHandlesRemote() { if (dbs.size() == 0) GetDbHandles(); return (DWORD)dbs.data() ; } +/* +* 获取数据库信息的具体实现 +* return:void +*/ void GetDbHandles() { dbs.clear(); DWORD WeChatWinBase = GetWeChatWinBase(); diff --git a/DWeChatRobot/GetDbHandles.h b/DWeChatRobot/GetDbHandles.h index 10d7a0e7ad1d2024799d6de6c8520963362f94f8..6698747eb88b84e3f8fb35f3dc2c249638a0204c 100644 --- a/DWeChatRobot/GetDbHandles.h +++ b/DWeChatRobot/GetDbHandles.h @@ -2,6 +2,13 @@ #include #include +/* +* 保存数据库单个表信息的结构体 +* name:表名;l_name:`name`字符数 +* tbl_name:表名;l_tbl_name:`tbl_name`字符数 +* sql:建表语句;l_sql:`sql`字符数 +* rootpage:表编号;l_rootpage:`rootpage`字符数 +*/ struct TableInfoStruct { char* name; DWORD l_name; @@ -13,6 +20,14 @@ struct TableInfoStruct { DWORD l_rootpage; }; +/* +* 保存数据库信息的结构体 +* handle:数据库句柄 +* dbname:数据库名 +* l_dbname:`dbname`字符数 +* tables:保存库中所有表信息的容器 +* count:库中表的数量 +*/ struct DbInfoStruct { DWORD handle; wchar_t* dbname; diff --git a/DWeChatRobot/LogMsgInfo.cpp b/DWeChatRobot/LogMsgInfo.cpp index 0391983dd92169d5105d7f6f1ce20e0624b05556..ce37a4dde1f0d6968453ada47603c33da8a90255 100644 --- a/DWeChatRobot/LogMsgInfo.cpp +++ b/DWeChatRobot/LogMsgInfo.cpp @@ -1,16 +1,29 @@ #include "pch.h" +// 微信日志HOOK地址偏移 #define HookLogMsgInfoAddrOffset 0x103408A4 - 0x0FC40000 +// HOOK的CALL偏移 #define HookLogMsgInfoNextCallOffset 0x11586DFC - 0x0FC40000 +// HOOK的跳转地址偏移 #define HookLogMsgJmpBackOffset 0x103408A9 - 0x0FC40000 +// 微信日志HOOK地址 DWORD HookLogMsgInfoAddr = GetWeChatWinBase() + HookLogMsgInfoAddrOffset; +// HOOK的CALL地址 DWORD NextCallAddr = GetWeChatWinBase() + HookLogMsgInfoNextCallOffset; +// HOOK的跳转地址 DWORD JmpBackAddr = GetWeChatWinBase() + HookLogMsgJmpBackOffset; +// 是否开启日志HOOK标志 BOOL LogMsgHooked = false; +// 保存HOOK前的指令用于恢复 char LogOldAsmCode[5] = { 0 }; +/* +* 处理函数,打印日志信息 +* msg:日志信息 +* return:void +*/ VOID PrintMsg(DWORD msg) { if (!msg) return; @@ -19,6 +32,9 @@ VOID PrintMsg(DWORD msg) { return; } +/* +* HOOK的具体实现,拦截日志并调用处理函数 +*/ __declspec(naked) void doprintmsg(){ __asm { pushad; @@ -33,6 +49,10 @@ __declspec(naked) void doprintmsg(){ } } +/* +* 开始HOOK微信日志 +* return:void +*/ VOID HookLogMsgInfo() { if (LogMsgHooked) return; @@ -40,6 +60,10 @@ VOID HookLogMsgInfo() { LogMsgHooked = true; } +/* +* 停止HOOK微信日志 +* return:void +*/ VOID UnHookLogMsgInfo() { if (!LogMsgHooked) return; diff --git a/DWeChatRobot/ReceiveMessage.cpp b/DWeChatRobot/ReceiveMessage.cpp index da95bd7c1048a5a4e4ad6ad1d03752d76de09406..d079c911eb3f2c85e3ff58d2b12ede7ae196f8b1 100644 --- a/DWeChatRobot/ReceiveMessage.cpp +++ b/DWeChatRobot/ReceiveMessage.cpp @@ -1,9 +1,19 @@ #include "pch.h" #include +// 接收消息的HOOK地址偏移 #define ReceiveMessageHookOffset 0x034A4F60 - 0x02FE0000 +// HOOK的CALL偏移 #define ReceiveMessageNextCallOffset 0x034A0CE0 - 0x02FE0000 +/* +* 保存单条信息的结构 +* messagetype:消息类型 +* sender:发送者wxid;l_sender:`sender`字符数 +* wxid:如果sender是群聊id,则此成员保存具体发送人wxid,否则与`sender`一致;l_wxid:`wxid`字符数 +* message:消息内容,非文本消息是xml格式;l_message:`message`字符数 +* filepath:图片、文件及其他资源的保存路径;l_filepath:`filepath`字符数 +*/ struct messageStruct { DWORD messagetype; wchar_t* sender; @@ -16,16 +26,27 @@ struct messageStruct { DWORD l_filepath; }; +// 保存多条信息的动态数组 vector messageVector; +// 是否开启接收消息HOOK标志 BOOL ReceiveMessageHooked = false; +// 保存HOOK前的字节码,用于恢复 char OldReceiveMessageAsmCode[5] = { 0 }; - +// 接收消息HOOK地址 DWORD ReceiveMessageHookAddress = GetWeChatWinBase() + ReceiveMessageHookOffset; +// HOOK的CALL地址 DWORD ReceiveMessageNextCall = GetWeChatWinBase() + ReceiveMessageNextCallOffset; +// HOOK的跳转地址 DWORD JmpBackAddress = ReceiveMessageHookAddress + 0x5; +/* +* 消息处理函数,根据消息缓冲区组装结构并存入容器 +* messageAddr:保存消息的缓冲区地址 +* return:void +*/ VOID ReceiveMessage(DWORD messageAddr) { + // 此处用于区别是发送的还是接收的消息,发送的消息会被过滤 DWORD isSendMessage = *(DWORD*)(messageAddr + 0x3C); if (isSendMessage) return; @@ -67,12 +88,20 @@ VOID ReceiveMessage(DWORD messageAddr) { messageVector.push_back(message); } +/* +* 供外部调用的获取消息接口,优先返回较早消息 +* return:DWORD,messageVector第一个成员地址 +*/ DWORD GetHeadMessage() { if (messageVector.size() == 0) return 0; return (DWORD)&messageVector[0].messagetype; } +/* +* 供外部调用的删除消息接口,用于删除messageVector第一个成员,每读一条需要执行一次 +* return:void +*/ VOID PopHeadMessage() { if (messageVector.size() == 0) return; @@ -88,6 +117,9 @@ VOID PopHeadMessage() { messageVector.erase(k); } +/* +* HOOK的具体实现,接收到消息后调用处理函数 +*/ _declspec(naked) void dealReceiveMessage() { __asm { pushad; @@ -103,6 +135,10 @@ _declspec(naked) void dealReceiveMessage() { } } +/* +* 开始接收消息HOOK +* return:void +*/ VOID HookReceiveMessage() { if (ReceiveMessageHooked) return; @@ -110,6 +146,10 @@ VOID HookReceiveMessage() { ReceiveMessageHooked = TRUE; } +/* +* 停止接收消息HOOK +* return:void +*/ VOID UnHookReceiveMessage() { if (!ReceiveMessageHooked) return; diff --git a/DWeChatRobot/SelfInfo.cpp b/DWeChatRobot/SelfInfo.cpp index 801b3cd3e05ed55877e23057690960b51a1f3f59..b5942d65151785326029beec1e2c173b4cd7114f 100644 --- a/DWeChatRobot/SelfInfo.cpp +++ b/DWeChatRobot/SelfInfo.cpp @@ -1,14 +1,23 @@ #include "pch.h" #include +// 保存个人信息的字符串 wstring selfinfo = L""; +/* +* 外部调用时的返回类型 +* message:selfinfo.c_str() +* length:selfinfo字符串长度 +*/ struct SelfInfoStruct { DWORD message; DWORD length; } ret; - +/* +* 供外部调用的获取个人信息接口 +* return:DWORD,ret的首地址 +*/ DWORD GetSelfInfoRemote() { DWORD WeChatWinBase = GetWeChatWinBase(); vector SelfInfoAddr = { @@ -90,6 +99,10 @@ DWORD GetSelfInfoRemote() { return (DWORD)&ret; } +/* +* 删除个人信息缓存 +* return:void +*/ VOID DeleteSelfInfoCacheRemote() { if (ret.length) { ZeroMemory((wchar_t*)ret.message, ret.length*2 + 2); diff --git a/DWeChatRobot/SendArticle.cpp b/DWeChatRobot/SendArticle.cpp index 54132ba9c3e6642a9be702597a12abedf1aa7d39..072b4b9740d26a9a63f4aa12fb704bb85ee700d0 100644 --- a/DWeChatRobot/SendArticle.cpp +++ b/DWeChatRobot/SendArticle.cpp @@ -1,14 +1,28 @@ #include "pch.h" +// 发送文章CALL1偏移 #define SendArticleCall1Offset 0x0F7454F0 - 0x0F6B0000 +// 发送文章CALL2偏移 #define SendArticleCall2Offset 0x0FA41F80 - 0x0F6B0000 +// 发送文章CALL3偏移 #define SendArticleCall3Offset 0x0F7794A0 - 0x0F6B0000 +// 发送文章CALL4偏移 #define SendArticleCall4Offset 0x0FA42150 - 0x0F6B0000 +// 发送文章CALL参数偏移 #define SendArticleParamOffset 0x118EEC34 - 0x0F6B0000 +// 清空缓存CALL1偏移 #define SendArticleClearCacheCall1Offset 0x0FCEB4F0 - 0x0F6B0000 +// 清空缓存CALL2偏移 #define SendArticleClearCacheCall2Offset 0x0F744200 - 0x0F6B0000 +/* +* 外部调用时传递的参数结构 +* wxid:接收人的保存地址 +* title:文章标题的保存地址 +* abstract:文章摘要的保存地址 +* url:文章链接的保存地址 +*/ struct SendArticleStruct { DWORD wxid; DWORD title; @@ -16,6 +30,11 @@ struct SendArticleStruct { DWORD url; }; +/* +* 供外部调用的发送文章消息接口 +* lparameter:SendArticleStruct类型结构体指针 +* return:void +*/ VOID SendArticleRemote(LPVOID lparameter) { SendArticleStruct* sas = (SendArticleStruct*)lparameter; wchar_t* wxid = (wchar_t*)sas->wxid; @@ -25,6 +44,10 @@ VOID SendArticleRemote(LPVOID lparameter) { SendArticle(wxid,title,abstract,url); } +/* +* 获取自己的wxid保存地址 +* return:DWORD,个人wxid保存地址 +*/ DWORD GetSelfWxIdAddr() { DWORD baseAddr = GetWeChatWinBase() + 0x222EB3C; char wxidbuffer[0x100] = { 0 }; @@ -41,6 +64,14 @@ DWORD GetSelfWxIdAddr() { return SelfWxIdAddr; } +/* +* 发送文章消息的具体实现 +* wxid:消息接收人wxid +* title:文章标题 +* abstract:文章摘要 +* url:文章链接 +* return:BOOL,成功返回`1`,失败返回`0` +*/ BOOL __stdcall SendArticle(wchar_t* wxid,wchar_t* title, wchar_t* abstract, wchar_t* url) { DWORD WeChatWinBase = GetWeChatWinBase(); DWORD SendArticleCall1 = WeChatWinBase + SendArticleCall1Offset; diff --git a/DWeChatRobot/SendAtText.cpp b/DWeChatRobot/SendAtText.cpp index 1ec98b9a7f973419d717edfa9028717a000c2251..b9bfed3ccff597c15fbeebb739b1cae957956533 100644 --- a/DWeChatRobot/SendAtText.cpp +++ b/DWeChatRobot/SendAtText.cpp @@ -1,22 +1,44 @@ #include "pch.h" +// 发送艾特消息CALL偏移 #define SendAtTextCallOffset 0x6782E7B0 - 0x67370000 +// 清空缓存CALL偏移 #define DeleteAtTextCacheCallOffset 0x67404200 - 0x67370000 +/* +* 外部调用时传递的参数结构 +* chatroomid:群聊ID的保存地址 +* wxidlist:艾特列表的保存地址,真实类型应当是`wchar_t**` +* wxmsg:发送的内容保存地址 +* length:艾特的人数量,用于指示wxidlist长度 +*/ struct SendAtTextStruct { DWORD chatroomid; - DWORD wxid; + DWORD wxidlist; DWORD wxmsg; DWORD length; }; +/* +* 内存中使用的参数结构 +* 构造与Release版本vector动态数组相仿 +* 成员类型:`WxString` +* AtUser:类似`vector`的`data`方法,保存数组首个成员的地址 +* addr_end1:数组尾地址 +* addr_end2:数组尾地址 +*/ struct AtStruct { DWORD AtUser; DWORD addr_end1; DWORD addr_end2; }; +/* +* 供外部调用的发送艾特消息接口 +* lpParameter:SendAtTextStruct类型结构体指针 +* return:void +*/ void SendAtTextRemote(LPVOID lpParameter) { SendAtTextStruct* rp = (SendAtTextStruct*)lpParameter; wchar_t* wsChatRoomId = (WCHAR*)rp->chatroomid; @@ -24,12 +46,21 @@ void SendAtTextRemote(LPVOID lpParameter) { if (rp->length == 0) return; else if(rp->length == 1) - SendAtText(wsChatRoomId, (DWORD*)&rp->wxid, wsTextMsg,rp->length); + SendAtText(wsChatRoomId, (DWORD*)&rp->wxidlist, wsTextMsg,rp->length); else - SendAtText(wsChatRoomId, (DWORD*)rp->wxid, wsTextMsg, rp->length); + SendAtText(wsChatRoomId, (DWORD*)rp->wxidlist, wsTextMsg, rp->length); } +/* +* 发送艾特消息的具体实现 +* wsChatRoomId:群聊ID +* wsWxId:艾特的人列表 +* wsTextMsg:发送的消息内容 +* length:艾特的人数量 +* return:void +*/ void __stdcall SendAtText(wchar_t* wsChatRoomId, DWORD wsWxId[], wchar_t* wsTextMsg,int length) { + // +1的作用是补充一个空结构体,将`AtStruct`尾地址设定为空结构的首地址即可 WxString* AtUsers = new WxString[length + 1]; wstring AtMessage = L""; int querySuccess = 0; diff --git a/DWeChatRobot/SendCard.cpp b/DWeChatRobot/SendCard.cpp index 76d37dbccc943e55df7e9249e763f953f904cafc..415ca4b1479eb2fe63e1d07649a15780b2ae6732 100644 --- a/DWeChatRobot/SendCard.cpp +++ b/DWeChatRobot/SendCard.cpp @@ -1,14 +1,27 @@ #include "pch.h" +// 发送名片的CALL偏移 #define SendCardCallOffset 0x644FE7B0 - 0x64040000 +// 清空缓存的CALL偏移 #define DeleteCardCacheCallOffset 0x640D4200 - 0x64040000 +/* +* 外部调用时提供的参数结构 +* receiver:名片消息接收人wxid保存地址 +* sharedwxid:被推荐人的wxid保存地址 +* nickname:名片显示的昵称保存地址 +*/ struct SendCardStruct { DWORD receiver; DWORD sharedwxid; DWORD nickname; }; +/* +* 供外部调用的发送名片接口 +* lparameter:SendCardStruct类型结构体指针 +* return:void +*/ VOID SendCardRemote(LPVOID lparameter) { SendCardStruct* scs = (SendCardStruct*)lparameter; wchar_t* receiver = (WCHAR*)scs->receiver; @@ -17,6 +30,13 @@ VOID SendCardRemote(LPVOID lparameter) { SendCard(receiver,sharedwxid,nickname); } +/* +* 发送名片消息的具体实现 +* receiver:消息接收人wxid +* sharedwxid:被推荐人wxid +* nickname:名片显示的昵称 +* return:BOOL,发送成功返回`0`,发送失败返回`1` +*/ BOOL __stdcall SendCard(wchar_t* receiver, wchar_t* sharedwxid, wchar_t* nickname) { DWORD WeChatWinBase = GetWeChatWinBase(); DWORD SendCardCall = WeChatWinBase + SendCardCallOffset; diff --git a/DWeChatRobot/SendFile.cpp b/DWeChatRobot/SendFile.cpp index e78d0939c2ddba3c557d280e5992396ba2e81d89..1ef04b6d44db4ca1148b91d50a76ce8d6327eff2 100644 --- a/DWeChatRobot/SendFile.cpp +++ b/DWeChatRobot/SendFile.cpp @@ -1,18 +1,37 @@ #include "pch.h" +// 发送文件CALL1偏移 #define SendFileCall1Offset (0x67A71DC0 - 0x67370000) +// 发送文件CALL2偏移 #define SendFileCall2Offset (0x68D81C83 - 0x67370000) +// 发送文件CALL3偏移 #define SendFileCall3Offset (0x68D8047A - 0x67370000) +// 发送文件CALL4偏移 #define SendFileCall4Offset (0x67702260 - 0x67370000) +// 发送文件参数偏移 #define SendFileParamsOffset (0x6959F170 - 0x67370000) - +// 清空缓存CALL偏移 #define DeleteSendFileCacheCallOffset (0x67404200 - 0x67370000) +/* +* 外部调用时传递的参数结构 +* wxid:wxid的保存地址 +* filepath:文件绝对路径的保存地址 +*/ struct FileParamStruct { DWORD wxid; DWORD filepath; }; +/* +* 内存中使用的参数结构 +* type:消息类型,文件消息为3 +* buffer:文件绝对路径 +* length:绝对路径字符数 +* maxLength:绝对路径最大字节数 +* fill:占位用空缓冲区 +* WxFileStruct:默认构造函数 +*/ struct WxFileStruct { int type = 3; wchar_t* buffer; @@ -27,11 +46,22 @@ struct WxFileStruct { } }; +/* +* 供外部调用的发送文件消息接口 +* lpParamStruct:FileParamStruct类型结构体指针 +* return:void +*/ void SendFileRemote(LPVOID lpParamStruct) { FileParamStruct* params = (FileParamStruct*)lpParamStruct; SendFile((WCHAR*)params->wxid, (WCHAR*)params->filepath); } +/* +* 发送文件消息的具体实现 +* receiver:接收人wxid +* FilePath:文件绝对路径 +* return:void +*/ void __stdcall SendFile(wchar_t* receiver, wchar_t* FilePath) { WxBaseStruct pReceiver(receiver); WxBaseStruct pFilePath(FilePath); diff --git a/DWeChatRobot/SendImage.cpp b/DWeChatRobot/SendImage.cpp index fec61bb159c03f9c81539f3290e8eff6d04ef4a3..fd8ca73395629a3964ca03db4ddbf95d0489c232 100644 --- a/DWeChatRobot/SendImage.cpp +++ b/DWeChatRobot/SendImage.cpp @@ -1,20 +1,40 @@ #include "pch.h" +// 发送图片CALL1偏移 #define SendImageCall1Offset (0x6740A1C0 - 0x67370000) +// 发送图片CALL2偏移 #define SendImageCall2Offset (0x67A71DC0 - 0x67370000) +// 发送图片CALL3偏移 #define SendImageCall3Offset (0x6782E160 - 0x67370000) +// 清空缓存的CALL偏移 #define DeleteSendImageCacheCallOffset (0x67404200 - 0x67370000) +/* +* 外部调用时传递的参数结构 +* wxid:保存wxid的地址 +* imagepath:保存图片绝对路径的地址 +*/ struct ImageParamStruct { DWORD wxid; DWORD imagepath; }; +/* +* 供外部调用的发送图片消息接口 +* lpParamStruct:ImageParamStruct类型结构体指针 +* return:void +*/ void SendImageRemote(LPVOID lpParamStruct) { ImageParamStruct* params = (ImageParamStruct*)lpParamStruct; SendImage((WCHAR*)params->wxid, (WCHAR*)params->imagepath); } +/* +* 发送图片消息的具体实现 +* receiver:接收人wxid +* ImagePath:图片绝对路径 +* return:void +*/ void __stdcall SendImage(wchar_t* receiver, wchar_t* ImagePath) { DWORD WeChatWinBase = GetWeChatWinBase(); DWORD SendImageCall1 = WeChatWinBase + SendImageCall1Offset; diff --git a/DWeChatRobot/SendText.cpp b/DWeChatRobot/SendText.cpp index 16eb053600d8db41b6d853c3611c841ee9043aaa..67a39883b03a09d0e63e9bee93fff3a0136e31e5 100644 --- a/DWeChatRobot/SendText.cpp +++ b/DWeChatRobot/SendText.cpp @@ -1,14 +1,26 @@ #include "pch.h" +// 发送文本消息的CALL偏移 #define SendTextCallOffset 0x6782E7B0 - 0x67370000 +// 清空缓存的CALL偏移 #define DeleteTextCacheCallOffset 0x67404200 - 0x67370000 +/* +* 外部调用时传递的参数结构 +* wxid:wxid保存地址 +* wxmsg:发送的内容保存地址 +*/ struct SendTextStruct { DWORD wxid; DWORD wxmsg; }; +/* +* 供外部调用的发送文本消息接口 +* lpParameter:SendTextStruct类型结构体指针 +* return:void +*/ void SendTextRemote(LPVOID lpParameter) { SendTextStruct* rp = (SendTextStruct*)lpParameter; wchar_t* wsWxId = (WCHAR*)rp->wxid; @@ -16,6 +28,12 @@ void SendTextRemote(LPVOID lpParameter) { SendText(wsWxId, wsTextMsg); } +/* +* 发送文本消息的具体实现 +* wsWxId:接收人wxid +* wsTextMsg:发送的消息内容 +* return:void +*/ void __stdcall SendText(wchar_t* wsWxId, wchar_t* wsTextMsg) { WxBaseStruct wxWxid(wsWxId); WxBaseStruct wxTextMsg(wsTextMsg); diff --git a/DWeChatRobot/UserInfo.cpp b/DWeChatRobot/UserInfo.cpp index 65bad3e5dbb024852ae1efdb38bc9040c8e9f401..ae458588f5fc2d6b543073619c87694d03cde03f 100644 --- a/DWeChatRobot/UserInfo.cpp +++ b/DWeChatRobot/UserInfo.cpp @@ -3,22 +3,40 @@ #include #include +// 获取好友信息CALL0偏移 #define GetUserInfoCall0Offset 0x6740A000 - 0x67370000 +// 获取好友信息CALL1偏移 #define GetUserInfoCall1Offset 0x679C9840 - 0x67370000 +// 获取好友信息CALL2偏移 #define GetUserInfoCall2Offset 0x67A71DC0 - 0x67370000 +// 获取好友信息CALL3偏移 #define GetUserInfoCall3Offset 0x677724A0 - 0x67370000 +// 清空缓存CALL1偏移 #define DeleteUserInfoCacheCall1Offset 0x67775990 - 0x67370000 +// 清空缓存CALL2偏移 #define DeleteUserInfoCacheCall2Offset 0x679CA340 - 0x67370000 +/* +* 外部调用时的返回类型 +* message:wUserInfo.c_str() +* length:wUserInfo字符串长度 +*/ struct GetUserInfoStruct { DWORD message; DWORD length; }; +// 保存好友信息的字符串 wstring wUserInfo = L""; +// 外部调用时的具体返回对象 GetUserInfoStruct ret = { 0 }; +/* +* 根据缓冲区内容拼接好友信息 +* address:缓冲区地址 +* return:void +*/ VOID WxUserInfo(DWORD address) { vector InfoType{ address + 0x10, @@ -64,7 +82,11 @@ VOID WxUserInfo(DWORD address) { #endif } - +/* +* 供外部调用的获取好友信息接口 +* lparamter:保存好友wxid的地址 +* return:DWORD,`ret`的首地址 +*/ DWORD GetWxUserInfoRemote(LPVOID lparamter) { wchar_t* userwxid = (wchar_t*)lparamter; @@ -76,6 +98,10 @@ DWORD GetWxUserInfoRemote(LPVOID lparamter) { return (DWORD)&ret; } +/* +* 供外部调用的清空好友信息缓存的接口 +* return:void +*/ VOID DeleteUserInfoCacheRemote() { if (ret.length) { ZeroMemory((wchar_t*)ret.message, ret.length * 2 + 2); @@ -84,6 +110,11 @@ VOID DeleteUserInfoCacheRemote() { } } +/* +* 根据wxid获取好友信息的具体实现 +* wxid:好友wxid +* return:BOOL,成功返回`1`,失败返回`0` +*/ BOOL __stdcall GetUserInfoByWxId(wchar_t* wxid) { DWORD WeChatWinBase = GetWeChatWinBase(); DWORD WxGetUserInfoCall0 = WeChatWinBase + GetUserInfoCall0Offset; @@ -131,6 +162,11 @@ BOOL __stdcall GetUserInfoByWxId(wchar_t* wxid) { return isSuccess; } +/* +* 根据wxid获取联系人昵称,主要用于发送艾特消息接口 +* wxid:联系人wxid +* return:wchar_t*,获取到的wxid +*/ wchar_t* __stdcall GetUserNickNameByWxId(wchar_t* wxid) { DWORD WeChatWinBase = GetWeChatWinBase(); DWORD WxGetUserInfoCall0 = WeChatWinBase + GetUserInfoCall0Offset; diff --git a/DWeChatRobot/pch.cpp b/DWeChatRobot/pch.cpp index 11559fb15419c9d58bd1b1a2acb2feee8d08ab28..fcdfbb8c9b16c65f1897c65c105b87f64e15f66c 100644 --- a/DWeChatRobot/pch.cpp +++ b/DWeChatRobot/pch.cpp @@ -3,6 +3,11 @@ #include "pch.h" // 褰撲娇鐢ㄩ缂栬瘧鐨勫ご鏃讹紝闇瑕佷娇鐢ㄦ婧愭枃浠讹紝缂栬瘧鎵嶈兘鎴愬姛銆 + +/* +* 鍒涘缓涓涓帶鍒跺彴绐楀彛 +* return锛欱OOL锛屾垚鍔熻繑鍥瀈0`锛屽け璐ヨ繑鍥瀈1` +*/ BOOL CreateConsole(void) { if (AllocConsole()) { AttachConsole(GetCurrentProcessId()); @@ -16,10 +21,17 @@ BOOL CreateConsole(void) { return 1; } +/* +* 鑾峰彇`WeChatWin.dll`鍩哄潃 +* return锛欴WORD锛宍WeChatWin.dll`妯″潡鍩哄潃 +*/ DWORD GetWeChatWinBase() { return (DWORD)GetModuleHandleA("WeChatWin.dll"); } +/* +* 灏嗗瀛楄妭瀛楃涓茶浆鎹㈡垚`std::string` +*/ void Wchar_tToString(std::string& szDst, wchar_t* wchar) { wchar_t* wText = wchar; @@ -31,6 +43,9 @@ void Wchar_tToString(std::string& szDst, wchar_t* wchar) delete[]psText;// psText鐨勬竻闄 } +/* +* 灏哢TF8缂栫爜鏁版嵁杞崲涓篏BK缂栫爜 +*/ string UTF8ToGBK(const std::string& strUTF8) { int len = MultiByteToWideChar(CP_UTF8, 0, strUTF8.c_str(), -1, NULL, 0); @@ -49,6 +64,13 @@ string UTF8ToGBK(const std::string& strUTF8) return strTemp; } +/* +* 瀵逛换鎰忓湴鍧娣诲姞HOOK +* dwHookAddr锛欻OOK鐨勭洰鏍囧湴鍧 +* dwJmpAddress锛氳烦杞埌鐨勫湴鍧 +* originalRecieveCode锛氫繚瀛樻棫鎸囦护鐨勬暟缁 +* return锛歷oid +*/ void HookAnyAddress(DWORD dwHookAddr, LPVOID dwJmpAddress,char* originalRecieveCode) { //缁勮璺宠浆鏁版嵁 @@ -72,6 +94,12 @@ void HookAnyAddress(DWORD dwHookAddr, LPVOID dwJmpAddress,char* originalRecieveC VirtualProtect((LPVOID)dwHookAddr, 5, OldProtext, &OldProtext); } +/* +* 瀵逛换鎰忓湴鍧鍙栨秷HOOK +* dwHookAddr锛欻OOK鐨勭洰鏍囧湴鍧 +* originalRecieveCode锛氫繚瀛樻棫鎸囦护鐨勬暟缁 +* return锛歷oid +*/ void UnHookAnyAddress(DWORD dwHookAddr, char* originalRecieveCode) { DWORD OldProtext = 0; @@ -80,11 +108,23 @@ void UnHookAnyAddress(DWORD dwHookAddr, char* originalRecieveCode) VirtualProtect((LPVOID)dwHookAddr, 5, OldProtext, &OldProtext); } +/* +* 鍙栨秷鎵鏈塇OOK +* return锛歷oid +*/ void UnHookAll() { UnHookLogMsgInfo(); + UnHookReceiveMessage(); return; } +/* +* 灏嗗崟瀛楃鏇挎崲涓烘寚瀹氱殑瀛楃涓 +* source锛氭簮瀛楃涓 +* replaced锛氳鏇挎崲鐨勫崟瀛楃 +* replaceto锛氭浛鎹㈡垚鐨勫瓧绗︿覆 +* return锛歴td::wstring锛屾浛鎹㈠悗鐨勫瓧绗︿覆 +*/ wstring wreplace(wstring source, wchar_t replaced, wstring replaceto) { wstring temp = L""; wchar_t* buffer = (wchar_t*)source.c_str(); diff --git a/DWeChatRobot/pch.h b/DWeChatRobot/pch.h index 66572a6c9314a112d0a3489601113fed5f46b2c4..71fa50caff037de23eba455a7f9b255e9d366bce 100644 --- a/DWeChatRobot/pch.h +++ b/DWeChatRobot/pch.h @@ -31,8 +31,18 @@ #endif //PCH_H using namespace std; +// 瀵逛簬瀵煎嚭鍑芥暟锛岄渶瑕佷娇鐢ㄦ瀹忎慨楗 #define DLLEXPORT extern "C" __declspec(dllexport) +/* +* 寰俊涓殑鍩虹鏁版嵁缁撴瀯 +* buffer锛歎NICODE瀛楃涓 +* length锛歚buffer`瀛楃鏁 +* maxLength锛歚buffer`鏈澶у瓧绗︽暟 +* fill1锛氬崰浣嶆垚鍛1锛岄粯璁や负0 +* fill2锛氬崰浣嶆垚鍛2锛岄粯璁や负0 +* WxBaseStruct锛氶粯璁ゆ瀯閫犲嚱鏁 +*/ struct WxBaseStruct { wchar_t* buffer; @@ -50,6 +60,9 @@ struct WxBaseStruct } }; +/* +* 涓嶄娇鐢ㄦ瀯閫犲嚱鏁扮殑寰俊鍩虹鏁版嵁缁撴瀯锛屼娇鐢ㄩ鐜囪緝浣 +*/ struct WxString { wchar_t* buffer = NULL; diff --git a/Release/DWeChatRobot.dll b/Release/DWeChatRobot.dll index 20777a754d1dd8fc530cbeb04982661d995221b9..e39603f874cbe84dfbd39094fbcb5f77cbbf0c45 100644 Binary files a/Release/DWeChatRobot.dll and b/Release/DWeChatRobot.dll differ