Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19d146db99 | ||
|
|
67949e16fc | ||
|
|
9f7b1dd273 | ||
|
|
4eab2a2414 | ||
|
|
b8dc032525 | ||
|
|
7e89c6ef2d |
@@ -1,109 +1,3 @@
|
|||||||
# wxhelper
|
|
||||||
wechat hook 。PC端微信逆向学习。支持3.8.0.41,3.8.1.26,3.9.0.28版本。
|
|
||||||
#### 免责声明:
|
|
||||||
本仓库发布的内容,仅用于学习研究,请勿用于非法用途和商业用途!如因此产生任何法律纠纷,均与作者无关!
|
|
||||||
|
|
||||||
#### 项目说明:
|
|
||||||
本项目是个人学习学习逆向的项目,主要参考 https://github.com/ljc545w/ComWeChatRobot ,在此基础上实现了微信的的其它版本的部分内容。
|
|
||||||
|
|
||||||
#### 使用说明:
|
|
||||||
支持的版本3.8.0.41,3.8.1.26, 3.9.0.28。
|
|
||||||
src:主要的dll代码
|
|
||||||
tool:简单的注入工具,一个是控制台,一个是图形界面。
|
|
||||||
python: 简单的服务器,用以接收hook的消息内容。
|
|
||||||
|
|
||||||
|
|
||||||
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.相应分支的文档对应相应版本,带有删除线的接口表示该版本的暂未实现,其他版本有实现。后续会继续实现。
|
|
||||||
|
|
||||||
|
|
||||||
#### 编译环境
|
|
||||||
|
|
||||||
Visual Studio 2022(x86)
|
|
||||||
|
|
||||||
Visual Studio code
|
|
||||||
|
|
||||||
cmake
|
|
||||||
|
|
||||||
vcpkg
|
|
||||||
#### 构建步骤
|
|
||||||
以下是在vscode中操作,vs中的操作类似。
|
|
||||||
1.安装vcpkg,cmake,vscode
|
|
||||||
|
|
||||||
2.安装相应的库,如果安装的版本不同,则根据vcpkg安装成功后提示的find_package修改CMakeLists.txt内容即可。或者自己编译。
|
|
||||||
```
|
|
||||||
vcpkg install mongoose
|
|
||||||
vcpkg install nlohmann-json
|
|
||||||
```
|
|
||||||
3.vscode 配置CMakePresets.json,主要设置CMAKE_C_COMPILER 和CMAKE_CXX_COMPILER 为cl.exe.参考如下
|
|
||||||
```
|
|
||||||
{
|
|
||||||
"name": "x86-release",
|
|
||||||
"displayName": "x86-release",
|
|
||||||
"description": "Sets Ninja generator, build and install directory",
|
|
||||||
"generator": "Ninja",
|
|
||||||
"binaryDir": "${sourceDir}/out/build/${presetName}",
|
|
||||||
"architecture":{
|
|
||||||
"value": "x86",
|
|
||||||
"strategy": "external"
|
|
||||||
},
|
|
||||||
"cacheVariables": {
|
|
||||||
"CMAKE_C_COMPILER": "cl.exe",
|
|
||||||
"CMAKE_CXX_COMPILER": "cl.exe",
|
|
||||||
"CMAKE_BUILD_TYPE": "Release",
|
|
||||||
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}",
|
|
||||||
"CMAKE_TOOLCHAIN_FILE": {
|
|
||||||
"value": "C:/soft/vcpkg/scripts/buildsystems/vcpkg.cmake",
|
|
||||||
"type": "FILEPATH"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"environment": {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
```
|
|
||||||
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 : 新增提取文字功能。
|
|
||||||
|
|
||||||
2023-01-02 : 退出微信登录。
|
|
||||||
|
|
||||||
2023-01-31 : 新增修改群昵称(仅支持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版本基础功能。
|
|
||||||
|
|
||||||
2023-02-13 : 新增查询联系人昵称功能。
|
|
||||||
|
|
||||||
2023-02-17 : 新增通过wxid添加好友和查找微信。
|
|
||||||
|
|
||||||
#### 功能预览:
|
#### 功能预览:
|
||||||
0.检查是否登录
|
0.检查是否登录
|
||||||
@@ -114,7 +8,9 @@ vcpkg
|
|||||||
9.hook消息
|
9.hook消息
|
||||||
10.取消hook消息
|
10.取消hook消息
|
||||||
11.hook图片
|
11.hook图片
|
||||||
12.取消hook图片
|
12.取消hook图片
|
||||||
|
13.hook语音
|
||||||
|
14.取消hook语音
|
||||||
17.删除好友
|
17.删除好友
|
||||||
19.通过手机或qq查找微信
|
19.通过手机或qq查找微信
|
||||||
20.通过wxid添加好友
|
20.通过wxid添加好友
|
||||||
@@ -125,6 +21,8 @@ vcpkg
|
|||||||
31.修改群昵称
|
31.修改群昵称
|
||||||
32.获取数据库句柄
|
32.获取数据库句柄
|
||||||
34.查询数据库
|
34.查询数据库
|
||||||
|
35.hook日志
|
||||||
|
36.关闭hook日志
|
||||||
40.转发消息
|
40.转发消息
|
||||||
44.退出登录
|
44.退出登录
|
||||||
45.确认收款
|
45.确认收款
|
||||||
@@ -138,6 +36,7 @@ vcpkg
|
|||||||
53.朋友圈首页
|
53.朋友圈首页
|
||||||
54.朋友圈下一页
|
54.朋友圈下一页
|
||||||
55.获取联系人或者群名称
|
55.获取联系人或者群名称
|
||||||
|
56.获取消息附件(图片,视频,文件)
|
||||||
### 接口文档:
|
### 接口文档:
|
||||||
|
|
||||||
|
|
||||||
@@ -259,6 +158,47 @@ vcpkg
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### 3.发送@文本消息**
|
||||||
|
###### 接口功能
|
||||||
|
> 发送@文本消息
|
||||||
|
|
||||||
|
###### 接口地址
|
||||||
|
> [/api/?type=3](/api/?type=3)
|
||||||
|
|
||||||
|
###### HTTP请求方式
|
||||||
|
> POST JSON
|
||||||
|
|
||||||
|
###### 请求参数
|
||||||
|
|参数|必选|类型|说明|
|
||||||
|
|---|---|---|---|
|
||||||
|
|chatRoomId |true |string| 群id |
|
||||||
|
|msg|true |string|消息文本内容|
|
||||||
|
|wxids |true |string| @的用户微信id用,号分隔, @所有人 传 notify@all ,区分大小写 |
|
||||||
|
|
||||||
|
###### 返回字段
|
||||||
|
|返回字段|字段类型|说明 |
|
||||||
|
|---|---|---|
|
||||||
|
|code|int|返回状态,不为0成功, 0失败|
|
||||||
|
|result|string|成功提示|
|
||||||
|
|
||||||
|
|
||||||
|
###### 接口示例
|
||||||
|
|
||||||
|
入参:
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
"chatRoomId": "123333@chatroom",
|
||||||
|
"wxids":"notify@all,wxid_122221",
|
||||||
|
"msg": "12333"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
响应:
|
||||||
|
``` javascript
|
||||||
|
{"code":345686720,"result":"OK"}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### 5.发送图片消息**
|
#### 5.发送图片消息**
|
||||||
###### 接口功能
|
###### 接口功能
|
||||||
> 发送图片消息
|
> 发送图片消息
|
||||||
@@ -471,7 +411,77 @@ vcpkg
|
|||||||
响应:
|
响应:
|
||||||
``` javascript
|
``` javascript
|
||||||
{"code":1,"result":"OK"}
|
{"code":1,"result":"OK"}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 13.hook语音**
|
||||||
|
###### 接口功能
|
||||||
|
> hook语音
|
||||||
|
|
||||||
|
###### 接口地址
|
||||||
|
> [/api/?type=13](/api/?type=13)
|
||||||
|
|
||||||
|
###### HTTP请求方式
|
||||||
|
> POST JSON
|
||||||
|
|
||||||
|
###### 请求参数
|
||||||
|
|参数|必选|类型|说明|
|
||||||
|
|---|---|---|---|
|
||||||
|
|voiceDir |true |string| 语音保存的目录 |
|
||||||
|
|
||||||
|
|
||||||
|
###### 返回字段
|
||||||
|
|返回字段|字段类型|说明 |
|
||||||
|
|---|---|---|
|
||||||
|
|code|int|返回状态,1成功, 0失败|
|
||||||
|
|result|string|成功提示|
|
||||||
|
|
||||||
|
|
||||||
|
###### 接口示例
|
||||||
|
入参:
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
"voiceDir":"C:\\other"
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
响应:
|
||||||
|
``` javascript
|
||||||
|
{"code":1,"result":"OK"}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### 14.取消hook语音**
|
||||||
|
###### 接口功能
|
||||||
|
> 取消hook语音
|
||||||
|
|
||||||
|
###### 接口地址
|
||||||
|
> [/api/?type=14](/api/?type=14)
|
||||||
|
|
||||||
|
###### HTTP请求方式
|
||||||
|
> POST JSON
|
||||||
|
|
||||||
|
###### 请求参数
|
||||||
|
|参数|必选|类型|说明|
|
||||||
|
|---|---|---|---|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
###### 返回字段
|
||||||
|
|返回字段|字段类型|说明 |
|
||||||
|
|---|---|---|
|
||||||
|
|code|int|返回状态,1成功, 0失败|
|
||||||
|
|result|string|成功提示|
|
||||||
|
|
||||||
|
|
||||||
|
###### 接口示例
|
||||||
|
入参:
|
||||||
|
``` javascript
|
||||||
|
|
||||||
|
```
|
||||||
|
响应:
|
||||||
|
``` javascript
|
||||||
|
{"code":1,"result":"OK"}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
#### 17.删除好友**
|
#### 17.删除好友**
|
||||||
###### 接口功能
|
###### 接口功能
|
||||||
@@ -900,6 +910,73 @@ vcpkg
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### 35.hook日志**
|
||||||
|
###### 接口功能
|
||||||
|
> hook微信日志,在控制台打印日志,方便调试
|
||||||
|
|
||||||
|
###### 接口地址
|
||||||
|
> [/api/?type=35](/api/?type=35)
|
||||||
|
|
||||||
|
###### HTTP请求方式
|
||||||
|
> POST JSON
|
||||||
|
|
||||||
|
###### 请求参数
|
||||||
|
|参数|必选|类型|说明|
|
||||||
|
|---|---|---|---|
|
||||||
|
|
||||||
|
|
||||||
|
###### 返回字段
|
||||||
|
|返回字段|字段类型|说明 |
|
||||||
|
|---|---|---|
|
||||||
|
|code|int|返回状态,1成功, 0失败|
|
||||||
|
|result|string|成功提示|
|
||||||
|
|
||||||
|
|
||||||
|
###### 接口示例
|
||||||
|
入参:
|
||||||
|
``` javascript
|
||||||
|
|
||||||
|
```
|
||||||
|
响应:
|
||||||
|
``` javascript
|
||||||
|
{"code":1,"result":"OK"}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### 36.取消hook日志**
|
||||||
|
###### 接口功能
|
||||||
|
> 取消hook日志
|
||||||
|
|
||||||
|
###### 接口地址
|
||||||
|
> [/api/?type=36](/api/?type=36)
|
||||||
|
|
||||||
|
###### HTTP请求方式
|
||||||
|
> POST JSON
|
||||||
|
|
||||||
|
###### 请求参数
|
||||||
|
|参数|必选|类型|说明|
|
||||||
|
|---|---|---|---|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
###### 返回字段
|
||||||
|
|返回字段|字段类型|说明 |
|
||||||
|
|---|---|---|
|
||||||
|
|code|int|返回状态,1成功, 0失败|
|
||||||
|
|result|string|成功提示|
|
||||||
|
|
||||||
|
|
||||||
|
###### 接口示例
|
||||||
|
入参:
|
||||||
|
``` javascript
|
||||||
|
|
||||||
|
```
|
||||||
|
响应:
|
||||||
|
``` javascript
|
||||||
|
{"code":1,"result":"OK"}
|
||||||
|
```
|
||||||
|
|
||||||
#### 40.转发消息**
|
#### 40.转发消息**
|
||||||
###### 接口功能
|
###### 接口功能
|
||||||
> 直接转发消息
|
> 直接转发消息
|
||||||
@@ -1423,6 +1500,46 @@ vcpkg
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### 56.获取消息附件**
|
||||||
|
###### 接口功能
|
||||||
|
> 根据消息id,下载消息附件(图片,视频,文件)
|
||||||
|
|
||||||
|
###### 接口地址
|
||||||
|
> [/api/?type=56](/api/?type=56)
|
||||||
|
|
||||||
|
###### HTTP请求方式
|
||||||
|
> POST JSON
|
||||||
|
|
||||||
|
###### 请求参数
|
||||||
|
|参数|必选|类型|说明|
|
||||||
|
|---|---|---|---|
|
||||||
|
|msgId |true |string| 消息id |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
###### 返回字段
|
||||||
|
|返回字段|字段类型|说明 |
|
||||||
|
|---|---|---|
|
||||||
|
|code|int|返回状态,0成功, 非0失败|
|
||||||
|
|result|string|成功提示|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
###### 接口示例
|
||||||
|
入参:
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
"msgId": 3224560917391784099
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
响应:
|
||||||
|
``` javascript
|
||||||
|
{"code":0,"result":"OK"}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
#### 感谢
|
#### 感谢
|
||||||
https://github.com/ljc545w/ComWeChatRobot
|
https://github.com/ljc545w/ComWeChatRobot
|
||||||
|
|
||||||
|
|||||||
+34
@@ -23,6 +23,9 @@
|
|||||||
#include "confirm_receipt.h"
|
#include "confirm_receipt.h"
|
||||||
#include "sns.h"
|
#include "sns.h"
|
||||||
#include "search_contact.h"
|
#include "search_contact.h"
|
||||||
|
#include "download.h"
|
||||||
|
#include "hook_log.h"
|
||||||
|
#include "hook_voice.h"
|
||||||
|
|
||||||
#pragma comment(lib, "ws2_32.lib")
|
#pragma comment(lib, "ws2_32.lib")
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@@ -240,6 +243,16 @@ void api_handle(mg_http_message *hm, struct mg_connection *c, string &ret) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case WECHAT_MSG_SEND_AT: {
|
case WECHAT_MSG_SEND_AT: {
|
||||||
|
wstring chat_room_id = get_http_req_param(hm, j_param, "chatRoomId", is_post);
|
||||||
|
vector<wstring> wxids = get_http_param_array(hm, j_param, "wxids", is_post);
|
||||||
|
wstring msg = get_http_req_param(hm, j_param, "msg", is_post);
|
||||||
|
vector<wchar_t *> wxid_list;
|
||||||
|
for (unsigned int i = 0; i < wxids.size(); i++){
|
||||||
|
wxid_list.push_back(WS2LW(wxids[i]));
|
||||||
|
}
|
||||||
|
int success = SendAtText(WS2LW(chat_room_id), wxid_list.data(), wxid_list.size(),WS2LW(msg));
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case WECHAT_MSG_SEND_CARD: {
|
case WECHAT_MSG_SEND_CARD: {
|
||||||
@@ -298,9 +311,16 @@ void api_handle(mg_http_message *hm, struct mg_connection *c, string &ret) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case WECHAT_MSG_START_VOICE_HOOK: {
|
case WECHAT_MSG_START_VOICE_HOOK: {
|
||||||
|
wstring voice_dir = get_http_req_param(hm, j_param, "voiceDir", is_post);
|
||||||
|
int success = HookVoice(voice_dir);
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case WECHAT_MSG_STOP_VOICE_HOOK: {
|
case WECHAT_MSG_STOP_VOICE_HOOK: {
|
||||||
|
int success = UnHookVoice();
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case WECHAT_CONTACT_GET_LIST: {
|
case WECHAT_CONTACT_GET_LIST: {
|
||||||
@@ -475,9 +495,15 @@ void api_handle(mg_http_message *hm, struct mg_connection *c, string &ret) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case WECHAT_LOG_START_HOOK: {
|
case WECHAT_LOG_START_HOOK: {
|
||||||
|
int success = HookLog();
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case WECHAT_LOG_STOP_HOOK: {
|
case WECHAT_LOG_STOP_HOOK: {
|
||||||
|
int success = UnHookLog();
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case WECHAT_BROWSER_OPEN_WITH_URL: {
|
case WECHAT_BROWSER_OPEN_WITH_URL: {
|
||||||
@@ -642,6 +668,13 @@ void api_handle(mg_http_message *hm, struct mg_connection *c, string &ret) {
|
|||||||
ret = ret_data.dump();
|
ret = ret_data.dump();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case WECHAT_ATTACH_DOWNLOAD:{
|
||||||
|
ULONG64 msg_id = get_http_param_ulong64(hm, j_param, "msgId", is_post);
|
||||||
|
int success = DoDownloadTask(msg_id);
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -717,5 +750,6 @@ int http_close() {
|
|||||||
UnHookRecvMsg();
|
UnHookRecvMsg();
|
||||||
UnHookImg();
|
UnHookImg();
|
||||||
UnHookSearchContact();
|
UnHookSearchContact();
|
||||||
|
UnHookLog();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -70,6 +70,7 @@ typedef enum WECHAT_HTTP_APISTag
|
|||||||
WECHAT_SNS_GET_FIRST_PAGE,
|
WECHAT_SNS_GET_FIRST_PAGE,
|
||||||
WECHAT_SNS_GET_NEXT_PAGE,
|
WECHAT_SNS_GET_NEXT_PAGE,
|
||||||
WECHAT_CONTACT_NAME,
|
WECHAT_CONTACT_NAME,
|
||||||
|
WECHAT_ATTACH_DOWNLOAD,
|
||||||
} WECHAT_HTTP_APIS,
|
} WECHAT_HTTP_APIS,
|
||||||
*PWECHAT_HTTP_APIS;
|
*PWECHAT_HTTP_APIS;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -126,7 +126,7 @@ string Wstring2String(wstring wstr) {
|
|||||||
BOOL FindOrCreateDirectoryW(const wchar_t *path) {
|
BOOL FindOrCreateDirectoryW(const wchar_t *path) {
|
||||||
WIN32_FIND_DATAW fd;
|
WIN32_FIND_DATAW fd;
|
||||||
HANDLE hFind = ::FindFirstFileW(path, &fd);
|
HANDLE hFind = ::FindFirstFileW(path, &fd);
|
||||||
if (hFind != INVALID_HANDLE_VALUE) {
|
if (hFind != INVALID_HANDLE_VALUE && (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||||
FindClose(hFind);
|
FindClose(hFind);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
+183
@@ -0,0 +1,183 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "download.h"
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "get_db_handle.h"
|
||||||
|
|
||||||
|
#include "wechat_data.h"
|
||||||
|
|
||||||
|
#define WX_NEW_CHAT_MSG_OFFSET 0x70e2a0
|
||||||
|
#define WX_GET_PRE_DOWNLOAD_MGR_OFFSET 0x7ae310
|
||||||
|
#define WX_PUSH_ATTACH_TASK_OFFSET 0x7c94a0
|
||||||
|
#define WX_FREE_CHAT_MSG_INSTANCE_COUNTER_OFFSET 0x6f5370
|
||||||
|
#define WX_FREE_CHAT_MSG_OFFSET 0x6f4ea0
|
||||||
|
#define WX_CHAT_MGR_OFFSET 0x732660
|
||||||
|
#define WX_GET_MGR_BY_PREFIX_LOCAL_ID_OFFSET 0xb54950
|
||||||
|
#define WX_GET_CURRENT_DATA_PATH_OFFSET 0xc11140
|
||||||
|
#define WX_APP_MSG_INFO_OFFSET 0x7571d0
|
||||||
|
#define WX_GET_APP_MSG_XML_OFFSET 0xddef80
|
||||||
|
#define WX_FREE_APP_MSG_INFO_OFFSET 0x73d820
|
||||||
|
#define WX_PUSH_THUMB_TASK_OFFSET 0x7c93a0
|
||||||
|
#define WX_VIDEO_MGR_OFFSET 0x7c7300
|
||||||
|
#define WX_DOWNLOAD_VIDEO_IMG_OFFSET 0xcc6d80
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int DoDownloadTask(ULONG64 msg_id) {
|
||||||
|
int success = -1;
|
||||||
|
int db_index = 0;
|
||||||
|
int local_id = GetLocalIdByMsgId(msg_id, db_index);
|
||||||
|
if (local_id < 1) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
char chat_msg[0x2C4] = {0};
|
||||||
|
DWORD base = GetWeChatWinBase();
|
||||||
|
DWORD new_chat_msg_addr = base + WX_NEW_CHAT_MSG_OFFSET;
|
||||||
|
DWORD get_chat_mgr_addr = base + WX_CHAT_MGR_OFFSET;
|
||||||
|
DWORD pre_download_mgr_addr = base + WX_GET_PRE_DOWNLOAD_MGR_OFFSET;
|
||||||
|
DWORD push_attach_task_addr = base + WX_PUSH_ATTACH_TASK_OFFSET;
|
||||||
|
DWORD free_addr = base + WX_FREE_CHAT_MSG_INSTANCE_COUNTER_OFFSET;
|
||||||
|
DWORD get_by_local_Id_addr = base + WX_GET_MGR_BY_PREFIX_LOCAL_ID_OFFSET;
|
||||||
|
DWORD get_current_data_path_addr = base + WX_GET_CURRENT_DATA_PATH_OFFSET;
|
||||||
|
DWORD free_app_msg_info_addr = base + WX_FREE_APP_MSG_INFO_OFFSET;
|
||||||
|
DWORD push_thumb_task_addr = base + WX_PUSH_THUMB_TASK_OFFSET;
|
||||||
|
DWORD video_mgr_addr = base + WX_VIDEO_MGR_OFFSET;
|
||||||
|
DWORD download_video_image_addr = base + WX_VIDEO_MGR_OFFSET;
|
||||||
|
|
||||||
|
WeChatString current_data_path;
|
||||||
|
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
PUSHFD
|
||||||
|
LEA ECX,current_data_path
|
||||||
|
CALL get_current_data_path_addr
|
||||||
|
|
||||||
|
LEA ECX,chat_msg
|
||||||
|
CALL new_chat_msg_addr
|
||||||
|
|
||||||
|
CALL get_chat_mgr_addr
|
||||||
|
PUSH dword ptr [db_index]
|
||||||
|
LEA ECX,chat_msg
|
||||||
|
PUSH dword ptr [local_id]
|
||||||
|
CALL get_by_local_Id_addr
|
||||||
|
ADD ESP,0x8
|
||||||
|
POPFD
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
wstring save_path = L"";
|
||||||
|
wstring thumb_path = L"";
|
||||||
|
if (current_data_path.length > 0) {
|
||||||
|
save_path += current_data_path.ptr;
|
||||||
|
save_path += L"wxhelper";
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!FindOrCreateDirectoryW(save_path.c_str())) {
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
DWORD type = *(DWORD *)(chat_msg + 0x38);
|
||||||
|
wchar_t *content = *(wchar_t **)(chat_msg + 0x70);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 0x3: {
|
||||||
|
save_path += L"\\image";
|
||||||
|
if (!FindOrCreateDirectoryW(save_path.c_str())) {
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
save_path = save_path +L"\\"+ to_wstring(msg_id) + L".png";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x3E:
|
||||||
|
case 0x2B: {
|
||||||
|
save_path += L"\\video";
|
||||||
|
if (!FindOrCreateDirectoryW(save_path.c_str())) {
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
thumb_path = save_path + L"\\"+ to_wstring(msg_id) + L".jpg";
|
||||||
|
save_path = save_path + L"\\"+ to_wstring(msg_id) + L".mp4";
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x31: {
|
||||||
|
save_path += L"\\file";
|
||||||
|
wcout << save_path << endl;
|
||||||
|
if (!FindOrCreateDirectoryW(save_path.c_str())) {
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
char xml_app_msg[0xC80] = {0};
|
||||||
|
DWORD new_app_msg_addr = base + WX_APP_MSG_INFO_OFFSET;
|
||||||
|
DWORD get_xml_addr = base + WX_GET_APP_MSG_XML_OFFSET;
|
||||||
|
WeChatString w_content(content);
|
||||||
|
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
PUSHFD
|
||||||
|
LEA ECX,xml_app_msg
|
||||||
|
CALL new_app_msg_addr
|
||||||
|
PUSH 0x1
|
||||||
|
LEA EAX,w_content
|
||||||
|
PUSH EAX
|
||||||
|
LEA ECX,xml_app_msg
|
||||||
|
CALL get_xml_addr
|
||||||
|
MOV success,EAX
|
||||||
|
LEA ECX,xml_app_msg
|
||||||
|
CALL free_app_msg_info_addr
|
||||||
|
POPFD
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
if (success != 1) {
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
WeChatString *file_name = (WeChatString *)((DWORD)xml_app_msg + 0x44);
|
||||||
|
save_path = save_path +L"\\" + to_wstring(msg_id) + L"_" +
|
||||||
|
wstring(file_name->ptr, file_name->length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
WeChatString w_save_path(save_path);
|
||||||
|
WeChatString w_thumb_path(thumb_path);
|
||||||
|
int temp =1;
|
||||||
|
memcpy(&chat_msg[0x19C], &w_thumb_path, sizeof(w_thumb_path));
|
||||||
|
memcpy(&chat_msg[0x1B0], &w_save_path, sizeof(w_save_path));
|
||||||
|
memcpy(&chat_msg[0x290], &temp, sizeof(temp));
|
||||||
|
// note: the image has been downloaded and will not be downloaded again
|
||||||
|
// use low-level method
|
||||||
|
// this function does not work, need to modify chatmsg.
|
||||||
|
// if (type == 0x3E || type == 0x2B){
|
||||||
|
// __asm{
|
||||||
|
// PUSHAD
|
||||||
|
// PUSHFD
|
||||||
|
// CALL video_mgr_addr
|
||||||
|
// LEA ECX,chat_msg
|
||||||
|
// PUSH ECX
|
||||||
|
// MOV ECX,EAX
|
||||||
|
// CALL download_video_image_addr
|
||||||
|
// POPFD
|
||||||
|
// POPAD
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
PUSHFD
|
||||||
|
CALL pre_download_mgr_addr
|
||||||
|
PUSH 0x1
|
||||||
|
PUSH 0x0
|
||||||
|
LEA ECX,chat_msg
|
||||||
|
PUSH ECX
|
||||||
|
MOV ECX,EAX
|
||||||
|
CALL push_attach_task_addr
|
||||||
|
MOV success,EAX
|
||||||
|
LEA ECX,chat_msg
|
||||||
|
PUSH 0x0
|
||||||
|
CALL free_addr
|
||||||
|
POPFD
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#ifndef DOWNLOAD_H_
|
||||||
|
#define DOWNLOAD_H_
|
||||||
|
|
||||||
|
int DoDownloadTask(ULONG64 msg_id);
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "hook_log.h"
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#define WX_HOOK_LOG_OFFSET 0xed1675
|
||||||
|
#define WX_HOOK_LOG_NEXT_OFFSET 0x2344832
|
||||||
|
|
||||||
|
static int kLogHooked = FALSE;
|
||||||
|
static DWORD kWeChatWinBase = GetWeChatWinBase();
|
||||||
|
static char kOriginLogAsmCode[5] = {0};
|
||||||
|
|
||||||
|
static DWORD kHookLogAddress = kWeChatWinBase + WX_HOOK_LOG_OFFSET;
|
||||||
|
static DWORD kHookLogNextAddress = kWeChatWinBase + WX_HOOK_LOG_NEXT_OFFSET;
|
||||||
|
static DWORD kHookLogJmpBackAddress = kWeChatWinBase + WX_HOOK_LOG_OFFSET + 0x5;
|
||||||
|
|
||||||
|
void log_print(DWORD addr) {
|
||||||
|
if (!addr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DWORD dwId = 0;
|
||||||
|
char *msg = (char *)addr;
|
||||||
|
int size = MultiByteToWideChar(CP_UTF8, 0, msg, -1, 0, 0);
|
||||||
|
wchar_t *w_msg = new wchar_t[size + 1];
|
||||||
|
memset(w_msg, 0, (size + 1) * 2);
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, msg, -1, w_msg, size);
|
||||||
|
size = WideCharToMultiByte(CP_ACP, 0, w_msg, -1, 0, 0, 0, 0);
|
||||||
|
char *ansi_message = new char[size + 1];
|
||||||
|
memset(ansi_message, 0, size + 1);
|
||||||
|
WideCharToMultiByte(CP_ACP, 0, w_msg, -1, ansi_message, size, 0, 0);
|
||||||
|
delete[] w_msg;
|
||||||
|
w_msg = NULL;
|
||||||
|
cout << ansi_message;
|
||||||
|
delete[] ansi_message;
|
||||||
|
ansi_message = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
_declspec(naked) void handle_log() {
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
PUSHFD
|
||||||
|
PUSH EAX
|
||||||
|
CALL log_print
|
||||||
|
ADD ESP, 0x4
|
||||||
|
POPFD
|
||||||
|
POPAD
|
||||||
|
CALL kHookLogNextAddress
|
||||||
|
JMP kHookLogJmpBackAddress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int HookLog() {
|
||||||
|
kWeChatWinBase = GetWeChatWinBase();
|
||||||
|
if (!kWeChatWinBase) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (kLogHooked) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
kHookLogAddress = kWeChatWinBase + WX_HOOK_LOG_OFFSET;
|
||||||
|
kHookLogNextAddress = kWeChatWinBase + WX_HOOK_LOG_NEXT_OFFSET;
|
||||||
|
kHookLogJmpBackAddress = kHookLogAddress + 0x5;
|
||||||
|
HookAnyAddress(kHookLogAddress, (LPVOID)handle_log, kOriginLogAsmCode);
|
||||||
|
kLogHooked = TRUE;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int UnHookLog() {
|
||||||
|
if (!kLogHooked) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
DWORD hook_img_addr = kWeChatWinBase + WX_HOOK_LOG_OFFSET;
|
||||||
|
UnHookAnyAddress(hook_img_addr, kOriginLogAsmCode);
|
||||||
|
kLogHooked = FALSE;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef HOOK_LOG_H_
|
||||||
|
#define HOOK_LOG_H_
|
||||||
|
#include "windows.h"
|
||||||
|
|
||||||
|
int HookLog();
|
||||||
|
int UnHookLog();
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "hook_voice.h"
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#define WX_HOOK_VOICE_OFFSET 0xccd561
|
||||||
|
#define WX_HOOK_VOICE_NEXT_OFFSET 0x1f74560
|
||||||
|
#define WX_SELF_ID_OFFSET 0x2E2CD3C
|
||||||
|
|
||||||
|
static wstring kVoiceStorePath = L"";
|
||||||
|
static int kVoiceHooked = FALSE;
|
||||||
|
static DWORD kWeChatWinBase = GetWeChatWinBase();
|
||||||
|
static char kOriginVoiceAsmCode[5] = {0};
|
||||||
|
|
||||||
|
static DWORD kHookVoiceNextAddress = kWeChatWinBase + WX_HOOK_VOICE_NEXT_OFFSET;
|
||||||
|
static DWORD kHookVoiceJmpBackAddress =
|
||||||
|
kWeChatWinBase + WX_HOOK_VOICE_OFFSET + 0x5;
|
||||||
|
|
||||||
|
void OnHookVoice(DWORD buff,int len , DWORD msg_addr) {
|
||||||
|
DWORD wxid_addr = GetWeChatWinBase() + WX_SELF_ID_OFFSET;
|
||||||
|
string wxid = string(*(char **)wxid_addr, *(DWORD *)(wxid_addr + 0x10));
|
||||||
|
wstring self_id = utf8_to_unicode(wxid.c_str());
|
||||||
|
wstring save_path = kVoiceStorePath + self_id;
|
||||||
|
if (!FindOrCreateDirectoryW(save_path.c_str())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unsigned long long msgid = *(unsigned long long *)(msg_addr + 0x30);
|
||||||
|
save_path = save_path + L"\\" + to_wstring(msgid) + L".amr";
|
||||||
|
HANDLE file_handle = CreateFileW(save_path.c_str(), GENERIC_ALL, 0, NULL,
|
||||||
|
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
if (file_handle == INVALID_HANDLE_VALUE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DWORD bytes_write = 0;
|
||||||
|
WriteFile(file_handle, (LPCVOID)buff, len, &bytes_write, 0);
|
||||||
|
CloseHandle(file_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief hook voice implement
|
||||||
|
_declspec(naked) void handle_voice() {
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
PUSHFD
|
||||||
|
PUSH EDI
|
||||||
|
PUSH EDX
|
||||||
|
PUSH EAX
|
||||||
|
CALL OnHookVoice
|
||||||
|
ADD ESP, 0xC
|
||||||
|
POPFD
|
||||||
|
POPAD
|
||||||
|
CALL kHookVoiceNextAddress
|
||||||
|
JMP kHookVoiceJmpBackAddress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int HookVoice(std::wstring save_path) {
|
||||||
|
kWeChatWinBase = GetWeChatWinBase();
|
||||||
|
if (!kWeChatWinBase) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (kVoiceHooked) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
kVoiceStorePath = save_path;
|
||||||
|
if (kVoiceStorePath.back() != '\\') {
|
||||||
|
kVoiceStorePath += L"\\";
|
||||||
|
}
|
||||||
|
wstring createpath = kVoiceStorePath.substr(0, kVoiceStorePath.length() - 1);
|
||||||
|
if (!FindOrCreateDirectoryW(createpath.c_str())) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
DWORD hook_voice_addr = kWeChatWinBase + WX_HOOK_VOICE_OFFSET;
|
||||||
|
kHookVoiceNextAddress = kWeChatWinBase + WX_HOOK_VOICE_NEXT_OFFSET;
|
||||||
|
static DWORD kHookVoiceJmpBackAddress = hook_voice_addr + 0x5;
|
||||||
|
HookAnyAddress(hook_voice_addr, (LPVOID)handle_voice, kOriginVoiceAsmCode);
|
||||||
|
kVoiceHooked = TRUE;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int UnHookVoice() {
|
||||||
|
if (!kVoiceHooked) return 1;
|
||||||
|
DWORD hook_voice_addr = kWeChatWinBase + WX_HOOK_VOICE_OFFSET;
|
||||||
|
UnHookAnyAddress(hook_voice_addr, kOriginVoiceAsmCode);
|
||||||
|
kVoiceHooked = FALSE;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef HOOK_VOICE_H_
|
||||||
|
#define HOOK_VOICE_H_
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
int HookVoice(std::wstring save_path);
|
||||||
|
|
||||||
|
int UnHookVoice();
|
||||||
|
#endif
|
||||||
+75
-31
@@ -20,10 +20,10 @@ using namespace std;
|
|||||||
#define WX_APP_DATA_SAVE_PATH_OFFSET 0x2E52DB0
|
#define WX_APP_DATA_SAVE_PATH_OFFSET 0x2E52DB0
|
||||||
#define WX_CURRENT_DATA_PATH_OFFSET 0x2E4F290
|
#define WX_CURRENT_DATA_PATH_OFFSET 0x2E4F290
|
||||||
|
|
||||||
#define WX_LOGOUT_OFFSET 0xdd5c90
|
#define WX_LOGOUT_OFFSET 0xdd5c90
|
||||||
#define WX_ACCOUNT_SERVICE_OFFSET 0x707960
|
#define WX_ACCOUNT_SERVICE_OFFSET 0x707960
|
||||||
#define WX_GET_APP_DATA_SAVE_PATH_OFFSET 0xeb4b00
|
#define WX_GET_APP_DATA_SAVE_PATH_OFFSET 0xeb4b00
|
||||||
#define WX_GET_CURRENT_DATA_PATH_OFFSET 0xc11140
|
#define WX_GET_CURRENT_DATA_PATH_OFFSET 0xc11140
|
||||||
int GetSelfInfo(SelfInfoInner &out) {
|
int GetSelfInfo(SelfInfoInner &out) {
|
||||||
DWORD base = GetWeChatWinBase();
|
DWORD base = GetWeChatWinBase();
|
||||||
DWORD accout_service_addr = base + WX_ACCOUNT_SERVICE_OFFSET;
|
DWORD accout_service_addr = base + WX_ACCOUNT_SERVICE_OFFSET;
|
||||||
@@ -41,72 +41,117 @@ int GetSelfInfo(SelfInfoInner &out) {
|
|||||||
*(DWORD *)(service_addr + 0x44 + 0x10) == 0) {
|
*(DWORD *)(service_addr + 0x44 + 0x10) == 0) {
|
||||||
out.wxid = string();
|
out.wxid = string();
|
||||||
} else {
|
} else {
|
||||||
out.wxid = string(*(char **)(service_addr + 0x44),
|
if (*(DWORD *)(service_addr + 0x44 + 0x14) == 0xF) {
|
||||||
*(DWORD *)(service_addr + 0x44 + 0x10));
|
out.wxid = string((char *)(service_addr + 0x44),
|
||||||
|
*(DWORD *)(service_addr + 0x44 + 0x10));
|
||||||
|
} else {
|
||||||
|
out.wxid = string(*(char **)(service_addr + 0x44),
|
||||||
|
*(DWORD *)(service_addr + 0x44 + 0x10));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*(DWORD *)(service_addr + 0xA8) == 0 ||
|
if (*(DWORD *)(service_addr + 0xA8) == 0 ||
|
||||||
*(DWORD *)(service_addr + 0xA8 + 0x10) == 0) {
|
*(DWORD *)(service_addr + 0xA8 + 0x10) == 0) {
|
||||||
out.account = string();
|
out.account = string();
|
||||||
} else {
|
} else {
|
||||||
out.account = string(*(char **)(service_addr + 0xA8),
|
if (*(DWORD *)(service_addr + 0xA8 + 0x14) == 0xF) {
|
||||||
*(DWORD *)(service_addr + 0xA8 + 0x10));
|
out.account = string((char *)(service_addr + 0xA8),
|
||||||
|
*(DWORD *)(service_addr + 0xA8 + 0x10));
|
||||||
|
} else {
|
||||||
|
out.account = string(*(char **)(service_addr + 0xA8),
|
||||||
|
*(DWORD *)(service_addr + 0xA8 + 0x10));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*(DWORD *)(service_addr + 0xC0) == 0 ||
|
if (*(DWORD *)(service_addr + 0xC0) == 0 ||
|
||||||
*(DWORD *)(service_addr + 0xC0 + 0x10) == 0) {
|
*(DWORD *)(service_addr + 0xC0 + 0x10) == 0) {
|
||||||
out.mobile = string();
|
out.mobile = string();
|
||||||
} else {
|
} else {
|
||||||
out.mobile = string((char *)(service_addr + 0xC0),
|
if (*(DWORD *)(service_addr + 0xC0 + 0x14) == 0xF) {
|
||||||
*(DWORD *)(service_addr + 0xC0 + 0x10));
|
out.mobile = string((char *)(service_addr + 0xC0),
|
||||||
|
*(DWORD *)(service_addr + 0xC0 + 0x10));
|
||||||
|
} else {
|
||||||
|
out.mobile = string(*(char **)(service_addr + 0xC0),
|
||||||
|
*(DWORD *)(service_addr + 0xC0 + 0x10));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*(DWORD *)(service_addr + 0xD8) == 0 ||
|
if (*(DWORD *)(service_addr + 0xD8) == 0 ||
|
||||||
*(DWORD *)(service_addr + 0xD8 + 0x10) == 0) {
|
*(DWORD *)(service_addr + 0xD8 + 0x10) == 0) {
|
||||||
out.signature = string();
|
out.signature = string();
|
||||||
} else {
|
} else {
|
||||||
out.signature = string((char *)(service_addr + 0xD8),
|
if (*(DWORD *)(service_addr + 0xD8 + 0x14) == 0xF) {
|
||||||
*(DWORD *)(service_addr + 0xD8 + 0x10));
|
out.signature = string((char *)(service_addr + 0xD8),
|
||||||
|
*(DWORD *)(service_addr + 0xD8 + 0x10));
|
||||||
|
} else {
|
||||||
|
out.signature = string(*(char **)(service_addr + 0xD8),
|
||||||
|
*(DWORD *)(service_addr + 0xD8 + 0x10));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*(DWORD *)(service_addr + 0xF0) == 0 ||
|
if (*(DWORD *)(service_addr + 0xF0) == 0 ||
|
||||||
*(DWORD *)(service_addr + 0xF0 + 0x10) == 0) {
|
*(DWORD *)(service_addr + 0xF0 + 0x10) == 0) {
|
||||||
out.country = string();
|
out.country = string();
|
||||||
} else {
|
} else {
|
||||||
out.country = string((char *)(service_addr + 0xF0),
|
if (*(DWORD *)(service_addr + 0xF0 + 0x14) == 0xF) {
|
||||||
*(DWORD *)(service_addr + 0xF0 + 0x10));
|
out.country = string((char *)(service_addr + 0xF0),
|
||||||
|
*(DWORD *)(service_addr + 0xF0 + 0x10));
|
||||||
|
} else {
|
||||||
|
out.country = string(*(char **)(service_addr + 0xF0),
|
||||||
|
*(DWORD *)(service_addr + 0xF0 + 0x10));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*(DWORD *)(service_addr + 0x108) == 0 ||
|
if (*(DWORD *)(service_addr + 0x108) == 0 ||
|
||||||
*(DWORD *)(service_addr + 0x108 + 0x10) == 0) {
|
*(DWORD *)(service_addr + 0x108 + 0x10) == 0) {
|
||||||
out.province = string();
|
out.province = string();
|
||||||
} else {
|
} else {
|
||||||
out.province = string((char *)(service_addr + 0x108),
|
if (*(DWORD *)(service_addr + 0x108 + 0x14) == 0xF) {
|
||||||
*(DWORD *)(service_addr + 0x108 + 0x10));
|
out.province = string((char *)(service_addr + 0x108),
|
||||||
|
*(DWORD *)(service_addr + 0x108 + 0x10));
|
||||||
|
} else {
|
||||||
|
out.province = string(*(char **)(service_addr + 0x108),
|
||||||
|
*(DWORD *)(service_addr + 0x108 + 0x10));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*(DWORD *)(service_addr + 0x120) == 0 ||
|
if (*(DWORD *)(service_addr + 0x120) == 0 ||
|
||||||
*(DWORD *)(service_addr + 0x120 + 0x10) == 0) {
|
*(DWORD *)(service_addr + 0x120 + 0x10) == 0) {
|
||||||
out.city = string();
|
out.city = string();
|
||||||
} else {
|
} else {
|
||||||
out.city = string((char *)(service_addr + 0x120),
|
if (*(DWORD *)(service_addr + 0x120 + 0x14) == 0xF) {
|
||||||
*(DWORD *)(service_addr + 0x120 + 0x10));
|
out.city = string((char *)(service_addr + 0x120),
|
||||||
|
*(DWORD *)(service_addr + 0x120 + 0x10));
|
||||||
|
} else {
|
||||||
|
out.city = string(*(char **)(service_addr + 0x120),
|
||||||
|
*(DWORD *)(service_addr + 0x120 + 0x10));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*(DWORD *)(service_addr + 0x150) == 0 ||
|
if (*(DWORD *)(service_addr + 0x150) == 0 ||
|
||||||
*(DWORD *)(service_addr + 0x150 + 0x10) == 0) {
|
*(DWORD *)(service_addr + 0x150 + 0x10) == 0) {
|
||||||
out.name = string();
|
out.name = string();
|
||||||
} else {
|
} else {
|
||||||
out.name = string((char *)(service_addr + 0x150),
|
if (*(DWORD *)(service_addr + 0x150 + 0x14) == 0xF) {
|
||||||
*(DWORD *)(service_addr + 0x150 + 0x10));
|
out.name = string((char *)(service_addr + 0x150),
|
||||||
|
*(DWORD *)(service_addr + 0x150 + 0x10));
|
||||||
|
} else {
|
||||||
|
out.name = string(*(char **)(service_addr + 0x150),
|
||||||
|
*(DWORD *)(service_addr + 0x150 + 0x10));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*(DWORD *)(service_addr + 0x304) == 0 ||
|
if (*(DWORD *)(service_addr + 0x304) == 0 ||
|
||||||
*(DWORD *)(service_addr + 0x304 + 0x10) == 0) {
|
*(DWORD *)(service_addr + 0x304 + 0x10) == 0) {
|
||||||
out.head_img = string();
|
out.head_img = string();
|
||||||
} else {
|
} else {
|
||||||
out.head_img = string(*(char **)(service_addr + 0x304),
|
if (*(DWORD *)(service_addr + 0x304 + 0x14) == 0xF) {
|
||||||
*(DWORD *)(service_addr + 0x304 + 0x10));
|
out.head_img = string((char *)(service_addr + 0x304),
|
||||||
|
*(DWORD *)(service_addr + 0x304 + 0x10));
|
||||||
|
} else {
|
||||||
|
out.head_img = string(*(char **)(service_addr + 0x304),
|
||||||
|
*(DWORD *)(service_addr + 0x304 + 0x10));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,21 +170,21 @@ int GetSelfInfo(SelfInfoInner &out) {
|
|||||||
if (data_save_path.ptr) {
|
if (data_save_path.ptr) {
|
||||||
out.data_save_path =
|
out.data_save_path =
|
||||||
Wstring2String(wstring(data_save_path.ptr, data_save_path.length));
|
Wstring2String(wstring(data_save_path.ptr, data_save_path.length));
|
||||||
}else {
|
}
|
||||||
|
else {
|
||||||
out.data_save_path = string();
|
out.data_save_path = string();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current_data_path.ptr) {
|
if (current_data_path.ptr) {
|
||||||
out.current_data_path =
|
out.current_data_path = Wstring2String(
|
||||||
Wstring2String(wstring(current_data_path.ptr, current_data_path.length));
|
wstring(current_data_path.ptr, current_data_path.length));
|
||||||
}else {
|
} else {
|
||||||
out.current_data_path = string();
|
out.current_data_path = string();
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CheckLogin() {
|
||||||
int CheckLogin(){
|
|
||||||
DWORD base = GetWeChatWinBase();
|
DWORD base = GetWeChatWinBase();
|
||||||
DWORD accout_service_addr = base + WX_ACCOUNT_SERVICE_OFFSET;
|
DWORD accout_service_addr = base + WX_ACCOUNT_SERVICE_OFFSET;
|
||||||
DWORD service_addr = NULL;
|
DWORD service_addr = NULL;
|
||||||
@@ -157,16 +202,15 @@ int CheckLogin(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Logout() {
|
||||||
int Logout(){
|
|
||||||
int success = 0;
|
int success = 0;
|
||||||
if(!CheckLogin()){
|
if (!CheckLogin()) {
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
DWORD base = GetWeChatWinBase();
|
DWORD base = GetWeChatWinBase();
|
||||||
DWORD account_service_addr = base + WX_ACCOUNT_SERVICE_OFFSET;
|
DWORD account_service_addr = base + WX_ACCOUNT_SERVICE_OFFSET;
|
||||||
DWORD logout_addr = base + WX_LOGOUT_OFFSET;
|
DWORD logout_addr = base + WX_LOGOUT_OFFSET;
|
||||||
__asm{
|
__asm {
|
||||||
PUSHAD
|
PUSHAD
|
||||||
CALL account_service_addr
|
CALL account_service_addr
|
||||||
PUSH 0x0
|
PUSH 0x0
|
||||||
|
|||||||
@@ -4,12 +4,14 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "wechat_data.h"
|
#include "wechat_data.h"
|
||||||
|
#include "contact.h"
|
||||||
|
|
||||||
#define WX_SEND_TEXT_OFFSET 0xc71a60
|
#define WX_SEND_TEXT_OFFSET 0xc71a60
|
||||||
|
|
||||||
#define WX_SEND_MESSAGE_MGR_OFFSET 0x706d30
|
#define WX_SEND_MESSAGE_MGR_OFFSET 0x706d30
|
||||||
|
|
||||||
#define WX_FREE_CHAT_MSG_OFFSET 0x6f4ea0
|
#define WX_FREE_CHAT_MSG_OFFSET 0x6f4ea0
|
||||||
|
using namespace std;
|
||||||
/// @brief 鍙戠敓鏂囨湰娑堟伅
|
/// @brief 鍙戠敓鏂囨湰娑堟伅
|
||||||
/// @param wxid wxid
|
/// @param wxid wxid
|
||||||
/// @param msg 鏂囨湰娑堟伅
|
/// @param msg 鏂囨湰娑堟伅
|
||||||
@@ -45,4 +47,72 @@ int SendText(wchar_t* wxid, wchar_t* msg) {
|
|||||||
POPAD
|
POPAD
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int SendAtText(wchar_t* chat_room_id,wchar_t** wxids,int len,wchar_t* msg){
|
||||||
|
int success = -1;
|
||||||
|
WeChatString * at_users = new WeChatString[len+1];
|
||||||
|
wstring at_msg = L"";
|
||||||
|
int number =0;
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
wstring nickname;
|
||||||
|
if (!lstrcmpiW((wchar_t *)wxids[i], (wchar_t *)L"notify@all")) {
|
||||||
|
nickname = L"所有人";
|
||||||
|
} else {
|
||||||
|
nickname = GetContactOrChatRoomNickname(wxids[i]);
|
||||||
|
}
|
||||||
|
if (nickname.length() == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
WeChatString temp = {0};
|
||||||
|
temp.ptr = (wchar_t *)wxids[i];
|
||||||
|
temp.length = wcslen((wchar_t *)wxids[i]);
|
||||||
|
temp.max_length = wcslen((wchar_t *)wxids[i]) * 2;
|
||||||
|
memcpy(&at_users[number], &temp, sizeof(WeChatString));
|
||||||
|
at_msg = at_msg + L"@" + nickname + L" ";
|
||||||
|
number++;
|
||||||
|
}
|
||||||
|
if (number < 1){
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
wstring origin(msg);
|
||||||
|
at_msg += origin;
|
||||||
|
AtInner at_list = {0};
|
||||||
|
at_list.start = (DWORD)at_users;
|
||||||
|
at_list.finsh = (DWORD)&at_users[number];
|
||||||
|
at_list.end = (DWORD)&at_users[number];
|
||||||
|
WeChatString to_user(chat_room_id);
|
||||||
|
WeChatString text_msg((wchar_t *)at_msg.c_str());
|
||||||
|
wchar_t **msg_pptr = &text_msg.ptr;
|
||||||
|
|
||||||
|
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_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
|
||||||
|
LEA EAX,at_list
|
||||||
|
PUSH EAX
|
||||||
|
MOV EAX,msg_pptr
|
||||||
|
PUSH EAX
|
||||||
|
LEA EDX,to_user
|
||||||
|
LEA ECX,chat_msg
|
||||||
|
CALL send_text_msg_addr
|
||||||
|
MOV success,EAX
|
||||||
|
ADD ESP,0x18
|
||||||
|
LEA ECX,chat_msg
|
||||||
|
CALL free_chat_msg_addr
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
+1
-1
@@ -2,5 +2,5 @@
|
|||||||
#define SEND_TEXT_H_
|
#define SEND_TEXT_H_
|
||||||
|
|
||||||
int SendText(wchar_t* wxid, wchar_t* msg);
|
int SendText(wchar_t* wxid, wchar_t* msg);
|
||||||
|
int SendAtText(wchar_t* chat_room_id,wchar_t** wxids,int len,wchar_t* msg);
|
||||||
#endif
|
#endif
|
||||||
@@ -180,4 +180,157 @@ struct UserInfo {
|
|||||||
DWORD sex;
|
DWORD sex;
|
||||||
BOOL over;
|
BOOL over;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AtInner{
|
||||||
|
DWORD start;
|
||||||
|
DWORD finsh;
|
||||||
|
DWORD end;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChatMsg {
|
||||||
|
DWORD **field0_0x0;
|
||||||
|
DWORD field1_0x4;
|
||||||
|
ULONG64 sequence;
|
||||||
|
DWORD field3_0x10;
|
||||||
|
DWORD field4_0x14;
|
||||||
|
ULONG64 msgSequence;
|
||||||
|
DWORD localId;
|
||||||
|
DWORD field7_0x24;
|
||||||
|
DWORD field8_0x28;
|
||||||
|
DWORD field9_0x2c;
|
||||||
|
ULONG64 msgId;
|
||||||
|
DWORD type;
|
||||||
|
DWORD isSendMsg;
|
||||||
|
DWORD msgStatus;
|
||||||
|
DWORD timestamp;
|
||||||
|
WeChatString talker;
|
||||||
|
DWORD field16_0x5c;
|
||||||
|
DWORD field17_0x60;
|
||||||
|
DWORD field18_0x64;
|
||||||
|
DWORD field19_0x68;
|
||||||
|
DWORD field20_0x6c;
|
||||||
|
WeChatString content;
|
||||||
|
DWORD field22_0x84;
|
||||||
|
DWORD field23_0x88;
|
||||||
|
DWORD field24_0x8c;
|
||||||
|
DWORD field25_0x90;
|
||||||
|
DWORD field26_0x94;
|
||||||
|
DWORD field27_0x98;
|
||||||
|
DWORD field28_0x9c;
|
||||||
|
DWORD field29_0xa0;
|
||||||
|
DWORD field30_0xa4;
|
||||||
|
DWORD field31_0xa8;
|
||||||
|
DWORD field32_0xac;
|
||||||
|
DWORD field33_0xb0;
|
||||||
|
DWORD field34_0xb4;
|
||||||
|
DWORD field35_0xb8;
|
||||||
|
DWORD field36_0xbc;
|
||||||
|
DWORD field37_0xc0;
|
||||||
|
DWORD field38_0xc4;
|
||||||
|
DWORD field39_0xc8;
|
||||||
|
DWORD field40_0xcc;
|
||||||
|
DWORD field41_0xd0;
|
||||||
|
DWORD field42_0xd4;
|
||||||
|
DWORD field43_0xd8;
|
||||||
|
DWORD field44_0xdc;
|
||||||
|
DWORD field45_0xe0;
|
||||||
|
DWORD field46_0xe4;
|
||||||
|
DWORD field47_0xe8;
|
||||||
|
DWORD field48_0xec;
|
||||||
|
DWORD field49_0xf0;
|
||||||
|
DWORD field50_0xf4;
|
||||||
|
DWORD field51_0xf8;
|
||||||
|
DWORD field52_0xfc;
|
||||||
|
DWORD field53_0x100;
|
||||||
|
DWORD field54_0x104;
|
||||||
|
DWORD field55_0x108;
|
||||||
|
DWORD field56_0x10c;
|
||||||
|
DWORD field57_0x110;
|
||||||
|
DWORD field58_0x114;
|
||||||
|
DWORD field59_0x118;
|
||||||
|
DWORD field60_0x11c;
|
||||||
|
DWORD field61_0x120;
|
||||||
|
DWORD field62_0x124;
|
||||||
|
DWORD field63_0x128;
|
||||||
|
DWORD field64_0x12c;
|
||||||
|
DWORD field65_0x130;
|
||||||
|
DWORD field66_0x134;
|
||||||
|
DWORD field67_0x138;
|
||||||
|
DWORD field68_0x13c;
|
||||||
|
DWORD field69_0x140;
|
||||||
|
DWORD field70_0x144;
|
||||||
|
DWORD field71_0x148;
|
||||||
|
DWORD field72_0x14c;
|
||||||
|
DWORD field73_0x150;
|
||||||
|
DWORD field74_0x154;
|
||||||
|
DWORD field75_0x158;
|
||||||
|
DWORD field76_0x15c;
|
||||||
|
DWORD field77_0x160;
|
||||||
|
DWORD field78_0x164;
|
||||||
|
DWORD field79_0x168;
|
||||||
|
DWORD field80_0x16c;
|
||||||
|
DWORD field81_0x170;
|
||||||
|
WeChatString fromGroup;
|
||||||
|
WeChatString sign;
|
||||||
|
WeChatString thumbPath;
|
||||||
|
WeChatString path;
|
||||||
|
DWORD field86_0x1c4;
|
||||||
|
DWORD field87_0x1c8;
|
||||||
|
DWORD field88_0x1cc;
|
||||||
|
DWORD field89_0x1d0;
|
||||||
|
DWORD field90_0x1d4;
|
||||||
|
DWORD field91_0x1d8;
|
||||||
|
DWORD field92_0x1dc;
|
||||||
|
DWORD field93_0x1e0;
|
||||||
|
DWORD field94_0x1e4;
|
||||||
|
DWORD field95_0x1e8;
|
||||||
|
DWORD field96_0x1ec;
|
||||||
|
WeChatString signature;
|
||||||
|
DWORD field98_0x204;
|
||||||
|
DWORD field99_0x208;
|
||||||
|
DWORD field100_0x20c;
|
||||||
|
DWORD field101_0x210;
|
||||||
|
DWORD field102_0x214;
|
||||||
|
DWORD field103_0x218;
|
||||||
|
DWORD field104_0x21c;
|
||||||
|
DWORD field105_0x220;
|
||||||
|
DWORD field106_0x224;
|
||||||
|
DWORD field107_0x228;
|
||||||
|
DWORD field108_0x22c;
|
||||||
|
DWORD field109_0x230;
|
||||||
|
DWORD field110_0x234;
|
||||||
|
DWORD field111_0x238;
|
||||||
|
DWORD field112_0x23c;
|
||||||
|
DWORD field113_0x240;
|
||||||
|
DWORD field114_0x244;
|
||||||
|
DWORD field115_0x248;
|
||||||
|
DWORD field116_0x24c;
|
||||||
|
DWORD field117_0x250;
|
||||||
|
DWORD field118_0x254;
|
||||||
|
DWORD field119_0x258;
|
||||||
|
DWORD field120_0x25c;
|
||||||
|
DWORD field121_0x260;
|
||||||
|
DWORD field122_0x264;
|
||||||
|
DWORD field123_0x268;
|
||||||
|
DWORD field124_0x26c;
|
||||||
|
DWORD field125_0x270;
|
||||||
|
DWORD field126_0x274;
|
||||||
|
DWORD field127_0x278;
|
||||||
|
DWORD field128_0x27c;
|
||||||
|
DWORD field129_0x280;
|
||||||
|
DWORD field130_0x284;
|
||||||
|
DWORD field131_0x288;
|
||||||
|
DWORD field132_0x28c;
|
||||||
|
DWORD field133_0x290;
|
||||||
|
DWORD field134_0x294;
|
||||||
|
DWORD field135_0x298;
|
||||||
|
DWORD field136_0x29c;
|
||||||
|
DWORD field137_0x2a0;
|
||||||
|
DWORD field138_0x2a4;
|
||||||
|
DWORD field139_0x2a8;
|
||||||
|
DWORD field140_0x2ac;
|
||||||
|
DWORD field141_0x2b0;
|
||||||
|
int field142_0x2b4;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user