Impl FUNC_REFRESH_PYQ
This commit is contained in:
parent
f2acc668bf
commit
fed3143b19
@ -22,6 +22,7 @@ enum Functions {
|
|||||||
FUNC_EXEC_DB_QUERY = 0x50;
|
FUNC_EXEC_DB_QUERY = 0x50;
|
||||||
FUNC_ACCEPT_FRIEND = 0x51;
|
FUNC_ACCEPT_FRIEND = 0x51;
|
||||||
FUNC_RECV_TRANSFER = 0x52;
|
FUNC_RECV_TRANSFER = 0x52;
|
||||||
|
FUNC_REFRESH_PYQ = 0x53;
|
||||||
FUNC_DECRYPT_IMAGE = 0x60;
|
FUNC_DECRYPT_IMAGE = 0x60;
|
||||||
FUNC_ADD_ROOM_MEMBERS = 0x70;
|
FUNC_ADD_ROOM_MEMBERS = 0x70;
|
||||||
FUNC_DEL_ROOM_MEMBERS = 0x71;
|
FUNC_DEL_ROOM_MEMBERS = 0x71;
|
||||||
|
@ -233,6 +233,7 @@ $(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto</Command>
|
|||||||
<ClInclude Include="contact_mgmt.h" />
|
<ClInclude Include="contact_mgmt.h" />
|
||||||
<ClInclude Include="load_calls.h" />
|
<ClInclude Include="load_calls.h" />
|
||||||
<ClInclude Include="log.h" />
|
<ClInclude Include="log.h" />
|
||||||
|
<ClInclude Include="pyq.h" />
|
||||||
<ClInclude Include="receive_msg.h" />
|
<ClInclude Include="receive_msg.h" />
|
||||||
<ClInclude Include="receive_transfer.h" />
|
<ClInclude Include="receive_transfer.h" />
|
||||||
<ClInclude Include="resource.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="contact_mgmt.cpp" />
|
||||||
<ClCompile Include="load_calls.cpp" />
|
<ClCompile Include="load_calls.cpp" />
|
||||||
<ClCompile Include="log.cpp" />
|
<ClCompile Include="log.cpp" />
|
||||||
|
<ClCompile Include="pyq.cpp" />
|
||||||
<ClCompile Include="receive_msg.cpp" />
|
<ClCompile Include="receive_msg.cpp" />
|
||||||
<ClCompile Include="receive_transfer.cpp" />
|
<ClCompile Include="receive_transfer.cpp" />
|
||||||
<ClCompile Include="rpc_server.cpp" />
|
<ClCompile Include="rpc_server.cpp" />
|
||||||
|
@ -90,6 +90,9 @@
|
|||||||
<ClInclude Include="sqlite3.h">
|
<ClInclude Include="sqlite3.h">
|
||||||
<Filter>头文件</Filter>
|
<Filter>头文件</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="pyq.h">
|
||||||
|
<Filter>头文件</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="dllmain.cpp">
|
<ClCompile Include="dllmain.cpp">
|
||||||
@ -149,6 +152,9 @@
|
|||||||
<ClCompile Include="receive_transfer.cpp">
|
<ClCompile Include="receive_transfer.cpp">
|
||||||
<Filter>源文件</Filter>
|
<Filter>源文件</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="pyq.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="spy.def">
|
<None Include="spy.def">
|
||||||
|
70
WeChatFerry/spy/pyq.cpp
Normal file
70
WeChatFerry/spy/pyq.cpp
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#include "framework.h"
|
||||||
|
|
||||||
|
#include "spy_types.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
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 + 0xC39680;
|
||||||
|
DWORD pyqCall2 = g_WeChatWinDllAddr + 0x14E2140;
|
||||||
|
|
||||||
|
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 + 0xC39680;
|
||||||
|
DWORD pyqCall3 = g_WeChatWinDllAddr + 0x14E21E0;
|
||||||
|
|
||||||
|
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 (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,6 +6,7 @@
|
|||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
#include "load_calls.h"
|
#include "load_calls.h"
|
||||||
|
#include "log.h"
|
||||||
#include "receive_msg.h"
|
#include "receive_msg.h"
|
||||||
#include "user_info.h"
|
#include "user_info.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@ -26,9 +27,16 @@ static DWORD recvMsgCallAddr = 0;
|
|||||||
static DWORD recvMsgJumpBackAddr = 0;
|
static DWORD recvMsgJumpBackAddr = 0;
|
||||||
static CHAR recvMsgBackupCode[5] = { 0 };
|
static CHAR recvMsgBackupCode[5] = { 0 };
|
||||||
|
|
||||||
|
static DWORD recvPyqHookAddr = 0;
|
||||||
|
static DWORD recvPyqCallAddr = 0;
|
||||||
|
static DWORD recvPyqJumpBackAddr = 0;
|
||||||
|
static CHAR recvPyqBackupCode[5] = { 0 };
|
||||||
|
static bool gIsListeningPyq = false;
|
||||||
|
|
||||||
MsgTypes_t GetMsgTypes()
|
MsgTypes_t GetMsgTypes()
|
||||||
{
|
{
|
||||||
const MsgTypes_t m = {
|
const MsgTypes_t m = {
|
||||||
|
{ 0x00, "朋友圈消息" },
|
||||||
{ 0x01, "文字" },
|
{ 0x01, "文字" },
|
||||||
{ 0x03, "图片" },
|
{ 0x03, "图片" },
|
||||||
{ 0x22, "语音" },
|
{ 0x22, "语音" },
|
||||||
@ -164,6 +172,7 @@ void ListenMessage()
|
|||||||
|
|
||||||
HookAddress(recvMsgHookAddr, RecieveMsgFunc, recvMsgBackupCode);
|
HookAddress(recvMsgHookAddr, RecieveMsgFunc, recvMsgBackupCode);
|
||||||
gIsListening = true;
|
gIsListening = true;
|
||||||
|
ListenPyq();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnListenMessage()
|
void UnListenMessage()
|
||||||
@ -173,4 +182,75 @@ void UnListenMessage()
|
|||||||
}
|
}
|
||||||
UnHookAddress(recvMsgHookAddr, recvMsgBackupCode);
|
UnHookAddress(recvMsgHookAddr, recvMsgBackupCode);
|
||||||
gIsListening = false;
|
gIsListening = false;
|
||||||
|
UnListenPyq();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DispatchPyq(DWORD reg)
|
||||||
|
{
|
||||||
|
DWORD startAddr = *(DWORD *)(reg + 0x20);
|
||||||
|
DWORD endAddr = *(DWORD *)(reg + 0x24);
|
||||||
|
|
||||||
|
if (startAddr == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (startAddr < endAddr) {
|
||||||
|
WxMsg_t wxMsg;
|
||||||
|
|
||||||
|
wxMsg.type = 0x00; // 朋友圈消息
|
||||||
|
wxMsg.is_self = 0x00;
|
||||||
|
wxMsg.id = GET_QWORD(startAddr);
|
||||||
|
wxMsg.ts = GET_DWORD(startAddr + 0x2C);
|
||||||
|
wxMsg.xml = GetStringByWstrAddr(startAddr + 0x384);
|
||||||
|
wxMsg.sender = GetStringByWstrAddr(startAddr + 0x18);
|
||||||
|
wxMsg.content = GetStringByWstrAddr(startAddr + 0x3C);
|
||||||
|
|
||||||
|
{
|
||||||
|
unique_lock<mutex> lock(gMutex);
|
||||||
|
gMsgQueue.push(wxMsg); // 推送到队列
|
||||||
|
}
|
||||||
|
|
||||||
|
gCV.notify_all(); // 通知各方消息就绪
|
||||||
|
|
||||||
|
startAddr += 0xB48;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__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 + 0x14F9E15;
|
||||||
|
recvPyqCallAddr = g_WeChatWinDllAddr + 0x14FA0A0;
|
||||||
|
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"
|
#include "pb_types.h"
|
||||||
|
|
||||||
|
void ListenPyq();
|
||||||
|
void UnListenPyq();
|
||||||
void ListenMessage();
|
void ListenMessage();
|
||||||
void UnListenMessage();
|
void UnListenMessage();
|
||||||
MsgTypes_t GetMsgTypes();
|
MsgTypes_t GetMsgTypes();
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "pb_types.h"
|
#include "pb_types.h"
|
||||||
#include "pb_util.h"
|
#include "pb_util.h"
|
||||||
|
#include "pyq.h"
|
||||||
#include "receive_msg.h"
|
#include "receive_msg.h"
|
||||||
#include "receive_transfer.h"
|
#include "receive_transfer.h"
|
||||||
#include "rpc_server.h"
|
#include "rpc_server.h"
|
||||||
@ -345,16 +346,18 @@ static void PushMessage()
|
|||||||
if (gCV.wait_for(lock, chrono::milliseconds(1000), []() { return !gMsgQueue.empty(); })) {
|
if (gCV.wait_for(lock, chrono::milliseconds(1000), []() { return !gMsgQueue.empty(); })) {
|
||||||
while (!gMsgQueue.empty()) {
|
while (!gMsgQueue.empty()) {
|
||||||
auto wxmsg = gMsgQueue.front();
|
auto wxmsg = gMsgQueue.front();
|
||||||
|
rsp.msg.wxmsg.id = wxmsg.id;
|
||||||
rsp.msg.wxmsg.is_self = wxmsg.is_self;
|
rsp.msg.wxmsg.is_self = wxmsg.is_self;
|
||||||
rsp.msg.wxmsg.is_group = wxmsg.is_group;
|
rsp.msg.wxmsg.is_group = wxmsg.is_group;
|
||||||
rsp.msg.wxmsg.type = wxmsg.type;
|
rsp.msg.wxmsg.type = wxmsg.type;
|
||||||
rsp.msg.wxmsg.id = (char *)wxmsg.id.c_str();
|
rsp.msg.wxmsg.ts = wxmsg.ts;
|
||||||
rsp.msg.wxmsg.xml = (char *)wxmsg.xml.c_str();
|
|
||||||
rsp.msg.wxmsg.sender = (char *)wxmsg.sender.c_str();
|
|
||||||
rsp.msg.wxmsg.roomid = (char *)wxmsg.roomid.c_str();
|
rsp.msg.wxmsg.roomid = (char *)wxmsg.roomid.c_str();
|
||||||
rsp.msg.wxmsg.content = (char *)wxmsg.content.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.thumb = (char *)wxmsg.thumb.c_str();
|
||||||
rsp.msg.wxmsg.extra = (char *)wxmsg.extra.c_str();
|
rsp.msg.wxmsg.extra = (char *)wxmsg.extra.c_str();
|
||||||
|
rsp.msg.wxmsg.xml = (char *)wxmsg.xml.c_str();
|
||||||
gMsgQueue.pop();
|
gMsgQueue.pop();
|
||||||
LOG_DEBUG("Recv msg: {}", wxmsg.content);
|
LOG_DEBUG("Recv msg: {}", wxmsg.content);
|
||||||
pb_ostream_t stream = pb_ostream_from_buffer(buffer, G_BUF_SIZE);
|
pb_ostream_t stream = pb_ostream_from_buffer(buffer, G_BUF_SIZE);
|
||||||
@ -486,6 +489,24 @@ bool func_receive_transfer(char *wxid, char *tfid, char *taid, uint8_t *out, siz
|
|||||||
return true;
|
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)
|
bool func_decrypt_image(char *src, char *dst, uint8_t *out, size_t *len)
|
||||||
{
|
{
|
||||||
Response rsp = Response_init_default;
|
Response rsp = Response_init_default;
|
||||||
@ -652,6 +673,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);
|
ret = func_receive_transfer(req.msg.tf.wxid, req.msg.tf.tfid, req.msg.tf.taid, out, out_len);
|
||||||
break;
|
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: {
|
case Functions_FUNC_DECRYPT_IMAGE: {
|
||||||
LOG_DEBUG("[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);
|
ret = func_decrypt_image(req.msg.dec.src, req.msg.dec.dst, out, out_len);
|
||||||
|
@ -526,6 +526,22 @@ class Wcf():
|
|||||||
rsp = self._send_request(req)
|
rsp = self._send_request(req)
|
||||||
return rsp.status
|
return rsp.status
|
||||||
|
|
||||||
|
def refresh_pyq(self, id: int) -> int:
|
||||||
|
"""刷新朋友圈
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id (int): 开始 id
|
||||||
|
|
||||||
|
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:
|
def decrypt_image(self, src: str, dst: str) -> bool:
|
||||||
"""解密图片:
|
"""解密图片:
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1,6 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from wcferry import wcf_pb2
|
from wcferry import wcf_pb2
|
||||||
|
|
||||||
@ -24,6 +25,8 @@ class WxMsg():
|
|||||||
self._is_group = msg.is_group
|
self._is_group = msg.is_group
|
||||||
self.type = msg.type
|
self.type = msg.type
|
||||||
self.id = msg.id
|
self.id = msg.id
|
||||||
|
self.ts = msg.ts
|
||||||
|
self.sign = msg.sign
|
||||||
self.xml = msg.xml
|
self.xml = msg.xml
|
||||||
self.sender = msg.sender
|
self.sender = msg.sender
|
||||||
self.roomid = msg.roomid
|
self.roomid = msg.roomid
|
||||||
@ -33,7 +36,8 @@ class WxMsg():
|
|||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
s = f"{'自己发的:' if self._is_self else ''}"
|
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 += self.content
|
||||||
s += f"\n{self.thumb}" if self.thumb else ""
|
s += f"\n{self.thumb}" if self.thumb else ""
|
||||||
s += f"\n{self.extra}" if self.extra else ""
|
s += f"\n{self.extra}" if self.extra else ""
|
||||||
|
Loading…
Reference in New Issue
Block a user