Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
m0_71398851
ComWeChatRobot
提交
c4d8afe5
C
ComWeChatRobot
项目概览
m0_71398851
/
ComWeChatRobot
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
C
ComWeChatRobot
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
c4d8afe5
编写于
6月 24, 2022
作者:
L
ljc545w
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
修复部分已知BUG
上级
d89225dd
变更
10
隐藏空白更改
内联
并排
Showing
10 changed file
with
67 addition
and
54 deletion
+67
-54
DWeChatRobot/HookImageMessage.cpp
DWeChatRobot/HookImageMessage.cpp
+4
-0
DWeChatRobot/ReceiveMessage.cpp
DWeChatRobot/ReceiveMessage.cpp
+29
-18
DWeChatRobot/pch.cpp
DWeChatRobot/pch.cpp
+3
-3
DWeChatRobot/wxapi.h
DWeChatRobot/wxapi.h
+1
-1
DWeChatRobot/wxsocket.cpp
DWeChatRobot/wxsocket.cpp
+5
-1
Python/wxRobot.py
Python/wxRobot.py
+17
-10
README.md
README.md
+8
-21
Release/CWeChatRobot.exe
Release/CWeChatRobot.exe
+0
-0
Release/DWeChatRobot.dll
Release/DWeChatRobot.dll
+0
-0
Release/socket/SWeChatRobot.dll
Release/socket/SWeChatRobot.dll
+0
-0
未找到文件。
DWeChatRobot/HookImageMessage.cpp
浏览文件 @
c4d8afe5
...
...
@@ -2,6 +2,7 @@
#define HookImageMsgAddrOffset 0x61211FF6 - 0x60AE0000
#define HookImageMsgNextCallOffset 0x61211430 - 0x60AE0000
#define AutoDownloadTimeSettingOffset 0x239BC50
BOOL
ImageMsgHooked
=
false
;
static
DWORD
WeChatWinBase
=
GetWeChatWinBase
();
...
...
@@ -74,6 +75,9 @@ void __stdcall HookImageMsg() {
if
(
ImageMsgHooked
)
return
;
HookAnyAddress
(
HookImageMsgAddr
,
dealImageMsg
,
ImageMsgOldAsm
);
char
settime
[]
=
"00:00-23:59"
;
DWORD
AutoDownloadTimeSettingAddr
=
GetWeChatWinBase
()
+
AutoDownloadTimeSettingOffset
;
WriteProcessMemory
(
GetCurrentProcess
(),
(
LPVOID
)
AutoDownloadTimeSettingAddr
,
settime
,
strlen
(
settime
)
+
1
,
0
);
ImageMsgHooked
=
true
;
}
...
...
DWeChatRobot/ReceiveMessage.cpp
浏览文件 @
c4d8afe5
...
...
@@ -28,7 +28,7 @@ struct ScoketMsgStruct {
wchar_t
wxid
[
80
];
wchar_t
message
[
0x1000B
];
wchar_t
filepath
[
MAX_PATH
];
wchar_t
time
[
2
0
];
wchar_t
time
[
3
0
];
};
// 是否开启接收消息HOOK标志
...
...
@@ -52,6 +52,10 @@ DWORD SendMessageJmpBackAddress = SendMessageHookAddress + 0x5;
// 通过socket将消息发送给服务端
BOOL
SendSocketMessage
(
ReceiveMsgStruct
*
ms
)
{
if
(
SRVPORT
==
0
)
{
delete
ms
;
return
false
;
}
SOCKET
clientsocket
=
socket
(
AF_INET
,
SOCK_STREAM
,
IPPROTO_TCP
);
if
(
clientsocket
<
0
)
{
...
...
@@ -85,6 +89,7 @@ BOOL SendSocketMessage(ReceiveMsgStruct* ms)
memcpy
(
sms
->
message
,
ms
->
message
,
ms
->
l_message
*
2
);
memcpy
(
sms
->
filepath
,
ms
->
filepath
,
ms
->
l_filepath
*
2
);
memcpy
(
sms
->
time
,
ms
->
time
,
ms
->
l_time
*
2
);
wcout
<<
sms
->
time
<<
endl
;
int
ret
=
send
(
clientsocket
,
(
char
*
)
sms
,
sizeof
(
ScoketMsgStruct
),
0
);
if
(
ret
==
-
1
||
ret
==
0
)
{
...
...
@@ -147,28 +152,21 @@ static SAFEARRAY* CreateMessageArray(ReceiveMsgStruct* ms) {
}
#endif
/*
* 消息处理函数,根据消息缓冲区组装结构并存入容器
* messageAddr:保存消息的缓冲区地址
* return:void
*/
VOID
ReceiveMessage
(
DWORD
messageAddr
)
{
// 此处用于区别是发送的还是接收的消息
static
void
dealMessage
(
DWORD
messageAddr
)
{
BOOL
isSendMessage
=
*
(
BOOL
*
)(
messageAddr
+
0x3C
);
ReceiveMsgStruct
*
message
=
new
ReceiveMsgStruct
;
ZeroMemory
(
message
,
sizeof
(
ReceiveMsgStruct
));
message
->
isSendMessage
=
isSendMessage
;
message
->
time
=
GetTimeW
();
message
->
time
=
GetTimeW
(
*
(
DWORD
*
)(
messageAddr
+
0x44
)
);
message
->
l_time
=
wcslen
(
message
->
time
);
message
->
messagetype
=
*
(
DWORD
*
)(
messageAddr
+
0x38
);
DWORD
length
=
*
(
DWORD
*
)(
messageAddr
+
0x48
+
0x4
);
message
->
sender
=
new
wchar_t
[
length
+
1
];
ZeroMemory
(
message
->
sender
,
(
length
+
1
)
*
2
);
memcpy
(
message
->
sender
,
(
wchar_t
*
)(
*
(
DWORD
*
)(
messageAddr
+
0x48
)),
length
*
2
);
memcpy
(
message
->
sender
,
(
wchar_t
*
)(
*
(
DWORD
*
)(
messageAddr
+
0x48
)),
length
*
2
);
message
->
l_sender
=
length
;
length
=
*
(
DWORD
*
)(
messageAddr
+
0x170
+
0x4
);
if
(
length
==
0
)
{
message
->
wxid
=
new
wchar_t
[
message
->
l_sender
+
1
];
...
...
@@ -182,7 +180,7 @@ VOID ReceiveMessage(DWORD messageAddr) {
memcpy
(
message
->
wxid
,
(
wchar_t
*
)(
*
(
DWORD
*
)(
messageAddr
+
0x170
)),
length
*
2
);
message
->
l_wxid
=
length
;
}
length
=
*
(
DWORD
*
)(
messageAddr
+
0x70
+
0x4
);
message
->
message
=
new
wchar_t
[
length
+
1
];
ZeroMemory
(
message
->
message
,
(
length
+
1
)
*
2
);
...
...
@@ -202,12 +200,25 @@ VOID ReceiveMessage(DWORD messageAddr) {
V_ARRAY
(
&
vsaValue
)
=
psaValue
;
PostComMessage
(
&
vsaValue
);
#endif
HANDLE
hThread
=
CreateThread
(
NULL
,
0
,(
LPTHREAD_START_ROUTINE
)
SendSocketMessage
,
message
,
NULL
,
0
);
HANDLE
hThread
=
CreateThread
(
NULL
,
0
,
(
LPTHREAD_START_ROUTINE
)
SendSocketMessage
,
message
,
NULL
,
0
);
if
(
hThread
)
{
CloseHandle
(
hThread
);
}
}
/*
* 消息处理函数,根据消息缓冲区组装结构并存入容器
* messageAddr:保存消息的缓冲区地址
* return:void
*/
VOID
ReceiveMessage
(
DWORD
messagesAddr
)
{
// 此处用于区别是发送的还是接收的消息
DWORD
*
messages
=
(
DWORD
*
)
messagesAddr
;
for
(
DWORD
messageAddr
=
messages
[
0
];
messageAddr
<
messages
[
1
];
messageAddr
+=
0x298
)
{
dealMessage
(
messageAddr
);
}
}
/*
* HOOK的具体实现,接收到消息后调用处理函数
...
...
@@ -216,8 +227,8 @@ _declspec(naked) void dealReceiveMessage() {
__asm
{
pushad
;
pushfd
;
mov
eax
,
[
edi
];
push
e
ax
;
//
mov eax, [edi];
push
e
di
;
call
ReceiveMessage
;
add
esp
,
0x4
;
popfd
;
...
...
@@ -235,7 +246,7 @@ _declspec(naked) void dealSendMessage() {
pushad
;
pushfd
;
push
edi
;
call
Receive
Message
;
call
deal
Message
;
add
esp
,
0x4
;
popfd
;
popad
;
...
...
DWeChatRobot/pch.cpp
浏览文件 @
c4d8afe5
...
...
@@ -162,12 +162,12 @@ wstring wreplace(wstring source, wchar_t replaced, wstring replaceto) {
/*
* 获取当前时间
*/
wchar_t
*
GetTimeW
()
{
wchar_t
*
GetTimeW
(
long
long
timestamp
)
{
wchar_t
*
wstr
=
new
wchar_t
[
20
];
memset
(
wstr
,
0
,
20
*
2
);
time_t
cTime
=
time
(
NULL
);
//
time_t cTime = time(NULL);
tm
tm_out
;
localtime_s
(
&
tm_out
,
&
cTime
);
localtime_s
(
&
tm_out
,
&
timestamp
);
swprintf_s
(
wstr
,
20
,
L"%04d-%02d-%02d %02d:%02d:%02d"
,
1900
+
tm_out
.
tm_year
,
tm_out
.
tm_mon
+
1
,
tm_out
.
tm_mday
,
tm_out
.
tm_hour
,
tm_out
.
tm_min
,
tm_out
.
tm_sec
);
...
...
DWeChatRobot/wxapi.h
浏览文件 @
c4d8afe5
...
...
@@ -37,6 +37,6 @@ void UnHookAnyAddress(DWORD dwHookAddr, char* originalRecieveCode);
DLLEXPORT
void
UnHookAll
();
wstring
wreplace
(
wstring
source
,
wchar_t
replaced
,
wstring
replaceto
);
void
PrintProcAddr
();
wchar_t
*
GetTimeW
();
wchar_t
*
GetTimeW
(
long
long
timestamp
);
BOOL
ProcessIsWeChat
();
BOOL
FindOrCreateDirectory
(
const
wchar_t
*
pszPath
);
\ No newline at end of file
DWeChatRobot/wxsocket.cpp
浏览文件 @
c4d8afe5
...
...
@@ -16,8 +16,11 @@ static void fn(struct mg_connection* c, int ev, void* ev_data, void* fn_data) {
if
(
ev
==
MG_EV_HTTP_MSG
)
{
struct
mg_http_message
*
hm
=
(
struct
mg_http_message
*
)
ev_data
,
tmp
=
{
0
};
if
(
mg_http_match_uri
(
hm
,
"/api/test/"
))
{
mg_http_reply
(
c
,
200
,
""
,
"{
\"
result
\"
:
\"
OK
\"
}"
,
0
,
0
);
// cout << hm->method.ptr << endl;
char
*
wxid
=
mg_json_get_str
(
hm
->
body
,
"$.wxid"
);
char
*
msg
=
mg_json_get_str
(
hm
->
body
,
"$.msg"
);
SendText
((
wchar_t
*
)
L"filehelper"
,
(
wchar_t
*
)
L"Ϣ"
);
mg_http_reply
(
c
,
200
,
""
,
"{
\"
result
\"
:
\"
OK
\"
}
\n
"
,
0
,
0
);
}
else
if
(
mg_http_match_uri
(
hm
,
"/api/f2/*"
))
{
mg_printf
(
c
,
"HTTP/1.1 200 OK
\r\n
Transfer-Encoding: chunked
\r\n\r\n
"
);
...
...
@@ -34,6 +37,7 @@ static void fn(struct mg_connection* c, int ev, void* ev_data, void* fn_data) {
}
void
HttpStart
()
{
CreateConsole
();
mg_log_set
(
"2"
);
mg_mgr_init
(
&
mgr
);
mg_http_listen
(
&
mgr
,
s_http_addr
,
fn
,
NULL
);
...
...
Python/wxRobot.py
浏览文件 @
c4d8afe5
...
...
@@ -15,7 +15,8 @@ import socketserver
import
threading
from
comtypes.client
import
GetEvents
from
comtypes.client
import
PumpEvents
class
WeChatEventSink
():
"""
接收消息的默认回调,可以自定义,并将实例化对象作为StartReceiveMsgByEvent参数
...
...
@@ -23,8 +24,7 @@ class WeChatEventSink():
"""
def
OnGetMessageEvent
(
self
,
msg
,
*
args
,
**
kwargs
):
print
(
msg
)
class
ReceviveMsgBaseServer
(
socketserver
.
BaseRequestHandler
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
().
__init__
(
*
args
,
**
kwargs
)
...
...
@@ -36,7 +36,7 @@ class ReceviveMsgBaseServer(socketserver.BaseRequestHandler):
(
"wxid"
,
comtypes
.
c_wchar
*
80
),
(
"message"
,
comtypes
.
c_wchar
*
0x1000B
),
(
"filepath"
,
comtypes
.
c_wchar
*
260
),
(
"time"
,
comtypes
.
c_wchar
*
20
),
(
"time"
,
comtypes
.
c_wchar
*
30
)
]
def
handle
(
self
):
...
...
@@ -44,10 +44,18 @@ class ReceviveMsgBaseServer(socketserver.BaseRequestHandler):
comtypes
.
CoInitialize
()
while
True
:
try
:
ptrdata
=
conn
.
recv
(
comtypes
.
sizeof
(
self
.
ReceiveMsgStruct
))
if
ptrdata
==
'bye'
.
encode
():
break
elif
ptrdata
:
ptrdata
=
conn
.
recv
(
1024
)
try
:
if
ptrdata
.
decode
()
==
'bye'
:
break
except
:
pass
while
len
(
ptrdata
)
<
comtypes
.
sizeof
(
self
.
ReceiveMsgStruct
):
data
=
conn
.
recv
(
1024
)
if
len
(
data
)
==
0
:
break
ptrdata
+=
data
if
ptrdata
:
pReceiveMsgStruct
=
comtypes
.
cast
(
ptrdata
,
comtypes
.
POINTER
(
self
.
ReceiveMsgStruct
))
self
.
msgcallback
(
pReceiveMsgStruct
.
contents
)
response
=
"200 OK"
...
...
@@ -72,7 +80,6 @@ class ReceviveMsgBaseServer(socketserver.BaseRequestHandler):
userinfo
=
robot
.
GetWxUserInfo
(
data
.
sender
)
msg
[
'nickname'
]
=
userinfo
[
'wxNickName'
]
msg
[
'alias'
]
=
userinfo
[
'wxNumber'
]
print
(
msg
)
# TODO: ...
...
...
@@ -572,7 +579,7 @@ class WeChatRobot():
.
"""
if
self
.
robot
.
CStartReceiveMessage
()
!=
0
:
if
self
.
robot
.
CStartReceiveMessage
(
0
)
!=
0
:
return
if
self
.
event
is
not
None
:
sink
=
EventSink
or
WeChatEventSink
()
...
...
README.md
浏览文件 @
c4d8afe5
...
...
@@ -21,24 +21,6 @@ PC微信机器人,实现以下功能:
微信电脑版
**3.7.0.26**
主分支对应微信3.7.0.26版本,其他版本请查看对应分支。
# 写给大家
大家好,最近大家报了好多issue,有的是BUG,有的是问新功能,有的是问如何实现某种功能,看到并且有空的时候就会回复,不过作者没有三头六臂,如果回复不及时还请见谅。
最近填了之前的一些坑,比如数据库无法查询BLOB类型,冗余的接口、缺少的注释,甚至是某个单词拼写错误。。
一些老哥提的需求,也尽可能的往上加了,功能比3.6.0.18又丰富了一些,别的功能,短期是不会添加了,优先解决一些接口导致的崩溃(主要是接收消息),新功能就留到下个微信版本吧。
这几天也一直在着手解决接收消息的bug,不得不说,又学会了一些奇奇怪怪的东西,比如COM的连接点,个人感觉这东西还挺好用的,但COM毕竟是不怎么火的技术,大家想用别的语言实现连接点,资料可能都找不到。
也实现了64位程序注入DLL到32位进程,还有如何使用汇编在内存中构造一个函数。各种花里胡哨。
要是最开始就解决了64位注入32位,可能就根本不会使用COM了。
本来还想在不引入第三方库的情况下,完成http通信,不过想了想,重复发明轮子太耗费脑细胞,等做好说不定微信4.0都出来了。
现在http只有一个测试接口,暂时还不能使用。后面会加上所有功能接口。
一个人搞这个真的很累,有些老哥做了C#、易语言的SDK,感谢你们,有空我会把资源整理一下,写在这里。
也感谢提交BUG的各位,是你们让此项目变得更健壮。
# 编译环境
**Visual Studio 2019**
(平台配置:win32(x86))
# 原理
...
...
@@ -66,11 +48,12 @@ CWeChatRobot.exe /unregserver
**Python:**
参考
[
wxRobot.py
](
/Python/wxRobot.py
)
**C#:**
参考
[
Program.cs
](
/wxRobot/Program.cs
)
参考
[
ComWechatRobotCsharp
](
https://github.com/RingoStudio/ComWechatRobotCsharp
)
,感谢@RingoStudio 的贡献
**ESDK**
参考
[
ESDK
](
/ESDK
)
,感谢@lovezm 的贡献
# 更多功能
后续计划功能:
1.
修改好友备注
2.
优化语音和图片Hook
有空的时候会按照上述顺序进行开发,不过嘛,计划只是计划,如果未实现也请见谅
**也欢迎您提交PR**
...
...
@@ -116,7 +99,11 @@ CWeChatRobot.exe /unregserver
## 2022.06.18
1.
修复了多个BUG
2.
整理代码结构,方便后续开发基于websocket的接口
3.
添加64位程序注入DLL到32位程序的driver
3.
添加64位程序注入DLL到32位程序的driver
## 2022.06.24
1.
解决Python脚本中,socket接收数据可能不完整的问题
2.
解决心跳时如果同步了同一个人的多条消息,只会返回一条的问题
3.
感谢@shangdev 提供的思路,现在开启hook图片的时会修改自动下载图片时段为"00:00-23:59"
# 打赏作者
请给作者一个star,感谢感谢
# 免责声明
...
...
Release/CWeChatRobot.exe
浏览文件 @
c4d8afe5
无法预览此类型文件
Release/DWeChatRobot.dll
浏览文件 @
c4d8afe5
无法预览此类型文件
Release/socket/SWeChatRobot.dll
浏览文件 @
c4d8afe5
无法预览此类型文件
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录