commit
703c2f62d2
@ -1,6 +1,9 @@
|
|||||||
# WeChatFerry
|
# WeChatFerry
|
||||||
一个玩微信的工具。更多介绍见:[WeChatFerry: 一个玩微信的工具](https://mp.weixin.qq.com/s/CGLfSaNDy8MyuyPWGjGJ7w)。
|
一个玩微信的工具。更多介绍见:[WeChatFerry: 一个玩微信的工具](https://mp.weixin.qq.com/s/CGLfSaNDy8MyuyPWGjGJ7w)。
|
||||||
|
|
||||||
|
|[📖 文档](https://wechatferry.readthedocs.io/)|[📺 视频教程](https://mp.weixin.qq.com/s/APdjGyZ2hllXxyG_sNCfXQ)|[🙋 FAQ](https://mp.weixin.qq.com/s/XTJ9H-FsCPCscixAts8i_A)|
|
||||||
|
|:-:|:-:|:-:|
|
||||||
|
|
||||||
👉 [WeChatRobot🤖](https://github.com/lich0821/WeChatRobot),一个基于 WeChatFerry 的 Python 机器人框架。
|
👉 [WeChatRobot🤖](https://github.com/lich0821/WeChatRobot),一个基于 WeChatFerry 的 Python 机器人框架。
|
||||||
|
|
||||||
<details><summary>点击查看功能清单</summary>
|
<details><summary>点击查看功能清单</summary>
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
# WeChatFerry Python 客户端
|
# WeChatFerry Python 客户端
|
||||||
[](https://pypi.python.org/pypi/wcferry) [](https://pypi.python.org/pypi/wcferry) [](https://wechatferry.readthedocs.io/zh/latest/?badge=latest)
|
[](https://pypi.python.org/pypi/wcferry) [](https://pypi.python.org/pypi/wcferry) [](https://wechatferry.readthedocs.io/zh/latest/?badge=latest)
|
||||||
|
|
||||||
|
|[📖 文档](https://wechatferry.readthedocs.io/)|[📺 视频教程](https://mp.weixin.qq.com/s/APdjGyZ2hllXxyG_sNCfXQ)|[🙋 FAQ](https://mp.weixin.qq.com/s/XTJ9H-FsCPCscixAts8i_A)|
|
||||||
|
|:-:|:-:|:-:|
|
||||||
🤖示例机器人框架:[WeChatRobot](https://github.com/lich0821/WeChatRobot)。
|
🤖示例机器人框架:[WeChatRobot](https://github.com/lich0821/WeChatRobot)。
|
||||||
|
|
||||||
## 快速开始
|
## 快速开始
|
||||||
@ -37,7 +39,6 @@ def process_msg(wcf: Wcf):
|
|||||||
def main():
|
def main():
|
||||||
LOG.info("Start demo...")
|
LOG.info("Start demo...")
|
||||||
wcf = Wcf(debug=True) # 默认连接本地服务
|
wcf = Wcf(debug=True) # 默认连接本地服务
|
||||||
# wcf = Wcf("tcp://127.0.0.1:10086") # 连接远端服务
|
|
||||||
|
|
||||||
sleep(5) # 等微信加载好,以免信息显示异常
|
sleep(5) # 等微信加载好,以免信息显示异常
|
||||||
LOG.info(f"已经登录: {True if wcf.is_login() else False}")
|
LOG.info(f"已经登录: {True if wcf.is_login() else False}")
|
||||||
@ -110,10 +111,49 @@ pip install grpcio-tools pynng
|
|||||||
|
|
||||||
### 重新生成 PB 文件
|
### 重新生成 PB 文件
|
||||||
```sh
|
```sh
|
||||||
cd python\wcferry
|
|
||||||
# CMD
|
# CMD
|
||||||
|
cd python\wcferry
|
||||||
python -m grpc_tools.protoc --python_out=. --proto_path=..\..\rpc\proto\ wcf.proto
|
python -m grpc_tools.protoc --python_out=. --proto_path=..\..\rpc\proto\ wcf.proto
|
||||||
|
|
||||||
# GitBash
|
# GitBash
|
||||||
|
cd python/wcferry
|
||||||
python -m grpc_tools.protoc --python_out=. --proto_path=../../rpc/proto/ wcf.proto
|
python -m grpc_tools.protoc --python_out=. --proto_path=../../rpc/proto/ wcf.proto
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 版本更新
|
||||||
|
版本号:`w.x.y.z`。
|
||||||
|
|
||||||
|
其中:
|
||||||
|
* `w` 是微信的大版本号,如 `37` (3.7.a.a), `38` (3.8.a.a), `39` (3.9.a.a)
|
||||||
|
* `x` 是适配的微信的小版本号,从 0 开始
|
||||||
|
* `y` 是 `WeChatFerry` 的版本,从 0 开始
|
||||||
|
* `z` 是各客户端的版本,从 0 开始
|
||||||
|
|
||||||
|
### 37.1.25.5 (2023.05.19)
|
||||||
|
支持 `3.7.0.30` 的最后一个版本。
|
||||||
|
|
||||||
|
功能:
|
||||||
|
|
||||||
|
* 检查登录状态
|
||||||
|
* 获取登录账号的 wxid
|
||||||
|
* 获取消息类型
|
||||||
|
* 获取所有联系人
|
||||||
|
* 获取所有好友
|
||||||
|
* 获取数据库
|
||||||
|
* 获取某数据库下的表
|
||||||
|
* 发送文本消息(可 @)
|
||||||
|
* 发送图片(Python 客户端支持网络路径)
|
||||||
|
* 发送文件
|
||||||
|
* 发送 XML
|
||||||
|
* 发送表情
|
||||||
|
* 允许接收消息
|
||||||
|
* 停止接收消息
|
||||||
|
* 执行 SQL 查询
|
||||||
|
* 接受好友申请
|
||||||
|
* 添加群成员
|
||||||
|
* 解密图片
|
||||||
|
* 某功能
|
||||||
|
|
||||||
|
<details><summary>历史更新</summary>
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#! /usr/bin/env python3
|
#! /usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
__version__ = "37.1.25.5"
|
__version__ = "39.0.0.0"
|
||||||
|
|
||||||
import atexit
|
import atexit
|
||||||
import base64
|
import base64
|
||||||
@ -180,6 +180,8 @@ class Wcf():
|
|||||||
gender = "男"
|
gender = "男"
|
||||||
elif gender == 2:
|
elif gender == 2:
|
||||||
gender = "女"
|
gender = "女"
|
||||||
|
else:
|
||||||
|
gender = ""
|
||||||
contact = {
|
contact = {
|
||||||
"wxid": cnt.get("wxid", ""),
|
"wxid": cnt.get("wxid", ""),
|
||||||
"code": cnt.get("code", ""),
|
"code": cnt.get("code", ""),
|
||||||
@ -502,29 +504,13 @@ class Wcf():
|
|||||||
|
|
||||||
return friends
|
return friends
|
||||||
|
|
||||||
def add_chatroom_members(self, roomid: str, wxids: str) -> int:
|
def receive_transfer(self, wxid: str, transferid: str, transactionid: str) -> int:
|
||||||
"""添加群成员
|
|
||||||
|
|
||||||
Args:
|
|
||||||
roomid (str): 待加群的 id
|
|
||||||
wxids (str): 要加到群里的 wxid,多个用逗号分隔
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
int: 1 为成功,其他失败
|
|
||||||
"""
|
|
||||||
req = wcf_pb2.Request()
|
|
||||||
req.func = wcf_pb2.FUNC_ADD_ROOM_MEMBERS # FUNC_ADD_ROOM_MEMBERS
|
|
||||||
req.m.roomid = roomid
|
|
||||||
req.m.wxids = wxids
|
|
||||||
rsp = self._send_request(req)
|
|
||||||
return rsp.status
|
|
||||||
|
|
||||||
def receive_transfer(self, wxid: str, transferid: str) -> int:
|
|
||||||
"""接收转账
|
"""接收转账
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
wxid (str): 转账消息里的发送人 wxid
|
wxid (str): 转账消息里的发送人 wxid
|
||||||
transferid (str): 转账消息里的 transferid
|
transferid (str): 转账消息里的 transferid
|
||||||
|
transactionid (str): 转账消息里的 transactionid
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
int: 1 为成功,其他失败
|
int: 1 为成功,其他失败
|
||||||
@ -532,7 +518,8 @@ class Wcf():
|
|||||||
req = wcf_pb2.Request()
|
req = wcf_pb2.Request()
|
||||||
req.func = wcf_pb2.FUNC_RECV_TRANSFER # FUNC_RECV_TRANSFER
|
req.func = wcf_pb2.FUNC_RECV_TRANSFER # FUNC_RECV_TRANSFER
|
||||||
req.tf.wxid = wxid
|
req.tf.wxid = wxid
|
||||||
req.tf.tid = transferid
|
req.tf.tfid = transferid
|
||||||
|
req.tf.taid = transactionid
|
||||||
rsp = self._send_request(req)
|
rsp = self._send_request(req)
|
||||||
return rsp.status
|
return rsp.status
|
||||||
|
|
||||||
@ -552,3 +539,37 @@ class Wcf():
|
|||||||
req.dec.dst = dst
|
req.dec.dst = dst
|
||||||
rsp = self._send_request(req)
|
rsp = self._send_request(req)
|
||||||
return rsp.status == 1
|
return rsp.status == 1
|
||||||
|
|
||||||
|
def add_chatroom_members(self, roomid: str, wxids: str) -> int:
|
||||||
|
"""添加群成员
|
||||||
|
|
||||||
|
Args:
|
||||||
|
roomid (str): 待加群的 id
|
||||||
|
wxids (str): 要加到群里的 wxid,多个用逗号分隔
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: 1 为成功,其他失败
|
||||||
|
"""
|
||||||
|
req = wcf_pb2.Request()
|
||||||
|
req.func = wcf_pb2.FUNC_ADD_ROOM_MEMBERS # FUNC_ADD_ROOM_MEMBERS
|
||||||
|
req.m.roomid = roomid
|
||||||
|
req.m.wxids = wxids
|
||||||
|
rsp = self._send_request(req)
|
||||||
|
return rsp.status
|
||||||
|
|
||||||
|
def del_chatroom_members(self, roomid: str, wxids: str) -> int:
|
||||||
|
"""删除群成员
|
||||||
|
|
||||||
|
Args:
|
||||||
|
roomid (str): 群的 id
|
||||||
|
wxids (str): 要删除成员的 wxid,多个用逗号分隔
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: 1 为成功,其他失败
|
||||||
|
"""
|
||||||
|
req = wcf_pb2.Request()
|
||||||
|
req.func = wcf_pb2.FUNC_DEL_ROOM_MEMBERS # FUNC_DEL_ROOM_MEMBERS
|
||||||
|
req.m.roomid = roomid
|
||||||
|
req.m.wxids = wxids.replace(" ", "")
|
||||||
|
rsp = self._send_request(req)
|
||||||
|
return rsp.status
|
||||||
|
|||||||
@ -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\"%\n\x08Transfer\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x0b\n\x03tid\x18\x02 \x01(\t*\xd3\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\x19\n\x15\x46UNC_ADD_ROOM_MEMBERS\x10R\x12\x16\n\x12\x46UNC_RECV_TRANSFER\x10S\x12\x16\n\x12\x46UNC_DECRYPT_IMAGE\x10`B\r\n\x0b\x63om.iamteerb\x06proto3')
|
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')
|
||||||
|
|
||||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
|
||||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'wcf_pb2', globals())
|
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'wcf_pb2', globals())
|
||||||
@ -23,8 +23,8 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|||||||
DESCRIPTOR._serialized_options = b'\n\013com.iamteer'
|
DESCRIPTOR._serialized_options = b'\n\013com.iamteer'
|
||||||
_MSGTYPES_TYPESENTRY._options = None
|
_MSGTYPES_TYPESENTRY._options = None
|
||||||
_MSGTYPES_TYPESENTRY._serialized_options = b'8\001'
|
_MSGTYPES_TYPESENTRY._serialized_options = b'8\001'
|
||||||
_FUNCTIONS._serialized_start=1805
|
_FUNCTIONS._serialized_start=1820
|
||||||
_FUNCTIONS._serialized_end=2272
|
_FUNCTIONS._serialized_end=2314
|
||||||
_REQUEST._serialized_start=19
|
_REQUEST._serialized_start=19
|
||||||
_REQUEST._serialized_end=347
|
_REQUEST._serialized_end=347
|
||||||
_RESPONSE._serialized_start=350
|
_RESPONSE._serialized_start=350
|
||||||
@ -70,5 +70,5 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|||||||
_DECPATH._serialized_start=1728
|
_DECPATH._serialized_start=1728
|
||||||
_DECPATH._serialized_end=1763
|
_DECPATH._serialized_end=1763
|
||||||
_TRANSFER._serialized_start=1765
|
_TRANSFER._serialized_start=1765
|
||||||
_TRANSFER._serialized_end=1802
|
_TRANSFER._serialized_end=1817
|
||||||
# @@protoc_insertion_point(module_scope)
|
# @@protoc_insertion_point(module_scope)
|
||||||
|
|||||||
@ -21,9 +21,10 @@ enum Functions {
|
|||||||
FUNC_DISABLE_RECV_TXT = 0x40;
|
FUNC_DISABLE_RECV_TXT = 0x40;
|
||||||
FUNC_EXEC_DB_QUERY = 0x50;
|
FUNC_EXEC_DB_QUERY = 0x50;
|
||||||
FUNC_ACCEPT_FRIEND = 0x51;
|
FUNC_ACCEPT_FRIEND = 0x51;
|
||||||
FUNC_ADD_ROOM_MEMBERS = 0x52;
|
FUNC_RECV_TRANSFER = 0x52;
|
||||||
FUNC_RECV_TRANSFER = 0x53;
|
|
||||||
FUNC_DECRYPT_IMAGE = 0x60;
|
FUNC_DECRYPT_IMAGE = 0x60;
|
||||||
|
FUNC_ADD_ROOM_MEMBERS = 0x70;
|
||||||
|
FUNC_DEL_ROOM_MEMBERS = 0x71;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Request
|
message Request
|
||||||
@ -167,5 +168,6 @@ message DecPath
|
|||||||
message Transfer
|
message Transfer
|
||||||
{
|
{
|
||||||
string wxid = 1; // 转账人
|
string wxid = 1; // 转账人
|
||||||
string tid = 2; // 转账id transferid
|
string tfid = 2; // 转账id transferid
|
||||||
|
string taid = 3; // Transaction id
|
||||||
}
|
}
|
||||||
|
|||||||
@ -88,3 +88,35 @@ bool CallDllFunc(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcNa
|
|||||||
CloseHandle(hThread);
|
CloseHandle(hThread);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CallDllFuncEx(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, LPVOID parameter, size_t sz,
|
||||||
|
DWORD *ret)
|
||||||
|
{
|
||||||
|
void *pFunc = GetFuncAddr(dllPath, dllBase, funcName);
|
||||||
|
if (pFunc == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LPVOID pRemoteAddress = VirtualAllocEx(process, NULL, sz, MEM_COMMIT, PAGE_READWRITE);
|
||||||
|
if (pRemoteAddress == NULL) {
|
||||||
|
MessageBox(NULL, L"申请内存失败", L"CallDllFuncEx", 0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteProcessMemory(process, pRemoteAddress, parameter, sz, NULL);
|
||||||
|
|
||||||
|
HANDLE hThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, pRemoteAddress, 0, NULL);
|
||||||
|
if (hThread == NULL) {
|
||||||
|
VirtualFree(pRemoteAddress, 0, MEM_RELEASE);
|
||||||
|
MessageBox(NULL, L"远程调用失败", L"CallDllFuncEx", 0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
WaitForSingleObject(hThread, INFINITE);
|
||||||
|
VirtualFree(pRemoteAddress, 0, MEM_RELEASE);
|
||||||
|
if (ret != NULL) {
|
||||||
|
GetExitCodeThread(hThread, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(hThread);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@ -5,3 +5,5 @@
|
|||||||
HANDLE InjectDll(DWORD pid, LPCWSTR dllPath, HMODULE *injectedBase);
|
HANDLE InjectDll(DWORD pid, LPCWSTR dllPath, HMODULE *injectedBase);
|
||||||
bool EjectDll(HANDLE process, HMODULE dllBase);
|
bool EjectDll(HANDLE process, HMODULE dllBase);
|
||||||
bool CallDllFunc(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, LPVOID parameter, DWORD *ret);
|
bool CallDllFunc(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, LPVOID parameter, DWORD *ret);
|
||||||
|
bool CallDllFuncEx(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, LPVOID parameter, size_t sz,
|
||||||
|
DWORD *ret);
|
||||||
|
|||||||
29
sdk/sdk.cpp
29
sdk/sdk.cpp
@ -1,10 +1,10 @@
|
|||||||
#include "Shlwapi.h"
|
#include "Shlwapi.h"
|
||||||
#include "framework.h"
|
#include "framework.h"
|
||||||
|
#include <filesystem>
|
||||||
#include <process.h>
|
#include <process.h>
|
||||||
#include <tlhelp32.h>
|
#include <tlhelp32.h>
|
||||||
|
|
||||||
#include "injector.h"
|
#include "injector.h"
|
||||||
#include "log.h"
|
|
||||||
#include "sdk.h"
|
#include "sdk.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
@ -17,7 +17,6 @@ static WCHAR spyDllPath[MAX_PATH] = { 0 };
|
|||||||
|
|
||||||
static int GetDllPath(bool debug, wchar_t *dllPath)
|
static int GetDllPath(bool debug, wchar_t *dllPath)
|
||||||
{
|
{
|
||||||
InitLogger();
|
|
||||||
GetModuleFileName(GetModuleHandle(WECHATSDKDLL), spyDllPath, MAX_PATH);
|
GetModuleFileName(GetModuleHandle(WECHATSDKDLL), spyDllPath, MAX_PATH);
|
||||||
PathRemoveFileSpec(spyDllPath);
|
PathRemoveFileSpec(spyDllPath);
|
||||||
if (debug) {
|
if (debug) {
|
||||||
@ -27,7 +26,7 @@ static int GetDllPath(bool debug, wchar_t *dllPath)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!PathFileExists(spyDllPath)) {
|
if (!PathFileExists(spyDllPath)) {
|
||||||
LOG_ERROR("DLL does not exists: {}.", Wstring2String(spyDllPath));
|
MessageBox(NULL, spyDllPath, L"文件不存在", 0);
|
||||||
return ERROR_FILE_NOT_FOUND;
|
return ERROR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,26 +45,30 @@ int WxInitSDK(bool debug, int port)
|
|||||||
|
|
||||||
status = OpenWeChat(&wcPid);
|
status = OpenWeChat(&wcPid);
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
LOG_ERROR("OpenWeChat failed: {}.", status);
|
MessageBox(NULL, L"打开微信失败", L"WxInitSDK", 0);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
Sleep(2000); // 等待微信打开
|
Sleep(2000); // 等待微信打开
|
||||||
wcProcess = InjectDll(wcPid, spyDllPath, &spyBase);
|
wcProcess = InjectDll(wcPid, spyDllPath, &spyBase);
|
||||||
if (wcProcess == NULL) {
|
if (wcProcess == NULL) {
|
||||||
LOG_ERROR("Failed to Inject DLL into WeChat.");
|
MessageBox(NULL, L"注入失败", L"WxInitSDK", 0);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CallDllFunc(wcProcess, spyDllPath, spyBase, "InitSpy", (LPVOID)port, NULL)) {
|
PortPath_t pp = { 0 };
|
||||||
LOG_ERROR("Failed to InitSpy.");
|
pp.port = port;
|
||||||
|
sprintf_s(pp.path, MAX_PATH, "%s", std::filesystem::current_path().string().c_str());
|
||||||
|
|
||||||
|
if (!CallDllFuncEx(wcProcess, spyDllPath, spyBase, "InitSpy", (LPVOID)&pp, sizeof(PortPath_t), NULL)) {
|
||||||
|
MessageBox(NULL, L"初始化失败", L"WxInitSDK", 0);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WCF
|
#ifdef WCF
|
||||||
FILE *fd = fopen(WCF_LOCK, "wb");
|
FILE *fd = fopen(WCF_LOCK, "wb");
|
||||||
if (fd == NULL) {
|
if (fd == NULL) {
|
||||||
LOG_ERROR("Failed to open {}.", WCF_LOCK);
|
MessageBox(NULL, L"无法打开lock文件", L"WxInitSDK", 0);
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
fwrite((uint8_t *)&debug, sizeof(debug), 1, fd);
|
fwrite((uint8_t *)&debug, sizeof(debug), 1, fd);
|
||||||
@ -83,19 +86,19 @@ int WxDestroySDK()
|
|||||||
bool debug;
|
bool debug;
|
||||||
DWORD pid = GetWeChatPid();
|
DWORD pid = GetWeChatPid();
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
LOG_ERROR("WeChat is not running.");
|
MessageBox(NULL, L"微信未运行", L"WxDestroySDK", 0);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
wcProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
|
wcProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
|
||||||
if (wcProcess == NULL) {
|
if (wcProcess == NULL) {
|
||||||
LOG_ERROR("WeChat is not running.");
|
MessageBox(NULL, L"微信未运行", L"WxDestroySDK", 0);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *fd = fopen(WCF_LOCK, "rb");
|
FILE *fd = fopen(WCF_LOCK, "rb");
|
||||||
if (fd == NULL) {
|
if (fd == NULL) {
|
||||||
LOG_ERROR("Failed to open {}.", WCF_LOCK);
|
MessageBox(NULL, L"无法打开lock文件", L"WxDestroySDK", 0);
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
fread((uint8_t *)&debug, sizeof(debug), 1, fd);
|
fread((uint8_t *)&debug, sizeof(debug), 1, fd);
|
||||||
@ -111,14 +114,12 @@ int WxDestroySDK()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!CallDllFunc(wcProcess, spyDllPath, spyBase, "CleanupSpy", NULL, NULL)) {
|
if (!CallDllFunc(wcProcess, spyDllPath, spyBase, "CleanupSpy", NULL, NULL)) {
|
||||||
LOG_ERROR("Failed to CleanupSpy.");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!EjectDll(wcProcess, spyBase)) {
|
if (!EjectDll(wcProcess, spyBase)) {
|
||||||
LOG_ERROR("Failed to Eject DLL.");
|
|
||||||
return -1; // TODO: Unify error codes
|
return -1; // TODO: Unify error codes
|
||||||
}
|
}
|
||||||
LOG_INFO("WxDestroySDK done.");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -107,7 +107,7 @@
|
|||||||
</PrecompiledHeaderFile>
|
</PrecompiledHeaderFile>
|
||||||
<AdditionalIncludeDirectories>$(SolutionDir)rpc;$(SolutionDir)rpc\nanopb;$(SolutionDir)rpc\proto;$(SolutionDir)spy;C:\Tools\vcpkg\installed\x86-windows-static\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(SolutionDir)rpc;$(SolutionDir)rpc\nanopb;$(SolutionDir)rpc\proto;$(SolutionDir)spy;C:\Tools\vcpkg\installed\x86-windows-static\include</AdditionalIncludeDirectories>
|
||||||
<PrecompiledHeaderOutputFile />
|
<PrecompiledHeaderOutputFile />
|
||||||
<DisableSpecificWarnings>4251;4819</DisableSpecificWarnings>
|
<DisableSpecificWarnings>4251;4731;4819</DisableSpecificWarnings>
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||||
<AdditionalOptions>/EHa %(AdditionalOptions)</AdditionalOptions>
|
<AdditionalOptions>/EHa %(AdditionalOptions)</AdditionalOptions>
|
||||||
@ -153,7 +153,7 @@ $(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto</Command>
|
|||||||
</PrecompiledHeaderFile>
|
</PrecompiledHeaderFile>
|
||||||
<AdditionalIncludeDirectories>$(SolutionDir)rpc;$(SolutionDir)rpc\nanopb;$(SolutionDir)rpc\proto;$(SolutionDir)spy;C:\Tools\vcpkg\installed\x86-windows-static\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(SolutionDir)rpc;$(SolutionDir)rpc\nanopb;$(SolutionDir)rpc\proto;$(SolutionDir)spy;C:\Tools\vcpkg\installed\x86-windows-static\include</AdditionalIncludeDirectories>
|
||||||
<PrecompiledHeaderOutputFile />
|
<PrecompiledHeaderOutputFile />
|
||||||
<DisableSpecificWarnings>4251;4819</DisableSpecificWarnings>
|
<DisableSpecificWarnings>4251;4731;4819</DisableSpecificWarnings>
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@ -226,12 +226,11 @@ $(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto</Command>
|
|||||||
<ClInclude Include="..\rpc\pb_types.h" />
|
<ClInclude Include="..\rpc\pb_types.h" />
|
||||||
<ClInclude Include="..\rpc\pb_util.h" />
|
<ClInclude Include="..\rpc\pb_util.h" />
|
||||||
<ClInclude Include="..\rpc\proto\wcf.pb.h" />
|
<ClInclude Include="..\rpc\proto\wcf.pb.h" />
|
||||||
<ClInclude Include="accept_new_friend.h" />
|
<ClInclude Include="chatroom_mgmt.h" />
|
||||||
<ClInclude Include="add_chatroom_member.h" />
|
|
||||||
<ClInclude Include="decrypt_image.h" />
|
<ClInclude Include="decrypt_image.h" />
|
||||||
<ClInclude Include="exec_sql.h" />
|
<ClInclude Include="exec_sql.h" />
|
||||||
<ClInclude Include="framework.h" />
|
<ClInclude Include="framework.h" />
|
||||||
<ClInclude Include="get_contacts.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="receive_msg.h" />
|
<ClInclude Include="receive_msg.h" />
|
||||||
@ -241,6 +240,7 @@ $(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto</Command>
|
|||||||
<ClInclude Include="send_msg.h" />
|
<ClInclude Include="send_msg.h" />
|
||||||
<ClInclude Include="spy.h" />
|
<ClInclude Include="spy.h" />
|
||||||
<ClInclude Include="spy_types.h" />
|
<ClInclude Include="spy_types.h" />
|
||||||
|
<ClInclude Include="sqlite3.h" />
|
||||||
<ClInclude Include="user_info.h" />
|
<ClInclude Include="user_info.h" />
|
||||||
<ClInclude Include="util.h" />
|
<ClInclude Include="util.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@ -250,12 +250,11 @@ $(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto</Command>
|
|||||||
<ClCompile Include="..\rpc\nanopb\pb_encode.c" />
|
<ClCompile Include="..\rpc\nanopb\pb_encode.c" />
|
||||||
<ClCompile Include="..\rpc\pb_util.cpp" />
|
<ClCompile Include="..\rpc\pb_util.cpp" />
|
||||||
<ClCompile Include="..\rpc\proto\wcf.pb.c" />
|
<ClCompile Include="..\rpc\proto\wcf.pb.c" />
|
||||||
<ClCompile Include="accept_new_friend.cpp" />
|
<ClCompile Include="chatroom_mgmt.cpp" />
|
||||||
<ClCompile Include="add_chatroom_member.cpp" />
|
|
||||||
<ClCompile Include="decrypt_image.cpp" />
|
<ClCompile Include="decrypt_image.cpp" />
|
||||||
<ClCompile Include="dllmain.cpp" />
|
<ClCompile Include="dllmain.cpp" />
|
||||||
<ClCompile Include="exec_sql.cpp" />
|
<ClCompile Include="exec_sql.cpp" />
|
||||||
<ClCompile Include="get_contacts.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="receive_msg.cpp" />
|
<ClCompile Include="receive_msg.cpp" />
|
||||||
|
|||||||
@ -27,13 +27,10 @@
|
|||||||
<ClInclude Include="log.h">
|
<ClInclude Include="log.h">
|
||||||
<Filter>头文件</Filter>
|
<Filter>头文件</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="accept_new_friend.h">
|
|
||||||
<Filter>头文件</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="exec_sql.h">
|
<ClInclude Include="exec_sql.h">
|
||||||
<Filter>头文件</Filter>
|
<Filter>头文件</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="get_contacts.h">
|
<ClInclude Include="contact_mgmt.h">
|
||||||
<Filter>头文件</Filter>
|
<Filter>头文件</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="load_calls.h">
|
<ClInclude Include="load_calls.h">
|
||||||
@ -75,7 +72,7 @@
|
|||||||
<ClInclude Include="..\rpc\pb_types.h">
|
<ClInclude Include="..\rpc\pb_types.h">
|
||||||
<Filter>nnrpc</Filter>
|
<Filter>nnrpc</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="add_chatroom_member.h">
|
<ClInclude Include="chatroom_mgmt.h">
|
||||||
<Filter>头文件</Filter>
|
<Filter>头文件</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="user_info.h">
|
<ClInclude Include="user_info.h">
|
||||||
@ -90,6 +87,9 @@
|
|||||||
<ClInclude Include="receive_transfer.h">
|
<ClInclude Include="receive_transfer.h">
|
||||||
<Filter>头文件</Filter>
|
<Filter>头文件</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="sqlite3.h">
|
||||||
|
<Filter>头文件</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="dllmain.cpp">
|
<ClCompile Include="dllmain.cpp">
|
||||||
@ -101,13 +101,10 @@
|
|||||||
<ClCompile Include="log.cpp">
|
<ClCompile Include="log.cpp">
|
||||||
<Filter>源文件</Filter>
|
<Filter>源文件</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="accept_new_friend.cpp">
|
|
||||||
<Filter>源文件</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="exec_sql.cpp">
|
<ClCompile Include="exec_sql.cpp">
|
||||||
<Filter>源文件</Filter>
|
<Filter>源文件</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="get_contacts.cpp">
|
<ClCompile Include="contact_mgmt.cpp">
|
||||||
<Filter>源文件</Filter>
|
<Filter>源文件</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="load_calls.cpp">
|
<ClCompile Include="load_calls.cpp">
|
||||||
@ -140,7 +137,7 @@
|
|||||||
<ClCompile Include="..\rpc\pb_util.cpp">
|
<ClCompile Include="..\rpc\pb_util.cpp">
|
||||||
<Filter>nnrpc</Filter>
|
<Filter>nnrpc</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="add_chatroom_member.cpp">
|
<ClCompile Include="chatroom_mgmt.cpp">
|
||||||
<Filter>源文件</Filter>
|
<Filter>源文件</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="user_info.cpp">
|
<ClCompile Include="user_info.cpp">
|
||||||
|
|||||||
@ -1,76 +0,0 @@
|
|||||||
#include "framework.h"
|
|
||||||
|
|
||||||
#include "accept_new_friend.h"
|
|
||||||
#include "load_calls.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
typedef struct NewFriendParam {
|
|
||||||
DWORD handle;
|
|
||||||
DWORD *status;
|
|
||||||
DWORD statusEnd1;
|
|
||||||
DWORD statusEnd2;
|
|
||||||
char buffer[0x3C];
|
|
||||||
} NewFriendParam_t;
|
|
||||||
|
|
||||||
extern WxCalls_t g_WxCalls;
|
|
||||||
extern DWORD g_WeChatWinDllAddr;
|
|
||||||
|
|
||||||
int AcceptNewFriend(std::string v3, std::string v4, int scene)
|
|
||||||
{
|
|
||||||
int isSucceeded = 0;
|
|
||||||
|
|
||||||
DWORD acceptNewFriendCall1 = g_WeChatWinDllAddr + g_WxCalls.anf.call1;
|
|
||||||
DWORD acceptNewFriendCall2 = g_WeChatWinDllAddr + g_WxCalls.anf.call2;
|
|
||||||
DWORD acceptNewFriendHandle = g_WeChatWinDllAddr + g_WxCalls.anf.handle;
|
|
||||||
|
|
||||||
char buffer[0x94] = { 0 };
|
|
||||||
NewFriendParam_t param = { 0 };
|
|
||||||
DWORD status[9] = { 0xB2, (DWORD)¶m, 0xB5, (DWORD)¶m, 0xB0, (DWORD)¶m, 0xB1, (DWORD)¶m, 0x00 };
|
|
||||||
|
|
||||||
param.handle = acceptNewFriendHandle;
|
|
||||||
param.status = status;
|
|
||||||
param.statusEnd1 = (DWORD)status + 0x20;
|
|
||||||
param.statusEnd2 = (DWORD)status + 0x20;
|
|
||||||
NewFriendParam_t *pParam = ¶m;
|
|
||||||
|
|
||||||
LOG_DEBUG("v3: {}\nv4: {}", v3, v4);
|
|
||||||
WxString_t wxV3 = { 0 };
|
|
||||||
WxString_t wxV4 = { 0 };
|
|
||||||
std::wstring wsV3 = String2Wstring(v3);
|
|
||||||
std::wstring wsV4 = String2Wstring(v4);
|
|
||||||
|
|
||||||
wxV3.text = (wchar_t *)wsV3.c_str();
|
|
||||||
wxV3.size = wsV3.size();
|
|
||||||
wxV3.capacity = wsV3.capacity();
|
|
||||||
|
|
||||||
wxV4.text = (wchar_t *)wsV4.c_str();
|
|
||||||
wxV4.size = wsV4.size();
|
|
||||||
wxV4.capacity = wsV4.capacity();
|
|
||||||
|
|
||||||
__asm {
|
|
||||||
pushad;
|
|
||||||
pushfd;
|
|
||||||
push 0x0;
|
|
||||||
mov eax, scene;
|
|
||||||
push eax;
|
|
||||||
sub esp, 0x14;
|
|
||||||
mov ecx, esp;
|
|
||||||
lea eax, wxV4;
|
|
||||||
push eax;
|
|
||||||
call acceptNewFriendCall1;
|
|
||||||
sub esp, 0x8;
|
|
||||||
push 0x0;
|
|
||||||
lea eax, buffer;
|
|
||||||
push eax;
|
|
||||||
lea eax, wxV3;
|
|
||||||
push eax;
|
|
||||||
mov ecx, pParam;
|
|
||||||
call acceptNewFriendCall2;
|
|
||||||
mov isSucceeded, eax;
|
|
||||||
popfd;
|
|
||||||
popad;
|
|
||||||
}
|
|
||||||
|
|
||||||
return isSucceeded; // 成功返回 1
|
|
||||||
}
|
|
||||||
@ -1,67 +0,0 @@
|
|||||||
#include "framework.h"
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include "add_chatroom_member.h"
|
|
||||||
#include "load_calls.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
extern WxCalls_t g_WxCalls;
|
|
||||||
extern DWORD g_WeChatWinDllAddr;
|
|
||||||
|
|
||||||
int AddChatroomMember(string roomid, string wxids)
|
|
||||||
{
|
|
||||||
if (roomid.empty() || wxids.empty()) {
|
|
||||||
LOG_ERROR("Empty roomid or wxids.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int rv = 0;
|
|
||||||
DWORD addRoomMemberCall1 = g_WeChatWinDllAddr + g_WxCalls.arm.call1;
|
|
||||||
DWORD addRoomMemberCall2 = g_WeChatWinDllAddr + g_WxCalls.arm.call2;
|
|
||||||
DWORD addRoomMemberCall3 = g_WeChatWinDllAddr + g_WxCalls.arm.call3;
|
|
||||||
|
|
||||||
WxString_t txtRoomid = { 0 };
|
|
||||||
wstring wsRoomid = String2Wstring(roomid);
|
|
||||||
txtRoomid.text = (wchar_t *)wsRoomid.c_str();
|
|
||||||
txtRoomid.size = wsRoomid.size();
|
|
||||||
txtRoomid.capacity = wsRoomid.capacity();
|
|
||||||
|
|
||||||
vector<wstring> vMembers;
|
|
||||||
vector<WxString_t> vTxtMembers;
|
|
||||||
wstringstream wss(String2Wstring(wxids));
|
|
||||||
while (wss.good()) {
|
|
||||||
wstring wstr;
|
|
||||||
getline(wss, wstr, L',');
|
|
||||||
vMembers.push_back(wstr);
|
|
||||||
WxString_t txtMember = { 0 };
|
|
||||||
txtMember.text = (wchar_t *)vMembers.back().c_str();
|
|
||||||
txtMember.size = vMembers.back().size();
|
|
||||||
txtMember.capacity = vMembers.back().capacity();
|
|
||||||
vTxtMembers.push_back(txtMember);
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DEBUG("Adding {} members[{}] to {}", vTxtMembers.size(), wxids.c_str(), roomid.c_str());
|
|
||||||
__asm {
|
|
||||||
pushad;
|
|
||||||
pushfd;
|
|
||||||
call addRoomMemberCall1;
|
|
||||||
sub esp, 0x14;
|
|
||||||
mov esi, eax;
|
|
||||||
mov ecx, esp;
|
|
||||||
lea eax, txtRoomid;
|
|
||||||
push eax;
|
|
||||||
call addRoomMemberCall2;
|
|
||||||
lea edi, vTxtMembers
|
|
||||||
push edi;
|
|
||||||
mov ecx, esi;
|
|
||||||
call addRoomMemberCall3;
|
|
||||||
mov rv, eax;
|
|
||||||
popfd;
|
|
||||||
popad;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
128
spy/chatroom_mgmt.cpp
Normal file
128
spy/chatroom_mgmt.cpp
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
#include "framework.h"
|
||||||
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "chatroom_mgmt.h"
|
||||||
|
#include "load_calls.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
extern WxCalls_t g_WxCalls;
|
||||||
|
extern DWORD g_WeChatWinDllAddr;
|
||||||
|
|
||||||
|
int AddChatroomMember(string roomid, string wxids)
|
||||||
|
{
|
||||||
|
if (roomid.empty() || wxids.empty()) {
|
||||||
|
LOG_ERROR("Empty roomid or wxids.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rv = 0;
|
||||||
|
DWORD addRoomMemberCall1 = g_WeChatWinDllAddr + g_WxCalls.arm.call1;
|
||||||
|
DWORD addRoomMemberCall2 = g_WeChatWinDllAddr + g_WxCalls.arm.call2;
|
||||||
|
DWORD addRoomMemberCall3 = g_WeChatWinDllAddr + g_WxCalls.arm.call3;
|
||||||
|
|
||||||
|
DWORD temp = 0;
|
||||||
|
WxString_t txtRoomid = { 0 };
|
||||||
|
wstring wsRoomid = String2Wstring(roomid);
|
||||||
|
txtRoomid.text = (wchar_t *)wsRoomid.c_str();
|
||||||
|
txtRoomid.size = wsRoomid.size();
|
||||||
|
txtRoomid.capacity = wsRoomid.capacity();
|
||||||
|
|
||||||
|
vector<wstring> vMembers;
|
||||||
|
vector<WxString_t> vTxtMembers;
|
||||||
|
wstringstream wss(String2Wstring(wxids));
|
||||||
|
while (wss.good()) {
|
||||||
|
wstring wstr;
|
||||||
|
getline(wss, wstr, L',');
|
||||||
|
vMembers.push_back(wstr);
|
||||||
|
WxString_t txtMember = { 0 };
|
||||||
|
txtMember.text = (wchar_t *)vMembers.back().c_str();
|
||||||
|
txtMember.size = vMembers.back().size();
|
||||||
|
txtMember.capacity = vMembers.back().capacity();
|
||||||
|
vTxtMembers.push_back(txtMember);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG("Adding {} members[{}] to {}", vTxtMembers.size(), wxids.c_str(), roomid.c_str());
|
||||||
|
__asm {
|
||||||
|
pushad;
|
||||||
|
pushfd;
|
||||||
|
call addRoomMemberCall1;
|
||||||
|
sub esp, 0x8;
|
||||||
|
mov temp, eax;
|
||||||
|
mov ecx, esp;
|
||||||
|
mov dword ptr[ecx], 0x0;
|
||||||
|
mov dword ptr[ecx + 4], 0x0;
|
||||||
|
test esi, esi;
|
||||||
|
sub esp, 0x14;
|
||||||
|
mov ecx, esp;
|
||||||
|
lea eax, txtRoomid;
|
||||||
|
push eax;
|
||||||
|
call addRoomMemberCall2;
|
||||||
|
mov ecx, temp;
|
||||||
|
lea eax, vTxtMembers;
|
||||||
|
push eax;
|
||||||
|
call addRoomMemberCall3;
|
||||||
|
mov rv, eax;
|
||||||
|
popfd;
|
||||||
|
popad;
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DelChatroomMember(string roomid, string wxids)
|
||||||
|
{
|
||||||
|
if (roomid.empty() || wxids.empty()) {
|
||||||
|
LOG_ERROR("Empty roomid or wxids.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rv = 0;
|
||||||
|
DWORD delRoomMemberCall1 = g_WeChatWinDllAddr + g_WxCalls.drm.call1;
|
||||||
|
DWORD delRoomMemberCall2 = g_WeChatWinDllAddr + g_WxCalls.drm.call2;
|
||||||
|
DWORD delRoomMemberCall3 = g_WeChatWinDllAddr + g_WxCalls.drm.call3;
|
||||||
|
|
||||||
|
DWORD temp = 0;
|
||||||
|
WxString_t txtRoomid = { 0 };
|
||||||
|
wstring wsRoomid = String2Wstring(roomid);
|
||||||
|
txtRoomid.text = (wchar_t *)wsRoomid.c_str();
|
||||||
|
txtRoomid.size = wsRoomid.size();
|
||||||
|
txtRoomid.capacity = wsRoomid.capacity();
|
||||||
|
|
||||||
|
vector<wstring> vMembers;
|
||||||
|
vector<WxString_t> vTxtMembers;
|
||||||
|
wstringstream wss(String2Wstring(wxids));
|
||||||
|
while (wss.good()) {
|
||||||
|
wstring wstr;
|
||||||
|
getline(wss, wstr, L',');
|
||||||
|
vMembers.push_back(wstr);
|
||||||
|
WxString_t txtMember = { 0 };
|
||||||
|
txtMember.text = (wchar_t *)vMembers.back().c_str();
|
||||||
|
txtMember.size = vMembers.back().size();
|
||||||
|
txtMember.capacity = vMembers.back().capacity();
|
||||||
|
vTxtMembers.push_back(txtMember);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG("Adding {} members[{}] to {}", vTxtMembers.size(), wxids.c_str(), roomid.c_str());
|
||||||
|
__asm {
|
||||||
|
pushad;
|
||||||
|
pushfd;
|
||||||
|
call delRoomMemberCall1;
|
||||||
|
sub esp, 0x14;
|
||||||
|
mov esi, eax;
|
||||||
|
mov ecx, esp;
|
||||||
|
lea edi, txtRoomid;
|
||||||
|
push edi;
|
||||||
|
call delRoomMemberCall2;
|
||||||
|
mov ecx, esi;
|
||||||
|
lea eax, vTxtMembers;
|
||||||
|
push eax;
|
||||||
|
call delRoomMemberCall3;
|
||||||
|
mov rv, eax;
|
||||||
|
popfd;
|
||||||
|
popad;
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
int AddChatroomMember(std::string roomid, std::string wxids);
|
int AddChatroomMember(std::string roomid, std::string wxids);
|
||||||
|
int DelChatroomMember(std::string roomid, std::string wxids);
|
||||||
149
spy/contact_mgmt.cpp
Normal file
149
spy/contact_mgmt.cpp
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
#pragma execution_character_set("utf-8")
|
||||||
|
|
||||||
|
#include "contact_mgmt.h"
|
||||||
|
#include "load_calls.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
extern WxCalls_t g_WxCalls;
|
||||||
|
extern DWORD g_WeChatWinDllAddr;
|
||||||
|
|
||||||
|
#define FEAT_LEN 5
|
||||||
|
static const uint8_t FEAT_COUNTRY[FEAT_LEN] = { 0xA4, 0xD9, 0x02, 0x4A, 0x18 };
|
||||||
|
static const uint8_t FEAT_PROVINCE[FEAT_LEN] = { 0xE2, 0xEA, 0xA8, 0xD1, 0x18 };
|
||||||
|
static const uint8_t FEAT_CITY[FEAT_LEN] = { 0x1D, 0x02, 0x5B, 0xBF, 0x18 };
|
||||||
|
|
||||||
|
static DWORD FindMem(DWORD start, DWORD end, const void *target, size_t len)
|
||||||
|
{
|
||||||
|
uint8_t *p = (uint8_t *)start;
|
||||||
|
while ((DWORD)p < end) {
|
||||||
|
if (memcmp((void *)p, target, len) == 0) {
|
||||||
|
return (DWORD)p;
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static string GetCntString(DWORD start, DWORD end, const uint8_t *feat, size_t len)
|
||||||
|
{
|
||||||
|
DWORD pfeat = FindMem(start, end, feat, len);
|
||||||
|
if (pfeat == 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD lfeat = GET_DWORD(pfeat + len);
|
||||||
|
if (lfeat <= 2) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return Wstring2String(wstring(GET_WSTRING_FROM_P(pfeat + FEAT_LEN + 4), lfeat));
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<RpcContact_t> GetContacts()
|
||||||
|
{
|
||||||
|
vector<RpcContact_t> contacts;
|
||||||
|
DWORD call1 = g_WeChatWinDllAddr + g_WxCalls.contact.base;
|
||||||
|
DWORD call2 = g_WeChatWinDllAddr + g_WxCalls.contact.head;
|
||||||
|
|
||||||
|
int success = 0;
|
||||||
|
DWORD *addr[3] = { 0, 0, 0 };
|
||||||
|
__asm {
|
||||||
|
pushad
|
||||||
|
call call1
|
||||||
|
lea ecx,addr
|
||||||
|
push ecx
|
||||||
|
mov ecx,eax
|
||||||
|
call call2
|
||||||
|
mov success,eax
|
||||||
|
popad
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD pstart = (DWORD)addr[0];
|
||||||
|
DWORD pend = (DWORD)addr[2];
|
||||||
|
|
||||||
|
while (pstart < pend) {
|
||||||
|
RpcContact_t cnt;
|
||||||
|
DWORD pbin = GET_DWORD(pstart + 0x150);
|
||||||
|
DWORD lenbin = GET_DWORD(pstart + 0x154);
|
||||||
|
|
||||||
|
cnt.wxid = GetStringByAddress(pstart + g_WxCalls.contact.wxId);
|
||||||
|
cnt.code = GetStringByAddress(pstart + g_WxCalls.contact.wxCode);
|
||||||
|
cnt.remark = GetStringByAddress(pstart + g_WxCalls.contact.wxRemark);
|
||||||
|
cnt.name = GetStringByAddress(pstart + g_WxCalls.contact.wxName);
|
||||||
|
|
||||||
|
cnt.country = GetCntString(pbin, pbin + lenbin, FEAT_COUNTRY, FEAT_LEN);
|
||||||
|
cnt.province = GetCntString(pbin, pbin + lenbin, FEAT_PROVINCE, FEAT_LEN);
|
||||||
|
cnt.city = GetCntString(pbin, pbin + lenbin, FEAT_CITY, FEAT_LEN);
|
||||||
|
|
||||||
|
if (pbin == 0) {
|
||||||
|
cnt.gender = 0;
|
||||||
|
} else {
|
||||||
|
cnt.gender = (DWORD) * (uint8_t *)(pbin + g_WxCalls.contact.wxGender);
|
||||||
|
}
|
||||||
|
|
||||||
|
contacts.push_back(cnt);
|
||||||
|
pstart += 0x438;
|
||||||
|
}
|
||||||
|
|
||||||
|
return contacts;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AcceptNewFriend(std::string v3, std::string v4, int scene)
|
||||||
|
{
|
||||||
|
int success = 0;
|
||||||
|
|
||||||
|
DWORD acceptNewFriendCall1 = g_WeChatWinDllAddr + g_WxCalls.anf.call1;
|
||||||
|
DWORD acceptNewFriendCall2 = g_WeChatWinDllAddr + g_WxCalls.anf.call2;
|
||||||
|
DWORD acceptNewFriendCall3 = g_WeChatWinDllAddr + g_WxCalls.anf.call3;
|
||||||
|
DWORD acceptNewFriendCall4 = g_WeChatWinDllAddr + g_WxCalls.anf.call4;
|
||||||
|
|
||||||
|
char buffer[0x40] = { 0 };
|
||||||
|
char nullbuffer[0x3CC] = { 0 };
|
||||||
|
|
||||||
|
LOG_DEBUG("\nv3: {}\nv4: {}\nscene: {}", v3, v4, scene);
|
||||||
|
WxString_t wxV3 = { 0 };
|
||||||
|
WxString_t wxV4 = { 0 };
|
||||||
|
std::wstring wsV3 = String2Wstring(v3);
|
||||||
|
std::wstring wsV4 = String2Wstring(v4);
|
||||||
|
|
||||||
|
wxV3.text = (wchar_t *)wsV3.c_str();
|
||||||
|
wxV3.size = wsV3.size();
|
||||||
|
wxV3.capacity = wsV3.capacity();
|
||||||
|
|
||||||
|
wxV4.text = (wchar_t *)wsV4.c_str();
|
||||||
|
wxV4.size = wsV4.size();
|
||||||
|
wxV4.capacity = wsV4.capacity();
|
||||||
|
|
||||||
|
__asm {
|
||||||
|
pushad;
|
||||||
|
pushfd;
|
||||||
|
lea ecx, buffer;
|
||||||
|
call acceptNewFriendCall1;
|
||||||
|
mov esi, 0x0;
|
||||||
|
mov edi, scene;
|
||||||
|
push esi;
|
||||||
|
push edi;
|
||||||
|
sub esp, 0x14;
|
||||||
|
mov ecx, esp;
|
||||||
|
lea eax, wxV4;
|
||||||
|
push eax;
|
||||||
|
call acceptNewFriendCall2;
|
||||||
|
sub esp, 0x8;
|
||||||
|
push 0x0;
|
||||||
|
lea eax, nullbuffer;
|
||||||
|
push eax;
|
||||||
|
lea eax, wxV3;
|
||||||
|
push eax;
|
||||||
|
lea ecx, buffer;
|
||||||
|
call acceptNewFriendCall3;
|
||||||
|
mov success, eax;
|
||||||
|
lea ecx, buffer;
|
||||||
|
call acceptNewFriendCall4;
|
||||||
|
popfd;
|
||||||
|
popad;
|
||||||
|
}
|
||||||
|
|
||||||
|
return success; // 成功返回 1
|
||||||
|
}
|
||||||
@ -1,5 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "string"
|
#include "string"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "pb_types.h"
|
||||||
|
|
||||||
|
vector<RpcContact_t> GetContacts();
|
||||||
int AcceptNewFriend(std::string v3, std::string v4, int scene);
|
int AcceptNewFriend(std::string v3, std::string v4, int scene);
|
||||||
@ -1,3 +1,5 @@
|
|||||||
|
#pragma warning( disable: 4244 )
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
#include "decrypt_image.h"
|
#include "decrypt_image.h"
|
||||||
|
|||||||
117
spy/exec_sql.cpp
117
spy/exec_sql.cpp
@ -2,90 +2,45 @@
|
|||||||
|
|
||||||
#include "exec_sql.h"
|
#include "exec_sql.h"
|
||||||
#include "load_calls.h"
|
#include "load_calls.h"
|
||||||
|
#include "sqlite3.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#define SQLITE_OK 0 /* Successful result */
|
#define OFFSET_DB_INSTANCE 0x2FFDDC8
|
||||||
#define SQLITE_ERROR 1 /* Generic error */
|
#define OFFSET_DB_MICROMSG 0x68
|
||||||
#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */
|
#define OFFSET_DB_CHAT_MSG 0x1C0
|
||||||
#define SQLITE_PERM 3 /* Access permission denied */
|
#define OFFSET_DB_MISC 0x3D8
|
||||||
#define SQLITE_ABORT 4 /* Callback routine requested an abort */
|
#define OFFSET_DB_EMOTION 0x558
|
||||||
#define SQLITE_BUSY 5 /* The database file is locked */
|
#define OFFSET_DB_MEDIA 0x9B8
|
||||||
#define SQLITE_LOCKED 6 /* A table in the database is locked */
|
#define OFFSET_DB_BIZCHAT_MSG 0x1120
|
||||||
#define SQLITE_NOMEM 7 /* A malloc() failed */
|
#define OFFSET_DB_FUNCTION_MSG 0x11B0
|
||||||
#define SQLITE_READONLY 8 /* Attempt to write a readonly database */
|
#define OFFSET_DB_NAME 0x14
|
||||||
#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/
|
|
||||||
#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */
|
|
||||||
#define SQLITE_CORRUPT 11 /* The database disk image is malformed */
|
|
||||||
#define SQLITE_NOTFOUND 12 /* Unknown opcode in sqlite3_file_control() */
|
|
||||||
#define SQLITE_FULL 13 /* Insertion failed because database is full */
|
|
||||||
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
|
|
||||||
#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
|
|
||||||
#define SQLITE_EMPTY 16 /* Internal use only */
|
|
||||||
#define SQLITE_SCHEMA 17 /* The database schema changed */
|
|
||||||
#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */
|
|
||||||
#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */
|
|
||||||
#define SQLITE_MISMATCH 20 /* Data type mismatch */
|
|
||||||
#define SQLITE_MISUSE 21 /* Library used incorrectly */
|
|
||||||
#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
|
|
||||||
#define SQLITE_AUTH 23 /* Authorization denied */
|
|
||||||
#define SQLITE_FORMAT 24 /* Not used */
|
|
||||||
#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */
|
|
||||||
#define SQLITE_NOTADB 26 /* File opened that is not a database file */
|
|
||||||
#define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */
|
|
||||||
#define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */
|
|
||||||
#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */
|
|
||||||
#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
|
|
||||||
|
|
||||||
#define SQLITE_INTEGER 1
|
|
||||||
#define SQLITE_FLOAT 2
|
|
||||||
#define SQLITE_TEXT 3
|
|
||||||
#define SQLITE_BLOB 4
|
|
||||||
#define SQLITE_NULL 5
|
|
||||||
|
|
||||||
extern WxCalls_t g_WxCalls;
|
|
||||||
extern DWORD g_WeChatWinDllAddr;
|
extern DWORD g_WeChatWinDllAddr;
|
||||||
|
|
||||||
typedef map<string, DWORD> dbMap_t;
|
typedef map<string, DWORD> dbMap_t;
|
||||||
static dbMap_t dbMap;
|
static dbMap_t dbMap;
|
||||||
|
|
||||||
// 回调函数指针
|
static void GetDbHandle(DWORD base, DWORD offset)
|
||||||
typedef int (*sqlite3_callback)(void *, int, char **, char **);
|
{
|
||||||
|
wchar_t *wsp;
|
||||||
// sqlite3_exec函数指针
|
wsp = (wchar_t *)(*(DWORD *)(base + offset + OFFSET_DB_NAME));
|
||||||
typedef int(__cdecl *Sqlite3_exec)(DWORD, /* The database on which the SQL executes */
|
string dbname = Wstring2String(wstring(wsp));
|
||||||
const char *, /* The SQL to be executed */
|
dbMap[dbname] = *(DWORD *)(base + offset);
|
||||||
sqlite3_callback, /* Invoke this callback routine */
|
}
|
||||||
void *, /* First argument to xCallback() */
|
|
||||||
char ** /* Write error messages here */
|
|
||||||
);
|
|
||||||
typedef int(__cdecl *Sqlite3_prepare)(DWORD, const char *, int, DWORD **, int);
|
|
||||||
typedef int(__cdecl *Sqlite3_step)(DWORD *);
|
|
||||||
typedef int(__cdecl *Sqlite3_column_count)(DWORD *);
|
|
||||||
typedef const char *(__cdecl *Sqlite3_column_name)(DWORD *, int);
|
|
||||||
typedef int(__cdecl *Sqlite3_column_type)(DWORD *, int);
|
|
||||||
typedef const void *(__cdecl *Sqlite3_column_blob)(DWORD *, int);
|
|
||||||
typedef int(__cdecl *Sqlite3_column_bytes)(DWORD *, int);
|
|
||||||
typedef int(__cdecl *Sqlite3_finalize)(DWORD *);
|
|
||||||
|
|
||||||
dbMap_t GetDbHandles()
|
dbMap_t GetDbHandles()
|
||||||
{
|
{
|
||||||
if (!dbMap.empty())
|
dbMap.clear();
|
||||||
return dbMap;
|
|
||||||
|
|
||||||
g_WeChatWinDllAddr = (DWORD)GetModuleHandle(L"WeChatWin.dll");
|
DWORD dbInstanceAddr = *(DWORD *)(g_WeChatWinDllAddr + OFFSET_DB_INSTANCE);
|
||||||
DWORD sqlHandleBaseAddr = *(DWORD *)(g_WeChatWinDllAddr + g_WxCalls.sql.base);
|
|
||||||
DWORD sqlHandleBeginAddr = *(DWORD *)(sqlHandleBaseAddr + g_WxCalls.sql.start);
|
GetDbHandle(dbInstanceAddr, OFFSET_DB_MICROMSG); // MicroMsg.db
|
||||||
DWORD sqlHandleEndAddr = *(DWORD *)(sqlHandleBaseAddr + g_WxCalls.sql.end);
|
GetDbHandle(dbInstanceAddr, OFFSET_DB_CHAT_MSG); // ChatMsg.db
|
||||||
while (sqlHandleBeginAddr < sqlHandleEndAddr) {
|
GetDbHandle(dbInstanceAddr, OFFSET_DB_MISC); // Misc.db
|
||||||
DWORD dwHandle = *(DWORD *)sqlHandleBeginAddr;
|
GetDbHandle(dbInstanceAddr, OFFSET_DB_EMOTION); // Emotion.db
|
||||||
string dbName = Wstring2String(wstring((wchar_t *)(*(DWORD *)(dwHandle + g_WxCalls.sql.name))));
|
GetDbHandle(dbInstanceAddr, OFFSET_DB_MEDIA); // Media.db
|
||||||
DWORD handle = *(DWORD *)(dwHandle + g_WxCalls.sql.slot);
|
GetDbHandle(dbInstanceAddr, OFFSET_DB_FUNCTION_MSG); // Function.db
|
||||||
if (handle) {
|
|
||||||
dbMap[dbName] = handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlHandleBeginAddr += 0x04;
|
|
||||||
}
|
|
||||||
return dbMap;
|
return dbMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,9 +88,9 @@ DbTables_t GetDbTables(const string db)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char *sql = "select name, sql from sqlite_master where type=\"table\";";
|
const char *sql = "select name, sql from sqlite_master where type=\"table\";";
|
||||||
Sqlite3_exec p_Sqlite3_exec = (Sqlite3_exec)(g_WeChatWinDllAddr + g_WxCalls.sql.exec);
|
Sqlite3_exec p_Sqlite3_exec = (Sqlite3_exec)(g_WeChatWinDllAddr + SQLITE3_EXEC_OFFSET);
|
||||||
|
|
||||||
p_Sqlite3_exec(it->second, sql, (sqlite3_callback)cbGetTables, (void *)&tables, 0);
|
p_Sqlite3_exec(it->second, sql, (Sqlite3_callback)cbGetTables, (void *)&tables, 0);
|
||||||
|
|
||||||
return tables;
|
return tables;
|
||||||
}
|
}
|
||||||
@ -143,14 +98,14 @@ DbTables_t GetDbTables(const string db)
|
|||||||
DbRows_t ExecDbQuery(const string db, const string sql)
|
DbRows_t ExecDbQuery(const string db, const string sql)
|
||||||
{
|
{
|
||||||
DbRows_t rows;
|
DbRows_t rows;
|
||||||
Sqlite3_prepare func_prepare = (Sqlite3_prepare)(g_WeChatWinDllAddr + 0x14227F0);
|
Sqlite3_prepare func_prepare = (Sqlite3_prepare)(g_WeChatWinDllAddr + SQLITE3_PREPARE_OFFSET);
|
||||||
Sqlite3_step func_step = (Sqlite3_step)(g_WeChatWinDllAddr + 0x13EA780);
|
Sqlite3_step func_step = (Sqlite3_step)(g_WeChatWinDllAddr + SQLITE3_STEP_OFFSET);
|
||||||
Sqlite3_column_count func_column_count = (Sqlite3_column_count)(g_WeChatWinDllAddr + 0x13EACD0);
|
Sqlite3_column_count func_column_count = (Sqlite3_column_count)(g_WeChatWinDllAddr + SQLITE3_COLUMN_COUNT_OFFSET);
|
||||||
Sqlite3_column_name func_column_name = (Sqlite3_column_name)(g_WeChatWinDllAddr + 0x13EB630);
|
Sqlite3_column_name func_column_name = (Sqlite3_column_name)(g_WeChatWinDllAddr + SQLITE3_COLUMN_NAME_OFFSET);
|
||||||
Sqlite3_column_type func_column_type = (Sqlite3_column_type)(g_WeChatWinDllAddr + 0x13EB470);
|
Sqlite3_column_type func_column_type = (Sqlite3_column_type)(g_WeChatWinDllAddr + SQLITE3_COLUMN_TYPE_OFFSET);
|
||||||
Sqlite3_column_blob func_column_blob = (Sqlite3_column_blob)(g_WeChatWinDllAddr + 0x13EAD10);
|
Sqlite3_column_blob func_column_blob = (Sqlite3_column_blob)(g_WeChatWinDllAddr + SQLITE3_COLUMN_BLOB_OFFSET);
|
||||||
Sqlite3_column_bytes func_column_bytes = (Sqlite3_column_bytes)(g_WeChatWinDllAddr + 0x13EADD0);
|
Sqlite3_column_bytes func_column_bytes = (Sqlite3_column_bytes)(g_WeChatWinDllAddr + SQLITE3_COLUMN_BYTES_OFFSET);
|
||||||
Sqlite3_finalize func_finalize = (Sqlite3_finalize)(g_WeChatWinDllAddr + 0x13E9730);
|
Sqlite3_finalize func_finalize = (Sqlite3_finalize)(g_WeChatWinDllAddr + SQLITE3_FINALIZE_OFFSET);
|
||||||
|
|
||||||
if (dbMap.empty()) {
|
if (dbMap.empty()) {
|
||||||
dbMap = GetDbHandles();
|
dbMap = GetDbHandles();
|
||||||
|
|||||||
@ -1,33 +0,0 @@
|
|||||||
#pragma execution_character_set("utf-8")
|
|
||||||
|
|
||||||
#include "get_contacts.h"
|
|
||||||
#include "load_calls.h"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
extern WxCalls_t g_WxCalls;
|
|
||||||
extern DWORD g_WeChatWinDllAddr;
|
|
||||||
|
|
||||||
vector<RpcContact_t> GetContacts()
|
|
||||||
{
|
|
||||||
vector<RpcContact_t> contacts;
|
|
||||||
DWORD baseAddr = g_WeChatWinDllAddr + g_WxCalls.contact.base;
|
|
||||||
DWORD tempAddr = GET_DWORD(baseAddr);
|
|
||||||
DWORD head = GET_DWORD(tempAddr + g_WxCalls.contact.head);
|
|
||||||
DWORD node = GET_DWORD(head);
|
|
||||||
|
|
||||||
while (node != head) {
|
|
||||||
RpcContact_t cnt;
|
|
||||||
cnt.wxid = GetStringByAddress(node + g_WxCalls.contact.wxId);
|
|
||||||
cnt.code = GetStringByAddress(node + g_WxCalls.contact.wxCode);
|
|
||||||
cnt.remark = GetStringByAddress(node + g_WxCalls.contact.wxRemark);
|
|
||||||
cnt.name = GetStringByAddress(node + g_WxCalls.contact.wxName);
|
|
||||||
cnt.country = GetStringByAddress(node + g_WxCalls.contact.wxCountry);
|
|
||||||
cnt.province = GetStringByAddress(node + g_WxCalls.contact.wxProvince);
|
|
||||||
cnt.city = GetStringByAddress(node + g_WxCalls.contact.wxCity);
|
|
||||||
cnt.gender = GET_DWORD(node + g_WxCalls.contact.wxGender);
|
|
||||||
contacts.push_back(cnt);
|
|
||||||
node = GET_DWORD(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
return contacts;
|
|
||||||
}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "pb_types.h"
|
|
||||||
|
|
||||||
vector<RpcContact_t> GetContacts();
|
|
||||||
@ -3,27 +3,28 @@
|
|||||||
|
|
||||||
#include "load_calls.h"
|
#include "load_calls.h"
|
||||||
|
|
||||||
#define SUPPORT_VERSION L"3.7.0.30"
|
#define SUPPORT_VERSION L"3.9.2.23"
|
||||||
WxCalls_t wxCalls = {
|
WxCalls_t wxCalls = {
|
||||||
0x2366538, // Login Status
|
0x2FFD638, // Login Status
|
||||||
{ 0x236607C, 0x23660F4, 0x2366128, 0x2386F7C }, // User Info: wxid, nickname, mobile, home
|
{ 0x2FFD4E8, 0x2FFD590, 0x2FFD500, 0x30238CC }, // User Info: wxid, nickname, mobile, home
|
||||||
0x521D30, // Send Message
|
{ 0x768140, 0xCE6C80, 0x756960 }, // Send Message
|
||||||
/* Receive Message:
|
/* Receive Message:
|
||||||
Hook, call, type, self, id, msgXml, roomId, wxId, content, thumb, extra */
|
Hook, call, type, self, id, msgXml, roomId, wxId, content, thumb, extra */
|
||||||
{ 0x550F4C, 0xA96350, 0x38, 0x3C, 0x184, 0x1EC, 0x48, 0x170, 0x70, 0x198, 0x1AC },
|
{ 0xD19A0B, 0x756960, 0x38, 0x3C, 0x194, 0x1FC, 0x48, 0x180, 0x70, 0x1A8, 0x1BC },
|
||||||
{ 0xBD780, 0x771980, 0x521640 }, // Send Image Message
|
{ 0x768140, 0XF59E40, 0XCE6640, 0x756960 }, // Send Image Message
|
||||||
{ 0xC3B70, 0x771980, 0x3ED8C0 }, // Send File Message
|
{ 0x76AE20, 0xF59E40, 0xB6D1F0, 0x756960 }, // Send File Message
|
||||||
{ 0xB8A70, 0x3ED5E0, 0x107F00, 0x3ED7B0, 0x2386FE4 }, // Send xml Message
|
{ 0xB8A70, 0x3ED5E0, 0x107F00, 0x3ED7B0, 0x2386FE4 }, // Send xml Message
|
||||||
{ 0x771980, 0x4777E0, 0x239E888 }, // Send Emotion Message
|
{ 0x771980, 0x4777E0, 0x239E888 }, // Send Emotion Message
|
||||||
/* Get Contacts:
|
/* Get Contacts:
|
||||||
Base, head, wxId, Code, Remark,Name, Gender, Country, Province, City*/
|
call1, call2, wxId, Code, Remark,Name, Gender, Country, Province, City*/
|
||||||
{ 0x23668F4, 0x4C, 0x30, 0x44, 0x78, 0x8C, 0x184, 0x1D0, 0x1E4, 0x1F8 },
|
{ 0x75A4A0, 0xC089F0, 0x10, 0x24, 0x58, 0x6C, 0x0E, 0x00, 0x00, 0x00 },
|
||||||
/* Exec Sql:
|
/* Exec Sql:
|
||||||
Exec, base, start, end, slot, name*/
|
Exec, base, start, end, slot, name*/
|
||||||
{ 0x141BDF0, 0x2366934, 0x1428, 0x142C, 0x3C, 0x50 },
|
{ 0x141BDF0, 0x2366934, 0x1428, 0x142C, 0x3C, 0x50 },
|
||||||
{ 0x771980, 0x2AE8D0, 0x1EE40E0 }, // Accept New Friend application
|
{ 0xA17D50, 0xF59E40, 0xA18BD0, 0xA17E70 }, // Accept New Friend application
|
||||||
{ 0xE29F0, 0x771980, 0x43D8D0 }, // Add chatroom members
|
{ 0x78CF20, 0xF59E40, 0xBD1DC0 }, // Add chatroom members
|
||||||
{ 0x771980, 0xCD2A90 } // Receive transfer
|
{ 0x78CF20, 0xF59E40, 0xBD22A0 }, // Delete chatroom members
|
||||||
|
{ 0x7B2E60, 0x15E2C20, 0x79C250 } // Receive transfer
|
||||||
};
|
};
|
||||||
|
|
||||||
int LoadCalls(const wchar_t *version, WxCalls_t *calls)
|
int LoadCalls(const wchar_t *version, WxCalls_t *calls)
|
||||||
|
|||||||
27
spy/log.cpp
27
spy/log.cpp
@ -1,27 +1,34 @@
|
|||||||
|
#include <filesystem>
|
||||||
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
#define LOGGER_NAME "WCF"
|
#define LOGGER_NAME "WCF"
|
||||||
#define LOGGER_FILE_NAME "logs/wcf.txt"
|
#define LOGGER_FILE_NAME "/logs/wcf.txt"
|
||||||
#define LOGGER_MAX_SIZE 1024 * 1024 * 10 // 10M
|
#define LOGGER_MAX_SIZE 1024 * 1024 * 10 // 10M
|
||||||
#define LOGGER_MAX_FILES 10 // 10 files
|
#define LOGGER_MAX_FILES 10 // 10 files
|
||||||
|
|
||||||
void InitLogger()
|
void InitLogger(std::string path)
|
||||||
{
|
{
|
||||||
static std::shared_ptr<spdlog::logger> gLogger = nullptr;
|
static std::shared_ptr<spdlog::logger> logger = nullptr;
|
||||||
if (gLogger != nullptr) {
|
if (logger != nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
gLogger = spdlog::rotating_logger_mt(LOGGER_NAME, LOGGER_FILE_NAME, LOGGER_MAX_SIZE, LOGGER_MAX_FILES);
|
auto filename = std::filesystem::path(path + LOGGER_FILE_NAME).make_preferred().string();
|
||||||
// gLogger = spdlog::stdout_color_mt("console");
|
try {
|
||||||
|
logger = spdlog::rotating_logger_mt(LOGGER_NAME, filename, LOGGER_MAX_SIZE, LOGGER_MAX_FILES);
|
||||||
|
} catch (const spdlog::spdlog_ex &ex) {
|
||||||
|
MessageBox(NULL, String2Wstring(ex.what()).c_str(), L"Init LOGGER ERROR", 0);
|
||||||
|
}
|
||||||
|
|
||||||
spdlog::set_default_logger(gLogger);
|
spdlog::set_default_logger(logger);
|
||||||
gLogger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] [%n] [%s::%#::%!] %v");
|
logger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] [%n] [%s::%#::%!] %v");
|
||||||
#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_DEBUG
|
#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_DEBUG
|
||||||
spdlog::set_level(spdlog::level::debug);
|
spdlog::set_level(spdlog::level::debug);
|
||||||
gLogger->flush_on(spdlog::level::debug);
|
logger->flush_on(spdlog::level::debug);
|
||||||
#else
|
#else
|
||||||
gLogger->flush_on(spdlog::level::info);
|
logger->flush_on(spdlog::level::info);
|
||||||
#endif
|
#endif
|
||||||
LOG_DEBUG("InitLogger with debug level");
|
LOG_DEBUG("InitLogger with debug level");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#ifdef ENABLE_DEBUG_LOG
|
#ifdef ENABLE_DEBUG_LOG
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
@ -19,4 +21,4 @@ void log_buffer(uint8_t *buffer, size_t len);
|
|||||||
#define LOG_WARN(...) SPDLOG_WARN(__VA_ARGS__);
|
#define LOG_WARN(...) SPDLOG_WARN(__VA_ARGS__);
|
||||||
#define LOG_ERROR(...) SPDLOG_ERROR(__VA_ARGS__);
|
#define LOG_ERROR(...) SPDLOG_ERROR(__VA_ARGS__);
|
||||||
|
|
||||||
void InitLogger();
|
void InitLogger(std::string path);
|
||||||
|
|||||||
@ -28,24 +28,40 @@ static CHAR recvMsgBackupCode[5] = { 0 };
|
|||||||
|
|
||||||
MsgTypes_t GetMsgTypes()
|
MsgTypes_t GetMsgTypes()
|
||||||
{
|
{
|
||||||
const MsgTypes_t m = { { 0x01, "文字" },
|
const MsgTypes_t m = {
|
||||||
{ 0x03, "图片" },
|
{ 0x01, "文字" },
|
||||||
{ 0x22, "语音" },
|
{ 0x03, "图片" },
|
||||||
{ 0x25, "好友确认" },
|
{ 0x22, "语音" },
|
||||||
{ 0x28, "POSSIBLEFRIEND_MSG" },
|
{ 0x25, "好友确认" },
|
||||||
{ 0x2A, "名片" },
|
{ 0x28, "POSSIBLEFRIEND_MSG" },
|
||||||
{ 0x2B, "视频" },
|
{ 0x2A, "名片" },
|
||||||
{ 0x2F, "石头剪刀布 | 表情图片" },
|
{ 0x2B, "视频" },
|
||||||
{ 0x30, "位置" },
|
{ 0x2F, "石头剪刀布 | 表情图片" },
|
||||||
{ 0x31, "共享实时位置、文件、转账、链接" },
|
{ 0x30, "位置" },
|
||||||
{ 0x32, "VOIPMSG" },
|
{ 0x31, "共享实时位置、文件、转账、链接" },
|
||||||
{ 0x33, "微信初始化" },
|
{ 0x32, "VOIPMSG" },
|
||||||
{ 0x34, "VOIPNOTIFY" },
|
{ 0x33, "微信初始化" },
|
||||||
{ 0x35, "VOIPINVITE" },
|
{ 0x34, "VOIPNOTIFY" },
|
||||||
{ 0x3E, "小视频" },
|
{ 0x35, "VOIPINVITE" },
|
||||||
{ 0x270F, "SYSNOTICE" },
|
{ 0x3E, "小视频" },
|
||||||
{ 0x2710, "红包、系统消息" },
|
{ 0x42, "微信红包" },
|
||||||
{ 0x2712, "撤回消息" } };
|
{ 0x270F, "SYSNOTICE" },
|
||||||
|
{ 0x2710, "红包、系统消息" },
|
||||||
|
{ 0x2712, "撤回消息" },
|
||||||
|
{ 0x100031, "搜狗表情" },
|
||||||
|
{ 0x1000031, "链接" },
|
||||||
|
{ 0x1A000031, "微信红包" },
|
||||||
|
{ 0x20010031, "红包封面" },
|
||||||
|
{ 0x2D000031, "视频号视频" },
|
||||||
|
{ 0x2E000031, "视频号名片" },
|
||||||
|
{ 0x31000031, "引用消息" },
|
||||||
|
{ 0x37000031, "拍一拍" },
|
||||||
|
{ 0x3A000031, "视频号直播" },
|
||||||
|
{ 0x3A100031, "商品链接" },
|
||||||
|
{ 0x3A200031, "视频号直播" },
|
||||||
|
{ 0x3E000031, "音乐链接" },
|
||||||
|
{ 0x41000031, "文件" },
|
||||||
|
};
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
@ -73,21 +89,20 @@ void UnHookAddress(DWORD hookAddr, CHAR restoreCode[5])
|
|||||||
void DispatchMsg(DWORD reg)
|
void DispatchMsg(DWORD reg)
|
||||||
{
|
{
|
||||||
WxMsg_t wxMsg;
|
WxMsg_t wxMsg;
|
||||||
DWORD *p = (DWORD *)reg; // 消息结构基址
|
|
||||||
|
|
||||||
wxMsg.type = GET_DWORD(*p + g_WxCalls.recvMsg.type);
|
wxMsg.type = GET_DWORD(reg + g_WxCalls.recvMsg.type);
|
||||||
wxMsg.is_self = GET_DWORD(*p + g_WxCalls.recvMsg.isSelf);
|
wxMsg.is_self = GET_DWORD(reg + g_WxCalls.recvMsg.isSelf);
|
||||||
wxMsg.id = GetStringByAddress(*p + g_WxCalls.recvMsg.msgId);
|
wxMsg.id = GetStringByStrAddr(reg + g_WxCalls.recvMsg.msgId);
|
||||||
wxMsg.xml = GetStringByAddress(*p + g_WxCalls.recvMsg.msgXml);
|
wxMsg.xml = GetStringByStrAddr(reg + g_WxCalls.recvMsg.msgXml);
|
||||||
|
|
||||||
string roomid = GetStringByAddress(*p + g_WxCalls.recvMsg.roomId);
|
string roomid = GetStringByWstrAddr(reg + g_WxCalls.recvMsg.roomId);
|
||||||
if (roomid.find("@chatroom") != string::npos) { // 群 ID 的格式为 xxxxxxxxxxx@chatroom
|
if (roomid.find("@chatroom") != string::npos) { // 群 ID 的格式为 xxxxxxxxxxx@chatroom
|
||||||
wxMsg.is_group = true;
|
wxMsg.is_group = true;
|
||||||
wxMsg.roomid = roomid;
|
wxMsg.roomid = roomid;
|
||||||
if (wxMsg.is_self) {
|
if (wxMsg.is_self) {
|
||||||
wxMsg.sender = GetSelfWxid();
|
wxMsg.sender = GetSelfWxid();
|
||||||
} else {
|
} else {
|
||||||
wxMsg.sender = GetStringByAddress(*p + g_WxCalls.recvMsg.wxId);
|
wxMsg.sender = GetStringByStrAddr(reg + g_WxCalls.recvMsg.wxId);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
wxMsg.is_group = false;
|
wxMsg.is_group = false;
|
||||||
@ -98,15 +113,16 @@ void DispatchMsg(DWORD reg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wxMsg.content = GetStringByAddress(*p + g_WxCalls.recvMsg.content);
|
wxMsg.content = GetStringByWstrAddr(reg + g_WxCalls.recvMsg.content);
|
||||||
wxMsg.thumb = GetStringByAddress(*p + g_WxCalls.recvMsg.thumb);
|
|
||||||
|
wxMsg.thumb = GetStringByStrAddr(reg + g_WxCalls.recvMsg.thumb);
|
||||||
if (!wxMsg.thumb.empty()) {
|
if (!wxMsg.thumb.empty()) {
|
||||||
wxMsg.thumb = GetHomePath() + "\\WeChat Files\\" + wxMsg.thumb;
|
wxMsg.thumb = GetHomePath() + wxMsg.thumb;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxMsg.extra = GetStringByAddress(*p + g_WxCalls.recvMsg.extra);
|
wxMsg.extra = GetStringByStrAddr(reg + g_WxCalls.recvMsg.extra);
|
||||||
if (!wxMsg.extra.empty()) {
|
if (!wxMsg.extra.empty()) {
|
||||||
wxMsg.extra = GetHomePath() + "\\WeChat Files\\" + wxMsg.extra;
|
wxMsg.extra = GetHomePath() + wxMsg.extra;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -120,13 +136,13 @@ void DispatchMsg(DWORD reg)
|
|||||||
__declspec(naked) void RecieveMsgFunc()
|
__declspec(naked) void RecieveMsgFunc()
|
||||||
{
|
{
|
||||||
__asm {
|
__asm {
|
||||||
mov reg_buffer, edi // 把值复制出来
|
pushad
|
||||||
}
|
pushfd
|
||||||
|
push ecx
|
||||||
DispatchMsg(reg_buffer);
|
call DispatchMsg
|
||||||
|
add esp, 0x4
|
||||||
__asm
|
popfd
|
||||||
{
|
popad
|
||||||
call recvMsgCallAddr // 这个为被覆盖的call
|
call recvMsgCallAddr // 这个为被覆盖的call
|
||||||
jmp recvMsgJumpBackAddr // 跳回被HOOK指令的下一条指令
|
jmp recvMsgJumpBackAddr // 跳回被HOOK指令的下一条指令
|
||||||
}
|
}
|
||||||
@ -134,6 +150,7 @@ __declspec(naked) void RecieveMsgFunc()
|
|||||||
|
|
||||||
void ListenMessage()
|
void ListenMessage()
|
||||||
{
|
{
|
||||||
|
// DbgMsg("ListenMessage");
|
||||||
// OutputDebugString(L"ListenMessage\n");
|
// OutputDebugString(L"ListenMessage\n");
|
||||||
// MessageBox(NULL, L"ListenMessage", L"ListenMessage", 0);
|
// MessageBox(NULL, L"ListenMessage", L"ListenMessage", 0);
|
||||||
if (gIsListening || (g_WeChatWinDllAddr == 0)) {
|
if (gIsListening || (g_WeChatWinDllAddr == 0)) {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
#include "receive_transfer.h"
|
#include "receive_transfer.h"
|
||||||
#include "load_calls.h"
|
#include "load_calls.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@ -8,31 +8,57 @@ using namespace std;
|
|||||||
extern WxCalls_t g_WxCalls;
|
extern WxCalls_t g_WxCalls;
|
||||||
extern DWORD g_WeChatWinDllAddr;
|
extern DWORD g_WeChatWinDllAddr;
|
||||||
|
|
||||||
int ReceiveTransfer(string wxid, string transferid)
|
int ReceiveTransfer(string wxid, string transferid, string transactionid)
|
||||||
{
|
{
|
||||||
int rv = 0;
|
int rv = 0;
|
||||||
DWORD recvTransferCall = g_WeChatWinDllAddr + g_WxCalls.tf.call1;
|
DWORD recvTransferCall1 = g_WeChatWinDllAddr + g_WxCalls.tf.call1;
|
||||||
DWORD recvTransferCall2 = g_WeChatWinDllAddr + g_WxCalls.tf.call2;
|
DWORD recvTransferCall2 = g_WeChatWinDllAddr + g_WxCalls.tf.call2;
|
||||||
|
DWORD recvTransferCall3 = g_WeChatWinDllAddr + g_WxCalls.tf.call3;
|
||||||
|
|
||||||
wstring wsWxid = String2Wstring(wxid);
|
char payInfo[0x134] = { 0 };
|
||||||
wstring wsTid = String2Wstring(transferid);
|
wstring wsWxid = String2Wstring(wxid);
|
||||||
|
WxString_t wxWxid = { 0 };
|
||||||
|
wxWxid.text = (wchar_t *)wsWxid.c_str();
|
||||||
|
wxWxid.size = wsWxid.size();
|
||||||
|
wxWxid.capacity = wsWxid.capacity();
|
||||||
|
|
||||||
LOG_DEBUG("Receiving transfer, from: {}, transferid: {}", wxid, transferid);
|
wstring wsTfid = String2Wstring(transferid);
|
||||||
|
WxString_t wxTfid = { 0 };
|
||||||
|
wxTfid.text = (wchar_t *)wsTfid.c_str();
|
||||||
|
wxTfid.size = wsTfid.size();
|
||||||
|
wxTfid.capacity = wsTfid.capacity();
|
||||||
|
|
||||||
|
wstring wsTaid = String2Wstring(transactionid);
|
||||||
|
WxString_t wxTaid = { 0 };
|
||||||
|
wxTaid.text = (wchar_t *)wsTaid.c_str();
|
||||||
|
wxTaid.size = wsTaid.size();
|
||||||
|
wxTaid.capacity = wsTaid.capacity();
|
||||||
|
|
||||||
|
LOG_DEBUG("Receiving transfer, from: {}, transferid: {}, transactionid: {}", wxid, transferid, transactionid);
|
||||||
__asm {
|
__asm {
|
||||||
pushad
|
pushad;
|
||||||
sub esp, 0x30
|
lea ecx, payInfo;
|
||||||
mov ecx, esp
|
call recvTransferCall1;
|
||||||
lea eax, wsTid
|
mov dword ptr[payInfo + 0x4], 0x1;
|
||||||
push eax
|
mov dword ptr[payInfo + 0x4C], 0x1;
|
||||||
call recvTransferCall
|
popad;
|
||||||
lea ecx, dword ptr ds:[esp+0x14]
|
}
|
||||||
lea eax, wsWxid
|
memcpy(&payInfo[0x1C], &wxTaid, sizeof(wxTaid));
|
||||||
push eax
|
memcpy(&payInfo[0x38], &wxTfid, sizeof(wxTfid));
|
||||||
call recvTransferCall
|
|
||||||
call recvTransferCall2
|
__asm {
|
||||||
add esp, 0x30
|
pushad;
|
||||||
mov rv, eax
|
push 0x1;
|
||||||
popad
|
sub esp, 0x8;
|
||||||
|
lea edx, wxWxid;
|
||||||
|
lea ecx, payInfo;
|
||||||
|
call recvTransferCall2;
|
||||||
|
mov rv, eax;
|
||||||
|
add esp, 0xC;
|
||||||
|
push 0x0;
|
||||||
|
lea ecx, payInfo;
|
||||||
|
call recvTransferCall3;
|
||||||
|
popad;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
|
|||||||
@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
int ReceiveTransfer(std::string wxid, std::string transferid);
|
int ReceiveTransfer(std::string wxid, std::string transferid, std::string transactionid);
|
||||||
|
|||||||
@ -16,11 +16,10 @@
|
|||||||
|
|
||||||
#include "wcf.pb.h"
|
#include "wcf.pb.h"
|
||||||
|
|
||||||
#include "accept_new_friend.h"
|
#include "chatroom_mgmt.h"
|
||||||
#include "add_chatroom_member.h"
|
#include "contact_mgmt.h"
|
||||||
#include "decrypt_image.h"
|
#include "decrypt_image.h"
|
||||||
#include "exec_sql.h"
|
#include "exec_sql.h"
|
||||||
#include "get_contacts.h"
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "pb_types.h"
|
#include "pb_types.h"
|
||||||
#include "pb_util.h"
|
#include "pb_util.h"
|
||||||
@ -465,36 +464,14 @@ bool func_accept_friend(char *v3, char *v4, int32_t scene, uint8_t *out, size_t
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool func_add_room_members(char *roomid, char *wxids, uint8_t *out, size_t *len)
|
bool func_receive_transfer(char *wxid, char *tfid, char *taid, uint8_t *out, size_t *len)
|
||||||
{
|
|
||||||
Response rsp = Response_init_default;
|
|
||||||
rsp.func = Functions_FUNC_ADD_ROOM_MEMBERS;
|
|
||||||
rsp.which_msg = Response_status_tag;
|
|
||||||
rsp.msg.status = 0;
|
|
||||||
|
|
||||||
rsp.msg.status = AddChatroomMember(roomid, wxids);
|
|
||||||
if (rsp.msg.status != 1) {
|
|
||||||
LOG_ERROR("AddChatroomMember failed: {}", rsp.msg.status);
|
|
||||||
}
|
|
||||||
|
|
||||||
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_receive_transfer(char *wxid, char *transferid, uint8_t *out, size_t *len)
|
|
||||||
{
|
{
|
||||||
Response rsp = Response_init_default;
|
Response rsp = Response_init_default;
|
||||||
rsp.func = Functions_FUNC_RECV_TRANSFER;
|
rsp.func = Functions_FUNC_RECV_TRANSFER;
|
||||||
rsp.which_msg = Response_status_tag;
|
rsp.which_msg = Response_status_tag;
|
||||||
rsp.msg.status = 0;
|
rsp.msg.status = 0;
|
||||||
|
|
||||||
rsp.msg.status = ReceiveTransfer(wxid, transferid);
|
rsp.msg.status = ReceiveTransfer(wxid, tfid, taid);
|
||||||
if (rsp.msg.status != 1) {
|
if (rsp.msg.status != 1) {
|
||||||
LOG_ERROR("AddChatroomMember failed: {}", rsp.msg.status);
|
LOG_ERROR("AddChatroomMember failed: {}", rsp.msg.status);
|
||||||
}
|
}
|
||||||
@ -531,6 +508,50 @@ bool func_decrypt_image(char *src, char *dst, uint8_t *out, size_t *len)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool func_add_room_members(char *roomid, char *wxids, uint8_t *out, size_t *len)
|
||||||
|
{
|
||||||
|
Response rsp = Response_init_default;
|
||||||
|
rsp.func = Functions_FUNC_ADD_ROOM_MEMBERS;
|
||||||
|
rsp.which_msg = Response_status_tag;
|
||||||
|
rsp.msg.status = 0;
|
||||||
|
|
||||||
|
rsp.msg.status = AddChatroomMember(roomid, wxids);
|
||||||
|
if (rsp.msg.status != 1) {
|
||||||
|
LOG_ERROR("AddChatroomMember failed: {}", rsp.msg.status);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_del_room_members(char *roomid, char *wxids, uint8_t *out, size_t *len)
|
||||||
|
{
|
||||||
|
Response rsp = Response_init_default;
|
||||||
|
rsp.func = Functions_FUNC_DEL_ROOM_MEMBERS;
|
||||||
|
rsp.which_msg = Response_status_tag;
|
||||||
|
rsp.msg.status = 0;
|
||||||
|
|
||||||
|
rsp.msg.status = DelChatroomMember(roomid, wxids);
|
||||||
|
if (rsp.msg.status != 1) {
|
||||||
|
LOG_ERROR("DelChatroomMember failed: {}", rsp.msg.status);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len)
|
static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
@ -594,6 +615,7 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len
|
|||||||
ret = func_send_file(req.msg.file.path, req.msg.file.receiver, out, out_len);
|
ret = func_send_file(req.msg.file.path, req.msg.file.receiver, out, out_len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
case Functions_FUNC_SEND_XML: {
|
case Functions_FUNC_SEND_XML: {
|
||||||
LOG_DEBUG("[Functions_FUNC_SEND_XML]");
|
LOG_DEBUG("[Functions_FUNC_SEND_XML]");
|
||||||
ret = func_send_xml(req.msg.xml, out, out_len);
|
ret = func_send_xml(req.msg.xml, out, out_len);
|
||||||
@ -604,6 +626,7 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len
|
|||||||
ret = func_send_emotion(req.msg.file.path, req.msg.file.receiver, out, out_len);
|
ret = func_send_emotion(req.msg.file.path, req.msg.file.receiver, out, out_len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
case Functions_FUNC_ENABLE_RECV_TXT: {
|
case Functions_FUNC_ENABLE_RECV_TXT: {
|
||||||
LOG_DEBUG("[Functions_FUNC_ENABLE_RECV_TXT]");
|
LOG_DEBUG("[Functions_FUNC_ENABLE_RECV_TXT]");
|
||||||
ret = func_enable_recv_txt(out, out_len);
|
ret = func_enable_recv_txt(out, out_len);
|
||||||
@ -624,14 +647,9 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len
|
|||||||
ret = func_accept_friend(req.msg.v.v3, req.msg.v.v4, req.msg.v.scene, out, out_len);
|
ret = func_accept_friend(req.msg.v.v3, req.msg.v.v4, req.msg.v.scene, out, out_len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Functions_FUNC_ADD_ROOM_MEMBERS: {
|
|
||||||
LOG_DEBUG("[Functions_FUNC_ADD_ROOM_MEMBERS]");
|
|
||||||
ret = func_add_room_members(req.msg.m.roomid, req.msg.m.wxids, out, out_len);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Functions_FUNC_RECV_TRANSFER: {
|
case Functions_FUNC_RECV_TRANSFER: {
|
||||||
LOG_DEBUG("[Functions_FUNC_RECV_TRANSFER]");
|
LOG_DEBUG("[Functions_FUNC_RECV_TRANSFER]");
|
||||||
ret = func_receive_transfer(req.msg.tf.wxid, req.msg.tf.tid, 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_DECRYPT_IMAGE: {
|
case Functions_FUNC_DECRYPT_IMAGE: {
|
||||||
@ -639,6 +657,16 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len
|
|||||||
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);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case Functions_FUNC_ADD_ROOM_MEMBERS: {
|
||||||
|
LOG_DEBUG("[Functions_FUNC_ADD_ROOM_MEMBERS]");
|
||||||
|
ret = func_add_room_members(req.msg.m.roomid, req.msg.m.wxids, out, out_len);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Functions_FUNC_DEL_ROOM_MEMBERS: {
|
||||||
|
LOG_DEBUG("[Functions_FUNC_DEL_ROOM_MEMBERS]");
|
||||||
|
ret = func_del_room_members(req.msg.m.roomid, req.msg.m.wxids, out, out_len);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
LOG_ERROR("[UNKNOW FUNCTION]");
|
LOG_ERROR("[UNKNOW FUNCTION]");
|
||||||
break;
|
break;
|
||||||
|
|||||||
155
spy/send_msg.cpp
155
spy/send_msg.cpp
@ -13,12 +13,15 @@ extern string GetSelfWxid(); // Defined in spy.cpp
|
|||||||
|
|
||||||
void SendTextMessage(string wxid, string msg, string atWxids)
|
void SendTextMessage(string wxid, string msg, string atWxids)
|
||||||
{
|
{
|
||||||
char buffer[0x3B0] = { 0 };
|
int success = 0;
|
||||||
|
char buffer[0x2D8] = { 0 };
|
||||||
WxString_t wxMsg = { 0 };
|
WxString_t wxMsg = { 0 };
|
||||||
WxString_t wxWxid = { 0 };
|
WxString_t wxWxid = { 0 };
|
||||||
|
|
||||||
// 发送消息Call地址 = 微信基址 + 偏移
|
// 发送消息Call地址 = 微信基址 + 偏移
|
||||||
DWORD sendCallAddress = g_WeChatWinDllAddr + g_WxCalls.sendTextMsg;
|
DWORD sendCall1 = g_WeChatWinDllAddr + g_WxCalls.sendText.call1;
|
||||||
|
DWORD sendCall2 = g_WeChatWinDllAddr + g_WxCalls.sendText.call2;
|
||||||
|
DWORD sendCall3 = g_WeChatWinDllAddr + g_WxCalls.sendText.call3;
|
||||||
|
|
||||||
wstring wsWxid = String2Wstring(wxid);
|
wstring wsWxid = String2Wstring(wxid);
|
||||||
wstring wsMsg = String2Wstring(msg);
|
wstring wsMsg = String2Wstring(msg);
|
||||||
@ -49,15 +52,24 @@ void SendTextMessage(string wxid, string msg, string atWxids)
|
|||||||
|
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
|
pushad;
|
||||||
|
call sendCall1;
|
||||||
|
push 0x0;
|
||||||
|
push 0x0;
|
||||||
|
push 0x0;
|
||||||
|
push 0x1;
|
||||||
lea eax, vTxtAtWxids;
|
lea eax, vTxtAtWxids;
|
||||||
push 0x01;
|
|
||||||
push eax;
|
push eax;
|
||||||
lea edi, wxMsg;
|
lea eax, wxMsg;
|
||||||
push edi;
|
push eax;
|
||||||
lea edx, wxWxid;
|
lea edx, wxWxid;
|
||||||
lea ecx, buffer;
|
lea ecx, buffer;
|
||||||
call sendCallAddress;
|
call sendCall2;
|
||||||
add esp, 0xC;
|
mov success, eax;
|
||||||
|
add esp, 0x18;
|
||||||
|
lea ecx, buffer;
|
||||||
|
call sendCall3;
|
||||||
|
popad;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,11 +78,12 @@ void SendImageMessage(string wxid, string path)
|
|||||||
if (g_WeChatWinDllAddr == 0) {
|
if (g_WeChatWinDllAddr == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DWORD tmpEAX = 0;
|
int success = 0;
|
||||||
char buf1[0x48] = { 0 };
|
DWORD tmpEAX = 0;
|
||||||
char buf2[0x3B0] = { 0 };
|
char buf[0x2D8] = { 0 };
|
||||||
WxString_t imgWxid = { 0 };
|
WxString_t imgWxid = { 0 };
|
||||||
WxString_t imgPath = { 0 };
|
WxString_t imgPath = { 0 };
|
||||||
|
WxString_t nullbuffer = { 0 };
|
||||||
|
|
||||||
wstring wsWxid = String2Wstring(wxid);
|
wstring wsWxid = String2Wstring(wxid);
|
||||||
wstring wspath = String2Wstring(path);
|
wstring wspath = String2Wstring(path);
|
||||||
@ -87,25 +100,29 @@ void SendImageMessage(string wxid, string path)
|
|||||||
DWORD sendCall1 = g_WeChatWinDllAddr + g_WxCalls.sendImg.call1;
|
DWORD sendCall1 = g_WeChatWinDllAddr + g_WxCalls.sendImg.call1;
|
||||||
DWORD sendCall2 = g_WeChatWinDllAddr + g_WxCalls.sendImg.call2;
|
DWORD sendCall2 = g_WeChatWinDllAddr + g_WxCalls.sendImg.call2;
|
||||||
DWORD sendCall3 = g_WeChatWinDllAddr + g_WxCalls.sendImg.call3;
|
DWORD sendCall3 = g_WeChatWinDllAddr + g_WxCalls.sendImg.call3;
|
||||||
|
DWORD sendCall4 = g_WeChatWinDllAddr + g_WxCalls.sendImg.call4;
|
||||||
|
|
||||||
__asm {
|
__asm {
|
||||||
pushad
|
pushad;
|
||||||
call sendCall1
|
call sendCall1;
|
||||||
sub esp, 0x14
|
sub esp,0x14;
|
||||||
mov tmpEAX, eax
|
mov tmpEAX,eax;
|
||||||
lea eax, buf1
|
lea eax,nullbuffer;
|
||||||
mov ecx, esp
|
mov ecx,esp;
|
||||||
lea edi, imgPath
|
lea edi,imgPath;
|
||||||
push eax
|
push eax;
|
||||||
call sendCall2
|
call sendCall2;
|
||||||
mov ecx, dword ptr[tmpEAX]
|
mov ecx,dword ptr [tmpEAX];
|
||||||
lea eax, imgWxid
|
lea eax,imgWxid;
|
||||||
push edi
|
push edi;
|
||||||
push eax
|
push eax;
|
||||||
lea eax, buf2
|
lea eax,buf;
|
||||||
push eax
|
push eax;
|
||||||
call sendCall3
|
call sendCall3;
|
||||||
popad
|
mov success,eax;
|
||||||
|
lea ecx,buf;
|
||||||
|
call sendCall4;
|
||||||
|
popad;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,8 +131,9 @@ void SendFileMessage(string wxid, string path)
|
|||||||
if (g_WeChatWinDllAddr == 0) {
|
if (g_WeChatWinDllAddr == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
int success = 0;
|
||||||
DWORD tmpEAX = 0;
|
DWORD tmpEAX = 0;
|
||||||
char buffer[0x3B0] = { 0 };
|
char buffer[0x2D8] = { 0 };
|
||||||
WxString_t fileWxid = { 0 };
|
WxString_t fileWxid = { 0 };
|
||||||
WxString_t filePath = { 0 };
|
WxString_t filePath = { 0 };
|
||||||
WxString_t nullbuffer = { 0 };
|
WxString_t nullbuffer = { 0 };
|
||||||
@ -135,46 +153,49 @@ void SendFileMessage(string wxid, string path)
|
|||||||
DWORD sendCall1 = g_WeChatWinDllAddr + g_WxCalls.sendFile.call1;
|
DWORD sendCall1 = g_WeChatWinDllAddr + g_WxCalls.sendFile.call1;
|
||||||
DWORD sendCall2 = g_WeChatWinDllAddr + g_WxCalls.sendFile.call2;
|
DWORD sendCall2 = g_WeChatWinDllAddr + g_WxCalls.sendFile.call2;
|
||||||
DWORD sendCall3 = g_WeChatWinDllAddr + g_WxCalls.sendFile.call3;
|
DWORD sendCall3 = g_WeChatWinDllAddr + g_WxCalls.sendFile.call3;
|
||||||
|
DWORD sendCall4 = g_WeChatWinDllAddr + g_WxCalls.sendFile.call4;
|
||||||
|
|
||||||
__asm {
|
__asm {
|
||||||
pushad;
|
pushad;
|
||||||
pushfd;
|
pushfd;
|
||||||
call sendCall1;
|
call sendCall1;
|
||||||
sub esp, 0x14;
|
sub esp, 0x14;
|
||||||
mov tmpEAX, eax;
|
mov tmpEAX, eax;
|
||||||
lea eax, nullbuffer;
|
lea eax, nullbuffer;
|
||||||
mov ecx, esp;
|
mov ecx, esp;
|
||||||
push eax;
|
push eax;
|
||||||
call sendCall2;
|
call sendCall2;
|
||||||
push 0x00DBE200;
|
push 0x0;
|
||||||
sub esp, 0x14;
|
sub esp, 0x14;
|
||||||
mov edi, esp;
|
mov edi, esp;
|
||||||
mov dword ptr ds : [edi] , 0x0;
|
mov dword ptr[edi], 0;
|
||||||
mov dword ptr ds : [edi + 0x4] , 0x0;
|
mov dword ptr[edi + 0x4], 0;
|
||||||
mov dword ptr ds : [edi + 0x8] , 0x0;
|
mov dword ptr[edi + 0x8], 0;
|
||||||
mov dword ptr ds : [edi + 0xC] , 0x0;
|
mov dword ptr[edi + 0xc], 0;
|
||||||
mov dword ptr ds : [edi + 0x10] , 0x0;
|
mov dword ptr[edi + 0x10], 0;
|
||||||
sub esp, 0x14;
|
sub esp, 0x14;
|
||||||
lea eax, filePath;
|
lea eax, filePath;
|
||||||
mov ecx, esp;
|
mov ecx, esp;
|
||||||
push eax;
|
push eax;
|
||||||
call sendCall2;
|
call sendCall2;
|
||||||
sub esp, 0x14;
|
sub esp, 0x14;
|
||||||
lea eax, fileWxid;
|
lea eax, fileWxid;
|
||||||
mov ecx, esp;
|
mov ecx, esp;
|
||||||
push eax;
|
push eax;
|
||||||
call sendCall2;
|
call sendCall2;
|
||||||
mov ecx, dword ptr [tmpEAX];
|
mov ecx, dword ptr[tmpEAX];
|
||||||
lea eax, buffer;
|
lea eax, buffer;
|
||||||
push eax;
|
push eax;
|
||||||
call sendCall3;
|
call sendCall3;
|
||||||
mov al,byte ptr [eax + 0x38];
|
mov al, byte ptr[eax + 0x38];
|
||||||
movzx eax,al;
|
movzx eax, al;
|
||||||
popfd;
|
mov success, eax;
|
||||||
popad;
|
lea ecx, buffer;
|
||||||
|
call sendCall4;
|
||||||
|
popfd;
|
||||||
|
popad;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendXmlMessage(string receiver, string xml, string path, int type)
|
void SendXmlMessage(string receiver, string xml, string path, int type)
|
||||||
{
|
{
|
||||||
if (g_WeChatWinDllAddr == 0) {
|
if (g_WeChatWinDllAddr == 0) {
|
||||||
@ -260,7 +281,7 @@ void SendEmotionMessage(string wxid, string path)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char buffer[0x1C] = { 0 };
|
char buffer[0x1C] = { 0 };
|
||||||
WxString_t emoWxid = { 0 };
|
WxString_t emoWxid = { 0 };
|
||||||
WxString_t emoPath = { 0 };
|
WxString_t emoPath = { 0 };
|
||||||
WxString_t nullbuffer = { 0 };
|
WxString_t nullbuffer = { 0 };
|
||||||
|
|||||||
BIN
spy/spy.aps
BIN
spy/spy.aps
Binary file not shown.
12
spy/spy.cpp
12
spy/spy.cpp
@ -1,16 +1,22 @@
|
|||||||
#include "spy.h"
|
#include <filesystem>
|
||||||
|
|
||||||
#include "load_calls.h"
|
#include "load_calls.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "rpc_server.h"
|
#include "rpc_server.h"
|
||||||
|
#include "spy.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
WxCalls_t g_WxCalls = { 0 };
|
WxCalls_t g_WxCalls = { 0 };
|
||||||
DWORD g_WeChatWinDllAddr = 0;
|
DWORD g_WeChatWinDllAddr = 0;
|
||||||
|
|
||||||
void InitSpy(int port)
|
void InitSpy(LPVOID args)
|
||||||
{
|
{
|
||||||
wchar_t version[16] = { 0 };
|
wchar_t version[16] = { 0 };
|
||||||
InitLogger();
|
PortPath_t *pp = (PortPath_t *)args;
|
||||||
|
int port = pp->port;
|
||||||
|
std::string path(pp->path);
|
||||||
|
|
||||||
|
InitLogger(path);
|
||||||
g_WeChatWinDllAddr = (DWORD)GetModuleHandle(L"WeChatWin.dll"); // 获取wechatWin模块地址
|
g_WeChatWinDllAddr = (DWORD)GetModuleHandle(L"WeChatWin.dll"); // 获取wechatWin模块地址
|
||||||
if (g_WeChatWinDllAddr == 0) {
|
if (g_WeChatWinDllAddr == 0) {
|
||||||
LOG_ERROR("获取wechatWin.dll模块地址失败");
|
LOG_ERROR("获取wechatWin.dll模块地址失败");
|
||||||
|
|||||||
@ -51,8 +51,8 @@ END
|
|||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 37,1,25,0
|
FILEVERSION 39,0,0,0
|
||||||
PRODUCTVERSION 3,7,0,30
|
PRODUCTVERSION 3,9,2,23
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
@ -69,12 +69,12 @@ BEGIN
|
|||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "WeChatFerry"
|
VALUE "CompanyName", "WeChatFerry"
|
||||||
VALUE "FileDescription", "WeChatFerry"
|
VALUE "FileDescription", "WeChatFerry"
|
||||||
VALUE "FileVersion", "37.1.25.0"
|
VALUE "FileVersion", "39.0.0.0"
|
||||||
VALUE "InternalName", "spy.dll"
|
VALUE "InternalName", "spy.dll"
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2023"
|
VALUE "LegalCopyright", "Copyright (C) 2023"
|
||||||
VALUE "OriginalFilename", "spy.dll"
|
VALUE "OriginalFilename", "spy.dll"
|
||||||
VALUE "ProductName", "WeChatFerry"
|
VALUE "ProductName", "WeChatFerry"
|
||||||
VALUE "ProductVersion", "3.7.0.30"
|
VALUE "ProductVersion", "3.9.2.23"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|||||||
@ -23,10 +23,17 @@ typedef struct RecvMsg {
|
|||||||
DWORD extra; // 附加数据
|
DWORD extra; // 附加数据
|
||||||
} RecvMsg_t;
|
} RecvMsg_t;
|
||||||
|
|
||||||
|
typedef struct SendText {
|
||||||
|
DWORD call1;
|
||||||
|
DWORD call2;
|
||||||
|
DWORD call3;
|
||||||
|
} SendText_t;
|
||||||
|
|
||||||
typedef struct Sendfile {
|
typedef struct Sendfile {
|
||||||
DWORD call1;
|
DWORD call1;
|
||||||
DWORD call2;
|
DWORD call2;
|
||||||
DWORD call3;
|
DWORD call3;
|
||||||
|
DWORD call4;
|
||||||
} Sendfile_t;
|
} Sendfile_t;
|
||||||
|
|
||||||
typedef struct Contact {
|
typedef struct Contact {
|
||||||
@ -54,7 +61,8 @@ typedef struct Sql {
|
|||||||
typedef struct NewFriend {
|
typedef struct NewFriend {
|
||||||
DWORD call1;
|
DWORD call1;
|
||||||
DWORD call2;
|
DWORD call2;
|
||||||
DWORD handle;
|
DWORD call3;
|
||||||
|
DWORD call4;
|
||||||
} NewFriend_t;
|
} NewFriend_t;
|
||||||
|
|
||||||
typedef struct RoomMember {
|
typedef struct RoomMember {
|
||||||
@ -74,12 +82,13 @@ typedef struct Xml {
|
|||||||
typedef struct TF {
|
typedef struct TF {
|
||||||
DWORD call1;
|
DWORD call1;
|
||||||
DWORD call2;
|
DWORD call2;
|
||||||
|
DWORD call3;
|
||||||
} TF_t;
|
} TF_t;
|
||||||
|
|
||||||
typedef struct WxCalls {
|
typedef struct WxCalls {
|
||||||
DWORD login; // 登录状态
|
DWORD login; // 登录状态
|
||||||
UserInfoCall_t ui; // 用户信息
|
UserInfoCall_t ui; // 用户信息
|
||||||
DWORD sendTextMsg; // 发送消息
|
SendText_t sendText; // 发送消息
|
||||||
RecvMsg_t recvMsg; // 接收消息
|
RecvMsg_t recvMsg; // 接收消息
|
||||||
Sendfile_t sendImg; // 发送图片
|
Sendfile_t sendImg; // 发送图片
|
||||||
Sendfile_t sendFile; // 发送文件
|
Sendfile_t sendFile; // 发送文件
|
||||||
@ -89,6 +98,7 @@ typedef struct WxCalls {
|
|||||||
Sql_t sql; // 执行 SQL
|
Sql_t sql; // 执行 SQL
|
||||||
NewFriend_t anf; // 通过好友申请
|
NewFriend_t anf; // 通过好友申请
|
||||||
RoomMember_t arm; // 添加群成员
|
RoomMember_t arm; // 添加群成员
|
||||||
|
RoomMember_t drm; // 删除群成员
|
||||||
TF_t tf; // 接收转账
|
TF_t tf; // 接收转账
|
||||||
} WxCalls_t;
|
} WxCalls_t;
|
||||||
|
|
||||||
|
|||||||
192
spy/sqlite3.h
Normal file
192
spy/sqlite3.h
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Windows.h"
|
||||||
|
|
||||||
|
#define SQLITE_OK 0 /* Successful result */
|
||||||
|
|
||||||
|
/* beginning-of-error-codes */
|
||||||
|
#define SQLITE_ERROR 1 /* Generic error */
|
||||||
|
#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */
|
||||||
|
#define SQLITE_PERM 3 /* Access permission denied */
|
||||||
|
#define SQLITE_ABORT 4 /* Callback routine requested an abort */
|
||||||
|
#define SQLITE_BUSY 5 /* The database file is locked */
|
||||||
|
#define SQLITE_LOCKED 6 /* A table in the database is locked */
|
||||||
|
#define SQLITE_NOMEM 7 /* A malloc() failed */
|
||||||
|
#define SQLITE_READONLY 8 /* Attempt to write a readonly database */
|
||||||
|
#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/
|
||||||
|
#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */
|
||||||
|
#define SQLITE_CORRUPT 11 /* The database disk image is malformed */
|
||||||
|
#define SQLITE_NOTFOUND 12 /* Unknown opcode in sqlite3_file_control() */
|
||||||
|
#define SQLITE_FULL 13 /* Insertion failed because database is full */
|
||||||
|
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
|
||||||
|
#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
|
||||||
|
#define SQLITE_EMPTY 16 /* Internal use only */
|
||||||
|
#define SQLITE_SCHEMA 17 /* The database schema changed */
|
||||||
|
#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */
|
||||||
|
#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */
|
||||||
|
#define SQLITE_MISMATCH 20 /* Data type mismatch */
|
||||||
|
#define SQLITE_MISUSE 21 /* Library used incorrectly */
|
||||||
|
#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
|
||||||
|
#define SQLITE_AUTH 23 /* Authorization denied */
|
||||||
|
#define SQLITE_FORMAT 24 /* Not used */
|
||||||
|
#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */
|
||||||
|
#define SQLITE_NOTADB 26 /* File opened that is not a database file */
|
||||||
|
#define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */
|
||||||
|
#define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */
|
||||||
|
#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */
|
||||||
|
#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
|
||||||
|
/* end-of-error-codes */
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI3REF: Extended Result Codes
|
||||||
|
** KEYWORDS: {extended result code definitions}
|
||||||
|
**
|
||||||
|
** In its default configuration, SQLite API routines return one of 30 integer
|
||||||
|
** [result codes]. However, experience has shown that many of
|
||||||
|
** these result codes are too coarse-grained. They do not provide as
|
||||||
|
** much information about problems as programmers might like. In an effort to
|
||||||
|
** address this, newer versions of SQLite (version 3.3.8 [dateof:3.3.8]
|
||||||
|
** and later) include
|
||||||
|
** support for additional result codes that provide more detailed information
|
||||||
|
** about errors. These [extended result codes] are enabled or disabled
|
||||||
|
** on a per database connection basis using the
|
||||||
|
** [sqlite3_extended_result_codes()] API. Or, the extended code for
|
||||||
|
** the most recent error can be obtained using
|
||||||
|
** [sqlite3_extended_errcode()].
|
||||||
|
*/
|
||||||
|
#define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1 << 8))
|
||||||
|
#define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2 << 8))
|
||||||
|
#define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3 << 8))
|
||||||
|
#define SQLITE_IOERR_READ (SQLITE_IOERR | (1 << 8))
|
||||||
|
#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2 << 8))
|
||||||
|
#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3 << 8))
|
||||||
|
#define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4 << 8))
|
||||||
|
#define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5 << 8))
|
||||||
|
#define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6 << 8))
|
||||||
|
#define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7 << 8))
|
||||||
|
#define SQLITE_IOERR_UNLOCK (SQLITE_IOERR | (8 << 8))
|
||||||
|
#define SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9 << 8))
|
||||||
|
#define SQLITE_IOERR_DELETE (SQLITE_IOERR | (10 << 8))
|
||||||
|
#define SQLITE_IOERR_BLOCKED (SQLITE_IOERR | (11 << 8))
|
||||||
|
#define SQLITE_IOERR_NOMEM (SQLITE_IOERR | (12 << 8))
|
||||||
|
#define SQLITE_IOERR_ACCESS (SQLITE_IOERR | (13 << 8))
|
||||||
|
#define SQLITE_IOERR_CHECKRESERVEDLOCK (SQLITE_IOERR | (14 << 8))
|
||||||
|
#define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15 << 8))
|
||||||
|
#define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16 << 8))
|
||||||
|
#define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17 << 8))
|
||||||
|
#define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18 << 8))
|
||||||
|
#define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19 << 8))
|
||||||
|
#define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20 << 8))
|
||||||
|
#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21 << 8))
|
||||||
|
#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22 << 8))
|
||||||
|
#define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23 << 8))
|
||||||
|
#define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24 << 8))
|
||||||
|
#define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25 << 8))
|
||||||
|
#define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26 << 8))
|
||||||
|
#define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27 << 8))
|
||||||
|
#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28 << 8))
|
||||||
|
#define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29 << 8))
|
||||||
|
#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30 << 8))
|
||||||
|
#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31 << 8))
|
||||||
|
#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32 << 8))
|
||||||
|
#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33 << 8))
|
||||||
|
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1 << 8))
|
||||||
|
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2 << 8))
|
||||||
|
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1 << 8))
|
||||||
|
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2 << 8))
|
||||||
|
#define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3 << 8))
|
||||||
|
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1 << 8))
|
||||||
|
#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2 << 8))
|
||||||
|
#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3 << 8))
|
||||||
|
#define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4 << 8))
|
||||||
|
#define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5 << 8)) /* Not Used */
|
||||||
|
#define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6 << 8))
|
||||||
|
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1 << 8))
|
||||||
|
#define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2 << 8))
|
||||||
|
#define SQLITE_CORRUPT_INDEX (SQLITE_CORRUPT | (3 << 8))
|
||||||
|
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1 << 8))
|
||||||
|
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2 << 8))
|
||||||
|
#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3 << 8))
|
||||||
|
#define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4 << 8))
|
||||||
|
#define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5 << 8))
|
||||||
|
#define SQLITE_READONLY_DIRECTORY (SQLITE_READONLY | (6 << 8))
|
||||||
|
#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT | (10 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT | (11 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT | (12 << 8))
|
||||||
|
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1 << 8))
|
||||||
|
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2 << 8))
|
||||||
|
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1 << 8))
|
||||||
|
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1 << 8))
|
||||||
|
#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1 << 8))
|
||||||
|
#define SQLITE_OK_SYMLINK (SQLITE_OK | (2 << 8)) /* internal use only */
|
||||||
|
|
||||||
|
#define SQLITE_INTEGER 1
|
||||||
|
#define SQLITE_FLOAT 2
|
||||||
|
#define SQLITE_BLOB 4
|
||||||
|
#define SQLITE_NULL 5
|
||||||
|
#define SQLITE_TEXT 3
|
||||||
|
|
||||||
|
#define SQLITE3_EXEC_OFFSET 0x1E24F70
|
||||||
|
#define SQLITE3_BACKUP_INIT_OFFSET 0x1DEA900
|
||||||
|
#define SQLITE3_PREPARE_OFFSET 0x1E2B8C0
|
||||||
|
#define SQLITE3_OPEN_OFFSET 0x1E598B0
|
||||||
|
#define SQLITE3_BACKUP_STEP_OFFSET 0x1DEAD00
|
||||||
|
#define SQLITE3_BACKUP_REMAINING_OFFSET 0x1DEB440
|
||||||
|
#define SQLITE3_BACKUP_PAGECOUNT_OFFSET 0x1DEB450
|
||||||
|
#define SQLITE3_BACKUP_FINISH_OFFSET 0x1DEB340
|
||||||
|
#define SQLITE3_SLEEP_OFFSET 0x1E5A0F0
|
||||||
|
#define SQLITE3_ERRCODE_OFFSET 0x1E58550
|
||||||
|
#define SQLITE3_CLOSE_OFFSET 0x1E56CD0
|
||||||
|
#define SQLITE3_STEP_OFFSET 0x1DF3770
|
||||||
|
#define SQLITE3_COLUMN_COUNT_OFFSET 0x1DF3C80
|
||||||
|
#define SQLITE3_COLUMN_NAME_OFFSET 0x1DF4570
|
||||||
|
#define SQLITE3_COLUMN_TYPE_OFFSET 0x1DF4410
|
||||||
|
#define SQLITE3_COLUMN_BLOB_OFFSET 0x1DF3CC0
|
||||||
|
#define SQLITE3_COLUMN_BYTES_OFFSET 0x1DF3DA0
|
||||||
|
#define SQLITE3_FINALIZE_OFFSET 0x1DF2740
|
||||||
|
|
||||||
|
typedef int (*Sqlite3_callback)(void *, int, char **, char **);
|
||||||
|
|
||||||
|
typedef int(__cdecl *Sqlite3_exec)(DWORD, /* An open database */
|
||||||
|
const char *sql, /* SQL to be evaluated */
|
||||||
|
Sqlite3_callback, /* Callback function */
|
||||||
|
void *, /* 1st argument to callback */
|
||||||
|
char **errmsg /* Error msg written here */
|
||||||
|
);
|
||||||
|
typedef DWORD(__cdecl *Sqlite3_backup_init)(DWORD *pDest, /* Destination database handle */
|
||||||
|
const char *zDestName, /* Destination database name */
|
||||||
|
DWORD *pSource, /* Source database handle */
|
||||||
|
const char *zSourceName /* Source database name */
|
||||||
|
);
|
||||||
|
typedef int(__cdecl *Sqlite3_prepare)(DWORD db, /* Database handle */
|
||||||
|
const char *zSql, /* SQL statement, UTF-8 encoded */
|
||||||
|
int nByte, /* Maximum length of zSql in bytes. */
|
||||||
|
DWORD **ppStmt, /* OUT: Statement handle */
|
||||||
|
const char **pzTail /* OUT: Pointer to unused portion of zSql */
|
||||||
|
);
|
||||||
|
typedef int(__cdecl *Sqlite3_open)(const char *filename, DWORD **ppDb);
|
||||||
|
typedef int(__cdecl *Sqlite3_backup_step)(DWORD *p, int nPage);
|
||||||
|
typedef int(__cdecl *Sqlite3_backup_remaining)(DWORD *p);
|
||||||
|
typedef int(__cdecl *Sqlite3_backup_pagecount)(DWORD *p);
|
||||||
|
typedef int(__cdecl *Sqlite3_backup_finish)(DWORD *p);
|
||||||
|
typedef int(__cdecl *Sqlite3_sleep)(int);
|
||||||
|
typedef int(__cdecl *Sqlite3_errcode)(DWORD *db);
|
||||||
|
typedef int(__cdecl *Sqlite3_close)(DWORD *);
|
||||||
|
|
||||||
|
typedef int(__cdecl *Sqlite3_step)(DWORD *);
|
||||||
|
typedef int(__cdecl *Sqlite3_column_count)(DWORD *pStmt);
|
||||||
|
typedef const char *(__cdecl *Sqlite3_column_name)(DWORD *, int N);
|
||||||
|
typedef int(__cdecl *Sqlite3_column_type)(DWORD *, int iCol);
|
||||||
|
typedef const void *(__cdecl *Sqlite3_column_blob)(DWORD *, int iCol);
|
||||||
|
typedef int(__cdecl *Sqlite3_column_bytes)(DWORD *, int iCol);
|
||||||
|
typedef int(__cdecl *Sqlite3_finalize)(DWORD *pStmt);
|
||||||
@ -6,14 +6,23 @@
|
|||||||
extern WxCalls_t g_WxCalls;
|
extern WxCalls_t g_WxCalls;
|
||||||
extern DWORD g_WeChatWinDllAddr;
|
extern DWORD g_WeChatWinDllAddr;
|
||||||
|
|
||||||
string GetHomePath() { return GET_STRING(g_WeChatWinDllAddr + g_WxCalls.ui.home); }
|
static char home[MAX_PATH] = { 0 };
|
||||||
|
|
||||||
|
string GetHomePath()
|
||||||
|
{
|
||||||
|
if (home[0] == 0) {
|
||||||
|
string path = Wstring2String(GET_WSTRING(g_WeChatWinDllAddr + g_WxCalls.ui.home)) + "\\WeChat Files\\";
|
||||||
|
strncpy_s(home, path.c_str(), path.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(home);
|
||||||
|
}
|
||||||
|
|
||||||
string GetSelfWxid()
|
string GetSelfWxid()
|
||||||
{
|
{
|
||||||
DWORD wxidType = 0;
|
DWORD wxidType = 0;
|
||||||
try {
|
try {
|
||||||
wxidType = GET_DWORD(g_WeChatWinDllAddr + g_WxCalls.ui.wxid + 0x14);
|
wxidType = GET_DWORD(g_WeChatWinDllAddr + g_WxCalls.ui.wxid + 0x14);
|
||||||
LOG_DEBUG("WeChatWinDll: {:#x}, wxid type: {:#x}", g_WeChatWinDllAddr, wxidType);
|
|
||||||
if (wxidType == 0xF) {
|
if (wxidType == 0xF) {
|
||||||
return GET_STRING_FROM_P(g_WeChatWinDllAddr + g_WxCalls.ui.wxid);
|
return GET_STRING_FROM_P(g_WeChatWinDllAddr + g_WxCalls.ui.wxid);
|
||||||
} else {
|
} else {
|
||||||
@ -33,7 +42,7 @@ UserInfo_t GetUserInfo()
|
|||||||
ui.wxid = GetSelfWxid();
|
ui.wxid = GetSelfWxid();
|
||||||
ui.name = GET_STRING_FROM_P(g_WeChatWinDllAddr + g_WxCalls.ui.nickName);
|
ui.name = GET_STRING_FROM_P(g_WeChatWinDllAddr + g_WxCalls.ui.nickName);
|
||||||
ui.mobile = GET_STRING_FROM_P(g_WeChatWinDllAddr + g_WxCalls.ui.mobile);
|
ui.mobile = GET_STRING_FROM_P(g_WeChatWinDllAddr + g_WxCalls.ui.mobile);
|
||||||
ui.home = GET_STRING(g_WeChatWinDllAddr + g_WxCalls.ui.home);
|
ui.home = GetHomePath();
|
||||||
|
|
||||||
return ui;
|
return ui;
|
||||||
}
|
}
|
||||||
|
|||||||
37
spy/util.cpp
37
spy/util.cpp
@ -5,6 +5,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <strsafe.h>
|
#include <strsafe.h>
|
||||||
#include <tlhelp32.h>
|
#include <tlhelp32.h>
|
||||||
|
#include <vector>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@ -212,6 +213,18 @@ string GetStringByAddress(DWORD address)
|
|||||||
return Wstring2String(wstring(GET_WSTRING(address), strLength));
|
return Wstring2String(wstring(GET_WSTRING(address), strLength));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string GetStringByStrAddr(DWORD addr)
|
||||||
|
{
|
||||||
|
DWORD strLength = GET_DWORD(addr + 4);
|
||||||
|
return strLength ? string(GET_STRING(addr), strLength) : string();
|
||||||
|
}
|
||||||
|
|
||||||
|
string GetStringByWstrAddr(DWORD addr)
|
||||||
|
{
|
||||||
|
DWORD strLength = GET_DWORD(addr + 4);
|
||||||
|
return strLength ? Wstring2String(wstring(GET_WSTRING(addr), strLength)) : string();
|
||||||
|
}
|
||||||
|
|
||||||
DWORD GetMemoryIntByAddress(HANDLE hProcess, DWORD address)
|
DWORD GetMemoryIntByAddress(HANDLE hProcess, DWORD address)
|
||||||
{
|
{
|
||||||
DWORD value = 0;
|
DWORD value = 0;
|
||||||
@ -244,3 +257,27 @@ wstring GetUnicodeInfoByAddress(HANDLE hProcess, DWORD address)
|
|||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DbgMsg(const char *zcFormat, ...)
|
||||||
|
{
|
||||||
|
// initialize use of the variable argument array
|
||||||
|
va_list vaArgs;
|
||||||
|
va_start(vaArgs, zcFormat);
|
||||||
|
|
||||||
|
// reliably acquire the size
|
||||||
|
// from a copy of the variable argument array
|
||||||
|
// and a functionally reliable call to mock the formatting
|
||||||
|
va_list vaArgsCopy;
|
||||||
|
va_copy(vaArgsCopy, vaArgs);
|
||||||
|
const int iLen = std::vsnprintf(NULL, 0, zcFormat, vaArgsCopy);
|
||||||
|
va_end(vaArgsCopy);
|
||||||
|
|
||||||
|
// return a formatted string without risking memory mismanagement
|
||||||
|
// and without assuming any compiler or platform specific behavior
|
||||||
|
std::vector<char> zc(iLen + 1);
|
||||||
|
std::vsnprintf(zc.data(), zc.size(), zcFormat, vaArgs);
|
||||||
|
va_end(vaArgs);
|
||||||
|
std::string strText(zc.data(), iLen);
|
||||||
|
|
||||||
|
OutputDebugStringA(strText.c_str());
|
||||||
|
}
|
||||||
|
|||||||
17
spy/util.h
17
spy/util.h
@ -8,10 +8,16 @@
|
|||||||
#define WECHATINJECTDLL L"spy.dll"
|
#define WECHATINJECTDLL L"spy.dll"
|
||||||
#define WECHATINJECTDLL_DEBUG L"spy_debug.dll"
|
#define WECHATINJECTDLL_DEBUG L"spy_debug.dll"
|
||||||
|
|
||||||
#define GET_DWORD(addr) ((DWORD) * (DWORD *)(addr))
|
#define GET_DWORD(addr) ((DWORD) * (DWORD *)(addr))
|
||||||
#define GET_STRING(addr) ((CHAR *)(*(DWORD *)(addr)))
|
#define GET_STRING(addr) ((CHAR *)(*(DWORD *)(addr)))
|
||||||
#define GET_WSTRING(addr) ((WCHAR *)(*(DWORD *)(addr)))
|
#define GET_WSTRING(addr) ((WCHAR *)(*(DWORD *)(addr)))
|
||||||
#define GET_STRING_FROM_P(addr) ((CHAR *)(addr))
|
#define GET_STRING_FROM_P(addr) ((CHAR *)(addr))
|
||||||
|
#define GET_WSTRING_FROM_P(addr) ((WCHAR *)(addr))
|
||||||
|
|
||||||
|
typedef struct PortPath {
|
||||||
|
int port;
|
||||||
|
char path[MAX_PATH];
|
||||||
|
} PortPath_t;
|
||||||
|
|
||||||
DWORD GetWeChatPid();
|
DWORD GetWeChatPid();
|
||||||
int OpenWeChat(DWORD *pid);
|
int OpenWeChat(DWORD *pid);
|
||||||
@ -22,3 +28,6 @@ std::wstring GetUnicodeInfoByAddress(HANDLE hProcess, DWORD address);
|
|||||||
std::wstring String2Wstring(std::string s);
|
std::wstring String2Wstring(std::string s);
|
||||||
std::string Wstring2String(std::wstring ws);
|
std::string Wstring2String(std::wstring ws);
|
||||||
std::string GetStringByAddress(DWORD address);
|
std::string GetStringByAddress(DWORD address);
|
||||||
|
std::string GetStringByStrAddr(DWORD addr);
|
||||||
|
std::string GetStringByWstrAddr(DWORD addr);
|
||||||
|
void DbgMsg(const char *zcFormat, ...);
|
||||||
|
|||||||
@ -2,14 +2,11 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "framework.h"
|
|
||||||
|
|
||||||
#include "log.h"
|
|
||||||
#include "sdk.h"
|
#include "sdk.h"
|
||||||
|
|
||||||
void help()
|
void help()
|
||||||
{
|
{
|
||||||
LOG_INFO("\nUsage: \n启动: wcf.exe start port [debug]\n关闭: wcf.exe stop\nport: 命令端口, 消息端口为命令端口+1\n");
|
printf("\nUsage: \n启动: wcf.exe start port [debug]\n关闭: wcf.exe stop\nport: 命令端口, 消息端口为命令端口+1\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
@ -34,4 +31,4 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user