commit
6bc052b4fe
@ -182,6 +182,12 @@ Rust 客户端。
|
||||
</details>
|
||||
|
||||
## 版本更新
|
||||
|
||||
### v39.0.2 (2023.07.16)
|
||||
* 修复朋友圈消息 `is_group` 为 `True` 问题
|
||||
|
||||
<details><summary>点击查看更多</summary>
|
||||
|
||||
客户端越来越多了,版本号开始混乱,所以重新定义了版本号:`w.x.y.z`。
|
||||
|
||||
其中:
|
||||
@ -190,7 +196,8 @@ Rust 客户端。
|
||||
* `y` 是 `WeChatFerry` 的版本,从 0 开始
|
||||
* `z` 是各客户端的版本,从 0 开始
|
||||
|
||||
<details><summary>点击查看</summary>
|
||||
### v39.0.1 (2023.07.16)
|
||||
* 获取朋友圈消息
|
||||
|
||||
### v39.0.0 (2023.07.14)
|
||||
升级到 `3.9.2.23`。
|
||||
|
@ -38,14 +38,16 @@ typedef vector<DbRow_t> DbRows_t;
|
||||
typedef struct {
|
||||
bool is_self;
|
||||
bool is_group;
|
||||
int32_t type;
|
||||
string id;
|
||||
string xml;
|
||||
uint32_t type;
|
||||
uint32_t ts;
|
||||
uint64_t id;
|
||||
string sender;
|
||||
string roomid;
|
||||
string content;
|
||||
string sign;
|
||||
string thumb;
|
||||
string extra;
|
||||
string xml;
|
||||
} WxMsg_t;
|
||||
|
||||
typedef struct {
|
||||
|
@ -22,6 +22,7 @@ enum Functions {
|
||||
FUNC_EXEC_DB_QUERY = 0x50;
|
||||
FUNC_ACCEPT_FRIEND = 0x51;
|
||||
FUNC_RECV_TRANSFER = 0x52;
|
||||
FUNC_REFRESH_PYQ = 0x53;
|
||||
FUNC_DECRYPT_IMAGE = 0x60;
|
||||
FUNC_ADD_ROOM_MEMBERS = 0x70;
|
||||
FUNC_DEL_ROOM_MEMBERS = 0x71;
|
||||
@ -42,6 +43,8 @@ message Request
|
||||
XmlMsg xml = 9;
|
||||
DecPath dec = 10;
|
||||
Transfer tf = 11;
|
||||
uint64 ui64 = 12; // 64 位整数,通用
|
||||
bool flag = 13;
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,14 +71,16 @@ message WxMsg
|
||||
{
|
||||
bool is_self = 1; // 是否自己发送的
|
||||
bool is_group = 2; // 是否群消息
|
||||
int32 type = 3; // 消息类型
|
||||
string id = 4; // 消息 id
|
||||
string xml = 5; // 消息 xml
|
||||
string sender = 6; // 消息发送者
|
||||
string roomid = 7; // 群 id(如果是群消息的话)
|
||||
string content = 8; // 消息内容
|
||||
string thumb = 9; // 缩略图
|
||||
string extra = 10; // 附加内容
|
||||
uint64 id = 3; // 消息 id
|
||||
uint32 type = 4; // 消息类型
|
||||
uint32 ts = 5; // 消息类型
|
||||
string roomid = 6; // 群 id(如果是群消息的话)
|
||||
string content = 7; // 消息内容
|
||||
string sender = 8; // 消息发送者
|
||||
string sign = 9; // Sign
|
||||
string thumb = 10; // 缩略图
|
||||
string extra = 11; // 附加内容
|
||||
string xml = 12; // 消息 xml
|
||||
}
|
||||
|
||||
message TextMsg
|
||||
|
@ -233,6 +233,7 @@ $(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto</Command>
|
||||
<ClInclude Include="contact_mgmt.h" />
|
||||
<ClInclude Include="load_calls.h" />
|
||||
<ClInclude Include="log.h" />
|
||||
<ClInclude Include="pyq.h" />
|
||||
<ClInclude Include="receive_msg.h" />
|
||||
<ClInclude Include="receive_transfer.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
@ -257,6 +258,7 @@ $(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto</Command>
|
||||
<ClCompile Include="contact_mgmt.cpp" />
|
||||
<ClCompile Include="load_calls.cpp" />
|
||||
<ClCompile Include="log.cpp" />
|
||||
<ClCompile Include="pyq.cpp" />
|
||||
<ClCompile Include="receive_msg.cpp" />
|
||||
<ClCompile Include="receive_transfer.cpp" />
|
||||
<ClCompile Include="rpc_server.cpp" />
|
||||
|
@ -90,6 +90,9 @@
|
||||
<ClInclude Include="sqlite3.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="pyq.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
@ -149,6 +152,9 @@
|
||||
<ClCompile Include="receive_transfer.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pyq.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="spy.def">
|
||||
|
@ -9,8 +9,8 @@ WxCalls_t wxCalls = {
|
||||
{ 0x2FFD484, 0x2FFD590, 0x2FFD500, 0x30238CC }, // User Info: wxid, nickname, mobile, home
|
||||
{ 0x768140, 0xCE6C80, 0x756960 }, // Send Message
|
||||
/* Receive Message:
|
||||
Hook, call, type, self, id, msgXml, roomId, wxId, content, thumb, extra */
|
||||
{ 0xD19A0B, 0x756960, 0x38, 0x3C, 0x194, 0x1FC, 0x48, 0x180, 0x70, 0x1A8, 0x1BC },
|
||||
Hook, call, msgId, type, isSelf, ts, roomId, content, wxid, sign, thumb, extra, msgXml */
|
||||
{ 0xD19A0B, 0x756960, 0x30, 0x38, 0x3C, 0x44, 0x48, 0x70, 0x180, 0x194, 0x1A8, 0x1BC, 0x1FC },
|
||||
{ 0x768140, 0XF59E40, 0XCE6640, 0x756960 }, // Send Image Message
|
||||
{ 0x76AE20, 0xF59E40, 0xB6D1F0, 0x756960 }, // Send File Message
|
||||
{ 0xB8A70, 0x3ED5E0, 0x107F00, 0x3ED7B0, 0x2386FE4 }, // Send xml Message
|
||||
@ -24,7 +24,10 @@ WxCalls_t wxCalls = {
|
||||
{ 0xA17D50, 0xF59E40, 0xA18BD0, 0xA17E70 }, // Accept New Friend application
|
||||
{ 0x78CF20, 0xF59E40, 0xBD1DC0 }, // Add chatroom members
|
||||
{ 0x78CF20, 0xF59E40, 0xBD22A0 }, // Delete chatroom members
|
||||
{ 0x7B2E60, 0x15E2C20, 0x79C250 } // Receive transfer
|
||||
{ 0x7B2E60, 0x15E2C20, 0x79C250 }, // Receive transfer
|
||||
/* Receive PYQ
|
||||
hook, call, call1, call2, call3, start, end, ts, wxid, content, xml, step*/
|
||||
{ 0x14F9E15, 0x14FA0A0, 0xC39680, 0x14E2140, 0x14E21E0, 0x20, 0x24, 0x2C, 0x18, 0x3C, 0x384, 0xB48 }
|
||||
};
|
||||
|
||||
int LoadCalls(const wchar_t *version, WxCalls_t *calls)
|
||||
|
77
WeChatFerry/spy/pyq.cpp
Normal file
77
WeChatFerry/spy/pyq.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
#include "framework.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "spy_types.h"
|
||||
#include "util.h"
|
||||
|
||||
extern bool gIsListeningPyq;
|
||||
extern WxCalls_t g_WxCalls;
|
||||
extern DWORD g_WeChatWinDllAddr;
|
||||
|
||||
typedef struct RawVector {
|
||||
DWORD start;
|
||||
DWORD finish;
|
||||
DWORD end;
|
||||
} RawVector_t;
|
||||
|
||||
static int GetFirstPage()
|
||||
{
|
||||
int rv = -1;
|
||||
DWORD pyqCall1 = g_WeChatWinDllAddr + g_WxCalls.pyq.call1;
|
||||
DWORD pyqCall2 = g_WeChatWinDllAddr + g_WxCalls.pyq.call2;
|
||||
|
||||
char buf[0xB44] = { 0 };
|
||||
__asm {
|
||||
pushad;
|
||||
call pyqCall1;
|
||||
push 0x1;
|
||||
lea ecx, buf;
|
||||
push ecx;
|
||||
mov ecx, eax;
|
||||
call pyqCall2;
|
||||
mov rv, eax;
|
||||
popad;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int GetNextPage(uint64_t id)
|
||||
{
|
||||
int rv = -1;
|
||||
DWORD pyqCall1 = g_WeChatWinDllAddr + g_WxCalls.pyq.call1;
|
||||
DWORD pyqCall3 = g_WeChatWinDllAddr + g_WxCalls.pyq.call3;
|
||||
|
||||
RawVector_t tmp = { 0 };
|
||||
|
||||
__asm {
|
||||
pushad;
|
||||
call pyqCall1;
|
||||
lea ecx, tmp;
|
||||
push ecx;
|
||||
mov ebx, dword ptr [id + 0x04];
|
||||
push ebx;
|
||||
mov edi, dword ptr [id]
|
||||
push edi;
|
||||
mov ecx, eax;
|
||||
call pyqCall3;
|
||||
mov rv, eax;
|
||||
popad;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int RefreshPyq(uint64_t id)
|
||||
{
|
||||
if (!gIsListeningPyq) {
|
||||
LOG_ERROR("没有启动朋友圈消息接收,参考:enable_receiving_msg");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (id == 0) {
|
||||
return GetFirstPage();
|
||||
}
|
||||
|
||||
return GetNextPage(id);
|
||||
}
|
5
WeChatFerry/spy/pyq.h
Normal file
5
WeChatFerry/spy/pyq.h
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
int RefreshPyq(uint64_t id);
|
@ -6,12 +6,13 @@
|
||||
#include <queue>
|
||||
|
||||
#include "load_calls.h"
|
||||
#include "log.h"
|
||||
#include "receive_msg.h"
|
||||
#include "user_info.h"
|
||||
#include "util.h"
|
||||
|
||||
// Defined in rpc_server.cpp
|
||||
extern bool gIsListening;
|
||||
extern bool gIsListening, gIsListeningPyq;
|
||||
extern mutex gMutex;
|
||||
extern condition_variable gCV;
|
||||
extern queue<WxMsg_t> gMsgQueue;
|
||||
@ -26,9 +27,15 @@ static DWORD recvMsgCallAddr = 0;
|
||||
static DWORD recvMsgJumpBackAddr = 0;
|
||||
static CHAR recvMsgBackupCode[5] = { 0 };
|
||||
|
||||
static DWORD recvPyqHookAddr = 0;
|
||||
static DWORD recvPyqCallAddr = 0;
|
||||
static DWORD recvPyqJumpBackAddr = 0;
|
||||
static CHAR recvPyqBackupCode[5] = { 0 };
|
||||
|
||||
MsgTypes_t GetMsgTypes()
|
||||
{
|
||||
const MsgTypes_t m = {
|
||||
{ 0x00, "朋友圈消息" },
|
||||
{ 0x01, "文字" },
|
||||
{ 0x03, "图片" },
|
||||
{ 0x22, "语音" },
|
||||
@ -90,9 +97,12 @@ void DispatchMsg(DWORD reg)
|
||||
{
|
||||
WxMsg_t wxMsg;
|
||||
|
||||
wxMsg.id = GET_QWORD(reg + g_WxCalls.recvMsg.msgId);
|
||||
wxMsg.type = GET_DWORD(reg + g_WxCalls.recvMsg.type);
|
||||
wxMsg.is_self = GET_DWORD(reg + g_WxCalls.recvMsg.isSelf);
|
||||
wxMsg.id = GetStringByStrAddr(reg + g_WxCalls.recvMsg.msgId);
|
||||
wxMsg.ts = GET_DWORD(reg + g_WxCalls.recvMsg.ts);
|
||||
wxMsg.content = GetStringByWstrAddr(reg + g_WxCalls.recvMsg.content);
|
||||
wxMsg.sign = GetStringByStrAddr(reg + g_WxCalls.recvMsg.sign);
|
||||
wxMsg.xml = GetStringByStrAddr(reg + g_WxCalls.recvMsg.msgXml);
|
||||
|
||||
string roomid = GetStringByWstrAddr(reg + g_WxCalls.recvMsg.roomId);
|
||||
@ -102,7 +112,7 @@ void DispatchMsg(DWORD reg)
|
||||
if (wxMsg.is_self) {
|
||||
wxMsg.sender = GetSelfWxid();
|
||||
} else {
|
||||
wxMsg.sender = GetStringByStrAddr(reg + g_WxCalls.recvMsg.wxId);
|
||||
wxMsg.sender = GetStringByStrAddr(reg + g_WxCalls.recvMsg.wxid);
|
||||
}
|
||||
} else {
|
||||
wxMsg.is_group = false;
|
||||
@ -113,8 +123,6 @@ void DispatchMsg(DWORD reg)
|
||||
}
|
||||
}
|
||||
|
||||
wxMsg.content = GetStringByWstrAddr(reg + g_WxCalls.recvMsg.content);
|
||||
|
||||
wxMsg.thumb = GetStringByStrAddr(reg + g_WxCalls.recvMsg.thumb);
|
||||
if (!wxMsg.thumb.empty()) {
|
||||
wxMsg.thumb = GetHomePath() + wxMsg.thumb;
|
||||
@ -173,3 +181,74 @@ void UnListenMessage()
|
||||
UnHookAddress(recvMsgHookAddr, recvMsgBackupCode);
|
||||
gIsListening = false;
|
||||
}
|
||||
|
||||
void DispatchPyq(DWORD reg)
|
||||
{
|
||||
DWORD startAddr = *(DWORD *)(reg + g_WxCalls.pyq.start);
|
||||
DWORD endAddr = *(DWORD *)(reg + g_WxCalls.pyq.end);
|
||||
|
||||
if (startAddr == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (startAddr < endAddr) {
|
||||
WxMsg_t wxMsg;
|
||||
|
||||
wxMsg.type = 0x00; // 朋友圈消息
|
||||
wxMsg.is_self = false;
|
||||
wxMsg.is_group = false;
|
||||
wxMsg.id = GET_QWORD(startAddr);
|
||||
wxMsg.ts = GET_DWORD(startAddr + g_WxCalls.pyq.ts);
|
||||
wxMsg.xml = GetStringByWstrAddr(startAddr + g_WxCalls.pyq.xml);
|
||||
wxMsg.sender = GetStringByWstrAddr(startAddr + g_WxCalls.pyq.wxid);
|
||||
wxMsg.content = GetStringByWstrAddr(startAddr + g_WxCalls.pyq.content);
|
||||
|
||||
{
|
||||
unique_lock<mutex> lock(gMutex);
|
||||
gMsgQueue.push(wxMsg); // 推送到队列
|
||||
}
|
||||
|
||||
gCV.notify_all(); // 通知各方消息就绪
|
||||
|
||||
startAddr += g_WxCalls.pyq.step;
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(naked) void RecievePyqFunc()
|
||||
{
|
||||
__asm {
|
||||
pushad
|
||||
pushfd
|
||||
push [esp + 0x24]
|
||||
call DispatchPyq
|
||||
add esp, 0x4
|
||||
popfd
|
||||
popad
|
||||
call recvPyqCallAddr // 这个为被覆盖的call
|
||||
jmp recvPyqJumpBackAddr // 跳回被HOOK指令的下一条指令
|
||||
}
|
||||
}
|
||||
|
||||
void ListenPyq()
|
||||
{
|
||||
if (gIsListeningPyq || (g_WeChatWinDllAddr == 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
recvPyqHookAddr = g_WeChatWinDllAddr + g_WxCalls.pyq.hook;
|
||||
recvPyqCallAddr = g_WeChatWinDllAddr + g_WxCalls.pyq.call;
|
||||
recvPyqJumpBackAddr = recvPyqHookAddr + 5;
|
||||
|
||||
HookAddress(recvPyqHookAddr, RecievePyqFunc, recvPyqBackupCode);
|
||||
gIsListeningPyq = true;
|
||||
}
|
||||
|
||||
void UnListenPyq()
|
||||
{
|
||||
if (!gIsListeningPyq) {
|
||||
return;
|
||||
}
|
||||
|
||||
UnHookAddress(recvPyqHookAddr, recvPyqBackupCode);
|
||||
gIsListeningPyq = false;
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
#include "pb_types.h"
|
||||
|
||||
void ListenPyq();
|
||||
void UnListenPyq();
|
||||
void ListenMessage();
|
||||
void UnListenMessage();
|
||||
MsgTypes_t GetMsgTypes();
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "log.h"
|
||||
#include "pb_types.h"
|
||||
#include "pb_util.h"
|
||||
#include "pyq.h"
|
||||
#include "receive_msg.h"
|
||||
#include "receive_transfer.h"
|
||||
#include "rpc_server.h"
|
||||
@ -38,7 +39,8 @@
|
||||
|
||||
extern int IsLogin(void); // Defined in spy.cpp
|
||||
|
||||
bool gIsListening;
|
||||
bool gIsListening = false;
|
||||
bool gIsListeningPyq = false;
|
||||
mutex gMutex;
|
||||
condition_variable gCV;
|
||||
queue<WxMsg_t> gMsgQueue;
|
||||
@ -345,16 +347,18 @@ static void PushMessage()
|
||||
if (gCV.wait_for(lock, chrono::milliseconds(1000), []() { return !gMsgQueue.empty(); })) {
|
||||
while (!gMsgQueue.empty()) {
|
||||
auto wxmsg = gMsgQueue.front();
|
||||
rsp.msg.wxmsg.id = wxmsg.id;
|
||||
rsp.msg.wxmsg.is_self = wxmsg.is_self;
|
||||
rsp.msg.wxmsg.is_group = wxmsg.is_group;
|
||||
rsp.msg.wxmsg.type = wxmsg.type;
|
||||
rsp.msg.wxmsg.id = (char *)wxmsg.id.c_str();
|
||||
rsp.msg.wxmsg.xml = (char *)wxmsg.xml.c_str();
|
||||
rsp.msg.wxmsg.sender = (char *)wxmsg.sender.c_str();
|
||||
rsp.msg.wxmsg.ts = wxmsg.ts;
|
||||
rsp.msg.wxmsg.roomid = (char *)wxmsg.roomid.c_str();
|
||||
rsp.msg.wxmsg.content = (char *)wxmsg.content.c_str();
|
||||
rsp.msg.wxmsg.sender = (char *)wxmsg.sender.c_str();
|
||||
rsp.msg.wxmsg.sign = (char *)wxmsg.sign.c_str();
|
||||
rsp.msg.wxmsg.thumb = (char *)wxmsg.thumb.c_str();
|
||||
rsp.msg.wxmsg.extra = (char *)wxmsg.extra.c_str();
|
||||
rsp.msg.wxmsg.xml = (char *)wxmsg.xml.c_str();
|
||||
gMsgQueue.pop();
|
||||
LOG_DEBUG("Recv msg: {}", wxmsg.content);
|
||||
pb_ostream_t stream = pb_ostream_from_buffer(buffer, G_BUF_SIZE);
|
||||
@ -374,7 +378,7 @@ static void PushMessage()
|
||||
nng_close(msg_sock);
|
||||
}
|
||||
|
||||
bool func_enable_recv_txt(uint8_t *out, size_t *len)
|
||||
bool func_enable_recv_txt(bool pyq, uint8_t *out, size_t *len)
|
||||
{
|
||||
Response rsp = Response_init_default;
|
||||
rsp.func = Functions_FUNC_ENABLE_RECV_TXT;
|
||||
@ -382,6 +386,9 @@ bool func_enable_recv_txt(uint8_t *out, size_t *len)
|
||||
rsp.msg.status = -1;
|
||||
|
||||
ListenMessage();
|
||||
if (pyq) {
|
||||
ListenPyq();
|
||||
}
|
||||
HANDLE msgThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PushMessage, NULL, NULL, NULL);
|
||||
if (msgThread != 0) {
|
||||
CloseHandle(msgThread);
|
||||
@ -405,6 +412,7 @@ bool func_disable_recv_txt(uint8_t *out, size_t *len)
|
||||
rsp.which_msg = Response_status_tag;
|
||||
rsp.msg.status = 0;
|
||||
|
||||
UnListenPyq();
|
||||
UnListenMessage(); // 可能需要1秒之后才能退出,见 PushMessage
|
||||
|
||||
pb_ostream_t stream = pb_ostream_from_buffer(out, *len);
|
||||
@ -486,6 +494,24 @@ bool func_receive_transfer(char *wxid, char *tfid, char *taid, uint8_t *out, siz
|
||||
return true;
|
||||
}
|
||||
|
||||
bool func_refresh_pyq(uint64_t id, uint8_t *out, size_t *len)
|
||||
{
|
||||
Response rsp = Response_init_default;
|
||||
rsp.func = Functions_FUNC_REFRESH_PYQ;
|
||||
rsp.which_msg = Response_status_tag;
|
||||
|
||||
rsp.msg.status = RefreshPyq(id);
|
||||
|
||||
pb_ostream_t stream = pb_ostream_from_buffer(out, *len);
|
||||
if (!pb_encode(&stream, Response_fields, &rsp)) {
|
||||
LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream));
|
||||
return false;
|
||||
}
|
||||
*len = stream.bytes_written;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool func_decrypt_image(char *src, char *dst, uint8_t *out, size_t *len)
|
||||
{
|
||||
Response rsp = Response_init_default;
|
||||
@ -629,7 +655,8 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len
|
||||
#endif
|
||||
case Functions_FUNC_ENABLE_RECV_TXT: {
|
||||
LOG_DEBUG("[Functions_FUNC_ENABLE_RECV_TXT]");
|
||||
ret = func_enable_recv_txt(out, out_len);
|
||||
LOG_BUFFER(in, in_len);
|
||||
ret = func_enable_recv_txt(req.msg.flag, out, out_len);
|
||||
break;
|
||||
}
|
||||
case Functions_FUNC_DISABLE_RECV_TXT: {
|
||||
@ -652,6 +679,11 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len
|
||||
ret = func_receive_transfer(req.msg.tf.wxid, req.msg.tf.tfid, req.msg.tf.taid, out, out_len);
|
||||
break;
|
||||
}
|
||||
case Functions_FUNC_REFRESH_PYQ: {
|
||||
LOG_DEBUG("[Functions_FUNC_REFRESH_PYQ]");
|
||||
ret = func_refresh_pyq(req.msg.ui64, out, out_len);
|
||||
break;
|
||||
}
|
||||
case Functions_FUNC_DECRYPT_IMAGE: {
|
||||
LOG_DEBUG("[FUNCTIONS_FUNC_DECRYPT_IMAGE]");
|
||||
ret = func_decrypt_image(req.msg.dec.src, req.msg.dec.dst, out, out_len);
|
||||
|
Binary file not shown.
@ -51,7 +51,7 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 39,0,0,0
|
||||
FILEVERSION 39,0,2,0
|
||||
PRODUCTVERSION 3,9,2,23
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
@ -69,7 +69,7 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "WeChatFerry"
|
||||
VALUE "FileDescription", "WeChatFerry"
|
||||
VALUE "FileVersion", "39.0.0.0"
|
||||
VALUE "FileVersion", "39.0.2.0"
|
||||
VALUE "InternalName", "spy.dll"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2023"
|
||||
VALUE "OriginalFilename", "spy.dll"
|
||||
|
@ -12,15 +12,17 @@ typedef struct UserInfoCall {
|
||||
typedef struct RecvMsg {
|
||||
DWORD hook; // Hook地址
|
||||
DWORD call; // Call地址
|
||||
DWORD msgId; // 消息ID地址
|
||||
DWORD type; // 消息类型地址
|
||||
DWORD isSelf; // 是否自己发送标志地址
|
||||
DWORD msgId; // 消息ID地址
|
||||
DWORD msgXml; // 消息xml内容地址
|
||||
DWORD ts; // TimeStamp
|
||||
DWORD roomId; // 群聊时,为群ID;私聊时,为微信ID
|
||||
DWORD wxId; // 私聊时,为空;群聊时,为发送者微信ID
|
||||
DWORD content; // 消息内容地址
|
||||
DWORD wxid; // 私聊时,为空;群聊时,为发送者微信ID
|
||||
DWORD sign; // Sign
|
||||
DWORD thumb; // 缩略图
|
||||
DWORD extra; // 附加数据
|
||||
DWORD msgXml; // 消息xml内容地址
|
||||
} RecvMsg_t;
|
||||
|
||||
typedef struct SendText {
|
||||
@ -85,6 +87,21 @@ typedef struct TF {
|
||||
DWORD call3;
|
||||
} TF_t;
|
||||
|
||||
typedef struct Pyq {
|
||||
DWORD hook;
|
||||
DWORD call;
|
||||
DWORD call1;
|
||||
DWORD call2;
|
||||
DWORD call3;
|
||||
DWORD start;
|
||||
DWORD end;
|
||||
DWORD ts;
|
||||
DWORD wxid;
|
||||
DWORD content;
|
||||
DWORD xml;
|
||||
DWORD step;
|
||||
} Pyq_t;
|
||||
|
||||
typedef struct WxCalls {
|
||||
DWORD login; // 登录状态
|
||||
UserInfoCall_t ui; // 用户信息
|
||||
@ -100,6 +117,7 @@ typedef struct WxCalls {
|
||||
RoomMember_t arm; // 添加群成员
|
||||
RoomMember_t drm; // 删除群成员
|
||||
TF_t tf; // 接收转账
|
||||
Pyq_t pyq; // 接收朋友圈消息
|
||||
} WxCalls_t;
|
||||
|
||||
typedef struct WxString {
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define WECHATINJECTDLL_DEBUG L"spy_debug.dll"
|
||||
|
||||
#define GET_DWORD(addr) ((DWORD) * (DWORD *)(addr))
|
||||
#define GET_QWORD(addr) ((uint64_t) * (uint64_t *)(addr))
|
||||
#define GET_STRING(addr) ((CHAR *)(*(DWORD *)(addr)))
|
||||
#define GET_WSTRING(addr) ((WCHAR *)(*(DWORD *)(addr)))
|
||||
#define GET_STRING_FROM_P(addr) ((CHAR *)(addr))
|
||||
|
@ -33,7 +33,7 @@ setup(
|
||||
"setuptools",
|
||||
"fastapi",
|
||||
"uvicorn[standard]",
|
||||
"wcferry>=39.0.0.0",
|
||||
"wcferry>=39.0.2.0",
|
||||
],
|
||||
classifiers=[
|
||||
"Environment :: Win32 (MS Windows)",
|
||||
|
@ -3,18 +3,22 @@
|
||||
|
||||
import base64
|
||||
import logging
|
||||
from queue import Empty
|
||||
from threading import Thread
|
||||
from typing import Any
|
||||
|
||||
import requests
|
||||
from fastapi import Body, FastAPI
|
||||
from fastapi import Body, Query, FastAPI
|
||||
from pydantic import BaseModel
|
||||
from wcferry import Wcf, WxMsg
|
||||
|
||||
__version__ = "39.0.0.1"
|
||||
__version__ = "39.0.2.0"
|
||||
|
||||
|
||||
class Msg(BaseModel):
|
||||
id: str
|
||||
id: int
|
||||
ts: int
|
||||
sign: str
|
||||
type: int
|
||||
xml: str
|
||||
sender: str
|
||||
@ -46,6 +50,7 @@ class Http(FastAPI):
|
||||
self.add_api_route("/friends", self.get_friends, methods=["GET"], summary="获取好友列表")
|
||||
self.add_api_route("/dbs", self.get_dbs, methods=["GET"], summary="获取所有数据库")
|
||||
self.add_api_route("/{db}/tables", self.get_tables, methods=["GET"], summary="获取 db 中所有表")
|
||||
self.add_api_route("/pyq/", self.refresh_pyq, methods=["GET"], summary="刷新朋友圈(数据从消息回调中查看)")
|
||||
|
||||
self.add_api_route("/text", self.send_text, methods=["POST"], summary="发送文本消息")
|
||||
self.add_api_route("/image", self.send_image, methods=["POST"], summary="发送图片消息")
|
||||
@ -55,35 +60,50 @@ class Http(FastAPI):
|
||||
self.add_api_route("/sql", self.query_sql, methods=["POST"], summary="执行 SQL,如果数据量大注意分页,以免 OOM")
|
||||
self.add_api_route("/new-friend", self.accept_new_friend, methods=["POST"], summary="通过好友申请")
|
||||
self.add_api_route("/chatroom-member", self.add_chatroom_members, methods=["POST"], summary="添加群成员")
|
||||
self.add_api_route("/chatroom-member", self.del_chatroom_members, methods=["DELETE"], summary="删除群成员")
|
||||
self.add_api_route("/transfer", self.receive_transfer, methods=["POST"], summary="接收转账")
|
||||
self.add_api_route("/dec-image", self.decrypt_image, methods=["POST"], summary="解密图片")
|
||||
|
||||
def _set_cb(self, cb):
|
||||
def callback(msg: WxMsg):
|
||||
data = {}
|
||||
data["id"] = msg.id
|
||||
data["type"] = msg.type
|
||||
data["xml"] = msg.xml
|
||||
data["sender"] = msg.sender
|
||||
data["roomid"] = msg.roomid
|
||||
data["content"] = msg.content
|
||||
data["thumb"] = msg.thumb
|
||||
data["extra"] = msg.extra
|
||||
data["is_at"] = msg.is_at(self.wcf.self_wxid)
|
||||
data["is_self"] = msg.from_self()
|
||||
data["is_group"] = msg.from_group()
|
||||
self.add_api_route("/chatroom-member", self.del_chatroom_members, methods=["DELETE"], summary="删除群成员")
|
||||
|
||||
try:
|
||||
rsp = requests.post(url=cb, json=data)
|
||||
if rsp.status_code != 200:
|
||||
self.LOG.error(f"消息转发失败,HTTP 状态码为: {rsp.status_code}")
|
||||
except Exception as e:
|
||||
self.LOG.error(f"消息转发异常: {e}")
|
||||
def _forward_msg(self, msg, cb):
|
||||
data = {}
|
||||
data["id"] = msg.id
|
||||
data["ts"] = msg.ts
|
||||
data["sign"] = msg.sign
|
||||
data["type"] = msg.type
|
||||
data["xml"] = msg.xml
|
||||
data["sender"] = msg.sender
|
||||
data["roomid"] = msg.roomid
|
||||
data["content"] = msg.content
|
||||
data["thumb"] = msg.thumb
|
||||
data["extra"] = msg.extra
|
||||
data["is_at"] = msg.is_at(self.wcf.self_wxid)
|
||||
data["is_self"] = msg.from_self()
|
||||
data["is_group"] = msg.from_group()
|
||||
|
||||
try:
|
||||
rsp = requests.post(url=cb, json=data)
|
||||
if rsp.status_code != 200:
|
||||
self.LOG.error(f"消息转发失败,HTTP 状态码为: {rsp.status_code}")
|
||||
except Exception as e:
|
||||
self.LOG.error(f"消息转发异常: {e}")
|
||||
|
||||
def _set_cb(self, cb):
|
||||
def callback(wcf: Wcf):
|
||||
while wcf.is_receiving_msg():
|
||||
try:
|
||||
msg = wcf.get_msg()
|
||||
self.LOG.info(msg)
|
||||
self._forward_msg(msg, cb)
|
||||
except Empty:
|
||||
continue # Empty message
|
||||
except Exception as e:
|
||||
self.LOG.error(f"Receiving message error: {e}")
|
||||
|
||||
if cb:
|
||||
self.LOG.info(f"消息回调: {cb}")
|
||||
self.wcf.enable_recv_msg(callback=callback)
|
||||
self.wcf.enable_receiving_msg(pyq=True) # 同时允许接收朋友圈消息
|
||||
Thread(target=callback, name="GetMessage", args=(self.wcf,), daemon=True).start()
|
||||
else:
|
||||
self.LOG.info(f"没有设置回调,打印消息")
|
||||
self.wcf.enable_recv_msg(print)
|
||||
@ -324,6 +344,18 @@ class Http(FastAPI):
|
||||
ret = self.wcf.receive_transfer(wxid, transferid, transactionid)
|
||||
return {"status": ret, "message": "成功"if ret == 1 else "失败"}
|
||||
|
||||
def refresh_pyq(self, id: int = Query(0, description="开始 id,0 为最新页")) -> dict:
|
||||
"""刷新朋友圈
|
||||
|
||||
Args:
|
||||
id (int): 开始 id,0 为最新页
|
||||
|
||||
Returns:
|
||||
int: 1 为成功,其他失败
|
||||
"""
|
||||
ret = self.wcf.refresh_pyq(id)
|
||||
return {"status": ret, "message": "成功"if ret == 1 else "失败"}
|
||||
|
||||
def decrypt_image(self,
|
||||
src: str = Body("C:\\...", description="加密的图片路径,从图片消息中获取"),
|
||||
dst: str = Body("C:\\...", description="解密的图片路径")) -> dict:
|
||||
|
@ -39,7 +39,7 @@ def process_msg(wcf: Wcf):
|
||||
|
||||
def main():
|
||||
LOG.info("Start demo...")
|
||||
wcf = Wcf(debug=True)
|
||||
wcf = Wcf(debug=True) # 默认连接本地服务
|
||||
|
||||
sleep(5) # 等微信加载好,以免信息显示异常
|
||||
LOG.info(f"已经登录: {True if wcf.is_login() else False}")
|
||||
@ -49,7 +49,7 @@ def main():
|
||||
# wcf.enable_recv_msg(LOG.info) # deprecated
|
||||
|
||||
# 允许接收消息
|
||||
wcf.enable_receiving_msg()
|
||||
wcf.enable_receiving_msg(pyq=True) # 同时允许接收朋友圈消息
|
||||
Thread(target=process_msg, name="GetMessage", args=(wcf,), daemon=True).start()
|
||||
|
||||
# wcf.disable_recv_msg() # 当需要停止接收消息时调用
|
||||
@ -71,7 +71,7 @@ def main():
|
||||
|
||||
sleep(5)
|
||||
LOG.info(f"DBs:\n{wcf.get_dbs()}")
|
||||
LOG.info(f"Tables:\n{wcf.get_tables('MicroMsg.db')}")
|
||||
LOG.info(f"Tables:\n{wcf.get_tables('db')}")
|
||||
LOG.info(f"Results:\n{wcf.query_sql('MicroMsg.db', 'SELECT * FROM Contact LIMIT 1;')}")
|
||||
|
||||
# 需要真正的 V3、V4 信息
|
||||
@ -85,6 +85,10 @@ def main():
|
||||
# ret = wcf.del_chatroom_members("chatroom id", "wxid1,wxid2,wxid3,...")
|
||||
# LOG.info(f"add_chatroom_members: {ret}")
|
||||
|
||||
sleep(5)
|
||||
wcf.refresh_pyq(0) # 刷新朋友圈第一页
|
||||
# wcf.refresh_pyq(id) # 从 id 开始刷新朋友圈
|
||||
|
||||
# 一直运行
|
||||
wcf.keep_running()
|
||||
|
||||
@ -114,15 +118,20 @@ pip install grpcio-tools pynng
|
||||
### 重新生成 PB 文件
|
||||
```sh
|
||||
# CMD
|
||||
cd python\wcferry
|
||||
python -m grpc_tools.protoc --python_out=. --proto_path=..\..\rpc\proto\ wcf.proto
|
||||
cd clients\python\wcferry
|
||||
python -m grpc_tools.protoc --python_out=. --proto_path=..\..\..\WeChatFerry\rpc\proto\ wcf.proto
|
||||
|
||||
# GitBash
|
||||
cd python/wcferry
|
||||
python -m grpc_tools.protoc --python_out=. --proto_path=../../rpc/proto/ wcf.proto
|
||||
cd clients/python/wcferry
|
||||
python -m grpc_tools.protoc --python_out=. --proto_path=../../../WeChatFerry/rpc/proto/ wcf.proto
|
||||
```
|
||||
|
||||
## 版本更新
|
||||
|
||||
### 39.0.2.0 (2023.07.16)
|
||||
* 获取朋友圈消息
|
||||
|
||||
<details><summary>点击查看更多</summary>
|
||||
版本号:`w.x.y.z`。
|
||||
|
||||
其中:
|
||||
@ -131,9 +140,6 @@ python -m grpc_tools.protoc --python_out=. --proto_path=../../rpc/proto/ wcf.pro
|
||||
* `y` 是 `WeChatFerry` 的版本,从 0 开始
|
||||
* `z` 是各客户端的版本,从 0 开始
|
||||
|
||||
### 39.0.0.1 (2023.07.15)
|
||||
修复不能 @ 问题。
|
||||
|
||||
功能:
|
||||
|
||||
* 检查登录状态
|
||||
@ -154,4 +160,7 @@ python -m grpc_tools.protoc --python_out=. --proto_path=../../rpc/proto/ wcf.pro
|
||||
* 添加群成员
|
||||
* 删除群成员
|
||||
* 解密图片
|
||||
* 获取朋友圈消息
|
||||
* 某功能(Breaking Change)
|
||||
|
||||
</details>
|
||||
|
@ -25,7 +25,6 @@ def process_msg(wcf: Wcf):
|
||||
def main():
|
||||
LOG.info("Start demo...")
|
||||
wcf = Wcf(debug=True) # 默认连接本地服务
|
||||
# wcf = Wcf("tcp://127.0.0.1:10086") # 连接远端服务
|
||||
|
||||
sleep(5) # 等微信加载好,以免信息显示异常
|
||||
LOG.info(f"已经登录: {True if wcf.is_login() else False}")
|
||||
@ -35,7 +34,7 @@ def main():
|
||||
# wcf.enable_recv_msg(LOG.info) # deprecated
|
||||
|
||||
# 允许接收消息
|
||||
wcf.enable_receiving_msg()
|
||||
wcf.enable_receiving_msg(pyq=True) # 同时允许接收朋友圈消息
|
||||
Thread(target=process_msg, name="GetMessage", args=(wcf,), daemon=True).start()
|
||||
|
||||
# wcf.disable_recv_msg() # 当需要停止接收消息时调用
|
||||
@ -71,6 +70,10 @@ def main():
|
||||
# ret = wcf.del_chatroom_members("chatroom id", "wxid1,wxid2,wxid3,...")
|
||||
# LOG.info(f"add_chatroom_members: {ret}")
|
||||
|
||||
sleep(5)
|
||||
wcf.refresh_pyq(0) # 刷新朋友圈第一页
|
||||
# wcf.refresh_pyq(id) # 从 id 开始刷新朋友圈
|
||||
|
||||
# 一直运行
|
||||
wcf.keep_running()
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#! /usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
__version__ = "39.0.0.1"
|
||||
__version__ = "39.0.2.0"
|
||||
|
||||
import atexit
|
||||
import base64
|
||||
@ -358,7 +358,7 @@ class Wcf():
|
||||
"""
|
||||
return self.msgQ.get(block, timeout=1)
|
||||
|
||||
def enable_receiving_msg(self) -> bool:
|
||||
def enable_receiving_msg(self, pyq=False) -> bool:
|
||||
"""允许接收消息,成功后通过 `get_msg` 读取消息"""
|
||||
def listening_msg():
|
||||
rsp = wcf_pb2.Response()
|
||||
@ -379,13 +379,14 @@ class Wcf():
|
||||
|
||||
req = wcf_pb2.Request()
|
||||
req.func = wcf_pb2.FUNC_ENABLE_RECV_TXT # FUNC_ENABLE_RECV_TXT
|
||||
req.flag = pyq
|
||||
rsp = self._send_request(req)
|
||||
if rsp.status != 0:
|
||||
return False
|
||||
|
||||
self._is_receiving_msg = True
|
||||
# 阻塞,把控制权交给用户
|
||||
# self._rpc_get_message(callback)
|
||||
# self.listening_msg(callback)
|
||||
|
||||
# 不阻塞,启动一个新的线程来接收消息
|
||||
Thread(target=listening_msg, name="GetMessage", daemon=True).start()
|
||||
@ -526,6 +527,21 @@ class Wcf():
|
||||
rsp = self._send_request(req)
|
||||
return rsp.status
|
||||
|
||||
def refresh_pyq(self, id: int = 0) -> int:
|
||||
"""刷新朋友圈
|
||||
|
||||
Args:
|
||||
id (int): 开始 id,0 为最新页
|
||||
|
||||
Returns:
|
||||
int: 1 为成功,其他失败
|
||||
"""
|
||||
req = wcf_pb2.Request()
|
||||
req.func = wcf_pb2.FUNC_REFRESH_PYQ # FUNC_REFRESH_PYQ
|
||||
req.ui64 = id
|
||||
rsp = self._send_request(req)
|
||||
return rsp.status
|
||||
|
||||
def decrypt_image(self, src: str, dst: str) -> bool:
|
||||
"""解密图片:
|
||||
|
||||
|
@ -13,7 +13,7 @@ _sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\twcf.proto\x12\x03wcf\"\xc8\x02\n\x07Request\x12\x1c\n\x04\x66unc\x18\x01 \x01(\x0e\x32\x0e.wcf.Functions\x12\x1b\n\x05\x65mpty\x18\x02 \x01(\x0b\x32\n.wcf.EmptyH\x00\x12\r\n\x03str\x18\x03 \x01(\tH\x00\x12\x1b\n\x03txt\x18\x04 \x01(\x0b\x32\x0c.wcf.TextMsgH\x00\x12\x1c\n\x04\x66ile\x18\x05 \x01(\x0b\x32\x0c.wcf.PathMsgH\x00\x12\x1d\n\x05query\x18\x06 \x01(\x0b\x32\x0c.wcf.DbQueryH\x00\x12\x1e\n\x01v\x18\x07 \x01(\x0b\x32\x11.wcf.VerificationH\x00\x12\x1c\n\x01m\x18\x08 \x01(\x0b\x32\x0f.wcf.AddMembersH\x00\x12\x1a\n\x03xml\x18\t \x01(\x0b\x32\x0b.wcf.XmlMsgH\x00\x12\x1b\n\x03\x64\x65\x63\x18\n \x01(\x0b\x32\x0c.wcf.DecPathH\x00\x12\x1b\n\x02tf\x18\x0b \x01(\x0b\x32\r.wcf.TransferH\x00\x42\x05\n\x03msg\"\xab\x02\n\x08Response\x12\x1c\n\x04\x66unc\x18\x01 \x01(\x0e\x32\x0e.wcf.Functions\x12\x10\n\x06status\x18\x02 \x01(\x05H\x00\x12\r\n\x03str\x18\x03 \x01(\tH\x00\x12\x1b\n\x05wxmsg\x18\x04 \x01(\x0b\x32\n.wcf.WxMsgH\x00\x12\x1e\n\x05types\x18\x05 \x01(\x0b\x32\r.wcf.MsgTypesH\x00\x12$\n\x08\x63ontacts\x18\x06 \x01(\x0b\x32\x10.wcf.RpcContactsH\x00\x12\x1b\n\x03\x64\x62s\x18\x07 \x01(\x0b\x32\x0c.wcf.DbNamesH\x00\x12\x1f\n\x06tables\x18\x08 \x01(\x0b\x32\r.wcf.DbTablesH\x00\x12\x1b\n\x04rows\x18\t \x01(\x0b\x32\x0b.wcf.DbRowsH\x00\x12\x1b\n\x02ui\x18\n \x01(\x0b\x32\r.wcf.UserInfoH\x00\x42\x05\n\x03msg\"\x07\n\x05\x45mpty\"\xa0\x01\n\x05WxMsg\x12\x0f\n\x07is_self\x18\x01 \x01(\x08\x12\x10\n\x08is_group\x18\x02 \x01(\x08\x12\x0c\n\x04type\x18\x03 \x01(\x05\x12\n\n\x02id\x18\x04 \x01(\t\x12\x0b\n\x03xml\x18\x05 \x01(\t\x12\x0e\n\x06sender\x18\x06 \x01(\t\x12\x0e\n\x06roomid\x18\x07 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x08 \x01(\t\x12\r\n\x05thumb\x18\t \x01(\t\x12\r\n\x05\x65xtra\x18\n \x01(\t\"7\n\x07TextMsg\x12\x0b\n\x03msg\x18\x01 \x01(\t\x12\x10\n\x08receiver\x18\x02 \x01(\t\x12\r\n\x05\x61ters\x18\x03 \x01(\t\")\n\x07PathMsg\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x10\n\x08receiver\x18\x02 \x01(\t\"G\n\x06XmlMsg\x12\x10\n\x08receiver\x18\x01 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x02 \x01(\t\x12\x0c\n\x04path\x18\x03 \x01(\t\x12\x0c\n\x04type\x18\x04 \x01(\x05\"a\n\x08MsgTypes\x12\'\n\x05types\x18\x01 \x03(\x0b\x32\x18.wcf.MsgTypes.TypesEntry\x1a,\n\nTypesEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x87\x01\n\nRpcContact\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x0c\n\x04\x63ode\x18\x02 \x01(\t\x12\x0e\n\x06remark\x18\x03 \x01(\t\x12\x0c\n\x04name\x18\x04 \x01(\t\x12\x0f\n\x07\x63ountry\x18\x05 \x01(\t\x12\x10\n\x08province\x18\x06 \x01(\t\x12\x0c\n\x04\x63ity\x18\x07 \x01(\t\x12\x0e\n\x06gender\x18\x08 \x01(\x05\"0\n\x0bRpcContacts\x12!\n\x08\x63ontacts\x18\x01 \x03(\x0b\x32\x0f.wcf.RpcContact\"\x18\n\x07\x44\x62Names\x12\r\n\x05names\x18\x01 \x03(\t\"$\n\x07\x44\x62Table\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0b\n\x03sql\x18\x02 \x01(\t\"(\n\x08\x44\x62Tables\x12\x1c\n\x06tables\x18\x01 \x03(\x0b\x32\x0c.wcf.DbTable\"\"\n\x07\x44\x62Query\x12\n\n\x02\x64\x62\x18\x01 \x01(\t\x12\x0b\n\x03sql\x18\x02 \x01(\t\"8\n\x07\x44\x62\x46ield\x12\x0c\n\x04type\x18\x01 \x01(\x05\x12\x0e\n\x06\x63olumn\x18\x02 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x03 \x01(\x0c\"%\n\x05\x44\x62Row\x12\x1c\n\x06\x66ields\x18\x01 \x03(\x0b\x32\x0c.wcf.DbField\"\"\n\x06\x44\x62Rows\x12\x18\n\x04rows\x18\x01 \x03(\x0b\x32\n.wcf.DbRow\"5\n\x0cVerification\x12\n\n\x02v3\x18\x01 \x01(\t\x12\n\n\x02v4\x18\x02 \x01(\t\x12\r\n\x05scene\x18\x03 \x01(\x05\"+\n\nAddMembers\x12\x0e\n\x06roomid\x18\x01 \x01(\t\x12\r\n\x05wxids\x18\x02 \x01(\t\"D\n\x08UserInfo\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0e\n\x06mobile\x18\x03 \x01(\t\x12\x0c\n\x04home\x18\x04 \x01(\t\"#\n\x07\x44\x65\x63Path\x12\x0b\n\x03src\x18\x01 \x01(\t\x12\x0b\n\x03\x64st\x18\x02 \x01(\t\"4\n\x08Transfer\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x0c\n\x04tfid\x18\x02 \x01(\t\x12\x0c\n\x04taid\x18\x03 \x01(\t*\xee\x03\n\tFunctions\x12\x11\n\rFUNC_RESERVED\x10\x00\x12\x11\n\rFUNC_IS_LOGIN\x10\x01\x12\x16\n\x12\x46UNC_GET_SELF_WXID\x10\x10\x12\x16\n\x12\x46UNC_GET_MSG_TYPES\x10\x11\x12\x15\n\x11\x46UNC_GET_CONTACTS\x10\x12\x12\x15\n\x11\x46UNC_GET_DB_NAMES\x10\x13\x12\x16\n\x12\x46UNC_GET_DB_TABLES\x10\x14\x12\x16\n\x12\x46UNC_GET_USER_INFO\x10\x15\x12\x11\n\rFUNC_SEND_TXT\x10 \x12\x11\n\rFUNC_SEND_IMG\x10!\x12\x12\n\x0e\x46UNC_SEND_FILE\x10\"\x12\x11\n\rFUNC_SEND_XML\x10#\x12\x15\n\x11\x46UNC_SEND_EMOTION\x10$\x12\x18\n\x14\x46UNC_ENABLE_RECV_TXT\x10\x30\x12\x19\n\x15\x46UNC_DISABLE_RECV_TXT\x10@\x12\x16\n\x12\x46UNC_EXEC_DB_QUERY\x10P\x12\x16\n\x12\x46UNC_ACCEPT_FRIEND\x10Q\x12\x16\n\x12\x46UNC_RECV_TRANSFER\x10R\x12\x16\n\x12\x46UNC_DECRYPT_IMAGE\x10`\x12\x19\n\x15\x46UNC_ADD_ROOM_MEMBERS\x10p\x12\x19\n\x15\x46UNC_DEL_ROOM_MEMBERS\x10qB\r\n\x0b\x63om.iamteerb\x06proto3')
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\twcf.proto\x12\x03wcf\"\xe8\x02\n\x07Request\x12\x1c\n\x04\x66unc\x18\x01 \x01(\x0e\x32\x0e.wcf.Functions\x12\x1b\n\x05\x65mpty\x18\x02 \x01(\x0b\x32\n.wcf.EmptyH\x00\x12\r\n\x03str\x18\x03 \x01(\tH\x00\x12\x1b\n\x03txt\x18\x04 \x01(\x0b\x32\x0c.wcf.TextMsgH\x00\x12\x1c\n\x04\x66ile\x18\x05 \x01(\x0b\x32\x0c.wcf.PathMsgH\x00\x12\x1d\n\x05query\x18\x06 \x01(\x0b\x32\x0c.wcf.DbQueryH\x00\x12\x1e\n\x01v\x18\x07 \x01(\x0b\x32\x11.wcf.VerificationH\x00\x12\x1c\n\x01m\x18\x08 \x01(\x0b\x32\x0f.wcf.AddMembersH\x00\x12\x1a\n\x03xml\x18\t \x01(\x0b\x32\x0b.wcf.XmlMsgH\x00\x12\x1b\n\x03\x64\x65\x63\x18\n \x01(\x0b\x32\x0c.wcf.DecPathH\x00\x12\x1b\n\x02tf\x18\x0b \x01(\x0b\x32\r.wcf.TransferH\x00\x12\x0e\n\x04ui64\x18\x0c \x01(\x04H\x00\x12\x0e\n\x04\x66lag\x18\r \x01(\x08H\x00\x42\x05\n\x03msg\"\xab\x02\n\x08Response\x12\x1c\n\x04\x66unc\x18\x01 \x01(\x0e\x32\x0e.wcf.Functions\x12\x10\n\x06status\x18\x02 \x01(\x05H\x00\x12\r\n\x03str\x18\x03 \x01(\tH\x00\x12\x1b\n\x05wxmsg\x18\x04 \x01(\x0b\x32\n.wcf.WxMsgH\x00\x12\x1e\n\x05types\x18\x05 \x01(\x0b\x32\r.wcf.MsgTypesH\x00\x12$\n\x08\x63ontacts\x18\x06 \x01(\x0b\x32\x10.wcf.RpcContactsH\x00\x12\x1b\n\x03\x64\x62s\x18\x07 \x01(\x0b\x32\x0c.wcf.DbNamesH\x00\x12\x1f\n\x06tables\x18\x08 \x01(\x0b\x32\r.wcf.DbTablesH\x00\x12\x1b\n\x04rows\x18\t \x01(\x0b\x32\x0b.wcf.DbRowsH\x00\x12\x1b\n\x02ui\x18\n \x01(\x0b\x32\r.wcf.UserInfoH\x00\x42\x05\n\x03msg\"\x07\n\x05\x45mpty\"\xba\x01\n\x05WxMsg\x12\x0f\n\x07is_self\x18\x01 \x01(\x08\x12\x10\n\x08is_group\x18\x02 \x01(\x08\x12\n\n\x02id\x18\x03 \x01(\x04\x12\x0c\n\x04type\x18\x04 \x01(\r\x12\n\n\x02ts\x18\x05 \x01(\r\x12\x0e\n\x06roomid\x18\x06 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x07 \x01(\t\x12\x0e\n\x06sender\x18\x08 \x01(\t\x12\x0c\n\x04sign\x18\t \x01(\t\x12\r\n\x05thumb\x18\n \x01(\t\x12\r\n\x05\x65xtra\x18\x0b \x01(\t\x12\x0b\n\x03xml\x18\x0c \x01(\t\"7\n\x07TextMsg\x12\x0b\n\x03msg\x18\x01 \x01(\t\x12\x10\n\x08receiver\x18\x02 \x01(\t\x12\r\n\x05\x61ters\x18\x03 \x01(\t\")\n\x07PathMsg\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x10\n\x08receiver\x18\x02 \x01(\t\"G\n\x06XmlMsg\x12\x10\n\x08receiver\x18\x01 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x02 \x01(\t\x12\x0c\n\x04path\x18\x03 \x01(\t\x12\x0c\n\x04type\x18\x04 \x01(\x05\"a\n\x08MsgTypes\x12\'\n\x05types\x18\x01 \x03(\x0b\x32\x18.wcf.MsgTypes.TypesEntry\x1a,\n\nTypesEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x87\x01\n\nRpcContact\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x0c\n\x04\x63ode\x18\x02 \x01(\t\x12\x0e\n\x06remark\x18\x03 \x01(\t\x12\x0c\n\x04name\x18\x04 \x01(\t\x12\x0f\n\x07\x63ountry\x18\x05 \x01(\t\x12\x10\n\x08province\x18\x06 \x01(\t\x12\x0c\n\x04\x63ity\x18\x07 \x01(\t\x12\x0e\n\x06gender\x18\x08 \x01(\x05\"0\n\x0bRpcContacts\x12!\n\x08\x63ontacts\x18\x01 \x03(\x0b\x32\x0f.wcf.RpcContact\"\x18\n\x07\x44\x62Names\x12\r\n\x05names\x18\x01 \x03(\t\"$\n\x07\x44\x62Table\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0b\n\x03sql\x18\x02 \x01(\t\"(\n\x08\x44\x62Tables\x12\x1c\n\x06tables\x18\x01 \x03(\x0b\x32\x0c.wcf.DbTable\"\"\n\x07\x44\x62Query\x12\n\n\x02\x64\x62\x18\x01 \x01(\t\x12\x0b\n\x03sql\x18\x02 \x01(\t\"8\n\x07\x44\x62\x46ield\x12\x0c\n\x04type\x18\x01 \x01(\x05\x12\x0e\n\x06\x63olumn\x18\x02 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x03 \x01(\x0c\"%\n\x05\x44\x62Row\x12\x1c\n\x06\x66ields\x18\x01 \x03(\x0b\x32\x0c.wcf.DbField\"\"\n\x06\x44\x62Rows\x12\x18\n\x04rows\x18\x01 \x03(\x0b\x32\n.wcf.DbRow\"5\n\x0cVerification\x12\n\n\x02v3\x18\x01 \x01(\t\x12\n\n\x02v4\x18\x02 \x01(\t\x12\r\n\x05scene\x18\x03 \x01(\x05\"+\n\nAddMembers\x12\x0e\n\x06roomid\x18\x01 \x01(\t\x12\r\n\x05wxids\x18\x02 \x01(\t\"D\n\x08UserInfo\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0e\n\x06mobile\x18\x03 \x01(\t\x12\x0c\n\x04home\x18\x04 \x01(\t\"#\n\x07\x44\x65\x63Path\x12\x0b\n\x03src\x18\x01 \x01(\t\x12\x0b\n\x03\x64st\x18\x02 \x01(\t\"4\n\x08Transfer\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x0c\n\x04tfid\x18\x02 \x01(\t\x12\x0c\n\x04taid\x18\x03 \x01(\t*\x84\x04\n\tFunctions\x12\x11\n\rFUNC_RESERVED\x10\x00\x12\x11\n\rFUNC_IS_LOGIN\x10\x01\x12\x16\n\x12\x46UNC_GET_SELF_WXID\x10\x10\x12\x16\n\x12\x46UNC_GET_MSG_TYPES\x10\x11\x12\x15\n\x11\x46UNC_GET_CONTACTS\x10\x12\x12\x15\n\x11\x46UNC_GET_DB_NAMES\x10\x13\x12\x16\n\x12\x46UNC_GET_DB_TABLES\x10\x14\x12\x16\n\x12\x46UNC_GET_USER_INFO\x10\x15\x12\x11\n\rFUNC_SEND_TXT\x10 \x12\x11\n\rFUNC_SEND_IMG\x10!\x12\x12\n\x0e\x46UNC_SEND_FILE\x10\"\x12\x11\n\rFUNC_SEND_XML\x10#\x12\x15\n\x11\x46UNC_SEND_EMOTION\x10$\x12\x18\n\x14\x46UNC_ENABLE_RECV_TXT\x10\x30\x12\x19\n\x15\x46UNC_DISABLE_RECV_TXT\x10@\x12\x16\n\x12\x46UNC_EXEC_DB_QUERY\x10P\x12\x16\n\x12\x46UNC_ACCEPT_FRIEND\x10Q\x12\x16\n\x12\x46UNC_RECV_TRANSFER\x10R\x12\x14\n\x10\x46UNC_REFRESH_PYQ\x10S\x12\x16\n\x12\x46UNC_DECRYPT_IMAGE\x10`\x12\x19\n\x15\x46UNC_ADD_ROOM_MEMBERS\x10p\x12\x19\n\x15\x46UNC_DEL_ROOM_MEMBERS\x10qB\r\n\x0b\x63om.iamteerb\x06proto3')
|
||||
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'wcf_pb2', globals())
|
||||
@ -23,52 +23,52 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
DESCRIPTOR._serialized_options = b'\n\013com.iamteer'
|
||||
_MSGTYPES_TYPESENTRY._options = None
|
||||
_MSGTYPES_TYPESENTRY._serialized_options = b'8\001'
|
||||
_FUNCTIONS._serialized_start=1820
|
||||
_FUNCTIONS._serialized_end=2314
|
||||
_FUNCTIONS._serialized_start=1878
|
||||
_FUNCTIONS._serialized_end=2394
|
||||
_REQUEST._serialized_start=19
|
||||
_REQUEST._serialized_end=347
|
||||
_RESPONSE._serialized_start=350
|
||||
_RESPONSE._serialized_end=649
|
||||
_EMPTY._serialized_start=651
|
||||
_EMPTY._serialized_end=658
|
||||
_WXMSG._serialized_start=661
|
||||
_WXMSG._serialized_end=821
|
||||
_TEXTMSG._serialized_start=823
|
||||
_TEXTMSG._serialized_end=878
|
||||
_PATHMSG._serialized_start=880
|
||||
_PATHMSG._serialized_end=921
|
||||
_XMLMSG._serialized_start=923
|
||||
_XMLMSG._serialized_end=994
|
||||
_MSGTYPES._serialized_start=996
|
||||
_MSGTYPES._serialized_end=1093
|
||||
_MSGTYPES_TYPESENTRY._serialized_start=1049
|
||||
_MSGTYPES_TYPESENTRY._serialized_end=1093
|
||||
_RPCCONTACT._serialized_start=1096
|
||||
_RPCCONTACT._serialized_end=1231
|
||||
_RPCCONTACTS._serialized_start=1233
|
||||
_RPCCONTACTS._serialized_end=1281
|
||||
_DBNAMES._serialized_start=1283
|
||||
_DBNAMES._serialized_end=1307
|
||||
_DBTABLE._serialized_start=1309
|
||||
_DBTABLE._serialized_end=1345
|
||||
_DBTABLES._serialized_start=1347
|
||||
_DBTABLES._serialized_end=1387
|
||||
_DBQUERY._serialized_start=1389
|
||||
_DBQUERY._serialized_end=1423
|
||||
_DBFIELD._serialized_start=1425
|
||||
_DBFIELD._serialized_end=1481
|
||||
_DBROW._serialized_start=1483
|
||||
_DBROW._serialized_end=1520
|
||||
_DBROWS._serialized_start=1522
|
||||
_DBROWS._serialized_end=1556
|
||||
_VERIFICATION._serialized_start=1558
|
||||
_VERIFICATION._serialized_end=1611
|
||||
_ADDMEMBERS._serialized_start=1613
|
||||
_ADDMEMBERS._serialized_end=1656
|
||||
_USERINFO._serialized_start=1658
|
||||
_USERINFO._serialized_end=1726
|
||||
_DECPATH._serialized_start=1728
|
||||
_DECPATH._serialized_end=1763
|
||||
_TRANSFER._serialized_start=1765
|
||||
_TRANSFER._serialized_end=1817
|
||||
_REQUEST._serialized_end=379
|
||||
_RESPONSE._serialized_start=382
|
||||
_RESPONSE._serialized_end=681
|
||||
_EMPTY._serialized_start=683
|
||||
_EMPTY._serialized_end=690
|
||||
_WXMSG._serialized_start=693
|
||||
_WXMSG._serialized_end=879
|
||||
_TEXTMSG._serialized_start=881
|
||||
_TEXTMSG._serialized_end=936
|
||||
_PATHMSG._serialized_start=938
|
||||
_PATHMSG._serialized_end=979
|
||||
_XMLMSG._serialized_start=981
|
||||
_XMLMSG._serialized_end=1052
|
||||
_MSGTYPES._serialized_start=1054
|
||||
_MSGTYPES._serialized_end=1151
|
||||
_MSGTYPES_TYPESENTRY._serialized_start=1107
|
||||
_MSGTYPES_TYPESENTRY._serialized_end=1151
|
||||
_RPCCONTACT._serialized_start=1154
|
||||
_RPCCONTACT._serialized_end=1289
|
||||
_RPCCONTACTS._serialized_start=1291
|
||||
_RPCCONTACTS._serialized_end=1339
|
||||
_DBNAMES._serialized_start=1341
|
||||
_DBNAMES._serialized_end=1365
|
||||
_DBTABLE._serialized_start=1367
|
||||
_DBTABLE._serialized_end=1403
|
||||
_DBTABLES._serialized_start=1405
|
||||
_DBTABLES._serialized_end=1445
|
||||
_DBQUERY._serialized_start=1447
|
||||
_DBQUERY._serialized_end=1481
|
||||
_DBFIELD._serialized_start=1483
|
||||
_DBFIELD._serialized_end=1539
|
||||
_DBROW._serialized_start=1541
|
||||
_DBROW._serialized_end=1578
|
||||
_DBROWS._serialized_start=1580
|
||||
_DBROWS._serialized_end=1614
|
||||
_VERIFICATION._serialized_start=1616
|
||||
_VERIFICATION._serialized_end=1669
|
||||
_ADDMEMBERS._serialized_start=1671
|
||||
_ADDMEMBERS._serialized_end=1714
|
||||
_USERINFO._serialized_start=1716
|
||||
_USERINFO._serialized_end=1784
|
||||
_DECPATH._serialized_start=1786
|
||||
_DECPATH._serialized_end=1821
|
||||
_TRANSFER._serialized_start=1823
|
||||
_TRANSFER._serialized_end=1875
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
|
@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import re
|
||||
from datetime import datetime
|
||||
|
||||
from wcferry import wcf_pb2
|
||||
|
||||
@ -24,6 +25,8 @@ class WxMsg():
|
||||
self._is_group = msg.is_group
|
||||
self.type = msg.type
|
||||
self.id = msg.id
|
||||
self.ts = msg.ts
|
||||
self.sign = msg.sign
|
||||
self.xml = msg.xml
|
||||
self.sender = msg.sender
|
||||
self.roomid = msg.roomid
|
||||
@ -33,7 +36,8 @@ class WxMsg():
|
||||
|
||||
def __str__(self) -> str:
|
||||
s = f"{'自己发的:' if self._is_self else ''}"
|
||||
s += f"{self.sender}[{self.roomid}]:{self.id}:{self.type}:{self.xml.replace(chr(10), '').replace(chr(9),'')}\n"
|
||||
s += f"{self.sender}[{self.roomid}]|{self.id}|{datetime.fromtimestamp(self.ts)}|{self.type}|{self.sign}"
|
||||
s += f"\n{self.xml.replace(chr(10), '').replace(chr(9),'')}\n"
|
||||
s += self.content
|
||||
s += f"\n{self.thumb}" if self.thumb else ""
|
||||
s += f"\n{self.extra}" if self.extra else ""
|
||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user