Compare commits
46
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80718a2af5 | ||
|
|
aaada266df | ||
|
|
581aacb8ce | ||
|
|
dccc997067 | ||
|
|
0b52a49155 | ||
|
|
4027c4afe6 | ||
|
|
dcbde9203b | ||
|
|
76dc8affe9 | ||
|
|
fd3e6f4a70 | ||
|
|
18e34cd11b | ||
|
|
83d779c072 | ||
|
|
8fa942c741 | ||
|
|
c0b55da015 | ||
|
|
34eb14edb2 | ||
|
|
f9a7924658 | ||
|
|
6105789fcc | ||
|
|
dffdbfb9d7 | ||
|
|
8279303614 | ||
|
|
5ba4f72d5c | ||
|
|
7220b23cb3 | ||
|
|
bfe5b0ee12 | ||
|
|
384aade1a8 | ||
|
|
61c9e6f8c1 | ||
|
|
c590a95425 | ||
|
|
4a3ef64467 | ||
|
|
789b4b6e75 | ||
|
|
1a1a1fe964 | ||
|
|
93798ddeca | ||
|
|
df57bb3317 | ||
|
|
a097ae334a | ||
|
|
4b88354f46 | ||
|
|
8ea5cbec8a | ||
|
|
b8db52d522 | ||
|
|
e52a9b87ed | ||
|
|
19d146db99 | ||
|
|
67949e16fc | ||
|
|
9f7b1dd273 | ||
|
|
4eab2a2414 | ||
|
|
b8dc032525 | ||
|
|
7e89c6ef2d | ||
|
|
82a5ca28db | ||
|
|
861a04e7a0 | ||
|
|
04e7967236 | ||
|
|
822e076a82 | ||
|
|
3ed52a7dbc | ||
|
|
9e5dce93f0 |
@@ -0,0 +1,3 @@
|
||||
[submodule "spdlog"]
|
||||
path = spdlog
|
||||
url = https://github.com/gabime/spdlog
|
||||
+14
-3
@@ -1,23 +1,31 @@
|
||||
cmake_minimum_required(VERSION 3.0.0)
|
||||
# include(ExternalProject)
|
||||
project(wxhelper VERSION 1.0.0)
|
||||
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D '_UNICODE' /D 'UNICODE'")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D '_UNICODE' /D 'UNICODE' ")
|
||||
|
||||
file(GLOB CPP_FILES ${PROJECT_SOURCE_DIR}/src/*.cc ${PROJECT_SOURCE_DIR}/src/*.cpp)
|
||||
|
||||
|
||||
|
||||
include_directories(${VCPKG_INSTALLED_DIR}/x86-windows/include)
|
||||
include_directories(${VCPKG_INSTALLED_DIR}/x86-windows/include ${PROJECT_SOURCE_DIR}/spdlog/include)
|
||||
|
||||
# add_subdirectory(3rd)
|
||||
|
||||
|
||||
add_subdirectory(spdlog)
|
||||
# add_subdirectory(source)
|
||||
|
||||
find_package(nlohmann_json CONFIG REQUIRED)
|
||||
find_package(unofficial-mongoose CONFIG REQUIRED)
|
||||
# find_package(spdlog CONFIG REQUIRED)
|
||||
|
||||
|
||||
|
||||
add_library(wxhelper SHARED ${CPP_FILES} )
|
||||
|
||||
@@ -26,6 +34,9 @@ add_library(wxhelper SHARED ${CPP_FILES} )
|
||||
|
||||
target_link_libraries(wxhelper PRIVATE nlohmann_json::nlohmann_json)
|
||||
target_link_libraries(wxhelper PRIVATE unofficial::mongoose::mongoose)
|
||||
target_link_libraries(wxhelper PRIVATE spdlog::spdlog spdlog::spdlog_header_only)
|
||||
|
||||
# target_link_libraries(wxhelper PRIVATE minhook::minhook)
|
||||
|
||||
SET_TARGET_PROPERTIES(wxhelper PROPERTIES LINKER_LANGUAGE C
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib
|
||||
|
||||
@@ -1,122 +1,22 @@
|
||||
# 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添加好友。
|
||||
|
||||
## 3.9.2.23版本,预览功能没有的接口,不能使用,文档仅供参考。
|
||||
#### 功能预览:
|
||||
0.检查是否登录
|
||||
0.检查是否登录
|
||||
1.获取登录微信信息
|
||||
2.发送文本
|
||||
2.发送文本
|
||||
3.发送@文本
|
||||
5.发送图片
|
||||
6.发送文件
|
||||
9.hook消息
|
||||
10.取消hook消息
|
||||
11.hook图片
|
||||
12.取消hook图片
|
||||
17.删除好友
|
||||
20.通过wxid添加好友
|
||||
12.取消hook图片
|
||||
13.hook语音(不推荐)
|
||||
14.取消hook语音
|
||||
<!-- 17.删除好友 -->
|
||||
19.通过手机或qq查找微信
|
||||
20.通过wxid添加好友
|
||||
23.通过好友申请
|
||||
25.获取群成员
|
||||
26.获取群成员昵称
|
||||
27.删除群成员
|
||||
@@ -124,9 +24,11 @@ vcpkg
|
||||
31.修改群昵称
|
||||
32.获取数据库句柄
|
||||
34.查询数据库
|
||||
35.hook日志
|
||||
36.关闭hook日志
|
||||
40.转发消息
|
||||
44.退出登录
|
||||
45.确认收款
|
||||
<!-- 45.确认收款 -->
|
||||
46.联系人列表
|
||||
47.获取群详情
|
||||
48.获取解密图片
|
||||
@@ -137,6 +39,8 @@ vcpkg
|
||||
53.朋友圈首页
|
||||
54.朋友圈下一页
|
||||
55.获取联系人或者群名称
|
||||
56.获取消息附件(图片,视频,文件)
|
||||
57.获取消息语音文件
|
||||
### 接口文档:
|
||||
|
||||
|
||||
@@ -196,17 +100,17 @@ vcpkg
|
||||
|result|string|成功提示|
|
||||
|data|object|响应内容|
|
||||
|account|string|账号|
|
||||
|bigImage|string|头像大图|
|
||||
|headImage|string|头像|
|
||||
|city|string|城市|
|
||||
|country|string|国家|
|
||||
|currentDataPath|string|当前数据目录|
|
||||
|dataRootPath|string|根目录|
|
||||
|dataSavePath|string|保存目录|
|
||||
|currentDataPath|string|当前数据目录,登录的账号目录|
|
||||
|dataSavePath|string|微信保存目录|
|
||||
|mobile|string|手机|
|
||||
|name|string|昵称|
|
||||
|province|string|省|
|
||||
|smallImage|string|小头像|
|
||||
|wxid|string|wxid|
|
||||
|signature|string|个人签名|
|
||||
|dbKey|string|数据库的SQLCipher的加密key,可以使用该key配合decrypt.py解密数据库
|
||||
|
||||
###### 接口示例
|
||||
入参:
|
||||
@@ -214,7 +118,7 @@ vcpkg
|
||||
```
|
||||
响应:
|
||||
``` javascript
|
||||
{"code":1,"data":{"account":"xx","bigImage":"https://wx.qlogo.cn/mmhead/ver_1xx","city":"xx","country":"CN","currentDataPath":"xxx","dataRootPath":"C:\\xx","dataSavePath":"C:\\xx","mobie":"13949175447","name":"xx","province":"xx","smallImage":"xx","wxid":"xx"},"result":"OK"}
|
||||
{"code":1,"data":{"account":"xx","headImage":"https://wx.qlogo.cn/mmhead/ver_1xx","city":"xx","country":"CN","currentDataPath":"C:\\xx\\wxid_xxxxx","dataSavePath":"C:\\xx","mobie":"13812345678","name":"xx","province":"xx","signature":"xx","wxid":"xx","dbKey":"aaa2222"},"result":"OK"}
|
||||
```
|
||||
|
||||
|
||||
@@ -259,6 +163,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.发送图片消息**
|
||||
###### 接口功能
|
||||
> 发送图片消息
|
||||
@@ -471,7 +416,77 @@ vcpkg
|
||||
响应:
|
||||
``` javascript
|
||||
{"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.删除好友**
|
||||
###### 接口功能
|
||||
@@ -508,6 +523,65 @@ vcpkg
|
||||
{"code":0,"result":"OK"}
|
||||
```
|
||||
|
||||
#### 19.通过手机或qq查找微信**
|
||||
###### 接口功能
|
||||
> 通过手机或qq查找微信
|
||||
|
||||
###### 接口地址
|
||||
> [/api/?type=19](/api/?type=19)
|
||||
|
||||
###### HTTP请求方式
|
||||
> POST JSON
|
||||
|
||||
###### 请求参数
|
||||
|参数|必选|类型|说明|
|
||||
|---|---|---|---|
|
||||
|keyword |true |string| 手机或qq |
|
||||
|
||||
|
||||
###### 返回字段
|
||||
|返回字段|字段类型|说明 |
|
||||
|---|---|---|
|
||||
|code|int|返回状态,1成功, -1失败|
|
||||
|result|string|成功提示|
|
||||
|userInfo|object|用户信息|
|
||||
|  bigImage|string|大头像|
|
||||
|  smallImage|string|小头像|
|
||||
|  city|string|城市|
|
||||
|  nation|string|民族|
|
||||
|  nickname|string|昵称|
|
||||
|  province|string|省|
|
||||
|  sex|number|性别|
|
||||
|  signature|string|签名|
|
||||
|  v2|string|v2|
|
||||
|  v3|string|v3|
|
||||
|
||||
###### 接口示例
|
||||
入参:
|
||||
``` javascript
|
||||
{
|
||||
"keyword":"131111111"
|
||||
}
|
||||
```
|
||||
响应:
|
||||
``` javascript
|
||||
{
|
||||
"code": 1,
|
||||
"result": "OK",
|
||||
"userInfo": {
|
||||
"bigImage": "http://wx.qlogo.cn/mmhead/ver_1/7NIHQAyXeaAPa7Vd7p122mKxgETJwoAiaERdk1sSyOyfnLLQOfElw4G9I32QkZzh7bGfZr2lg0OIQE1Az3cUwtWaLUM79Q/0",
|
||||
"city": "",
|
||||
"nation": "",
|
||||
"nickname": "昵称",
|
||||
"province": "",
|
||||
"sex": 0,
|
||||
"signature": "",
|
||||
"smallImage": "http://wx.qlogo.cn/mmhead/ver_1/7NIHQAyXeaAPa7Vd7p4KR3vxiasmKxgETJwoAiaER23QE6G5mLBcdBQkZzh7bGfZr2lg0OIQE1Az3cUwtWaLUM79Q/132",
|
||||
"v2": "wxid_12333",
|
||||
"v3": "v3_020b3826fd0301000000000098ca23832239a3dba12f95f6b60a0536a1adb6b40fc4086288f46c0b89e6c4eb70c34f118c7b4b6a6845144843b088f0077e406507f821068571289b36c4158a8ac47ec41ae47bee65e9@stranger"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -525,7 +599,42 @@ vcpkg
|
||||
|参数|必选|类型|说明|
|
||||
|---|---|---|---|
|
||||
|wxid |true |string| 好友wxid |
|
||||
|msg |true |string| 验证消息 |
|
||||
|
||||
###### 返回字段
|
||||
|返回字段|字段类型|说明 |
|
||||
|---|---|---|
|
||||
|code|int|返回状态,1成功, -1失败|
|
||||
|result|string|成功提示|
|
||||
|
||||
|
||||
###### 接口示例
|
||||
入参:
|
||||
``` javascript
|
||||
{
|
||||
"wxid":"wxid_o1112222"
|
||||
}
|
||||
```
|
||||
响应:
|
||||
``` javascript
|
||||
{"code":1,"result":"OK"}
|
||||
```
|
||||
|
||||
#### 23.通过好友申请**
|
||||
###### 接口功能
|
||||
> 通过好友的申请
|
||||
|
||||
###### 接口地址
|
||||
> [/api/?type=23](/api/?type=23)
|
||||
|
||||
###### HTTP请求方式
|
||||
> POST JSON
|
||||
|
||||
###### 请求参数
|
||||
|参数|必选|类型|说明|
|
||||
|---|---|---|---|
|
||||
|v3 |true |string| 添加好友消息内容里的encryptusername|
|
||||
|v4 |true |string| 添加好友消息内容里的ticket|
|
||||
|
||||
###### 返回字段
|
||||
|返回字段|字段类型|说明 |
|
||||
@@ -841,6 +950,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.转发消息**
|
||||
###### 接口功能
|
||||
> 直接转发消息
|
||||
@@ -1364,6 +1540,87 @@ 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"}
|
||||
```
|
||||
|
||||
|
||||
#### 57.获取语音文件**
|
||||
###### 接口功能
|
||||
> 根据消息id,获取该语音消息的语音文件,文件为silk3格式,可以自行转换mp3.
|
||||
|
||||
###### 接口地址
|
||||
> [/api/?type=57](/api/?type=57)
|
||||
|
||||
###### HTTP请求方式
|
||||
> POST JSON
|
||||
|
||||
###### 请求参数
|
||||
|参数|必选|类型|说明|
|
||||
|---|---|---|---|
|
||||
|msgId |true |string| 消息id |
|
||||
|voiceDir |true |string| 语音文件保存的目录,文件名称为 (msgid).amr |
|
||||
|
||||
|
||||
###### 返回字段
|
||||
|返回字段|字段类型|说明 |
|
||||
|---|---|---|
|
||||
|code|int|返回状态,1成功, 非0失败|
|
||||
|result|string|成功提示|
|
||||
|
||||
|
||||
|
||||
###### 接口示例
|
||||
入参:
|
||||
``` javascript
|
||||
{
|
||||
"msgId": 3224560917391784099,
|
||||
"voiceDir" : "c:\\voice"
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
响应:
|
||||
``` javascript
|
||||
{"code":1,"result":"OK"}
|
||||
```
|
||||
|
||||
|
||||
#### 感谢
|
||||
https://github.com/ljc545w/ComWeChatRobot
|
||||
|
||||
|
||||
+1630
File diff suppressed because it is too large
Load Diff
+1697
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,595 @@
|
||||
import requests
|
||||
import json
|
||||
|
||||
|
||||
def check_login():
|
||||
"""
|
||||
0.检查是否登录
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=0"
|
||||
payload = {}
|
||||
headers = {}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def user_info():
|
||||
"""
|
||||
登录用户信息
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=8"
|
||||
payload = {}
|
||||
headers = {}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def send_text():
|
||||
"""
|
||||
发送文本
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=2"
|
||||
payload = json.dumps({
|
||||
"wxid": "filehelper",
|
||||
"msg": "123"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def send_at():
|
||||
"""
|
||||
发送@消息
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=3"
|
||||
payload = json.dumps({
|
||||
"chatRoomId": "12333@chatroom",
|
||||
"wxids": "notify@all",
|
||||
"msg": "12333"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def send_img():
|
||||
"""
|
||||
发送图片
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=5"
|
||||
payload = json.dumps({
|
||||
"wxid": "filehelper",
|
||||
"imagePath": "C:/123.png"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def send_file():
|
||||
"""
|
||||
发送文件
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=6"
|
||||
payload = json.dumps({
|
||||
"wxid": "filehelper",
|
||||
"filePath": "C:/test.txt"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def hook_msg():
|
||||
"""
|
||||
hook 消息
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=9"
|
||||
payload = json.dumps({
|
||||
"port": "19099",
|
||||
"ip": "127.0.0.1"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def unhook_msg():
|
||||
"""
|
||||
取消消息hook
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=10"
|
||||
payload = {}
|
||||
headers = {}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def hook_img():
|
||||
"""
|
||||
hook 图片
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=11"
|
||||
payload = json.dumps({
|
||||
"imgDir": "C:\\img"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def unhook_img():
|
||||
"""
|
||||
取消hook 图片
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=12"
|
||||
payload = json.dumps({
|
||||
"imgDir": "C:\\img"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def hook_voice():
|
||||
"""
|
||||
hook 语音
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=56"
|
||||
payload = json.dumps({
|
||||
"msgId": 322456091115784000
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def unhook_voice():
|
||||
"""
|
||||
取消hook 语音
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=14"
|
||||
payload = {}
|
||||
headers = {}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def del_friend():
|
||||
"""
|
||||
删除好友
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=17"
|
||||
payload = json.dumps({
|
||||
"wxid": "wxid_1124423322"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def search_friend():
|
||||
"""
|
||||
网络搜素用户
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=19"
|
||||
payload = json.dumps({
|
||||
"keyword": "13812345678"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def add_friend():
|
||||
"""
|
||||
添加好友
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=20"
|
||||
payload = json.dumps({
|
||||
"wxid": "wxid_o11222334422"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def fetch_chat_room_members():
|
||||
"""
|
||||
群成员
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=25"
|
||||
payload = json.dumps({
|
||||
"chatRoomId": "2112222004@chatroom"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def get_member_nickname():
|
||||
"""
|
||||
群成员昵称
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=26"
|
||||
payload = json.dumps({
|
||||
"chatRoomId": "322333384@chatroom",
|
||||
"memberId": "wxid_4m1112222u22"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def del_member():
|
||||
"""
|
||||
删除群成员
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=27"
|
||||
payload = json.dumps({
|
||||
"chatRoomId": "31122263384@chatroom",
|
||||
"memberIds": "wxid_12223334422"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def add_member():
|
||||
"""
|
||||
增加群成员
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=28"
|
||||
payload = json.dumps({
|
||||
"chatRoomId": "1111163384@chatroom",
|
||||
"memberIds": "wxid_o12222222"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def modify_room_name():
|
||||
"""
|
||||
修改群昵称
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=31"
|
||||
payload = json.dumps({
|
||||
"chatRoomId": "222285428@chatroom",
|
||||
"wxid": "wxid_222222512",
|
||||
"nickName": "qqq"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def get_db_handlers():
|
||||
"""
|
||||
获取sqlite3的操作句柄
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=32"
|
||||
payload = {}
|
||||
headers = {}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def query_db_by_sql():
|
||||
"""
|
||||
查询数据库
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=34"
|
||||
payload = json.dumps({
|
||||
"dbHandle": 116201928,
|
||||
"sql": "select localId from MSG where MsgSvrID= 7533111101686156"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def hook_log():
|
||||
"""
|
||||
hook 日志
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=36"
|
||||
payload = {}
|
||||
headers = {}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def unhook_log():
|
||||
"""
|
||||
取消hook日志
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=37"
|
||||
payload = {}
|
||||
headers = {}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def forward():
|
||||
"""
|
||||
转发消息
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=40"
|
||||
payload = json.dumps({
|
||||
"wxid": "filehelper",
|
||||
"msgid": "705117679011122708"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def logout():
|
||||
"""
|
||||
退出登录
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=44"
|
||||
payload = {}
|
||||
headers = {}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def confirm_receipt():
|
||||
"""
|
||||
确认收款
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=45"
|
||||
payload = json.dumps({
|
||||
"wxid": "wxid_1111112622",
|
||||
"transcationId": "10000500012312222212243388865912",
|
||||
"transferId": "100005000120212222173123036"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def contact_list():
|
||||
"""
|
||||
好友列表
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=46"
|
||||
payload = {}
|
||||
headers = {}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def room_detail():
|
||||
"""
|
||||
群详情
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=47"
|
||||
payload = json.dumps({
|
||||
"chatRoomId": "199134446111@chatroom"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def ocr():
|
||||
"""
|
||||
ocr提取文字
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=49"
|
||||
payload = json.dumps({
|
||||
"imagePath": "C:\\WeChat Files\\b23e84997144dd12f21554b0.dat"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def pat():
|
||||
"""
|
||||
拍一拍
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=50"
|
||||
payload = json.dumps({
|
||||
"chatRoomId": "211111121004@chatroom",
|
||||
"wxid": "wxid_111111111422"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def top_msg():
|
||||
"""
|
||||
消息置顶
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=51"
|
||||
payload = json.dumps({
|
||||
"wxid": "wxid_o11114422",
|
||||
"msgid": 3728307145189195000
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def close_top_msg():
|
||||
"""
|
||||
取消置顶
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=52"
|
||||
payload = json.dumps({
|
||||
"chatRoomId": "213222231004@chatroom",
|
||||
"msgid": 3728307145189195000
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def sns_first():
|
||||
"""
|
||||
朋友圈首页
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=53"
|
||||
payload = {}
|
||||
headers = {}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def sns_next():
|
||||
"""
|
||||
朋友圈下一页
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=54"
|
||||
payload = json.dumps({
|
||||
"snsId": "14091988153735844377"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def query_nickname():
|
||||
"""
|
||||
查询联系人或群名称
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=55"
|
||||
|
||||
payload = json.dumps({
|
||||
"id": "wxid_1112p4422"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def download_msg_attach():
|
||||
"""
|
||||
下载消息附件
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=56"
|
||||
payload = json.dumps({
|
||||
"msgId": 6080100336053626000
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def get_member_info():
|
||||
"""
|
||||
获取群/群成员信息
|
||||
:return:
|
||||
"""
|
||||
url = "127.0.0.1:19088/api/?type=57"
|
||||
payload = json.dumps({
|
||||
"wxid": "wxid_tx8k6tu21112"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
check_login()
|
||||
user_info()
|
||||
send_text()
|
||||
@@ -0,0 +1,51 @@
|
||||
import ctypes
|
||||
import hashlib
|
||||
import hmac
|
||||
|
||||
# pip install pycryptodome
|
||||
from Crypto.Cipher import AES
|
||||
|
||||
|
||||
def decrypt(password, input_file, out_file):
|
||||
password = bytes.fromhex(password.replace(' ', ''))
|
||||
with open(input_file, 'rb') as (f):
|
||||
blist = f.read()
|
||||
print(len(blist))
|
||||
salt = blist[:16]
|
||||
key = hashlib.pbkdf2_hmac('sha1', password, salt, DEFAULT_ITER, KEY_SIZE)
|
||||
first = blist[16:DEFAULT_PAGESIZE]
|
||||
mac_salt = bytes([x ^ 58 for x in salt])
|
||||
mac_key = hashlib.pbkdf2_hmac('sha1', key, mac_salt, 2, KEY_SIZE)
|
||||
hash_mac = hmac.new(mac_key, digestmod='sha1')
|
||||
hash_mac.update(first[:-32])
|
||||
hash_mac.update(bytes(ctypes.c_int(1)))
|
||||
if hash_mac.digest() == first[-32:-12]:
|
||||
print('decrypt success')
|
||||
else:
|
||||
print('password error')
|
||||
return
|
||||
blist = [blist[i:i + DEFAULT_PAGESIZE] for i in range(DEFAULT_PAGESIZE, len(blist), DEFAULT_PAGESIZE)]
|
||||
with open(out_file, 'wb') as (f):
|
||||
f.write(SQLITE_FILE_HEADER)
|
||||
t = AES.new(key, AES.MODE_CBC, first[-48:-32])
|
||||
f.write(t.decrypt(first[:-48]))
|
||||
f.write(first[-48:])
|
||||
for i in blist:
|
||||
t = AES.new(key, AES.MODE_CBC, i[-48:-32])
|
||||
f.write(t.decrypt(i[:-48]))
|
||||
f.write(i[-48:])
|
||||
|
||||
|
||||
def main():
|
||||
password = '565735E30E474DA09250CB5AA047E3940FFA1C6F767C4263B13ABB512933DA49'
|
||||
input_file = 'C:/var/Applet.db'
|
||||
out_file = 'c:/var/out/Applet.db'
|
||||
decrypt(password, input_file, out_file)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
SQLITE_FILE_HEADER = bytes('SQLite format 3', encoding='ASCII') + bytes(1)
|
||||
KEY_SIZE = 32
|
||||
DEFAULT_PAGESIZE = 4096
|
||||
DEFAULT_ITER = 64000
|
||||
main()
|
||||
@@ -0,0 +1,20 @@
|
||||
cmake_minimum_required(VERSION 3.0.0)
|
||||
project(ConsoleApplication VERSION 1.0.0)
|
||||
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D '_UNICODE' /D 'UNICODE'")
|
||||
|
||||
file(GLOB INJECT_CPP_FILES ${PROJECT_SOURCE_DIR}/*.cc ${PROJECT_SOURCE_DIR}/*.cpp)
|
||||
|
||||
add_executable (ConsoleApplication ${INJECT_CPP_FILES})
|
||||
|
||||
SET_TARGET_PROPERTIES(ConsoleApplication PROPERTIES LINKER_LANGUAGE C
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin
|
||||
LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin
|
||||
RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin
|
||||
OUTPUT_NAME "ConsoleApplication"
|
||||
PREFIX "")
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+659
@@ -0,0 +1,659 @@
|
||||
#ifndef __GETOPT_H__
|
||||
/**
|
||||
* DISCLAIMER
|
||||
* This file is part of the mingw-w64 runtime package.
|
||||
*
|
||||
* The mingw-w64 runtime package and its code is distributed in the hope that it
|
||||
* will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR
|
||||
* IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to
|
||||
* warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Sponsored in part by the Defense Advanced Research Projects
|
||||
* Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
||||
*/
|
||||
/*-
|
||||
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Dieter Baron and Thomas Klausner.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma warning(disable:4996);
|
||||
|
||||
#define __GETOPT_H__
|
||||
|
||||
/* All the headers include this file. */
|
||||
#include <crtdefs.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
|
||||
|
||||
#ifdef REPLACE_GETOPT
|
||||
int opterr = 1; /* if error message should be printed */
|
||||
int optind = 1; /* index into parent argv vector */
|
||||
int optopt = '?'; /* character checked for validity */
|
||||
#undef optreset /* see getopt.h */
|
||||
#define optreset __mingw_optreset
|
||||
int optreset; /* reset getopt */
|
||||
char* optarg; /* argument associated with option */
|
||||
#endif
|
||||
|
||||
//extern int optind; /* index of first non-option in argv */
|
||||
//extern int optopt; /* single option character, as parsed */
|
||||
//extern int opterr; /* flag to enable built-in diagnostics... */
|
||||
// /* (user may set to zero, to suppress) */
|
||||
//
|
||||
//extern char *optarg; /* pointer to argument of current option */
|
||||
|
||||
#define PRINT_ERROR ((opterr) && (*options != ':'))
|
||||
|
||||
#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
|
||||
#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
|
||||
#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
|
||||
|
||||
/* return values */
|
||||
#define BADCH (int)'?'
|
||||
#define BADARG ((*options == ':') ? (int)':' : (int)'?')
|
||||
#define INORDER (int)1
|
||||
|
||||
#ifndef __CYGWIN__
|
||||
#define __progname __argv[0]
|
||||
#else
|
||||
extern char __declspec(dllimport)* __progname;
|
||||
#endif
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
static char EMSG[] = "";
|
||||
#else
|
||||
#define EMSG ""
|
||||
#endif
|
||||
|
||||
static int getopt_internal(int, char* const*, const char*,
|
||||
const struct option*, int*, int);
|
||||
static int parse_long_options(char* const*, const char*,
|
||||
const struct option*, int*, int);
|
||||
static int gcd(int, int);
|
||||
static void permute_args(int, int, int, char* const*);
|
||||
|
||||
static char* place = EMSG; /* option letter processing */
|
||||
|
||||
/* XXX: set optreset to 1 rather than these two */
|
||||
static int nonopt_start = -1; /* first non option argument (for permute) */
|
||||
static int nonopt_end = -1; /* first option after non options (for permute) */
|
||||
|
||||
/* Error messages */
|
||||
static const char recargchar[] = "option requires an argument -- %c";
|
||||
static const char recargstring[] = "option requires an argument -- %s";
|
||||
static const char ambig[] = "ambiguous option -- %.*s";
|
||||
static const char noarg[] = "option doesn't take an argument -- %.*s";
|
||||
static const char illoptchar[] = "unknown option -- %c";
|
||||
static const char illoptstring[] = "unknown option -- %s";
|
||||
|
||||
static void
|
||||
_vwarnx(const char* fmt, va_list ap)
|
||||
{
|
||||
(void)fprintf(stderr, "%s: ", __progname);
|
||||
if (fmt != NULL)
|
||||
(void)vfprintf(stderr, fmt, ap);
|
||||
(void)fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
static void
|
||||
warnx(const char* fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
_vwarnx(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the greatest common divisor of a and b.
|
||||
*/
|
||||
static int
|
||||
gcd(int a, int b)
|
||||
{
|
||||
int c;
|
||||
|
||||
c = a % b;
|
||||
while (c != 0) {
|
||||
a = b;
|
||||
b = c;
|
||||
c = a % b;
|
||||
}
|
||||
|
||||
return (b);
|
||||
}
|
||||
|
||||
/*
|
||||
* Exchange the block from nonopt_start to nonopt_end with the block
|
||||
* from nonopt_end to opt_end (keeping the same order of arguments
|
||||
* in each block).
|
||||
*/
|
||||
static void
|
||||
permute_args(int panonopt_start, int panonopt_end, int opt_end,
|
||||
char* const* nargv)
|
||||
{
|
||||
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
|
||||
char* swap;
|
||||
|
||||
/*
|
||||
* compute lengths of blocks and number and size of cycles
|
||||
*/
|
||||
nnonopts = panonopt_end - panonopt_start;
|
||||
nopts = opt_end - panonopt_end;
|
||||
ncycle = gcd(nnonopts, nopts);
|
||||
cyclelen = (opt_end - panonopt_start) / ncycle;
|
||||
|
||||
for (i = 0; i < ncycle; i++) {
|
||||
cstart = panonopt_end + i;
|
||||
pos = cstart;
|
||||
for (j = 0; j < cyclelen; j++) {
|
||||
if (pos >= panonopt_end)
|
||||
pos -= nnonopts;
|
||||
else
|
||||
pos += nopts;
|
||||
swap = nargv[pos];
|
||||
/* LINTED const cast */
|
||||
((char**)nargv)[pos] = nargv[cstart];
|
||||
/* LINTED const cast */
|
||||
((char**)nargv)[cstart] = swap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef REPLACE_GETOPT
|
||||
/*
|
||||
* getopt --
|
||||
* Parse argc/argv argument vector.
|
||||
*
|
||||
* [eventually this will replace the BSD getopt]
|
||||
*/
|
||||
int
|
||||
getopt(int nargc, char* const* nargv, const char* options)
|
||||
{
|
||||
|
||||
/*
|
||||
* We don't pass FLAG_PERMUTE to getopt_internal() since
|
||||
* the BSD getopt(3) (unlike GNU) has never done this.
|
||||
*
|
||||
* Furthermore, since many privileged programs call getopt()
|
||||
* before dropping privileges it makes sense to keep things
|
||||
* as simple (and bug-free) as possible.
|
||||
*/
|
||||
return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
|
||||
}
|
||||
#endif /* REPLACE_GETOPT */
|
||||
|
||||
//extern int getopt(int nargc, char * const *nargv, const char *options);
|
||||
|
||||
#ifdef _BSD_SOURCE
|
||||
/*
|
||||
* BSD adds the non-standard `optreset' feature, for reinitialisation
|
||||
* of `getopt' parsing. We support this feature, for applications which
|
||||
* proclaim their BSD heritage, before including this header; however,
|
||||
* to maintain portability, developers are advised to avoid it.
|
||||
*/
|
||||
# define optreset __mingw_optreset
|
||||
extern int optreset;
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* POSIX requires the `getopt' API to be specified in `unistd.h';
|
||||
* thus, `unistd.h' includes this header. However, we do not want
|
||||
* to expose the `getopt_long' or `getopt_long_only' APIs, when
|
||||
* included in this manner. Thus, close the standard __GETOPT_H__
|
||||
* declarations block, and open an additional __GETOPT_LONG_H__
|
||||
* specific block, only when *not* __UNISTD_H_SOURCED__, in which
|
||||
* to declare the extended API.
|
||||
*/
|
||||
#endif /* !defined(__GETOPT_H__) */
|
||||
|
||||
#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__)
|
||||
#define __GETOPT_LONG_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct option /* specification for a long form option... */
|
||||
{
|
||||
const char* name; /* option name, without leading hyphens */
|
||||
int has_arg; /* does it take an argument? */
|
||||
int* flag; /* where to save its status, or NULL */
|
||||
int val; /* its associated status value */
|
||||
};
|
||||
|
||||
enum /* permitted values for its `has_arg' field... */
|
||||
{
|
||||
no_argument = 0, /* option never takes an argument */
|
||||
required_argument, /* option always requires an argument */
|
||||
optional_argument /* option may take an argument */
|
||||
};
|
||||
|
||||
/*
|
||||
* parse_long_options --
|
||||
* Parse long options in argc/argv argument vector.
|
||||
* Returns -1 if short_too is set and the option does not match long_options.
|
||||
*/
|
||||
static int
|
||||
parse_long_options(char* const* nargv, const char* options,
|
||||
const struct option* long_options, int* idx, int short_too)
|
||||
{
|
||||
char* current_argv, * has_equal;
|
||||
size_t current_argv_len;
|
||||
int i, ambiguous, match;
|
||||
|
||||
#define IDENTICAL_INTERPRETATION(_x, _y) \
|
||||
(long_options[(_x)].has_arg == long_options[(_y)].has_arg && \
|
||||
long_options[(_x)].flag == long_options[(_y)].flag && \
|
||||
long_options[(_x)].val == long_options[(_y)].val)
|
||||
|
||||
current_argv = place;
|
||||
match = -1;
|
||||
ambiguous = 0;
|
||||
|
||||
optind++;
|
||||
|
||||
if ((has_equal = strchr(current_argv, '=')) != NULL) {
|
||||
/* argument found (--option=arg) */
|
||||
current_argv_len = has_equal - current_argv;
|
||||
has_equal++;
|
||||
}
|
||||
else
|
||||
current_argv_len = strlen(current_argv);
|
||||
|
||||
for (i = 0; long_options[i].name; i++) {
|
||||
/* find matching long option */
|
||||
if (strncmp(current_argv, long_options[i].name,
|
||||
current_argv_len))
|
||||
continue;
|
||||
|
||||
if (strlen(long_options[i].name) == current_argv_len) {
|
||||
/* exact match */
|
||||
match = i;
|
||||
ambiguous = 0;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* If this is a known short option, don't allow
|
||||
* a partial match of a single character.
|
||||
*/
|
||||
if (short_too && current_argv_len == 1)
|
||||
continue;
|
||||
|
||||
if (match == -1) /* partial match */
|
||||
match = i;
|
||||
else if (!IDENTICAL_INTERPRETATION(i, match))
|
||||
ambiguous = 1;
|
||||
}
|
||||
if (ambiguous) {
|
||||
/* ambiguous abbreviation */
|
||||
if (PRINT_ERROR)
|
||||
warnx(ambig, (int)current_argv_len,
|
||||
current_argv);
|
||||
optopt = 0;
|
||||
return (BADCH);
|
||||
}
|
||||
if (match != -1) { /* option found */
|
||||
if (long_options[match].has_arg == no_argument
|
||||
&& has_equal) {
|
||||
if (PRINT_ERROR)
|
||||
warnx(noarg, (int)current_argv_len,
|
||||
current_argv);
|
||||
/*
|
||||
* XXX: GNU sets optopt to val regardless of flag
|
||||
*/
|
||||
if (long_options[match].flag == NULL)
|
||||
optopt = long_options[match].val;
|
||||
else
|
||||
optopt = 0;
|
||||
return (BADARG);
|
||||
}
|
||||
if (long_options[match].has_arg == required_argument ||
|
||||
long_options[match].has_arg == optional_argument) {
|
||||
if (has_equal)
|
||||
optarg = has_equal;
|
||||
else if (long_options[match].has_arg ==
|
||||
required_argument) {
|
||||
/*
|
||||
* optional argument doesn't use next nargv
|
||||
*/
|
||||
optarg = nargv[optind++];
|
||||
}
|
||||
}
|
||||
if ((long_options[match].has_arg == required_argument)
|
||||
&& (optarg == NULL)) {
|
||||
/*
|
||||
* Missing argument; leading ':' indicates no error
|
||||
* should be generated.
|
||||
*/
|
||||
if (PRINT_ERROR)
|
||||
warnx(recargstring,
|
||||
current_argv);
|
||||
/*
|
||||
* XXX: GNU sets optopt to val regardless of flag
|
||||
*/
|
||||
if (long_options[match].flag == NULL)
|
||||
optopt = long_options[match].val;
|
||||
else
|
||||
optopt = 0;
|
||||
--optind;
|
||||
return (BADARG);
|
||||
}
|
||||
}
|
||||
else { /* unknown option */
|
||||
if (short_too) {
|
||||
--optind;
|
||||
return (-1);
|
||||
}
|
||||
if (PRINT_ERROR)
|
||||
warnx(illoptstring, current_argv);
|
||||
optopt = 0;
|
||||
return (BADCH);
|
||||
}
|
||||
if (idx)
|
||||
*idx = match;
|
||||
if (long_options[match].flag) {
|
||||
*long_options[match].flag = long_options[match].val;
|
||||
return (0);
|
||||
}
|
||||
else
|
||||
return (long_options[match].val);
|
||||
#undef IDENTICAL_INTERPRETATION
|
||||
}
|
||||
|
||||
/*
|
||||
* getopt_internal --
|
||||
* Parse argc/argv argument vector. Called by user level routines.
|
||||
*/
|
||||
static int
|
||||
getopt_internal(int nargc, char* const* nargv, const char* options,
|
||||
const struct option* long_options, int* idx, int flags)
|
||||
{
|
||||
char* oli; /* option letter list index */
|
||||
int optchar, short_too;
|
||||
static int posixly_correct = -1;
|
||||
|
||||
if (options == NULL)
|
||||
return (-1);
|
||||
|
||||
/*
|
||||
* XXX Some GNU programs (like cvs) set optind to 0 instead of
|
||||
* XXX using optreset. Work around this braindamage.
|
||||
*/
|
||||
if (optind == 0)
|
||||
optind = optreset = 1;
|
||||
|
||||
/*
|
||||
* Disable GNU extensions if POSIXLY_CORRECT is set or options
|
||||
* string begins with a '+'.
|
||||
*
|
||||
* CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or
|
||||
* optreset != 0 for GNU compatibility.
|
||||
*/
|
||||
if (posixly_correct == -1 || optreset != 0)
|
||||
posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
|
||||
if (*options == '-')
|
||||
flags |= FLAG_ALLARGS;
|
||||
else if (posixly_correct || *options == '+')
|
||||
flags &= ~FLAG_PERMUTE;
|
||||
if (*options == '+' || *options == '-')
|
||||
options++;
|
||||
|
||||
optarg = NULL;
|
||||
if (optreset)
|
||||
nonopt_start = nonopt_end = -1;
|
||||
start:
|
||||
if (optreset || !*place) { /* update scanning pointer */
|
||||
optreset = 0;
|
||||
if (optind >= nargc) { /* end of argument vector */
|
||||
place = EMSG;
|
||||
if (nonopt_end != -1) {
|
||||
/* do permutation, if we have to */
|
||||
permute_args(nonopt_start, nonopt_end,
|
||||
optind, nargv);
|
||||
optind -= nonopt_end - nonopt_start;
|
||||
}
|
||||
else if (nonopt_start != -1) {
|
||||
/*
|
||||
* If we skipped non-options, set optind
|
||||
* to the first of them.
|
||||
*/
|
||||
optind = nonopt_start;
|
||||
}
|
||||
nonopt_start = nonopt_end = -1;
|
||||
return (-1);
|
||||
}
|
||||
if (*(place = nargv[optind]) != '-' ||
|
||||
(place[1] == '\0' && strchr(options, '-') == NULL)) {
|
||||
place = EMSG; /* found non-option */
|
||||
if (flags & FLAG_ALLARGS) {
|
||||
/*
|
||||
* GNU extension:
|
||||
* return non-option as argument to option 1
|
||||
*/
|
||||
optarg = nargv[optind++];
|
||||
return (INORDER);
|
||||
}
|
||||
if (!(flags & FLAG_PERMUTE)) {
|
||||
/*
|
||||
* If no permutation wanted, stop parsing
|
||||
* at first non-option.
|
||||
*/
|
||||
return (-1);
|
||||
}
|
||||
/* do permutation */
|
||||
if (nonopt_start == -1)
|
||||
nonopt_start = optind;
|
||||
else if (nonopt_end != -1) {
|
||||
permute_args(nonopt_start, nonopt_end,
|
||||
optind, nargv);
|
||||
nonopt_start = optind -
|
||||
(nonopt_end - nonopt_start);
|
||||
nonopt_end = -1;
|
||||
}
|
||||
optind++;
|
||||
/* process next argument */
|
||||
goto start;
|
||||
}
|
||||
if (nonopt_start != -1 && nonopt_end == -1)
|
||||
nonopt_end = optind;
|
||||
|
||||
/*
|
||||
* If we have "-" do nothing, if "--" we are done.
|
||||
*/
|
||||
if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
|
||||
optind++;
|
||||
place = EMSG;
|
||||
/*
|
||||
* We found an option (--), so if we skipped
|
||||
* non-options, we have to permute.
|
||||
*/
|
||||
if (nonopt_end != -1) {
|
||||
permute_args(nonopt_start, nonopt_end,
|
||||
optind, nargv);
|
||||
optind -= nonopt_end - nonopt_start;
|
||||
}
|
||||
nonopt_start = nonopt_end = -1;
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check long options if:
|
||||
* 1) we were passed some
|
||||
* 2) the arg is not just "-"
|
||||
* 3) either the arg starts with -- we are getopt_long_only()
|
||||
*/
|
||||
if (long_options != NULL && place != nargv[optind] &&
|
||||
(*place == '-' || (flags & FLAG_LONGONLY))) {
|
||||
short_too = 0;
|
||||
if (*place == '-')
|
||||
place++; /* --foo long option */
|
||||
else if (*place != ':' && strchr(options, *place) != NULL)
|
||||
short_too = 1; /* could be short option too */
|
||||
|
||||
optchar = parse_long_options(nargv, options, long_options,
|
||||
idx, short_too);
|
||||
if (optchar != -1) {
|
||||
place = EMSG;
|
||||
return (optchar);
|
||||
}
|
||||
}
|
||||
|
||||
if ((optchar = (int)*place++) == (int)':' ||
|
||||
(optchar == (int)'-' && *place != '\0') ||
|
||||
(oli = (char*)strchr(options, optchar)) == NULL) {
|
||||
/*
|
||||
* If the user specified "-" and '-' isn't listed in
|
||||
* options, return -1 (non-option) as per POSIX.
|
||||
* Otherwise, it is an unknown option character (or ':').
|
||||
*/
|
||||
if (optchar == (int)'-' && *place == '\0')
|
||||
return (-1);
|
||||
if (!*place)
|
||||
++optind;
|
||||
if (PRINT_ERROR)
|
||||
warnx(illoptchar, optchar);
|
||||
optopt = optchar;
|
||||
return (BADCH);
|
||||
}
|
||||
if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
|
||||
/* -W long-option */
|
||||
if (*place) /* no space */
|
||||
/* NOTHING */;
|
||||
else if (++optind >= nargc) { /* no arg */
|
||||
place = EMSG;
|
||||
if (PRINT_ERROR)
|
||||
warnx(recargchar, optchar);
|
||||
optopt = optchar;
|
||||
return (BADARG);
|
||||
}
|
||||
else /* white space */
|
||||
place = nargv[optind];
|
||||
optchar = parse_long_options(nargv, options, long_options,
|
||||
idx, 0);
|
||||
place = EMSG;
|
||||
return (optchar);
|
||||
}
|
||||
if (*++oli != ':') { /* doesn't take argument */
|
||||
if (!*place)
|
||||
++optind;
|
||||
}
|
||||
else { /* takes (optional) argument */
|
||||
optarg = NULL;
|
||||
if (*place) /* no white space */
|
||||
optarg = place;
|
||||
else if (oli[1] != ':') { /* arg not optional */
|
||||
if (++optind >= nargc) { /* no arg */
|
||||
place = EMSG;
|
||||
if (PRINT_ERROR)
|
||||
warnx(recargchar, optchar);
|
||||
optopt = optchar;
|
||||
return (BADARG);
|
||||
}
|
||||
else
|
||||
optarg = nargv[optind];
|
||||
}
|
||||
place = EMSG;
|
||||
++optind;
|
||||
}
|
||||
/* dump back option letter */
|
||||
return (optchar);
|
||||
}
|
||||
|
||||
/*
|
||||
* getopt_long --
|
||||
* Parse argc/argv argument vector.
|
||||
*/
|
||||
int
|
||||
getopt_long(int nargc, char* const* nargv, const char* options,
|
||||
const struct option* long_options, int* idx)
|
||||
{
|
||||
|
||||
return (getopt_internal(nargc, nargv, options, long_options, idx,
|
||||
FLAG_PERMUTE));
|
||||
}
|
||||
|
||||
/*
|
||||
* getopt_long_only --
|
||||
* Parse argc/argv argument vector.
|
||||
*/
|
||||
int
|
||||
getopt_long_only(int nargc, char* const* nargv, const char* options,
|
||||
const struct option* long_options, int* idx)
|
||||
{
|
||||
|
||||
return (getopt_internal(nargc, nargv, options, long_options, idx,
|
||||
FLAG_PERMUTE | FLAG_LONGONLY));
|
||||
}
|
||||
|
||||
//extern int getopt_long(int nargc, char * const *nargv, const char *options,
|
||||
// const struct option *long_options, int *idx);
|
||||
//extern int getopt_long_only(int nargc, char * const *nargv, const char *options,
|
||||
// const struct option *long_options, int *idx);
|
||||
/*
|
||||
* Previous MinGW implementation had...
|
||||
*/
|
||||
#ifndef HAVE_DECL_GETOPT
|
||||
/*
|
||||
* ...for the long form API only; keep this for compatibility.
|
||||
*/
|
||||
# define HAVE_DECL_GETOPT 1
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */
|
||||
Submodule
+1
Submodule spdlog added at ad0e89cbfb
@@ -0,0 +1,244 @@
|
||||
#include "pch.h"
|
||||
#include "account_mgr.h"
|
||||
#include "wechat_function.h"
|
||||
|
||||
using namespace std;
|
||||
namespace wxhelper {
|
||||
AccountMgr::AccountMgr(DWORD base) : BaseMgr(base) {}
|
||||
AccountMgr::~AccountMgr() {}
|
||||
int AccountMgr::GetSelfInfo(SelfInfoInner &out) {
|
||||
DWORD accout_service_addr = base_addr_ + WX_ACCOUNT_SERVICE_OFFSET;
|
||||
DWORD get_app_save_addr = base_addr_ + WX_GET_APP_DATA_SAVE_PATH_OFFSET;
|
||||
DWORD get_current_data_path_addr =
|
||||
base_addr_ + WX_GET_CURRENT_DATA_PATH_OFFSET;
|
||||
DWORD service_addr = NULL;
|
||||
__asm {
|
||||
PUSHAD
|
||||
CALL accout_service_addr
|
||||
MOV service_addr,EAX
|
||||
POPAD
|
||||
}
|
||||
if (service_addr) {
|
||||
if (*(DWORD *)(service_addr + 0x44) == 0 ||
|
||||
*(DWORD *)(service_addr + 0x44 + 0x10) == 0) {
|
||||
out.wxid = string();
|
||||
} else {
|
||||
if (*(DWORD *)(service_addr + 0x44 + 0x14) == 0xF) {
|
||||
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 ||
|
||||
*(DWORD *)(service_addr + 0xA8 + 0x10) == 0) {
|
||||
out.account = string();
|
||||
} else {
|
||||
if (*(DWORD *)(service_addr + 0xA8 + 0x14) == 0xF) {
|
||||
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 ||
|
||||
*(DWORD *)(service_addr + 0xC0 + 0x10) == 0) {
|
||||
out.mobile = string();
|
||||
} else {
|
||||
if (*(DWORD *)(service_addr + 0xC0 + 0x14) == 0xF) {
|
||||
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 ||
|
||||
*(DWORD *)(service_addr + 0xD8 + 0x10) == 0) {
|
||||
out.signature = string();
|
||||
} else {
|
||||
if (*(DWORD *)(service_addr + 0xD8 + 0x14) == 0xF) {
|
||||
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 ||
|
||||
*(DWORD *)(service_addr + 0xF0 + 0x10) == 0) {
|
||||
out.country = string();
|
||||
} else {
|
||||
if (*(DWORD *)(service_addr + 0xF0 + 0x14) == 0xF) {
|
||||
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 ||
|
||||
*(DWORD *)(service_addr + 0x108 + 0x10) == 0) {
|
||||
out.province = string();
|
||||
} else {
|
||||
if (*(DWORD *)(service_addr + 0x108 + 0x14) == 0xF) {
|
||||
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 ||
|
||||
*(DWORD *)(service_addr + 0x120 + 0x10) == 0) {
|
||||
out.city = string();
|
||||
} else {
|
||||
if (*(DWORD *)(service_addr + 0x120 + 0x14) == 0xF) {
|
||||
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 ||
|
||||
*(DWORD *)(service_addr + 0x150 + 0x10) == 0) {
|
||||
out.name = string();
|
||||
} else {
|
||||
if (*(DWORD *)(service_addr + 0x150 + 0x14) == 0xF) {
|
||||
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 + 0x31C) == 0 ||
|
||||
*(DWORD *)(service_addr + 0x31C + 0x10) == 0) {
|
||||
out.head_img = string();
|
||||
} else {
|
||||
if (*(DWORD *)(service_addr + 0x31C + 0x14) == 0xF) {
|
||||
out.head_img = string((char *)(service_addr + 0x31C),
|
||||
*(DWORD *)(service_addr + 0x31C + 0x10));
|
||||
} else {
|
||||
out.head_img = string(*(char **)(service_addr + 0x31C),
|
||||
*(DWORD *)(service_addr + 0x31C + 0x10));
|
||||
}
|
||||
}
|
||||
|
||||
if (*(DWORD *)(service_addr + 0x4CC) == 0 ||
|
||||
*(DWORD *)(service_addr + 0x4D0) == 0) {
|
||||
out.db_key = string();
|
||||
} else {
|
||||
DWORD byte_addr = *(DWORD *)(service_addr + 0x4CC);
|
||||
DWORD len = *(DWORD *)(service_addr + 0x4D0);
|
||||
out.db_key = Utils::Bytes2Hex((BYTE *)byte_addr, len);
|
||||
}
|
||||
}
|
||||
|
||||
WeChatString data_save_path;
|
||||
WeChatString current_data_path;
|
||||
|
||||
__asm {
|
||||
PUSHAD
|
||||
LEA ECX,data_save_path
|
||||
CALL get_app_save_addr
|
||||
LEA ECX,current_data_path
|
||||
CALL get_current_data_path_addr
|
||||
POPAD
|
||||
}
|
||||
|
||||
if (data_save_path.ptr) {
|
||||
out.data_save_path = Utils::WstringToUTF8(
|
||||
wstring(data_save_path.ptr, data_save_path.length));
|
||||
}
|
||||
else {
|
||||
out.data_save_path = string();
|
||||
}
|
||||
|
||||
if (current_data_path.ptr) {
|
||||
out.current_data_path = Utils::WstringToUTF8(
|
||||
wstring(current_data_path.ptr, current_data_path.length));
|
||||
} else {
|
||||
out.current_data_path = string();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int AccountMgr::CheckLogin() {
|
||||
int success = -1;
|
||||
DWORD accout_service_addr = base_addr_ + WX_ACCOUNT_SERVICE_OFFSET;
|
||||
DWORD service_addr = NULL;
|
||||
__asm {
|
||||
PUSHAD
|
||||
CALL accout_service_addr
|
||||
MOV service_addr,EAX
|
||||
POPAD
|
||||
}
|
||||
if (service_addr) {
|
||||
success = *(DWORD *)(service_addr + 0x4C8);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
int AccountMgr::Logout() {
|
||||
int success = -1;
|
||||
if (!CheckLogin()) {
|
||||
return success;
|
||||
}
|
||||
DWORD account_service_addr = base_addr_ + WX_ACCOUNT_SERVICE_OFFSET;
|
||||
DWORD logout_addr = base_addr_ + WX_LOGOUT_OFFSET;
|
||||
__asm {
|
||||
PUSHAD
|
||||
CALL account_service_addr
|
||||
PUSH 0x0
|
||||
MOV ECX,EAX
|
||||
CALL logout_addr
|
||||
MOV success,EAX
|
||||
POPAD
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/// @brief 根据 502647092 提供的偏移 获取二维码url
|
||||
/// @return
|
||||
std::string AccountMgr::GetQRCodeUrl() {
|
||||
DWORD qr_code_login_addr = base_addr_ + WX_QR_CODE_LOGIN_MGR_OFFSET ;
|
||||
DWORD get_qr_code_img_addr = base_addr_ + WX_GET_QR_CODE_IMAGE_OFFSET ;
|
||||
|
||||
DWORD temp;
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
CALL qr_code_login_addr
|
||||
MOV temp,EAX
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
std::string pre("https://weixin.qq.com/x/");
|
||||
DWORD ptr = temp + 0x8;
|
||||
DWORD len = *(DWORD*)(ptr+0x10);
|
||||
if (*(DWORD *)(ptr) == 0) {
|
||||
return std::string();
|
||||
} else {
|
||||
if( *(DWORD*) (temp+0x1c) > 0xf){
|
||||
std::string suff(*(char **)ptr,len);
|
||||
return pre + suff;
|
||||
}else{
|
||||
std::string suff((char *)ptr,len);
|
||||
return pre + suff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace wxhelper
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef WXHELPER_ACCOUNT_MGR_H_
|
||||
#define WXHELPER_ACCOUNT_MGR_H_
|
||||
#include "wechat_function.h"
|
||||
#include"base_mgr.h"
|
||||
namespace wxhelper{
|
||||
class AccountMgr: public BaseMgr
|
||||
{
|
||||
public:
|
||||
explicit AccountMgr(DWORD base);
|
||||
~AccountMgr();
|
||||
int GetSelfInfo(SelfInfoInner& out);
|
||||
|
||||
int CheckLogin();
|
||||
|
||||
int Logout();
|
||||
|
||||
std::string GetQRCodeUrl();
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
-685
@@ -1,685 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "api.h"
|
||||
#include <mongoose.h>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
|
||||
#include "send_text.h"
|
||||
#include "common.h"
|
||||
#include "send_image.h"
|
||||
#include "send_file.h"
|
||||
#include "hook_recv_msg.h"
|
||||
#include "get_db_handle.h"
|
||||
#include "wechat_data.h"
|
||||
#include "forward.h"
|
||||
#include "db_operation.h"
|
||||
#include "contact.h"
|
||||
#include "chat_room.h"
|
||||
#include "self_info.h"
|
||||
#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;
|
||||
using namespace nlohmann;
|
||||
|
||||
#define STR2INT(str) (is_digit(str) ? stoi(str) : 0)
|
||||
#define WS2LW(wstr) (LPWSTR) wstr.c_str()
|
||||
|
||||
static bool kHttpRuning = false;
|
||||
static HANDLE kHttpThread = NULL;
|
||||
|
||||
bool is_digit(string str) {
|
||||
if (str.length() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto it : str) {
|
||||
if (it < '0' || it > '9') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
string get_var(mg_http_message *hm, string name) {
|
||||
string ret;
|
||||
char *buffer = new char[hm->query.len + 1];
|
||||
ZeroMemory(buffer, hm->query.len + 1);
|
||||
int len = mg_http_get_var(&hm->query, name.c_str(), buffer, hm->query.len);
|
||||
if (len > 0) ret = string(buffer, len);
|
||||
delete[] buffer;
|
||||
buffer = NULL;
|
||||
return ret;
|
||||
}
|
||||
/// @brief 获取request中的请求参数int类型
|
||||
/// @param hm 消息
|
||||
/// @param data json数据
|
||||
/// @param key key
|
||||
/// @param method 是否是post,暂时全部用post
|
||||
/// @return int
|
||||
static int get_http_req_param_int(mg_http_message *hm, json data, string key, int method){
|
||||
int result;
|
||||
switch (method) {
|
||||
case 0: {
|
||||
result = STR2INT(get_var(hm,key).c_str());
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
try {
|
||||
result = data[key].get<int>();
|
||||
} catch (json::exception) {
|
||||
result = STR2INT(data[key].get<string>());
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @brief 获取request中的请求参数
|
||||
/// @param hm 消息
|
||||
/// @param data json数据
|
||||
/// @param key key
|
||||
/// @param method 是否是post,暂时全部用post
|
||||
/// @return
|
||||
static wstring get_http_req_param(mg_http_message *hm, json data, string key, int method){
|
||||
wstring result;
|
||||
switch (method) {
|
||||
case 0: {
|
||||
result = utf8_to_unicode(get_var(hm,key).c_str());
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
result = utf8_to_unicode(data[key].get<string>().c_str());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static unsigned long long get_http_param_ulong64(mg_http_message *hm,
|
||||
json j_data, string key,
|
||||
int method) {
|
||||
unsigned long long result = 0;
|
||||
switch (method) {
|
||||
case 0: {
|
||||
string value = get_var(hm, key);
|
||||
istringstream is(value);
|
||||
is >> result;
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
try {
|
||||
result = j_data[key].get<ULONG64>();
|
||||
} catch (json::exception) {
|
||||
string value = j_data[key].get<string>();
|
||||
istringstream is(value);
|
||||
is >> result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int get_http_param_int(mg_http_message *hm, json j_data, string key,
|
||||
int method) {
|
||||
int result = 0;
|
||||
switch (method) {
|
||||
case 0: {
|
||||
result = STR2INT(get_var(hm, key));
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
try {
|
||||
result = j_data[key].get<int>();
|
||||
} catch (json::exception) {
|
||||
result = STR2INT(j_data[key].get<string>());
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static vector<wstring> get_http_param_array(mg_http_message *hm, json j_data,
|
||||
string key, int method) {
|
||||
vector<wstring> result;
|
||||
switch (method) {
|
||||
case 0: {
|
||||
result = split(utf8_to_unicode(get_var(hm, key).c_str()), L',');
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
result = split(utf8_to_unicode(j_data[key].get<string>().c_str()), L',');
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @brief api接口入口解析
|
||||
/// @param hm mg_http_message
|
||||
/// @param c connection
|
||||
/// @param ret json数据
|
||||
void api_handle(mg_http_message *hm, struct mg_connection *c, string &ret) {
|
||||
int is_post = 0;
|
||||
|
||||
if (mg_vcasecmp(&hm->method, "POST") == 0) {
|
||||
is_post = 1;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
printf("method:%s body: %s", hm->method.ptr,hm->body.ptr);
|
||||
#endif
|
||||
if (is_post == 0){
|
||||
json ret_data = {{"result", "ERROR"}, {"msg", "not support method"}};
|
||||
ret = ret_data.dump();
|
||||
return;
|
||||
}
|
||||
|
||||
json j_param =
|
||||
json::parse(hm->body.ptr, hm->body.ptr + hm->body.len, nullptr, false);
|
||||
if (hm->body.len != 0 && j_param.is_discarded() == true) {
|
||||
json ret_data = {{"result", "ERROR"}, {"msg", "json string is invalid."}};
|
||||
ret = ret_data.dump();
|
||||
return;
|
||||
}
|
||||
int api_number = STR2INT(get_var(hm, "type"));
|
||||
switch (api_number) {
|
||||
case WECHAT_IS_LOGIN: {
|
||||
int success = CheckLogin();
|
||||
json ret_data = {{"result", "OK"}, {"code", success}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_GET_SELF_INFO: {
|
||||
SelfInfoInner self_info;
|
||||
int success = GetSelfInfo(self_info);
|
||||
json ret_data = {{"result", "OK"}, {"code", success}};
|
||||
if (success) {
|
||||
json j_info = {
|
||||
{"name", self_info.name},
|
||||
{"city", self_info.city},
|
||||
{"province", self_info.province},
|
||||
{"country", self_info.country},
|
||||
{"account", self_info.account},
|
||||
{"wxid", self_info.wxid},
|
||||
{"mobile", self_info.mobile},
|
||||
{"smallImage", self_info.small_img},
|
||||
{"bigImage", self_info.big_img},
|
||||
{"dataRootPath",self_info.data_root_path},
|
||||
{"dataSavePath",self_info.data_save_path},
|
||||
{"currentDataPath",self_info.current_data_path},
|
||||
};
|
||||
ret_data["data"] = j_info;
|
||||
}
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_SEND_TEXT: {
|
||||
wstring wxid = get_http_req_param(hm, j_param, "wxid", is_post);
|
||||
wstring msg = get_http_req_param(hm, j_param, "msg", is_post);
|
||||
int success = SendText(WS2LW(wxid), WS2LW(msg));
|
||||
json ret_data = {{"result", "OK"}, {"code", success}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_SEND_AT: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_SEND_CARD: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_SEND_IMAGE: {
|
||||
wstring receiver = get_http_req_param(hm, j_param, "wxid", is_post);
|
||||
wstring img_path = get_http_req_param(hm, j_param, "imagePath", is_post);
|
||||
int success = SendImage(WS2LW(receiver), WS2LW(img_path));
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_SEND_FILE: {
|
||||
wstring receiver = get_http_req_param(hm, j_param, "wxid", is_post);
|
||||
wstring file_path = get_http_req_param(hm, j_param, "filePath", is_post);
|
||||
int success = SendFile(WS2LW(receiver), WS2LW(file_path));
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_SEND_ARTICLE: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_SEND_APP: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_START_HOOK: {
|
||||
int port = get_http_req_param_int(hm, j_param, "port", is_post);
|
||||
wstring ip = get_http_req_param(hm, j_param, "ip", is_post);
|
||||
string client_ip = Wstring2String(ip);
|
||||
char ip_cstr[16];
|
||||
strcpy_s(ip_cstr,client_ip.c_str());
|
||||
int success = HookRecvMsg(ip_cstr,port);
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_STOP_HOOK: {
|
||||
int success = UnHookRecvMsg();
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_START_IMAGE_HOOK: {
|
||||
wstring img_dir = get_http_req_param(hm, j_param, "imgDir", is_post);
|
||||
int success = HookImg(img_dir);
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_STOP_IMAGE_HOOK: {
|
||||
int success = UnHookImg();
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_START_VOICE_HOOK: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_STOP_VOICE_HOOK: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_CONTACT_GET_LIST: {
|
||||
|
||||
break;
|
||||
}
|
||||
case WECHAT_CONTACT_CHECK_STATUS: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_CONTACT_DEL: {
|
||||
wstring user_id = get_http_req_param(hm, j_param, "wxid", is_post);
|
||||
int success = DelContact(WS2LW(user_id));
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_CONTACT_SEARCH_BY_CACHE: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_CONTACT_SEARCH_BY_NET: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_CONTACT_ADD_BY_WXID: {
|
||||
wstring user_id = get_http_req_param(hm, j_param, "wxid", is_post);
|
||||
int success = AddFriendByWxid(WS2LW(user_id));
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_CONTACT_ADD_BY_V3: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_CONTACT_ADD_BY_PUBLIC_ID: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_CONTACT_VERIFY_APPLY: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_CONTACT_EDIT_REMARK: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_CHATROOM_GET_MEMBER_LIST: {
|
||||
wstring room_id = get_http_req_param(hm, j_param, "chatRoomId", is_post);
|
||||
ChatRoomInner out{0};
|
||||
int success = GetMemberFromChatRoom(WS2LW(room_id),out);
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
if (success){
|
||||
json member_info ={
|
||||
{"admin",unicode_to_utf8(out.admin)},
|
||||
{"chatRoomId",unicode_to_utf8(out.chat_room)},
|
||||
{"members",out.members},
|
||||
};
|
||||
ret_data["data"] = member_info;
|
||||
}
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_CHATROOM_GET_MEMBER_NICKNAME: {
|
||||
wstring room_id = get_http_req_param(hm, j_param, "chatRoomId", is_post);
|
||||
wstring member_id = get_http_req_param(hm, j_param, "memberId", is_post);
|
||||
|
||||
wstring nickname = GetChatRoomMemberNickname(WS2LW(room_id),WS2LW(member_id));
|
||||
json ret_data = {{"code", 1}, {"result", "OK"},{"nickname",unicode_to_utf8(WS2LW(nickname))}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_CHATROOM_DEL_MEMBER: {
|
||||
wstring room_id = get_http_req_param(hm, j_param, "chatRoomId", is_post);
|
||||
vector<wstring> wxids = get_http_param_array(hm, j_param, "memberIds", 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 = DelMemberFromChatRoom(WS2LW(room_id), wxid_list.data(),wxid_list.size());
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_CHATROOM_ADD_MEMBER: {
|
||||
wstring room_id = get_http_req_param(hm, j_param, "chatRoomId", is_post);
|
||||
vector<wstring> wxids = get_http_param_array(hm, j_param, "memberIds", 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 = AddMemberToChatRoom(WS2LW(room_id), wxid_list.data(),wxid_list.size());
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_CHATROOM_SET_ANNOUNCEMENT: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_CHATROOM_SET_CHATROOM_NAME: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_CHATROOM_SET_SELF_NICKNAME: {
|
||||
wstring room_id = get_http_req_param(hm, j_param, "chatRoomId", is_post);
|
||||
wstring wxid = get_http_req_param(hm, j_param, "wxid", is_post);
|
||||
wstring nick = get_http_req_param(hm, j_param, "nickName", is_post);
|
||||
int success = ModChatRoomMemberNickName(WS2LW(room_id),WS2LW(wxid),WS2LW(nick));
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_DATABASE_GET_HANDLES: {
|
||||
vector<void *> v_ptr = GetDbHandles();
|
||||
json ret_data = {{"data", json::array()}, {"result", "OK"}};
|
||||
for (unsigned int i = 0; i < v_ptr.size(); i++) {
|
||||
json db_info;
|
||||
db_info["tables"] = json::array();
|
||||
DatabaseInfo *db = reinterpret_cast<DatabaseInfo *>(v_ptr[i]);
|
||||
db_info["handle"] = db->handle;
|
||||
db_info["databaseName"] = unicode_to_utf8(db->db_name);
|
||||
for (auto table : db->tables) {
|
||||
json table_info = {{"name", table.name},
|
||||
{"tableName", table.table_name},
|
||||
{"sql", table.sql},
|
||||
{"rootpage", table.rootpage}};
|
||||
db_info["tables"].push_back(table_info);
|
||||
}
|
||||
ret_data["data"].push_back(db_info);
|
||||
}
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_DATABASE_BACKUP: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_DATABASE_QUERY: {
|
||||
DWORD db_handle = get_http_param_int(hm, j_param, "dbHandle", is_post);
|
||||
wstring sql = get_http_req_param(hm, j_param, "sql", is_post);
|
||||
string sql_str = unicode_to_utf8(WS2LW(sql));
|
||||
vector<vector<string>> items;
|
||||
int success = Select(db_handle, sql_str.c_str(),items);
|
||||
json ret_data = {{"data", json::array()}, {"code",success},{"result", "OK"}};
|
||||
if(success == 0){
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
for (auto it : items) {
|
||||
json temp_arr = json::array();
|
||||
for (size_t i = 0; i < it.size(); i++) {
|
||||
temp_arr.push_back(it[i]);
|
||||
}
|
||||
ret_data["data"].push_back(temp_arr);
|
||||
}
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_SET_VERSION: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_LOG_START_HOOK: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_LOG_STOP_HOOK: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_BROWSER_OPEN_WITH_URL: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_GET_PUBLIC_MSG: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_FORWARD_MESSAGE: {
|
||||
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 = ForwardMsg(WS2LW(wxid), msgid);
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_GET_QRCODE_IMAGE: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_GET_A8KEY: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_SEND_XML: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_LOGOUT: {
|
||||
int success = Logout();
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
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: {
|
||||
vector<Contact> vec;
|
||||
int success = GetAllContact(vec);
|
||||
json ret_data = {
|
||||
{"data", json::array()}, {"code", success}, {"result", "OK"}};
|
||||
|
||||
for (unsigned int i = 0; i < vec.size(); i++) {
|
||||
#ifdef _DEBUG
|
||||
cout << "vector :" <<i << endl;
|
||||
cout<< "custom :" << vec[i].custom_account.ptr << endl;
|
||||
cout<< "userName :" << vec[i].encrypt_name.ptr << endl;
|
||||
cout<< "wxid :" << vec[i].wxid.ptr << endl;
|
||||
#endif
|
||||
json item = {
|
||||
{"customAccount",
|
||||
vec[i].custom_account.length > 0
|
||||
? vec[i].custom_account.ptr != nullptr
|
||||
? unicode_to_utf8(vec[i].custom_account.ptr)
|
||||
: string()
|
||||
: string()},
|
||||
{"delFlag", vec[i].del_flag},
|
||||
{"userName", vec[i].encrypt_name.length > 0
|
||||
? vec[i].encrypt_name.ptr != nullptr
|
||||
? unicode_to_utf8(vec[i].encrypt_name.ptr)
|
||||
: string()
|
||||
: string()},
|
||||
{"type", vec[i].type},
|
||||
{"verifyFlag", vec[i].verify_flag},
|
||||
{"verifyFlag", vec[i].verify_flag},
|
||||
{"wxid", vec[i].wxid.length > 0 ? unicode_to_utf8(vec[i].wxid.ptr)
|
||||
: string()},
|
||||
};
|
||||
ret_data["data"].push_back(item);
|
||||
}
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_GET_CHATROOM_INFO: {
|
||||
wstring room_id = get_http_req_param(hm, j_param, "chatRoomId", is_post);
|
||||
ChatRoomInfoInner chat_room_detail{0};
|
||||
int success = GetChatRoomDetailInfo(WS2LW(room_id), chat_room_detail);
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
if(!success){
|
||||
break;
|
||||
}
|
||||
json detail = {
|
||||
{"chatRoomId",
|
||||
chat_room_detail.chat_room_id.length > 0
|
||||
? unicode_to_utf8(chat_room_detail.chat_room_id.ptr)
|
||||
: string()},
|
||||
{"notice", chat_room_detail.notice.length > 0
|
||||
? unicode_to_utf8(chat_room_detail.notice.ptr)
|
||||
: string()},
|
||||
{"admin", chat_room_detail.admin.length > 0
|
||||
? unicode_to_utf8(chat_room_detail.admin.ptr)
|
||||
: string()},
|
||||
{"xml", chat_room_detail.xml.length > 0
|
||||
? unicode_to_utf8(chat_room_detail.xml.ptr)
|
||||
: string()},
|
||||
};
|
||||
ret_data["data"]=detail;
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_GET_IMG_BY_NAME: {
|
||||
wstring image_path = get_http_req_param(hm, j_param, "imagePath", is_post);
|
||||
wstring save_path = get_http_req_param(hm, j_param, "savePath", is_post);
|
||||
int success = GetImgByName(WS2LW(image_path),WS2LW(save_path));
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_DO_OCR:{
|
||||
wstring image_path = get_http_req_param(hm, j_param, "imagePath", is_post);
|
||||
string text("");
|
||||
int success = DoOCRTask(WS2LW(image_path),text);
|
||||
json ret_data = {{"code", success}, {"result", "OK"},{"text",text}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_SEND_PAT_MSG:{
|
||||
wstring room_id = get_http_req_param(hm, j_param, "chatRoomId", is_post);
|
||||
wstring wxid = get_http_req_param(hm, j_param, "wxid", is_post);
|
||||
int success = SendPatMsg(WS2LW(room_id),WS2LW(wxid));
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
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;
|
||||
}
|
||||
case WECHAT_CONTACT_NAME:{
|
||||
wstring pri_id = get_http_req_param(hm, j_param, "id", is_post);
|
||||
wstring name =GetContactOrChatRoomNickname(WS2LW(pri_id));
|
||||
json ret_data = {{"code", 1}, {"result", "OK"},{"name",unicode_to_utf8(WS2LW(name))}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 事件回调函数
|
||||
/// @param c 链接
|
||||
/// @param ev 事件
|
||||
/// @param ev_data 事件数据
|
||||
/// @param fn_data 回调数据
|
||||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
struct mg_http_serve_opts opts = {0};
|
||||
if (ev == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_message *hm = (struct mg_http_message *)ev_data;
|
||||
string ret = R"({"result":"OK"})";
|
||||
if (mg_http_match_uri(hm, "/api/")) {
|
||||
try {
|
||||
api_handle(hm, c, ret);
|
||||
} catch (json::exception &e) {
|
||||
json res = {{"result", "ERROR"}, {"msg", e.what()}};
|
||||
ret = res.dump();
|
||||
}
|
||||
if (ret != "") {
|
||||
mg_http_reply(c, 200, "", ret.c_str(), 0, 0);
|
||||
}
|
||||
} else {
|
||||
mg_http_reply(c, 500, NULL, "%s", "Invalid URI");
|
||||
}
|
||||
}
|
||||
(void)fn_data;
|
||||
}
|
||||
/// @brief http server
|
||||
/// @param port 端口
|
||||
void http_server(int port) {
|
||||
string lsten_addr = "http://0.0.0.0:" + to_string(port);
|
||||
struct mg_mgr mgr;
|
||||
// Init manager
|
||||
mg_mgr_init(&mgr);
|
||||
// Setup listener
|
||||
mg_http_listen(&mgr, lsten_addr.c_str(), fn, &mgr);
|
||||
// Event loop
|
||||
for (;;) mg_mgr_poll(&mgr, 1000);
|
||||
// Cleanup
|
||||
mg_mgr_free(&mgr);
|
||||
}
|
||||
|
||||
/// @brief 启动http服务
|
||||
/// @param port 端口
|
||||
/// @return 成功返回0
|
||||
int http_start(int port) {
|
||||
if (kHttpRuning) {
|
||||
return 1;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
CreateConsole();
|
||||
#endif
|
||||
kHttpRuning = true;
|
||||
kHttpThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)http_server,
|
||||
(LPVOID)port, NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
#ifndef API_H_
|
||||
#define API_H_
|
||||
|
||||
|
||||
typedef enum WECHAT_HTTP_APISTag
|
||||
{
|
||||
// login check
|
||||
WECHAT_IS_LOGIN = 0,
|
||||
// self info
|
||||
WECHAT_GET_SELF_INFO,
|
||||
// send message
|
||||
WECHAT_MSG_SEND_TEXT,
|
||||
WECHAT_MSG_SEND_AT,
|
||||
WECHAT_MSG_SEND_CARD,
|
||||
WECHAT_MSG_SEND_IMAGE,
|
||||
WECHAT_MSG_SEND_FILE,
|
||||
WECHAT_MSG_SEND_ARTICLE,
|
||||
WECHAT_MSG_SEND_APP,
|
||||
// receive message
|
||||
WECHAT_MSG_START_HOOK,
|
||||
WECHAT_MSG_STOP_HOOK,
|
||||
WECHAT_MSG_START_IMAGE_HOOK,
|
||||
WECHAT_MSG_STOP_IMAGE_HOOK,
|
||||
WECHAT_MSG_START_VOICE_HOOK,
|
||||
WECHAT_MSG_STOP_VOICE_HOOK,
|
||||
// contact
|
||||
WECHAT_CONTACT_GET_LIST,
|
||||
WECHAT_CONTACT_CHECK_STATUS,
|
||||
WECHAT_CONTACT_DEL,
|
||||
WECHAT_CONTACT_SEARCH_BY_CACHE,
|
||||
WECHAT_CONTACT_SEARCH_BY_NET,
|
||||
WECHAT_CONTACT_ADD_BY_WXID,
|
||||
WECHAT_CONTACT_ADD_BY_V3,
|
||||
WECHAT_CONTACT_ADD_BY_PUBLIC_ID,
|
||||
WECHAT_CONTACT_VERIFY_APPLY,
|
||||
WECHAT_CONTACT_EDIT_REMARK,
|
||||
// chatroom
|
||||
WECHAT_CHATROOM_GET_MEMBER_LIST,
|
||||
WECHAT_CHATROOM_GET_MEMBER_NICKNAME,
|
||||
WECHAT_CHATROOM_DEL_MEMBER,
|
||||
WECHAT_CHATROOM_ADD_MEMBER,
|
||||
WECHAT_CHATROOM_SET_ANNOUNCEMENT,
|
||||
WECHAT_CHATROOM_SET_CHATROOM_NAME,
|
||||
WECHAT_CHATROOM_SET_SELF_NICKNAME,
|
||||
// database
|
||||
WECHAT_DATABASE_GET_HANDLES,
|
||||
WECHAT_DATABASE_BACKUP,
|
||||
WECHAT_DATABASE_QUERY,
|
||||
// version
|
||||
WECHAT_SET_VERSION,
|
||||
// log
|
||||
WECHAT_LOG_START_HOOK,
|
||||
WECHAT_LOG_STOP_HOOK,
|
||||
// browser
|
||||
WECHAT_BROWSER_OPEN_WITH_URL,
|
||||
WECHAT_GET_PUBLIC_MSG,
|
||||
WECHAT_MSG_FORWARD_MESSAGE,
|
||||
WECHAT_GET_QRCODE_IMAGE,
|
||||
WECHAT_GET_A8KEY,
|
||||
WECHAT_MSG_SEND_XML,
|
||||
WECHAT_LOGOUT,
|
||||
WECHAT_GET_TRANSFER,
|
||||
WECHAT_GET_CONTACT_ALL,
|
||||
WECHAT_GET_CHATROOM_INFO,
|
||||
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_CONTACT_NAME,
|
||||
} WECHAT_HTTP_APIS,
|
||||
*PWECHAT_HTTP_APIS;
|
||||
|
||||
|
||||
int http_start(int port);
|
||||
#endif
|
||||
@@ -0,0 +1,80 @@
|
||||
#ifndef WXHELPER_API_ROUTINES_H_
|
||||
#define WXHELPER_API_ROUTINES_H_
|
||||
namespace wxhelper {
|
||||
|
||||
typedef enum HTTP_API_ROUTE {
|
||||
// login check
|
||||
WECHAT_IS_LOGIN = 0,
|
||||
// self info
|
||||
WECHAT_GET_SELF_INFO,
|
||||
// send message
|
||||
WECHAT_MSG_SEND_TEXT,
|
||||
WECHAT_MSG_SEND_AT,
|
||||
WECHAT_MSG_SEND_CARD,
|
||||
WECHAT_MSG_SEND_IMAGE,
|
||||
WECHAT_MSG_SEND_FILE,
|
||||
WECHAT_MSG_SEND_ARTICLE,
|
||||
WECHAT_MSG_SEND_APP,
|
||||
// receive message
|
||||
WECHAT_MSG_START_HOOK,
|
||||
WECHAT_MSG_STOP_HOOK,
|
||||
WECHAT_MSG_START_IMAGE_HOOK,
|
||||
WECHAT_MSG_STOP_IMAGE_HOOK,
|
||||
WECHAT_MSG_START_VOICE_HOOK,
|
||||
WECHAT_MSG_STOP_VOICE_HOOK,
|
||||
// contact
|
||||
WECHAT_CONTACT_GET_LIST,
|
||||
WECHAT_CONTACT_CHECK_STATUS,
|
||||
WECHAT_CONTACT_DEL,
|
||||
WECHAT_CONTACT_SEARCH_BY_CACHE,
|
||||
WECHAT_CONTACT_SEARCH_BY_NET,
|
||||
WECHAT_CONTACT_ADD_BY_WXID,
|
||||
WECHAT_CONTACT_ADD_BY_V3,
|
||||
WECHAT_CONTACT_ADD_BY_PUBLIC_ID,
|
||||
WECHAT_CONTACT_VERIFY_APPLY,
|
||||
WECHAT_CONTACT_EDIT_REMARK,
|
||||
// chatroom
|
||||
WECHAT_CHATROOM_GET_MEMBER_LIST,
|
||||
WECHAT_CHATROOM_GET_MEMBER_NICKNAME,
|
||||
WECHAT_CHATROOM_DEL_MEMBER,
|
||||
WECHAT_CHATROOM_ADD_MEMBER,
|
||||
WECHAT_CHATROOM_SET_ANNOUNCEMENT,
|
||||
WECHAT_CHATROOM_SET_CHATROOM_NAME,
|
||||
WECHAT_CHATROOM_SET_SELF_NICKNAME,
|
||||
// database
|
||||
WECHAT_DATABASE_GET_HANDLES,
|
||||
WECHAT_DATABASE_BACKUP,
|
||||
WECHAT_DATABASE_QUERY,
|
||||
// version
|
||||
WECHAT_SET_VERSION,
|
||||
// log
|
||||
WECHAT_LOG_START_HOOK,
|
||||
WECHAT_LOG_STOP_HOOK,
|
||||
// browser
|
||||
WECHAT_BROWSER_OPEN_WITH_URL,
|
||||
WECHAT_GET_PUBLIC_MSG,
|
||||
WECHAT_MSG_FORWARD_MESSAGE,
|
||||
WECHAT_GET_QRCODE_IMAGE,
|
||||
WECHAT_GET_A8KEY,
|
||||
WECHAT_MSG_SEND_XML,
|
||||
WECHAT_LOGOUT,
|
||||
WECHAT_GET_TRANSFER,
|
||||
WECHAT_GET_CONTACT_ALL,
|
||||
WECHAT_GET_CHATROOM_INFO,
|
||||
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_CONTACT_NAME,
|
||||
WECHAT_ATTACH_DOWNLOAD,
|
||||
WECHAT_GET_VOICE,
|
||||
WECHAT_GET_QRCODE,
|
||||
WECHAT_INVITE_MEMBERS,
|
||||
} WECHAT_HTTP_APIS,
|
||||
*PWECHAT_HTTP_APIS;
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "base_mgr.h"
|
||||
|
||||
namespace wxhelper{
|
||||
|
||||
BaseMgr::BaseMgr(DWORD base):base_addr_(base)
|
||||
{
|
||||
}
|
||||
|
||||
BaseMgr::~BaseMgr()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef WXHELPER_BASE_MGR_H_
|
||||
#define WXHELPER_BASE_MGR_H_
|
||||
#include <Windows.h>
|
||||
namespace wxhelper{
|
||||
class BaseMgr{
|
||||
public:
|
||||
explicit BaseMgr(DWORD base);
|
||||
~BaseMgr();
|
||||
protected:
|
||||
DWORD base_addr_;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
@@ -1,418 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "chat_room.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "get_db_handle.h"
|
||||
#include "wechat_data.h"
|
||||
#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
|
||||
#define WX_FREE_CHAT_MSG_INSTANCE_COUNTER_OFFSET 0x6f5370
|
||||
#define WX_GET_MEMBER_NICKNAME_OFFSET 0xb703f0
|
||||
#define WX_CONTACT_MGR_INSTANCE_OFFSET 0x6f8990
|
||||
#define WX_GET_CONTACT_OFFSET 0xb93b20
|
||||
#define WX_FREE_CONTACT_OFFSET 0xe23690
|
||||
|
||||
int GetChatRoomDetailInfo(wchar_t* chat_room_id, ChatRoomInfoInner& room_info) {
|
||||
int success = 0;
|
||||
WeChatString chat_room(chat_room_id);
|
||||
DWORD base = GetWeChatWinBase();
|
||||
DWORD get_chat_room_mgr_addr = base + WX_CHAT_ROOM_MGR_OFFSET;
|
||||
DWORD get_chat_room_detail_addr = base + WX_GET_CHAT_ROOM_DETAIL_INFO_OFFSET;
|
||||
DWORD create_chat_room_info_addr = base + WX_NEW_CHAT_ROOM_INFO_OFFSET;
|
||||
DWORD free_chat_room_info_addr = base + WX_FREE_CHAT_ROOM_INFO_OFFSET;
|
||||
char chat_room_info[0xDC] = {0};
|
||||
__asm {
|
||||
PUSHAD
|
||||
LEA ECX,chat_room_info
|
||||
CALL create_chat_room_info_addr
|
||||
CALL get_chat_room_mgr_addr
|
||||
PUSH 0x0
|
||||
LEA ECX,chat_room_info
|
||||
PUSH ECX
|
||||
LEA ECX,chat_room
|
||||
PUSH ECX
|
||||
MOV ECX,EAX
|
||||
CALL get_chat_room_detail_addr
|
||||
MOV success,EAX
|
||||
POPAD
|
||||
}
|
||||
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;
|
||||
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
__asm {
|
||||
PUSHAD
|
||||
LEA ECX,chat_room_info
|
||||
CALL free_chat_room_info_addr
|
||||
POPAD
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
int DelMemberFromChatRoom(wchar_t* chat_room_id, wchar_t** wxids,int len) {
|
||||
int success = 0;
|
||||
WeChatString chat_room(chat_room_id);
|
||||
vector<WeChatString> members;
|
||||
VectorInner *list = (VectorInner *)&members;
|
||||
DWORD members_ptr = (DWORD)&list->start;
|
||||
for (int i = 0; i < len; i++) {
|
||||
WeChatString pwxid(wxids[i]);
|
||||
members.push_back(pwxid);
|
||||
}
|
||||
DWORD base = GetWeChatWinBase();
|
||||
DWORD get_chat_room_mgr_addr = base + WX_CHAT_ROOM_MGR_OFFSET;
|
||||
DWORD del_member_addr = base + WX_DEL_CHAT_ROOM_MEMBER_OFFSET;
|
||||
DWORD init_chat_msg_addr = base + WX_INIT_CHAT_MSG_OFFSET;
|
||||
__asm {
|
||||
PUSHAD
|
||||
CALL get_chat_room_mgr_addr
|
||||
SUB ESP,0x14
|
||||
MOV ESI,EAX
|
||||
MOV ECX,ESP
|
||||
LEA EDI,chat_room
|
||||
PUSH EDI
|
||||
CALL init_chat_msg_addr
|
||||
MOV ECX,ESI
|
||||
MOV EAX,dword ptr[members_ptr]
|
||||
PUSH EAX
|
||||
CALL del_member_addr
|
||||
MOV success,EAX
|
||||
POPAD
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
int AddMemberToChatRoom(wchar_t* chat_room_id, wchar_t** wxids,int len){
|
||||
int success = 0;
|
||||
WeChatString chat_room(chat_room_id);
|
||||
vector<WeChatString> members;
|
||||
VectorInner *list = (VectorInner *)&members;
|
||||
DWORD members_ptr = (DWORD)&list->start;
|
||||
for (int i = 0; i < len; i++) {
|
||||
WeChatString pwxid(wxids[i]);
|
||||
members.push_back(pwxid);
|
||||
}
|
||||
DWORD base = GetWeChatWinBase();
|
||||
DWORD get_chat_room_mgr_addr = base + WX_CHAT_ROOM_MGR_OFFSET;
|
||||
DWORD add_member_addr = base + WX_ADD_MEMBER_TO_CHAT_ROOM_OFFSET;
|
||||
DWORD init_chat_msg_addr = base + WX_INIT_CHAT_MSG_OFFSET;
|
||||
DWORD temp=0;
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
CALL get_chat_room_mgr_addr
|
||||
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,chat_room
|
||||
PUSH EAX
|
||||
CALL init_chat_msg_addr
|
||||
MOV ECX,temp
|
||||
MOV EAX,dword ptr[members_ptr]
|
||||
PUSH EAX
|
||||
CALL add_member_addr
|
||||
MOV success,EAX
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
char buffer[0x1D4] = {0};
|
||||
DWORD base = GetWeChatWinBase();
|
||||
DWORD get_member_addr = base + WX_GET_MEMBER_FROM_CHAT_ROOM_OFFSET;
|
||||
DWORD get_chat_room_mgr_addr = base + WX_CHAT_ROOM_MGR_OFFSET;
|
||||
DWORD create_chat_room_addr = base + WX_INIT_CHAT_ROOM_OFFSET;
|
||||
DWORD free_chat_room_addr = base + WX_FREE_CHAT_ROOM_OFFSET;
|
||||
__asm {
|
||||
PUSHAD
|
||||
LEA ECX,buffer
|
||||
CALL create_chat_room_addr
|
||||
CALL get_chat_room_mgr_addr
|
||||
LEA EAX, buffer
|
||||
PUSH EAX
|
||||
PUSH chat_room_ptr
|
||||
CALL get_member_addr
|
||||
MOVZX EAX,AL
|
||||
MOV success,EAX
|
||||
POPAD
|
||||
}
|
||||
char* members = *(char **)(buffer +0x1c);
|
||||
wchar_t* room = *(wchar_t **)(buffer +0x8);
|
||||
wchar_t* admin = *(wchar_t **)(buffer +0x4c);
|
||||
|
||||
out.members = new char[strlen(members) + 1];
|
||||
memcpy(out.members, members, strlen(members) + 1);
|
||||
|
||||
out.chat_room = new wchar_t[wcslen(room)+1];
|
||||
wmemcpy(out.chat_room ,room,wcslen(room)+1);
|
||||
|
||||
out.admin = new wchar_t[wcslen(admin)+1];
|
||||
wmemcpy(out.admin ,admin,wcslen(admin)+1);
|
||||
|
||||
__asm{
|
||||
LEA ECX,buffer
|
||||
CALL free_chat_room_addr
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
int ModChatRoomMemberNickName(wchar_t* chat_room_id,wchar_t* wxid,wchar_t * nick){
|
||||
int success = 0;
|
||||
WeChatString chat_room(chat_room_id);
|
||||
WeChatString self_wxid(wxid);
|
||||
WeChatString new_nick(nick);
|
||||
DWORD base = GetWeChatWinBase();
|
||||
DWORD get_chat_room_mgr_addr = base + WX_CHAT_ROOM_MGR_OFFSET;
|
||||
DWORD mod_member_nick_name_addr = base + WX_MOD_CHAT_ROOM_MEMBER_NICK_NAME_OFFSET;
|
||||
DWORD init_chat_msg_addr = base + WX_INIT_CHAT_MSG_OFFSET;
|
||||
__asm{
|
||||
PUSHAD
|
||||
CALL get_chat_room_mgr_addr
|
||||
SUB ESP,0x14
|
||||
MOV ECX,ESP
|
||||
LEA EDI,new_nick
|
||||
PUSH EDI
|
||||
CALL init_chat_msg_addr
|
||||
SUB ESP,0x14
|
||||
LEA EAX,self_wxid
|
||||
MOV ECX,ESP
|
||||
PUSH EAX
|
||||
CALL init_chat_msg_addr
|
||||
SUB ESP,0x14
|
||||
LEA EAX,chat_room
|
||||
MOV ECX,ESP
|
||||
PUSH EAX
|
||||
CALL init_chat_msg_addr
|
||||
CALL mod_member_nick_name_addr
|
||||
MOVZX EAX,AL
|
||||
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;
|
||||
DWORD free_addr = base + WX_FREE_CHAT_MSG_INSTANCE_COUNTER_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 0x0
|
||||
LEA EAX,chat_msg
|
||||
PUSH EAX
|
||||
CALL handle_top_msg_addr
|
||||
MOV success,EAX
|
||||
LEA ECX,chat_msg
|
||||
PUSH 0x0
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::wstring GetChatRoomMemberNickname(wchar_t* chat_room_id,wchar_t* wxid){
|
||||
WeChatString chat_room(chat_room_id);
|
||||
WeChatString member_id(wxid);
|
||||
WeChatString nickname(NULL);
|
||||
DWORD base = GetWeChatWinBase();
|
||||
DWORD get_chat_room_mgr_addr = base + WX_CHAT_ROOM_MGR_OFFSET;
|
||||
DWORD get_nickname_addr = base + WX_GET_MEMBER_NICKNAME_OFFSET;
|
||||
DWORD contact_mgr_addr = base + WX_CONTACT_MGR_INSTANCE_OFFSET;
|
||||
DWORD get_contact_addr = base + WX_GET_CONTACT_OFFSET;
|
||||
DWORD free_contact_addr = base + WX_FREE_CONTACT_OFFSET;
|
||||
__asm{
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
CALL get_chat_room_mgr_addr
|
||||
LEA ECX,nickname
|
||||
PUSH ECX
|
||||
LEA ECX,member_id
|
||||
PUSH ECX
|
||||
LEA ECX,chat_room
|
||||
PUSH ECX
|
||||
MOV ECX,EAX
|
||||
CALL get_nickname_addr
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
wstring name = L"";
|
||||
if (nickname.ptr) {
|
||||
name += wstring(nickname.ptr);
|
||||
}else {
|
||||
char buff[0x440] = {0};
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
CALL contact_mgr_addr
|
||||
LEA ECX,buff
|
||||
PUSH ECX
|
||||
LEA ECX,member_id
|
||||
PUSH ECX
|
||||
MOV ECX,EAX
|
||||
CALL get_contact_addr
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
name += READ_WSTRING(buff, 0x6C);
|
||||
|
||||
__asm{
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
LEA ECX,buff
|
||||
CALL free_contact_addr
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
#ifndef CHAT_ROOM_H_
|
||||
#define CHAT_ROOM_H_
|
||||
#include "wechat_data.h"
|
||||
|
||||
int GetChatRoomDetailInfo(wchar_t* chat_room_id, ChatRoomInfoInner& room_info);
|
||||
int DelMemberFromChatRoom(wchar_t* chat_room_id,wchar_t** wxids,int len);
|
||||
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);
|
||||
|
||||
std::wstring GetChatRoomMemberNickname(wchar_t* chat_room_id,wchar_t* wxid);
|
||||
#endif
|
||||
@@ -0,0 +1,438 @@
|
||||
#include "pch.h"
|
||||
#include "chat_room_mgr.h"
|
||||
|
||||
#include "db.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace wxhelper {
|
||||
|
||||
ChatRoomMgr::ChatRoomMgr(DWORD base) : BaseMgr(base) {}
|
||||
|
||||
ChatRoomMgr::~ChatRoomMgr() {}
|
||||
|
||||
int ChatRoomMgr::GetChatRoomDetailInfo(wchar_t* chat_room_id,
|
||||
ChatRoomInfoInner& room_info) {
|
||||
int success = -1;
|
||||
WeChatString chat_room(chat_room_id);
|
||||
DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
|
||||
DWORD get_chat_room_detail_addr =
|
||||
base_addr_ + WX_GET_CHAT_ROOM_DETAIL_INFO_OFFSET;
|
||||
DWORD create_chat_room_info_addr = base_addr_ + WX_NEW_CHAT_ROOM_INFO_OFFSET;
|
||||
DWORD free_chat_room_info_addr = base_addr_ + WX_FREE_CHAT_ROOM_INFO_OFFSET;
|
||||
char chat_room_info[0xDC] = {0};
|
||||
__asm {
|
||||
PUSHAD
|
||||
LEA ECX,chat_room_info
|
||||
CALL create_chat_room_info_addr
|
||||
CALL get_chat_room_mgr_addr
|
||||
PUSH 0x0
|
||||
LEA ECX,chat_room_info
|
||||
PUSH ECX
|
||||
LEA ECX,chat_room
|
||||
PUSH ECX
|
||||
MOV ECX,EAX
|
||||
CALL get_chat_room_detail_addr
|
||||
MOV success,EAX
|
||||
POPAD
|
||||
}
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
__asm {
|
||||
PUSHAD
|
||||
LEA ECX,chat_room_info
|
||||
CALL free_chat_room_info_addr
|
||||
POPAD
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
int ChatRoomMgr::DelMemberFromChatRoom(wchar_t* chat_room_id, wchar_t** wxids,
|
||||
int len) {
|
||||
int success = 0;
|
||||
WeChatString chat_room(chat_room_id);
|
||||
vector<WeChatString> members;
|
||||
VectorInner* list = (VectorInner*)&members;
|
||||
DWORD members_ptr = (DWORD)&list->start;
|
||||
for (int i = 0; i < len; i++) {
|
||||
WeChatString pwxid(wxids[i]);
|
||||
members.push_back(pwxid);
|
||||
}
|
||||
DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
|
||||
DWORD del_member_addr = base_addr_ + WX_DEL_CHAT_ROOM_MEMBER_OFFSET;
|
||||
DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET;
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
CALL get_chat_room_mgr_addr
|
||||
SUB ESP,0x14
|
||||
MOV ESI,EAX
|
||||
MOV ECX,ESP
|
||||
LEA EDI,chat_room
|
||||
PUSH EDI
|
||||
CALL init_chat_msg_addr
|
||||
MOV ECX,ESI
|
||||
MOV EAX,dword ptr[members_ptr]
|
||||
PUSH EAX
|
||||
CALL del_member_addr
|
||||
MOV success,EAX
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
int ChatRoomMgr::AddMemberToChatRoom(wchar_t* chat_room_id, wchar_t** wxids,
|
||||
int len) {
|
||||
int success = -1;
|
||||
WeChatString chat_room(chat_room_id);
|
||||
vector<WeChatString> members;
|
||||
VectorInner* list = (VectorInner*)&members;
|
||||
DWORD members_ptr = (DWORD)&list->start;
|
||||
for (int i = 0; i < len; i++) {
|
||||
WeChatString pwxid(wxids[i]);
|
||||
members.push_back(pwxid);
|
||||
}
|
||||
DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
|
||||
DWORD add_member_addr = base_addr_ + WX_ADD_MEMBER_TO_CHAT_ROOM_OFFSET;
|
||||
DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET;
|
||||
DWORD temp = 0;
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
CALL get_chat_room_mgr_addr
|
||||
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,chat_room
|
||||
PUSH EAX
|
||||
CALL init_chat_msg_addr
|
||||
MOV ECX,temp
|
||||
MOV EAX,dword ptr[members_ptr]
|
||||
PUSH EAX
|
||||
CALL add_member_addr
|
||||
MOV success,EAX
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
int ChatRoomMgr::GetMemberFromChatRoom(wchar_t* chat_room_id,
|
||||
ChatRoomInner& out) {
|
||||
int success = -1;
|
||||
WeChatString chat_room(chat_room_id);
|
||||
DWORD chat_room_ptr = (DWORD)&chat_room;
|
||||
char buffer[0x1D4] = {0};
|
||||
DWORD get_member_addr = base_addr_ + WX_GET_MEMBER_FROM_CHAT_ROOM_OFFSET;
|
||||
DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
|
||||
DWORD create_chat_room_addr = base_addr_ + WX_INIT_CHAT_ROOM_OFFSET;
|
||||
DWORD free_chat_room_addr = base_addr_ + WX_FREE_CHAT_ROOM_OFFSET;
|
||||
__asm {
|
||||
PUSHAD
|
||||
LEA ECX,buffer
|
||||
CALL create_chat_room_addr
|
||||
CALL get_chat_room_mgr_addr
|
||||
LEA EAX, buffer
|
||||
PUSH EAX
|
||||
PUSH chat_room_ptr
|
||||
CALL get_member_addr
|
||||
MOVZX EAX,AL
|
||||
MOV success,EAX
|
||||
POPAD
|
||||
}
|
||||
char* members = *(char**)(buffer + 0x1c);
|
||||
wchar_t* room = *(wchar_t**)(buffer + 0x8);
|
||||
wchar_t* admin = *(wchar_t**)(buffer + 0x4c);
|
||||
|
||||
out.members = new char[strlen(members) + 1];
|
||||
memcpy(out.members, members, strlen(members) + 1);
|
||||
|
||||
out.chat_room = new wchar_t[wcslen(room) + 1];
|
||||
wmemcpy(out.chat_room, room, wcslen(room) + 1);
|
||||
|
||||
out.admin = new wchar_t[wcslen(admin) + 1];
|
||||
wmemcpy(out.admin, admin, wcslen(admin) + 1);
|
||||
|
||||
__asm {
|
||||
LEA ECX,buffer
|
||||
CALL free_chat_room_addr
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
int ChatRoomMgr::ModChatRoomMemberNickName(wchar_t* chat_room_id, wchar_t* wxid,
|
||||
wchar_t* nick) {
|
||||
int success = -1;
|
||||
WeChatString chat_room(chat_room_id);
|
||||
WeChatString self_wxid(wxid);
|
||||
WeChatString new_nick(nick);
|
||||
DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
|
||||
DWORD mod_member_nick_name_addr =
|
||||
base_addr_ + WX_MOD_CHAT_ROOM_MEMBER_NICK_NAME_OFFSET;
|
||||
DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET;
|
||||
__asm {
|
||||
PUSHAD
|
||||
CALL get_chat_room_mgr_addr
|
||||
SUB ESP,0x14
|
||||
MOV ECX,ESP
|
||||
LEA EDI,new_nick
|
||||
PUSH EDI
|
||||
CALL init_chat_msg_addr
|
||||
SUB ESP,0x14
|
||||
LEA EAX,self_wxid
|
||||
MOV ECX,ESP
|
||||
PUSH EAX
|
||||
CALL init_chat_msg_addr
|
||||
SUB ESP,0x14
|
||||
LEA EAX,chat_room
|
||||
MOV ECX,ESP
|
||||
PUSH EAX
|
||||
CALL init_chat_msg_addr
|
||||
CALL mod_member_nick_name_addr
|
||||
MOVZX EAX,AL
|
||||
MOV success,EAX
|
||||
POPAD
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
int ChatRoomMgr::SetTopMsg(wchar_t* wxid, ULONG64 msg_id) {
|
||||
int success = -1;
|
||||
char chat_msg[0x2D8] = {0};
|
||||
DWORD new_chat_msg_addr = base_addr_ + WX_NEW_CHAT_MSG_OFFSET;
|
||||
DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
|
||||
DWORD handle_top_msg_addr = base_addr_ + WX_TOP_MSG_OFFSET;
|
||||
DWORD free_addr = base_addr_ + WX_FREE_CHAT_MSG_INSTANCE_COUNTER_OFFSET;
|
||||
DWORD get_chat_mgr_addr = base_addr_ + WX_CHAT_MGR_OFFSET;
|
||||
DWORD get_by_local_Id_addr = base_addr_ + WX_GET_MGR_BY_PREFIX_LOCAL_ID_OFFSET;
|
||||
|
||||
|
||||
int db_index = 0;
|
||||
int local_id = DB::GetInstance().GetLocalIdByMsgId(msg_id, db_index);
|
||||
if (local_id < 1) {
|
||||
return -2;
|
||||
}
|
||||
__asm{
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
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
|
||||
CALL get_chat_room_mgr_addr
|
||||
PUSH 0x0
|
||||
LEA EAX,chat_msg
|
||||
PUSH EAX
|
||||
CALL handle_top_msg_addr
|
||||
MOV success,EAX
|
||||
LEA ECX,chat_msg
|
||||
PUSH 0x0
|
||||
CALL free_addr
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
int ChatRoomMgr::RemoveTopMsg(wchar_t* chat_room_id, ULONG64 msg_id) {
|
||||
int success = -1;
|
||||
WeChatString chat_room(chat_room_id);
|
||||
DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
|
||||
DWORD new_chat_msg_addr = base_addr_ + WX_NEW_CHAT_MSG_OFFSET;
|
||||
DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET;
|
||||
DWORD remove_top_msg_addr = base_addr_ + 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;
|
||||
}
|
||||
|
||||
std::wstring ChatRoomMgr::GetChatRoomMemberNickname(wchar_t* chat_room_id,
|
||||
wchar_t* wxid) {
|
||||
WeChatString chat_room(chat_room_id);
|
||||
WeChatString member_id(wxid);
|
||||
WeChatString nickname(NULL);
|
||||
DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
|
||||
DWORD get_nickname_addr = base_addr_ + WX_GET_MEMBER_NICKNAME_OFFSET;
|
||||
DWORD contact_mgr_addr = base_addr_ + WX_CONTACT_MGR_OFFSET;
|
||||
DWORD get_contact_addr = base_addr_ + WX_GET_CONTACT_OFFSET;
|
||||
DWORD free_contact_addr = base_addr_ + WX_FREE_CONTACT_OFFSET;
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
CALL get_chat_room_mgr_addr
|
||||
LEA ECX,nickname
|
||||
PUSH ECX
|
||||
LEA ECX,member_id
|
||||
PUSH ECX
|
||||
LEA ECX,chat_room
|
||||
PUSH ECX
|
||||
MOV ECX,EAX
|
||||
CALL get_nickname_addr
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
wstring name = L"";
|
||||
if (nickname.ptr) {
|
||||
name += wstring(nickname.ptr);
|
||||
} else {
|
||||
char buff[0x440] = {0};
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
CALL contact_mgr_addr
|
||||
LEA ECX,buff
|
||||
PUSH ECX
|
||||
LEA ECX,member_id
|
||||
PUSH ECX
|
||||
MOV ECX,EAX
|
||||
CALL get_contact_addr
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
name += READ_WSTRING(buff, 0x6C);
|
||||
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
LEA ECX,buff
|
||||
CALL free_contact_addr
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
int ChatRoomMgr::InviteMemberToChatRoom(wchar_t* chat_room_id, wchar_t** wxids, int len) {
|
||||
int success = -1;
|
||||
WeChatString chat_room(chat_room_id);
|
||||
vector<WeChatString> members;
|
||||
VectorInner* list = (VectorInner*)&members;
|
||||
DWORD members_ptr = (DWORD)&list->start;
|
||||
for (int i = 0; i < len; i++) {
|
||||
WeChatString pwxid(wxids[i]);
|
||||
members.push_back(pwxid);
|
||||
}
|
||||
DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
|
||||
DWORD add_member_addr = base_addr_ + WX_ADD_MEMBER_TO_CHAT_ROOM_OFFSET;
|
||||
DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET;
|
||||
DWORD get_share_record_mgr_addr = base_addr_ + WX_SHARE_RECORD_MGR_OFFSET;
|
||||
|
||||
DWORD fn1 = base_addr_ + 0x7fa730;
|
||||
DWORD fn2 = base_addr_ + 0x78d9a0;
|
||||
DWORD fn3 = base_addr_ + 0x7fb6e0;
|
||||
DWORD fn4 = base_addr_ + 0x755af0;
|
||||
DWORD invite_addr = base_addr_ + 0xbd28a0;
|
||||
|
||||
DWORD sys_addr = (DWORD)GetModuleHandleA("win32u.dll") + 0x116C;
|
||||
DWORD addr[2] = {sys_addr,0};
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
CALL get_share_record_mgr_addr
|
||||
LEA ECX,addr
|
||||
PUSH ECX
|
||||
MOV ECX,EAX
|
||||
CALL fn1
|
||||
CALL get_chat_room_mgr_addr
|
||||
SUB ESP,0x8
|
||||
LEA EAX,addr
|
||||
MOV ECX,ESP
|
||||
PUSH EAX
|
||||
CALL fn2
|
||||
SUB ESP,0x14
|
||||
MOV ECX,ESP
|
||||
LEA EAX,chat_room
|
||||
PUSH EAX
|
||||
CALL init_chat_msg_addr
|
||||
MOV EAX,dword ptr[members_ptr]
|
||||
PUSH EAX
|
||||
CALL invite_addr
|
||||
CALL get_share_record_mgr_addr
|
||||
PUSH 0x0
|
||||
PUSH 0x1
|
||||
MOV ECX,EAX
|
||||
CALL fn3
|
||||
LEA ECX,addr
|
||||
CALL fn4
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
success = 1;
|
||||
return success;
|
||||
|
||||
}
|
||||
|
||||
} // namespace wxhelper
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef WXHELPER_CHAT_ROOM_MGR_H_
|
||||
#define WXHELPER_CHAT_ROOM_MGR_H_
|
||||
#include "wechat_function.h"
|
||||
#include "base_mgr.h"
|
||||
namespace wxhelper {
|
||||
class ChatRoomMgr:public BaseMgr {
|
||||
public:
|
||||
explicit ChatRoomMgr(DWORD base);
|
||||
~ChatRoomMgr();
|
||||
int GetChatRoomDetailInfo(wchar_t* chat_room_id,
|
||||
ChatRoomInfoInner& room_info);
|
||||
int DelMemberFromChatRoom(wchar_t* chat_room_id, wchar_t** wxids,
|
||||
int len);
|
||||
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);
|
||||
|
||||
std::wstring GetChatRoomMemberNickname(wchar_t* chat_room_id,
|
||||
wchar_t* wxid);
|
||||
int InviteMemberToChatRoom(wchar_t* chat_room_id, wchar_t** wxids,
|
||||
int len);
|
||||
};
|
||||
} // namespace wxhelper
|
||||
#endif
|
||||
-138
@@ -1,138 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "common.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
/// @brief utf8 转换成unicode
|
||||
/// @param buffer utf8
|
||||
/// @return unicode
|
||||
wstring utf8_to_unicode(const char *buffer) {
|
||||
int c_size = MultiByteToWideChar(CP_UTF8, 0, buffer, -1, NULL, 0);
|
||||
if (c_size > 0) {
|
||||
wchar_t *temp = new wchar_t[c_size + 1];
|
||||
MultiByteToWideChar(CP_UTF8, 0, buffer, -1, temp, c_size);
|
||||
temp[c_size] = L'\0';
|
||||
wstring ret(temp);
|
||||
delete[] temp;
|
||||
temp = NULL;
|
||||
return ret;
|
||||
}
|
||||
return wstring();
|
||||
}
|
||||
|
||||
/// @brief unicode转换utf8
|
||||
/// @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);
|
||||
if (c_size > 0) {
|
||||
char *buffer = new char[c_size + 1];
|
||||
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, buffer, c_size, NULL, FALSE);
|
||||
buffer[c_size] = '\0';
|
||||
string str(buffer);
|
||||
delete[] buffer;
|
||||
buffer = NULL;
|
||||
return str;
|
||||
}
|
||||
return string();
|
||||
}
|
||||
|
||||
/// @brief 获取WeChatWin.dll基址
|
||||
/// @return 基址
|
||||
DWORD GetWeChatWinBase() { return (DWORD)GetModuleHandleA("WeChatWin.dll"); }
|
||||
|
||||
/// @brief 创建窗口
|
||||
/// @param void
|
||||
/// @return 创建结果
|
||||
BOOL CreateConsole(void) {
|
||||
if (AllocConsole()) {
|
||||
AttachConsole(GetCurrentProcessId());
|
||||
FILE *retStream;
|
||||
freopen_s(&retStream, "CONOUT$", "w", stdout);
|
||||
if (!retStream) throw std::runtime_error("Stdout redirection failed.");
|
||||
freopen_s(&retStream, "CONOUT$", "w", stderr);
|
||||
if (!retStream) throw std::runtime_error("Stderr redirection failed.");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// @brief hook any addr
|
||||
/// @param hook_addr need hook of addr
|
||||
/// @param jmp_addr hook function addr
|
||||
/// @param origin origin code
|
||||
void HookAnyAddress(DWORD hook_addr, LPVOID jmp_addr, char *origin) {
|
||||
BYTE jmp_code[5] = {0};
|
||||
jmp_code[0] = 0xE9;
|
||||
*(DWORD *)&jmp_code[1] = (DWORD)jmp_addr - hook_addr - 5;
|
||||
DWORD old_protext = 0;
|
||||
VirtualProtect((LPVOID)hook_addr, 5, PAGE_EXECUTE_READWRITE, &old_protext);
|
||||
ReadProcessMemory(GetCurrentProcess(), (LPVOID)hook_addr, origin, 5, 0);
|
||||
memcpy((void *)hook_addr, jmp_code, 5);
|
||||
VirtualProtect((LPVOID)hook_addr, 5, old_protext, &old_protext);
|
||||
}
|
||||
|
||||
/// @brief unhook
|
||||
/// @param hook_addr hook addr
|
||||
/// @param origin origin addr code
|
||||
void UnHookAnyAddress(DWORD hook_addr, char *origin) {
|
||||
DWORD old_protext = 0;
|
||||
VirtualProtect((LPVOID)hook_addr, 5, PAGE_EXECUTE_READWRITE, &old_protext);
|
||||
WriteProcessMemory(GetCurrentProcess(), (LPVOID)hook_addr, origin, 5, 0);
|
||||
VirtualProtect((LPVOID)hook_addr, 5, old_protext, &old_protext);
|
||||
}
|
||||
|
||||
/// @brief get timeW
|
||||
/// @param timestamp timestamp
|
||||
/// @return str
|
||||
wstring GetTimeW(long long timestamp) {
|
||||
wchar_t *wstr = new wchar_t[20];
|
||||
memset(wstr, 0, 20 * 2);
|
||||
tm tm_out;
|
||||
localtime_s(&tm_out, ×tamp);
|
||||
swprintf_s(wstr, 20, L"%04d-%02d-%02d %02d:%02d:%02d", 1900 + tm_out.tm_year,
|
||||
tm_out.tm_mon + 1, tm_out.tm_mday, tm_out.tm_hour, tm_out.tm_min,
|
||||
tm_out.tm_sec);
|
||||
wstring strTimeW(wstr);
|
||||
delete[] wstr;
|
||||
return strTimeW;
|
||||
}
|
||||
|
||||
wstring String2Wstring(string str) {
|
||||
wstring result;
|
||||
int len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), NULL, 0);
|
||||
wchar_t *buffer = new wchar_t[len + 1];
|
||||
MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), buffer, len);
|
||||
buffer[len] = '\0';
|
||||
result.append(buffer);
|
||||
delete[] buffer;
|
||||
return result;
|
||||
}
|
||||
|
||||
string Wstring2String(wstring wstr) {
|
||||
string result;
|
||||
int len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), NULL, 0,
|
||||
NULL, NULL);
|
||||
char *buffer = new char[len + 1];
|
||||
WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), buffer, len, NULL,
|
||||
NULL);
|
||||
buffer[len] = '\0';
|
||||
result.append(buffer);
|
||||
delete[] buffer;
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL FindOrCreateDirectoryW(const wchar_t *path) {
|
||||
WIN32_FIND_DATAW fd;
|
||||
HANDLE hFind = ::FindFirstFileW(path, &fd);
|
||||
if (hFind != INVALID_HANDLE_VALUE) {
|
||||
FindClose(hFind);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!::CreateDirectoryW(path, NULL)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
#ifndef COMMON_H_
|
||||
#define COMMON_H_
|
||||
#include <string>
|
||||
#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
|
||||
std::wstring utf8_to_unicode(const char *buffer);
|
||||
|
||||
/// @brief unicode转换utf8
|
||||
/// @param wstr unicode
|
||||
/// @return utf8
|
||||
std::string unicode_to_utf8(wchar_t *wstr);
|
||||
|
||||
/// @brief 获取WeChatWin.dll基址
|
||||
/// @return 基址
|
||||
DWORD GetWeChatWinBase();
|
||||
/// @brief 创建窗口
|
||||
/// @param void
|
||||
/// @return 创建结果
|
||||
BOOL CreateConsole(void);
|
||||
/// @brief hook任意地址
|
||||
/// @param hook_addr 被hook的地址
|
||||
/// @param jmp_addr 被hook的函数的地址
|
||||
/// @param origin 原始code
|
||||
void HookAnyAddress(DWORD hook_addr, LPVOID jmp_addr, char *origin);
|
||||
|
||||
/// @brief 取消hook
|
||||
/// @param hook_addr 被hook的地址
|
||||
/// @param origin 原始code
|
||||
void UnHookAnyAddress(DWORD hook_addr, char *origin);
|
||||
|
||||
/// @brief get timeW
|
||||
/// @param timestamp timestamp
|
||||
/// @return str
|
||||
std::wstring GetTimeW(long long timestamp);
|
||||
/// @brief unicode trans utf8
|
||||
/// @param str unicode str
|
||||
/// @return utf8 str
|
||||
std::string UnicodeToUtf8(const wchar_t *str);
|
||||
/// @brief string convert wstring
|
||||
/// @param str
|
||||
/// @return
|
||||
std::wstring String2Wstring(std::string str);
|
||||
/// @brief wstring convert string
|
||||
/// @param str
|
||||
/// @return
|
||||
std::string Wstring2String(std::wstring wstr);
|
||||
|
||||
/// @brief create dir
|
||||
/// @param path
|
||||
/// @return
|
||||
BOOL FindOrCreateDirectoryW(const wchar_t *path);
|
||||
|
||||
|
||||
template <typename T1, typename T2>
|
||||
std::vector<T1> split(T1 str, T2 letter) {
|
||||
vector<T1> arr;
|
||||
size_t pos;
|
||||
while ((pos = str.find_first_of(letter)) != T1::npos) {
|
||||
T1 str1 = str.substr(0, pos);
|
||||
arr.push_back(str1);
|
||||
str = str.substr(pos + 1, str.length() - pos - 1);
|
||||
}
|
||||
arr.push_back(str);
|
||||
return arr;
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
T1 replace(T1 source, T2 replaced, T1 replaceto) {
|
||||
vector<T1> v_arr = split(source, replaced);
|
||||
if (v_arr.size() < 2) return source;
|
||||
T1 temp;
|
||||
for (unsigned int i = 0; i < v_arr.size() - 1; i++) {
|
||||
temp += v_arr[i];
|
||||
temp += replaceto;
|
||||
}
|
||||
temp += v_arr[v_arr.size() - 1];
|
||||
return temp;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "pch.h"
|
||||
#include "config.h"
|
||||
|
||||
namespace wxhelper {
|
||||
Config::Config(/* args */) {}
|
||||
|
||||
Config::~Config() {}
|
||||
|
||||
|
||||
void Config::Initialize(){
|
||||
port_ = GetPrivateProfileInt("config", "Port", 19088, "./config.ini");
|
||||
}
|
||||
int Config::GetPort(){
|
||||
return port_;
|
||||
}
|
||||
|
||||
} // namespace wxhelper
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef WXHELPER_CONFIG_H_
|
||||
#define WXHELPER_CONFIG_H_
|
||||
|
||||
namespace wxhelper {
|
||||
|
||||
class Config {
|
||||
public:
|
||||
Config(/* args */);
|
||||
~Config();
|
||||
void Initialize();
|
||||
int GetPort();
|
||||
|
||||
private:
|
||||
int port_;
|
||||
};
|
||||
} // namespace wxhelper
|
||||
#endif
|
||||
@@ -1,49 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "confirm_receipt.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "wechat_data.h"
|
||||
|
||||
#define WX_NEW_WCPAYINFO_OFFSET 0x756340
|
||||
#define WX_FREE_WCPAYINFO_OFFSET 0x73c170
|
||||
#define WX_CONFIRM_RECEIPT_OFFSET 0x15287a0
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#ifndef CONFIRM_RECEIPT_H
|
||||
#define CONFIRM_RECEIPT_H
|
||||
|
||||
int DoConfirmReceipt(wchar_t* wxid,wchar_t *transcationid, wchar_t *transferid);
|
||||
|
||||
#endif
|
||||
-192
@@ -1,192 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "contact.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "wechat_data.h"
|
||||
using namespace std;
|
||||
#define WX_CONTACT_MGR_INSTANCE_OFFSET 0x6f8990
|
||||
#define WX_CONTACT_GET_LIST_OFFSET 0xb97550
|
||||
#define WX_CONTACT_DEL_OFFSET 0xb9b3b0
|
||||
#define WX_INIT_CHAT_MSG_OFFSET 0xed3be0
|
||||
#define WX_SYNC_MGR_OFFSET 0xa87fd0
|
||||
#define WX_SET_VALUE_OFFSET 0x1f80900
|
||||
#define WX_DO_DEL_CONTACT_OFFSET 0xca6480
|
||||
#define WX_FREE_CONTACT_OFFSET 0xe23690
|
||||
#define WX_GET_CONTACT_OFFSET 0xb93b20
|
||||
#define WX_DO_VERIFY_USER_OFFSET 0xB91160
|
||||
|
||||
int GetAllContact(vector<Contact> &vec) {
|
||||
DWORD base = GetWeChatWinBase();
|
||||
DWORD get_instance = base + WX_CONTACT_MGR_INSTANCE_OFFSET;
|
||||
DWORD contact_get_list = base + WX_CONTACT_GET_LIST_OFFSET;
|
||||
// char contact[0xc] = {0};
|
||||
DWORD* contact[3] = {0, 0, 0};
|
||||
int success = 0;
|
||||
__asm {
|
||||
PUSHAD
|
||||
CALL get_instance
|
||||
LEA ECX,contact
|
||||
PUSH ECX
|
||||
MOV ECX,EAX
|
||||
CALL contact_get_list
|
||||
MOVZX EAX,AL
|
||||
MOV success,EAX
|
||||
POPAD
|
||||
}
|
||||
DWORD start = (DWORD)contact[0];
|
||||
DWORD end = (DWORD)contact[2];
|
||||
#ifdef _DEBUG
|
||||
cout << "address = " << &contact << endl;
|
||||
cout << "refresh contact = " << success << endl;
|
||||
cout << "start = " << start << endl;
|
||||
cout << "end = " << end << endl;
|
||||
#endif
|
||||
while (start < end) {
|
||||
Contact temp{0};
|
||||
|
||||
temp.wxid.ptr = *(wchar_t **)(start + 0x10);
|
||||
temp.wxid.length = *(DWORD *)(start + 0x14);
|
||||
temp.wxid.max_length = *(DWORD *)(start + 0x18);
|
||||
|
||||
temp.custom_account.ptr = *(wchar_t **)(start + 0x24);
|
||||
temp.custom_account.length = *(DWORD *)(start + 0x28);
|
||||
temp.custom_account.max_length = *(DWORD *)(start + 0x2C);
|
||||
|
||||
temp.encrypt_name.ptr = *(wchar_t **)(start + 0x6c);
|
||||
temp.encrypt_name.length = *(DWORD *)(start + 0x70);
|
||||
temp.encrypt_name.max_length = *(DWORD *)(start + 0x74);
|
||||
|
||||
temp.pinyin.ptr = *(wchar_t **)(start + 0xAC);
|
||||
temp.pinyin.length = *(DWORD *)(start + 0xB0);
|
||||
temp.pinyin.max_length = *(DWORD *)(start + 0xB4);
|
||||
|
||||
temp.pinyin_all.ptr = *(wchar_t **)(start + 0xC0);
|
||||
temp.pinyin_all.length = *(DWORD *)(start + 0xC4);
|
||||
temp.pinyin_all.max_length = *(DWORD *)(start + 0xC8);
|
||||
|
||||
temp.del_flag = *(DWORD *)(start + 0x4c);
|
||||
temp.type = *(DWORD *)(start + 0x50);
|
||||
temp.verify_flag = *(DWORD *)(start + 0x54);
|
||||
vec.push_back(temp);
|
||||
start += 0x438;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
// note maybe not delete
|
||||
int DelContact(wchar_t *wxid) {
|
||||
int success = -1;
|
||||
WeChatString user_id(wxid);
|
||||
DWORD id_ptr = (DWORD) &user_id;
|
||||
DWORD base = GetWeChatWinBase();
|
||||
DWORD sync_mgr_addr = base + WX_SYNC_MGR_OFFSET;
|
||||
DWORD set_id_addr = base + WX_SET_VALUE_OFFSET;
|
||||
DWORD del_contact_addr = base + WX_DO_DEL_CONTACT_OFFSET;
|
||||
int len = user_id.length;
|
||||
|
||||
string id_cstr = unicode_to_utf8(wxid);
|
||||
char id_[0x20]={0};
|
||||
memcpy(id_,id_cstr.c_str(),id_cstr.size()+1);
|
||||
char buff[0x10]={0};
|
||||
__asm{
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
CALL sync_mgr_addr
|
||||
MOV ECX,EAX
|
||||
LEA EAX,buff
|
||||
MOV [ECX + 4],EAX
|
||||
LEA EAX,id_
|
||||
Mov dword ptr[buff +0x4],EAX
|
||||
CALL del_contact_addr
|
||||
MOV success,EAX
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
std::wstring GetContactOrChatRoomNickname(wchar_t *id) {
|
||||
int success = -1;
|
||||
char buff[0x440] = {0};
|
||||
WeChatString pri(id);
|
||||
DWORD base = GetWeChatWinBase();
|
||||
DWORD contact_mgr_addr = base + WX_CONTACT_MGR_INSTANCE_OFFSET;
|
||||
DWORD get_contact_addr = base + WX_GET_CONTACT_OFFSET;
|
||||
DWORD free_contact_addr = base + WX_FREE_CONTACT_OFFSET;
|
||||
wstring name = L"";
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
CALL contact_mgr_addr
|
||||
LEA ECX,buff
|
||||
PUSH ECX
|
||||
LEA ECX,pri
|
||||
PUSH ECX
|
||||
MOV ECX,EAX
|
||||
CALL get_contact_addr
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
name += READ_WSTRING(buff, 0x6C);
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
LEA ECX,buff
|
||||
CALL free_contact_addr
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
int AddFriendByWxid(wchar_t *wxid){
|
||||
int success = -1;
|
||||
DWORD base = GetWeChatWinBase();
|
||||
DWORD contact_mgr_addr = base + WX_CONTACT_MGR_INSTANCE_OFFSET;
|
||||
DWORD set_group_addr = base + 0x746E20;
|
||||
DWORD fn2_addr = base + 0x285D968;
|
||||
DWORD fn3_addr = base + 0x6F6050;
|
||||
DWORD fn4_addr = base + 0xED3BE0;
|
||||
DWORD do_verify_user_addr = base + WX_DO_VERIFY_USER_OFFSET;
|
||||
|
||||
DWORD instance =0;
|
||||
WeChatString chat_room(NULL);
|
||||
WeChatString user_id(wxid);
|
||||
__asm{
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
CALL contact_mgr_addr
|
||||
SUB ESP,0x18
|
||||
MOV dword ptr [instance],EAX
|
||||
MOV ECX,ESP
|
||||
PUSH ECX
|
||||
LEA ECX,chat_room
|
||||
CALL set_group_addr
|
||||
MOV EAX,fn2_addr
|
||||
SUB ESP,0x18
|
||||
MOV ECX,ESP
|
||||
PUSH EAX
|
||||
CALL fn3_addr
|
||||
PUSH 0x0
|
||||
PUSH 0XE
|
||||
SUB ESP,0x14
|
||||
MOV ESI,ESP
|
||||
MOV dword ptr [ESI],0x0
|
||||
MOV dword ptr [ESI+0x4],0x0
|
||||
MOV dword ptr [ESI+0x8],0x0
|
||||
MOV dword ptr [ESI+0xC],0x0
|
||||
MOV dword ptr [ESI+0x10],0x0
|
||||
PUSH 0x1
|
||||
SUB ESP,0x14
|
||||
MOV ECX,ESP
|
||||
LEA EAX,user_id
|
||||
PUSH EAX
|
||||
CALL fn4_addr
|
||||
MOV ECX,dword ptr [instance]
|
||||
CALL do_verify_user_addr
|
||||
MOV success,EAX
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
return success;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
#ifndef CONTACT_H_
|
||||
#define CONTACT_H_
|
||||
#include <vector>
|
||||
#include "wechat_data.h"
|
||||
|
||||
int GetAllContact(std::vector<Contact> &vec);
|
||||
|
||||
|
||||
|
||||
int DelContact(wchar_t* wxid);
|
||||
|
||||
std::wstring GetContactOrChatRoomNickname(wchar_t* id);
|
||||
|
||||
int AddFriendByWxid(wchar_t *wxid);
|
||||
#endif
|
||||
@@ -0,0 +1,220 @@
|
||||
#include "pch.h"
|
||||
#include "contact_mgr.h"
|
||||
|
||||
|
||||
#include "wechat_function.h"
|
||||
|
||||
using namespace std;
|
||||
namespace wxhelper {
|
||||
ContactMgr::ContactMgr(DWORD base) : BaseMgr(base) {}
|
||||
ContactMgr::~ContactMgr() {}
|
||||
int ContactMgr::GetAllContact(vector<Contact> &vec) {
|
||||
DWORD get_instance = base_addr_ + WX_CONTACT_MGR_OFFSET;
|
||||
DWORD contact_get_list = base_addr_ + WX_CONTACT_GET_LIST_OFFSET;
|
||||
DWORD *contact[3] = {0, 0, 0};
|
||||
int success = 0;
|
||||
__asm {
|
||||
PUSHAD
|
||||
CALL get_instance
|
||||
LEA ECX,contact
|
||||
PUSH ECX
|
||||
MOV ECX,EAX
|
||||
CALL contact_get_list
|
||||
MOVZX EAX,AL
|
||||
MOV success,EAX
|
||||
POPAD
|
||||
}
|
||||
DWORD start = (DWORD)contact[0];
|
||||
DWORD end = (DWORD)contact[2];
|
||||
while (start < end) {
|
||||
Contact temp{0};
|
||||
|
||||
temp.wxid.ptr = *(wchar_t **)(start + 0x10);
|
||||
temp.wxid.length = *(DWORD *)(start + 0x14);
|
||||
temp.wxid.max_length = *(DWORD *)(start + 0x18);
|
||||
|
||||
temp.custom_account.ptr = *(wchar_t **)(start + 0x24);
|
||||
temp.custom_account.length = *(DWORD *)(start + 0x28);
|
||||
temp.custom_account.max_length = *(DWORD *)(start + 0x2C);
|
||||
|
||||
temp.encrypt_name.ptr = *(wchar_t **)(start + 0x6c);
|
||||
temp.encrypt_name.length = *(DWORD *)(start + 0x70);
|
||||
temp.encrypt_name.max_length = *(DWORD *)(start + 0x74);
|
||||
|
||||
temp.pinyin.ptr = *(wchar_t **)(start + 0xAC);
|
||||
temp.pinyin.length = *(DWORD *)(start + 0xB0);
|
||||
temp.pinyin.max_length = *(DWORD *)(start + 0xB4);
|
||||
|
||||
temp.pinyin_all.ptr = *(wchar_t **)(start + 0xC0);
|
||||
temp.pinyin_all.length = *(DWORD *)(start + 0xC4);
|
||||
temp.pinyin_all.max_length = *(DWORD *)(start + 0xC8);
|
||||
|
||||
temp.del_flag = *(DWORD *)(start + 0x4c);
|
||||
temp.type = *(DWORD *)(start + 0x50);
|
||||
temp.verify_flag = *(DWORD *)(start + 0x54);
|
||||
vec.push_back(temp);
|
||||
start += 0x438;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
int ContactMgr::DelContact(wchar_t *wxid) {
|
||||
int success = -1;
|
||||
WeChatString user_id(wxid);
|
||||
DWORD id_ptr = (DWORD)&user_id;
|
||||
DWORD sync_mgr_addr = base_addr_ + WX_SYNC_MGR_OFFSET;
|
||||
DWORD set_id_addr = base_addr_ + WX_SET_VALUE_OFFSET;
|
||||
DWORD del_contact_addr = base_addr_ + WX_DO_DEL_CONTACT_OFFSET;
|
||||
int len = user_id.length;
|
||||
wstring ws_wxid(wxid);
|
||||
|
||||
string id_cstr = Utils::WstringToUTF8(ws_wxid);
|
||||
char id_[0x20] = {0};
|
||||
memcpy(id_, id_cstr.c_str(), id_cstr.size() + 1);
|
||||
char buff[0x10] = {0};
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
CALL sync_mgr_addr
|
||||
MOV ECX,EAX
|
||||
LEA EAX,buff
|
||||
MOV [ECX + 4],EAX
|
||||
LEA EAX,id_
|
||||
Mov dword ptr[buff +0x4],EAX
|
||||
CALL del_contact_addr
|
||||
MOV success,EAX
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
return success;
|
||||
}
|
||||
wstring ContactMgr::GetContactOrChatRoomNickname(wchar_t *id) {
|
||||
int success = -1;
|
||||
char buff[0x440] = {0};
|
||||
WeChatString pri(id);
|
||||
DWORD contact_mgr_addr = base_addr_ + WX_CONTACT_MGR_OFFSET;
|
||||
DWORD get_contact_addr = base_addr_ + WX_GET_CONTACT_OFFSET;
|
||||
DWORD free_contact_addr = base_addr_ + WX_FREE_CONTACT_OFFSET;
|
||||
wstring name = L"";
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
CALL contact_mgr_addr
|
||||
LEA ECX,buff
|
||||
PUSH ECX
|
||||
LEA ECX,pri
|
||||
PUSH ECX
|
||||
MOV ECX,EAX
|
||||
CALL get_contact_addr
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
name += READ_WSTRING(buff, 0x6C);
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
LEA ECX,buff
|
||||
CALL free_contact_addr
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
int ContactMgr::AddFriendByWxid(wchar_t *wxid,wchar_t* msg) {
|
||||
int success = -1;
|
||||
DWORD contact_mgr_addr = base_addr_ + WX_CONTACT_MGR_OFFSET;
|
||||
DWORD verify_msg_addr = base_addr_ + WX_VERIFY_MSG_OFFSET;
|
||||
DWORD set_value_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET;
|
||||
DWORD do_verify_user_addr = base_addr_ + WX_DO_VERIFY_USER_OFFSET;
|
||||
DWORD fn1_addr = base_addr_ + 0x7591b0;
|
||||
WeChatString user_id(wxid);
|
||||
WeChatString w_msg(msg);
|
||||
DWORD instance =0;
|
||||
Unkown null_obj={0,0,0,0,0,0xF};
|
||||
__asm{
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
CALL contact_mgr_addr
|
||||
MOV dword ptr [instance],EAX
|
||||
MOV EDI,0x6
|
||||
MOV ESI,0
|
||||
MOV EAX,0x2
|
||||
SUB ESP,0x18
|
||||
MOV EAX,ESP
|
||||
MOV dword ptr ds:[EAX],0
|
||||
MOV dword ptr ds:[EAX+0x14],0xF
|
||||
MOV dword ptr ds:[EAX+0x10],0
|
||||
MOV byte ptr ds:[EAX],0
|
||||
SUB ESP,0x18
|
||||
LEA EAX,null_obj
|
||||
MOV ECX,ESP
|
||||
PUSH EAX
|
||||
CALL fn1_addr
|
||||
PUSH 0x0
|
||||
PUSH 0x6
|
||||
MOV EAX,w_msg
|
||||
|
||||
SUB ESP,0x14
|
||||
MOV ECX,ESP
|
||||
PUSH -0x1
|
||||
PUSH EAX
|
||||
CALL verify_msg_addr
|
||||
PUSH 0x2
|
||||
LEA EAX,user_id
|
||||
|
||||
SUB ESP,0x14
|
||||
MOV ECX,ESP
|
||||
PUSH EAX
|
||||
CALL set_value_addr
|
||||
MOV ECX,dword ptr [instance]
|
||||
CALL do_verify_user_addr
|
||||
MOV success,EAX
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
int ContactMgr::VerifyApply(wchar_t *v3, wchar_t *v4,int permission){
|
||||
int success = -1;
|
||||
DWORD set_value_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET;
|
||||
DWORD verify_addr = base_addr_ + WX_VERIFY_OK_OFFSET;
|
||||
DWORD new_helper_addr = base_addr_ + WX_NEW_ADD_FRIEND_HELPER_OFFSET;
|
||||
DWORD free_helper_addr = base_addr_ + WX_FREE_ADD_FRIEND_HELPER_OFFSET;
|
||||
|
||||
WeChatString v4_str(v4);
|
||||
WeChatString v3_str(v3);
|
||||
char helper_obj[0x40] = {0};
|
||||
char nullbuffer[0x3CC] = {0};
|
||||
int flag = permission < 0 ? 0:permission;
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
LEA ECX,helper_obj
|
||||
CALL new_helper_addr
|
||||
MOV ESI,flag
|
||||
MOV EDI,0x6
|
||||
PUSH ESI
|
||||
PUSH EDI
|
||||
SUB ESP,0x14
|
||||
MOV ECX,ESP
|
||||
LEA EAX,v4_str
|
||||
PUSH EAX
|
||||
CALL set_value_addr
|
||||
SUB ESP,0x8
|
||||
PUSH 0x0
|
||||
LEA EAX, nullbuffer
|
||||
PUSH EAX
|
||||
LEA EAX,v3_str
|
||||
PUSH EAX
|
||||
LEA ECX,helper_obj
|
||||
CALL verify_addr
|
||||
MOV success,EAX
|
||||
LEA ECX,helper_obj
|
||||
CALL free_helper_addr
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
return success;
|
||||
}
|
||||
} // namespace wxhelper
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef WXHELPER_CONTACT_MGR_H_
|
||||
#define WXHELPER_CONTACT_MGR_H_
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base_mgr.h"
|
||||
#include "wechat_function.h"
|
||||
namespace wxhelper {
|
||||
class ContactMgr : public BaseMgr {
|
||||
public:
|
||||
explicit ContactMgr(DWORD base);
|
||||
~ContactMgr();
|
||||
int GetAllContact(std::vector<Contact>& vec);
|
||||
int DelContact(wchar_t* wxid);
|
||||
std::wstring GetContactOrChatRoomNickname(wchar_t* id);
|
||||
int AddFriendByWxid(wchar_t* wxid,wchar_t* msg);
|
||||
int VerifyApply(wchar_t *v3, wchar_t *v4,int permission);
|
||||
};
|
||||
} // namespace wxhelper
|
||||
|
||||
#endif;
|
||||
@@ -0,0 +1,547 @@
|
||||
#include "pch.h"
|
||||
#include "db.h"
|
||||
|
||||
#include "base64.h"
|
||||
#include "wechat_function.h"
|
||||
#include "utils.h"
|
||||
using namespace std;
|
||||
|
||||
namespace wxhelper {
|
||||
|
||||
void DB::init(DWORD base) {
|
||||
base_addr_ = base;
|
||||
dbmap_ = {};
|
||||
dbs_ = {};
|
||||
}
|
||||
|
||||
void FreeResult(vector<vector<SqlResult>> &data) {
|
||||
if (data.size() == 0) {
|
||||
return;
|
||||
}
|
||||
for (unsigned int i = 0; i < data.size(); i++) {
|
||||
for (unsigned j = 0; j < data[i].size(); j++) {
|
||||
SqlResult *sr = (SqlResult *)&data[i][j];
|
||||
if (sr->column_name) {
|
||||
delete[] sr->column_name;
|
||||
sr->column_name = NULL;
|
||||
}
|
||||
if (sr->content) {
|
||||
delete[] sr->content;
|
||||
sr->content = NULL;
|
||||
}
|
||||
}
|
||||
data[i].clear();
|
||||
}
|
||||
data.clear();
|
||||
}
|
||||
|
||||
int DB::SelectDataInner(DWORD db, const char *sql,
|
||||
vector<vector<SqlResult>> &data) {
|
||||
Sqlite3_prepare p_Sqlite3_prepare =
|
||||
(Sqlite3_prepare)(base_addr_ + SQLITE3_PREPARE_OFFSET);
|
||||
Sqlite3_step p_Sqlite3_step =
|
||||
(Sqlite3_step)(base_addr_ + SQLITE3_STEP_OFFSET);
|
||||
Sqlite3_column_count p_Sqlite3_column_count =
|
||||
(Sqlite3_column_count)(base_addr_ + SQLITE3_COLUMN_COUNT_OFFSET);
|
||||
Sqlite3_column_name p_Sqlite3_column_name =
|
||||
(Sqlite3_column_name)(base_addr_ + SQLITE3_COLUMN_NAME_OFFSET);
|
||||
Sqlite3_column_type p_Sqlite3_column_type =
|
||||
(Sqlite3_column_type)(base_addr_ + SQLITE3_COLUMN_TYPE_OFFSET);
|
||||
Sqlite3_column_blob p_Sqlite3_column_blob =
|
||||
(Sqlite3_column_blob)(base_addr_ + SQLITE3_COLUMN_BLOB_OFFSET);
|
||||
Sqlite3_column_bytes p_Sqlite3_column_bytes =
|
||||
(Sqlite3_column_bytes)(base_addr_ + SQLITE3_COLUMN_BYTES_OFFSET);
|
||||
Sqlite3_finalize p_Sqlite3_finalize =
|
||||
(Sqlite3_finalize)(base_addr_ + SQLITE3_FINALIZE_OFFSET);
|
||||
DWORD *stmt;
|
||||
int rc = p_Sqlite3_prepare(db, sql, -1, &stmt, 0);
|
||||
if (rc != SQLITE_OK) return NULL;
|
||||
while (p_Sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
int col_count = p_Sqlite3_column_count(stmt);
|
||||
vector<SqlResult> tempStruct;
|
||||
for (int i = 0; i < col_count; i++) {
|
||||
SqlResult temp = {0};
|
||||
const char *ColName = p_Sqlite3_column_name(stmt, i);
|
||||
int nType = p_Sqlite3_column_type(stmt, i);
|
||||
const void *pReadBlobData = p_Sqlite3_column_blob(stmt, i);
|
||||
int nLength = p_Sqlite3_column_bytes(stmt, i);
|
||||
temp.column_name = new char[strlen(ColName) + 1];
|
||||
memcpy(temp.column_name, ColName, strlen(ColName) + 1);
|
||||
temp.column_name_len = strlen(ColName);
|
||||
temp.content_len = nLength;
|
||||
switch (nType) {
|
||||
case SQLITE_BLOB: {
|
||||
temp.content = new char[nLength];
|
||||
memcpy(temp.content, pReadBlobData, nLength);
|
||||
temp.is_blob = true;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (nLength != 0) {
|
||||
temp.content = new char[nLength + 1];
|
||||
memcpy(temp.content, pReadBlobData, nLength + 1);
|
||||
} else {
|
||||
temp.content = new char[2];
|
||||
ZeroMemory(temp.content, 2);
|
||||
}
|
||||
temp.is_blob = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
tempStruct.push_back(temp);
|
||||
}
|
||||
data.push_back(tempStruct);
|
||||
}
|
||||
p_Sqlite3_finalize(stmt);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int DB::Select(DWORD db_hanle, const char *sql,
|
||||
vector<vector<string>> &query_result) {
|
||||
vector<vector<SqlResult>> data;
|
||||
int status = SelectDataInner(db_hanle, sql, data);
|
||||
if (status == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (data.size() == 0) {
|
||||
return 1;
|
||||
}
|
||||
vector<string> index;
|
||||
for (size_t i = 0; i < data[0].size(); i++) {
|
||||
index.push_back(data[0][i].column_name);
|
||||
}
|
||||
query_result.push_back(index);
|
||||
|
||||
for (auto it : data) {
|
||||
vector<string> item;
|
||||
for (size_t i = 0; i < it.size(); i++) {
|
||||
if (!it[i].is_blob) {
|
||||
bool is_utf8 = Utils::IsTextUtf8(it[i].content, it[i].content_len);
|
||||
if (is_utf8) {
|
||||
string content(it[i].content);
|
||||
item.push_back(content);
|
||||
} else {
|
||||
string base64_str =
|
||||
base64_encode((BYTE *)it[i].content, it[i].content_len);
|
||||
item.push_back(base64_str);
|
||||
}
|
||||
|
||||
} else {
|
||||
string b64_str =
|
||||
base64_encode((BYTE *)it[i].content, it[i].content_len);
|
||||
item.push_back(b64_str);
|
||||
}
|
||||
}
|
||||
query_result.push_back(item);
|
||||
}
|
||||
FreeResult(data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SelectDbInfo(void *data, int argc, char **argv, char **name) {
|
||||
vector<SqlResult> result;
|
||||
for (int i = 0; i < argc; i++) {
|
||||
SqlResult temp = {0};
|
||||
temp.column_name = new char[strlen(name[i]) + 1];
|
||||
memcpy(temp.column_name, name[i], strlen(name[i]) + 1);
|
||||
temp.column_name_len = strlen(name[i]);
|
||||
if (argv[i]) {
|
||||
temp.content = new char[strlen(argv[i]) + 1];
|
||||
memcpy(temp.content, argv[i], strlen(argv[i]) + 1);
|
||||
temp.content_len = strlen(argv[i]);
|
||||
} else {
|
||||
temp.content = new char[2];
|
||||
ZeroMemory(temp.content, 2);
|
||||
temp.content_len = 0;
|
||||
}
|
||||
result.push_back(temp);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int DB::ExecuteSQL(DWORD db, const char *sql, DWORD callback, void *data) {
|
||||
DWORD sqlite3_exec_addr = base_addr_ + SQLITE3_EXEC_OFFSET;
|
||||
Sqlite3_exec fn_sqlite3_exec = (Sqlite3_exec)sqlite3_exec_addr;
|
||||
int status = fn_sqlite3_exec(db, sql, (Sqlite3_callback)callback, data, 0);
|
||||
return status;
|
||||
}
|
||||
|
||||
int GetDbInfo(void *data, int argc, char **argv, char **name) {
|
||||
DatabaseInfo *pdata = (DatabaseInfo *)data;
|
||||
TableInfo tb = {0};
|
||||
if (argv[1]) {
|
||||
tb.name = new char[strlen(argv[1]) + 1];
|
||||
memcpy(tb.name, argv[1], strlen(argv[1]) + 1);
|
||||
} else {
|
||||
tb.name = (char *)"NULL";
|
||||
}
|
||||
if (argv[2]) {
|
||||
tb.table_name = new char[strlen(argv[2]) + 1];
|
||||
memcpy(tb.table_name, argv[2], strlen(argv[2]) + 1);
|
||||
} else {
|
||||
tb.table_name = (char *)"NULL";
|
||||
}
|
||||
if (argv[3]) {
|
||||
tb.rootpage = new char[strlen(argv[3]) + 1];
|
||||
memcpy(tb.rootpage, argv[3], strlen(argv[3]) + 1);
|
||||
} else {
|
||||
tb.rootpage = (char *)"NULL";
|
||||
}
|
||||
if (argv[4]) {
|
||||
tb.sql = new char[strlen(argv[4]) + 1];
|
||||
memcpy(tb.sql, argv[4], strlen(argv[4]) + 1);
|
||||
} else {
|
||||
tb.sql = (char *)"NULL";
|
||||
}
|
||||
tb.name_len = strlen(tb.name);
|
||||
tb.table_name_len = strlen(tb.table_name);
|
||||
tb.sql_len = strlen(tb.sql);
|
||||
tb.rootpage_len = strlen(tb.rootpage);
|
||||
pdata->tables.push_back(tb);
|
||||
pdata->count = pdata->tables.size();
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<void *> DB::GetDbHandles() {
|
||||
dbs_.clear();
|
||||
dbmap_.clear();
|
||||
DWORD p_contact_addr = *(DWORD *)(base_addr_ + 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);
|
||||
DWORD emotion_db_addr = *(DWORD *)(p_contact_addr + DB_EMOTION_OFFSET);
|
||||
DWORD media_db_addr = *(DWORD *)(p_contact_addr + DB_MEDIA_OFFSET);
|
||||
DWORD bizchat_msg_db_addr =
|
||||
*(DWORD *)(p_contact_addr + DB_BIZCHAT_MSG_OFFSET);
|
||||
DWORD function_msg_db_addr =
|
||||
*(DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET);
|
||||
|
||||
// microMsg.db
|
||||
DatabaseInfo micro_msg_db{0};
|
||||
micro_msg_db.db_name = (wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_MICRO_MSG_OFFSET + DB_NAME_OFFSET));
|
||||
micro_msg_db.db_name_len =
|
||||
*(DWORD *)(p_contact_addr + DB_MICRO_MSG_OFFSET + DB_NAME_OFFSET + 0x4);
|
||||
micro_msg_db.handle = micro_msg_db_addr;
|
||||
ExecuteSQL(micro_msg_db_addr,
|
||||
"select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, µ_msg_db);
|
||||
dbs_.push_back(micro_msg_db);
|
||||
wstring micro_msg_name = wstring((wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_MICRO_MSG_OFFSET + DB_NAME_OFFSET)));
|
||||
dbmap_[micro_msg_name] = micro_msg_db;
|
||||
|
||||
// chatMsg.db
|
||||
DatabaseInfo chat_msg_db{0};
|
||||
chat_msg_db.db_name = (wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_CHAT_MSG_OFFSET + DB_NAME_OFFSET));
|
||||
chat_msg_db.db_name_len =
|
||||
*(DWORD *)(p_contact_addr + DB_CHAT_MSG_OFFSET + DB_NAME_OFFSET + 0x4);
|
||||
chat_msg_db.handle = chat_msg_db_addr;
|
||||
ExecuteSQL(chat_msg_db_addr,
|
||||
"select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, &chat_msg_db);
|
||||
dbs_.push_back(chat_msg_db);
|
||||
wstring chat_msg_name = wstring((wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_CHAT_MSG_OFFSET + DB_NAME_OFFSET)));
|
||||
dbmap_[chat_msg_name] = chat_msg_db;
|
||||
|
||||
// misc.db
|
||||
DatabaseInfo misc_db{0};
|
||||
misc_db.db_name =
|
||||
(wchar_t *)(*(DWORD *)(p_contact_addr + DB_MISC_OFFSET + DB_NAME_OFFSET));
|
||||
misc_db.db_name_len =
|
||||
*(DWORD *)(p_contact_addr + DB_MISC_OFFSET + DB_NAME_OFFSET + 0x4);
|
||||
misc_db.handle = misc_db_addr;
|
||||
ExecuteSQL(misc_db_addr, "select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, &misc_db);
|
||||
dbs_.push_back(misc_db);
|
||||
wstring misc_name = wstring((
|
||||
wchar_t *)(*(DWORD *)(p_contact_addr + DB_MISC_OFFSET + DB_NAME_OFFSET)));
|
||||
dbmap_[misc_name] = misc_db;
|
||||
|
||||
// emotion.db
|
||||
DatabaseInfo emotion_db{0};
|
||||
emotion_db.db_name = (wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_EMOTION_OFFSET + DB_NAME_OFFSET));
|
||||
emotion_db.db_name_len =
|
||||
*(DWORD *)(p_contact_addr + DB_EMOTION_OFFSET + DB_NAME_OFFSET + 0x4);
|
||||
emotion_db.handle = emotion_db_addr;
|
||||
ExecuteSQL(emotion_db_addr,
|
||||
"select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, &emotion_db);
|
||||
dbs_.push_back(emotion_db);
|
||||
wstring emotion_name = wstring((wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_EMOTION_OFFSET + DB_NAME_OFFSET)));
|
||||
dbmap_[emotion_name] = emotion_db;
|
||||
|
||||
// media.db
|
||||
DatabaseInfo media_db{0};
|
||||
media_db.db_name = (wchar_t *)(*(DWORD *)(p_contact_addr + DB_MEDIA_OFFSET +
|
||||
DB_NAME_OFFSET));
|
||||
media_db.db_name_len =
|
||||
*(DWORD *)(p_contact_addr + DB_MEDIA_OFFSET + DB_NAME_OFFSET + 0x4);
|
||||
media_db.handle = media_db_addr;
|
||||
ExecuteSQL(media_db_addr, "select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, &media_db);
|
||||
dbs_.push_back(media_db);
|
||||
wstring media_name = wstring((wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_MEDIA_OFFSET + DB_NAME_OFFSET)));
|
||||
dbmap_[media_name] = media_db;
|
||||
|
||||
// functionMsg.db
|
||||
DatabaseInfo function_msg_db{0};
|
||||
function_msg_db.db_name = (wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET));
|
||||
function_msg_db.db_name_len = *(
|
||||
DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET + 0x4);
|
||||
function_msg_db.handle = function_msg_db_addr;
|
||||
ExecuteSQL(function_msg_db_addr,
|
||||
"select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, &function_msg_db);
|
||||
dbs_.push_back(function_msg_db);
|
||||
wstring function_msg_name = wstring((wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET)));
|
||||
dbmap_[function_msg_name] = function_msg_db;
|
||||
|
||||
if (bizchat_msg_db_addr) {
|
||||
// functionMsg.db maybe null
|
||||
DatabaseInfo bizchat_msg_db{0};
|
||||
bizchat_msg_db.db_name = (wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET));
|
||||
bizchat_msg_db.db_name_len =
|
||||
*(DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET +
|
||||
0x4);
|
||||
bizchat_msg_db.handle = bizchat_msg_db_addr;
|
||||
ExecuteSQL(bizchat_msg_db_addr,
|
||||
"select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, &bizchat_msg_db);
|
||||
dbs_.push_back(bizchat_msg_db);
|
||||
wstring bizchat_msg_name = wstring((wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET)));
|
||||
dbmap_[bizchat_msg_name] = bizchat_msg_db;
|
||||
}
|
||||
// Storage
|
||||
DWORD storage_start = *(DWORD *)(p_contact_addr + STORAGE_START_OFFSET);
|
||||
DWORD storage_end = *(DWORD *)(p_contact_addr + STORAGE_END_OFFSET);
|
||||
|
||||
// do {
|
||||
// DWORD vtable_ptr = *(DWORD *)(storage_start);
|
||||
|
||||
// if(vtable_ptr == base + OP_LOG_STORAGE_VFTABLE){
|
||||
|
||||
// }else if(vtable_ptr == base + CHAT_MSG_STORAGE_VFTABLE){
|
||||
|
||||
// }else if(vtable_ptr == base + CHAT_CR_MSG_STORAGE_VFTABLE){
|
||||
|
||||
// }else if(vtable_ptr == base + SESSION_STORAGE_VFTABLE){
|
||||
|
||||
// }else if(vtable_ptr == base + APP_INFO_STORAGE_VFTABLE){
|
||||
|
||||
// }else if(vtable_ptr == base + HEAD_IMG_STORAGE_VFTABLE){
|
||||
|
||||
// }else if(vtable_ptr == base + HEAD_IMG_URL_STORAGE_VFTABLE){
|
||||
|
||||
// }else if(vtable_ptr == base + BIZ_INFO_STORAGE_VFTABLE){
|
||||
|
||||
// }else if(vtable_ptr == base + TICKET_INFO_STORAGE_VFTABLE){
|
||||
|
||||
// }else if(vtable_ptr == base + CHAT_ROOM_STORAGE_VFTABLE){
|
||||
|
||||
// }else if(vtable_ptr == base + CHAT_ROOM_INFO_STORAGE_VFTABLE){
|
||||
|
||||
// }else if(vtable_ptr == base + MEDIA_STORAGE_VFTABLE){
|
||||
|
||||
// }else if(vtable_ptr == base + NAME_2_ID_STORAGE_VFTABLE){
|
||||
|
||||
// }else if(vtable_ptr == base + EMOTION_PACKAGE_STORAGE_VFTABLE){
|
||||
|
||||
// }else if(vtable_ptr == base + EMOTION_STORAGE_VFTABLE){
|
||||
|
||||
// }else if(vtable_ptr == base + BUFINFO_STORAGE_VFTABLE){
|
||||
|
||||
// }else if(vtable_ptr == base + CUSTOM_EMOTION_STORAGE_VFTABLE){
|
||||
|
||||
// }else if(vtable_ptr == base + DEL_SESSIONINFO_STORAGE_VFTABLE){
|
||||
|
||||
// }else if(vtable_ptr == base + FUNCTION_MSG_STORAGE_VFTABLE){
|
||||
|
||||
// }else if(vtable_ptr == base + FUNCTION_MSG_TASK_STORAGE_VFTABLE){
|
||||
|
||||
// }else if(vtable_ptr == base + REVOKE_MSG_STORAGE_VFTABLE){
|
||||
|
||||
// }
|
||||
|
||||
// storage_start = storage_start + 0x4;
|
||||
// } while (storage_start != storage_end);
|
||||
|
||||
DWORD multi_db_mgr_addr = base_addr_ + MULTI_DB_MSG_MGR_OFFSET;
|
||||
DWORD public_msg_mgr_addr = base_addr_ + PUBLIC_MSG_MGR_OFFSET;
|
||||
DWORD favorite_storage_mgr_addr = base_addr_ + FAVORITE_STORAGE_MGR_OFFSET;
|
||||
DWORD fts_favorite_mgr_addr = base_addr_ + FTS_FAVORITE_MGR_OFFSET;
|
||||
|
||||
// MsgX.db
|
||||
DWORD wrap_ptr = *(DWORD *)(multi_db_mgr_addr);
|
||||
DWORD db_num = *(DWORD *)(wrap_ptr + 0x30);
|
||||
DWORD current_db_num = *(DWORD *)(wrap_ptr + 0x38);
|
||||
DWORD begin_ptr = *(DWORD *)(wrap_ptr + 0x2c);
|
||||
|
||||
for (unsigned int i = 0; i < current_db_num; i++) {
|
||||
DWORD next_addr = begin_ptr + i * 0x4;
|
||||
DWORD db_addr = *(DWORD *)next_addr;
|
||||
if (db_addr) {
|
||||
DWORD msg0_db_addr = *(DWORD *)(db_addr + 0x60);
|
||||
DatabaseInfo msg0_db{0};
|
||||
msg0_db.db_name = (wchar_t *)(*(DWORD *)(db_addr));
|
||||
msg0_db.db_name_len = *(DWORD *)(db_addr + 0x4);
|
||||
msg0_db.handle = msg0_db_addr;
|
||||
msg0_db.extrainfo = *(DWORD *)(*(DWORD *)(db_addr + 0x18) + 0x144);
|
||||
ExecuteSQL(msg0_db_addr,
|
||||
"select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, &msg0_db);
|
||||
dbs_.push_back(msg0_db);
|
||||
wstring msg_db_name = wstring((wchar_t *)(*(DWORD *)(db_addr)));
|
||||
dbmap_[msg_db_name] = msg0_db;
|
||||
|
||||
// BufInfoStorage
|
||||
DWORD buf_info_addr = *(DWORD *)(db_addr + 0x14);
|
||||
|
||||
DWORD buf_info_handle = *(DWORD *)(buf_info_addr + 0x38);
|
||||
DatabaseInfo media_msg0_db{0};
|
||||
media_msg0_db.db_name = (wchar_t *)(*(DWORD *)(buf_info_addr + 0x4C));
|
||||
media_msg0_db.db_name_len = *(DWORD *)(buf_info_addr + 0x50);
|
||||
media_msg0_db.handle = buf_info_handle;
|
||||
ExecuteSQL(buf_info_handle,
|
||||
"select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, &media_msg0_db);
|
||||
dbs_.push_back(media_msg0_db);
|
||||
wstring media_msg_db_name =
|
||||
wstring((wchar_t *)(*(DWORD *)(buf_info_addr + 0x4C)));
|
||||
dbmap_[media_msg_db_name] = media_msg0_db;
|
||||
}
|
||||
}
|
||||
|
||||
// publicMsg.db
|
||||
DWORD public_msg_ptr = *(DWORD *)(*(DWORD *)(public_msg_mgr_addr) + 0x8);
|
||||
if (public_msg_ptr) {
|
||||
DWORD public_msg_db_addr = *(DWORD *)(public_msg_ptr + 0x38);
|
||||
DatabaseInfo public_msg_db{0};
|
||||
public_msg_db.db_name = (wchar_t *)(*(DWORD *)(public_msg_ptr + 0x4C));
|
||||
public_msg_db.db_name_len = *(DWORD *)(public_msg_ptr + 0x50);
|
||||
public_msg_db.handle = public_msg_db_addr;
|
||||
ExecuteSQL(public_msg_db_addr,
|
||||
"select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, &public_msg_db);
|
||||
dbs_.push_back(public_msg_db);
|
||||
wstring public_msg_db_name =
|
||||
wstring((wchar_t *)(*(DWORD *)(public_msg_ptr + 0x4C)));
|
||||
dbmap_[public_msg_db_name] = public_msg_db;
|
||||
}
|
||||
|
||||
// Favorite.db
|
||||
DWORD favItems_ptr =
|
||||
*(DWORD *)(*(DWORD *)(*(DWORD *)(favorite_storage_mgr_addr) + 0x8) + 0x4);
|
||||
if (favItems_ptr) {
|
||||
DWORD favorite_db_addr = *(DWORD *)(favItems_ptr + 0x38);
|
||||
DatabaseInfo favorite_db{0};
|
||||
favorite_db.db_name = (wchar_t *)(*(DWORD *)(favItems_ptr + 0x4C));
|
||||
favorite_db.db_name_len = *(DWORD *)(favItems_ptr + 0x50);
|
||||
favorite_db.handle = favorite_db_addr;
|
||||
ExecuteSQL(favorite_db_addr,
|
||||
"select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, &favorite_db);
|
||||
dbs_.push_back(favorite_db);
|
||||
wstring public_msg_db_name =
|
||||
wstring((wchar_t *)(*(DWORD *)(favItems_ptr + 0x4C)));
|
||||
dbmap_[public_msg_db_name] = favorite_db;
|
||||
}
|
||||
|
||||
DatabaseInfo db_end = {0};
|
||||
dbs_.push_back(db_end);
|
||||
#ifdef _DEBUG
|
||||
for (unsigned int i = 0; i < dbs_.size() - 1; i++) {
|
||||
// LOG(INFO) << "dbname =" << dbs_[i].db_name;
|
||||
// LOG(INFO) << "handle =" << dbs_[i].handle;
|
||||
// LOG(INFO) << "table_count =" << dbs_[i].tables.size();
|
||||
}
|
||||
#endif
|
||||
vector<void *> ret_array;
|
||||
for (unsigned int i = 0; i < dbs_.size() - 1; i++)
|
||||
ret_array.push_back(&dbs_[i]);
|
||||
return ret_array;
|
||||
}
|
||||
|
||||
DWORD DB::GetDbHandleByDbName(wchar_t *dbname) {
|
||||
if (dbmap_.size() == 0) {
|
||||
GetDbHandles();
|
||||
}
|
||||
if (dbmap_.find(dbname) != dbmap_.end()) {
|
||||
return dbmap_[dbname].handle;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int DB::GetLocalIdByMsgId(ULONG64 msgid, int &dbIndex) {
|
||||
char sql[260] = {0};
|
||||
sprintf_s(sql, "select localId 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) {
|
||||
SPDLOG_INFO("MSG db handle is null");
|
||||
return 0;
|
||||
}
|
||||
vector<vector<string>> result;
|
||||
int ret = Select(handle, (const char *)sql, result);
|
||||
if (result.size() == 0) continue;
|
||||
dbIndex = dbmap_[dbname].extrainfo;
|
||||
return stoi(result[1][0]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
vector<string> DB::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) {
|
||||
// LOG(INFO) << "MSG db handle is null";
|
||||
return {};
|
||||
}
|
||||
vector<vector<string>> result;
|
||||
int ret = Select(handle, (const char *)sql, result);
|
||||
if (result.size() == 0) continue;
|
||||
return result[1];
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string DB::GetVoiceBuffByMsgId(ULONG64 msgid) {
|
||||
char sql[260] = {0};
|
||||
sprintf_s(sql, "SELECT Buf from Media WHERE Reserved0=%llu;", msgid);
|
||||
wchar_t dbname[20] = {0};
|
||||
for (int i = 0;; i++) {
|
||||
swprintf_s(dbname, L"MediaMSG%d.db", i);
|
||||
DWORD handle = GetDbHandleByDbName(dbname);
|
||||
if (handle == 0) {
|
||||
// LOG(INFO) << "Media db handle is null";
|
||||
return "";
|
||||
}
|
||||
vector<vector<string>> result;
|
||||
int ret = Select(handle, (const char *)sql, result);
|
||||
if (result.size() == 0) continue;
|
||||
return result[1][0];
|
||||
}
|
||||
return "";
|
||||
}
|
||||
} // namespace wxhelper
|
||||
@@ -0,0 +1,38 @@
|
||||
#ifndef WXHELPER_DB_H_
|
||||
#define WXHELPER_DB_H_
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base_mgr.h"
|
||||
#include "wechat_function.h"
|
||||
#include "windows.h"
|
||||
#include "singleton.h"
|
||||
namespace wxhelper {
|
||||
class DB :public Singleton<DB>{
|
||||
public:
|
||||
void init(DWORD base);
|
||||
int ExecuteSQL(DWORD db, const char *sql, DWORD callback, void *data);
|
||||
|
||||
int Select(DWORD db_hanle, const char *sql,
|
||||
std::vector<std::vector<std::string>> &query_result);
|
||||
|
||||
std::vector<void *> GetDbHandles();
|
||||
DWORD GetDbHandleByDbName(wchar_t *dbname);
|
||||
unsigned int GetLocalIdByMsgId(ULONG64 msgid, int &dbIndex);
|
||||
std::vector<std::string> GetChatMsgByMsgId(ULONG64 msgid);
|
||||
|
||||
std::string GetVoiceBuffByMsgId(ULONG64 msgid);
|
||||
|
||||
private:
|
||||
int SelectDataInner(DWORD db, const char *sql,
|
||||
std::vector<std::vector<SqlResult>> &data);
|
||||
|
||||
private:
|
||||
std::map<std::wstring, DatabaseInfo> dbmap_;
|
||||
std::vector<DatabaseInfo> dbs_;
|
||||
DWORD base_addr_;
|
||||
};
|
||||
|
||||
} // namespace wxhelper
|
||||
|
||||
#endif
|
||||
@@ -1,155 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "db_operation.h"
|
||||
|
||||
#include "base64.h"
|
||||
#include "common.h"
|
||||
#include "new_sqlite3.h"
|
||||
using namespace std;
|
||||
|
||||
/// @brief free data
|
||||
void FreeResult(vector<vector<SqlResult>> &data) {
|
||||
if (data.size() == 0) {
|
||||
return;
|
||||
}
|
||||
for (unsigned int i = 0; i < data.size(); i++) {
|
||||
for (unsigned j = 0; j < data[i].size(); j++) {
|
||||
SqlResult *sr = (SqlResult *)&data[i][j];
|
||||
if (sr->column_name) {
|
||||
delete[] sr->column_name;
|
||||
sr->column_name = NULL;
|
||||
}
|
||||
if (sr->content) {
|
||||
delete[] sr->content;
|
||||
sr->content = NULL;
|
||||
}
|
||||
}
|
||||
data[i].clear();
|
||||
}
|
||||
data.clear();
|
||||
}
|
||||
|
||||
int SelectDataInner(DWORD db, const char *sql,
|
||||
vector<vector<SqlResult>> &data) {
|
||||
DWORD wxBaseAddress = GetWeChatWinBase();
|
||||
Sqlite3_prepare p_Sqlite3_prepare =
|
||||
(Sqlite3_prepare)(wxBaseAddress + SQLITE3_PREPARE_OFFSET);
|
||||
Sqlite3_step p_Sqlite3_step =
|
||||
(Sqlite3_step)(wxBaseAddress + SQLITE3_STEP_OFFSET);
|
||||
Sqlite3_column_count p_Sqlite3_column_count =
|
||||
(Sqlite3_column_count)(wxBaseAddress + SQLITE3_COLUMN_COUNT_OFFSET);
|
||||
Sqlite3_column_name p_Sqlite3_column_name =
|
||||
(Sqlite3_column_name)(wxBaseAddress + SQLITE3_COLUMN_NAME_OFFSET);
|
||||
Sqlite3_column_type p_Sqlite3_column_type =
|
||||
(Sqlite3_column_type)(wxBaseAddress + SQLITE3_COLUMN_TYPE_OFFSET);
|
||||
Sqlite3_column_blob p_Sqlite3_column_blob =
|
||||
(Sqlite3_column_blob)(wxBaseAddress + SQLITE3_COLUMN_BLOB_OFFSET);
|
||||
Sqlite3_column_bytes p_Sqlite3_column_bytes =
|
||||
(Sqlite3_column_bytes)(wxBaseAddress + SQLITE3_COLUMN_BYTES_OFFSET);
|
||||
Sqlite3_finalize p_Sqlite3_finalize =
|
||||
(Sqlite3_finalize)(wxBaseAddress + SQLITE3_FINALIZE_OFFSET);
|
||||
DWORD *stmt;
|
||||
int rc = p_Sqlite3_prepare(db, sql, -1, &stmt, 0);
|
||||
if (rc != SQLITE_OK) return NULL;
|
||||
while (p_Sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
int col_count = p_Sqlite3_column_count(stmt);
|
||||
vector<SqlResult> tempStruct;
|
||||
for (int i = 0; i < col_count; i++) {
|
||||
SqlResult temp = {0};
|
||||
const char *ColName = p_Sqlite3_column_name(stmt, i);
|
||||
int nType = p_Sqlite3_column_type(stmt, i);
|
||||
const void *pReadBlobData = p_Sqlite3_column_blob(stmt, i);
|
||||
int nLength = p_Sqlite3_column_bytes(stmt, i);
|
||||
temp.column_name = new char[strlen(ColName) + 1];
|
||||
memcpy(temp.column_name, ColName, strlen(ColName) + 1);
|
||||
temp.column_name_len = strlen(ColName);
|
||||
temp.content_len = nLength;
|
||||
switch (nType) {
|
||||
case SQLITE_BLOB: {
|
||||
temp.content = new char[nLength];
|
||||
memcpy(temp.content, pReadBlobData, nLength);
|
||||
temp.is_blob = true;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (nLength != 0) {
|
||||
temp.content = new char[nLength + 1];
|
||||
memcpy(temp.content, pReadBlobData, nLength + 1);
|
||||
} else {
|
||||
temp.content = new char[2];
|
||||
ZeroMemory(temp.content, 2);
|
||||
}
|
||||
temp.is_blob = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
tempStruct.push_back(temp);
|
||||
}
|
||||
data.push_back(tempStruct);
|
||||
}
|
||||
p_Sqlite3_finalize(stmt);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Select(DWORD db_hanle, const char *sql,
|
||||
vector<vector<string>> &query_result) {
|
||||
vector<vector<SqlResult>> data;
|
||||
int status = SelectDataInner(db_hanle, sql, data);
|
||||
if (status == 0) {
|
||||
return 0;
|
||||
}
|
||||
vector<string> index;
|
||||
for (size_t i = 0; i < data[0].size(); i++)
|
||||
index.push_back(data[0][i].column_name);
|
||||
query_result.push_back(index);
|
||||
for (auto it : data) {
|
||||
vector<string> item;
|
||||
for (size_t i = 0; i < it.size(); i++) {
|
||||
if (!it[i].is_blob) {
|
||||
string content(it[i].content);
|
||||
item.push_back(content);
|
||||
} else {
|
||||
string b64_str =
|
||||
base64_encode((BYTE *)it[i].content, it[i].content_len);
|
||||
item.push_back(b64_str);
|
||||
}
|
||||
}
|
||||
query_result.push_back(item);
|
||||
}
|
||||
FreeResult(data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SelectDbInfo(void *data, int argc, char **argv, char **name) {
|
||||
vector<SqlResult> result;
|
||||
for (int i = 0; i < argc; i++) {
|
||||
SqlResult temp = {0};
|
||||
temp.column_name = new char[strlen(name[i]) + 1];
|
||||
memcpy(temp.column_name, name[i], strlen(name[i]) + 1);
|
||||
temp.column_name_len = strlen(name[i]);
|
||||
if (argv[i]) {
|
||||
temp.content = new char[strlen(argv[i]) + 1];
|
||||
memcpy(temp.content, argv[i], strlen(argv[i]) + 1);
|
||||
temp.content_len = strlen(argv[i]);
|
||||
} else {
|
||||
temp.content = new char[2];
|
||||
ZeroMemory(temp.content, 2);
|
||||
temp.content_len = 0;
|
||||
}
|
||||
result.push_back(temp);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// @brief sqlite3_exec
|
||||
/// @param db
|
||||
/// @param sql
|
||||
/// @param callback
|
||||
/// @param data
|
||||
/// @return
|
||||
int ExecuteSQL(DWORD db, const char *sql, DWORD callback, void *data) {
|
||||
DWORD base = GetWeChatWinBase();
|
||||
DWORD sqlite3_exec_addr = base + SQLITE3_EXEC_OFFSET;
|
||||
Sqlite3_exec fn_sqlite3_exec = (Sqlite3_exec)sqlite3_exec_addr;
|
||||
int status = fn_sqlite3_exec(db, sql, (Sqlite3_callback)callback, data, 0);
|
||||
return status;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
#ifndef DB_OPERATION_H_
|
||||
#define DB_OPERATION_H_
|
||||
#include <windows.h>
|
||||
#include <vector>
|
||||
struct SqlResult {
|
||||
char *column_name;
|
||||
DWORD column_name_len;
|
||||
char *content;
|
||||
DWORD content_len;
|
||||
BOOL is_blob;
|
||||
};
|
||||
/// @brief exec sql
|
||||
/// @param db opened db
|
||||
/// @param sql sql
|
||||
/// @param callback callback func
|
||||
/// @param data data
|
||||
/// @return
|
||||
int ExecuteSQL(DWORD db, const char *sql, DWORD callback, void *data);
|
||||
|
||||
int Select(DWORD db_hanle, const char *sql,std::vector<std::vector<std::string>> &query_result);
|
||||
|
||||
#endif
|
||||
+13
-4
@@ -1,12 +1,20 @@
|
||||
#include "pch.h"
|
||||
#include "api.h"
|
||||
#include "common.h"
|
||||
#include "pch.h"
|
||||
#include "hide_module.h"
|
||||
#include "global_context.h"
|
||||
|
||||
|
||||
using namespace wxhelper;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved) {
|
||||
switch (ul_reason_for_call) {
|
||||
case DLL_PROCESS_ATTACH: {
|
||||
http_start(19088);
|
||||
DisableThreadLibraryCalls(hModule);
|
||||
GlobalContext::GetInstance().initialize(hModule);
|
||||
break;
|
||||
}
|
||||
case DLL_THREAD_ATTACH: {
|
||||
@@ -16,6 +24,7 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call,
|
||||
break;
|
||||
}
|
||||
case DLL_PROCESS_DETACH: {
|
||||
GlobalContext::GetInstance().finally();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "forward.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "get_db_handle.h"
|
||||
#include "wechat_data.h"
|
||||
#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;
|
||||
|
||||
int db_index = 0;
|
||||
int localid = GetLocalIdByMsgId(msgid, db_index);
|
||||
|
||||
if (localid == 0) return 0;
|
||||
WeChatString to_user(wxid);
|
||||
DWORD base = GetWeChatWinBase();
|
||||
DWORD forward_msg_addr = base + WX_FORWARD_MSG_OFFSET;
|
||||
DWORD init_chat_msg_addr = base + WX_INIT_CHAT_MSG_OFFSET;
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
MOV EDX, DWORD PTR [db_index]
|
||||
PUSH EDX
|
||||
MOV EAX, DWORD PTR [localid]
|
||||
PUSH EAX
|
||||
SUB ESP,0x14
|
||||
MOV ECX,ESP
|
||||
LEA ESI,to_user
|
||||
PUSH ESI
|
||||
CALL init_chat_msg_addr
|
||||
CALL forward_msg_addr
|
||||
MOVZX EAX,AL
|
||||
MOV success,EAX
|
||||
ADD ESP,0x1c
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
return success;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#ifndef FORWARD_H_
|
||||
#define FORWARD_H_
|
||||
|
||||
int ForwardMsg(wchar_t *wxid, unsigned long long msgid);
|
||||
#endif
|
||||
@@ -1,318 +0,0 @@
|
||||
#include "get_db_handle.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "db_operation.h"
|
||||
#include "new_sqlite3.h"
|
||||
#include "pch.h"
|
||||
#include "wechat_data.h"
|
||||
#define CONTACT_G_PINSTANCE_OFFSET 0x2e2d628
|
||||
#define DB_MICRO_MSG_OFFSET 0x68
|
||||
#define DB_CHAT_MSG_OFFSET 0x1C0
|
||||
#define DB_MISC_OFFSET 0x3D8
|
||||
#define DB_EMOTION_OFFSET 0x558
|
||||
#define DB_MEDIA_OFFSET 0x9B8
|
||||
#define DB_BIZCHAT_MSG_OFFSET 0x1120
|
||||
#define DB_FUNCTION_MSG_OFFSET 0x11B0
|
||||
#define DB_NAME_OFFSET 0x14
|
||||
|
||||
#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;
|
||||
std::vector<DatabaseInfo> dbs;
|
||||
|
||||
int GetDbInfo(void *data, int argc, char **argv, char **name) {
|
||||
DatabaseInfo *pdata = (DatabaseInfo *)data;
|
||||
TableInfo tb = {0};
|
||||
if (argv[1]) {
|
||||
tb.name = new char[strlen(argv[1]) + 1];
|
||||
memcpy(tb.name, argv[1], strlen(argv[1]) + 1);
|
||||
} else {
|
||||
tb.name = (char *)"NULL";
|
||||
}
|
||||
if (argv[2]) {
|
||||
tb.table_name = new char[strlen(argv[2]) + 1];
|
||||
memcpy(tb.table_name, argv[2], strlen(argv[2]) + 1);
|
||||
} else {
|
||||
tb.table_name = (char *)"NULL";
|
||||
}
|
||||
if (argv[3]) {
|
||||
tb.rootpage = new char[strlen(argv[3]) + 1];
|
||||
memcpy(tb.rootpage, argv[3], strlen(argv[3]) + 1);
|
||||
} else {
|
||||
tb.rootpage = (char *)"NULL";
|
||||
}
|
||||
if (argv[4]) {
|
||||
tb.sql = new char[strlen(argv[4]) + 1];
|
||||
memcpy(tb.sql, argv[4], strlen(argv[4]) + 1);
|
||||
} else {
|
||||
tb.sql = (char *)"NULL";
|
||||
}
|
||||
tb.name_len = strlen(tb.name);
|
||||
tb.table_name_len = strlen(tb.table_name);
|
||||
tb.sql_len = strlen(tb.sql);
|
||||
tb.rootpage_len = strlen(tb.rootpage);
|
||||
pdata->tables.push_back(tb);
|
||||
pdata->count = pdata->tables.size();
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<void *> GetDbHandles() {
|
||||
dbs.clear();
|
||||
dbmap.clear();
|
||||
DWORD base = GetWeChatWinBase();
|
||||
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);
|
||||
DWORD emotion_db_addr = *(DWORD *)(p_contact_addr + DB_EMOTION_OFFSET);
|
||||
DWORD media_db_addr = *(DWORD *)(p_contact_addr + DB_MEDIA_OFFSET);
|
||||
DWORD bizchat_msg_db_addr =
|
||||
*(DWORD *)(p_contact_addr + DB_BIZCHAT_MSG_OFFSET);
|
||||
DWORD function_msg_db_addr =
|
||||
*(DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET);
|
||||
|
||||
// microMsg.db
|
||||
DatabaseInfo micro_msg_db{0};
|
||||
micro_msg_db.db_name = (wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_MICRO_MSG_OFFSET + DB_NAME_OFFSET));
|
||||
micro_msg_db.db_name_len =
|
||||
*(DWORD *)(p_contact_addr + DB_MICRO_MSG_OFFSET + DB_NAME_OFFSET + 0x4);
|
||||
micro_msg_db.handle = micro_msg_db_addr;
|
||||
ExecuteSQL(micro_msg_db_addr,
|
||||
"select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, µ_msg_db);
|
||||
dbs.push_back(micro_msg_db);
|
||||
wstring micro_msg_name = wstring((wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_MICRO_MSG_OFFSET + DB_NAME_OFFSET)));
|
||||
dbmap[micro_msg_name] = micro_msg_db;
|
||||
|
||||
// chatMsg.db
|
||||
DatabaseInfo chat_msg_db{0};
|
||||
chat_msg_db.db_name = (wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_CHAT_MSG_OFFSET + DB_NAME_OFFSET));
|
||||
chat_msg_db.db_name_len =
|
||||
*(DWORD *)(p_contact_addr + DB_CHAT_MSG_OFFSET + DB_NAME_OFFSET + 0x4);
|
||||
chat_msg_db.handle = chat_msg_db_addr;
|
||||
ExecuteSQL(chat_msg_db_addr,
|
||||
"select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, &chat_msg_db);
|
||||
dbs.push_back(chat_msg_db);
|
||||
wstring chat_msg_name = wstring((wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_CHAT_MSG_OFFSET + DB_NAME_OFFSET)));
|
||||
dbmap[chat_msg_name] = chat_msg_db;
|
||||
|
||||
// misc.db
|
||||
DatabaseInfo misc_db{0};
|
||||
misc_db.db_name =
|
||||
(wchar_t *)(*(DWORD *)(p_contact_addr + DB_MISC_OFFSET + DB_NAME_OFFSET));
|
||||
misc_db.db_name_len =
|
||||
*(DWORD *)(p_contact_addr + DB_MISC_OFFSET + DB_NAME_OFFSET + 0x4);
|
||||
misc_db.handle = misc_db_addr;
|
||||
ExecuteSQL(misc_db_addr, "select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, &misc_db);
|
||||
dbs.push_back(misc_db);
|
||||
wstring misc_name = wstring((
|
||||
wchar_t *)(*(DWORD *)(p_contact_addr + DB_MISC_OFFSET + DB_NAME_OFFSET)));
|
||||
dbmap[misc_name] = misc_db;
|
||||
|
||||
// emotion.db
|
||||
DatabaseInfo emotion_db{0};
|
||||
emotion_db.db_name = (wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_EMOTION_OFFSET + DB_NAME_OFFSET));
|
||||
emotion_db.db_name_len =
|
||||
*(DWORD *)(p_contact_addr + DB_EMOTION_OFFSET + DB_NAME_OFFSET + 0x4);
|
||||
emotion_db.handle = emotion_db_addr;
|
||||
ExecuteSQL(emotion_db_addr,
|
||||
"select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, &emotion_db);
|
||||
dbs.push_back(emotion_db);
|
||||
wstring emotion_name = wstring((wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_EMOTION_OFFSET + DB_NAME_OFFSET)));
|
||||
dbmap[emotion_name] = emotion_db;
|
||||
|
||||
// media.db
|
||||
DatabaseInfo media_db{0};
|
||||
media_db.db_name = (wchar_t *)(*(DWORD *)(p_contact_addr + DB_MEDIA_OFFSET +
|
||||
DB_NAME_OFFSET));
|
||||
media_db.db_name_len =
|
||||
*(DWORD *)(p_contact_addr + DB_MEDIA_OFFSET + DB_NAME_OFFSET + 0x4);
|
||||
media_db.handle = media_db_addr;
|
||||
ExecuteSQL(media_db_addr, "select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, &media_db);
|
||||
dbs.push_back(media_db);
|
||||
wstring media_name = wstring((wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_MEDIA_OFFSET + DB_NAME_OFFSET)));
|
||||
dbmap[media_name] = media_db;
|
||||
|
||||
// functionMsg.db
|
||||
DatabaseInfo function_msg_db{0};
|
||||
function_msg_db.db_name = (wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET));
|
||||
function_msg_db.db_name_len = *(
|
||||
DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET + 0x4);
|
||||
function_msg_db.handle = function_msg_db_addr;
|
||||
ExecuteSQL(function_msg_db_addr,
|
||||
"select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, &function_msg_db);
|
||||
dbs.push_back(function_msg_db);
|
||||
wstring function_msg_name = wstring((wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET)));
|
||||
dbmap[function_msg_name] = function_msg_db;
|
||||
|
||||
if (bizchat_msg_db_addr) {
|
||||
// functionMsg.db maybe null
|
||||
DatabaseInfo bizchat_msg_db{0};
|
||||
bizchat_msg_db.db_name = (wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET));
|
||||
bizchat_msg_db.db_name_len =
|
||||
*(DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET +
|
||||
0x4);
|
||||
bizchat_msg_db.handle = bizchat_msg_db_addr;
|
||||
ExecuteSQL(bizchat_msg_db_addr,
|
||||
"select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, &bizchat_msg_db);
|
||||
dbs.push_back(bizchat_msg_db);
|
||||
wstring bizchat_msg_name = wstring((wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET)));
|
||||
dbmap[bizchat_msg_name] = bizchat_msg_db;
|
||||
}
|
||||
DWORD multi_db_mgr_addr = base + MULTI_DB_MSG_MGR_OFFSET;
|
||||
DWORD public_msg_mgr_addr = base + PUBLIC_MSG_MGR_OFFSET;
|
||||
DWORD favorite_storage_mgr_addr = base + FAVORITE_STORAGE_MGR_OFFSET;
|
||||
DWORD fts_favorite_mgr_addr = base + FTS_FAVORITE_MGR_OFFSET;
|
||||
|
||||
// MsgX.db
|
||||
DWORD wrap_ptr = *(DWORD *)(multi_db_mgr_addr);
|
||||
DWORD db_num = *(DWORD *)(wrap_ptr+0x30);
|
||||
DWORD current_db_num = *(DWORD *)(wrap_ptr+0x38);
|
||||
DWORD begin_ptr = *(DWORD *)(wrap_ptr + 0x2c);
|
||||
|
||||
for (unsigned int i = 0; i < current_db_num; i++) {
|
||||
DWORD next_addr = begin_ptr + i * 0x4;
|
||||
DWORD db_addr = *(DWORD *) next_addr;
|
||||
if (db_addr) {
|
||||
DWORD msg0_db_addr = *(DWORD *)(db_addr + 0x60);
|
||||
DatabaseInfo msg0_db{0};
|
||||
msg0_db.db_name = (wchar_t *)(*(DWORD *)(db_addr));
|
||||
msg0_db.db_name_len = *(DWORD *)(db_addr + 0x4);
|
||||
msg0_db.handle = msg0_db_addr;
|
||||
msg0_db.extrainfo = *(DWORD *) (*(DWORD *)(db_addr + 0x18) +0x144);
|
||||
ExecuteSQL(
|
||||
msg0_db_addr, "select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, &msg0_db);
|
||||
dbs.push_back(msg0_db);
|
||||
wstring msg_db_name = wstring((wchar_t *)(*(DWORD *)(db_addr)));
|
||||
dbmap[msg_db_name] = msg0_db;
|
||||
}
|
||||
}
|
||||
|
||||
// publicMsg.db
|
||||
DWORD public_msg_ptr = *(DWORD *) (*(DWORD *)(public_msg_mgr_addr) + 0x8);
|
||||
if (public_msg_ptr) {
|
||||
DWORD public_msg_db_addr = *(DWORD *)(public_msg_ptr + 0x38);
|
||||
DatabaseInfo public_msg_db{0};
|
||||
public_msg_db.db_name = (wchar_t *)(*(DWORD *)(public_msg_ptr + 0x4C));
|
||||
public_msg_db.db_name_len =*(DWORD *)(public_msg_ptr + 0x50);
|
||||
public_msg_db.handle = public_msg_db_addr;
|
||||
ExecuteSQL(public_msg_db_addr,
|
||||
"select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, &public_msg_db);
|
||||
dbs.push_back(public_msg_db);
|
||||
wstring public_msg_db_name =wstring((wchar_t *)(*(DWORD *)(public_msg_ptr + 0x4C)));
|
||||
dbmap[public_msg_db_name] = public_msg_db;
|
||||
}
|
||||
|
||||
// Favorite.db
|
||||
DWORD favItems_ptr = *(DWORD *)(*(DWORD *)(favorite_storage_mgr_addr) + 0x8);
|
||||
if (favItems_ptr) {
|
||||
DWORD favorite_db_addr = *(DWORD *)(favItems_ptr + 0x38);
|
||||
DatabaseInfo favorite_db{0};
|
||||
favorite_db.db_name =(wchar_t *)(*(DWORD *)(favItems_ptr + 0x4C));
|
||||
favorite_db.db_name_len = *(DWORD *)(favItems_ptr + 0x50);
|
||||
favorite_db.handle = favorite_db_addr;
|
||||
ExecuteSQL(favorite_db_addr,
|
||||
"select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, &favorite_db);
|
||||
dbs.push_back(favorite_db);
|
||||
wstring public_msg_db_name =wstring((wchar_t *)(*(DWORD *)(favItems_ptr + 0x4C)));
|
||||
dbmap[public_msg_db_name] = favorite_db;
|
||||
}
|
||||
|
||||
DatabaseInfo db_end = {0};
|
||||
dbs.push_back(db_end);
|
||||
#ifdef _DEBUG
|
||||
for (unsigned int i = 0; i < dbs.size() - 1; i++) {
|
||||
printf("dbname = %ws,handle = 0x%08X,table_count:%d\n", dbs[i].db_name,
|
||||
dbs[i].handle, dbs[i].tables.size());
|
||||
for (unsigned int j = 0; j < dbs[i].tables.size(); j++) {
|
||||
cout << "name = " << dbs[i].tables[j].name << endl;
|
||||
cout << "tbl_name = " << dbs[i].tables[j].table_name << endl;
|
||||
cout << "rootpage = " << dbs[i].tables[j].rootpage << endl;
|
||||
cout << "sql = " << dbs[i].tables[j].sql << endl;
|
||||
cout << endl;
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
#endif
|
||||
vector<void *> ret_array;
|
||||
for (unsigned int i = 0; i < dbs.size() - 1; i++)
|
||||
ret_array.push_back(&dbs[i]);
|
||||
return ret_array;
|
||||
}
|
||||
|
||||
DWORD GetDbHandleByDbName(wchar_t *dbname) {
|
||||
if (dbmap.size() == 0) {
|
||||
GetDbHandles();
|
||||
}
|
||||
if (dbmap.find(dbname) != dbmap.end()) {
|
||||
return dbmap[dbname].handle;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int GetLocalIdByMsgId(ULONG64 msgid, int &dbIndex) {
|
||||
char sql[260] = {0};
|
||||
sprintf_s(sql, "select localId 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);
|
||||
#ifdef _DEBUG
|
||||
cout <<" handle =" <<handle<<endl;
|
||||
#endif
|
||||
if (handle == 0) return 0;
|
||||
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;
|
||||
dbIndex = dbmap[dbname].extrainfo;
|
||||
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 {};
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
#ifndef GET_DB_HANDLE_H_
|
||||
#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
|
||||
@@ -0,0 +1,40 @@
|
||||
#include "pch.h"
|
||||
#include "global_context.h"
|
||||
#include "http_server.h"
|
||||
#include "hooks.h"
|
||||
#include "thread_pool.h"
|
||||
|
||||
|
||||
namespace wxhelper {
|
||||
|
||||
void GlobalContext::initialize(HMODULE module) {
|
||||
module_ = module;
|
||||
DWORD base = Utils::GetWeChatWinBase();
|
||||
config.emplace();
|
||||
config->Initialize();
|
||||
log.emplace();
|
||||
log->Initialize();
|
||||
hide_module.emplace();
|
||||
#ifndef _DEBUG
|
||||
hide_module->Hide(module_);
|
||||
#endif
|
||||
|
||||
HttpServer::GetInstance().Init(config->GetPort());
|
||||
HttpServer::GetInstance().HttpStart();
|
||||
DB::GetInstance().init(base);
|
||||
contact_mgr.emplace(ContactMgr{base});
|
||||
misc_mgr.emplace(MiscMgr{base});
|
||||
send_mgr.emplace(SendMessageMgr{base});
|
||||
account_mgr.emplace(AccountMgr{base});
|
||||
chat_room_mgr.emplace(ChatRoomMgr{base});
|
||||
sns_mgr.emplace(SNSMgr{base});
|
||||
ThreadPool::GetInstance().Create(1,512);
|
||||
}
|
||||
|
||||
void GlobalContext::finally() {
|
||||
HttpServer::GetInstance().HttpClose();
|
||||
hooks::UnHookLog();
|
||||
hooks::UnHookRecvMsg();
|
||||
hooks::UnHookSearchContact();
|
||||
}
|
||||
} // namespace wxhelper
|
||||
@@ -0,0 +1,43 @@
|
||||
#ifndef GLOBAL_CONTEXT_H_
|
||||
#define GLOBAL_CONTEXT_H_
|
||||
#include "account_mgr.h"
|
||||
#include "config.h"
|
||||
#include "contact_mgr.h"
|
||||
#include "db.h"
|
||||
#include "hide_module.h"
|
||||
#include "http_server.h"
|
||||
#include "log.h"
|
||||
#include "misc_mgr.h"
|
||||
#include "send_message_mgr.h"
|
||||
#include "chat_room_mgr.h"
|
||||
#include "sns_mgr.h"
|
||||
#include "singleton.h"
|
||||
|
||||
namespace wxhelper {
|
||||
|
||||
enum class GlobalContextState { NOT_INITIALIZED, INITIALIZING, INITIALIZED };
|
||||
|
||||
class GlobalContext :public Singleton<GlobalContext>{
|
||||
public:
|
||||
void initialize(HMODULE module);
|
||||
void finally();
|
||||
|
||||
public:
|
||||
std::optional<Config> config;
|
||||
std::optional<HideModule> hide_module;
|
||||
std::optional<Log> log;
|
||||
std::optional<ContactMgr> contact_mgr;
|
||||
std::optional<MiscMgr> misc_mgr;
|
||||
std::optional<SendMessageMgr> send_mgr;
|
||||
std::optional<AccountMgr> account_mgr;
|
||||
std::optional<ChatRoomMgr> chat_room_mgr;
|
||||
std::optional<SNSMgr> sns_mgr;
|
||||
|
||||
GlobalContextState state = GlobalContextState::INITIALIZED;
|
||||
|
||||
private:
|
||||
HMODULE module_;
|
||||
};
|
||||
|
||||
} // namespace wxhelper
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef WXHELPER_HANDLER_H_
|
||||
#define WXHELPER_HANDLER_H_
|
||||
#include <mongoose.h>
|
||||
namespace wxhelper {
|
||||
class Handler {
|
||||
public:
|
||||
virtual void HandlerRequest(struct mg_connection *c, void *ev_data) = 0;
|
||||
};
|
||||
} // namespace wxhelper
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
#include "pch.h"
|
||||
#include "hide_module.h"
|
||||
|
||||
|
||||
namespace wxhelper {
|
||||
|
||||
void HideModule::Hide(const char* module_name) {
|
||||
HMODULE hMod = ::GetModuleHandleA(module_name);
|
||||
PLIST_ENTRY Head, Cur;
|
||||
PPEB_LDR_DATA ldr;
|
||||
PLDR_MODULE ldm;
|
||||
|
||||
__asm {
|
||||
mov eax, fs: [0x30]
|
||||
mov ecx, [eax + 0x0c]
|
||||
mov ldr, ecx
|
||||
}
|
||||
Head = &(ldr->InLoadOrderModuleList);
|
||||
Cur = Head->Flink;
|
||||
do {
|
||||
ldm = CONTAINING_RECORD(Cur, LDR_MODULE, InLoadOrderModuleList);
|
||||
if (hMod == ldm->BaseAddress) {
|
||||
ldm->InLoadOrderModuleList.Blink->Flink =
|
||||
ldm->InLoadOrderModuleList.Flink;
|
||||
ldm->InLoadOrderModuleList.Flink->Blink =
|
||||
ldm->InLoadOrderModuleList.Blink;
|
||||
ldm->InInitializationOrderModuleList.Blink->Flink =
|
||||
ldm->InInitializationOrderModuleList.Flink;
|
||||
ldm->InInitializationOrderModuleList.Flink->Blink =
|
||||
ldm->InInitializationOrderModuleList.Blink;
|
||||
ldm->InMemoryOrderModuleList.Blink->Flink =
|
||||
ldm->InMemoryOrderModuleList.Flink;
|
||||
ldm->InMemoryOrderModuleList.Flink->Blink =
|
||||
ldm->InMemoryOrderModuleList.Blink;
|
||||
break;
|
||||
}
|
||||
Cur = Cur->Flink;
|
||||
} while (Head != Cur);
|
||||
}
|
||||
|
||||
void HideModule::Hide(HMODULE module) {
|
||||
void* peb_ptr = nullptr;
|
||||
_asm {
|
||||
PUSH EAX
|
||||
MOV EAX, FS:[0x30]
|
||||
MOV peb_ptr, EAX
|
||||
POP EAX
|
||||
}
|
||||
void* ldr_ptr = *((void**)((unsigned char*)peb_ptr + 0xc));
|
||||
void* cur_ptr = *((void**)((unsigned char*)ldr_ptr + 0x0c));
|
||||
void* next_ptr = cur_ptr;
|
||||
do {
|
||||
void* next = *((void**)((unsigned char*)next_ptr));
|
||||
void* last = *((void**)((unsigned char*)next_ptr + 0x4));
|
||||
void* base_addr = *((void**)((unsigned char*)next_ptr + 0x18));
|
||||
if (base_addr == module) {
|
||||
*((void**)((unsigned char*)last)) = next;
|
||||
*((void**)((unsigned char*)next + 0x4)) = last;
|
||||
cur_ptr = next;
|
||||
}
|
||||
next_ptr = *((void**)next_ptr);
|
||||
} while (cur_ptr != next_ptr);
|
||||
}
|
||||
} // namespace wxhelper
|
||||
@@ -0,0 +1,48 @@
|
||||
#ifndef WXHELEPER_HIDE_MODULE_H_
|
||||
#define WXHELEPER_HIDE_MODULE_H_
|
||||
#include <Windows.h>
|
||||
namespace wxhelper {
|
||||
typedef struct _UNICODE_STRING {
|
||||
USHORT Length;
|
||||
USHORT MaximumLength;
|
||||
PWSTR Buffer;
|
||||
} UNICODE_STRING, *PUNICODE_STRING;
|
||||
|
||||
typedef struct _PEB_LDR_DATA {
|
||||
ULONG Length;
|
||||
BOOLEAN Initialized;
|
||||
PVOID SsHandle;
|
||||
LIST_ENTRY InLoadOrderModuleList;
|
||||
LIST_ENTRY InMemoryOrderModuleList;
|
||||
LIST_ENTRY InInitializationOrderModuleList;
|
||||
} PEB_LDR_DATA, *PPEB_LDR_DATA;
|
||||
|
||||
typedef struct _LDR_DATA_TABLE_ENTRY {
|
||||
LIST_ENTRY InLoadOrderModuleList;
|
||||
LIST_ENTRY InMemoryOrderModuleList;
|
||||
LIST_ENTRY InInitializationOrderModuleList;
|
||||
void* BaseAddress;
|
||||
void* EntryPoint;
|
||||
ULONG SizeOfImage;
|
||||
UNICODE_STRING FullDllName;
|
||||
UNICODE_STRING BaseDllName;
|
||||
ULONG Flags;
|
||||
SHORT LoadCount;
|
||||
SHORT TlsIndex;
|
||||
HANDLE SectionHandle;
|
||||
ULONG CheckSum;
|
||||
ULONG TimeDateStamp;
|
||||
} LDR_MODULE, *PLDR_MODULE;
|
||||
|
||||
|
||||
class HideModule {
|
||||
private:
|
||||
/* data */
|
||||
public:
|
||||
static void Hide(const char* module_name);
|
||||
static void Hide(HMODULE module);
|
||||
};
|
||||
|
||||
|
||||
} // namespace wxhelper
|
||||
#endif
|
||||
-231
@@ -1,231 +0,0 @@
|
||||
#include "pch.h"
|
||||
#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 0xd723dc
|
||||
#define WX_HOOK_IMG_NEXT_OFFSET 0xe91d90
|
||||
#define WX_SELF_ID_OFFSET 0x2E2CD3C
|
||||
#define BUFSIZE 1024
|
||||
|
||||
#define JPEG0 0xFF
|
||||
#define JPEG1 0xD8
|
||||
#define JPEG2 0xFF
|
||||
#define PNG0 0x89
|
||||
#define PNG1 0x50
|
||||
#define PNG2 0x4E
|
||||
#define BMP0 0x42
|
||||
#define BMP1 0x4D
|
||||
#define GIF0 0x47
|
||||
#define GIF1 0x49
|
||||
#define GIF2 0x46
|
||||
|
||||
|
||||
|
||||
static wstring kImgStorePath = L"";
|
||||
static int kImgHooked = FALSE;
|
||||
static DWORD kWeChatWinBase = GetWeChatWinBase();
|
||||
static char kOriginImgAsmCode[5] = {0};
|
||||
|
||||
static DWORD kHookImgNextAddress = kWeChatWinBase + WX_HOOK_IMG_NEXT_OFFSET;
|
||||
static DWORD kHookImgJmpBackAddress = kWeChatWinBase + WX_HOOK_IMG_OFFSET + 0x5;
|
||||
|
||||
void OnHookImg(DWORD obj_addr) {
|
||||
DWORD wxid_addr = GetWeChatWinBase() + WX_SELF_ID_OFFSET;
|
||||
string wxid = string(*(char **)wxid_addr, *(DWORD *)(wxid_addr + 0x10));
|
||||
wstring self_id = String2Wstring(wxid);
|
||||
wstring save_path = kImgStorePath + self_id;
|
||||
if (!FindOrCreateDirectoryW(save_path.c_str())) {
|
||||
return;
|
||||
}
|
||||
wchar_t *origin_file_path = *(wchar_t **)obj_addr;
|
||||
wstring img_path(origin_file_path);
|
||||
if (img_path.find(L"_t.dat") != wstring::npos) {
|
||||
return;
|
||||
}
|
||||
|
||||
int pos_begin = img_path.find_last_of(L"\\") + 1;
|
||||
int pos_end = img_path.find_last_of(L".");
|
||||
wstring file_name = img_path.substr(pos_begin, pos_end - pos_begin);
|
||||
char buffer[BUFSIZE] = {0};
|
||||
DWORD bytes_read = 0;
|
||||
DWORD bytes_write = 0;
|
||||
unsigned char magic_head[4] = {0};
|
||||
wchar_t suffix[5] = {0};
|
||||
|
||||
HANDLE h_origin_file =
|
||||
CreateFileW(origin_file_path, GENERIC_READ, 0, NULL, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (h_origin_file == INVALID_HANDLE_VALUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ReadFile(h_origin_file, buffer, BUFSIZE, &bytes_read, NULL)) {
|
||||
memcpy(magic_head, buffer, 3);
|
||||
}
|
||||
|
||||
if (magic_head[0] == PNG0 && magic_head[1] == PNG1 && magic_head[2] == PNG2) {
|
||||
lstrcpyW(suffix, L".png");
|
||||
} else if (magic_head[0] == GIF0 && magic_head[1] == GIF1 &&
|
||||
magic_head[2] == GIF2) {
|
||||
lstrcpyW(suffix, L".gif");
|
||||
} else if (magic_head[0] == JPEG0 && magic_head[1] == JPEG1 &&
|
||||
magic_head[2] == JPEG2) {
|
||||
lstrcpyW(suffix, L".jpg");
|
||||
} else {
|
||||
lstrcpyW(suffix, L"");
|
||||
}
|
||||
|
||||
wstring save_img_path = save_path + L"\\" + file_name + suffix;
|
||||
HANDLE save_file = CreateFileW(save_img_path.c_str(), GENERIC_ALL, 0, NULL,
|
||||
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (save_file == INVALID_HANDLE_VALUE) {
|
||||
return;
|
||||
}
|
||||
if (!WriteFile(save_file, (LPCVOID)buffer, bytes_read, &bytes_write, 0)) {
|
||||
CloseHandle(h_origin_file);
|
||||
CloseHandle(save_file);
|
||||
return;
|
||||
}
|
||||
do {
|
||||
if (ReadFile(h_origin_file, buffer, BUFSIZE, &bytes_read, NULL)) {
|
||||
if (!WriteFile(save_file, (LPCVOID)buffer, bytes_read, &bytes_write, 0)) {
|
||||
CloseHandle(h_origin_file);
|
||||
CloseHandle(save_file);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} while (bytes_read == BUFSIZE);
|
||||
CloseHandle(h_origin_file);
|
||||
CloseHandle(save_file);
|
||||
}
|
||||
|
||||
/// @brief hook img implement
|
||||
_declspec(naked) void handle_img() {
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
PUSH ECX
|
||||
CALL OnHookImg
|
||||
ADD ESP, 0x4
|
||||
POPFD
|
||||
POPAD
|
||||
CALL kHookImgNextAddress
|
||||
JMP kHookImgJmpBackAddress
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief hook image
|
||||
/// @param save_path image save dir
|
||||
/// @return
|
||||
int HookImg(wstring save_path) {
|
||||
kWeChatWinBase = GetWeChatWinBase();
|
||||
if (!kWeChatWinBase) {
|
||||
return -1;
|
||||
}
|
||||
if (kImgHooked) {
|
||||
return 2;
|
||||
}
|
||||
kImgStorePath = save_path;
|
||||
if (kImgStorePath.back() != '\\') {
|
||||
kImgStorePath += L"\\";
|
||||
}
|
||||
wstring createpath = kImgStorePath.substr(0, kImgStorePath.length() - 1);
|
||||
if (!FindOrCreateDirectoryW(createpath.c_str())) {
|
||||
return -2;
|
||||
}
|
||||
DWORD hook_img_addr = kWeChatWinBase + WX_HOOK_IMG_OFFSET;
|
||||
kHookImgNextAddress = kWeChatWinBase + WX_HOOK_IMG_NEXT_OFFSET;
|
||||
static DWORD kHookImgJmpBackAddress = hook_img_addr + 0x5;
|
||||
HookAnyAddress(hook_img_addr, (LPVOID)handle_img, kOriginImgAsmCode);
|
||||
kImgHooked = TRUE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int UnHookImg() {
|
||||
if (!kImgHooked) return 1;
|
||||
DWORD hook_img_addr = kWeChatWinBase + WX_HOOK_IMG_OFFSET;
|
||||
UnHookAnyAddress(hook_img_addr, kOriginImgAsmCode);
|
||||
kImgHooked = FALSE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int GetImgByName(wchar_t* file_path,wchar_t* save_dir) {
|
||||
wstring save_path(save_dir);
|
||||
wstring orign_file_path(file_path);
|
||||
if (!FindOrCreateDirectoryW(save_path.c_str())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pos_begin = orign_file_path.find_last_of(L"\\") + 1;
|
||||
int pos_end = orign_file_path.find_last_of(L".");
|
||||
wstring file_name = orign_file_path.substr(pos_begin, pos_end - pos_begin);
|
||||
HANDLE h_origin_file =
|
||||
CreateFileW(file_path, GENERIC_READ, 0, NULL, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
char buffer[BUFSIZE] = {0};
|
||||
DWORD bytes_read = 0;
|
||||
DWORD bytes_write = 0;
|
||||
unsigned char magic_head[4] = {0};
|
||||
wstring suffix;
|
||||
short key = 0;
|
||||
if (ReadFile(h_origin_file, buffer, BUFSIZE, &bytes_read, NULL)) {
|
||||
memcpy(magic_head, buffer, 3);
|
||||
} else {
|
||||
CloseHandle(h_origin_file);
|
||||
return 0;
|
||||
}
|
||||
if ((magic_head[0] ^ JPEG0) == (magic_head[1] ^ JPEG1)) {
|
||||
key = magic_head[0] ^ JPEG0;
|
||||
suffix = L".jpg";
|
||||
} else if ((magic_head[0] ^ PNG1) == (magic_head[1] ^ PNG2)) {
|
||||
key = magic_head[0] ^ PNG1;
|
||||
suffix = L".png";
|
||||
} else if ((magic_head[0] ^ GIF0) == (magic_head[1] ^ GIF1)) {
|
||||
key = magic_head[0] ^ GIF0;
|
||||
suffix = L".gif";
|
||||
} else if ((magic_head[0] ^ BMP0) == (magic_head[1] ^ BMP1)) {
|
||||
key = magic_head[0] ^ BMP0;
|
||||
suffix = L".bmp";
|
||||
} else {
|
||||
key = -1;
|
||||
suffix = L".dat";
|
||||
}
|
||||
wstring save_img_path = save_path + L"\\" + file_name + suffix;
|
||||
HANDLE save_img = CreateFileW(save_img_path.c_str(), GENERIC_ALL, 0, NULL,
|
||||
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (save_img == INVALID_HANDLE_VALUE) {
|
||||
return 0;
|
||||
}
|
||||
if (key > 0) {
|
||||
for (unsigned int i = 0; i < bytes_read; i++) {
|
||||
buffer[i]^=key;
|
||||
}
|
||||
}
|
||||
if (!WriteFile(save_img, (LPCVOID)buffer, bytes_read, &bytes_write, 0)) {
|
||||
CloseHandle(h_origin_file);
|
||||
CloseHandle(save_img);
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
if (ReadFile(h_origin_file, buffer, BUFSIZE, &bytes_read, NULL)) {
|
||||
if (key > 0) {
|
||||
for (unsigned int i = 0; i < bytes_read; i++) {
|
||||
buffer[i] ^= key;
|
||||
}
|
||||
}
|
||||
if (!WriteFile(save_img, (LPCVOID)buffer, bytes_read, &bytes_write, 0)) {
|
||||
CloseHandle(h_origin_file);
|
||||
CloseHandle(save_img);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} while (bytes_read == BUFSIZE);
|
||||
CloseHandle(h_origin_file);
|
||||
CloseHandle(save_img);
|
||||
return 1;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#ifndef HOOK_IMG_H_
|
||||
#define HOOK_IMG_H_
|
||||
#include "windows.h"
|
||||
|
||||
int HookImg(std::wstring save_path);
|
||||
int UnHookImg();
|
||||
|
||||
int GetImgByName(wchar_t* file_path,wchar_t* save_dir);
|
||||
#endif
|
||||
@@ -1,301 +0,0 @@
|
||||
#include "hook_recv_msg.h"
|
||||
|
||||
#include <Ws2tcpip.h>
|
||||
#include <winsock2.h>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include "common.h"
|
||||
#include "pch.h"
|
||||
using namespace nlohmann;
|
||||
|
||||
using namespace std;
|
||||
#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
|
||||
// #define WX_RECV_MSG_HOOK_NEXT_OFFSET 0x722FF0
|
||||
|
||||
#define CLIENT_IP "127.0.0.1"
|
||||
static int kServerPort = 0;
|
||||
static int kMessageHooked = FALSE;
|
||||
static char kServerIp[16]= "127.0.0.1";
|
||||
static DWORD kWeChatWinBase = GetWeChatWinBase();
|
||||
|
||||
static char kOriginReceMsgAsmCode[5] = {0};
|
||||
static DWORD kReceMsgJmpBackAddress =
|
||||
kWeChatWinBase + WX_RECV_MSG_HOOK_OFFSET + 0x5;
|
||||
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;
|
||||
~InnerMessageStruct() {
|
||||
if (this->buffer != NULL) {
|
||||
delete[] this->buffer;
|
||||
this->buffer = NULL;
|
||||
}
|
||||
}
|
||||
};
|
||||
/// @brief send message by socket
|
||||
/// @param buffer content
|
||||
/// @param len len
|
||||
/// @return true/false
|
||||
BOOL SendBySocket(const char *buffer, size_t len) {
|
||||
if (kServerPort == 0) {
|
||||
return false;
|
||||
}
|
||||
SOCKET client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (client_socket < 0) {
|
||||
#ifdef _DEBUG
|
||||
cout << "create socket error,"
|
||||
<< " errno:" << errno << endl;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
BOOL status = false;
|
||||
sockaddr_in client_addr;
|
||||
memset(&client_addr, 0, sizeof(client_addr));
|
||||
client_addr.sin_family = AF_INET;
|
||||
client_addr.sin_port = htons((u_short)kServerPort);
|
||||
InetPtonA(AF_INET, kServerIp, &client_addr.sin_addr.s_addr);
|
||||
if (connect(client_socket, reinterpret_cast<sockaddr *>(&client_addr),
|
||||
sizeof(sockaddr)) < 0) {
|
||||
#ifdef _DEBUG
|
||||
cout << "kServerIp:" << kServerIp <<endl;
|
||||
cout << "port:" << kServerPort <<endl;
|
||||
cout << "connect error,"
|
||||
<< " errno:" << errno << endl;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
char recv_buf[1024] = {0};
|
||||
int ret = send(client_socket, buffer, len, 0);
|
||||
if (ret == -1 || ret == 0) {
|
||||
#ifdef _DEBUG
|
||||
cout << "send fail,"
|
||||
<< " errno:" << errno << endl;
|
||||
#endif
|
||||
closesocket(client_socket);
|
||||
return false;
|
||||
}
|
||||
memset(recv_buf, 0, sizeof(recv_buf));
|
||||
ret = recv(client_socket, recv_buf, sizeof(recv_buf), 0);
|
||||
closesocket(client_socket);
|
||||
if (ret == -1 || ret == 0) {
|
||||
#ifdef _DEBUG
|
||||
cout << "the server close" << endl;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/// @brief send wrap
|
||||
/// @param msg msg
|
||||
void SendSocketMessage(InnerMessageStruct *msg) {
|
||||
if (msg == NULL) {
|
||||
return;
|
||||
}
|
||||
unique_ptr<InnerMessageStruct> sms(msg);
|
||||
json j_msg =
|
||||
json::parse(msg->buffer, msg->buffer + msg->length, nullptr, false);
|
||||
if (j_msg.is_discarded() == true) {
|
||||
return;
|
||||
}
|
||||
string jstr = j_msg.dump() + "\n";
|
||||
#ifdef _DEBUG
|
||||
cout << "json:" + jstr << endl;
|
||||
#endif
|
||||
SendBySocket(jstr.c_str(), jstr.size());
|
||||
}
|
||||
/// @brief msg handle
|
||||
/// @param msg_addr msg address in memory
|
||||
void __cdecl OnRecvMsg(DWORD msg_addr) {
|
||||
json j_msg;
|
||||
unsigned long long msgid = *(unsigned long long *)(msg_addr + 0x30);
|
||||
j_msg["msgId"] = msgid;
|
||||
j_msg["pid"] = GetCurrentProcessId();
|
||||
j_msg["type"] = *(DWORD *)(msg_addr + 0x38);
|
||||
j_msg["isSendMsg"] = *(BOOL *)(msg_addr + 0x3C);
|
||||
if (j_msg["isSendMsg"].get<BOOL>()) {
|
||||
j_msg["isSendByPhone"] = (int)(*(BYTE *)(msg_addr + 0xD8));
|
||||
}
|
||||
j_msg["time"] =
|
||||
unicode_to_utf8((wchar_t *)GetTimeW(*(DWORD *)(msg_addr + 0x44)).c_str());
|
||||
j_msg["timestamp"] = *(DWORD *)(msg_addr + 0x44);
|
||||
j_msg["fromGroup"] =
|
||||
unicode_to_utf8((wchar_t *)READ_WSTRING(msg_addr, 0x48).c_str());
|
||||
int length = *(DWORD *)(msg_addr + 0x178);
|
||||
if (length == 0) {
|
||||
j_msg["fromUser"] = j_msg["fromGroup"].get<std::string>();
|
||||
} else {
|
||||
j_msg["fromUser"] =
|
||||
unicode_to_utf8((wchar_t *)READ_WSTRING(msg_addr, 0x174).c_str());
|
||||
}
|
||||
int content_len = *(DWORD *)(msg_addr + 0x74);
|
||||
if (content_len > 0) {
|
||||
j_msg["content"] =
|
||||
unicode_to_utf8((wchar_t *)READ_WSTRING(msg_addr, 0x70).c_str());
|
||||
}
|
||||
int sign_len = *(DWORD *)(msg_addr + 0x18C);
|
||||
if (sign_len > 0) {
|
||||
j_msg["sign"] =
|
||||
unicode_to_utf8((wchar_t *)READ_WSTRING(msg_addr, 0x188).c_str());
|
||||
}
|
||||
int thumb_len = *(DWORD *)(msg_addr + 0x1A0);
|
||||
if (thumb_len > 0) {
|
||||
j_msg["thumbPath"] =
|
||||
unicode_to_utf8((wchar_t *)READ_WSTRING(msg_addr, 0x19C).c_str());
|
||||
}
|
||||
int path_len = *(DWORD *)(msg_addr + 0x1B4);
|
||||
if (path_len > 0) {
|
||||
j_msg["path"] =
|
||||
unicode_to_utf8((wchar_t *)READ_WSTRING(msg_addr, 0x1B0).c_str());
|
||||
}
|
||||
|
||||
int signature_len = *(DWORD *)(msg_addr + 0x1F4);
|
||||
if (signature_len > 0) {
|
||||
j_msg["signature"] =
|
||||
unicode_to_utf8((wchar_t *)READ_WSTRING(msg_addr, 0x1F0).c_str());
|
||||
}
|
||||
|
||||
string jstr = j_msg.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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
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 {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
PUSH ECX
|
||||
CALL OnRecvMsg
|
||||
ADD ESP, 0x4
|
||||
POPFD
|
||||
POPAD
|
||||
CALL kReceMsgNextAddress
|
||||
JMP kReceMsgJmpBackAddress
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @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
|
||||
int HookRecvMsg(char* client_ip,int port) {
|
||||
kServerPort = port;
|
||||
strcpy_s(kServerIp,client_ip);
|
||||
kWeChatWinBase = GetWeChatWinBase();
|
||||
if (!kWeChatWinBase) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (kMessageHooked) {
|
||||
return 2;
|
||||
}
|
||||
kWeChatWinBase = GetWeChatWinBase();
|
||||
DWORD hook_recv_msg_addr = kWeChatWinBase + WX_RECV_MSG_HOOK_OFFSET;
|
||||
kReceMsgNextAddress = kWeChatWinBase + WX_RECV_MSG_HOOK_NEXT_OFFSET;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#ifndef HOOK_RECV_MSG_H_
|
||||
#define HOOK_RECV_MSG_H_
|
||||
|
||||
/// @brief hook any address address+0x5
|
||||
/// @param port 端口
|
||||
/// @return 成功返回1,已经hook返回2
|
||||
int HookRecvMsg(char* client_ip,int port);
|
||||
|
||||
int UnHookRecvMsg();
|
||||
#endif
|
||||
+661
@@ -0,0 +1,661 @@
|
||||
#include "pch.h"
|
||||
#include <Ws2tcpip.h>
|
||||
#include <winsock2.h>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "thread_pool.h"
|
||||
#include "wechat_function.h"
|
||||
using namespace nlohmann;
|
||||
using namespace std;
|
||||
namespace wxhelper {
|
||||
namespace hooks {
|
||||
static int server_port_ = 0;
|
||||
static bool msg_hook_flag_ = false;
|
||||
static char server_ip_[16] = "127.0.0.1";
|
||||
|
||||
static char msg_asm_code_[5] = {0};
|
||||
static DWORD msg_back_addr_ = 0;
|
||||
static DWORD msg_next_addr_ = 0;
|
||||
|
||||
static char sns_asm_code_[5] = {0};
|
||||
static DWORD sns_back_addr_ = 0;
|
||||
static DWORD sns_next_addr_ = 0;
|
||||
|
||||
static bool log_hook_flag_ = false;
|
||||
static char log_asm_code_[5] = {0};
|
||||
static DWORD log_back_addr_ = 0;
|
||||
static DWORD log_next_addr_ = 0;
|
||||
|
||||
static bool search_contact_flag_ = false;
|
||||
static char search_contact_asm_code_[5] = {0};
|
||||
static DWORD search_contact_back_addr_ = 0;
|
||||
static DWORD search_contact_next_addr_ = 0;
|
||||
|
||||
static bool error_code_flag_ = false;
|
||||
static char error_code_asm_code_[5] = {0};
|
||||
static DWORD error_code_back_addr_ = 0;
|
||||
static DWORD error_code_next_addr_ = 0;
|
||||
|
||||
bool user_info_flag_ = false;
|
||||
static char user_info_asm_code_[5] = {0};
|
||||
static DWORD user_info_back_addr_ = 0;
|
||||
static DWORD user_info_next_addr_ = 0;
|
||||
|
||||
UserInfo userinfo = {};
|
||||
|
||||
void SendSocketMessage(InnerMessageStruct *msg) {
|
||||
if (msg == NULL) {
|
||||
return;
|
||||
}
|
||||
unique_ptr<InnerMessageStruct> sms(msg);
|
||||
json j_msg =
|
||||
json::parse(msg->buffer, msg->buffer + msg->length, nullptr, false);
|
||||
if (j_msg.is_discarded() == true) {
|
||||
return;
|
||||
}
|
||||
string jstr = j_msg.dump() + "\n";
|
||||
|
||||
if (server_port_ == 0) {
|
||||
SPDLOG_ERROR("http server port error :{}",server_port_);
|
||||
return;
|
||||
}
|
||||
SOCKET client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (client_socket < 0) {
|
||||
SPDLOG_ERROR("socket init fail");
|
||||
return;
|
||||
}
|
||||
BOOL status = false;
|
||||
sockaddr_in client_addr;
|
||||
memset(&client_addr, 0, sizeof(client_addr));
|
||||
client_addr.sin_family = AF_INET;
|
||||
client_addr.sin_port = htons((u_short)server_port_);
|
||||
InetPtonA(AF_INET, server_ip_, &client_addr.sin_addr.s_addr);
|
||||
if (connect(client_socket, reinterpret_cast<sockaddr *>(&client_addr),
|
||||
sizeof(sockaddr)) < 0) {
|
||||
SPDLOG_ERROR("socket connect fail");
|
||||
return;
|
||||
}
|
||||
char recv_buf[1024] = {0};
|
||||
int ret = send(client_socket, jstr.c_str(), jstr.size(), 0);
|
||||
if (ret == -1 || ret == 0) {
|
||||
SPDLOG_ERROR("socket send fail ,ret::{}",ret);
|
||||
closesocket(client_socket);
|
||||
return;
|
||||
}
|
||||
memset(recv_buf, 0, sizeof(recv_buf));
|
||||
ret = recv(client_socket, recv_buf, sizeof(recv_buf), 0);
|
||||
closesocket(client_socket);
|
||||
if (ret == -1 || ret == 0) {
|
||||
SPDLOG_ERROR("socket recv fail ,ret:{}",ret);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
VOID CALLBACK SendMsgCallback(PTP_CALLBACK_INSTANCE instance, PVOID context,
|
||||
PTP_WORK Work) {
|
||||
InnerMessageStruct *msg = (InnerMessageStruct *)context;
|
||||
if (msg == NULL) {
|
||||
SPDLOG_INFO("add work:msg is null");
|
||||
return;
|
||||
}
|
||||
unique_ptr<InnerMessageStruct> sms(msg);
|
||||
json j_msg =
|
||||
json::parse(msg->buffer, msg->buffer + msg->length, nullptr, false);
|
||||
if (j_msg.is_discarded() == true) {
|
||||
return;
|
||||
}
|
||||
string jstr = j_msg.dump() + "\n";
|
||||
|
||||
if (server_port_ == 0) {
|
||||
SPDLOG_ERROR("http server port error :{}", server_port_);
|
||||
return;
|
||||
}
|
||||
WSADATA was_data = {0};
|
||||
int ret = WSAStartup(MAKEWORD(2, 2), &was_data);
|
||||
if (ret != 0) {
|
||||
SPDLOG_ERROR("WSAStartup failed:{}", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
SOCKET client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (client_socket < 0) {
|
||||
SPDLOG_ERROR("socket init fail");
|
||||
return;
|
||||
}
|
||||
BOOL status = false;
|
||||
sockaddr_in client_addr;
|
||||
memset(&client_addr, 0, sizeof(client_addr));
|
||||
client_addr.sin_family = AF_INET;
|
||||
client_addr.sin_port = htons((u_short)server_port_);
|
||||
InetPtonA(AF_INET, server_ip_, &client_addr.sin_addr.s_addr);
|
||||
if (connect(client_socket, reinterpret_cast<sockaddr *>(&client_addr),
|
||||
sizeof(sockaddr)) < 0) {
|
||||
SPDLOG_ERROR("socket connect fail");
|
||||
closesocket(client_socket);
|
||||
WSACleanup();
|
||||
return ;
|
||||
}
|
||||
char recv_buf[1024] = {0};
|
||||
ret = send(client_socket, jstr.c_str(), jstr.size(), 0);
|
||||
if (ret == -1 || ret == 0) {
|
||||
SPDLOG_ERROR("socket send fail ,ret:{}", ret);
|
||||
closesocket(client_socket);
|
||||
WSACleanup();
|
||||
return;
|
||||
}
|
||||
ret = shutdown(client_socket, SD_SEND);
|
||||
if (ret == SOCKET_ERROR) {
|
||||
SPDLOG_ERROR("shutdown failed with erro:{}", ret);
|
||||
closesocket(client_socket);
|
||||
WSACleanup();
|
||||
return ;
|
||||
}
|
||||
|
||||
memset(recv_buf, 0, sizeof(recv_buf));
|
||||
ret = recv(client_socket, recv_buf, sizeof(recv_buf), 0);
|
||||
closesocket(client_socket);
|
||||
if (ret == -1 || ret == 0) {
|
||||
SPDLOG_ERROR("socket recv fail ,ret:{}", ret);
|
||||
WSACleanup();
|
||||
return;
|
||||
}
|
||||
WSACleanup();
|
||||
return;
|
||||
}
|
||||
|
||||
void __cdecl OnRecvMsg(DWORD msg_addr) {
|
||||
json j_msg;
|
||||
unsigned long long msgid = *(unsigned long long *)(msg_addr + 0x30);
|
||||
j_msg["msgId"] = msgid;
|
||||
j_msg["pid"] = GetCurrentProcessId();
|
||||
j_msg["type"] = *(DWORD *)(msg_addr + 0x38);
|
||||
j_msg["isSendMsg"] = *(BOOL *)(msg_addr + 0x3C);
|
||||
if (j_msg["isSendMsg"].get<BOOL>()) {
|
||||
j_msg["isSendByPhone"] = (int)(*(BYTE *)(msg_addr + 0xD8));
|
||||
}
|
||||
j_msg["time"] =
|
||||
Utils::WstringToUTF8(Utils::GetTimeW(*(DWORD *)(msg_addr + 0x44)));
|
||||
j_msg["timestamp"] = *(DWORD *)(msg_addr + 0x44);
|
||||
j_msg["fromGroup"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x48));
|
||||
int length = *(DWORD *)(msg_addr + 0x178);
|
||||
if (length == 0) {
|
||||
j_msg["fromUser"] = j_msg["fromGroup"].get<std::string>();
|
||||
} else {
|
||||
j_msg["fromUser"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x174));
|
||||
}
|
||||
int content_len = *(DWORD *)(msg_addr + 0x74);
|
||||
if (content_len > 0) {
|
||||
j_msg["content"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x70));
|
||||
}
|
||||
int sign_len = *(DWORD *)(msg_addr + 0x18C);
|
||||
if (sign_len > 0) {
|
||||
j_msg["sign"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x188));
|
||||
}
|
||||
int thumb_len = *(DWORD *)(msg_addr + 0x1A0);
|
||||
if (thumb_len > 0) {
|
||||
j_msg["thumbPath"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x19C));
|
||||
}
|
||||
int path_len = *(DWORD *)(msg_addr + 0x1B4);
|
||||
if (path_len > 0) {
|
||||
j_msg["path"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x1B0));
|
||||
}
|
||||
|
||||
int signature_len = *(DWORD *)(msg_addr + 0x1F4);
|
||||
if (signature_len > 0) {
|
||||
j_msg["signature"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x1F0));
|
||||
}
|
||||
|
||||
string jstr = j_msg.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();
|
||||
bool add = ThreadPool::GetInstance().AddWork(SendMsgCallback,inner_msg);
|
||||
SPDLOG_INFO("add work:{}",add);
|
||||
// HANDLE thread = CreateThread(
|
||||
// NULL, 0, (LPTHREAD_START_ROUTINE)SendSocketMessage, inner_msg, NULL, 0);
|
||||
// if (thread) {
|
||||
// CloseHandle(thread);
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief hook msg implement
|
||||
_declspec(naked) void HandleSyncMsg() {
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
PUSH ECX
|
||||
CALL OnRecvMsg
|
||||
ADD ESP, 0x4
|
||||
POPFD
|
||||
POPAD
|
||||
CALL msg_next_addr_
|
||||
JMP msg_back_addr_
|
||||
}
|
||||
}
|
||||
|
||||
void __cdecl OnSnsTimeLineMsg(DWORD msg_addr) {
|
||||
json j_sns;
|
||||
DWORD begin_addr = *(DWORD *)(msg_addr + 0x20);
|
||||
DWORD end_addr = *(DWORD *)(msg_addr + 0x24);
|
||||
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"] = Utils::WstringToUTF8(READ_WSTRING(begin_addr, 0x18));
|
||||
|
||||
j_item["content"] = Utils::WstringToUTF8(READ_WSTRING(begin_addr, 0x3c));
|
||||
|
||||
j_item["xml"] = Utils::WstringToUTF8(READ_WSTRING(begin_addr, 0x384));
|
||||
|
||||
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 sns msg implement
|
||||
_declspec(naked) void HandleSNSMsg() {
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
PUSH [ESP + 0x24]
|
||||
CALL OnSnsTimeLineMsg
|
||||
ADD ESP, 0x4
|
||||
POPFD
|
||||
POPAD
|
||||
CALL sns_next_addr_
|
||||
JMP sns_back_addr_
|
||||
}
|
||||
}
|
||||
|
||||
int HookRecvMsg(char *client_ip, int port) {
|
||||
server_port_ = port;
|
||||
strcpy_s(server_ip_, client_ip);
|
||||
DWORD base = Utils::GetWeChatWinBase();
|
||||
if (!base) {
|
||||
SPDLOG_INFO("base addr is null");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msg_hook_flag_) {
|
||||
SPDLOG_INFO("recv msg hook already called");
|
||||
return 2;
|
||||
}
|
||||
|
||||
DWORD hook_recv_msg_addr = base + WX_RECV_MSG_HOOK_OFFSET;
|
||||
msg_next_addr_ = base + WX_RECV_MSG_HOOK_NEXT_OFFSET;
|
||||
msg_back_addr_ = hook_recv_msg_addr + 0x5;
|
||||
Utils::HookAnyAddress(hook_recv_msg_addr, (LPVOID)HandleSyncMsg,
|
||||
msg_asm_code_);
|
||||
|
||||
DWORD hook_sns_msg_addr = base + WX_SNS_HOOK_OFFSET;
|
||||
sns_next_addr_ = base + WX_SNS_HOOK_NEXT_OFFSET;
|
||||
sns_back_addr_ = hook_sns_msg_addr + 0x5;
|
||||
Utils::HookAnyAddress(hook_sns_msg_addr, (LPVOID)HandleSNSMsg, sns_asm_code_);
|
||||
|
||||
msg_hook_flag_ = true;
|
||||
SPDLOG_INFO("hook recv msg success");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int UnHookRecvMsg() {
|
||||
server_port_ = 0;
|
||||
if (!msg_hook_flag_) {
|
||||
SPDLOG_INFO("recv msg hook already called");
|
||||
return 2;
|
||||
}
|
||||
DWORD base = Utils::GetWeChatWinBase();
|
||||
DWORD hook_recv_msg_addr = base + WX_RECV_MSG_HOOK_OFFSET;
|
||||
DWORD hook_sns_addr = base + WX_SNS_HOOK_OFFSET;
|
||||
Utils::UnHookAnyAddress(hook_recv_msg_addr, msg_asm_code_);
|
||||
Utils::UnHookAnyAddress(hook_sns_addr, sns_asm_code_);
|
||||
msg_hook_flag_ = false;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void PrintLog(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);
|
||||
spdlog::info("wechat log:{}", ansi_message);
|
||||
delete[] w_msg;
|
||||
w_msg = NULL;
|
||||
delete[] ansi_message;
|
||||
ansi_message = NULL;
|
||||
}
|
||||
|
||||
_declspec(naked) void HandleLog() {
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
PUSH EAX
|
||||
CALL PrintLog
|
||||
ADD ESP, 0x4
|
||||
POPFD
|
||||
POPAD
|
||||
CALL log_next_addr_
|
||||
JMP log_back_addr_
|
||||
}
|
||||
}
|
||||
|
||||
int HookLog() {
|
||||
DWORD base = Utils::GetWeChatWinBase();
|
||||
if (!base) {
|
||||
return -1;
|
||||
}
|
||||
if (log_hook_flag_) {
|
||||
return 2;
|
||||
}
|
||||
DWORD hook_log_addr = base + WX_HOOK_LOG_OFFSET;
|
||||
log_next_addr_ = base + WX_HOOK_LOG_NEXT_OFFSET;
|
||||
log_back_addr_ = hook_log_addr + 0x5;
|
||||
Utils::HookAnyAddress(hook_log_addr, (LPVOID)HandleLog, log_asm_code_);
|
||||
log_hook_flag_ = true;
|
||||
return 1;
|
||||
}
|
||||
int UnHookLog() {
|
||||
if (!log_hook_flag_) {
|
||||
return 1;
|
||||
}
|
||||
DWORD base = Utils::GetWeChatWinBase();
|
||||
DWORD hook_log_addr = base + WX_HOOK_LOG_OFFSET;
|
||||
Utils::UnHookAnyAddress(hook_log_addr, log_asm_code_);
|
||||
log_hook_flag_ = FALSE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void SetErrorCode(int code) { userinfo.error_code = code; }
|
||||
|
||||
void SetUserInfoDetail(DWORD address) {
|
||||
SPDLOG_INFO("hook userinfo addr = {}",address);
|
||||
DWORD length = *(DWORD *)(address + 0x8);
|
||||
userinfo.keyword = new wchar_t[length + 1];
|
||||
userinfo.keyword_len = length;
|
||||
if (length) {
|
||||
memcpy(userinfo.keyword, (wchar_t *)(*(DWORD *)(address + 0x4)),
|
||||
(length + 1) * sizeof(wchar_t));
|
||||
} else {
|
||||
ZeroMemory(userinfo.keyword, (length + 1) * sizeof(wchar_t));
|
||||
}
|
||||
|
||||
length = *(DWORD *)(address + 0x1C);
|
||||
userinfo.v3 = new wchar_t[length + 1];
|
||||
userinfo.v3_len = length;
|
||||
if (length) {
|
||||
memcpy(userinfo.v3, (wchar_t *)(*(DWORD *)(address + 0x18)),
|
||||
(length + 1) * sizeof(wchar_t));
|
||||
} else {
|
||||
ZeroMemory(userinfo.v3, (length + 1) * sizeof(wchar_t));
|
||||
}
|
||||
|
||||
length = *(DWORD *)(address + 0x30);
|
||||
userinfo.big_image = new wchar_t[length + 1];
|
||||
userinfo.big_image_len = length;
|
||||
if (length) {
|
||||
memcpy(userinfo.big_image, (wchar_t *)(*(DWORD *)(address + 0x2C)),
|
||||
(length + 1) * sizeof(wchar_t));
|
||||
} else {
|
||||
ZeroMemory(userinfo.big_image, (length + 1) * sizeof(wchar_t));
|
||||
}
|
||||
|
||||
length = *(DWORD *)(address + 0x6C);
|
||||
userinfo.V3 = new wchar_t[length + 1];
|
||||
userinfo.V3_len = length;
|
||||
if (length) {
|
||||
memcpy(userinfo.V3, (wchar_t *)(*(DWORD *)(address + 0x68)),
|
||||
(length + 1) * sizeof(wchar_t));
|
||||
} else {
|
||||
ZeroMemory(userinfo.V3, (length + 1) * sizeof(wchar_t));
|
||||
}
|
||||
|
||||
length = *(DWORD *)(address + 0x80);
|
||||
userinfo.account = new wchar_t[length + 1];
|
||||
userinfo.account_len = length;
|
||||
if (length) {
|
||||
memcpy(userinfo.account, (wchar_t *)(*(DWORD *)(address + 0x7C)),
|
||||
(length + 1) * sizeof(wchar_t));
|
||||
} else {
|
||||
ZeroMemory(userinfo.account, (length + 1) * sizeof(wchar_t));
|
||||
}
|
||||
|
||||
// length = *(DWORD *)(address + 0x94);
|
||||
// userinfo.friend_name = new wchar_t[length + 1];
|
||||
// userinfo.friend_name_len = length;
|
||||
// if (length) {
|
||||
// memcpy(userinfo.friend_name, (wchar_t *)(*(DWORD *)(address + 0x90)),
|
||||
// (length + 1) * sizeof(wchar_t));
|
||||
// } else {
|
||||
// ZeroMemory(userinfo.friend_name, (length + 1) * sizeof(wchar_t));
|
||||
// }
|
||||
|
||||
length = *(DWORD *)(address + 0xC8);
|
||||
userinfo.nickname = new wchar_t[length + 1];
|
||||
userinfo.nickname_len = length;
|
||||
if (length) {
|
||||
memcpy(userinfo.nickname, (wchar_t *)(*(DWORD *)(address + 0xC4)),
|
||||
(length + 1) * sizeof(wchar_t));
|
||||
} else {
|
||||
ZeroMemory(userinfo.nickname, (length + 1) * sizeof(wchar_t));
|
||||
}
|
||||
|
||||
// the results of calling and UI operations are different
|
||||
//
|
||||
// length = *(DWORD *)(address + 0x108);
|
||||
// userinfo.v2 = new wchar_t[length + 1];
|
||||
// userinfo.v2_len = length;
|
||||
// if (length) {
|
||||
// memcpy(userinfo.v2, (wchar_t *)(*(DWORD *)(address + 0x104)),
|
||||
// (length + 1) * sizeof(wchar_t));
|
||||
// } else {
|
||||
// ZeroMemory(userinfo.v2, (length + 1) * sizeof(wchar_t));
|
||||
// }
|
||||
|
||||
// length = *(DWORD *)(address + 0x11C);
|
||||
// userinfo.py = new wchar_t[length + 1];
|
||||
// userinfo.py_len = length;
|
||||
// if (length) {
|
||||
// memcpy(userinfo.py, (wchar_t *)(*(DWORD *)(address + 0x118)),
|
||||
// (length + 1) * sizeof(wchar_t));
|
||||
// } else {
|
||||
// ZeroMemory(userinfo.py, (length + 1) * sizeof(wchar_t));
|
||||
// }
|
||||
|
||||
|
||||
length = *(DWORD *)(address + 0x16C);
|
||||
userinfo.small_image = new wchar_t[length + 1];
|
||||
userinfo.small_image_len = length;
|
||||
if (length) {
|
||||
memcpy(userinfo.small_image, (wchar_t *)(*(DWORD *)(address + 0x168)),
|
||||
(length + 1) * sizeof(wchar_t));
|
||||
} else {
|
||||
ZeroMemory(userinfo.small_image, (length + 1) * sizeof(wchar_t));
|
||||
}
|
||||
|
||||
length = *(DWORD *)(address + 0x1F8);
|
||||
userinfo.signature = new wchar_t[length + 1];
|
||||
userinfo.signature_len = length;
|
||||
if (length) {
|
||||
memcpy(userinfo.signature, (wchar_t *)(*(DWORD *)(address + 0x1F4)),
|
||||
(length + 1) * sizeof(wchar_t));
|
||||
} else {
|
||||
ZeroMemory(userinfo.signature, (length + 1) * sizeof(wchar_t));
|
||||
}
|
||||
|
||||
length = *(DWORD *)(address + 0x20C);
|
||||
userinfo.nation = new wchar_t[length + 1];
|
||||
userinfo.nation_len = length;
|
||||
if (length) {
|
||||
memcpy(userinfo.nation, (wchar_t *)(*(DWORD *)(address + 0x208)),
|
||||
(length + 1) * sizeof(wchar_t));
|
||||
} else {
|
||||
ZeroMemory(userinfo.nation, (length + 1) * sizeof(wchar_t));
|
||||
}
|
||||
|
||||
length = *(DWORD *)(address + 0x220);
|
||||
userinfo.province = new wchar_t[length + 1];
|
||||
userinfo.province_len = length;
|
||||
if (length) {
|
||||
memcpy(userinfo.province, (wchar_t *)(*(DWORD *)(address + 0x21C)),
|
||||
(length + 1) * sizeof(wchar_t));
|
||||
} else {
|
||||
ZeroMemory(userinfo.province, (length + 1) * sizeof(wchar_t));
|
||||
}
|
||||
|
||||
length = *(DWORD *)(address + 0x234);
|
||||
userinfo.city = new wchar_t[length + 1];
|
||||
userinfo.city_len = length;
|
||||
if (length) {
|
||||
memcpy(userinfo.city, (wchar_t *)(*(DWORD *)(address + 0x230)),
|
||||
(length + 1) * sizeof(wchar_t));
|
||||
} else {
|
||||
ZeroMemory(userinfo.city, (length + 1) * sizeof(wchar_t));
|
||||
}
|
||||
|
||||
userinfo.sex = *(DWORD *)(address + 0x1BC);
|
||||
userinfo.over = true;
|
||||
}
|
||||
|
||||
void DeleteUserInfoCache() {
|
||||
if (userinfo.keyword) {
|
||||
delete userinfo.keyword;
|
||||
}
|
||||
if (userinfo.v2) {
|
||||
delete userinfo.v2;
|
||||
}
|
||||
if (userinfo.v3) {
|
||||
delete userinfo.v3;
|
||||
}
|
||||
if (userinfo.V3) {
|
||||
delete userinfo.V3;
|
||||
}
|
||||
if (userinfo.account) {
|
||||
delete userinfo.account;
|
||||
}
|
||||
if (userinfo.friend_name) {
|
||||
delete userinfo.friend_name;
|
||||
}
|
||||
if (userinfo.nickname) {
|
||||
delete userinfo.nickname;
|
||||
}
|
||||
if (userinfo.py) {
|
||||
delete userinfo.py;
|
||||
}
|
||||
if (userinfo.nation) {
|
||||
delete userinfo.nation;
|
||||
}
|
||||
if (userinfo.province) {
|
||||
delete userinfo.province;
|
||||
}
|
||||
if (userinfo.city) {
|
||||
delete userinfo.city;
|
||||
}
|
||||
if (userinfo.signature) {
|
||||
delete userinfo.signature;
|
||||
}
|
||||
if (userinfo.small_image) {
|
||||
delete userinfo.small_image;
|
||||
}
|
||||
if (userinfo.big_image) {
|
||||
delete userinfo.big_image;
|
||||
}
|
||||
ZeroMemory(&userinfo, sizeof(UserInfo));
|
||||
userinfo.error_code = 1;
|
||||
}
|
||||
|
||||
__declspec(naked) void HandleErrorCode() {
|
||||
__asm {
|
||||
PUSHAD;
|
||||
PUSHFD;
|
||||
PUSH ESI;
|
||||
CALL SetErrorCode;
|
||||
ADD ESP, 0x4;
|
||||
POPFD;
|
||||
POPAD;
|
||||
CALL error_code_next_addr_;
|
||||
JMP error_code_back_addr_;
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(naked) void HandleUserInfoDetail() {
|
||||
__asm {
|
||||
PUSHAD;
|
||||
PUSHFD;
|
||||
PUSH dword ptr [EBP + 0x14];
|
||||
CALL SetUserInfoDetail;
|
||||
ADD ESP, 0x4;
|
||||
POPFD;
|
||||
POPAD;
|
||||
CALL user_info_next_addr_;
|
||||
JMP user_info_back_addr_;
|
||||
}
|
||||
}
|
||||
|
||||
int HookSearchContact() {
|
||||
DWORD base = Utils::GetWeChatWinBase();
|
||||
if (!base) {
|
||||
return -1;
|
||||
}
|
||||
if (search_contact_flag_) {
|
||||
return 2;
|
||||
}
|
||||
// DWORD hook_error_code_addr = base + WX_SEARCH_CONTACT_ERROR_CODE_HOOK_OFFSET;
|
||||
// error_code_next_addr_ = base + WX_SEARCH_CONTACT_ERROR_CODE_HOOK_NEXT_OFFSET;
|
||||
// error_code_back_addr_ = hook_error_code_addr + 0x5;
|
||||
// Utils::HookAnyAddress(hook_error_code_addr, (LPVOID)HandleErrorCode,
|
||||
// error_code_asm_code_);
|
||||
|
||||
DWORD hook_user_info_addr = base + WX_SEARCH_CONTACT_DETAIL_HOOK_OFFSET;
|
||||
user_info_next_addr_ = base + WX_SEARCH_CONTACT_DETAIL_HOOK_NEXT_OFFSET;
|
||||
user_info_back_addr_ = hook_user_info_addr + 0x5;
|
||||
|
||||
Utils::HookAnyAddress(hook_user_info_addr, (LPVOID)HandleUserInfoDetail,
|
||||
user_info_asm_code_);
|
||||
error_code_flag_ = true;
|
||||
user_info_flag_ = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int UnHookSearchContact() {
|
||||
DWORD base = Utils::GetWeChatWinBase();
|
||||
DWORD hook_user_info_addr = base + WX_SEARCH_CONTACT_DETAIL_HOOK_OFFSET;
|
||||
DWORD hook_error_code_addr = base + WX_SEARCH_CONTACT_ERROR_CODE_HOOK_OFFSET;
|
||||
|
||||
if (!user_info_flag_) return 2;
|
||||
Utils::UnHookAnyAddress(hook_user_info_addr, user_info_asm_code_);
|
||||
user_info_flag_ = false;
|
||||
|
||||
if (!error_code_flag_) return 2;
|
||||
Utils::UnHookAnyAddress(hook_error_code_addr, error_code_asm_code_);
|
||||
error_code_flag_ = false;
|
||||
|
||||
return 1;
|
||||
}
|
||||
} // namespace hooks
|
||||
} // namespace wxhelper
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
#ifndef WXHELPER_HOOKS_H_
|
||||
#define WXHELPER_HOOKS_H_
|
||||
#include "Windows.h"
|
||||
#include "wechat_function.h"
|
||||
namespace wxhelper {
|
||||
namespace hooks {
|
||||
extern UserInfo userinfo;
|
||||
extern bool user_info_flag_ ;
|
||||
|
||||
int HookRecvMsg(char* client_ip, int port);
|
||||
|
||||
int UnHookRecvMsg();
|
||||
|
||||
void SendSocketMessage(InnerMessageStruct* msg);
|
||||
|
||||
int HookLog();
|
||||
int UnHookLog();
|
||||
int HookSearchContact();
|
||||
int UnHookSearchContact();
|
||||
void DeleteUserInfoCache();
|
||||
} // namespace hooks
|
||||
} // namespace wxhelper
|
||||
#endif
|
||||
@@ -0,0 +1,621 @@
|
||||
#include "pch.h"
|
||||
#include "http_handler.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include "utils.h"
|
||||
#include "account_mgr.h"
|
||||
#include "api_route.h"
|
||||
#include "chat_room_mgr.h"
|
||||
#include "contact_mgr.h"
|
||||
#include "db.h"
|
||||
#include "hooks.h"
|
||||
#include "misc_mgr.h"
|
||||
#include "send_message_mgr.h"
|
||||
#include "sns_mgr.h"
|
||||
#include "global_context.h"
|
||||
#include "hooks.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace nlohmann;
|
||||
|
||||
namespace wxhelper {
|
||||
string GetParamOfGetReq(mg_http_message *hm, string name) {
|
||||
string ret;
|
||||
char *buffer = new char[hm->query.len + 1];
|
||||
ZeroMemory(buffer, hm->query.len + 1);
|
||||
int len = mg_http_get_var(&hm->query, name.c_str(), buffer, hm->query.len);
|
||||
if (len > 0) ret = string(buffer, len);
|
||||
delete[] buffer;
|
||||
buffer = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int GetIntParam(json data, string key) {
|
||||
int result;
|
||||
try {
|
||||
result = data[key].get<int>();
|
||||
} catch (json::exception) {
|
||||
result = STRING2INT(data[key].get<string>());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
wstring GetWStringParam(json data, string key) {
|
||||
return Utils::UTF8ToWstring(data[key].get<string>());
|
||||
}
|
||||
|
||||
unsigned long long GetULong64Param(json j_data, string key) {
|
||||
unsigned long long result = 0;
|
||||
try {
|
||||
result = j_data[key].get<ULONG64>();
|
||||
} catch (json::exception) {
|
||||
string value = j_data[key].get<string>();
|
||||
istringstream is(value);
|
||||
is >> result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static vector<wstring> getArrayParam(json j_data, string key) {
|
||||
vector<wstring> result;
|
||||
wstring param = GetWStringParam(j_data, key);
|
||||
result = Utils::split(param, L',');
|
||||
return result;
|
||||
}
|
||||
|
||||
string Dispatch(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
int is_post = 0;
|
||||
string ret;
|
||||
if (mg_vcasecmp(&hm->method, "POST") == 0) {
|
||||
is_post = 1;
|
||||
}
|
||||
// el::Logger *defaultLogger = el::Loggers::getLogger("default");
|
||||
// defaultLogger->info("method: %v body: %v", hm->method.ptr, hm->body.ptr);
|
||||
// LOG_IF(is_post != 1, INFO) << "request method is not post";
|
||||
|
||||
if (is_post == 0) {
|
||||
json ret_data = {{"result", "ERROR"}, {"msg", "not support method"}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
}
|
||||
|
||||
json j_param =
|
||||
json::parse(hm->body.ptr, hm->body.ptr + hm->body.len, nullptr, false);
|
||||
if (hm->body.len != 0 && j_param.is_discarded() == true) {
|
||||
json ret_data = {{"result", "ERROR"}, {"msg", "json string is invalid."}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
}
|
||||
int api_number = STRING2INT(GetParamOfGetReq(hm, "type"));
|
||||
GlobalContext& g_context = GlobalContext::GetInstance();
|
||||
switch (api_number) {
|
||||
case WECHAT_IS_LOGIN: {
|
||||
int success = -1;
|
||||
success = g_context.account_mgr->CheckLogin();
|
||||
json ret_data = {{"result", "OK"}, {"code", success}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_GET_SELF_INFO: {
|
||||
SelfInfoInner self_info;
|
||||
int success = g_context.account_mgr->GetSelfInfo(self_info);
|
||||
json ret_data = {{"result", "OK"}, {"code", success}};
|
||||
if (success) {
|
||||
json j_info = {
|
||||
{"name", self_info.name},
|
||||
{"city", self_info.city},
|
||||
{"province", self_info.province},
|
||||
{"country", self_info.country},
|
||||
{"account", self_info.account},
|
||||
{"wxid", self_info.wxid},
|
||||
{"mobile", self_info.mobile},
|
||||
{"headImage", self_info.head_img},
|
||||
{"signature", self_info.signature},
|
||||
{"dataSavePath", self_info.data_save_path},
|
||||
{"currentDataPath", self_info.current_data_path},
|
||||
{"dbKey", self_info.db_key},
|
||||
};
|
||||
ret_data["data"] = j_info;
|
||||
}
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_SEND_TEXT: {
|
||||
wstring wxid = GetWStringParam(j_param, "wxid");
|
||||
wstring msg = GetWStringParam(j_param, "msg");
|
||||
int success = g_context.send_mgr->SendText(WS2LPWS(wxid), WS2LPWS(msg));
|
||||
json ret_data = {{"result", "OK"}, {"code", success}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_SEND_AT: {
|
||||
wstring chat_room_id = GetWStringParam(j_param, "chatRoomId");
|
||||
vector<wstring> wxids = getArrayParam(j_param, "wxids");
|
||||
wstring msg = GetWStringParam(j_param, "msg");
|
||||
vector<wchar_t *> wxid_list;
|
||||
for (unsigned int i = 0; i < wxids.size(); i++) {
|
||||
wxid_list.push_back(WS2LPWS(wxids[i]));
|
||||
}
|
||||
int success = g_context.send_mgr->SendAtText(WS2LPWS(chat_room_id), wxid_list.data(),
|
||||
wxid_list.size(), WS2LPWS(msg));
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_SEND_CARD: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_SEND_IMAGE: {
|
||||
wstring receiver = GetWStringParam(j_param, "wxid");
|
||||
wstring img_path = GetWStringParam(j_param, "imagePath");
|
||||
int success =
|
||||
g_context.send_mgr->SendImage(WS2LPWS(receiver), WS2LPWS(img_path));
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_SEND_FILE: {
|
||||
wstring receiver = GetWStringParam(j_param, "wxid");
|
||||
wstring file_path = GetWStringParam(j_param, "filePath");
|
||||
int success =
|
||||
g_context.send_mgr->SendFile(WS2LPWS(receiver), WS2LPWS(file_path));
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_SEND_ARTICLE: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_SEND_APP: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_START_HOOK: {
|
||||
int port = GetIntParam(j_param, "port");
|
||||
wstring ip = GetWStringParam(j_param, "ip");
|
||||
string client_ip = Utils::WstringToUTF8(ip);
|
||||
char ip_cstr[16];
|
||||
strcpy_s(ip_cstr, client_ip.c_str());
|
||||
int success = hooks::HookRecvMsg(ip_cstr, port);
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_STOP_HOOK: {
|
||||
int success = hooks::UnHookRecvMsg();
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_START_IMAGE_HOOK: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_STOP_IMAGE_HOOK: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_START_VOICE_HOOK: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_STOP_VOICE_HOOK: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_CONTACT_GET_LIST: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_CONTACT_CHECK_STATUS: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_CONTACT_DEL: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_CONTACT_SEARCH_BY_CACHE: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_CONTACT_SEARCH_BY_NET: {
|
||||
wstring keyword = GetWStringParam(j_param, "keyword");
|
||||
UserInfo *user = nullptr;
|
||||
int success = g_context.misc_mgr->SearchContactNetScene(WS2LPWS(keyword), &user);
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
if (user) {
|
||||
json info = {
|
||||
{"bigImage", Utils::WCharToUTF8(user->big_image)},
|
||||
{"smallImage", Utils::WCharToUTF8(user->small_image)},
|
||||
{"city", Utils::WCharToUTF8(user->city)},
|
||||
{"nation", Utils::WCharToUTF8(user->nation)},
|
||||
{"nickname", Utils::WCharToUTF8(user->nickname)},
|
||||
{"province", Utils::WCharToUTF8(user->province)},
|
||||
{"sex", user->sex},
|
||||
{"signature", Utils::WCharToUTF8(user->signature)},
|
||||
// {"v2", Utils::WCharToUTF8(user->v2)},
|
||||
{"v3", Utils::WCharToUTF8(user->v3)},
|
||||
{"V3", Utils::WCharToUTF8(user->V3)},
|
||||
{"account", Utils::WCharToUTF8(user->account)},
|
||||
// {"friendName", Utils::WCharToUTF8(user->friend_name)},
|
||||
// {"py", Utils::WCharToUTF8(user->py)},
|
||||
};
|
||||
ret_data["userInfo"] = info;
|
||||
}
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_CONTACT_ADD_BY_WXID: {
|
||||
wstring user_id = GetWStringParam(j_param, "wxid");
|
||||
wstring msg = GetWStringParam(j_param, "msg");
|
||||
int success = g_context.contact_mgr->AddFriendByWxid(WS2LPWS(user_id),WS2LPWS(msg));
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_CONTACT_ADD_BY_V3: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_CONTACT_ADD_BY_PUBLIC_ID: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_CONTACT_VERIFY_APPLY: {
|
||||
wstring v3 = GetWStringParam(j_param, "v3");
|
||||
wstring v4 = GetWStringParam(j_param, "v4");
|
||||
int permission = GetIntParam(j_param, "permission");
|
||||
int success = g_context.contact_mgr->VerifyApply(WS2LPWS(v3),WS2LPWS(v4),permission);
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_CONTACT_EDIT_REMARK: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_CHATROOM_GET_MEMBER_LIST: {
|
||||
wstring room_id = GetWStringParam(j_param, "chatRoomId");
|
||||
ChatRoomInner out{0};
|
||||
int success = g_context.chat_room_mgr->GetMemberFromChatRoom(WS2LPWS(room_id), out);
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
if (success) {
|
||||
json member_info = {
|
||||
{"admin", Utils::WstringToUTF8(out.admin)},
|
||||
{"chatRoomId", Utils::WstringToUTF8(out.chat_room)},
|
||||
{"members", out.members},
|
||||
};
|
||||
ret_data["data"] = member_info;
|
||||
}
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_CHATROOM_GET_MEMBER_NICKNAME: {
|
||||
wstring room_id = GetWStringParam(j_param, "chatRoomId");
|
||||
wstring member_id = GetWStringParam(j_param, "memberId");
|
||||
|
||||
wstring nickname =g_context.chat_room_mgr->GetChatRoomMemberNickname(
|
||||
WS2LPWS(room_id), WS2LPWS(member_id));
|
||||
json ret_data = {{"code", 1},
|
||||
{"result", "OK"},
|
||||
{"nickname", Utils::WstringToUTF8(nickname)}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_CHATROOM_DEL_MEMBER: {
|
||||
wstring room_id = GetWStringParam(j_param, "chatRoomId");
|
||||
vector<wstring> wxids = getArrayParam(j_param, "memberIds");
|
||||
vector<wchar_t *> wxid_list;
|
||||
for (unsigned int i = 0; i < wxids.size(); i++) {
|
||||
wxid_list.push_back(WS2LPWS(wxids[i]));
|
||||
}
|
||||
int success = g_context.chat_room_mgr->DelMemberFromChatRoom(
|
||||
WS2LPWS(room_id), wxid_list.data(), wxid_list.size());
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_CHATROOM_ADD_MEMBER: {
|
||||
wstring room_id = GetWStringParam(j_param, "chatRoomId");
|
||||
vector<wstring> wxids = getArrayParam(j_param, "memberIds");
|
||||
vector<wchar_t *> wxid_list;
|
||||
for (unsigned int i = 0; i < wxids.size(); i++) {
|
||||
wxid_list.push_back(WS2LPWS(wxids[i]));
|
||||
}
|
||||
int success = g_context.chat_room_mgr->AddMemberToChatRoom(
|
||||
WS2LPWS(room_id), wxid_list.data(), wxid_list.size());
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_CHATROOM_SET_ANNOUNCEMENT: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_CHATROOM_SET_CHATROOM_NAME: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_CHATROOM_SET_SELF_NICKNAME: {
|
||||
wstring room_id = GetWStringParam(j_param, "chatRoomId");
|
||||
wstring wxid = GetWStringParam(j_param, "wxid");
|
||||
wstring nick = GetWStringParam(j_param, "nickName");
|
||||
int success = g_context.chat_room_mgr->ModChatRoomMemberNickName(
|
||||
WS2LPWS(room_id), WS2LPWS(wxid), WS2LPWS(nick));
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_DATABASE_GET_HANDLES: {
|
||||
vector<void *> v_ptr = DB::GetInstance().GetDbHandles();
|
||||
json ret_data = {{"data", json::array()}, {"result", "OK"}};
|
||||
for (unsigned int i = 0; i < v_ptr.size(); i++) {
|
||||
json db_info;
|
||||
db_info["tables"] = json::array();
|
||||
DatabaseInfo *db = reinterpret_cast<DatabaseInfo *>(v_ptr[i]);
|
||||
db_info["handle"] = db->handle;
|
||||
wstring dbname(db->db_name);
|
||||
db_info["databaseName"] = Utils::WstringToUTF8(dbname);
|
||||
for (auto table : db->tables) {
|
||||
json table_info = {{"name", table.name},
|
||||
{"tableName", table.table_name},
|
||||
{"sql", table.sql},
|
||||
{"rootpage", table.rootpage}};
|
||||
db_info["tables"].push_back(table_info);
|
||||
}
|
||||
ret_data["data"].push_back(db_info);
|
||||
}
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_DATABASE_BACKUP: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_DATABASE_QUERY: {
|
||||
DWORD db_handle = GetIntParam(j_param, "dbHandle");
|
||||
wstring sql = GetWStringParam(j_param, "sql");
|
||||
string sql_str = Utils::WstringToUTF8(sql);
|
||||
vector<vector<string>> items;
|
||||
int success = DB::GetInstance().Select(db_handle, sql_str.c_str(), items);
|
||||
json ret_data = {
|
||||
{"data", json::array()}, {"code", success}, {"result", "OK"}};
|
||||
if (success == 0) {
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
for (auto it : items) {
|
||||
json temp_arr = json::array();
|
||||
for (size_t i = 0; i < it.size(); i++) {
|
||||
temp_arr.push_back(it[i]);
|
||||
}
|
||||
ret_data["data"].push_back(temp_arr);
|
||||
}
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_SET_VERSION: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_LOG_START_HOOK: {
|
||||
int success = hooks::HookLog();
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_LOG_STOP_HOOK: {
|
||||
int success = hooks::UnHookLog();
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_BROWSER_OPEN_WITH_URL: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_GET_PUBLIC_MSG: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_FORWARD_MESSAGE: {
|
||||
wstring wxid = GetWStringParam(j_param, "wxid");
|
||||
ULONG64 msgid = GetULong64Param(j_param, "msgid");
|
||||
int success =g_context.send_mgr->ForwardMsg(WS2LPWS(wxid), msgid);
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_GET_QRCODE_IMAGE: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_GET_A8KEY: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_MSG_SEND_XML: {
|
||||
break;
|
||||
}
|
||||
case WECHAT_LOGOUT: {
|
||||
int success = g_context.account_mgr->Logout();
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_GET_TRANSFER: {
|
||||
wstring wxid = GetWStringParam(j_param, "wxid");
|
||||
wstring transcationid = GetWStringParam(j_param, "transcationId");
|
||||
wstring transferid = GetWStringParam(j_param, "transferId");
|
||||
BOOL response =g_context.misc_mgr->DoConfirmReceipt(
|
||||
WS2LPWS(wxid), WS2LPWS(transcationid), WS2LPWS(transferid));
|
||||
json ret_data = {{"msg", response}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_GET_CONTACT_ALL: {
|
||||
vector<Contact> vec;
|
||||
int success = g_context.contact_mgr->GetAllContact(vec);
|
||||
json ret_data = {
|
||||
{"data", json::array()}, {"code", success}, {"result", "OK"}};
|
||||
|
||||
for (unsigned int i = 0; i < vec.size(); i++) {
|
||||
json item = {
|
||||
{"customAccount",
|
||||
vec[i].custom_account.length > 0
|
||||
? vec[i].custom_account.ptr != nullptr
|
||||
? Utils::WCharToUTF8(vec[i].custom_account.ptr)
|
||||
: string()
|
||||
: string()},
|
||||
{"delFlag", vec[i].del_flag},
|
||||
{"userName", vec[i].encrypt_name.length > 0
|
||||
? vec[i].encrypt_name.ptr != nullptr
|
||||
? Utils::WCharToUTF8(vec[i].encrypt_name.ptr)
|
||||
: string()
|
||||
: string()},
|
||||
{"type", vec[i].type},
|
||||
{"verifyFlag", vec[i].verify_flag},
|
||||
{"verifyFlag", vec[i].verify_flag},
|
||||
{"wxid", vec[i].wxid.length > 0
|
||||
? Utils::WCharToUTF8(vec[i].wxid.ptr)
|
||||
: string()},
|
||||
};
|
||||
ret_data["data"].push_back(item);
|
||||
}
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_GET_CHATROOM_INFO: {
|
||||
wstring room_id = GetWStringParam(j_param, "chatRoomId");
|
||||
ChatRoomInfoInner chat_room_detail{0};
|
||||
int success = g_context.chat_room_mgr->GetChatRoomDetailInfo(WS2LPWS(room_id),
|
||||
chat_room_detail);
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
if (!success) {
|
||||
break;
|
||||
}
|
||||
json detail = {
|
||||
{"chatRoomId",
|
||||
chat_room_detail.chat_room_id.length > 0
|
||||
? Utils::WCharToUTF8(chat_room_detail.chat_room_id.ptr)
|
||||
: string()},
|
||||
{"notice", chat_room_detail.notice.length > 0
|
||||
? Utils::WCharToUTF8(chat_room_detail.notice.ptr)
|
||||
: string()},
|
||||
{"admin", chat_room_detail.admin.length > 0
|
||||
? Utils::WCharToUTF8(chat_room_detail.admin.ptr)
|
||||
: string()},
|
||||
{"xml", chat_room_detail.xml.length > 0
|
||||
? Utils::WCharToUTF8(chat_room_detail.xml.ptr)
|
||||
: string()},
|
||||
};
|
||||
ret_data["data"] = detail;
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_GET_IMG_BY_NAME: {
|
||||
wstring image_path = GetWStringParam( j_param, "imagePath");
|
||||
wstring save_path = GetWStringParam( j_param, "savePath");
|
||||
int success =
|
||||
g_context.misc_mgr->GetImgByName(WS2LPWS(image_path),WS2LPWS(save_path)); json
|
||||
ret_data = {{"code", success}, {"result", "OK"}}; ret =
|
||||
ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_DO_OCR: {
|
||||
wstring image_path = GetWStringParam(j_param, "imagePath");
|
||||
string text("");
|
||||
int success = g_context.misc_mgr->DoOCRTask(WS2LPWS(image_path), text);
|
||||
json ret_data = {{"code", success}, {"result", "OK"}, {"text", text}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_SEND_PAT_MSG: {
|
||||
wstring room_id = GetWStringParam(j_param, "chatRoomId");
|
||||
wstring wxid = GetWStringParam(j_param, "wxid");
|
||||
int success = g_context.misc_mgr->SendPatMsg(WS2LPWS(room_id), WS2LPWS(wxid));
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_SET_TOP_MSG: {
|
||||
wstring wxid = GetWStringParam(j_param, "wxid");
|
||||
ULONG64 msgid = GetULong64Param(j_param, "msgid");
|
||||
int success = g_context.chat_room_mgr->SetTopMsg(WS2LPWS(wxid), msgid);
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_REMOVE_TOP_MSG: {
|
||||
wstring room_id = GetWStringParam(j_param, "chatRoomId");
|
||||
ULONG64 msgid = GetULong64Param(j_param, "msgid");
|
||||
int success = g_context.chat_room_mgr->RemoveTopMsg(WS2LPWS(room_id), msgid);
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_SNS_GET_FIRST_PAGE: {
|
||||
int success = g_context.sns_mgr->GetFirstPage();
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_SNS_GET_NEXT_PAGE: {
|
||||
ULONG64 snsid = GetULong64Param(j_param, "snsId");
|
||||
int success = g_context.sns_mgr->GetNextPage(snsid);
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_CONTACT_NAME: {
|
||||
wstring pri_id = GetWStringParam(j_param, "id");
|
||||
wstring name = g_context.contact_mgr->GetContactOrChatRoomNickname(WS2LPWS(pri_id));
|
||||
json ret_data = {
|
||||
{"code", 1}, {"result", "OK"}, {"name", Utils::WstringToUTF8(name)}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_ATTACH_DOWNLOAD: {
|
||||
ULONG64 msg_id = GetULong64Param(j_param, "msgId");
|
||||
int success = g_context.misc_mgr->DoDownloadTask(msg_id);
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_GET_VOICE: {
|
||||
ULONG64 msg_id = GetULong64Param(j_param, "msgId");
|
||||
wstring voice_dir = GetWStringParam(j_param, "voiceDir");
|
||||
int success = g_context.misc_mgr->GetVoice(msg_id, WS2LPWS(voice_dir));
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_GET_QRCODE: {
|
||||
string url = g_context.account_mgr->GetQRCodeUrl();
|
||||
json ret_data = {{"code", 1}, {"result", "OK"},{"qrCodeUrl",url}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
case WECHAT_INVITE_MEMBERS: {
|
||||
wstring room_id = GetWStringParam(j_param, "chatRoomId");
|
||||
vector<wstring> wxids = getArrayParam(j_param, "memberIds");
|
||||
vector<wchar_t *> wxid_list;
|
||||
for (unsigned int i = 0; i < wxids.size(); i++) {
|
||||
wxid_list.push_back(WS2LPWS(wxids[i]));
|
||||
}
|
||||
int success = g_context.chat_room_mgr->InviteMemberToChatRoom(
|
||||
WS2LPWS(room_id), wxid_list.data(), wxid_list.size());
|
||||
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||
ret = ret_data.dump();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
HttpHandler::HttpHandler() {}
|
||||
HttpHandler::~HttpHandler() {}
|
||||
void HttpHandler::HandlerRequest(struct mg_connection *c, void *ev_data) {
|
||||
struct mg_http_message *hm = (struct mg_http_message *)ev_data;
|
||||
string ret = R"({"result":"OK"})";
|
||||
if (mg_http_match_uri(hm, "/api/")) {
|
||||
try {
|
||||
ret = Dispatch(c, hm);
|
||||
} catch (json::exception &e) {
|
||||
json res = {{"result", "ERROR"}, {"msg", e.what()}};
|
||||
ret = res.dump();
|
||||
}
|
||||
if (ret != "") {
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "%s\n", ret.c_str());
|
||||
}
|
||||
} else {
|
||||
mg_http_reply(c, 500, NULL, "%s", "Invalid URI");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace wxhelper
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef WXHELPER_HTTP_HANDLER_H_
|
||||
#define WXHELPER_HTTP_HANDLER_H_
|
||||
#include "handler.h"
|
||||
#include "mongoose.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <nlohmann/json.hpp>
|
||||
namespace wxhelper {
|
||||
class HttpHandler : public Handler {
|
||||
public:
|
||||
HttpHandler();
|
||||
~HttpHandler();
|
||||
void HandlerRequest(struct mg_connection *c, void *ev_data);
|
||||
};
|
||||
|
||||
} // namespace wxhelper
|
||||
#endif
|
||||
@@ -0,0 +1,100 @@
|
||||
#include "pch.h"
|
||||
#include "http_server.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include "api_route.h"
|
||||
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
using namespace std;
|
||||
using namespace nlohmann;
|
||||
|
||||
namespace wxhelper {
|
||||
HttpServer& HttpServer::GetInstance() {
|
||||
static HttpServer p;
|
||||
return p;
|
||||
}
|
||||
|
||||
void HttpServer::Init(int port) {
|
||||
port_ = port;
|
||||
running_ = false;
|
||||
http_handler_ = new HttpHandler();
|
||||
mg_mgr_init(&mgr_);
|
||||
|
||||
}
|
||||
|
||||
HttpServer::~HttpServer() {
|
||||
mg_mgr_free(&mgr_);
|
||||
delete http_handler_;
|
||||
}
|
||||
|
||||
bool HttpServer::HttpStart() {
|
||||
if (running_) {
|
||||
return true;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
Utils::CreateConsole();
|
||||
#endif
|
||||
running_ = true;
|
||||
thread_ = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)StartHttpServer, NULL,
|
||||
NULL, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
void HttpServer::StartHttpServer() {
|
||||
string lsten_addr = "http://0.0.0.0:" + to_string(GetInstance().port_);
|
||||
mg_http_listen(&GetInstance().mgr_, lsten_addr.c_str(), EventHandler,
|
||||
&GetInstance().mgr_);
|
||||
for (;;) mg_mgr_poll(&GetInstance().mgr_, 1000);
|
||||
}
|
||||
|
||||
void HttpServer::EventHandler(struct mg_connection *c,
|
||||
int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_OPEN) {
|
||||
// c->is_hexdumping = 1;
|
||||
} else if (ev == MG_EV_HTTP_MSG) {
|
||||
struct mg_http_message *hm = (struct mg_http_message *)ev_data;
|
||||
if (mg_http_match_uri(hm, "/websocket")) {
|
||||
mg_ws_upgrade(c, hm, NULL);
|
||||
} else if (mg_http_match_uri(hm, "/api/")) {
|
||||
GetInstance().HandleHttpRequest(c,hm);
|
||||
} else {
|
||||
mg_http_reply(c, 500, NULL, "%s", "Invalid URI");
|
||||
}
|
||||
} else if (ev == MG_EV_WS_MSG) {
|
||||
|
||||
GetInstance().HandleWebsocketRequest(c,ev_data);
|
||||
}
|
||||
(void)fn_data;
|
||||
}
|
||||
|
||||
void HttpServer::HandleHttpRequest(struct mg_connection *c,
|
||||
void *ev_data) {
|
||||
|
||||
http_handler_->HandlerRequest(c,ev_data);
|
||||
}
|
||||
|
||||
void HttpServer::HandleWebsocketRequest(struct mg_connection *c,
|
||||
void *ev_data) {
|
||||
// Got websocket frame. Received data is wm->data. Echo it back!
|
||||
struct mg_ws_message *wm = (struct mg_ws_message *)ev_data;
|
||||
mg_ws_send(c, wm->data.ptr, wm->data.len, WEBSOCKET_OP_TEXT);
|
||||
}
|
||||
|
||||
bool HttpServer::HttpClose() {
|
||||
if (!running_) {
|
||||
return true;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
Utils::CloseConsole();
|
||||
#endif
|
||||
running_ = false;
|
||||
if (thread_) {
|
||||
WaitForSingleObject(thread_, -1);
|
||||
CloseHandle(thread_);
|
||||
thread_ = NULL;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace wxhelper
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef WXHELPER_HTTP_SERVER_H_
|
||||
#define WXHELPER_HTTP_SERVER_H_
|
||||
|
||||
#include <mongoose.h>
|
||||
|
||||
#include "http_handler.h"
|
||||
namespace wxhelper {
|
||||
class HttpServer {
|
||||
public:
|
||||
static HttpServer &GetInstance();
|
||||
bool HttpStart();
|
||||
bool HttpClose();
|
||||
void Init(int port);
|
||||
|
||||
private:
|
||||
HttpServer(){};
|
||||
HttpServer(const HttpServer &) = delete;
|
||||
HttpServer &operator=(const HttpServer &) = delete;
|
||||
~HttpServer();
|
||||
static void StartHttpServer();
|
||||
static void EventHandler(struct mg_connection *c, int ev, void *ev_data,
|
||||
void *fn_data);
|
||||
void HandleHttpRequest(struct mg_connection *c, void *ev_data);
|
||||
void HandleWebsocketRequest(struct mg_connection *c, void *ev_data);
|
||||
|
||||
private:
|
||||
int port_;
|
||||
bool running_;
|
||||
struct mg_mgr mgr_;
|
||||
HttpHandler *http_handler_;
|
||||
HANDLE thread_;
|
||||
};
|
||||
} // namespace wxhelper
|
||||
|
||||
#endif
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
#include "pch.h"
|
||||
#include "log.h"
|
||||
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO
|
||||
namespace wxhelper {
|
||||
Log::Log(/* args */) {}
|
||||
|
||||
Log::~Log() {
|
||||
|
||||
}
|
||||
|
||||
void Log::Initialize() {
|
||||
auto logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 23, 59);
|
||||
logger->flush_on(spdlog::level::err);
|
||||
spdlog::set_default_logger(logger);
|
||||
spdlog::flush_every(std::chrono::seconds(3));
|
||||
spdlog::set_level(spdlog::level::debug);
|
||||
spdlog::set_pattern("%Y-%m-%d %H:%M:%S [%l] [%t] - <%s>|<%#>|<%!>,%v");
|
||||
}
|
||||
|
||||
} // namespace wxhelper
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef WXHELPER_LOG_H_
|
||||
#define WXHELPER_LOG_H_
|
||||
namespace wxhelper{
|
||||
class Log
|
||||
{
|
||||
private:
|
||||
/* data */
|
||||
public:
|
||||
Log(/* args */);
|
||||
~Log();
|
||||
void Initialize();
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+418
@@ -0,0 +1,418 @@
|
||||
#include "misc_mgr.h"
|
||||
|
||||
#include "pch.h"
|
||||
#include "wechat_function.h"
|
||||
#include "base64.h"
|
||||
#include "db.h"
|
||||
#include "hooks.h"
|
||||
#define BUFSIZE 1024
|
||||
|
||||
#define JPEG0 0xFF
|
||||
#define JPEG1 0xD8
|
||||
#define JPEG2 0xFF
|
||||
#define PNG0 0x89
|
||||
#define PNG1 0x50
|
||||
#define PNG2 0x4E
|
||||
#define BMP0 0x42
|
||||
#define BMP1 0x4D
|
||||
#define GIF0 0x47
|
||||
#define GIF1 0x49
|
||||
#define GIF2 0x46
|
||||
using namespace std;
|
||||
namespace wxhelper {
|
||||
MiscMgr::MiscMgr(DWORD base) : BaseMgr::BaseMgr(base) {}
|
||||
MiscMgr::~MiscMgr() {}
|
||||
int MiscMgr::SendPatMsg(wchar_t *chat_room_id, wchar_t *wxid) {
|
||||
int success = -1;
|
||||
WeChatString chat_room(chat_room_id);
|
||||
WeChatString self_wxid(wxid);
|
||||
DWORD get_pat_mgr_addr = base_addr_ + WX_PAT_MGR_OFFSET;
|
||||
DWORD send_pat_msg_addr = base_addr_ + WX_SEND_PAT_MSG_OFFSET;
|
||||
DWORD ret_addr = base_addr_ + WX_RET_OFFSET;
|
||||
__asm {
|
||||
PUSHAD
|
||||
CALL get_pat_mgr_addr
|
||||
PUSH ret_addr
|
||||
PUSH 0x0
|
||||
PUSH EAX
|
||||
LEA ECX,chat_room
|
||||
LEA EDX,self_wxid
|
||||
CALL send_pat_msg_addr
|
||||
ADD ESP,0xc
|
||||
MOVZX EAX,AL
|
||||
MOV success,EAX
|
||||
POPAD
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
int MiscMgr::DoOCRTask(wchar_t *img_path, std::string &result) {
|
||||
int success = -1;
|
||||
WeChatString path(img_path);
|
||||
WeChatString null_obj = {0};
|
||||
WeChatString ocr_result = {0};
|
||||
DWORD ocr_manager_addr = base_addr_ + WX_OCR_MANAGER_OFFSET;
|
||||
DWORD do_ocr_task_addr = base_addr_ + WX_DO_OCR_TASK_OFFSET;
|
||||
DWORD init_addr = base_addr_ + WX_INIT_OBJ_OFFSET;
|
||||
DWORD flag = 0;
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
LEA ECX,ocr_result
|
||||
CALL init_addr
|
||||
CALL ocr_manager_addr
|
||||
LEA ECX,null_obj
|
||||
PUSH ECX
|
||||
LEA ECX,flag
|
||||
PUSH ECX
|
||||
LEA ECX,ocr_result
|
||||
PUSH ECX
|
||||
PUSH 0x0
|
||||
LEA ECX,path
|
||||
PUSH ECX
|
||||
MOV ECX,EAX
|
||||
CALL do_ocr_task_addr
|
||||
MOV success,EAX
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
|
||||
if (success == 0) {
|
||||
DWORD addr = (DWORD)&ocr_result;
|
||||
DWORD ptr = *(DWORD *)addr;
|
||||
DWORD num = *(DWORD *)(addr + 0x4);
|
||||
if (num <= 0) {
|
||||
return success;
|
||||
}
|
||||
|
||||
DWORD header = *(DWORD *)ptr;
|
||||
for (unsigned int i = 0; i < num - 1; i++) {
|
||||
DWORD content = *(DWORD *)header;
|
||||
result += Utils::WstringToUTF8(READ_WSTRING(content, 0x14));
|
||||
result += "\r\n";
|
||||
header = content;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
int MiscMgr::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 new_pay_info_addr = base_addr_ + WX_NEW_WCPAYINFO_OFFSET;
|
||||
DWORD free_pay_info_addr = base_addr_ + WX_FREE_WCPAYINFO_OFFSET;
|
||||
DWORD do_confirm_addr = base_addr_ + 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;
|
||||
}
|
||||
|
||||
int MiscMgr::DoDownloadTask(ULONG64 msg_id) {
|
||||
int success = -1;
|
||||
int db_index = 0;
|
||||
int local_id = DB::GetInstance().GetLocalIdByMsgId(msg_id, db_index);
|
||||
if (local_id < 1) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
char chat_msg[0x2D8] = {0};
|
||||
DWORD new_chat_msg_addr = base_addr_ + WX_NEW_CHAT_MSG_OFFSET;
|
||||
DWORD get_chat_mgr_addr = base_addr_ + WX_CHAT_MGR_OFFSET;
|
||||
DWORD pre_download_mgr_addr = base_addr_ + WX_GET_PRE_DOWNLOAD_MGR_OFFSET;
|
||||
DWORD push_attach_task_addr = base_addr_ + WX_PUSH_ATTACH_TASK_OFFSET;
|
||||
DWORD free_addr = base_addr_ + WX_FREE_CHAT_MSG_INSTANCE_COUNTER_OFFSET;
|
||||
DWORD get_by_local_Id_addr = base_addr_ + WX_GET_MGR_BY_PREFIX_LOCAL_ID_OFFSET;
|
||||
DWORD get_current_data_path_addr = base_addr_ + WX_GET_CURRENT_DATA_PATH_OFFSET;
|
||||
DWORD free_app_msg_info_addr = base_addr_ + WX_FREE_APP_MSG_INFO_OFFSET;
|
||||
DWORD push_thumb_task_addr = base_addr_ + WX_PUSH_THUMB_TASK_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 (!Utils::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 (!Utils::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 (!Utils::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 (!Utils::FindOrCreateDirectoryW(save_path.c_str())) {
|
||||
return -3;
|
||||
}
|
||||
char xml_app_msg[0xC80] = {0};
|
||||
DWORD new_app_msg_addr = base_addr_ + WX_APP_MSG_INFO_OFFSET;
|
||||
DWORD get_xml_addr = base_addr_ + 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[0x29C], &temp, sizeof(temp));
|
||||
|
||||
__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;
|
||||
}
|
||||
|
||||
int MiscMgr::GetVoice(ULONG64 msg_id, wchar_t *dir) {
|
||||
int success = -1;
|
||||
string buff = DB::GetInstance().GetVoiceBuffByMsgId(msg_id);
|
||||
if (buff.size() == 0) {
|
||||
success = 0;
|
||||
return success;
|
||||
}
|
||||
wstring save_path = wstring(dir);
|
||||
if (!Utils::FindOrCreateDirectoryW(save_path.c_str())) {
|
||||
success = -2;
|
||||
return success;
|
||||
}
|
||||
save_path = save_path + L"\\" + to_wstring(msg_id) + 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) {
|
||||
#ifdef _DEBUG
|
||||
wcout <<" save_path =" <<save_path<<endl;
|
||||
#endif
|
||||
return success;
|
||||
}
|
||||
DWORD bytes_write = 0;
|
||||
string decode = base64_decode(buff);
|
||||
WriteFile(file_handle, (LPCVOID)decode.c_str(), decode.size(), &bytes_write, 0);
|
||||
CloseHandle(file_handle);
|
||||
success = 1;
|
||||
return success;
|
||||
}
|
||||
|
||||
int MiscMgr::GetImgByName(wchar_t* file_path,wchar_t* save_dir) {
|
||||
wstring save_path(save_dir);
|
||||
wstring orign_file_path(file_path);
|
||||
if (!Utils::FindOrCreateDirectoryW(save_path.c_str())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pos_begin = orign_file_path.find_last_of(L"\\") + 1;
|
||||
int pos_end = orign_file_path.find_last_of(L".");
|
||||
wstring file_name = orign_file_path.substr(pos_begin, pos_end - pos_begin);
|
||||
HANDLE h_origin_file =
|
||||
CreateFileW(file_path, GENERIC_READ, 0, NULL, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
char buffer[BUFSIZE] = {0};
|
||||
DWORD bytes_read = 0;
|
||||
DWORD bytes_write = 0;
|
||||
unsigned char magic_head[4] = {0};
|
||||
wstring suffix;
|
||||
short key = 0;
|
||||
if (ReadFile(h_origin_file, buffer, BUFSIZE, &bytes_read, NULL)) {
|
||||
memcpy(magic_head, buffer, 3);
|
||||
} else {
|
||||
CloseHandle(h_origin_file);
|
||||
return 0;
|
||||
}
|
||||
if ((magic_head[0] ^ JPEG0) == (magic_head[1] ^ JPEG1)) {
|
||||
key = magic_head[0] ^ JPEG0;
|
||||
suffix = L".jpg";
|
||||
} else if ((magic_head[0] ^ PNG1) == (magic_head[1] ^ PNG2)) {
|
||||
key = magic_head[0] ^ PNG1;
|
||||
suffix = L".png";
|
||||
} else if ((magic_head[0] ^ GIF0) == (magic_head[1] ^ GIF1)) {
|
||||
key = magic_head[0] ^ GIF0;
|
||||
suffix = L".gif";
|
||||
} else if ((magic_head[0] ^ BMP0) == (magic_head[1] ^ BMP1)) {
|
||||
key = magic_head[0] ^ BMP0;
|
||||
suffix = L".bmp";
|
||||
} else {
|
||||
key = -1;
|
||||
suffix = L".dat";
|
||||
}
|
||||
wstring save_img_path = save_path + L"\\" + file_name + suffix;
|
||||
HANDLE save_img = CreateFileW(save_img_path.c_str(), GENERIC_ALL, 0, NULL,
|
||||
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (save_img == INVALID_HANDLE_VALUE) {
|
||||
return 0;
|
||||
}
|
||||
if (key > 0) {
|
||||
for (unsigned int i = 0; i < bytes_read; i++) {
|
||||
buffer[i]^=key;
|
||||
}
|
||||
}
|
||||
if (!WriteFile(save_img, (LPCVOID)buffer, bytes_read, &bytes_write, 0)) {
|
||||
CloseHandle(h_origin_file);
|
||||
CloseHandle(save_img);
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
if (ReadFile(h_origin_file, buffer, BUFSIZE, &bytes_read, NULL)) {
|
||||
if (key > 0) {
|
||||
for (unsigned int i = 0; i < bytes_read; i++) {
|
||||
buffer[i] ^= key;
|
||||
}
|
||||
}
|
||||
if (!WriteFile(save_img, (LPCVOID)buffer, bytes_read, &bytes_write, 0)) {
|
||||
CloseHandle(h_origin_file);
|
||||
CloseHandle(save_img);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} while (bytes_read == BUFSIZE);
|
||||
CloseHandle(h_origin_file);
|
||||
CloseHandle(save_img);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int MiscMgr::SearchContactNetScene(wchar_t *keyword,UserInfo ** user) {
|
||||
int success = -1;
|
||||
hooks::DeleteUserInfoCache();
|
||||
hooks::HookSearchContact();
|
||||
DWORD search_contact_mgr_addr = base_addr_ + WX_SEARCH_CONTACT_MGR_OFFSET;
|
||||
DWORD search_contact_addr = base_addr_ + WX_SEARCH_CONTACT_OFFSET;
|
||||
WeChatString key(keyword);
|
||||
|
||||
__asm {
|
||||
pushad;
|
||||
pushfd;
|
||||
call search_contact_mgr_addr;
|
||||
lea ebx, key;
|
||||
push ebx;
|
||||
mov ecx, eax;
|
||||
call search_contact_addr;
|
||||
popfd;
|
||||
popad;
|
||||
}
|
||||
success = 1;
|
||||
// while (hooks::userinfo.error_code == 1 && hooks::user_info_flag_) {
|
||||
// Sleep(20);
|
||||
// }
|
||||
// if (hooks::userinfo.error_code == 0) {
|
||||
while (hooks::userinfo.over == false && hooks::user_info_flag_) {
|
||||
Sleep(2);
|
||||
}
|
||||
// }
|
||||
*user= &hooks::userinfo;
|
||||
return success;
|
||||
}
|
||||
|
||||
} // namespace wxhelper
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef WXHELPER_MISC_MGR_H_
|
||||
#define WXHELPER_MISC_MGR_H_
|
||||
#include <string>
|
||||
#include "Windows.h"
|
||||
#include "base_mgr.h"
|
||||
#include "wechat_function.h"
|
||||
namespace wxhelper {
|
||||
class MiscMgr :public BaseMgr{
|
||||
public:
|
||||
MiscMgr(DWORD base);
|
||||
~MiscMgr();
|
||||
int SendPatMsg(wchar_t* chat_room_id, wchar_t* wxid);
|
||||
int DoOCRTask(wchar_t* img_path, std::string& result);
|
||||
int DoConfirmReceipt(wchar_t* wxid, wchar_t* transcationid,
|
||||
wchar_t* transferid);
|
||||
int DoDownloadTask(ULONG64 msg_id);
|
||||
|
||||
int GetVoice(ULONG64 msg_id, wchar_t* dir);
|
||||
int GetImgByName(wchar_t* file_path,wchar_t* save_dir);
|
||||
int SearchContactNetScene(wchar_t *keyword,UserInfo ** user);
|
||||
};
|
||||
} // namespace wxhelper
|
||||
|
||||
#endif
|
||||
+18
-18
@@ -135,24 +135,24 @@
|
||||
#define SQLITE_NULL 5
|
||||
#define SQLITE_TEXT 3
|
||||
|
||||
#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
|
||||
#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**);
|
||||
|
||||
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "ocr.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "wechat_data.h"
|
||||
|
||||
#define WX_INIT_OBJ_OFFSET 0x7a98f0
|
||||
#define WX_OCR_MANAGER_OFFSET 0x7ae470
|
||||
#define WX_DO_OCR_TASK_OFFSET 0x13230c0
|
||||
using namespace std;
|
||||
int DoOCRTask(wchar_t *img_path, std::string &result) {
|
||||
int success = -1;
|
||||
WeChatString path(img_path);
|
||||
WeChatString null_obj = {0};
|
||||
WeChatString ocr_result = {0};
|
||||
DWORD base = GetWeChatWinBase();
|
||||
DWORD ocr_manager_addr = base + WX_OCR_MANAGER_OFFSET;
|
||||
DWORD do_ocr_task_addr = base + WX_DO_OCR_TASK_OFFSET;
|
||||
DWORD init_addr = base + WX_INIT_OBJ_OFFSET;
|
||||
DWORD flag = 0;
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
LEA ECX,ocr_result
|
||||
CALL init_addr
|
||||
CALL ocr_manager_addr
|
||||
LEA ECX,null_obj
|
||||
PUSH ECX
|
||||
LEA ECX,flag
|
||||
PUSH ECX
|
||||
LEA ECX,ocr_result
|
||||
PUSH ECX
|
||||
PUSH 0x0
|
||||
LEA ECX,path
|
||||
PUSH ECX
|
||||
MOV ECX,EAX
|
||||
CALL do_ocr_task_addr
|
||||
MOV success,EAX
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
|
||||
if (success == 0) {
|
||||
DWORD addr = (DWORD)&ocr_result;
|
||||
DWORD ptr = *(DWORD *)addr;
|
||||
DWORD num = *(DWORD *)(addr + 0x4);
|
||||
if (num <= 0) {
|
||||
return success;
|
||||
}
|
||||
|
||||
DWORD header = *(DWORD *)ptr;
|
||||
for (unsigned int i = 0; i < num -1; i++) {
|
||||
DWORD content = *(DWORD *)header;
|
||||
result += unicode_to_utf8((wchar_t *)READ_WSTRING(content, 0x14).c_str());
|
||||
|
||||
header = content;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
cout << "num:" << num << endl;
|
||||
cout << "all:" << result << endl;
|
||||
#endif
|
||||
}
|
||||
return success;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#ifndef OCR_H_
|
||||
#define OCR_H_
|
||||
#include <string>
|
||||
int DoOCRTask(wchar_t* img_path,std::string &result);
|
||||
#endif
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "pat.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "wechat_data.h"
|
||||
|
||||
#define WX_PAT_MGR_OFFSET 0x8d0c00
|
||||
#define WX_SEND_PAT_MSG_OFFSET 0x1369850
|
||||
#define WX_RET_OFFSET 0x1C94D34
|
||||
|
||||
int SendPatMsg(wchar_t* chat_room_id, wchar_t* wxid) {
|
||||
int success = -1;
|
||||
WeChatString chat_room(chat_room_id);
|
||||
WeChatString self_wxid(wxid);
|
||||
DWORD base = GetWeChatWinBase();
|
||||
DWORD get_pat_mgr_addr = base + WX_PAT_MGR_OFFSET;
|
||||
DWORD send_pat_msg_addr = base + WX_SEND_PAT_MSG_OFFSET;
|
||||
DWORD ret_addr = base + WX_RET_OFFSET;
|
||||
__asm {
|
||||
PUSHAD
|
||||
CALL get_pat_mgr_addr
|
||||
PUSH ret_addr
|
||||
PUSH 0x0
|
||||
PUSH EAX
|
||||
LEA ECX,chat_room
|
||||
LEA EDX,self_wxid
|
||||
CALL send_pat_msg_addr
|
||||
ADD ESP,0xc
|
||||
MOVZX EAX,AL
|
||||
MOV success,EAX
|
||||
POPAD
|
||||
}
|
||||
return success;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
#ifndef PAT_H_
|
||||
#define PAT_H_
|
||||
int SendPatMsg(wchar_t* chat_room_id,wchar_t* wxid);
|
||||
#endif
|
||||
@@ -9,10 +9,19 @@
|
||||
#include <map>
|
||||
#include <strstream>
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include "Windows.h"
|
||||
#include "utils.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "spdlog/sinks/rotating_file_sink.h"
|
||||
#include "spdlog/sinks/daily_file_sink.h"
|
||||
#include "spdlog/sinks/stdout_color_sinks.h"
|
||||
|
||||
|
||||
#endif // PCH_H
|
||||
|
||||
|
||||
|
||||
@@ -1,162 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "self_info.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "wechat_data.h"
|
||||
using namespace std;
|
||||
|
||||
#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 0xdd5c90
|
||||
#define WX_ACCOUT_SERVICE_OFFSET 0x707960
|
||||
|
||||
int GetSelfInfo(SelfInfoInner &out) {
|
||||
DWORD base = GetWeChatWinBase();
|
||||
#ifdef _DEBUG
|
||||
cout << "mobile:" << (char *)(base + WX_SELF_MOBILE_OFFSET) << endl;
|
||||
cout << "name:" << (char *)(base + WX_SELF_NAME_OFFSET) << endl;
|
||||
cout << "city:" << (char *)(base + WX_SELF_CITY_OFFSET) << endl;
|
||||
cout << "city:" << (char *)(base + WX_SELF_CITY_OFFSET) << endl;
|
||||
cout << "province:" << (char *)(base + WX_SELF_PROVINCE_OFFSET) << endl;
|
||||
cout << "country:" << (char *)(base + WX_SELF_COUNTRY_OFFSET) << endl;
|
||||
cout << "account:" << (char *)(base + WX_SELF_ACCOUNT_OFFSET) << endl;
|
||||
cout << "wxid:" << (char *)(base + WX_SELF_ID_OFFSET) << endl;
|
||||
cout << "small_img:" << (char *)(base + WX_SELF_SMALL_IMG_OFFSET) << endl;
|
||||
cout << "big_img:" << (char *)(base + WX_SELF_BIG_IMG_OFFSET) << endl;
|
||||
#endif
|
||||
if (*(DWORD *)(base + WX_SELF_NAME_OFFSET) == 0 ||
|
||||
*(DWORD *)(base + WX_SELF_NAME_OFFSET + 0x10) == 0) {
|
||||
out.name = string();
|
||||
} else {
|
||||
out.name = string((char *)(base + WX_SELF_NAME_OFFSET),
|
||||
*(DWORD *)(base + WX_SELF_NAME_OFFSET + 0x10));
|
||||
}
|
||||
if (*(DWORD *)(base + WX_SELF_MOBILE_OFFSET) == 0 ||
|
||||
*(DWORD *)(base + WX_SELF_MOBILE_OFFSET + 0x10) == 0) {
|
||||
out.mobile = string();
|
||||
} else {
|
||||
out.mobile = string((char *)(base + WX_SELF_MOBILE_OFFSET),
|
||||
*(DWORD *)(base + WX_SELF_MOBILE_OFFSET + 0x10));
|
||||
}
|
||||
|
||||
if (*(DWORD *)(base + WX_SELF_CITY_OFFSET) == 0 ||
|
||||
*(DWORD *)(base + WX_SELF_CITY_OFFSET + 0x10) == 0) {
|
||||
out.city = string();
|
||||
} else {
|
||||
out.city = string((char *)(base + WX_SELF_CITY_OFFSET),
|
||||
*(DWORD *)(base + WX_SELF_CITY_OFFSET + 0x10));
|
||||
}
|
||||
|
||||
if (*(DWORD *)(base + WX_SELF_PROVINCE_OFFSET) == 0 ||
|
||||
*(DWORD *)(base + WX_SELF_PROVINCE_OFFSET + 0x10) == 0) {
|
||||
out.province = string();
|
||||
} else {
|
||||
out.province = string((char *)(base + WX_SELF_PROVINCE_OFFSET),
|
||||
*(DWORD *)(base + WX_SELF_PROVINCE_OFFSET + 0x10));
|
||||
}
|
||||
|
||||
if (*(DWORD *)(base + WX_SELF_COUNTRY_OFFSET) == 0 ||
|
||||
*(DWORD *)(base + WX_SELF_COUNTRY_OFFSET + 0x10) == 0) {
|
||||
out.country = string();
|
||||
} else {
|
||||
out.country = string((char *)(base + WX_SELF_COUNTRY_OFFSET),
|
||||
*(DWORD *)(base + WX_SELF_COUNTRY_OFFSET + 0x10));
|
||||
}
|
||||
|
||||
if (*(DWORD *)(base + WX_SELF_ACCOUNT_OFFSET) == 0 ||
|
||||
*(DWORD *)(base + WX_SELF_ACCOUNT_OFFSET + 0x10) == 0) {
|
||||
out.account = string();
|
||||
} else {
|
||||
out.account = string(*(char **)(base + WX_SELF_ACCOUNT_OFFSET),
|
||||
*(DWORD *)(base + WX_SELF_ACCOUNT_OFFSET + 0x10));
|
||||
}
|
||||
|
||||
if (*(DWORD *)(base + WX_SELF_ID_OFFSET) == 0 ||
|
||||
*(DWORD *)(base + WX_SELF_ID_OFFSET + 0x10) == 0) {
|
||||
out.wxid = string();
|
||||
} else {
|
||||
out.wxid = string(*(char **)(base + WX_SELF_ID_OFFSET),
|
||||
*(DWORD *)(base + WX_SELF_ID_OFFSET + 0x10));
|
||||
}
|
||||
|
||||
if (*(DWORD *)(base + WX_SELF_SMALL_IMG_OFFSET) == 0 ||
|
||||
*(DWORD *)(base + WX_SELF_SMALL_IMG_OFFSET + 0x10) == 0) {
|
||||
out.small_img = string();
|
||||
} else {
|
||||
out.small_img = string(*(char **)(base + WX_SELF_SMALL_IMG_OFFSET),
|
||||
*(DWORD *)(base + WX_SELF_SMALL_IMG_OFFSET + 0x10));
|
||||
}
|
||||
|
||||
if (*(DWORD *)(base + WX_SELF_BIG_IMG_OFFSET) == 0 ||
|
||||
*(DWORD *)(base + WX_SELF_BIG_IMG_OFFSET + 0x10) == 0) {
|
||||
out.big_img = string();
|
||||
} else {
|
||||
out.big_img = string(*(char **)(base + WX_SELF_BIG_IMG_OFFSET),
|
||||
*(DWORD *)(base + WX_SELF_BIG_IMG_OFFSET + 0x10));
|
||||
}
|
||||
|
||||
if (*(DWORD *)(base + WX_APP_DATA_ROOT_PATH_OFFSET) == 0 ||
|
||||
*(DWORD *)(base + WX_APP_DATA_ROOT_PATH_OFFSET + 0x4) == 0) {
|
||||
out.data_root_path = string();
|
||||
} else {
|
||||
out.data_root_path = Wstring2String(wstring(*(wchar_t **)(base + WX_APP_DATA_ROOT_PATH_OFFSET),
|
||||
*(DWORD *)(base + WX_APP_DATA_ROOT_PATH_OFFSET + 0x4)));
|
||||
}
|
||||
|
||||
if (*(DWORD *)(base + WX_APP_DATA_SAVE_PATH_OFFSET) == 0 ||
|
||||
*(DWORD *)(base + WX_APP_DATA_SAVE_PATH_OFFSET + 0x4) == 0) {
|
||||
out.data_save_path = string();
|
||||
} else {
|
||||
out.data_save_path = Wstring2String(wstring(*(wchar_t **)(base + WX_APP_DATA_SAVE_PATH_OFFSET),
|
||||
*(DWORD *)(base + WX_APP_DATA_SAVE_PATH_OFFSET + 0x4)));
|
||||
}
|
||||
if (*(DWORD *)(base + WX_CURRENT_DATA_PATH_OFFSET) == 0 ||
|
||||
*(DWORD *)(base + WX_CURRENT_DATA_PATH_OFFSET + 0x4) == 0) {
|
||||
out.current_data_path = string();
|
||||
} else {
|
||||
out.current_data_path = Wstring2String(wstring(*(wchar_t **)(base + WX_CURRENT_DATA_PATH_OFFSET),
|
||||
*(DWORD *)(base + WX_CURRENT_DATA_PATH_OFFSET + 0x4)));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int CheckLogin(){
|
||||
DWORD base = GetWeChatWinBase();
|
||||
return *(DWORD*) (base + WX_LOGIN_STATUS_OFFSET);
|
||||
}
|
||||
|
||||
|
||||
int Logout(){
|
||||
int success = 0;
|
||||
if(!CheckLogin()){
|
||||
return success;
|
||||
}
|
||||
DWORD base = GetWeChatWinBase();
|
||||
DWORD account_service_addr = base + WX_ACCOUT_SERVICE_OFFSET;
|
||||
DWORD logout_addr = base + WX_LOGOUT_OFFSET;
|
||||
__asm{
|
||||
PUSHAD
|
||||
CALL account_service_addr
|
||||
PUSH 0x0
|
||||
MOV ECX,EAX
|
||||
CALL logout_addr
|
||||
MOV success,EAX
|
||||
POPAD
|
||||
}
|
||||
return success;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#ifndef SELF_INFO_H_
|
||||
#define SELF_INFO_H_
|
||||
#include "wechat_data.h"
|
||||
int GetSelfInfo(SelfInfoInner& out);
|
||||
|
||||
int CheckLogin();
|
||||
|
||||
int Logout();
|
||||
#endif
|
||||
@@ -1,67 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "send_file.h"
|
||||
#include "common.h"
|
||||
#include "wechat_data.h"
|
||||
|
||||
#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[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;
|
||||
DWORD send_file_addr = base + WX_SEND_FILE_OFFSET;
|
||||
DWORD free_msg_addr = base + WX_FREE_CHAT_MSG_OFFSET;
|
||||
DWORD temp = 0;
|
||||
WeChatString null_obj = {0};
|
||||
__asm{
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
CALL app_msg_mgr_addr
|
||||
SUB ESP,0x14
|
||||
MOV temp,EAX
|
||||
LEA EAX,null_obj
|
||||
MOV ECX,ESP
|
||||
PUSH EAX
|
||||
CALL init_chat_msg_addr
|
||||
PUSH 0x0
|
||||
SUB ESP,0x14
|
||||
MOV EDI,ESP
|
||||
MOV dword ptr [EDI],0
|
||||
MOV dword ptr [EDI + 0x4],0
|
||||
MOV dword ptr [EDI + 0x8],0
|
||||
MOV dword ptr [EDI + 0xc],0
|
||||
MOV dword ptr [EDI + 0x10],0
|
||||
SUB ESP,0x14
|
||||
LEA EAX,path
|
||||
MOV ECX,ESP
|
||||
PUSH EAX
|
||||
CALL init_chat_msg_addr
|
||||
SUB ESP,0x14
|
||||
LEA EAX,to_user
|
||||
MOV ECX,ESP
|
||||
PUSH EAX
|
||||
CALL init_chat_msg_addr
|
||||
MOV ECX,dword ptr [temp]
|
||||
LEA EAX,chat_msg
|
||||
PUSH EAX
|
||||
CALL send_file_addr
|
||||
MOV AL,byte ptr [eax + 0x38]
|
||||
MOVZX EAX,AL
|
||||
MOV success,EAX
|
||||
LEA ECX,chat_msg
|
||||
CALL free_msg_addr
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
if (success == 0x31){
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#ifndef SEND_FILE_H_
|
||||
#define SEND_FILE_H_
|
||||
|
||||
int SendFile(wchar_t *wxid, wchar_t *file_path);
|
||||
#endif
|
||||
@@ -1,47 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "send_image.h"
|
||||
#include "common.h"
|
||||
#include "wechat_data.h"
|
||||
|
||||
#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[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;
|
||||
DWORD send_image_msg_addr = base + WX_SEND_IMAGE_OFFSET;
|
||||
DWORD free_msg_addr = base + WX_FREE_CHAT_MSG_OFFSET;
|
||||
DWORD temp = 0;
|
||||
WeChatString null_obj = {0};
|
||||
__asm{
|
||||
PUSHAD
|
||||
CALL send_message_mgr_addr
|
||||
SUB ESP,0x14
|
||||
MOV temp,EAX
|
||||
LEA EAX,null_obj
|
||||
MOV ECX,ESP
|
||||
LEA EDI,path
|
||||
PUSH EAX
|
||||
CALL init_chat_msg_addr
|
||||
MOV ECX,dword ptr [temp]
|
||||
LEA EAX,to_user
|
||||
PUSH EDI
|
||||
PUSH EAX
|
||||
LEA EAX,chat_msg
|
||||
PUSH EAX
|
||||
CALL send_image_msg_addr
|
||||
MOV success,EAX
|
||||
LEA ECX,chat_msg
|
||||
CALL free_msg_addr
|
||||
POPAD
|
||||
}
|
||||
return success;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#ifndef SEND_IMAGE_H_
|
||||
#define SEND_IMAGE_H_
|
||||
|
||||
int SendImage(wchar_t *wxid, wchar_t *image_path);
|
||||
#endif
|
||||
@@ -0,0 +1,240 @@
|
||||
#include "pch.h"
|
||||
#include "send_message_mgr.h"
|
||||
#include "wechat_function.h"
|
||||
#include "db.h"
|
||||
#include "contact_mgr.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
namespace wxhelper {
|
||||
SendMessageMgr::SendMessageMgr(DWORD base):BaseMgr(base) {}
|
||||
SendMessageMgr::~SendMessageMgr() {}
|
||||
int SendMessageMgr::SendText(wchar_t* wxid, wchar_t* msg) {
|
||||
int success = -1;
|
||||
WeChatString to_user(wxid);
|
||||
WeChatString text_msg(msg);
|
||||
wchar_t** msg_pptr = &text_msg.ptr;
|
||||
DWORD send_message_mgr_addr = base_addr_ + WX_SEND_MESSAGE_MGR_OFFSET;
|
||||
DWORD send_text_msg_addr = base_addr_ + WX_SEND_TEXT_OFFSET;
|
||||
DWORD free_chat_msg_addr = base_addr_ + WX_FREE_CHAT_MSG_OFFSET;
|
||||
char chat_msg[0x2D8] = {0};
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
CALL send_message_mgr_addr
|
||||
PUSH 0x0
|
||||
PUSH 0x0
|
||||
PUSH 0x0
|
||||
PUSH 0x1
|
||||
PUSH 0x0
|
||||
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
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
SPDLOG_INFO("SendText code = {}",success);
|
||||
SPDLOG_INFO("global log with source info");
|
||||
return success;
|
||||
}
|
||||
int SendMessageMgr::SendAtText(wchar_t* chat_room_id, wchar_t** wxids, int len,
|
||||
wchar_t* msg) {
|
||||
int success = -1;
|
||||
WeChatString * at_users = new WeChatString[len+1];
|
||||
std::wstring at_msg = L"";
|
||||
int number =0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
std::wstring nickname;
|
||||
if (!lstrcmpiW((wchar_t *)wxids[i], (wchar_t *)L"notify@all")) {
|
||||
nickname = L"所有人";
|
||||
} else {
|
||||
ContactMgr contact{base_addr_};
|
||||
nickname = contact.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;
|
||||
}
|
||||
std::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 send_message_mgr_addr = base_addr_ + WX_SEND_MESSAGE_MGR_OFFSET;
|
||||
DWORD send_text_msg_addr = base_addr_ + WX_SEND_TEXT_OFFSET;
|
||||
DWORD free_chat_msg_addr = base_addr_ + WX_FREE_CHAT_MSG_OFFSET;
|
||||
char chat_msg[0x2D8] = {0};
|
||||
__asm{
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
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
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
SPDLOG_INFO("SendText code = {}",success);
|
||||
return success;
|
||||
}
|
||||
int SendMessageMgr::SendImage(wchar_t* wxid, wchar_t* image_path) {
|
||||
int success = -1;
|
||||
WeChatString to_user(wxid);
|
||||
WeChatString path(image_path);
|
||||
char chat_msg[0x2D8] = {0};
|
||||
DWORD send_message_mgr_addr = base_addr_ + WX_SEND_MESSAGE_MGR_OFFSET;
|
||||
DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET;
|
||||
DWORD send_image_msg_addr = base_addr_ + WX_SEND_IMAGE_OFFSET;
|
||||
DWORD free_msg_addr = base_addr_ + WX_FREE_CHAT_MSG_OFFSET;
|
||||
DWORD temp = 0;
|
||||
WeChatString null_obj = {0};
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
CALL send_message_mgr_addr
|
||||
SUB ESP,0x14
|
||||
MOV temp,EAX
|
||||
LEA EAX,null_obj
|
||||
MOV ECX,ESP
|
||||
LEA EDI,path
|
||||
PUSH EAX
|
||||
CALL init_chat_msg_addr
|
||||
MOV ECX,dword ptr [temp]
|
||||
LEA EAX,to_user
|
||||
PUSH EDI
|
||||
PUSH EAX
|
||||
LEA EAX,chat_msg
|
||||
PUSH EAX
|
||||
CALL send_image_msg_addr
|
||||
MOV success,EAX
|
||||
LEA ECX,chat_msg
|
||||
CALL free_msg_addr
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
SPDLOG_INFO("SendImage code = {}",success);
|
||||
return success;
|
||||
}
|
||||
int SendMessageMgr::SendFile(wchar_t* wxid, wchar_t* file_path) {
|
||||
int success = -1;
|
||||
WeChatString to_user(wxid);
|
||||
WeChatString path(file_path);
|
||||
char chat_msg[0x2D8] = {0};
|
||||
DWORD app_msg_mgr_addr = base_addr_ + WX_APP_MSG_MGR_OFFSET;
|
||||
DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET;
|
||||
DWORD send_file_addr = base_addr_ + WX_SEND_FILE_OFFSET;
|
||||
DWORD free_msg_addr = base_addr_ + WX_FREE_CHAT_MSG_OFFSET;
|
||||
DWORD temp = 0;
|
||||
WeChatString null_obj = {0};
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
CALL app_msg_mgr_addr
|
||||
SUB ESP,0x14
|
||||
MOV temp,EAX
|
||||
LEA EAX,null_obj
|
||||
MOV ECX,ESP
|
||||
PUSH EAX
|
||||
CALL init_chat_msg_addr
|
||||
PUSH 0x0
|
||||
SUB ESP,0x14
|
||||
MOV EDI,ESP
|
||||
MOV dword ptr [EDI],0
|
||||
MOV dword ptr [EDI + 0x4],0
|
||||
MOV dword ptr [EDI + 0x8],0
|
||||
MOV dword ptr [EDI + 0xc],0
|
||||
MOV dword ptr [EDI + 0x10],0
|
||||
SUB ESP,0x14
|
||||
LEA EAX,path
|
||||
MOV ECX,ESP
|
||||
PUSH EAX
|
||||
CALL init_chat_msg_addr
|
||||
SUB ESP,0x14
|
||||
LEA EAX,to_user
|
||||
MOV ECX,ESP
|
||||
PUSH EAX
|
||||
CALL init_chat_msg_addr
|
||||
MOV ECX,dword ptr [temp]
|
||||
LEA EAX,chat_msg
|
||||
PUSH EAX
|
||||
CALL send_file_addr
|
||||
MOV AL,byte ptr [eax + 0x38]
|
||||
MOVZX EAX,AL
|
||||
MOV success,EAX
|
||||
LEA ECX,chat_msg
|
||||
CALL free_msg_addr
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
SPDLOG_INFO("SendFile code = {}",success);
|
||||
if (success == 0x31) {
|
||||
return 1;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
int SendMessageMgr::ForwardMsg(wchar_t* wxid, unsigned long long msgid) {
|
||||
int success = 0;
|
||||
|
||||
int db_index = 0;
|
||||
int localid = DB::GetInstance().GetLocalIdByMsgId(msgid, db_index);
|
||||
|
||||
if (localid == 0) return 0;
|
||||
WeChatString to_user(wxid);
|
||||
DWORD forward_msg_addr = base_addr_ + WX_FORWARD_MSG_OFFSET;
|
||||
DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET;
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
MOV EDX, DWORD PTR [db_index]
|
||||
PUSH EDX
|
||||
MOV EAX, DWORD PTR [localid]
|
||||
PUSH EAX
|
||||
SUB ESP,0x14
|
||||
MOV ECX,ESP
|
||||
LEA ESI,to_user
|
||||
PUSH ESI
|
||||
CALL init_chat_msg_addr
|
||||
XOR ECX,ECX
|
||||
CALL forward_msg_addr
|
||||
MOVZX EAX,AL
|
||||
MOV success,EAX
|
||||
ADD ESP,0x1c
|
||||
POPFD
|
||||
POPAD
|
||||
}
|
||||
return success;
|
||||
}
|
||||
} // namespace wxhelper
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef WXHELPER_SEND_MESSAGE_MGR_H_
|
||||
#define WXHELPER_SEND_MESSAGE_MGR_H_
|
||||
#include "base_mgr.h"
|
||||
namespace wxhelper {
|
||||
class SendMessageMgr:public BaseMgr {
|
||||
public:
|
||||
explicit SendMessageMgr(DWORD base);
|
||||
~SendMessageMgr();
|
||||
int SendText(wchar_t* wxid, wchar_t* msg);
|
||||
int SendAtText(wchar_t* chat_room_id, wchar_t** wxids, int len, wchar_t* msg);
|
||||
int SendImage(wchar_t *wxid, wchar_t *image_path);
|
||||
int SendFile(wchar_t *wxid, wchar_t *file_path);
|
||||
int ForwardMsg(wchar_t *wxid, unsigned long long msgid);
|
||||
|
||||
private:
|
||||
};
|
||||
} // namespace wxhelper
|
||||
#endif
|
||||
@@ -1,48 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "send_text.h"
|
||||
|
||||
|
||||
#include "common.h"
|
||||
#include "wechat_data.h"
|
||||
|
||||
#define WX_SEND_TEXT_OFFSET 0xc71a60
|
||||
|
||||
#define WX_SEND_MESSAGE_MGR_OFFSET 0x706d30
|
||||
|
||||
#define WX_FREE_CHAT_MSG_OFFSET 0x6f4ea0
|
||||
/// @brief 发生文本消息
|
||||
/// @param wxid wxid
|
||||
/// @param msg 文本消息
|
||||
/// @return 成功返回1
|
||||
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;
|
||||
|
||||
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
|
||||
PUSH 0x0
|
||||
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,6 +0,0 @@
|
||||
#ifndef SEND_TEXT_H_
|
||||
#define SEND_TEXT_H_
|
||||
|
||||
int SendText(wchar_t* wxid, wchar_t* msg);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef WXHELPER_SINGLETON_H_
|
||||
#define WXHELPER_SINGLETON_H_
|
||||
template <typename T>
|
||||
class Singleton {
|
||||
protected:
|
||||
Singleton() {}
|
||||
~Singleton() {}
|
||||
|
||||
Singleton(const Singleton&) = delete;
|
||||
Singleton& operator=(const Singleton&) = delete;
|
||||
|
||||
Singleton(Singleton&&) = delete;
|
||||
Singleton& operator=(Singleton&&) = delete;
|
||||
|
||||
public:
|
||||
static T& GetInstance() {
|
||||
static T instance{};
|
||||
return instance;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
@@ -1,6 +0,0 @@
|
||||
#ifndef SNS_H_
|
||||
#define SNS_H_
|
||||
|
||||
int GetFirstPage();
|
||||
int GetNextPage(ULONG64 sns_id);
|
||||
#endif
|
||||
+16
-19
@@ -1,18 +1,17 @@
|
||||
#include "pch.h"
|
||||
#include "sns.h"
|
||||
#include "pch.h"
|
||||
#include "sns_mgr.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() {
|
||||
#include "wechat_function.h"
|
||||
|
||||
|
||||
namespace wxhelper {
|
||||
SNSMgr::SNSMgr(DWORD base):BaseMgr(base) {}
|
||||
SNSMgr::~SNSMgr() {}
|
||||
int SNSMgr::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;
|
||||
DWORD sns_data_mgr_addr = base_addr_ + WX_SNS_DATA_MGR_OFFSET;
|
||||
DWORD get_first_page_addr = base_addr_ + WX_SNS_GET_FIRST_PAGE_OFFSET;
|
||||
|
||||
char buff[0xB44] = {};
|
||||
__asm {
|
||||
@@ -29,15 +28,12 @@ int GetFirstPage() {
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
int GetNextPage(ULONG64 sns_id) {
|
||||
int SNSMgr::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;
|
||||
DWORD sns_data_mgr_addr = base_addr_ + WX_SNS_DATA_MGR_OFFSET;
|
||||
DWORD get_next_page_addr = base_addr_ + WX_SNS_GET_NEXT_PAGE_OFFSET;
|
||||
VectorInner temp = {};
|
||||
__asm{
|
||||
__asm {
|
||||
PUSHAD
|
||||
CALL sns_data_mgr_addr
|
||||
LEA ECX,temp
|
||||
@@ -53,3 +49,4 @@ int GetNextPage(ULONG64 sns_id) {
|
||||
}
|
||||
return success;
|
||||
}
|
||||
} // namespace wxhelper
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef WXHELPER_SNS_MGR_H_
|
||||
#define WXHELPER_SNS_MGR_H_
|
||||
#include "Windows.h"
|
||||
#include "base_mgr.h"
|
||||
namespace wxhelper{
|
||||
class SNSMgr:public BaseMgr{
|
||||
public:
|
||||
explicit SNSMgr(DWORD base);
|
||||
~SNSMgr();
|
||||
int GetFirstPage();
|
||||
int GetNextPage(ULONG64 sns_id);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,41 @@
|
||||
|
||||
#include "pch.h"
|
||||
#include "thread_pool.h"
|
||||
|
||||
#include "Windows.h"
|
||||
|
||||
namespace wxhelper {
|
||||
ThreadPool::~ThreadPool() {
|
||||
CloseThreadpoolCleanupGroupMembers(cleanup_group_, true, NULL);
|
||||
CloseThreadpoolCleanupGroup(cleanup_group_);
|
||||
CloseThreadpool(pool_);
|
||||
}
|
||||
bool ThreadPool::Create(unsigned long min, unsigned long max) {
|
||||
InitializeThreadpoolEnvironment(&env_);
|
||||
pool_ = CreateThreadpool(NULL);
|
||||
if (NULL == pool_) {
|
||||
return false;
|
||||
}
|
||||
SetThreadpoolThreadMaximum(pool_, max);
|
||||
BOOL ret = SetThreadpoolThreadMinimum(pool_, min);
|
||||
if (FALSE == ret) {
|
||||
return false;
|
||||
}
|
||||
cleanup_group_ = CreateThreadpoolCleanupGroup();
|
||||
if (NULL == cleanup_group_) {
|
||||
return false;
|
||||
}
|
||||
SetThreadpoolCallbackPool(&env_, pool_);
|
||||
SetThreadpoolCallbackCleanupGroup(&env_, cleanup_group_, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThreadPool::AddWork(PTP_WORK_CALLBACK callback,PVOID opt) {
|
||||
PTP_WORK work = CreateThreadpoolWork(callback, opt, &env_);
|
||||
if (NULL == work) {
|
||||
return false;
|
||||
}
|
||||
SubmitThreadpoolWork(work);
|
||||
return true;
|
||||
}
|
||||
} // namespace wxhelper
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef WXHELPER_THREAD_POOL_H_
|
||||
#define WXHELPER_THREAD_POOL_H_
|
||||
#include "Windows.h"
|
||||
#include "singleton.h"
|
||||
namespace wxhelper {
|
||||
|
||||
class ThreadPool :public Singleton<ThreadPool>{
|
||||
public:
|
||||
~ThreadPool();
|
||||
|
||||
bool Create(unsigned long min = 1, unsigned long max = 4);
|
||||
|
||||
bool AddWork(PTP_WORK_CALLBACK callback,PVOID opt);
|
||||
|
||||
private:
|
||||
void operator=(const ThreadPool&) = delete;
|
||||
void operator=(ThreadPool&&) = delete;
|
||||
|
||||
PTP_POOL pool_;
|
||||
PTP_CLEANUP_GROUP cleanup_group_;
|
||||
TP_CALLBACK_ENVIRON env_;
|
||||
};
|
||||
|
||||
} // namespace wxhelper
|
||||
|
||||
#endif
|
||||
+214
@@ -0,0 +1,214 @@
|
||||
#include "utils.h"
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
namespace wxhelper {
|
||||
std::wstring Utils::UTF8ToWstring(const std::string &str) {
|
||||
return Utils::AnsiToWstring(str, CP_UTF8);
|
||||
}
|
||||
|
||||
std::string Utils::WstringToUTF8(const std::wstring &str) {
|
||||
return Utils::WstringToAnsi(str, CP_UTF8);
|
||||
}
|
||||
|
||||
std::wstring Utils::AnsiToWstring(const std::string &input, DWORD locale) {
|
||||
int wchar_len = MultiByteToWideChar(locale, 0, input.c_str(), -1, NULL, 0);
|
||||
if (wchar_len > 0) {
|
||||
std::vector<wchar_t> temp(wchar_len);
|
||||
MultiByteToWideChar(CP_UTF8, 0, input.c_str(), -1, &temp[0], wchar_len);
|
||||
return std::wstring(&temp[0]);
|
||||
}
|
||||
|
||||
return std::wstring();
|
||||
}
|
||||
|
||||
std::string Utils::WstringToAnsi(const std::wstring &input, DWORD locale) {
|
||||
int char_len = WideCharToMultiByte(locale, 0, input.c_str(), -1, 0, 0, 0, 0);
|
||||
if (char_len > 0) {
|
||||
std::vector<char> temp(char_len);
|
||||
WideCharToMultiByte(locale, 0, input.c_str(), -1, &temp[0], char_len, 0, 0);
|
||||
return std::string(&temp[0]);
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
||||
DWORD Utils::GetWeChatWinBase() {
|
||||
return (DWORD)GetModuleHandleA("WeChatWin.dll");
|
||||
}
|
||||
|
||||
bool Utils::CreateConsole() {
|
||||
if (AllocConsole()) {
|
||||
AttachConsole(GetCurrentProcessId());
|
||||
FILE *retStream;
|
||||
freopen_s(&retStream, "CONOUT$", "w", stdout);
|
||||
if (!retStream) throw std::runtime_error("Stdout redirection failed.");
|
||||
freopen_s(&retStream, "CONOUT$", "w", stderr);
|
||||
if (!retStream) throw std::runtime_error("Stderr redirection failed.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Utils::CloseConsole() {
|
||||
fclose(stdin);
|
||||
fclose(stdout);
|
||||
fclose(stderr);
|
||||
FreeConsole();
|
||||
}
|
||||
|
||||
std::string Utils::EncodeHexString(const std::string &str) {
|
||||
const std::string hex_table = "0123456789abcdef";
|
||||
std::string sb;
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
sb += hex_table.at((str[i] & 0xf0) >> 4);
|
||||
sb += hex_table.at((str[i] & 0x0f) >> 0);
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
std::string Utils::Hex2String(const std::string &hex_str) {
|
||||
std::string ret;
|
||||
const std::string hex_table = "0123456789abcdef";
|
||||
for (int i = 0; i < hex_str.length(); i += 2) {
|
||||
ret += BYTE(hex_table.find(hex_str.at(i)) << 4 |
|
||||
hex_table.find(hex_str.at(i + 1)));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string Utils::Bytes2Hex(const BYTE *bytes, const int length) {
|
||||
if (bytes == NULL) {
|
||||
return "";
|
||||
}
|
||||
std::string buff;
|
||||
const int len = length;
|
||||
for (int j = 0; j < len; j++) {
|
||||
int high = bytes[j] / 16, low = bytes[j] % 16;
|
||||
buff += (high < 10) ? ('0' + high) : ('a' + high - 10);
|
||||
buff += (low < 10) ? ('0' + low) : ('a' + low - 10);
|
||||
}
|
||||
return buff;
|
||||
}
|
||||
|
||||
void Utils::Hex2Bytes(const std::string &hex, BYTE *bytes) {
|
||||
int byte_len = hex.length() / 2;
|
||||
std::string str;
|
||||
unsigned int n;
|
||||
for (int i = 0; i < byte_len; i++) {
|
||||
str = hex.substr(i * 2, 2);
|
||||
sscanf_s(str.c_str(), "%x", &n);
|
||||
bytes[i] = n;
|
||||
}
|
||||
}
|
||||
|
||||
bool Utils::IsDigit(std::string str) {
|
||||
if (str.length() == 0) {
|
||||
return false;
|
||||
}
|
||||
for (auto it : str) {
|
||||
if (it < '0' || it > '9') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Utils::FindOrCreateDirectoryW(const wchar_t *path) {
|
||||
WIN32_FIND_DATAW fd;
|
||||
HANDLE hFind = ::FindFirstFileW(path, &fd);
|
||||
if (hFind != INVALID_HANDLE_VALUE &&
|
||||
(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
FindClose(hFind);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!::CreateDirectoryW(path, NULL)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Utils::HookAnyAddress(DWORD hook_addr, LPVOID jmp_addr, char *origin) {
|
||||
BYTE jmp_code[5] = {0};
|
||||
jmp_code[0] = 0xE9;
|
||||
*(DWORD *)&jmp_code[1] = (DWORD)jmp_addr - hook_addr - 5;
|
||||
DWORD old_protext = 0;
|
||||
VirtualProtect((LPVOID)hook_addr, 5, PAGE_EXECUTE_READWRITE, &old_protext);
|
||||
ReadProcessMemory(GetCurrentProcess(), (LPVOID)hook_addr, origin, 5, 0);
|
||||
memcpy((void *)hook_addr, jmp_code, 5);
|
||||
VirtualProtect((LPVOID)hook_addr, 5, old_protext, &old_protext);
|
||||
}
|
||||
|
||||
void Utils::UnHookAnyAddress(DWORD hook_addr, char *origin) {
|
||||
DWORD old_protext = 0;
|
||||
VirtualProtect((LPVOID)hook_addr, 5, PAGE_EXECUTE_READWRITE, &old_protext);
|
||||
WriteProcessMemory(GetCurrentProcess(), (LPVOID)hook_addr, origin, 5, 0);
|
||||
VirtualProtect((LPVOID)hook_addr, 5, old_protext, &old_protext);
|
||||
}
|
||||
|
||||
std::wstring Utils::GetTimeW(long long timestamp) {
|
||||
wchar_t *wstr = new wchar_t[20];
|
||||
memset(wstr, 0, 20 * 2);
|
||||
tm tm_out;
|
||||
localtime_s(&tm_out, ×tamp);
|
||||
swprintf_s(wstr, 20, L"%04d-%02d-%02d %02d:%02d:%02d", 1900 + tm_out.tm_year,
|
||||
tm_out.tm_mon + 1, tm_out.tm_mday, tm_out.tm_hour, tm_out.tm_min,
|
||||
tm_out.tm_sec);
|
||||
std::wstring str_time(wstr);
|
||||
delete[] wstr;
|
||||
return str_time;
|
||||
}
|
||||
|
||||
std::string Utils::WCharToUTF8(wchar_t *wstr) {
|
||||
int c_size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, FALSE);
|
||||
if (c_size > 0) {
|
||||
char *buffer = new char[c_size];
|
||||
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, buffer, c_size, NULL, FALSE);
|
||||
std::string str(buffer);
|
||||
delete[] buffer;
|
||||
buffer = NULL;
|
||||
return str;
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
||||
bool Utils::IsTextUtf8(const char *str,int length) {
|
||||
char endian = 1;
|
||||
bool littlen_endian = (*(char *)&endian == 1);
|
||||
|
||||
size_t i;
|
||||
int bytes_num;
|
||||
unsigned char chr;
|
||||
|
||||
i = 0;
|
||||
bytes_num = 0;
|
||||
while (i < length) {
|
||||
if (littlen_endian) {
|
||||
chr = *(str + i);
|
||||
} else { // Big Endian
|
||||
chr = (*(str + i) << 8) | *(str + i + 1);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (bytes_num == 0) {
|
||||
if ((chr & 0x80) != 0) {
|
||||
while ((chr & 0x80) != 0) {
|
||||
chr <<= 1;
|
||||
bytes_num++;
|
||||
}
|
||||
if ((bytes_num < 2) || (bytes_num > 6)) {
|
||||
return false;
|
||||
}
|
||||
bytes_num--;
|
||||
}
|
||||
} else {
|
||||
if ((chr & 0xC0) != 0x80) {
|
||||
return false;
|
||||
}
|
||||
bytes_num--;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return (bytes_num == 0);
|
||||
}
|
||||
} // namespace wxhelper
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
#ifndef WXHELPER_UTILS_H_
|
||||
#define WXHELPER_UTILS_H_
|
||||
#include <windows.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#define STRING2INT(str) (Utils::IsDigit(str) ? stoi(str) : 0)
|
||||
#define WS2LPWS(wstr) (LPWSTR) wstr.c_str()
|
||||
#define READ_WSTRING(addr, offset) ((*(DWORD *)(addr + offset + 0x4) == 0) ? std::wstring(L"") : std::wstring((wchar_t *)(*(DWORD *)(addr + offset)), *(DWORD *)(addr + offset + 0x4)))
|
||||
|
||||
|
||||
namespace wxhelper {
|
||||
|
||||
class Utils {
|
||||
public:
|
||||
static std::wstring UTF8ToWstring(const std::string &str);
|
||||
|
||||
static std::string WstringToUTF8(const std::wstring &str);
|
||||
|
||||
static std::wstring AnsiToWstring(const std::string &input,
|
||||
DWORD locale = CP_ACP);
|
||||
|
||||
static std::string WstringToAnsi(const std::wstring &input,
|
||||
DWORD locale = CP_ACP);
|
||||
|
||||
static DWORD GetWeChatWinBase();
|
||||
|
||||
static bool CreateConsole();
|
||||
|
||||
static void CloseConsole();
|
||||
|
||||
static std::string EncodeHexString(const std::string &str);
|
||||
|
||||
static std::string Hex2String(const std::string &hex_str);
|
||||
|
||||
static std::string Bytes2Hex(const BYTE *bytes, const int length);
|
||||
|
||||
static void Hex2Bytes(const std::string &hex, BYTE *bytes);
|
||||
|
||||
static bool IsDigit(std::string str);
|
||||
|
||||
static bool FindOrCreateDirectoryW(const wchar_t *path);
|
||||
|
||||
static void HookAnyAddress(DWORD hook_addr, LPVOID jmp_addr, char *origin);
|
||||
static void UnHookAnyAddress(DWORD hook_addr, char *origin);
|
||||
static std::wstring GetTimeW(long long timestamp);
|
||||
|
||||
static std::string WCharToUTF8(wchar_t *wstr);
|
||||
|
||||
static bool IsTextUtf8(const char * str,int length) ;
|
||||
|
||||
template <typename T1, typename T2>
|
||||
static std::vector<T1> split(T1 str, T2 letter) {
|
||||
std::vector<T1> arr;
|
||||
size_t pos;
|
||||
while ((pos = str.find_first_of(letter)) != T1::npos) {
|
||||
T1 str1 = str.substr(0, pos);
|
||||
arr.push_back(str1);
|
||||
str = str.substr(pos + 1, str.length() - pos - 1);
|
||||
}
|
||||
arr.push_back(str);
|
||||
return arr;
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
static T1 replace(T1 source, T2 replaced, T1 replaceto) {
|
||||
std::vector<T1> v_arr = split(source, replaced);
|
||||
if (v_arr.size() < 2) return source;
|
||||
T1 temp;
|
||||
for (unsigned int i = 0; i < v_arr.size() - 1; i++) {
|
||||
temp += v_arr[i];
|
||||
temp += replaceto;
|
||||
}
|
||||
temp += v_arr[v_arr.size() - 1];
|
||||
return temp;
|
||||
}
|
||||
};
|
||||
} // namespace wxhelper
|
||||
#endif
|
||||
@@ -1,158 +0,0 @@
|
||||
#ifndef WECHAT_DATA_H_
|
||||
#define WECHAT_DATA_H_
|
||||
|
||||
// #include <windows.h>
|
||||
|
||||
#include <vector>
|
||||
struct WeChatString {
|
||||
wchar_t *ptr;
|
||||
DWORD length;
|
||||
DWORD max_length;
|
||||
DWORD c_ptr = 0;
|
||||
DWORD c_len = 0;
|
||||
WeChatString() { WeChatString(NULL); }
|
||||
|
||||
WeChatString(std::wstring &s) {
|
||||
ptr = (wchar_t *)(s.c_str());
|
||||
length = s.length();
|
||||
max_length = s.length() * 2;
|
||||
}
|
||||
WeChatString(const wchar_t *pStr) { WeChatString((wchar_t *)pStr); }
|
||||
WeChatString(int tmp) {
|
||||
ptr = NULL;
|
||||
length = 0x0;
|
||||
max_length = 0x0;
|
||||
}
|
||||
WeChatString(wchar_t *pStr) {
|
||||
ptr = pStr;
|
||||
length = wcslen(pStr);
|
||||
max_length = wcslen(pStr) * 2;
|
||||
}
|
||||
void set_value(const wchar_t *pStr) {
|
||||
ptr = (wchar_t *)pStr;
|
||||
length = wcslen(pStr);
|
||||
max_length = wcslen(pStr) * 2;
|
||||
}
|
||||
};
|
||||
|
||||
struct TableInfo {
|
||||
char *name;
|
||||
DWORD name_len;
|
||||
char *table_name;
|
||||
DWORD table_name_len;
|
||||
char *sql;
|
||||
DWORD sql_len;
|
||||
char *rootpage;
|
||||
DWORD rootpage_len;
|
||||
};
|
||||
|
||||
struct DatabaseInfo {
|
||||
DWORD handle = 0;
|
||||
wchar_t *db_name = NULL;
|
||||
DWORD db_name_len = 0;
|
||||
std::vector<TableInfo> tables;
|
||||
DWORD count = 0;
|
||||
DWORD extrainfo = 0;
|
||||
};
|
||||
|
||||
struct Contact {
|
||||
WeChatString wxid;
|
||||
WeChatString custom_account;
|
||||
WeChatString encrypt_name;
|
||||
WeChatString nick_name;
|
||||
WeChatString pinyin;
|
||||
WeChatString pinyin_all;
|
||||
int del_flag;
|
||||
int type;
|
||||
int verify_flag;
|
||||
};
|
||||
|
||||
struct ChatRoomInfo {
|
||||
DWORD vftable;
|
||||
WeChatString chat_room_id;
|
||||
WeChatString notice;
|
||||
WeChatString admin;
|
||||
DWORD filed_40;
|
||||
DWORD filed_44;
|
||||
DWORD filed_48;
|
||||
DWORD filed_4C;
|
||||
WeChatString xml;
|
||||
DWORD filed_64;
|
||||
DWORD filed_68;
|
||||
DWORD filed_6C;
|
||||
DWORD filed_70;
|
||||
DWORD filed_74;
|
||||
DWORD filed_78;
|
||||
DWORD filed_7C;
|
||||
DWORD filed_80;
|
||||
DWORD filed_84;
|
||||
DWORD filed_88;
|
||||
DWORD filed_8c;
|
||||
DWORD filed_90;
|
||||
DWORD filed_94;
|
||||
DWORD filed_98;
|
||||
DWORD filed_9C;
|
||||
DWORD filed_A0;
|
||||
};
|
||||
|
||||
struct ChatRoomInfoInner {
|
||||
WeChatString chat_room_id;
|
||||
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 {
|
||||
#ifdef _DEBUG
|
||||
DWORD head;
|
||||
#endif
|
||||
DWORD start;
|
||||
DWORD finsh;
|
||||
DWORD end;
|
||||
};
|
||||
|
||||
struct ChatRoomInner{
|
||||
char* members;
|
||||
wchar_t* chat_room;
|
||||
wchar_t* admin;
|
||||
~ChatRoomInner(){
|
||||
delete []members;
|
||||
delete []chat_room;
|
||||
delete []admin;
|
||||
}
|
||||
};
|
||||
|
||||
struct SelfInfoInner{
|
||||
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
|
||||
@@ -0,0 +1,781 @@
|
||||
#ifndef WXHELPER_WECHAT_FUNCTION_H_
|
||||
#define WXHELPER_WECHAT_FUNCTION_H_
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
// snsDataMgr
|
||||
#define WX_SNS_DATA_MGR_OFFSET 0xc3a500
|
||||
// chatRoomMgr
|
||||
#define WX_CHAT_ROOM_MGR_OFFSET 0x78d9d0
|
||||
// contactMgr
|
||||
#define WX_CONTACT_MGR_OFFSET 0x75af30
|
||||
// syncMgr
|
||||
#define WX_SYNC_MGR_OFFSET 0xa87fd0
|
||||
// preDownloadMgr
|
||||
#define WX_GET_PRE_DOWNLOAD_MGR_OFFSET 0x80fe50
|
||||
// chatMgr
|
||||
#define WX_CHAT_MGR_OFFSET 0x7931b0
|
||||
// videoMgr
|
||||
#define WX_VIDEO_MGR_OFFSET 0x82a560
|
||||
// patMgr
|
||||
#define WX_PAT_MGR_OFFSET 0x932470
|
||||
// searchContactMgr
|
||||
#define WX_SEARCH_CONTACT_MGR_OFFSET 0xa6d860
|
||||
// appMsgMgr
|
||||
#define WX_APP_MSG_MGR_OFFSET 0x76b8c0
|
||||
// sendMessageMgr
|
||||
#define WX_SEND_MESSAGE_MGR_OFFSET 0x768be0
|
||||
// shareRecordMgr
|
||||
#define WX_SHARE_RECORD_MGR_OFFSET 0x78d5f0
|
||||
|
||||
|
||||
// setChatMsgValue
|
||||
#define WX_INIT_CHAT_MSG_OFFSET 0xf5b3f0
|
||||
|
||||
// chatMsg
|
||||
#define WX_NEW_CHAT_MSG_OFFSET 0x76fab0
|
||||
#define WX_FREE_CHAT_MSG_OFFSET 0x7573f0
|
||||
// #define WX_FREE_CHAT_MSG_2_OFFSET 0x6f4ea0
|
||||
#define WX_FREE_CHAT_MSG_INSTANCE_COUNTER_OFFSET 0x7578c0
|
||||
|
||||
|
||||
//sns
|
||||
#define WX_SNS_GET_FIRST_PAGE_OFFSET 0x14e36e0
|
||||
#define WX_SNS_GET_NEXT_PAGE_OFFSET 0x14e3780
|
||||
|
||||
//chat room
|
||||
#define WX_GET_CHAT_ROOM_DETAIL_INFO_OFFSET 0xbdef30
|
||||
// chatRoomInfo
|
||||
#define WX_NEW_CHAT_ROOM_INFO_OFFSET 0xe9abd0
|
||||
#define WX_FREE_CHAT_ROOM_INFO_OFFSET 0xe9aed0
|
||||
#define WX_DEL_CHAT_ROOM_MEMBER_OFFSET 0xbd3140
|
||||
#define WX_ADD_MEMBER_TO_CHAT_ROOM_OFFSET 0xbd2c60
|
||||
|
||||
|
||||
// chatRoom
|
||||
#define WX_INIT_CHAT_ROOM_OFFSET 0xe98820
|
||||
#define WX_FREE_CHAT_ROOM_OFFSET 0xe98a40
|
||||
|
||||
#define WX_GET_MEMBER_FROM_CHAT_ROOM_OFFSET 0xbe0100
|
||||
#define WX_MOD_CHAT_ROOM_MEMBER_NICK_NAME_OFFSET 0xbda520
|
||||
|
||||
#define WX_TOP_MSG_OFFSET 0xbe26e0
|
||||
#define WX_REMOVE_TOP_MSG_OFFSET 0xbe24c0
|
||||
|
||||
#define WX_GET_MEMBER_NICKNAME_OFFSET 0xbe0290
|
||||
|
||||
#define WX_FREE_CONTACT_OFFSET 0xea8800
|
||||
|
||||
// wcpayinfo
|
||||
#define WX_NEW_WCPAYINFO_OFFSET 0x7b3900
|
||||
#define WX_FREE_WCPAYINFO_OFFSET 0x79cd00
|
||||
#define WX_CONFIRM_RECEIPT_OFFSET 0x15e41d0
|
||||
|
||||
|
||||
//contact
|
||||
#define WX_CONTACT_GET_LIST_OFFSET 0xc09890
|
||||
#define WX_CONTACT_DEL_OFFSET 0xb9b3b0
|
||||
|
||||
#define WX_SET_VALUE_OFFSET 0x1f80900
|
||||
#define WX_DO_DEL_CONTACT_OFFSET 0xca6480
|
||||
#define WX_GET_CONTACT_OFFSET 0xc05ca0
|
||||
#define WX_DO_VERIFY_USER_OFFSET 0xc02f90
|
||||
#define WX_VERIFY_MSG_OFFSET 0xf5b2f0
|
||||
#define WX_VERIFY_OK_OFFSET 0xa19940
|
||||
#define WX_NEW_ADD_FRIEND_HELPER_OFFSET 0xa18ac0
|
||||
#define WX_FREE_ADD_FRIEND_HELPER_OFFSET 0xa18be0
|
||||
|
||||
// pushAttachTask
|
||||
|
||||
|
||||
#define WX_PUSH_ATTACH_TASK_OFFSET 0x82c880
|
||||
|
||||
#define WX_GET_MGR_BY_PREFIX_LOCAL_ID_OFFSET 0xbc11d0
|
||||
#define WX_APP_MSG_INFO_OFFSET 0x7b3d20
|
||||
#define WX_GET_APP_MSG_XML_OFFSET 0xe628a0
|
||||
#define WX_FREE_APP_MSG_INFO_OFFSET 0x79e3b0
|
||||
#define WX_PUSH_THUMB_TASK_OFFSET 0x82c780
|
||||
#define WX_DOWNLOAD_VIDEO_IMG_OFFSET 0xd46c30
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// pat
|
||||
#define WX_SEND_PAT_MSG_OFFSET 0x1422f30
|
||||
#define WX_RET_OFFSET 0x1D59DB1
|
||||
|
||||
|
||||
//search hook
|
||||
#define WX_SEARCH_CONTACT_ERROR_CODE_HOOK_OFFSET 0xe17ed4
|
||||
#define WX_SEARCH_CONTACT_ERROR_CODE_HOOK_NEXT_OFFSET 0xf58fd0
|
||||
#define WX_SEARCH_CONTACT_DETAIL_HOOK_OFFSET 0xa8dc00
|
||||
#define WX_SEARCH_CONTACT_DETAIL_HOOK_NEXT_OFFSET 0xa8de50
|
||||
#define WX_SEARCH_CONTACT_OFFSET 0xcd2370
|
||||
|
||||
|
||||
|
||||
//login
|
||||
#define WX_LOGOUT_OFFSET 0xe596d0
|
||||
#define WX_ACCOUNT_SERVICE_OFFSET 0x769720
|
||||
#define WX_GET_APP_DATA_SAVE_PATH_OFFSET 0xf3bbd0
|
||||
#define WX_GET_CURRENT_DATA_PATH_OFFSET 0xc88120
|
||||
#define WX_QR_CODE_LOGIN_MGR_OFFSET 0xaeab70
|
||||
#define WX_GET_QR_CODE_IMAGE_OFFSET 0xcdb560
|
||||
|
||||
//forward
|
||||
#define WX_FORWARD_MSG_OFFSET 0xce75a0
|
||||
// send file
|
||||
#define WX_SEND_FILE_OFFSET 0xb6dfd0
|
||||
// send image
|
||||
#define WX_SEND_IMAGE_OFFSET 0xce74b0
|
||||
// send text
|
||||
#define WX_SEND_TEXT_OFFSET 0xce7af0
|
||||
|
||||
|
||||
//ocr
|
||||
#define WX_INIT_OBJ_OFFSET 0x80b540
|
||||
#define WX_OCR_MANAGER_OFFSET 0x80ffc0
|
||||
#define WX_DO_OCR_TASK_OFFSET 0x13db9a0
|
||||
|
||||
|
||||
//storage
|
||||
|
||||
#define CONTACT_G_PINSTANCE_OFFSET 0x2fffe08
|
||||
#define DB_MICRO_MSG_OFFSET 0x68
|
||||
#define DB_CHAT_MSG_OFFSET 0x1C0
|
||||
#define DB_MISC_OFFSET 0x3D8
|
||||
#define DB_EMOTION_OFFSET 0x558
|
||||
#define DB_MEDIA_OFFSET 0x9B8
|
||||
#define DB_BIZCHAT_MSG_OFFSET 0x1120
|
||||
#define DB_FUNCTION_MSG_OFFSET 0x11B0
|
||||
#define DB_NAME_OFFSET 0x14
|
||||
|
||||
#define STORAGE_START_OFFSET 0x13f8
|
||||
#define STORAGE_END_OFFSET 0x13fc
|
||||
|
||||
#define PUBLIC_MSG_MGR_OFFSET 0x30400a4
|
||||
#define MULTI_DB_MSG_MGR_OFFSET 0x30424dc
|
||||
#define FAVORITE_STORAGE_MGR_OFFSET 0x3041e70
|
||||
#define FTS_FAVORITE_MGR_OFFSET 0x3000948
|
||||
|
||||
#define OP_LOG_STORAGE_VFTABLE 0x2AD3A20
|
||||
#define CHAT_MSG_STORAGE_VFTABLE 0x2AC10F0
|
||||
#define CHAT_CR_MSG_STORAGE_VFTABLE 0x2ABEF14
|
||||
#define SESSION_STORAGE_VFTABLE 0x2AD3578
|
||||
#define APP_INFO_STORAGE_VFTABLE 0x2ABCC58
|
||||
#define HEAD_IMG_STORAGE_VFTABLE 0x2ACD9DC
|
||||
#define HEAD_IMG_URL_STORAGE_VFTABLE 0x2ACDF70
|
||||
|
||||
#define BIZ_INFO_STORAGE_VFTABLE 0x2ABD718
|
||||
#define TICKET_INFO_STORAGE_VFTABLE 0x2AD5400
|
||||
#define CHAT_ROOM_STORAGE_VFTABLE 0x2AC299C
|
||||
#define CHAT_ROOM_INFO_STORAGE_VFTABLE 0x2AC245C
|
||||
#define MEDIA_STORAGE_VFTABLE 0x2ACE998
|
||||
#define NAME_2_ID_STORAGE_VFTABLE 0x2AD222C
|
||||
#define EMOTION_PACKAGE_STORAGE_VFTABLE 0x2AC6400
|
||||
|
||||
#define EMOTION_STORAGE_VFTABLE 0x2AC7018
|
||||
#define BUFINFO_STORAGE_VFTABLE 0x2AC3178
|
||||
|
||||
#define CUSTOM_EMOTION_STORAGE_VFTABLE 0x2AC4E90
|
||||
#define DEL_SESSIONINFO_STORAGE_VFTABLE 0x2AC5F98
|
||||
#define FUNCTION_MSG_STORAGE_VFTABLE 0x2ACD10C
|
||||
|
||||
#define FUNCTION_MSG_TASK_STORAGE_VFTABLE 0x2ACC5C8
|
||||
#define REVOKE_MSG_STORAGE_VFTABLE 0x2AD27BC
|
||||
|
||||
|
||||
|
||||
/*******************hook*********************************************/
|
||||
|
||||
|
||||
// hook image
|
||||
#define WX_HOOK_IMG_OFFSET 0xd723dc
|
||||
#define WX_HOOK_IMG_NEXT_OFFSET 0xe91d90
|
||||
|
||||
|
||||
|
||||
// hook log
|
||||
#define WX_HOOK_LOG_OFFSET 0xf59317
|
||||
#define WX_HOOK_LOG_NEXT_OFFSET 0x24102b4
|
||||
|
||||
// hook msg
|
||||
|
||||
#define WX_RECV_MSG_HOOK_OFFSET 0xd1a89b
|
||||
#define WX_RECV_MSG_HOOK_NEXT_OFFSET 0x7573f0
|
||||
#define WX_SNS_HOOK_OFFSET 0x14fb3b5
|
||||
#define WX_SNS_HOOK_NEXT_OFFSET 0x14fb640
|
||||
|
||||
|
||||
// hook voice
|
||||
#define WX_HOOK_VOICE_OFFSET 0xd4d8d8
|
||||
#define WX_HOOK_VOICE_NEXT_OFFSET 0x203d130
|
||||
#define WX_SELF_ID_OFFSET 0x2FFD484
|
||||
|
||||
/*******************hook end*********************************************/
|
||||
|
||||
|
||||
/***************************sqlite3***************************************/
|
||||
#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 0x1e26770
|
||||
#define SQLITE3_BACKUP_INIT_OFFSET 0x1dec100
|
||||
#define SQLITE3_PREPARE_OFFSET 0x1E2D0C0
|
||||
#define SQLITE3_OPEN_OFFSET 0x1e5b090
|
||||
#define SQLITE3_BACKUP_STEP_OFFSET 0x1DEC500
|
||||
#define SQLITE3_BACKUP_REMAINING_OFFSET 0x1DECC40
|
||||
#define SQLITE3_BACKUP_PAGECOUNT_OFFSET 0x1DECC50
|
||||
#define SQLITE3_BACKUP_FINISH_OFFSET 0x1DECB40
|
||||
#define SQLITE3_SLEEP_OFFSET 0x1e5b8d0
|
||||
#define SQLITE3_ERRCODE_OFFSET 0x1e59d30
|
||||
#define SQLITE3_CLOSE_OFFSET 0x1e584b0
|
||||
#define SQLITE3_STEP_OFFSET 0x1df4f70
|
||||
#define SQLITE3_COLUMN_COUNT_OFFSET 0x1df5480
|
||||
#define SQLITE3_COLUMN_NAME_OFFSET 0x1df5d70
|
||||
#define SQLITE3_COLUMN_TYPE_OFFSET 0x1df5c10
|
||||
#define SQLITE3_COLUMN_BLOB_OFFSET 0x1df54c0
|
||||
#define SQLITE3_COLUMN_BYTES_OFFSET 0x1df55a0
|
||||
#define SQLITE3_FINALIZE_OFFSET 0x1df3f40
|
||||
|
||||
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);
|
||||
|
||||
|
||||
/***************************sqlite3 end*************************************/
|
||||
|
||||
struct SqlResult {
|
||||
char *column_name;
|
||||
DWORD column_name_len;
|
||||
char *content;
|
||||
DWORD content_len;
|
||||
BOOL is_blob;
|
||||
};
|
||||
|
||||
struct WeChatString {
|
||||
wchar_t *ptr;
|
||||
DWORD length;
|
||||
DWORD max_length;
|
||||
DWORD c_ptr = 0;
|
||||
DWORD c_len = 0;
|
||||
WeChatString() { WeChatString(NULL); }
|
||||
|
||||
WeChatString(std::wstring &s) {
|
||||
ptr = (wchar_t *)(s.c_str());
|
||||
length = s.length();
|
||||
max_length = s.length() * 2;
|
||||
}
|
||||
WeChatString(const wchar_t *pStr) { WeChatString((wchar_t *)pStr); }
|
||||
WeChatString(int tmp) {
|
||||
ptr = NULL;
|
||||
length = 0x0;
|
||||
max_length = 0x0;
|
||||
}
|
||||
WeChatString(wchar_t *pStr) {
|
||||
ptr = pStr;
|
||||
length = wcslen(pStr);
|
||||
max_length = wcslen(pStr) * 2;
|
||||
}
|
||||
void set_value(const wchar_t *pStr) {
|
||||
ptr = (wchar_t *)pStr;
|
||||
length = wcslen(pStr);
|
||||
max_length = wcslen(pStr) * 2;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct SelfInfoInner{
|
||||
std::string name;
|
||||
std::string city;
|
||||
std::string province;
|
||||
std::string country;
|
||||
std::string account;
|
||||
std::string wxid;
|
||||
std::string mobile;
|
||||
std::string head_img;
|
||||
std::string data_save_path;
|
||||
std::string signature;
|
||||
std::string current_data_path;
|
||||
std::string db_key;
|
||||
};
|
||||
|
||||
struct VectorInner {
|
||||
#ifdef _DEBUG
|
||||
DWORD head;
|
||||
#endif
|
||||
DWORD start;
|
||||
DWORD finsh;
|
||||
DWORD end;
|
||||
};
|
||||
|
||||
struct TableInfo {
|
||||
char *name;
|
||||
DWORD name_len;
|
||||
char *table_name;
|
||||
DWORD table_name_len;
|
||||
char *sql;
|
||||
DWORD sql_len;
|
||||
char *rootpage;
|
||||
DWORD rootpage_len;
|
||||
};
|
||||
|
||||
struct DatabaseInfo {
|
||||
DWORD handle = 0;
|
||||
wchar_t *db_name = NULL;
|
||||
DWORD db_name_len = 0;
|
||||
std::vector<TableInfo> tables;
|
||||
DWORD count = 0;
|
||||
DWORD extrainfo = 0;
|
||||
};
|
||||
|
||||
|
||||
struct Contact {
|
||||
WeChatString wxid;
|
||||
WeChatString custom_account;
|
||||
WeChatString encrypt_name;
|
||||
WeChatString nick_name;
|
||||
WeChatString pinyin;
|
||||
WeChatString pinyin_all;
|
||||
int del_flag;
|
||||
int type;
|
||||
int verify_flag;
|
||||
};
|
||||
|
||||
struct ChatRoomInfo {
|
||||
DWORD vftable;
|
||||
WeChatString chat_room_id;
|
||||
WeChatString notice;
|
||||
WeChatString admin;
|
||||
DWORD filed_40;
|
||||
DWORD filed_44;
|
||||
DWORD filed_48;
|
||||
DWORD filed_4C;
|
||||
WeChatString xml;
|
||||
DWORD filed_64;
|
||||
DWORD filed_68;
|
||||
DWORD filed_6C;
|
||||
DWORD filed_70;
|
||||
DWORD filed_74;
|
||||
DWORD filed_78;
|
||||
DWORD filed_7C;
|
||||
DWORD filed_80;
|
||||
DWORD filed_84;
|
||||
DWORD filed_88;
|
||||
DWORD filed_8c;
|
||||
DWORD filed_90;
|
||||
DWORD filed_94;
|
||||
DWORD filed_98;
|
||||
DWORD filed_9C;
|
||||
DWORD filed_A0;
|
||||
};
|
||||
|
||||
struct ChatRoomInfoInner {
|
||||
WeChatString chat_room_id;
|
||||
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 ChatRoomInner{
|
||||
char* members;
|
||||
wchar_t* chat_room;
|
||||
wchar_t* admin;
|
||||
~ChatRoomInner(){
|
||||
delete []members;
|
||||
delete []chat_room;
|
||||
delete []admin;
|
||||
}
|
||||
};
|
||||
|
||||
struct UserInfo {
|
||||
int error_code;
|
||||
wchar_t *keyword;
|
||||
int keyword_len;
|
||||
wchar_t *v3;
|
||||
int v3_len;
|
||||
wchar_t *V3;
|
||||
int V3_len;
|
||||
wchar_t *account;
|
||||
int account_len;
|
||||
wchar_t *friend_name;
|
||||
int friend_name_len;
|
||||
wchar_t *nickname;
|
||||
int nickname_len;
|
||||
wchar_t *signature;
|
||||
int signature_len;
|
||||
wchar_t *v2;
|
||||
int v2_len;
|
||||
wchar_t *py;
|
||||
int py_len;
|
||||
wchar_t *nation;
|
||||
int nation_len;
|
||||
wchar_t *province;
|
||||
int province_len;
|
||||
wchar_t *city;
|
||||
int city_len;
|
||||
wchar_t *big_image;
|
||||
int big_image_len;
|
||||
wchar_t *small_image;
|
||||
int small_image_len;
|
||||
DWORD sex;
|
||||
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;
|
||||
};
|
||||
|
||||
struct InnerMessageStruct {
|
||||
char *buffer;
|
||||
int length;
|
||||
~InnerMessageStruct() {
|
||||
if (this->buffer != NULL) {
|
||||
delete[] this->buffer;
|
||||
this->buffer = NULL;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct Unkown{
|
||||
DWORD field1 = 0;
|
||||
DWORD field2= 0;
|
||||
DWORD field3= 0;
|
||||
DWORD field4= 0;
|
||||
DWORD field5= 0;
|
||||
DWORD field6= 0;
|
||||
};
|
||||
#endif
|
||||
Reference in New Issue
Block a user