Compare commits

...
11 Commits
Author SHA1 Message Date
hugy 7be2903dd2 3.9.0.28版本数据库和群相关功能 2023-02-10 15:52:55 +08:00
hugy e563710f80 3.9.0.28版本 2023-02-09 15:47:55 +08:00
hugy 915cb1602f 文档修改 2023-02-08 13:43:57 +08:00
hugy 254a9eeb30 朋友圈消息hook和朋友圈消息获取 2023-02-08 13:35:04 +08:00
hugy a0f83b5a99 转账收款 2023-02-07 08:36:13 +08:00
hugy e7a460ad25 新增确认收款 close #12 2023-02-06 17:56:37 +08:00
hugy ebde430aec 修复一些内存泄漏 2023-02-06 11:21:13 +08:00
hugy 1216733b82 完善接口文档 close #10 2023-02-04 16:42:57 +08:00
hugy 6dca99474b 修改转发消息接口文档 2023-02-04 16:28:34 +08:00
hugy d818c826e5 使用微信内部函数释放内存 2023-02-04 15:07:01 +08:00
hugy b0e73002ff 新增群消息置顶,修改问题 close #9 2023-02-04 12:04:28 +08:00
29 changed files with 884 additions and 169 deletions
+338 -31
View File
@@ -1,25 +1,28 @@
# wxhelper
wechat hook 。PC端微信逆向学习。支持3.8.0.41,3.8.1.26版本。
wechat hook 。PC端微信逆向学习。支持3.8.0.41,3.8.1.26,3.9.0.28版本。
#### 免责声明:
本仓库发布的内容,仅用于学习研究,请勿用于非法用途和商业用途!如因此产生任何法律纠纷,均与作者无关!
#### 项目说明:
本项目是个人学习学习逆向的项目,主要参考https://github.com/ttttupup/ComWeChatRobot,在此基础上实现了微信的的其它版本的部分内容。
本项目是个人学习学习逆向的项目,主要参考 https://github.com/ljc545w/ComWeChatRobot ,在此基础上实现了微信的的其它版本的部分内容。
#### 使用说明:
支持的版本3.8.0.41,3.8.1.26。
支持的版本3.8.0.41,3.8.1.26,3.9.0.28。
src:主要的dll代码
tool:简单的注入工具,一个是控制台,一个是图形界面。
python: 简单的服务器,用以接收消息内容。
release:编译好的dll。
0.首先安装对应的微信版本,主分支是3.8.0.41版本,3.8.1.26分支对应3.8.1.26版本。
0.首先安装对应的微信版本,主分支是3.8.0.41版本,分支对应相应的微信版本号.
1.通过cmake构建成功后,将wxhelper.dll注入到微信,本地启动tcp server,监听19088端口。
2.通过http协议与dll通信,方便客户端操作。
3.接口的url为http://127.0.0.1:19088,注入成功后,直接进行调用即可。
4.特别注意数据库查询接口需要先调用获取到句柄之后,才能进行查询。
5.相关功能只在win11环境下进行简单测试,其他环境无法保证。
6.注意个别接口在3.8.0.41版本没有实现,具体参考源码。
7.对应分支接口文档都是支持指定版本的,其他版本不支持,请特别注意版本。
8.相应分支的文档对应相应版本,带有删除线的接口表示该版本的暂未实现,其他版本有实现。后续会继续实现。
#### 编译环境
@@ -67,20 +70,69 @@ vcpkg
}
```
4.vscode中右键configure all projects,在Terminal中点击Run Task,如没有先配置build任务,然后运行即可
4.vscode中右键configure all projects,在Terminal中点击Run Task,如没有先配置build任务,然后运行即可
5.命令行注入工具,注入命令
``` javascript
//-i 注入程序名 -p 注入dll路径
// -u 卸载程序名 -d 卸载dll名称
//注入
ConsoleInject.exe -i demo.exe -p E:\testInject.dll
//卸载
ConsoleInject.exe -u demo.exe -d testInject.dll
```
#### 更新说明
2022-12-26 : 增加3.8.1.26版本支持。
2022-12-29 : 新增提取文字功能。
2022-01-02 : 退出微信登录。
2023-01-02 : 退出微信登录。
2022-01-31 : 新增修改群昵称(仅支持3.8.1.26)。
2023-01-31 : 新增修改群昵称(仅支持3.8.1.26)。
2022-02-01 : 新增拍一拍(仅支持3.8.1.26)。
2023-02-01 : 新增拍一拍(仅支持3.8.1.26)。
2023-02-04 : 新增群消息置顶和取消置顶。
2023-02-06 : 新增确认收款。
2023-02-08 : 新增朋友圈消息。
2023-02-09 : 新增3.9.0.28版本基础功能。
#### 功能预览:
0.检查是否登录
1.获取登录微信信息
2.发送文本
5.发送图片
6.发送文件
9.hook消息
10.取消hook消息
11.hook图片
12.取消hook图片
~~17.删除好友~~
25.获取群成员
27.删除群成员
28.增加群成员
31.修改群昵称
32.获取数据库句柄
34.查询数据库
40.转发消息
44.退出登录
~~45.确认收款~~
46.联系人列表
47.获取群详情
48.获取解密图片
~~49.图片提取文字ocr~~
~~50.拍一拍~~
~~51.群消息置顶消息~~
~~52.群消息取消置顶~~
53.朋友圈首页
54.朋友圈下一页
### 接口文档:
#### 0.检查微信登录**
###### 接口功能
> 检查微信是否登录
@@ -174,7 +226,7 @@ vcpkg
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
|wxid |ture |string| 接收人wxid |
|wxid |true |string| 接收人wxid |
|msg|true |string|消息文本内容|
###### 返回字段
@@ -213,7 +265,7 @@ vcpkg
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
|wxid |ture |string| 接收人wxid |
|wxid |true |string| 接收人wxid |
|imagePath|true |string|图片路径|
###### 返回字段
@@ -251,7 +303,7 @@ vcpkg
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
|wxid |ture |string| 接收人wxid |
|wxid |true |string| 接收人wxid |
|filePath|true |string|文件路径|
###### 返回字段
@@ -288,8 +340,8 @@ vcpkg
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
|port |ture |string| 本地服务端端口,用来接收消息内容 |
|ip |ture |string| 服务端ip地址,用来接收消息内容,可以是任意ip,即tcp客户端连接的服务端的ip (3.8.1.26版本)|
|port |true |string| 本地服务端端口,用来接收消息内容 |
|ip |true |string| 服务端ip地址,用来接收消息内容,可以是任意ip,即tcp客户端连接的服务端的ip (3.8.1.26版本)|
###### 返回字段
|返回字段|字段类型|说明 |
@@ -358,7 +410,7 @@ vcpkg
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
|imgDir |ture |string| 图片保存的目录 |
|imgDir |true |string| 图片保存的目录 |
###### 返回字段
@@ -427,7 +479,7 @@ vcpkg
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
|wxid |ture |string| 好友wxid |
|wxid |true |string| 好友wxid |
###### 返回字段
@@ -464,7 +516,7 @@ vcpkg
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
|chatRoomId |ture |string| 群id |
|chatRoomId |true |string| 群id |
###### 返回字段
@@ -505,8 +557,8 @@ vcpkg
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
|chatRoomId |ture |string| 群id |
|memberIds |ture |string| 成员id,以,分割 |
|chatRoomId |true |string| 群id |
|memberIds |true |string| 成员id,以,分割 |
###### 返回字段
@@ -544,8 +596,8 @@ vcpkg
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
|chatRoomId |ture |string| 群id |
|memberIds |ture |string| 成员id,以,分割 |
|chatRoomId |true |string| 群id |
|memberIds |true |string| 成员id,以,分割 |
###### 返回字段
@@ -582,9 +634,9 @@ vcpkg
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
|chatRoomId |ture |string| 群id |
|wxid |ture |string| 自己的id,只能修改自己的群名片 |
|nickName |ture |string| 修改的昵称 |
|chatRoomId |true |string| 群id |
|wxid |true |string| 自己的id,只能修改自己的群名片 |
|nickName |true |string| 修改的昵称 |
###### 返回字段
|返回字段|字段类型|说明 |
@@ -681,8 +733,8 @@ vcpkg
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
|dbHandle |ture |int| 句柄 |
|sql |ture |string| sql语句 |
|dbHandle |true |int| 句柄 |
|sql |true |string| sql语句 |
###### 返回字段
@@ -708,6 +760,43 @@ vcpkg
```
#### 40.转发消息**
###### 接口功能
> 直接转发消息
###### 接口地址
> [/api/?type=40](/api/?type=40)
###### HTTP请求方式
> POST JSON
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
|wxid |true |string| 消息接收人wxid |
|msgid |true |number| 消息id,hook消息接口中返回的消息id |
###### 返回字段
|返回字段|字段类型|说明 |
|---|---|---|
|code|int|返回状态,非0成功|
|result|string|成功提示|
###### 接口示例
入参:
``` javascript
{
"wxid": "filehelper",
"msgid":7215505498606506901
}
```
响应:
``` javascript
{"code":4344,"result":"OK"}
```
#### 44.退出登录**
###### 接口功能
@@ -745,6 +834,45 @@ vcpkg
```
#### 45.确认收款**
###### 接口功能
> 收到转账消息后,自动收款确认。type=49 即是转账消息。
###### 接口地址
> [/api/?type=45](/api/?type=45)
###### HTTP请求方式
> POST JSON
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
|wxid|string|转账人微信id,从hook的消息中获取|
|transcationId|string|从hook的消息中获取对应的字段内容。|
|transferId|string|从hook的消息中获取对应的字段内容。|
###### 返回字段
|返回字段|字段类型|说明 |
|---|---|---|
|code|int|返回状态,1成功|
|result|string|成功提示|
###### 接口示例
入参:
``` javascript
{
"wxid":"wxid_agz5q76f11112",
"transcationId":"10000500012302060002831233124719620",
"transferId":"10000500012023020619112332136412"
}
```
响应:
``` javascript
{"code":1,"result":"OK"}
```
#### 46.联系人列表**
###### 接口功能
@@ -803,7 +931,7 @@ vcpkg
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
|chatRoomId |ture |string| 群id |
|chatRoomId |true |string| 群id |
###### 返回字段
|返回字段|字段类型|说明 |
@@ -846,8 +974,8 @@ vcpkg
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
|imagePath |ture |string| 图片路径 |
|savePath |ture |string| 保存路径 |
|imagePath |true |string| 图片路径 |
|savePath |true |string| 保存路径 |
###### 返回字段
|返回字段|字段类型|说明 |
@@ -886,7 +1014,7 @@ vcpkg
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
|imagePath |ture |string| 图片路径 |
|imagePath |true |string| 图片路径 |
###### 返回字段
|返回字段|字段类型|说明 |
@@ -909,8 +1037,8 @@ vcpkg
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
|chatRoomId |ture |string| 微信群聊id |
|wxid |ture |string| 要拍的用户wxid,如果使用用户自定义的微信号,则不会显示群内昵称 |
|chatRoomId |true |string| 微信群聊id |
|wxid |true |string| 要拍的用户wxid,如果使用用户自定义的微信号,则不会显示群内昵称 |
###### 返回字段
|返回字段|字段类型|说明 |
|---|---|---|
@@ -934,6 +1062,185 @@ vcpkg
```
#### 51.群内消息置顶**
###### 接口功能
> 在群聊里置顶某条消息,可以置顶文字和图片消息,其他消息未测试,部分低版本移动端置顶消息点击后会直接取消,高版本会一直置顶,其他未测试。
###### 接口地址
> [/api/?type=51](/api/?type=51)
###### HTTP请求方式
> POST JSON
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
|wxid |true |string| 置顶消息的发送人wxid |
|msgid |true |string| 消息id |
###### 返回字段
|返回字段|字段类型|说明 |
|---|---|---|
|code|int|返回状态,0成功, -1失败,-2 未查到该消息|
|result|string|成功提示|
###### 接口示例
入参:
``` javascript
{
"wxid":"wxid_oy11111p4422",
"msgid":3334956046278903121
}
```
响应:
``` javascript
{"code":0,"result":"OK"}
```
#### 52.取消群内消息置顶**
###### 接口功能
> 取消置顶的消息。部分低版本移动端会不显示移除消息,但是会正常移除。
###### 接口地址
> [/api/?type=52](/api/?type=52)
###### HTTP请求方式
> POST JSON
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
|chatRoomId |true |string| 微信群聊id |
|msgid |true |string| 消息id |
###### 返回字段
|返回字段|字段类型|说明 |
|---|---|---|
|code|int|返回状态,0成功, -1失败|
|result|string|成功提示|
###### 接口示例
入参:
``` javascript
{
"chatRoomId":"2136311004@chatroom",
"msgid":3374951233278903120
}
```
响应:
``` javascript
{"code":0,"result":"OK"}
```
#### 53.朋友圈首页消息**
###### 接口功能
> 获取朋友圈最新消息,调用之后,会在tcpserver服务中收到朋友圈的消息。格式如下:
``` javascript
{
'data': [
{
'content': '朋友圈[玫瑰][玫瑰]',
'createTime': 1675827480,
'senderId': 'wxid_12333',
'snsId': 14057859804711563695,
'xml': '<TimelineObject><id><![CDATA[1405712322563695]]></id><username><![CDATA[wxid_12333]]></username><createTime><![CDATA[1675827480]]></createTime><contentDescShowType>0</contentDescShowType><contentDescScene>0</contentDescScene><private><![CDATA[0]]></private><contentDesc><![CDATA[朋友圈[玫瑰][玫瑰]]]></contentDesc><contentattr><![CDATA[0]]></contentattr><sourceUserName></sourceUserName><sourceNickName></sourceNickName><statisticsData></statisticsData><weappInfo><appUserName></appUserName><pagePath></pagePath><version><![CDATA[0]]></version><debugMode><![CDATA[0]]></debugMode><shareActionId></shareActionId><isGame><![CDATA[0]]></isGame><messageExtraData></messageExtraData><subType><![CDATA[0]]></subType><preloadResources></preloadResources></weappInfo><canvasInfoXml></canvasInfoXml><ContentObject><contentStyle><![CDATA[2]]></contentStyle><contentSubStyle><![CDATA[0]]></contentSubStyle><title></title><description></description><contentUrl></contentUrl></ContentObject><actionInfo><appMsg><mediaTagName></mediaTagName><messageExt></messageExt><messageAction></messageAction></appMsg></actionInfo><appInfo><id></id></appInfo><location poiClassifyId="" poiName="" poiAddress="" poiClassifyType="0" city=""></location><publicUserName></publicUserName><streamvideo><streamvideourl></streamvideourl><streamvideothumburl></streamvideothumburl><streamvideoweburl></streamvideoweburl></streamvideo></TimelineObject>'
}]
}
```
###### 接口地址
> [/api/?type=53](/api/?type=53)
###### HTTP请求方式
> POST JSON
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
###### 返回字段
|返回字段|字段类型|说明 |
|---|---|---|
|code|int|返回状态,1成功, -1失败|
|result|string|成功提示|
###### 接口示例
入参:
``` javascript
```
响应:
``` javascript
{"code":1,"result":"OK"}
```
#### 54.朋友圈下一页**
###### 接口功能
> 朋友圈下一页,会在tcpserver服务中收到朋友圈的消息。格式如下:
``` javascript
{
'data': [
{
'content': '朋友圈[玫瑰][玫瑰]',
'createTime': 1675827480,
'senderId': 'wxid_12333',
'snsId': 14057859804711563695,
'xml': '<TimelineObject><id><![CDATA[1405712322563695]]></id><username><![CDATA[wxid_12333]]></username><createTime><![CDATA[1675827480]]></createTime><contentDescShowType>0</contentDescShowType><contentDescScene>0</contentDescScene><private><![CDATA[0]]></private><contentDesc><![CDATA[朋友圈[玫瑰][玫瑰]]]></contentDesc><contentattr><![CDATA[0]]></contentattr><sourceUserName></sourceUserName><sourceNickName></sourceNickName><statisticsData></statisticsData><weappInfo><appUserName></appUserName><pagePath></pagePath><version><![CDATA[0]]></version><debugMode><![CDATA[0]]></debugMode><shareActionId></shareActionId><isGame><![CDATA[0]]></isGame><messageExtraData></messageExtraData><subType><![CDATA[0]]></subType><preloadResources></preloadResources></weappInfo><canvasInfoXml></canvasInfoXml><ContentObject><contentStyle><![CDATA[2]]></contentStyle><contentSubStyle><![CDATA[0]]></contentSubStyle><title></title><description></description><contentUrl></contentUrl></ContentObject><actionInfo><appMsg><mediaTagName></mediaTagName><messageExt></messageExt><messageAction></messageAction></appMsg></actionInfo><appInfo><id></id></appInfo><location poiClassifyId="" poiName="" poiAddress="" poiClassifyType="0" city=""></location><publicUserName></publicUserName><streamvideo><streamvideourl></streamvideourl><streamvideothumburl></streamvideothumburl><streamvideoweburl></streamvideoweburl></streamvideo></TimelineObject>'
}]
}
```
###### 接口地址
> [/api/?type=54](/api/?type=54)
###### HTTP请求方式
> POST JSON
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
|snsId |true |string| 朋友圈的snsId |
###### 返回字段
|返回字段|字段类型|说明 |
|---|---|---|
|code|int|返回状态,1成功, -1失败|
|result|string|成功提示|
###### 接口示例
入参:
``` javascript
{
"snsId":"14056334227327177401"
}
```
响应:
``` javascript
{"code":1,"result":"OK"}
```
#### 感谢
https://github.com/ljc545w/ComWeChatRobot
+37
View File
@@ -20,6 +20,8 @@
#include "hook_img.h"
#include "ocr.h"
#include "pat.h"
#include "confirm_receipt.h"
#include "sns.h"
#pragma comment(lib, "ws2_32.lib")
using namespace std;
@@ -478,6 +480,12 @@ void api_handle(mg_http_message *hm, struct mg_connection *c, string &ret) {
break;
}
case WECHAT_GET_TRANSFER: {
wstring wxid = get_http_req_param(hm, j_param, "wxid", is_post);
wstring transcationid = get_http_req_param(hm, j_param, "transcationId", is_post);
wstring transferid = get_http_req_param(hm, j_param, "transferId", is_post);
BOOL response = DoConfirmReceipt(WS2LW(wxid), WS2LW(transcationid), WS2LW(transferid));
json ret_data = {{"msg", response}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_GET_CONTACT_ALL: {
@@ -568,6 +576,35 @@ void api_handle(mg_http_message *hm, struct mg_connection *c, string &ret) {
ret = ret_data.dump();
break;
}
case WECHAT_SET_TOP_MSG:{
wstring wxid = get_http_req_param(hm, j_param, "wxid", is_post);
ULONG64 msgid = get_http_param_ulong64(hm, j_param, "msgid", is_post);
int success = SetTopMsg(WS2LW(wxid),msgid);
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_REMOVE_TOP_MSG:{
wstring room_id = get_http_req_param(hm, j_param, "chatRoomId", is_post);
ULONG64 msgid = get_http_param_ulong64(hm, j_param, "msgid", is_post);
int success = RemoveTopMsg(WS2LW(room_id),msgid);
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_SNS_GET_FIRST_PAGE:{
int success = GetFirstPage();
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_SNS_GET_NEXT_PAGE:{
ULONG64 snsid = get_http_param_ulong64(hm, j_param, "snsId", is_post);
int success = GetNextPage(snsid);
json ret_data = {{"code", success}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
default:
break;
}
+4
View File
@@ -65,6 +65,10 @@ typedef enum WECHAT_HTTP_APISTag
WECHAT_GET_IMG_BY_NAME,
WECHAT_DO_OCR,
WECHAT_SEND_PAT_MSG,
WECHAT_SET_TOP_MSG,
WECHAT_REMOVE_TOP_MSG,
WECHAT_SNS_GET_FIRST_PAGE,
WECHAT_SNS_GET_NEXT_PAGE,
} WECHAT_HTTP_APIS,
*PWECHAT_HTTP_APIS;
+158 -27
View File
@@ -2,20 +2,26 @@
#include "chat_room.h"
#include "common.h"
#include "get_db_handle.h"
#include "wechat_data.h"
#define WX_CHAT_ROOM_MGR_OFFSET 0x67ee70
#define WX_GET_CHAT_ROOM_DETAIL_INFO_OFFSET 0xa73a80
#define WX_NEW_CHAT_ROOM_INFO_OFFSET 0xd07010
#define WX_FREE_CHAT_ROOM_INFO_OFFSET 0xd072f0
#define WX_DEL_CHAT_ROOM_MEMBER_OFFSET 0xa69a50
#define WX_INIT_CHAT_MSG_OFFSET 0xdbf380
#define WX_FREE_CHAT_MSG_OFFSET 0x649ac0
#define WX_ADD_MEMBER_TO_CHAT_ROOM_OFFSET 0xa69560
#define WX_GET_MEMBER_FROM_CHAT_ROOM_OFFSET 0xa749b0
#define WX_INIT_CHAT_ROOM_OFFSET 0xd04d80
#define WX_FREE_CHAT_ROOM_OFFSET 0xa7c620
#define WX_MOD_CHAT_ROOM_MEMBER_NICK_NAME_OFFSET 0xa6f8f0
#include "base64.h"
using namespace std;
#define WX_CHAT_ROOM_MGR_OFFSET 0x72cf60
#define WX_GET_CHAT_ROOM_DETAIL_INFO_OFFSET 0xb6f260
#define WX_NEW_CHAT_ROOM_INFO_OFFSET 0xe15de0
#define WX_FREE_CHAT_ROOM_INFO_OFFSET 0xe160b0
#define WX_DEL_CHAT_ROOM_MEMBER_OFFSET 0xb64180
#define WX_INIT_CHAT_MSG_OFFSET 0xed3be0
#define WX_ADD_MEMBER_TO_CHAT_ROOM_OFFSET 0xb63c50
#define WX_GET_MEMBER_FROM_CHAT_ROOM_OFFSET 0xB70260
#define WX_INIT_CHAT_ROOM_OFFSET 0xe13b30
#define WX_FREE_CHAT_ROOM_OFFSET 0xe13d50
#define WX_MOD_CHAT_ROOM_MEMBER_NICK_NAME_OFFSET 0xb6adf0
#define WX_NEW_CHAT_MSG_OFFSET 0x70e2a0
#define WX_FREE_CHAT_MSG_OFFSET 0x6f4ea0
#define WX_TOP_MSG_OFFSET 0xb727e0
#define WX_REMOVE_TOP_MSG_OFFSET 0xb725a0
int GetChatRoomDetailInfo(wchar_t* chat_room_id, ChatRoomInfoInner& room_info) {
int success = 0;
@@ -41,21 +47,54 @@ int GetChatRoomDetailInfo(wchar_t* chat_room_id, ChatRoomInfoInner& room_info) {
MOV success,EAX
POPAD
}
room_info.chat_room_id.ptr = *(wchar_t**)(chat_room_info + 0x4);
room_info.chat_room_id.length = *(DWORD*)(chat_room_info + 0x8);
room_info.chat_room_id.max_length = *(DWORD*)(chat_room_info + 0xC);
DWORD room_id_len = *(DWORD*)(chat_room_info + 0x8);
DWORD room_id_max_len = *(DWORD*)(chat_room_info + 0xC);
wchar_t * room_id = new wchar_t[room_id_len + 1];
wmemcpy(room_id,*(wchar_t**)(chat_room_info + 0x4),room_id_len + 1);
room_info.chat_room_id.ptr = room_id;
room_info.chat_room_id.length = room_id_len;
room_info.chat_room_id.max_length = room_id_max_len;
room_info.notice.ptr = *(wchar_t**)(chat_room_info + 0x18);
room_info.notice.length = *(DWORD*)(chat_room_info + 0x1C);
room_info.notice.max_length = *(DWORD*)(chat_room_info + 0x20);
DWORD notice_len = *(DWORD*)(chat_room_info + 0x1C);
DWORD notice_max_len = *(DWORD*)(chat_room_info + 0x20);
wchar_t* notice_ptr = *(wchar_t**)(chat_room_info + 0x18);
if(notice_len <= 0){
room_info.notice.ptr = nullptr;
}else{
wchar_t * notice = new wchar_t[notice_len + 1];
wmemcpy(notice,notice_ptr,notice_len+1);
room_info.notice.ptr = notice;
}
room_info.notice.length = notice_len;
room_info.notice.max_length = notice_max_len;
room_info.admin.ptr = *(wchar_t**)(chat_room_info + 0x2C);
room_info.admin.length = *(DWORD*)(chat_room_info + 0x30);
room_info.admin.max_length = *(DWORD*)(chat_room_info + 0x34);
DWORD admin_len = *(DWORD*)(chat_room_info + 0x30);
DWORD admin_max_len = *(DWORD*)(chat_room_info + 0x34);
wchar_t* admin_ptr = *(wchar_t**)(chat_room_info + 0x2C);
if(admin_len <= 0){
room_info.admin.ptr = nullptr;
}else{
wchar_t * admin = new wchar_t[admin_len + 1];
wmemcpy(admin,admin_ptr,admin_len+1);
room_info.admin.ptr = admin;
}
room_info.admin.length = admin_len;
room_info.admin.max_length = admin_max_len;
DWORD xml_len = *(DWORD*)(chat_room_info + 0x54);
DWORD xml_max_len = *(DWORD*)(chat_room_info + 0x58);
wchar_t* xml_ptr = *(wchar_t**)(chat_room_info + 0x50);
if (xml_len <= 0){
room_info.xml.ptr = nullptr;
}else{
wchar_t * xml = new wchar_t[xml_len + 1];
wmemcpy(xml,xml_ptr,xml_len+1);
room_info.xml.ptr = xml;
}
room_info.xml.length = xml_len;
room_info.xml.max_length = xml_max_len;
room_info.xml.ptr = *(wchar_t**)(chat_room_info + 0x50);
room_info.xml.length = *(DWORD*)(chat_room_info + 0x54);
room_info.xml.max_length = *(DWORD*)(chat_room_info + 0x58);
__asm {
PUSHAD
LEA ECX,chat_room_info
@@ -143,8 +182,8 @@ int AddMemberToChatRoom(wchar_t* chat_room_id, wchar_t** wxids,int len){
int GetMemberFromChatRoom(wchar_t* chat_room_id,ChatRoomInner & out){
int success = 0;
WeChatString chat_room(chat_room_id);
DWORD chat_room_ptr = (DWORD) &chat_room;
WeChatString chat_room(chat_room_id);
DWORD chat_room_ptr = (DWORD) &chat_room;
char buffer[0x1D4] = {0};
DWORD base = GetWeChatWinBase();
DWORD get_member_addr = base + WX_GET_MEMBER_FROM_CHAT_ROOM_OFFSET;
@@ -216,5 +255,97 @@ int ModChatRoomMemberNickName(wchar_t* chat_room_id,wchar_t* wxid,wchar_t * nick
MOV success,EAX
POPAD
}
return success;
}
int SetTopMsg(wchar_t* wxid,ULONG64 msg_id){
int success = -1;
char chat_msg[0x2C4] ={0};
DWORD base = GetWeChatWinBase();
DWORD new_chat_msg_addr = base + WX_NEW_CHAT_MSG_OFFSET;
DWORD get_chat_room_mgr_addr = base + WX_CHAT_ROOM_MGR_OFFSET;
DWORD handle_top_msg_addr = base + WX_TOP_MSG_OFFSET;
DWORD free_addr = base + WX_FREE_CHAT_MSG_OFFSET;
vector<string> local_msg = GetChatMsgByMsgId(msg_id);
if(local_msg.empty()){
return -2;
}
string type = local_msg[3];
string status = local_msg[10];
string talker = local_msg[13];
string content = local_msg[14];
wstring w_talker = String2Wstring(talker);
wstring w_content = String2Wstring(content);
int msg_type =stoi(type);
int msg_status =stoi(status);
#ifdef _DEBUG
wcout << "w_talker:" <<w_talker <<endl;
wcout << "w_content:" <<w_content <<endl;
#endif
WeChatString chat_room(w_talker);
WeChatString msg_content(w_content);
WeChatString user_id(wxid);
__asm{
PUSHAD
LEA ECX,chat_msg
CALL new_chat_msg_addr
POPAD
}
memcpy(&chat_msg[0x30],&msg_id,sizeof(msg_id));
memcpy(&chat_msg[0x38],&msg_type,sizeof(msg_type));
memcpy(&chat_msg[0x40],&msg_status,sizeof(msg_status));
memcpy(&chat_msg[0x48],&chat_room,sizeof(chat_room));
memcpy(&chat_msg[0x70],&msg_content,sizeof(msg_content));
memcpy(&chat_msg[0x174],&user_id,sizeof(user_id));
__asm{
PUSHAD
CALL get_chat_room_mgr_addr
PUSH 0x1
LEA EAX,chat_msg
PUSH EAX
CALL handle_top_msg_addr
MOV success,EAX
LEA ECX,chat_msg
CALL free_addr
POPAD
}
return success;
}
int RemoveTopMsg(wchar_t* chat_room_id,ULONG64 msg_id){
int success = -1;
WeChatString chat_room(chat_room_id);
DWORD base = GetWeChatWinBase();
DWORD get_chat_room_mgr_addr = base + WX_CHAT_ROOM_MGR_OFFSET;
DWORD new_chat_msg_addr = base + WX_NEW_CHAT_MSG_OFFSET;
DWORD init_chat_msg_addr = base + WX_INIT_CHAT_MSG_OFFSET;
DWORD remove_top_msg_addr = base + WX_REMOVE_TOP_MSG_OFFSET;
__asm{
PUSHAD
CALL get_chat_room_mgr_addr
MOV EDI,dword ptr [msg_id]
LEA EAX,chat_room
MOV ESI,dword ptr [msg_id + 0x4]
SUB ESP,0x14
MOV ECX,ESP
PUSH EAX
CALL init_chat_msg_addr
PUSH ESI
PUSH EDI
CALL remove_top_msg_addr
MOV success,EAX
POPAD
}
return success;
}
+3
View File
@@ -8,4 +8,7 @@ int AddMemberToChatRoom(wchar_t* chat_room_id, wchar_t** wxids,int len);
int GetMemberFromChatRoom(wchar_t* chat_room_id,ChatRoomInner & out);
int ModChatRoomMemberNickName(wchar_t* chat_room_id,wchar_t* wxid,wchar_t * nick);
int SetTopMsg(wchar_t* wxid,ULONG64 msg_id);
int RemoveTopMsg(wchar_t* chat_room_id,ULONG64 msg_id);
#endif
+1 -1
View File
@@ -25,7 +25,7 @@ wstring utf8_to_unicode(const char *buffer) {
/// @param wstr unicode
/// @return string utf8
string unicode_to_utf8(wchar_t *wstr) {
int c_size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, FALSE);
int c_size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, FALSE);
if (c_size > 0) {
char *buffer = new char[c_size + 1];
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, buffer, c_size, NULL, FALSE);
+7 -8
View File
@@ -1,18 +1,17 @@
#ifndef COMMON_H_
#define COMMON_H_
#include <string>
using namespace std;
#define READ_WSTRING(addr, offset) ((*(DWORD *)(addr + offset + 0x4) == 0) ? wstring(L"") : wstring((wchar_t *)(*(DWORD *)(addr + offset)), *(DWORD *)(addr + offset + 0x4)))
#define READ_WSTRING(addr, offset) ((*(DWORD *)(addr + offset + 0x4) == 0) ? std::wstring(L"") : std::wstring((wchar_t *)(*(DWORD *)(addr + offset)), *(DWORD *)(addr + offset + 0x4)))
/// @brief utf8 转换成unicode
/// @param buffer utf8
/// @return unicode
wstring utf8_to_unicode(const char *buffer);
std::wstring utf8_to_unicode(const char *buffer);
/// @brief unicode转换utf8
/// @param wstr unicode
/// @return utf8
string unicode_to_utf8(wchar_t *wstr);
std::string unicode_to_utf8(wchar_t *wstr);
/// @brief 获取WeChatWin.dll基址
/// @return 基址
@@ -35,7 +34,7 @@ void UnHookAnyAddress(DWORD hook_addr, char *origin);
/// @brief get timeW
/// @param timestamp timestamp
/// @return str
wstring GetTimeW(long long timestamp);
std::wstring GetTimeW(long long timestamp);
/// @brief unicode trans utf8
/// @param str unicode str
/// @return utf8 str
@@ -43,11 +42,11 @@ std::string UnicodeToUtf8(const wchar_t *str);
/// @brief string convert wstring
/// @param str
/// @return
wstring String2Wstring(string str);
std::wstring String2Wstring(std::string str);
/// @brief wstring convert string
/// @param str
/// @return
string Wstring2String(wstring wstr);
std::string Wstring2String(std::wstring wstr);
/// @brief create dir
/// @param path
@@ -56,7 +55,7 @@ BOOL FindOrCreateDirectoryW(const wchar_t *path);
template <typename T1, typename T2>
vector<T1> split(T1 str, T2 letter) {
std::vector<T1> split(T1 str, T2 letter) {
vector<T1> arr;
size_t pos;
while ((pos = str.find_first_of(letter)) != T1::npos) {
+49
View File
@@ -0,0 +1,49 @@
#include "pch.h"
#include "confirm_receipt.h"
#include "common.h"
#include "wechat_data.h"
#define WX_NEW_WCPAYINFO_OFFSET 0x69d2b0
#define WX_FREE_WCPAYINFO_OFFSET 0x68d610
#define WX_CONFIRM_RECEIPT_OFFSET 0x13d5e00
int DoConfirmReceipt(wchar_t *wxid, wchar_t *transcationid,
wchar_t *transferid) {
int success = -1;
WeChatString recv_id(wxid);
WeChatString transcation_id(transcationid);
WeChatString transfer_id(transferid);
char pay_info[0x134] = {0};
DWORD base = GetWeChatWinBase();
DWORD new_pay_info_addr = base + WX_NEW_WCPAYINFO_OFFSET;
DWORD free_pay_info_addr = base + WX_FREE_WCPAYINFO_OFFSET;
DWORD do_confirm_addr = base + WX_CONFIRM_RECEIPT_OFFSET;
__asm {
PUSHAD
LEA ECX,pay_info
CALL new_pay_info_addr
MOV dword ptr [pay_info + 0x4], 0x1
MOV dword ptr [pay_info + 0x4C], 0x1
POPAD
}
memcpy(&pay_info[0x1c], &transcation_id, sizeof(transcation_id));
memcpy(&pay_info[0x38], &transfer_id, sizeof(transfer_id));
__asm {
PUSHAD
PUSH 0x1
SUB ESP,0x8
LEA EDX,recv_id
LEA ECX,pay_info
CALL do_confirm_addr
MOV success,EAX
ADD ESP,0xC
PUSH 0x0
LEA ECX,pay_info
CALL free_pay_info_addr
POPAD
}
return success;
}
+6
View File
@@ -0,0 +1,6 @@
#ifndef CONFIRM_RECEIPT_H
#define CONFIRM_RECEIPT_H
int DoConfirmReceipt(wchar_t* wxid,wchar_t *transcationid, wchar_t *transferid);
#endif
+3 -3
View File
@@ -3,9 +3,9 @@
#include "common.h"
#include "wechat_data.h"
#define WX_CONTACT_MGR_INSTANCE_OFFSET 0x64dc30
#define WX_CONTACT_GET_LIST_OFFSET 0xa9b000
using namespace std;
#define WX_CONTACT_MGR_INSTANCE_OFFSET 0x6f8990
#define WX_CONTACT_GET_LIST_OFFSET 0xb97550
#define WX_CONTACT_DEL_OFFSET 0xa9ef40
#define WX_INIT_CHAT_MSG_OFFSET 0xdbf380
#define WX_DB_QUERY_OFFSET 0xa9ec40
+1 -1
View File
@@ -3,7 +3,7 @@
#include <vector>
#include "wechat_data.h"
int GetAllContact(vector<Contact> &vec);
int GetAllContact(std::vector<Contact> &vec);
+3 -3
View File
@@ -4,7 +4,7 @@
#include "base64.h"
#include "common.h"
#include "new_sqlite3.h"
using namespace std;
/// @brief free data
void FreeResult(vector<vector<SqlResult>> &data) {
@@ -15,11 +15,11 @@ void FreeResult(vector<vector<SqlResult>> &data) {
for (unsigned j = 0; j < data[i].size(); j++) {
SqlResult *sr = (SqlResult *)&data[i][j];
if (sr->column_name) {
delete sr->column_name;
delete[] sr->column_name;
sr->column_name = NULL;
}
if (sr->content) {
delete sr->content;
delete[] sr->content;
sr->content = NULL;
}
}
+1 -2
View File
@@ -2,7 +2,6 @@
#define DB_OPERATION_H_
#include <windows.h>
#include <vector>
using namespace std;
struct SqlResult {
char *column_name;
DWORD column_name_len;
@@ -18,6 +17,6 @@ struct SqlResult {
/// @return
int ExecuteSQL(DWORD db, const char *sql, DWORD callback, void *data);
int Select(DWORD db_hanle, const char *sql,vector<vector<string>> &query_result);
int Select(DWORD db_hanle, const char *sql,std::vector<std::vector<std::string>> &query_result);
#endif
+2 -2
View File
@@ -4,8 +4,8 @@
#include "common.h"
#include "get_db_handle.h"
#include "wechat_data.h"
#define WX_FORWARD_MSG_OFFSET 0xb6a4e0
#define WX_INIT_CHAT_MSG_OFFSET 0xdbf380
#define WX_FORWARD_MSG_OFFSET 0xc715f0
#define WX_INIT_CHAT_MSG_OFFSET 0xed3be0
int ForwardMsg(wchar_t *wxid, unsigned long long msgid) {
int success = 0;
+25 -6
View File
@@ -5,7 +5,7 @@
#include "new_sqlite3.h"
#include "pch.h"
#include "wechat_data.h"
#define CONTACT_G_PINSTANCE 0x2c42e78
#define CONTACT_G_PINSTANCE_OFFSET 0x2e2d628
#define DB_MICRO_MSG_OFFSET 0x68
#define DB_CHAT_MSG_OFFSET 0x1C0
#define DB_MISC_OFFSET 0x3D8
@@ -15,10 +15,10 @@
#define DB_FUNCTION_MSG_OFFSET 0x11B0
#define DB_NAME_OFFSET 0x14
#define PUBLIC_MSG_MGR_OFFSET 0x2c7ec88
#define MULTI_DB_MSG_MGR_OFFSET 0x2c807d0
#define FAVORITE_STORAGE_MGR_OFFSET 0x2c801f8
#define FTS_FAVORITE_MGR_OFFSET 0x2c439b8
#define PUBLIC_MSG_MGR_OFFSET 0x2e6ce20
#define MULTI_DB_MSG_MGR_OFFSET 0x2e6ec84
#define FAVORITE_STORAGE_MGR_OFFSET 0x2e6e630
#define FTS_FAVORITE_MGR_OFFSET 0x2e2e168
using namespace std;
map<wstring, DatabaseInfo> dbmap;
@@ -64,7 +64,7 @@ std::vector<void *> GetDbHandles() {
dbs.clear();
dbmap.clear();
DWORD base = GetWeChatWinBase();
DWORD p_contact_addr = *(DWORD *)(base + CONTACT_G_PINSTANCE);
DWORD p_contact_addr = *(DWORD *)(base + CONTACT_G_PINSTANCE_OFFSET);
DWORD micro_msg_db_addr = *(DWORD *)(p_contact_addr + DB_MICRO_MSG_OFFSET);
DWORD chat_msg_db_addr = *(DWORD *)(p_contact_addr + DB_CHAT_MSG_OFFSET);
DWORD misc_db_addr = *(DWORD *)(p_contact_addr + DB_MISC_OFFSET);
@@ -296,4 +296,23 @@ unsigned int GetLocalIdByMsgId(ULONG64 msgid, int &dbIndex) {
return stoi(result[1][0]);
}
return 0;
}
vector<string> GetChatMsgByMsgId(ULONG64 msgid){
char sql[260] = {0};
sprintf_s(sql, "select localId,TalkerId,MsgSvrID,Type,SubType,IsSender,CreateTime,Sequence,StatusEx,FlagEx,Status,MsgServerSeq,MsgSequence,StrTalker,StrContent,BytesExtra from MSG where MsgSvrID=%llu;", msgid);
wchar_t dbname[20] = {0};
for (int i = 0;; i++) {
swprintf_s(dbname, L"MSG%d.db", i);
DWORD handle = GetDbHandleByDbName(dbname);
if (handle == 0) return {};
vector<vector<string>> result;
int ret = Select(handle, (const char *)sql, result);
#ifdef _DEBUG
cout <<" size =" <<result.size()<<endl;
#endif
if (result.size() == 0) continue;
return result[1];
}
return {};
}
+2
View File
@@ -2,8 +2,10 @@
#define GET_DB_HANDLE_H_
#include "windows.h"
#include <vector>
#include <string>
std::vector<void *> GetDbHandles();
DWORD GetDbHandleByDbName(wchar_t *dbname);
unsigned int GetLocalIdByMsgId(ULONG64 msgid, int &dbIndex);
std::vector<std::string> GetChatMsgByMsgId(ULONG64 msgid);
#endif
+4 -4
View File
@@ -2,13 +2,13 @@
#include "hook_img.h"
#include "common.h"
using namespace std;
// #define WX_HOOK_IMG_OFFSET 0xd7eaa5
// #define WX_HOOK_IMG_NEXT_OFFSET 0xda56e0
#define WX_HOOK_IMG_OFFSET 0xc672cc
#define WX_HOOK_IMG_NEXT_OFFSET 0xd82370
#define WX_SELF_ID_OFFSET 0x2C42A38
#define WX_HOOK_IMG_OFFSET 0xd723dc
#define WX_HOOK_IMG_NEXT_OFFSET 0xe91d90
#define WX_SELF_ID_OFFSET 0x2E2CD3C
#define BUFSIZE 1024
#define JPEG0 0xFF
+1 -2
View File
@@ -1,9 +1,8 @@
#ifndef HOOK_IMG_H_
#define HOOK_IMG_H_
#include "windows.h"
using namespace std;
int HookImg(wstring save_path);
int HookImg(std::wstring save_path);
int UnHookImg();
int GetImgByName(wchar_t* file_path,wchar_t* save_dir);
+83 -6
View File
@@ -10,8 +10,10 @@
using namespace nlohmann;
using namespace std;
#define WX_RECV_MSG_HOOK_OFFSET 0xb97126
#define WX_RECV_MSG_HOOK_NEXT_OFFSET 0x6fc850
#define WX_RECV_MSG_HOOK_OFFSET 0xca0284
#define WX_RECV_MSG_HOOK_NEXT_OFFSET 0x7d5030
#define WX_SNS_HOOK_OFFSET 0x143ef09
#define WX_SNS_HOOK_NEXT_OFFSET 0x143f1b0
// SyncMgr::addMsgListToDB
// #define WX_RECV_MSG_HOOK_OFFSET 0xB9C919
@@ -29,6 +31,13 @@ static DWORD kReceMsgJmpBackAddress =
static DWORD kReceMsgNextAddress =
kWeChatWinBase + WX_RECV_MSG_HOOK_NEXT_OFFSET;
static char kOriginSnsMsgAsmCode[5] = {0};
static DWORD kSnsMsgJmpBackAddress =
kWeChatWinBase + WX_SNS_HOOK_OFFSET + 0x5;
static DWORD kSnsMsgNextAddress =
kWeChatWinBase + WX_SNS_HOOK_NEXT_OFFSET;
struct InnerMessageStruct {
char *buffer;
int length;
@@ -112,7 +121,7 @@ void SendSocketMessage(InnerMessageStruct *msg) {
}
/// @brief msg handle
/// @param msg_addr msg address in memory
void OnRecvMsg(DWORD msg_addr) {
void __cdecl OnRecvMsg(DWORD msg_addr) {
json j_msg;
unsigned long long msgid = *(unsigned long long *)(msg_addr + 0x30);
j_msg["msgId"] = msgid;
@@ -138,9 +147,6 @@ void OnRecvMsg(DWORD msg_addr) {
if (content_len > 0) {
j_msg["content"] =
unicode_to_utf8((wchar_t *)READ_WSTRING(msg_addr, 0x70).c_str());
#ifdef _DEBUG
printf("%s", j_msg["content"].get<std::string>().c_str());
#endif
}
int sign_len = *(DWORD *)(msg_addr + 0x18C);
if (sign_len > 0) {
@@ -175,6 +181,50 @@ void OnRecvMsg(DWORD msg_addr) {
CloseHandle(thread);
}
}
void __cdecl OnSnsTimeLineMsg(DWORD msg_addr) {
json j_sns;
DWORD begin_addr = *(DWORD *)(msg_addr + 0x20);
DWORD end_addr = *(DWORD *)(msg_addr + 0x24);
#ifdef _DEBUG
cout << "begin" <<begin_addr<<endl;
cout << "end" <<end_addr<<endl;
#endif
if (begin_addr == 0) {
j_sns = {{"data", json::array()}};
} else {
while (begin_addr < end_addr) {
json j_item;
j_item["snsId"] = *(unsigned long long *)(begin_addr);
j_item["createTime"] = *(DWORD *)(begin_addr + 0x2C);
j_item["senderId"] =
unicode_to_utf8((wchar_t *)READ_WSTRING(begin_addr, 0x18).c_str());
j_item["content"] =
unicode_to_utf8((wchar_t *)READ_WSTRING(begin_addr, 0x3c).c_str());
j_item["xml"] =
unicode_to_utf8((wchar_t *)READ_WSTRING(begin_addr, 0x384).c_str());
j_sns["data"].push_back(j_item);
begin_addr += 0xB48;
}
}
string jstr = j_sns.dump() + '\n';
InnerMessageStruct *inner_msg = new InnerMessageStruct;
inner_msg->buffer = new char[jstr.size() + 1];
memcpy(inner_msg->buffer, jstr.c_str(), jstr.size() + 1);
inner_msg->length = jstr.size();
HANDLE thread = CreateThread(
NULL, 0, (LPTHREAD_START_ROUTINE)SendSocketMessage, inner_msg, NULL, 0);
if (thread) {
CloseHandle(thread);
}
}
/// @brief hook implement
_declspec(naked) void handle_sync_msg() {
__asm {
@@ -190,6 +240,23 @@ _declspec(naked) void handle_sync_msg() {
}
}
/// @brief hook sns msg implement
_declspec(naked) void handle_sns_msg() {
__asm {
PUSHAD
PUSHFD
PUSH [ESP + 0x24]
CALL OnSnsTimeLineMsg
ADD ESP, 0x4
POPFD
POPAD
CALL kSnsMsgNextAddress
JMP kSnsMsgJmpBackAddress
}
}
/// @brief hook any address address+0x5
/// @param port 端口
/// @return 成功返回1,已经hook返回2,失败返回-1
@@ -210,6 +277,14 @@ int HookRecvMsg(char* client_ip,int port) {
kReceMsgJmpBackAddress = hook_recv_msg_addr + 0x5;
HookAnyAddress(hook_recv_msg_addr, (LPVOID)handle_sync_msg,
kOriginReceMsgAsmCode);
DWORD hook_sns_msg_addr = kWeChatWinBase + WX_SNS_HOOK_OFFSET;
kSnsMsgNextAddress = kWeChatWinBase + WX_SNS_HOOK_NEXT_OFFSET;
kSnsMsgJmpBackAddress = hook_sns_msg_addr + 0x5;
HookAnyAddress(hook_sns_msg_addr, (LPVOID)handle_sns_msg,
kOriginSnsMsgAsmCode);
kMessageHooked = TRUE;
return 1;
}
@@ -218,7 +293,9 @@ int UnHookRecvMsg() {
kServerPort = 0;
if (!kMessageHooked) return 2;
DWORD hook_recv_msg_addr = kWeChatWinBase + WX_RECV_MSG_HOOK_OFFSET;
DWORD hook_sns_addr = kWeChatWinBase + WX_SNS_HOOK_OFFSET;
UnHookAnyAddress(hook_recv_msg_addr, kOriginReceMsgAsmCode);
UnHookAnyAddress(hook_sns_addr, kOriginSnsMsgAsmCode);
kMessageHooked = FALSE;
return 1;
}
+18 -18
View File
@@ -135,24 +135,24 @@
#define SQLITE_NULL 5
#define SQLITE_TEXT 3
#define SQLITE3_EXEC_OFFSET 0x1ba9de0
#define SQLITE3_BACKUP_INIT_OFFSET 0x1b6f760
#define SQLITE3_PREPARE_OFFSET 0x1bb0730
#define SQLITE3_OPEN_OFFSET 0x1bde730
#define SQLITE3_BACKUP_STEP_OFFSET 0x1b6fb60
#define SQLITE3_BACKUP_REMAINING_OFFSET 0x1b702a0
#define SQLITE3_BACKUP_PAGECOUNT_OFFSET 0x1b702b0
#define SQLITE3_BACKUP_FINISH_OFFSET 0x1b701a0
#define SQLITE3_SLEEP_OFFSET 0x1bdef70
#define SQLITE3_ERRCODE_OFFSET 0x1bdd3d0
#define SQLITE3_CLOSE_OFFSET 0x1bdbb20
#define SQLITE3_STEP_OFFSET 0x1b785d0
#define SQLITE3_COLUMN_COUNT_OFFSET 0x1b78ae0
#define SQLITE3_COLUMN_NAME_OFFSET 0x1b793d0
#define SQLITE3_COLUMN_TYPE_OFFSET 0x1b79270
#define SQLITE3_COLUMN_BLOB_OFFSET 0x1b78b20
#define SQLITE3_COLUMN_BYTES_OFFSET 0x1b78c00
#define SQLITE3_FINALIZE_OFFSET 0x1b775a0
#define SQLITE3_EXEC_OFFSET 0x1d5cf70
#define SQLITE3_BACKUP_INIT_OFFSET 0x1d228d0
#define SQLITE3_PREPARE_OFFSET 0x1d638c0
#define SQLITE3_OPEN_OFFSET 0x1d918b0
#define SQLITE3_BACKUP_STEP_OFFSET 0x1d22ce0
#define SQLITE3_BACKUP_REMAINING_OFFSET 0x1d23420
#define SQLITE3_BACKUP_PAGECOUNT_OFFSET 0x1d23430
#define SQLITE3_BACKUP_FINISH_OFFSET 0x1d23320
#define SQLITE3_SLEEP_OFFSET 0x1d920f0
#define SQLITE3_ERRCODE_OFFSET 0x1d90550
#define SQLITE3_CLOSE_OFFSET 0x1d8ecd0
#define SQLITE3_STEP_OFFSET 0x1d2b750
#define SQLITE3_COLUMN_COUNT_OFFSET 0x1d2bc60
#define SQLITE3_COLUMN_NAME_OFFSET 0x1d2c550
#define SQLITE3_COLUMN_TYPE_OFFSET 0x1d2c3f0
#define SQLITE3_COLUMN_BLOB_OFFSET 0x1d2bca0
#define SQLITE3_COLUMN_BYTES_OFFSET 0x1d2bd80
#define SQLITE3_FINALIZE_OFFSET 0x1d2a720
typedef int (*Sqlite3_callback)(void*, int, char**, char**);
+1 -1
View File
@@ -7,7 +7,7 @@
#define WX_INIT_OBJ_OFFSET 0x6cbab0
#define WX_OCR_MANAGER_OFFSET 0x6cff00
#define WX_DO_OCR_TASK_OFFSET 0x11e3210
using namespace std;
int DoOCRTask(wchar_t *img_path, std::string &result) {
int success = -1;
WeChatString path(img_path);
+2 -2
View File
@@ -4,9 +4,9 @@
#include "common.h"
#include "wechat_data.h"
#define WX_PAT_MGR_OFFSET 0x7e91c0
#define WX_PAT_MGR_OFFSET 0x8d0c00
#define WX_SEND_PAT_MSG_OFFSET 0x1228510
#define WX_RET_OFFSET 0x1AE4A45
#define WX_RET_OFFSET 0x1C94D34
int SendPatMsg(wchar_t* chat_room_id, wchar_t* wxid) {
int success = -1;
+16 -15
View File
@@ -4,23 +4,24 @@
#include "common.h"
#include "wechat_data.h"
using namespace std;
#define WX_SELF_NAME_OFFSET 0x2C426E8
#define WX_SELF_MOBILE_OFFSET 0x2C42658
#define WX_SELF_CITY_OFFSET 0x2C426B8
#define WX_SELF_PROVINCE_OFFSET 0x2C426A0
#define WX_SELF_COUNTRY_OFFSET 0x2C42688
#define WX_SELF_ACCOUNT_OFFSET 0x2C42640
#define WX_SELF_ID_OFFSET 0x2C42A38
#define WX_SELF_SMALL_IMG_OFFSET 0x2C4289C
#define WX_SELF_BIG_IMG_OFFSET 0x2C428B4
#define WX_LOGIN_STATUS_OFFSET 0x2c42a10
#define WX_APP_DATA_ROOT_PATH_OFFSET 0x2c84ae0
#define WX_APP_DATA_SAVE_PATH_OFFSET 0x2c65728
#define WX_CURRENT_DATA_PATH_OFFSET 0x2c636fc
#define WX_SELF_NAME_OFFSET 0x2E2CE48
#define WX_SELF_MOBILE_OFFSET 0x2E2CDB8
#define WX_SELF_CITY_OFFSET 0x2E2CE18
#define WX_SELF_PROVINCE_OFFSET 0x2E2CE00
#define WX_SELF_COUNTRY_OFFSET 0x2E2CDE8
#define WX_SELF_ACCOUNT_OFFSET 0x2e2d1d0
#define WX_SELF_ID_OFFSET 0x2E2CD3C
#define WX_SELF_SMALL_IMG_OFFSET 0x2E2D014
#define WX_SELF_BIG_IMG_OFFSET 0x2E2CFFC
#define WX_LOGIN_STATUS_OFFSET 0x2E2D1C0
#define WX_APP_DATA_ROOT_PATH_OFFSET 0x2E73010
#define WX_APP_DATA_SAVE_PATH_OFFSET 0x2E52DB0
#define WX_CURRENT_DATA_PATH_OFFSET 0x2E4F290
#define WX_LOGOUT_OFFSET 0xccc320
#define WX_ACCOUT_SERVICE_OFFSET 0x65bcc0
#define WX_LOGOUT_OFFSET 0xdd5c90
#define WX_ACCOUT_SERVICE_OFFSET 0x707960
int GetSelfInfo(SelfInfoInner &out) {
DWORD base = GetWeChatWinBase();
+5 -5
View File
@@ -3,16 +3,16 @@
#include "common.h"
#include "wechat_data.h"
#define WX_APP_MSG_MGR_OFFSET 0x65df50
#define WX_SEND_FILE_OFFSET 0xa10190
#define WX_INIT_CHAT_MSG_OFFSET 0xdbf380
#define WX_FREE_CHAT_MSG_OFFSET 0x649ac0
#define WX_APP_MSG_MGR_OFFSET 0x709bb0
#define WX_SEND_FILE_OFFSET 0xb06240
#define WX_INIT_CHAT_MSG_OFFSET 0xed3be0
#define WX_FREE_CHAT_MSG_OFFSET 0x6f4ea0
int SendFile(wchar_t *wxid, wchar_t *file_path){
int success = 0;
WeChatString to_user(wxid);
WeChatString path(file_path);
char chat_msg[0x2A8] = {0};
char chat_msg[0x2C4] = {0};
DWORD base = GetWeChatWinBase();
DWORD app_msg_mgr_addr = base + WX_APP_MSG_MGR_OFFSET;
DWORD init_chat_msg_addr = base + WX_INIT_CHAT_MSG_OFFSET;
+5 -5
View File
@@ -3,17 +3,17 @@
#include "common.h"
#include "wechat_data.h"
#define WX_SEND_IMAGE_OFFSET 0xb6a3f0
#define WX_SEND_MESSAGE_MGR_OFFSET 0x65b2a0
#define WX_INIT_CHAT_MSG_OFFSET 0xdbf380
#define WX_FREE_CHAT_MSG_OFFSET 0x649ac0
#define WX_SEND_IMAGE_OFFSET 0xc71500
#define WX_SEND_MESSAGE_MGR_OFFSET 0x706d30
#define WX_INIT_CHAT_MSG_OFFSET 0xed3be0
#define WX_FREE_CHAT_MSG_OFFSET 0x6f4ea0
int SendImage(wchar_t *wxid, wchar_t *image_path){
int success = 0;
WeChatString to_user(wxid);
WeChatString path(image_path);
char chat_msg[0x2A8] ={0};
char chat_msg[0x2C4] ={0};
DWORD base = GetWeChatWinBase();
DWORD send_message_mgr_addr = base + WX_SEND_MESSAGE_MGR_OFFSET;
DWORD init_chat_msg_addr = base + WX_INIT_CHAT_MSG_OFFSET;
+15 -12
View File
@@ -5,40 +5,43 @@
#include "common.h"
#include "wechat_data.h"
#define WX_SEND_TEXT_OFFSET 0xb6a930
#define WX_SEND_TEXT_OFFSET 0xc71a60
#define WX_SEND_MESSAGE_MGR_OFFSET 0x65b2a0
#define WX_SEND_MESSAGE_MGR_OFFSET 0x706d30
#define WX_FREE_CHAT_MSG_OFFSET 0x649ac0
#define WX_FREE_CHAT_MSG_OFFSET 0x6f4ea0
/// @brief 发生文本消息
/// @param wxid wxid
/// @param msg 文本消息
/// @return 成功返回1
int SendText(wchar_t* wxid, wchar_t* msg) {
int SendText(wchar_t* wxid, wchar_t* msg) {
int success = 0;
WeChatString to_user(wxid);
WeChatString text_msg(msg);
wchar_t **msg_pptr = &text_msg.ptr;
char chat_msg[0x2A8] ={0};
DWORD base = GetWeChatWinBase();
DWORD send_message_mgr_addr = base + WX_SEND_MESSAGE_MGR_OFFSET;
DWORD send_text_msg_addr = base + WX_SEND_TEXT_OFFSET;
DWORD free_msg_addr = base + WX_FREE_CHAT_MSG_OFFSET;
DWORD free_chat_msg_addr = base + WX_FREE_CHAT_MSG_OFFSET;
char chat_msg[0x2C4] ={0};
__asm{
PUSHAD
CALL send_message_mgr_addr
PUSH 0x0
PUSH 0x0
PUSH 0x0
PUSH 0x1
PUSH 0x0
MOV EDI,msg_pptr
PUSH EDI
MOV EAX,msg_pptr
PUSH EAX
LEA EDX,to_user
LEA ECX,chat_msg
CALL send_text_msg_addr
ADD ESP,0x14
CALL send_text_msg_addr
MOV success,EAX
LEA ECX,chat_msg
CALL free_msg_addr
ADD ESP,0x18
LEA ECX,chat_msg
CALL free_chat_msg_addr
POPAD
}
return success;
+55
View File
@@ -0,0 +1,55 @@
#include "pch.h"
#include "sns.h"
#include "common.h"
#include "wechat_data.h"
using namespace std;
#define WX_SNS_DATA_MGR_OFFSET 0xbc4100
#define WX_SNS_GET_FIRST_PAGE_OFFSET 0x1427be0
#define WX_SNS_GET_NEXT_PAGE_OFFSET 0x1427c80
int GetFirstPage() {
int success = -1;
DWORD base = GetWeChatWinBase();
DWORD sns_data_mgr_addr = base + WX_SNS_DATA_MGR_OFFSET;
DWORD get_first_page_addr = base + WX_SNS_GET_FIRST_PAGE_OFFSET;
char buff[0xB44] = {};
__asm {
PUSHAD
CALL sns_data_mgr_addr
PUSH 0x1
LEA ECX,buff
PUSH ECX
MOV ECX,EAX
CALL get_first_page_addr
MOV success,EAX
POPAD
}
return success;
}
int GetNextPage(ULONG64 sns_id) {
int success = -1;
DWORD base = GetWeChatWinBase();
DWORD sns_data_mgr_addr = base + WX_SNS_DATA_MGR_OFFSET;
DWORD get_next_page_addr = base + WX_SNS_GET_NEXT_PAGE_OFFSET;
VectorInner temp = {};
__asm{
PUSHAD
CALL sns_data_mgr_addr
LEA ECX,temp
PUSH ECX
MOV EBX,dword ptr [sns_id + 0x4]
PUSH EBX
MOV EDI,dword ptr [sns_id ]
PUSH EDI
MOV ECX,EAX
CALL get_next_page_addr
MOV success,EAX
POPAD
}
return success;
}
+6
View File
@@ -0,0 +1,6 @@
#ifndef SNS_H_
#define SNS_H_
int GetFirstPage();
int GetNextPage(ULONG64 sns_id);
#endif
+33 -15
View File
@@ -4,7 +4,6 @@
// #include <windows.h>
#include <vector>
using namespace std;
struct WeChatString {
wchar_t *ptr;
DWORD length;
@@ -13,7 +12,7 @@ struct WeChatString {
DWORD c_len = 0;
WeChatString() { WeChatString(NULL); }
WeChatString(wstring &s) {
WeChatString(std::wstring &s) {
ptr = (wchar_t *)(s.c_str());
length = s.length();
max_length = s.length() * 2;
@@ -51,7 +50,7 @@ struct DatabaseInfo {
DWORD handle = 0;
wchar_t *db_name = NULL;
DWORD db_name_len = 0;
vector<TableInfo> tables;
std::vector<TableInfo> tables;
DWORD count = 0;
DWORD extrainfo = 0;
};
@@ -101,6 +100,25 @@ struct ChatRoomInfoInner {
WeChatString notice;
WeChatString admin;
WeChatString xml;
~ChatRoomInfoInner(){
if(chat_room_id.ptr){
delete []chat_room_id.ptr;
chat_room_id.ptr = nullptr;
}
if(notice.ptr){
delete []notice.ptr;
notice.ptr = nullptr;
}
if(admin.ptr){
delete []admin.ptr;
admin.ptr = nullptr;
}
if(xml.ptr){
delete []xml.ptr;
xml.ptr = nullptr;
}
}
};
struct VectorInner {
@@ -124,17 +142,17 @@ struct ChatRoomInner{
};
struct SelfInfoInner{
string name;
string city;
string province;
string country;
string account;
string wxid;
string mobile;
string small_img;
string big_img;
string data_root_path;
string data_save_path;
string current_data_path;
std::string name;
std::string city;
std::string province;
std::string country;
std::string account;
std::string wxid;
std::string mobile;
std::string small_img;
std::string big_img;
std::string data_root_path;
std::string data_save_path;
std::string current_data_path;
};
#endif