mirror of
https://github.com/ttttupup/wxhelper.git
synced 2025-04-20 03:49:17 +08:00
Compare commits
161 Commits
3.9.2.26-v
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
24bb7212fa | ||
|
1528b66b94 | ||
|
62a641d7f7 | ||
|
49188b7ef0 | ||
|
e4656e5139 | ||
|
0bd8b47da0 | ||
|
7a5a8a90df | ||
|
b5cc83be77 | ||
|
3b5f191bf2 | ||
|
dff024745c | ||
|
8b6e2d7160 | ||
|
5d7c1d1d48 | ||
|
d574af863a | ||
|
632d4222fa | ||
|
ee7d4ee9a3 | ||
|
1ba2ed87b7 | ||
|
2863f8258f | ||
|
fa31de81e0 | ||
|
758b773d99 | ||
|
b17af7a9e0 | ||
|
b364885daf | ||
|
427b43304c | ||
|
0593dbe79e | ||
|
13f182a95b | ||
|
1718ddefdd | ||
|
4c3c02283e | ||
|
bb46b9b8d9 | ||
|
e806914775 | ||
|
e5ead96c05 | ||
|
938e7e9bc2 | ||
|
8acad316a9 | ||
|
a5a2f0f17d | ||
|
3b76b2332c | ||
|
5088f5171b | ||
|
d8c8078f5c | ||
|
8bdc8c7e46 | ||
|
212613e3b6 | ||
|
608c6d26de | ||
|
2f6760e28e | ||
|
6436ce072a | ||
|
58caad4f34 | ||
|
bdf91943f3 | ||
|
41b3b6b18d | ||
|
129bb55c36 | ||
|
e9a6e0da57 | ||
|
e6e72dd492 | ||
|
9b4d326d63 | ||
|
64ba6007a8 | ||
|
f9b859baca | ||
|
ae44434662 | ||
|
4ab28cfc03 | ||
|
1268d37a57 | ||
|
e6c57f8ede | ||
|
17aff3b6aa | ||
|
51a4693330 | ||
|
7e06eaf4e4 | ||
|
b996a9d91c | ||
|
e0c946bf72 | ||
|
bf52de1560 | ||
|
2ed409e7b0 | ||
|
6f97a499b8 | ||
|
d33df9391e | ||
|
23fc28d011 | ||
|
e373b2f063 | ||
|
7e0b877d99 | ||
|
2ee16e36bf | ||
|
91bd8f5977 | ||
|
a9029e4a3d | ||
|
53a7938335 | ||
|
ce72262d58 | ||
|
bdf19fe4e4 | ||
|
44623e5b2e | ||
|
1824d6507c | ||
|
9b643901cd | ||
|
7ab8d4733f | ||
|
539d026146 | ||
|
272d62b0e9 | ||
|
0bbba4a902 | ||
|
5a9f91b425 | ||
|
66ea9d5428 | ||
|
f25f04f54e | ||
|
8229a15089 | ||
|
6d8218428f | ||
|
88e5c8fb9c | ||
|
6062a75b02 | ||
|
7ff6242c18 | ||
|
1aa7182a9a | ||
|
777faa5673 | ||
|
a94dfa9f71 | ||
|
a3d689d80a | ||
|
5a91d975a6 | ||
|
a2ebb527f9 | ||
|
7d9aa01d8d | ||
|
6875302b04 | ||
|
e39e4362fe | ||
|
292b9da378 | ||
|
bce22ee3df | ||
|
8472a5c36e | ||
|
e058879295 | ||
|
74831d9d8b | ||
|
51498cde8a | ||
|
391011b696 | ||
|
b5bb1e4e77 | ||
|
2d16226d10 | ||
|
37b1f727b8 | ||
|
003ceca7d6 | ||
|
3f66d7b6d0 | ||
|
81ea48b534 | ||
|
fa27a73355 | ||
|
fad5920bbe | ||
|
472c53b863 | ||
|
2ceece90f6 | ||
|
3b4a4aa3da | ||
|
4c9a292c77 | ||
|
a4540117e3 | ||
|
40940c0b7a | ||
|
620d4d38db | ||
|
0942a691ed | ||
|
9248d2f91a | ||
|
233b9f11f4 | ||
|
c453b8fb30 | ||
|
af54cbcc82 | ||
|
13e7e3bba3 | ||
|
cae25147f1 | ||
|
3626c40492 | ||
|
b56f93e372 | ||
|
6a58ad71b1 | ||
|
437f657faf | ||
|
5dd3584122 | ||
|
20250dd7ca | ||
|
055adf5eab | ||
|
75ca6f9477 | ||
|
ee90ec3755 | ||
|
3ebb4ec269 | ||
|
259d40c73f | ||
|
63632ad8cd | ||
|
ae2d5ba437 | ||
|
a1cff41756 | ||
|
259cb4eeb3 | ||
|
e66d6c35e3 | ||
|
64d49d3a94 | ||
|
95160ae175 | ||
|
6a89f08519 | ||
|
b1e267d991 | ||
|
5ef79f9b93 | ||
|
96bbf8be85 | ||
|
0db008e298 | ||
|
60a1b59f73 | ||
|
f324db9b7b | ||
|
380663b5b5 | ||
|
bc731b47e4 | ||
|
4060da487b | ||
|
5e2a32713a | ||
|
1dad7fe3fd | ||
|
95d8bb50c9 | ||
|
81e5150bef | ||
|
fe56d50041 | ||
|
ca66f987f6 | ||
|
8670d70147 | ||
|
6a5e174f27 | ||
|
65625a573e |
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -30,6 +30,6 @@
|
||||
#*.exe
|
||||
*.out
|
||||
*.app
|
||||
/out
|
||||
CMakePresets.json
|
||||
.vscode
|
||||
out
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "spdlog"]
|
||||
path = spdlog
|
||||
url = https://github.com/gabime/spdlog
|
@ -1,36 +1,48 @@
|
||||
cmake_minimum_required(VERSION 3.0.0)
|
||||
# include(ExternalProject)
|
||||
project(wxhelper VERSION 1.0.0)
|
||||
enable_language(ASM_MASM)
|
||||
|
||||
|
||||
|
||||
# SET(CMAKE_ASM_NASM_FLAGS "-w0")
|
||||
|
||||
|
||||
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' ")
|
||||
|
||||
file(GLOB CPP_FILES ${PROJECT_SOURCE_DIR}/src/*.cc ${PROJECT_SOURCE_DIR}/src/*.cpp)
|
||||
file(GLOB CPP_FILES ${PROJECT_SOURCE_DIR}/src/*.cc ${PROJECT_SOURCE_DIR}/src/*.cpp ${PROJECT_SOURCE_DIR}/src/*.c )
|
||||
|
||||
file(GLOB ASM_FILES ${PROJECT_SOURCE_DIR}/src/*.asm )
|
||||
|
||||
include_directories(${VCPKG_INSTALLED_DIR}/x64-windows/include ${PROJECT_SOURCE_DIR}/spdlog/include ${DETOURS_INCLUDE_DIRS})
|
||||
# include_directories(${VCPKG_INSTALLED_DIR}/x64-windows/include ${PROJECT_SOURCE_DIR}/spdlog/include )
|
||||
|
||||
|
||||
|
||||
include_directories(${VCPKG_INSTALLED_DIR}/x86-windows/include)
|
||||
add_subdirectory(spdlog)
|
||||
add_subdirectory(source)
|
||||
|
||||
# add_subdirectory(3rd)
|
||||
# add_subdirectory(source)
|
||||
# find_package(spdlog CONFIG REQUIRED)
|
||||
|
||||
find_package(nlohmann_json CONFIG REQUIRED)
|
||||
find_package(unofficial-mongoose CONFIG REQUIRED)
|
||||
# find_package(spdlog CONFIG REQUIRED)
|
||||
# find_package(minhook CONFIG REQUIRED)
|
||||
|
||||
find_path(DETOURS_INCLUDE_DIRS "detours/detours.h")
|
||||
find_library(DETOURS_LIBRARY detours REQUIRED)
|
||||
|
||||
|
||||
add_library(wxhelper SHARED ${CPP_FILES} )
|
||||
add_library(wxhelper SHARED ${CPP_FILES} ${ASM_FILES} )
|
||||
|
||||
|
||||
#target_include_directories(wxhelper PUBLIC 3rd/mongoose )
|
||||
|
||||
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)
|
||||
target_link_libraries(wxhelper PRIVATE spdlog::spdlog spdlog::spdlog_header_only)
|
||||
target_link_libraries(wxhelper PRIVATE ${DETOURS_LIBRARY})
|
||||
|
||||
|
||||
SET_TARGET_PROPERTIES(wxhelper PROPERTIES LINKER_LANGUAGE C
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib
|
||||
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 ttttupup
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
1633
doc/3.9.2.23.md
Normal file
1633
doc/3.9.2.23.md
Normal file
File diff suppressed because it is too large
Load Diff
1829
doc/3.9.5.81.md
Normal file
1829
doc/3.9.5.81.md
Normal file
File diff suppressed because it is too large
Load Diff
640
doc/postman.json
Normal file
640
doc/postman.json
Normal file
@ -0,0 +1,640 @@
|
||||
{
|
||||
"info": {
|
||||
"name": "Wechat Hook 395",
|
||||
"_postman_id": "d2b6a4f2-6d7d-4a21-9bbf-65b5a5a3a5a",
|
||||
"description": "A collection of Wechat Hook 395 API requests.",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "checkLogin",
|
||||
"request": {
|
||||
"url": {
|
||||
"raw": "http://127.0.0.1:19088/api/checkLogin",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"127.0.0.1"
|
||||
],
|
||||
"port": "19088",
|
||||
"path": [
|
||||
"api",
|
||||
"checkLogin"
|
||||
]
|
||||
},
|
||||
"method": "POST",
|
||||
"header": [],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": ""
|
||||
},
|
||||
"description": "API to check login status."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "userInfo",
|
||||
"request": {
|
||||
"url": {
|
||||
"raw": "http://127.0.0.1:19088/api/userInfo",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"127.0.0.1"
|
||||
],
|
||||
"port": "19088",
|
||||
"path": [
|
||||
"api",
|
||||
"userInfo"
|
||||
]
|
||||
},
|
||||
"method": "POST",
|
||||
"header": [],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": ""
|
||||
},
|
||||
"description": "API to get user information."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sendTextMsg",
|
||||
"request": {
|
||||
"url": {
|
||||
"raw": "http://127.0.0.1:19088/api/sendTextMsg",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"127.0.0.1"
|
||||
],
|
||||
"port": "19088",
|
||||
"path": [
|
||||
"api",
|
||||
"sendTextMsg"
|
||||
]
|
||||
},
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"wxid\": \"filehelper\",\"msg\": \"12www\"}"
|
||||
},
|
||||
"description": "API to send text messages."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sendImagesMsg",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/sendImagesMsg",
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Specify that the request body is in JSON format."
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"wxid\": \"filehelper\",\"imagePath\": \"C:\\pic.png\"}"
|
||||
},
|
||||
"description": "API to send image messages."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sendFileMsg",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/sendFileMsg",
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Specify that the request body is in JSON format."
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"wxid\": \"filehelper\",\"filePath\": \"C:\\test.zip\"}"
|
||||
},
|
||||
"description": "API to send file messages."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "hookSyncMsg",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/hookSyncMsg",
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Specify that the request body is in JSON format."
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"port\": \"19099\",\"ip\": \"127.0.0.1\",\"url\": \"http://localhost:8080\",\"timeout\": \"3000\",\"enableHttp\": \"0\"}"
|
||||
},
|
||||
"description": "API to hook sync messages."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "unhookSyncMsg",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/unhookSyncMsg",
|
||||
"method": "POST",
|
||||
"header": [],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": ""
|
||||
},
|
||||
"description": "API to unhook sync messages."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "getContactList",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/getContactList",
|
||||
"method": "POST",
|
||||
"header": [],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": ""
|
||||
},
|
||||
"description": "API to get the contact list."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "getDBInfo",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/getDBInfo",
|
||||
"method": "POST",
|
||||
"header": [],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": ""
|
||||
},
|
||||
"description": "API to get database information."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "execSql",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/execSql",
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Specify that the request body is in JSON format."
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"dbHandle\": 1713425147584,\"sql\": \"select * from MSG where localId =100;\"}"
|
||||
},
|
||||
"description": "API to execute SQL queries."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "getChatRoomDetailInfo",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/getChatRoomDetailInfo",
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Specify that the request body is in JSON format."
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"chatRoomId\": \"123333@chatroom\"}"
|
||||
},
|
||||
"description": "API to get chat room detail information."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "addMemberToChatRoom",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/addMemberToChatRoom",
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Specify that the request body is in JSON format."
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"chatRoomId\": \"123@chatroom\",\"memberIds\": \"wxid_123\"}"
|
||||
},
|
||||
"description": "API to add member to chat room."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "delMemberFromChatRoom",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/delMemberFromChatRoom",
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Specify that the request body is in JSON format."
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"chatRoomId\": \"21363231004@chatroom\",\"memberIds\": \"wxid_123\"}"
|
||||
},
|
||||
"description": "API to delete member from chat room."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "modifyNickname",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/modifyNickname",
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Specify that the request body is in JSON format."
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"chatRoomId\": \"123@chatroom\",\"wxid\": \"wxid_123\",\"nickName\": \"test\"}"
|
||||
},
|
||||
"description": "API to modify a nickname in a chat room."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "getMemberFromChatRoom",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/getMemberFromChatRoom",
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Specify that the request body is in JSON format."
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"chatRoomId\": \"123@chatroom\"}"
|
||||
},
|
||||
"description": "API to get members from a chat room."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "topMsg",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/topMsg",
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Specify that the request body is in JSON format."
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"msgId\": 1222222}"
|
||||
},
|
||||
"description": "API to top a message."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "removeTopMsg",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/removeTopMsg",
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Specify that the request body is in JSON format."
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"chatRoomId\": \"123@chatroom\",\"msgId\": 123}"
|
||||
},
|
||||
"description": "API to remove a topped message."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "InviteMemberToChatRoom",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/InviteMemberToChatRoom",
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Specify that the request body is in JSON format."
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"chatRoomId\": \"123@chatroom\",\"memberIds\": \"wxid_123\"}"
|
||||
},
|
||||
"description": "API to invite members to a chat room."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "hookLog",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/hookLog",
|
||||
"method": "POST",
|
||||
"header": [],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": ""
|
||||
},
|
||||
"description": "API to hook logs."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "unhookLog",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/unhookLog",
|
||||
"method": "POST",
|
||||
"header": [],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": ""
|
||||
},
|
||||
"description": "API to unhook logs."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "createChatRoom",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/createChatRoom",
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Specify that the request body is in JSON format."
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"memberIds\": \"wxid_8yn4k908tdqp22,wxid_oyb662qhop4422\"}"
|
||||
},
|
||||
"description": "API to create a chat room."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "quitChatRoom",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/quitChatRoom",
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Specify that the request body is in JSON format."
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"chatRoomId\": \"123@chatroom\"}"
|
||||
},
|
||||
"description": "API to quit a chat room."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "forwardMsg",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/forwardMsg",
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Specify that the request body is in JSON format."
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"wxid\": \"filehelper\",\"msgId\": \"12331\"}"
|
||||
},
|
||||
"description": "API to forward a message."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "getSNSFirstPage",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/getSNSFirstPage",
|
||||
"method": "POST",
|
||||
"header": [],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": ""
|
||||
},
|
||||
"description": "API to get the first page of SNS data."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "getSNSNextPage",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/getSNSNextPage",
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Specify that the request body is in JSON format."
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"snsId\": \"\"}"
|
||||
},
|
||||
"description": "API to get the next page of SNS data."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "addFavFromMsg",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/addFavFromMsg",
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Specify that the request body is in JSON format."
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"msgId\": \"1222222\"}"
|
||||
},
|
||||
"description": "API to add a favorite from a message."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "addFavFromImage",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/addFavFromImage",
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Specify that the request body is in JSON format."
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"wxid\": \"\",\"imagePath\": \"\"}"
|
||||
},
|
||||
"description": "API to add a favorite from an image."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "getContactProfile",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/getContactProfile",
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Specify that the request body is in JSON format."
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"wxid\": \"\"}"
|
||||
},
|
||||
"description": "API to get contact profile."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sendAtText",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/sendAtText",
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Specify that the request body is in JSON format."
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"wxids\": \"notify@all\",\"chatRoomId\": \"123@chatroom\",\"msg\": \"你好啊\"}"
|
||||
},
|
||||
"description": "API to send an at-text message."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "forwardPublicMsg",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/forwardPublicMsg",
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Specify that the request body is in JSON format."
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"appName\": \"\",\"userName\": \"\",\"title\": \"\",\"url\": \"\",\"thumbUrl\": \"\",\"digest\": \"\",\"wxid\": \"filehelper\"}"
|
||||
},
|
||||
"description": "API to forward a public message."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "forwardPublicMsgByMsgId",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/forwardPublicMsgByMsgId",
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Specify that the request body is in JSON format."
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"msgId\": 123,\"wxid\": \"filehelper\"}"
|
||||
},
|
||||
"description": "API to forward a public message by message ID."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "downloadAttach",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/downloadAttach",
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Specify that the request body is in JSON format."
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"msgId\": 123}"
|
||||
},
|
||||
"description": "API to download an attachment."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "decodeImage",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/decodeImage",
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Specify that the request body is in JSON format."
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"filePath\": \"C:\\66664816980131.dat\",\"storeDir\": \"C:\\test\"}"
|
||||
},
|
||||
"description": "API to decode an image."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "getVoiceByMsgId",
|
||||
"request": {
|
||||
"url": "http://127.0.0.1:19088/api/getVoiceByMsgId",
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Specify that the request body is in JSON format."
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"msgId\": 7880439644200,\"storeDir\": \"c:\\test\"}"
|
||||
},
|
||||
"description": "API to get voice by message ID."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
11
go_client/main.go
Normal file
11
go_client/main.go
Normal file
@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"go_client/tcpserver"
|
||||
"log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||
tcpserver.Listen(19099)
|
||||
}
|
44
go_client/tcpserver/tcpserver.go
Normal file
44
go_client/tcpserver/tcpserver.go
Normal file
@ -0,0 +1,44 @@
|
||||
package tcpserver
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"log"
|
||||
"net"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func Listen(port int) {
|
||||
p := strconv.Itoa(port)
|
||||
adress := "127.0.0.1:" + p
|
||||
ln, err := net.Listen("tcp", adress)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer ln.Close()
|
||||
log.Println("tcp server started")
|
||||
for {
|
||||
conn, err := ln.Accept()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
go handle(conn)
|
||||
}
|
||||
}
|
||||
|
||||
func handle(conn net.Conn) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
log.Println("发生了未处理的异常", err)
|
||||
}
|
||||
}()
|
||||
defer conn.Close()
|
||||
scanner := bufio.NewScanner(conn)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Bytes()
|
||||
log.Println("收到消息:", string(line))
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
log.Println("错误:", err)
|
||||
}
|
||||
}
|
33
java_client/.gitignore
vendored
Normal file
33
java_client/.gitignore
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
HELP.md
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
21
java_client/README.md
Normal file
21
java_client/README.md
Normal file
@ -0,0 +1,21 @@
|
||||
环境为jdk17
|
||||
执行之后会在当前项目所处磁盘根路径生成一个exec文件夹,然后会把src/main/resources/exec下的文件放在那避免因为路径问题出错
|
||||
java_client/src/main/resources/exec/c.exe 为注入器,只不过把名字改短了,更新的话换成最新版,改个名字就行, wxhelper.dll同理
|
||||
|
||||
项目启动之后,会生成一个tcp服务端,用来接受hook信息,然后把接收的信息放在队列中,之后用一个线程去循环处理消息.
|
||||
具体实现可以看
|
||||
```com.example.wxhk.tcp.vertx```包下的三个文件
|
||||
|
||||
com.example.wxhk.tcp.vertx.VertxTcp 这个是tcp服务端,接受信息
|
||||
|
||||
com.example.wxhk.tcp.vertx.InitWeChat 微信环境初始化
|
||||
|
||||
com.example.wxhk.tcp.vertx.ArrHandle 循环消息处理
|
||||
|
||||
com.example.wxhk.server.WxSmgServer 为消息处理接口,实现其中的方法即可
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
启动项目需要去修改配置文件的微信路径
|
185
java_client/pom.xml
Normal file
185
java_client/pom.xml
Normal file
@ -0,0 +1,185 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.2.2</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>wxhk</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>wxhk</name>
|
||||
<description>wxhk</description>
|
||||
<properties>
|
||||
<java.version>21</java.version>
|
||||
<vertx-web-client.version>4.5.3</vertx-web-client.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-mail</artifactId>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.springframework.boot</groupId>-->
|
||||
<!-- <artifactId>spring-boot-starter-thymeleaf</artifactId>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.springframework.boot</groupId>-->
|
||||
<!-- <artifactId>spring-boot-starter-web</artifactId>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>4.1.105.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>4.11.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-core</artifactId>
|
||||
<version>${vertx-web-client.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-web</artifactId>
|
||||
<version>${vertx-web-client.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-web-client</artifactId>
|
||||
<version>${vertx-web-client.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-mysql-client</artifactId>
|
||||
<version>${vertx-web-client.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<scope>runtime</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.dromara.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>6.0.0.M3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.15.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
|
||||
<!-- 排除文件配置 -->
|
||||
<!-- <excludes> -->
|
||||
<!-- <exclude>*.**</exclude> -->
|
||||
<!-- <exclude>*/**.xml</exclude> -->
|
||||
<!-- </excludes> -->
|
||||
|
||||
<!-- 包含文件配置,现在只打包 com 文件夹 -->
|
||||
<includes>
|
||||
<include>
|
||||
**/com/example/wxhk/**
|
||||
</include>
|
||||
</includes>
|
||||
|
||||
<archive>
|
||||
<manifest>
|
||||
<!-- 配置加入依赖包 -->
|
||||
<addClasspath>true</addClasspath>
|
||||
<classpathPrefix>lib/</classpathPrefix>
|
||||
<useUniqueVersions>false</useUniqueVersions>
|
||||
<!-- Spring Boot 启动类(自行修改) -->
|
||||
<mainClass>com.example.wxhk.WxhkApplication</mainClass>
|
||||
</manifest>
|
||||
<manifestEntries>
|
||||
<!-- 外部资源路径加入 manifest.mf 的 Class-Path -->
|
||||
<Class-Path>resources/</Class-Path>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
<!-- jar 输出目录 -->
|
||||
<outputDirectory>${project.build.directory}/pack/</outputDirectory>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<!-- 复制依赖 -->
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-dependencies</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<!-- 依赖包 输出目录 -->
|
||||
<outputDirectory>${project.build.directory}/pack/lib</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<!-- 复制资源 -->
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-resources</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>copy-resources</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<!-- 资源文件 输出目录 -->
|
||||
<outputDirectory>${project.build.directory}/pack/resources</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -0,0 +1,22 @@
|
||||
package com.example.wxhk;
|
||||
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.core.VertxOptions;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class WxhkApplication {
|
||||
public static final Vertx vertx;
|
||||
|
||||
static {
|
||||
vertx = Vertx.vertx(new VertxOptions().setWorkerPoolSize(5).setEventLoopPoolSize(5));
|
||||
}
|
||||
|
||||
//ConsoleInject.exe -i WeChat.exe -p D:\wxhelper.dll
|
||||
//ConsoleApplication.exe -I 4568 -p C:\wxhelper.dll -m 17484 -P 1888
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(WxhkApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.example.wxhk.constant;
|
||||
|
||||
/**
|
||||
* 接受到的微信消息类型
|
||||
*
|
||||
* @author wt
|
||||
* @date 2023/05/26
|
||||
*/
|
||||
public enum WxMsgType {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
私聊信息(1),
|
||||
好友请求(37),
|
||||
收到名片(42),
|
||||
表情(47),
|
||||
转账和收款(49),
|
||||
收到转账之后或者文件助手等信息(51),
|
||||
|
||||
入群(10000),
|
||||
/**
|
||||
* 扫码触发,会触发2次, 有一次有编号,一次没有,还有登陆之后也有,很多情况都会调用这个
|
||||
*/
|
||||
扫码触发(10002),
|
||||
|
||||
;
|
||||
Integer type;
|
||||
|
||||
WxMsgType(Integer type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Integer getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.example.wxhk.controller;
|
||||
|
||||
|
||||
import org.dromara.hutool.log.Log;
|
||||
|
||||
public class WxMsgController {
|
||||
|
||||
protected static final Log log = Log.get();
|
||||
|
||||
|
||||
void init() {
|
||||
|
||||
}
|
||||
}
|
11
java_client/src/main/java/com/example/wxhk/infe/Resp.java
Normal file
11
java_client/src/main/java/com/example/wxhk/infe/Resp.java
Normal file
@ -0,0 +1,11 @@
|
||||
package com.example.wxhk.infe;
|
||||
|
||||
/**
|
||||
* http 响应
|
||||
* @author wt
|
||||
* @date 2023/06/01
|
||||
*/
|
||||
public interface Resp extends java.io.Serializable{
|
||||
|
||||
|
||||
}
|
17
java_client/src/main/java/com/example/wxhk/infe/SendMsg.java
Normal file
17
java_client/src/main/java/com/example/wxhk/infe/SendMsg.java
Normal file
@ -0,0 +1,17 @@
|
||||
package com.example.wxhk.infe;
|
||||
|
||||
import io.vertx.core.json.JsonObject;
|
||||
|
||||
/**
|
||||
* http接口请求的基础接口
|
||||
*
|
||||
* @author wt
|
||||
* @date 2023/06/01
|
||||
*/
|
||||
public interface SendMsg<T> extends java.io.Serializable{
|
||||
|
||||
default JsonObject toJson(){
|
||||
return JsonObject.mapFrom(this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package com.example.wxhk.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 私聊
|
||||
*
|
||||
* @author wt
|
||||
* @date 2023/05/26
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class PrivateChatMsg implements Serializable {
|
||||
|
||||
String path;
|
||||
/**
|
||||
* 内容
|
||||
*/
|
||||
|
||||
private String content;
|
||||
/**
|
||||
* 当是群聊的时候 为群id,否则为微信id
|
||||
*/
|
||||
private String fromGroup;
|
||||
/**
|
||||
* 微信id
|
||||
*/
|
||||
private String fromUser;
|
||||
private Integer isSendMsg;
|
||||
/**
|
||||
* 1通过手机发送
|
||||
*/
|
||||
private Integer isSendByPhone;
|
||||
private Long msgId;
|
||||
private Integer pid;
|
||||
private String sign;
|
||||
private String signature;
|
||||
private String time;
|
||||
private Integer timestamp;
|
||||
|
||||
/**
|
||||
* 对用户,如果是文件助手是filehelper
|
||||
*/
|
||||
private String toUser;
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private Integer type;
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.example.wxhk.model.dto;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 支付信息
|
||||
*
|
||||
* @author wt
|
||||
* @param receiverUsername 付款人
|
||||
* @param decimal 收款金额
|
||||
* @param remark 备注
|
||||
* @param transcationid
|
||||
* @param transferid
|
||||
* @date 2023/06/06
|
||||
*/
|
||||
public record PayoutInformation(String receiverUsername, BigDecimal decimal, String remark,String transcationid,String transferid) implements java.io.Serializable {
|
||||
|
||||
public PayoutInformation(String receiverUsername, BigDecimal decimal, String remark) {
|
||||
this(receiverUsername, decimal, remark, null, null);
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.example.wxhk.model.request;
|
||||
|
||||
import com.example.wxhk.infe.SendMsg;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 添加wxid 好友
|
||||
* @author wt
|
||||
* @date 2023/06/01
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class AddFriends implements SendMsg<AddFriends> {
|
||||
String wxid;
|
||||
/**
|
||||
* 验证信息
|
||||
*/
|
||||
String msg;
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.example.wxhk.model.request;
|
||||
|
||||
import com.example.wxhk.infe.SendMsg;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 确认收款
|
||||
* @author wt
|
||||
* @date 2023/06/01
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class ConfirmThePayment implements SendMsg<ConfirmThePayment> {
|
||||
/**
|
||||
* 转账人微信id,从hook的消息中获取
|
||||
*/
|
||||
String wxid;
|
||||
/**
|
||||
* 从hook的消息中获取对应的字段内容
|
||||
*/
|
||||
String transcationId;
|
||||
/**
|
||||
* 从hook的消息中获取对应的字段内容。
|
||||
*/
|
||||
String transferId;
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.example.wxhk.model.request;
|
||||
|
||||
import com.example.wxhk.infe.SendMsg;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 通过手机或者qq查找微信
|
||||
* @author wt
|
||||
* @date 2023/06/01
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class FindWeChat implements SendMsg<FindWeChat> {
|
||||
/**
|
||||
* 通过 手机或qq查询信息
|
||||
*/
|
||||
String keyword;
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.example.wxhk.model.request;
|
||||
|
||||
import com.example.wxhk.infe.SendMsg;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 转发消息
|
||||
* @author wt
|
||||
* @date 2023/06/01
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class ForwardMessages implements SendMsg<ForwardMessages> {
|
||||
/**
|
||||
* 消息接收人wxid
|
||||
*/
|
||||
String wxid;
|
||||
/**
|
||||
* 消息id
|
||||
*/
|
||||
String msgid;
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.example.wxhk.model.request;
|
||||
|
||||
import com.example.wxhk.infe.SendMsg;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 获取群成员
|
||||
* @author wt
|
||||
* @date 2023/06/01
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class GetGroupMembers implements SendMsg<GetGroupMembers> {
|
||||
String chatRoomId;
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.example.wxhk.model.request;
|
||||
|
||||
import com.example.wxhk.infe.SendMsg;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 获取群成员昵称
|
||||
* @author wt
|
||||
* @date 2023/06/01
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class GetsTheNicknameOfAGroupMember implements SendMsg<GetsTheNicknameOfAGroupMember> {
|
||||
/**
|
||||
* 聊天室id
|
||||
*/
|
||||
String chatRoomId;
|
||||
/**
|
||||
* 成员id
|
||||
*/
|
||||
String memberId;
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.example.wxhk.model.request;
|
||||
|
||||
import com.example.wxhk.infe.SendMsg;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 增加群成员
|
||||
* @author wt
|
||||
* @date 2023/06/01
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class IncreaseGroupMembership implements SendMsg<IncreaseGroupMembership> {
|
||||
/**
|
||||
* 聊天室id
|
||||
*/
|
||||
String chatRoomId;
|
||||
/**
|
||||
* 成员id,以,分割
|
||||
*/
|
||||
String memberIds;
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.example.wxhk.model.request;
|
||||
|
||||
import com.example.wxhk.infe.SendMsg;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 开启hook
|
||||
*
|
||||
* @author wt
|
||||
* @date 2023/06/01
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class OpenHook implements SendMsg<OpenHook> {
|
||||
String port;
|
||||
String ip;
|
||||
/**
|
||||
* 0/1 :1.启用http 0.不启用http
|
||||
*/
|
||||
boolean enableHttp;
|
||||
/**
|
||||
* 超时时间,单位ms
|
||||
*/
|
||||
String timeout;
|
||||
|
||||
/**
|
||||
* http的请求地址,enableHttp=1时,不能为空
|
||||
*/
|
||||
String url;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.example.wxhk.model.request;
|
||||
|
||||
import com.example.wxhk.infe.SendMsg;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 发送at文本
|
||||
* @author wt
|
||||
* @date 2023/06/01
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class SendAtText implements SendMsg<SendAtText> {
|
||||
/**
|
||||
* 聊天室id,群聊用
|
||||
*/
|
||||
String chatRoomId;
|
||||
/**
|
||||
* 群聊的时候用at多个用逗号隔开,@所有人则是<b>notify@all</b>
|
||||
*/
|
||||
String wxids;
|
||||
|
||||
String msg;
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.example.wxhk.model.request;
|
||||
|
||||
import com.example.wxhk.infe.SendMsg;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 发送文件
|
||||
*
|
||||
* @author wt
|
||||
* @date 2023/06/01
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class SendFile implements SendMsg<SendFile> {
|
||||
String wxid;
|
||||
/**
|
||||
* 发送文件路径
|
||||
* "filePath": "C:/Users/123.txt"
|
||||
*/
|
||||
String filePath;
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.example.wxhk.model.request;
|
||||
|
||||
import com.example.wxhk.infe.SendMsg;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 发送图片
|
||||
*
|
||||
* @author wt
|
||||
* @date 2023/06/01
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class SendImg implements SendMsg<SendImg> {
|
||||
String wxid;
|
||||
/**
|
||||
* 发送图片接口
|
||||
* "imagePath": "C:/Users/123.png"
|
||||
*/
|
||||
String imagePath;
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package com.example.wxhk.model.request;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* http请求参数
|
||||
*
|
||||
* @author wt
|
||||
* @date 2023/06/01
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class SendMsg {
|
||||
/**
|
||||
* wxid
|
||||
*/
|
||||
String wxid;
|
||||
/**
|
||||
* 消息内容
|
||||
*/
|
||||
String msg;
|
||||
|
||||
/**
|
||||
* 聊天室id,群聊用
|
||||
*/
|
||||
String chatRoomId;
|
||||
/**
|
||||
* 成员id
|
||||
*/
|
||||
String memberId;
|
||||
|
||||
/**
|
||||
* 群聊的时候用at多个用逗号隔开,@所有人则是<b>notify@all</b>
|
||||
*/
|
||||
String wxids;
|
||||
/**
|
||||
* 发送图片接口
|
||||
* "imagePath": "C:/Users/123.png"
|
||||
*/
|
||||
String imagePath;
|
||||
/**
|
||||
* 发送文件路径
|
||||
* "filePath": "C:/Users/123.txt"
|
||||
*/
|
||||
String filePath;
|
||||
/**
|
||||
* 通过 手机或qq查询信息
|
||||
*/
|
||||
String keyword;
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.example.wxhk.model.request;
|
||||
|
||||
import com.example.wxhk.infe.SendMsg;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 发送文本
|
||||
*
|
||||
* @author wt
|
||||
* @date 2023/06/01
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class SendText implements SendMsg<SendText> {
|
||||
String wxid;
|
||||
String msg;
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.example.wxhk.model.request;
|
||||
|
||||
import com.example.wxhk.infe.SendMsg;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 通过好友请求
|
||||
* @author wt
|
||||
* @date 2023/06/01
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class ThroughFriends implements SendMsg<ThroughFriends> {
|
||||
/**
|
||||
* 添加好友消息内容里的encryptusername
|
||||
*/
|
||||
String v3;
|
||||
/**
|
||||
* 添加好友消息内容里的ticket
|
||||
*/
|
||||
String v4;
|
||||
/**
|
||||
* 好友权限,0是无限制,1是不让他看我,2是不看他,3是1+2
|
||||
*/
|
||||
String permission;
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package com.example.wxhk.model.response;
|
||||
|
||||
import com.example.wxhk.infe.Resp;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 联系人列表
|
||||
* @author wt
|
||||
* @date 2023/06/01
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class ContactList implements Resp {
|
||||
|
||||
/**
|
||||
* code : 1
|
||||
* data : [{"customAccount":"","delFlag":0,"type":1,"userName":"朋友推荐消息","verifyFlag":0,"wxid":"fmessage"},{"customAccount":"tencent_cloud","delFlag":0,"type":3,"userName":"腾讯云助手","verifyFlag":24,"wxid":"gh_a73e2407e0f8"},{"customAccount":"","delFlag":0,"type":1,"userName":"语音记事本","verifyFlag":0,"wxid":"medianote"},{"customAccount":"","delFlag":0,"type":1,"userName":"漂流瓶","verifyFlag":0,"wxid":"floatbottle"},{"customAccount":"jys-wt","delFlag":0,"type":8651011,"userName":"时光似水戏流年","verifyFlag":0,"wxid":"wxid_gf1fogt5a0pq22"},{"customAccount":"wxzhifu","delFlag":0,"type":3,"userName":"微信支付","verifyFlag":24,"wxid":"gh_3dfda90e39d6"},{"customAccount":"dhkzfr","delFlag":0,"type":3,"userName":"阿芙(代发)","verifyFlag":0,"wxid":"wxid_kh16lri40gzj22"},{"customAccount":"","delFlag":0,"type":3,"userName":"文件传输助手","verifyFlag":0,"wxid":"filehelper"},{"customAccount":"","delFlag":0,"type":3,"userName":"fff","verifyFlag":0,"wxid":"24964676359@chatroom"},{"customAccount":"","delFlag":0,"type":2,"userName":"最美阿芙","verifyFlag":0,"wxid":"23793178249@chatroom"},{"customAccount":"afu943344","delFlag":0,"type":2,"userName":"A-阿芙4号-LOL永劫云顶出租-代发","verifyFlag":0,"wxid":"wxid_1gxthknqbmwv22"},{"customAccount":"","delFlag":0,"type":3,"userName":"微信收款助手","verifyFlag":24,"wxid":"gh_f0a92aa7146c"},{"customAccount":"","delFlag":0,"type":0,"userName":"","verifyFlag":0,"wxid":"25984984710827869@openim"}]
|
||||
* result : OK
|
||||
*/
|
||||
|
||||
private Integer code;
|
||||
private String result;
|
||||
private List<DataBean> data;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public static class DataBean implements Serializable {
|
||||
/**
|
||||
* customAccount :
|
||||
* delFlag : 0
|
||||
* type : 1
|
||||
* userName : 朋友推荐消息
|
||||
* verifyFlag : 0
|
||||
* wxid : fmessage
|
||||
*/
|
||||
|
||||
private String customAccount;
|
||||
private Integer delFlag;
|
||||
private Integer type;
|
||||
private String userName;
|
||||
private Integer verifyFlag;
|
||||
private String wxid;
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.example.wxhk.model.response;
|
||||
|
||||
import com.example.wxhk.infe.Resp;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class GroupMembers implements Resp {
|
||||
|
||||
/**
|
||||
* code : 1
|
||||
* data : {"admin":"wxid_gf1fogt5a0pq22","chatRoomId":"24964676359@chatroom","members":"wxid_gf1fogt5a0pq22^Gwxid_4yr8erik0uho22"}
|
||||
* result : OK
|
||||
*/
|
||||
|
||||
private Integer code;
|
||||
private DataBean data;
|
||||
private String result;
|
||||
|
||||
@Data
|
||||
public static class DataBean implements Serializable {
|
||||
/**
|
||||
* admin : wxid_gf1fogt5a0pq22
|
||||
* chatRoomId : 24964676359@chatroom
|
||||
* members : wxid_gf1fogt5a0pq22^Gwxid_4yr8erik0uho22
|
||||
*/
|
||||
|
||||
private String admin;
|
||||
private String chatRoomId;
|
||||
private String members;
|
||||
}
|
||||
}
|
256
java_client/src/main/java/com/example/wxhk/msg/WxMsgHandle.java
Normal file
256
java_client/src/main/java/com/example/wxhk/msg/WxMsgHandle.java
Normal file
@ -0,0 +1,256 @@
|
||||
package com.example.wxhk.msg;
|
||||
|
||||
import com.example.wxhk.constant.WxMsgType;
|
||||
import com.example.wxhk.model.PrivateChatMsg;
|
||||
import com.example.wxhk.model.dto.PayoutInformation;
|
||||
import com.example.wxhk.server.WxSmgServer;
|
||||
import com.example.wxhk.tcp.vertx.InitWeChat;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import org.dromara.hutool.core.util.XmlUtil;
|
||||
import org.dromara.hutool.log.Log;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
@Component
|
||||
public class WxMsgHandle {
|
||||
public static final ConcurrentHashMap<Integer, Handle> map = new ConcurrentHashMap<>(32);
|
||||
protected static final Log log = Log.get();
|
||||
/**
|
||||
* 文件传输助手
|
||||
*/
|
||||
public static final String FILEHELPER = "filehelper";
|
||||
/**
|
||||
* 收款码缓存 因为有2段信息,一段是交易id,里面可以解析出来源方,二段解析出金额
|
||||
*/
|
||||
public static ConcurrentHashMap<String, String> collection_code_caching = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
public static WxSmgServer wxSmgServer;
|
||||
/**
|
||||
* 看
|
||||
*/
|
||||
public static final ReentrantReadWriteLock LOOK = new ReentrantReadWriteLock();
|
||||
|
||||
@Autowired
|
||||
public void setWxSmgServer(WxSmgServer wxSmgServer) {
|
||||
WxMsgHandle.wxSmgServer = wxSmgServer;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
add(chatMsg -> {
|
||||
if(Objects.equals(chatMsg.getToUser(), FILEHELPER)){
|
||||
wxSmgServer.文件助手(chatMsg);
|
||||
}else{
|
||||
wxSmgServer.私聊(chatMsg);
|
||||
}
|
||||
|
||||
return null;
|
||||
}, WxMsgType.私聊信息);
|
||||
add(chatMsg -> {
|
||||
if (FILEHELPER.equals(chatMsg.getFromUser())) {
|
||||
wxSmgServer.文件助手(chatMsg);
|
||||
}
|
||||
return 1;
|
||||
}, WxMsgType.收到转账之后或者文件助手等信息);
|
||||
add(chatMsg -> {
|
||||
wxSmgServer.收到名片(chatMsg);
|
||||
return 1;
|
||||
}, WxMsgType.收到名片);
|
||||
add(chatMsg -> {
|
||||
wxSmgServer.收到好友请求(chatMsg);
|
||||
return 1;
|
||||
}, WxMsgType.好友请求);// 好友请求
|
||||
add(chatMsg -> {
|
||||
boolean f = 解析扫码支付第二段(chatMsg);
|
||||
if (f) {
|
||||
f = 解析收款信息1段(chatMsg);
|
||||
if (f) {
|
||||
解析收款信息2段(chatMsg);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}, WxMsgType.转账和收款);
|
||||
add(chatMsg -> {
|
||||
boolean f = 解析扫码支付第一段(chatMsg);
|
||||
return null;
|
||||
}, WxMsgType.扫码触发);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析扫码支付第一段,得到交易id和微信id
|
||||
*
|
||||
* @param chatMsg
|
||||
* @return boolean 返回true 则继续解析,否则解析成功,不需要解析了
|
||||
*/
|
||||
public static boolean 解析扫码支付第一段(PrivateChatMsg chatMsg) {
|
||||
try {
|
||||
Document document = XmlUtil.parseXml(chatMsg.getContent());
|
||||
Element documentElement = document.getDocumentElement();
|
||||
String localName = documentElement.getLocalName();
|
||||
if ("sysmsg".equals(localName)) {
|
||||
String type = documentElement.getAttribute("type");
|
||||
if ("paymsg".equals(type)) {
|
||||
NodeList outtradeno = documentElement.getElementsByTagName("outtradeno");
|
||||
if (outtradeno.getLength() > 0) {
|
||||
String textContent = outtradeno.item(0).getTextContent();
|
||||
String textContent1 = documentElement.getElementsByTagName("username").item(0).getTextContent();
|
||||
collection_code_caching.put(textContent, textContent1);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 解析扫码支付第二段
|
||||
*
|
||||
* @param chatMsg 聊天味精
|
||||
* @return boolean true 则 继续解析, false则解析成功,不需要再解析了
|
||||
*/
|
||||
public static boolean 解析扫码支付第二段(PrivateChatMsg chatMsg) {
|
||||
try {
|
||||
Document document = XmlUtil.parseXml(chatMsg.getContent());
|
||||
Element documentElement = document.getDocumentElement();
|
||||
String localName = documentElement.getLocalName();
|
||||
if ("msg".equals(localName)) {
|
||||
NodeList outtradeno = documentElement.getElementsByTagName("weapp_path");
|
||||
if (outtradeno.getLength() > 1) {
|
||||
String textContent = outtradeno.item(1).getTextContent();
|
||||
Set<Map.Entry<String, String>> entries = collection_code_caching.entrySet();
|
||||
Iterator<Map.Entry<String, String>> iterator = entries.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, String> next = iterator.next();
|
||||
if (textContent.contains(next.getKey())) {
|
||||
// 得到了交易信息
|
||||
NodeList word = documentElement.getElementsByTagName("word");
|
||||
String monery = word.item(1).getTextContent();
|
||||
String remark = word.item(3).getTextContent();
|
||||
if (monery.startsWith("¥")) {
|
||||
String substring = monery.substring(1);
|
||||
BigDecimal decimal = new BigDecimal(substring);
|
||||
log.info("扫码收款:{},付款人:{},付款备注:{}", decimal.stripTrailingZeros().toPlainString(), next.getValue(), remark);
|
||||
wxSmgServer.扫码收款(new PayoutInformation(next.getValue(),decimal,remark));
|
||||
iterator.remove();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean 解析收款信息2段(PrivateChatMsg chatMsg) {
|
||||
try {
|
||||
Document document = XmlUtil.parseXml(chatMsg.getContent());
|
||||
Element documentElement = document.getDocumentElement();
|
||||
String localName = documentElement.getLocalName();
|
||||
if ("msg".equals(localName)) {
|
||||
if (documentElement.getElementsByTagName("transcationid").getLength() > 0) {
|
||||
String remark = documentElement.getElementsByTagName("pay_memo").item(0).getTextContent();
|
||||
String monery = documentElement.getElementsByTagName("feedesc").item(0).getTextContent();
|
||||
String receiver_username = documentElement.getElementsByTagName("receiver_username").item(0).getTextContent();
|
||||
// 如果是机器人发出的,则跳过解析
|
||||
if (InitWeChat.WXID_MAP.contains(receiver_username) ) {
|
||||
return false;
|
||||
}
|
||||
if (monery.startsWith("¥")) {
|
||||
String substring = monery.substring(1);
|
||||
BigDecimal decimal = new BigDecimal(substring);
|
||||
log.info("收款:{},付款人:{},付款备注:{}", decimal.stripTrailingZeros().toPlainString(), receiver_username, remark);
|
||||
wxSmgServer.收款之后(new PayoutInformation(receiver_username, decimal, remark));
|
||||
return false;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 解析收款信息1段
|
||||
* <b>会自动进行收款</b>
|
||||
*
|
||||
* @param chatMsg
|
||||
* @return boolean true则 继续解析,false则不需要解析了
|
||||
*/
|
||||
public static boolean 解析收款信息1段(PrivateChatMsg chatMsg) {
|
||||
try {
|
||||
String content = chatMsg.getContent();
|
||||
Document document = XmlUtil.parseXml(content);
|
||||
NodeList paysubtype1 = document.getElementsByTagName("paysubtype");
|
||||
if (paysubtype1.getLength() == 0) {
|
||||
return true;
|
||||
}
|
||||
Node paysubtype = paysubtype1.item(0);
|
||||
if ("1".equals(paysubtype.getTextContent().trim())) {
|
||||
// 手机发出去的
|
||||
String textContent = document.getElementsByTagName("receiver_username").item(0).getTextContent();
|
||||
if (!InitWeChat.WXID_MAP.contains(textContent)) {
|
||||
// 如果不是机器人收款,则认为不需要解析了,大概率是机器人自己发出去的
|
||||
return false;
|
||||
}
|
||||
|
||||
String remark = document.getElementsByTagName("pay_memo").item(0).getTextContent();
|
||||
String monery = document.getElementsByTagName("feedesc").item(0).getTextContent();
|
||||
String receiver_username = document.getElementsByTagName("receiver_username").item(0).getTextContent();
|
||||
if (monery.startsWith("¥")) {
|
||||
String substring = monery.substring(1);
|
||||
BigDecimal decimal = new BigDecimal(substring);
|
||||
Node transcationid = document.getDocumentElement().getElementsByTagName("transcationid").item(0);
|
||||
Node transferid = document.getDocumentElement().getElementsByTagName("transferid").item(0);
|
||||
wxSmgServer.接到收款(new PayoutInformation(chatMsg.getFromUser(), decimal, remark, transcationid.getTextContent(), transferid.getTextContent()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void exec(PrivateChatMsg chatMsg) {
|
||||
Handle handle = map.get(chatMsg.getType());
|
||||
if (handle != null) {
|
||||
handle.handle(chatMsg);
|
||||
}
|
||||
}
|
||||
|
||||
public void add(Handle handle, WxMsgType... type) {
|
||||
for (WxMsgType integer : type) {
|
||||
map.put(integer.getType(), handle);
|
||||
}
|
||||
}
|
||||
|
||||
public interface Handle {
|
||||
Object handle(PrivateChatMsg chatMsg);
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.example.wxhk.server;
|
||||
|
||||
import com.example.wxhk.model.PrivateChatMsg;
|
||||
import com.example.wxhk.model.dto.PayoutInformation;
|
||||
|
||||
/**
|
||||
* 微信消息处理提取
|
||||
* @author wt
|
||||
* @date 2023/06/06
|
||||
*/
|
||||
public interface WxSmgServer {
|
||||
/**
|
||||
* 接到收款
|
||||
*
|
||||
* @param payoutInformation 支付信息
|
||||
*/
|
||||
void 接到收款(PayoutInformation payoutInformation);
|
||||
|
||||
void 收款之后(PayoutInformation pay);
|
||||
|
||||
void 私聊(PrivateChatMsg chatMsg);
|
||||
|
||||
void 文件助手(PrivateChatMsg chatMsg);
|
||||
|
||||
void 收到名片(PrivateChatMsg chatMsg);
|
||||
|
||||
void 收到好友请求(PrivateChatMsg chatMsg);
|
||||
|
||||
void 扫码收款(PayoutInformation payoutInformation);
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package com.example.wxhk.server.impl;
|
||||
|
||||
import com.example.wxhk.model.PrivateChatMsg;
|
||||
import com.example.wxhk.model.dto.PayoutInformation;
|
||||
import com.example.wxhk.model.request.ConfirmThePayment;
|
||||
import com.example.wxhk.util.HttpSendUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.util.XmlUtil;
|
||||
import org.dromara.hutool.log.Log;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@Service
|
||||
public class WxSmgServerImpl implements com.example.wxhk.server.WxSmgServer {
|
||||
|
||||
protected static final Log log=Log.get();
|
||||
|
||||
public static final String FILEHELPER = "filehelper";
|
||||
@Override
|
||||
public void 接到收款(PayoutInformation payoutInformation) {
|
||||
HttpSendUtil.确认收款(new ConfirmThePayment().setWxid(payoutInformation.receiverUsername()).setTranscationId(payoutInformation.transcationid()).setTransferId(payoutInformation.transferid()));
|
||||
}
|
||||
@Override
|
||||
public void 收款之后(PayoutInformation pay) {
|
||||
HttpSendUtil.发送文本(pay.receiverUsername(), StrUtil.format("收到款项:{},备注:{}", pay.decimal().stripTrailingZeros().toPlainString(), pay.remark()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void 私聊(PrivateChatMsg chatMsg) {
|
||||
if (Objects.equals(chatMsg.getIsSendMsg(), 1) && Objects.equals(chatMsg.getIsSendByPhone(), 1)) {
|
||||
log.info("手机端对:{}发出:{}", chatMsg.getFromUser(), chatMsg.getContent());
|
||||
}else{
|
||||
log.info("收到私聊{}",chatMsg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void 文件助手(PrivateChatMsg chatMsg) {
|
||||
log.info("文件助手:{}",chatMsg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void 收到名片(PrivateChatMsg chatMsg) {
|
||||
if (FILEHELPER.equals(chatMsg.getFromUser())) {
|
||||
Document document = XmlUtil.parseXml(chatMsg.getContent());
|
||||
Element documentElement = document.getDocumentElement();
|
||||
String username = documentElement.getAttribute("username");
|
||||
if (StrUtil.isNotBlank(username)) {
|
||||
HttpSendUtil.发送文本(username);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void 收到好友请求(PrivateChatMsg chatMsg) {
|
||||
HttpSendUtil.通过好友请求(chatMsg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void 扫码收款(PayoutInformation payoutInformation) {
|
||||
HttpSendUtil.发送文本(payoutInformation.receiverUsername(), StrUtil.format("扫码收款:{},备注:{}", payoutInformation.decimal().stripTrailingZeros().toPlainString(), payoutInformation.remark()));
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
package com.example.wxhk.tcp.vertx;
|
||||
|
||||
import com.example.wxhk.model.PrivateChatMsg;
|
||||
import com.example.wxhk.msg.WxMsgHandle;
|
||||
import com.example.wxhk.util.HttpSendUtil;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import org.dromara.hutool.core.thread.NamedThreadFactory;
|
||||
import org.dromara.hutool.log.Log;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 消息处理
|
||||
*
|
||||
* @author wt
|
||||
* @date 2023/05/31
|
||||
*/
|
||||
@Component
|
||||
public class ArrHandle {
|
||||
|
||||
/**
|
||||
* 线程处理消息队列,但是必须保证核心数大于2,其中必定要有一个线程可以单独处理交易队列信息
|
||||
*/
|
||||
public static final ThreadPoolExecutor sub = new ThreadPoolExecutor(4, 10, 30, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new NamedThreadFactory("sub", false));
|
||||
public static final ThreadLocal<PrivateChatMsg> chatMsgThreadLocal = new InheritableThreadLocal<>();
|
||||
protected static final Log log = Log.get();
|
||||
|
||||
/**
|
||||
* 得到当前正在处理的消息
|
||||
*
|
||||
* @return {@link PrivateChatMsg}
|
||||
*/
|
||||
public static PrivateChatMsg getPriMsg() {
|
||||
return chatMsgThreadLocal.get();
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void exec() {
|
||||
for (int i = 0; i < sub.getCorePoolSize()-1; i++) {
|
||||
sub.submit(() -> {
|
||||
while (!Thread.currentThread().isInterrupted()) {
|
||||
try {
|
||||
JsonObject take = VertxTcp.LINKED_BLOCKING_QUEUE.take();
|
||||
log.info("{}", take.encode());
|
||||
PrivateChatMsg privateChatMsg = take.mapTo(PrivateChatMsg.class);
|
||||
chatMsgThreadLocal.set(privateChatMsg);
|
||||
if ("weixin".equals(privateChatMsg.getFromUser())) {
|
||||
String s = HttpSendUtil.获取当前登陆微信id();
|
||||
InitWeChat.WXID_MAP.add(s);
|
||||
continue;
|
||||
}
|
||||
WxMsgHandle.exec(privateChatMsg);
|
||||
} catch (Exception e) {
|
||||
log.error(e);
|
||||
}finally {
|
||||
chatMsgThreadLocal.remove();
|
||||
}
|
||||
}
|
||||
log.error("退出线程了");
|
||||
});
|
||||
}
|
||||
sub.submit(() -> {
|
||||
while (!Thread.currentThread().isInterrupted()) {
|
||||
try {
|
||||
JsonObject take = VertxTcp.LINKED_BLOCKING_QUEUE_MON.take();
|
||||
log.info("{}", take.encode());
|
||||
PrivateChatMsg privateChatMsg = take.mapTo(PrivateChatMsg.class);
|
||||
chatMsgThreadLocal.set(privateChatMsg);
|
||||
if ("weixin".equals(privateChatMsg.getFromUser())) {
|
||||
String s = HttpSendUtil.获取当前登陆微信id();
|
||||
InitWeChat.WXID_MAP.add(s);
|
||||
continue;
|
||||
}
|
||||
WxMsgHandle.exec(privateChatMsg);
|
||||
} catch (Exception e) {
|
||||
log.error(e);
|
||||
}finally {
|
||||
chatMsgThreadLocal.remove();
|
||||
}
|
||||
}
|
||||
log.error("退出线程了");
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,158 @@
|
||||
package com.example.wxhk.tcp.vertx;
|
||||
|
||||
import com.example.wxhk.util.HttpAsyncUtil;
|
||||
import com.example.wxhk.util.HttpSyncUtil;
|
||||
import io.vertx.core.impl.ConcurrentHashSet;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import org.dromara.hutool.core.io.file.FileUtil;
|
||||
import org.dromara.hutool.core.net.NetUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.thread.ThreadUtil;
|
||||
import org.dromara.hutool.log.Log;
|
||||
import org.dromara.hutool.setting.Setting;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 微信注入环境初始化和相关方法
|
||||
*
|
||||
* @author wt
|
||||
* @date 2023/05/16
|
||||
*/
|
||||
@Order(-1)
|
||||
@Component
|
||||
public class InitWeChat implements CommandLineRunner {
|
||||
|
||||
public final static Log log = Log.get();
|
||||
public static final ConcurrentHashSet<String> WXID_MAP = new ConcurrentHashSet<>();
|
||||
public static String wxPath;
|
||||
public static Integer wxPort;
|
||||
public static Integer vertxPort;
|
||||
/**
|
||||
* wxhelper.dll 所在路径
|
||||
*/
|
||||
public static File DLL_PATH;
|
||||
|
||||
public static void 注入dll(String wxPid) throws IOException {
|
||||
String format = StrUtil.format("cmd /C c.exe -I {} -p {}\\wxhelper.dll -m {}", wxPid, DLL_PATH.getAbsolutePath(), wxPid);
|
||||
Process exec = Runtime.getRuntime().exec(format, null, DLL_PATH);
|
||||
log.info("注入结果:{}", new String(exec.getInputStream().readAllBytes(), "gbk"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static File 环境初始化() {
|
||||
File target = new File(new File("").getAbsolutePath().split("\\\\")[0] + "\\exec\\");
|
||||
try {
|
||||
File wxPathFile = new File(wxPath);
|
||||
File config = new File(wxPathFile.getParentFile(), "config.ini");
|
||||
Setting setting = new Setting(config.getAbsolutePath());
|
||||
setting.getGroupedMap().put("config", "port", String.valueOf(wxPort));
|
||||
setting.store();
|
||||
ClassPathResource classPathResource = new ClassPathResource("exec");
|
||||
File file = classPathResource.getFile();
|
||||
target.mkdir();
|
||||
for (File listFile : file.listFiles()) {
|
||||
FileUtil.copy(listFile, target, true);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e, "环境初始化失败,请检查");
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回最后一个微信的pid
|
||||
*
|
||||
* @return {@link String}
|
||||
* @throws IOException ioexception
|
||||
*/
|
||||
public static String createWx() throws IOException {
|
||||
Runtime.getRuntime().exec("cmd /C \"" + wxPath + "\"");
|
||||
return getWxPid();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getWxPid() throws IOException {
|
||||
String line = null;
|
||||
try {
|
||||
Process exec = Runtime.getRuntime().exec("cmd /C tasklist /FI \"IMAGENAME eq WeChat.exe\" ");
|
||||
byte[] bytes = exec.getInputStream().readAllBytes();
|
||||
line = new String(bytes, "gbk");
|
||||
String[] split = line.split("\n");
|
||||
if (!line.contains("WeChat.exe")) {
|
||||
return createWx();
|
||||
}
|
||||
String[] split1 = split[split.length - 1].replaceAll("\\s{2,}", " ").split(" ");
|
||||
return split1[1];
|
||||
} catch (IOException e) {
|
||||
log.error("获取端口错误:{}", line);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public static Integer getWxPort() {
|
||||
return wxPort;
|
||||
}
|
||||
|
||||
@Value("${wx.port}")
|
||||
public void setWxPort(Integer wxPort) {
|
||||
InitWeChat.wxPort = wxPort;
|
||||
}
|
||||
|
||||
public static String getWxPath() {
|
||||
return wxPath;
|
||||
}
|
||||
|
||||
@Value("${wx.path}")
|
||||
public void setWxPath(String wxPath) {
|
||||
InitWeChat.wxPath = wxPath;
|
||||
}
|
||||
|
||||
public static Integer getVertxPort() {
|
||||
return vertxPort;
|
||||
}
|
||||
|
||||
@Value("${vertx.port}")
|
||||
public void setVertxPort(Integer vertxPort) {
|
||||
InitWeChat.vertxPort = vertxPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
//tasklist /FI "IMAGENAME eq WeChat.exe" /m
|
||||
boolean usableLocalPort = NetUtil.isUsableLocalPort(wxPort);
|
||||
if (usableLocalPort) {
|
||||
DLL_PATH = 环境初始化();
|
||||
String wxPid = getWxPid();
|
||||
注入dll(wxPid);
|
||||
}
|
||||
ThreadUtil.execute(() -> {
|
||||
while (!Thread.currentThread().isInterrupted()) {
|
||||
JsonObject exec = HttpSyncUtil.exec(HttpAsyncUtil.Type.检查微信登陆, new JsonObject());
|
||||
if (exec.getInteger("code").equals(1)) {
|
||||
JsonObject dl = HttpSyncUtil.exec(HttpAsyncUtil.Type.获取登录信息, new JsonObject());
|
||||
JsonObject jsonObject = dl.getJsonObject("data");
|
||||
String wx = jsonObject.getString("wxid");
|
||||
WXID_MAP.add(wx);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("检测到微信登陆:{}", wx);
|
||||
}
|
||||
break;
|
||||
}
|
||||
ThreadUtil.safeSleep(500);
|
||||
}
|
||||
|
||||
});
|
||||
// FIXME: 2023/6/2 程序结束后关闭hook会偶尔出现微信闪退情况,暂时禁用
|
||||
// Runtime.getRuntime().addShutdownHook(new Thread(HttpSendUtil::关闭hook));
|
||||
//netstat -aon|findstr "端口号"
|
||||
// c.exe -I 4568 -p D:\exec\wxhelper.dll -m 4568
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
package com.example.wxhk.tcp.vertx;
|
||||
|
||||
import com.example.wxhk.WxhkApplication;
|
||||
import com.example.wxhk.constant.WxMsgType;
|
||||
import com.example.wxhk.model.request.OpenHook;
|
||||
import com.example.wxhk.util.HttpSendUtil;
|
||||
import io.vertx.core.AbstractVerticle;
|
||||
import io.vertx.core.DeploymentOptions;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.Promise;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.core.net.NetServer;
|
||||
import io.vertx.core.net.NetServerOptions;
|
||||
import io.vertx.core.parsetools.JsonParser;
|
||||
import org.dromara.hutool.log.Log;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
/**
|
||||
* 接受微信hook信息
|
||||
*
|
||||
* @author wt
|
||||
* @date 2023/05/26
|
||||
*/
|
||||
@Component
|
||||
@Order()
|
||||
public class VertxTcp extends AbstractVerticle implements CommandLineRunner {
|
||||
public final static LinkedBlockingQueue<JsonObject> LINKED_BLOCKING_QUEUE = new LinkedBlockingQueue<>();
|
||||
/**
|
||||
* 这个只保留交易相关的类型
|
||||
*/
|
||||
public final static LinkedBlockingQueue<JsonObject> LINKED_BLOCKING_QUEUE_MON = new LinkedBlockingQueue<>();
|
||||
protected static final Log log = Log.get();
|
||||
NetServer netServer;
|
||||
|
||||
@Override
|
||||
public void start(Promise<Void> startPromise) throws Exception {
|
||||
netServer = vertx.createNetServer(new NetServerOptions()
|
||||
.setPort(InitWeChat.getVertxPort())
|
||||
.setIdleTimeout(0)
|
||||
.setLogActivity(false)
|
||||
);
|
||||
netServer.connectHandler(socket -> {
|
||||
JsonParser parser = JsonParser.newParser();
|
||||
parser.objectValueMode();
|
||||
parser.handler(event -> {
|
||||
switch (event.type()) {
|
||||
case START_OBJECT -> {
|
||||
}
|
||||
case END_OBJECT -> {
|
||||
}
|
||||
case START_ARRAY -> {
|
||||
}
|
||||
case END_ARRAY -> {
|
||||
}
|
||||
case VALUE -> {
|
||||
JsonObject entries = event.objectValue();
|
||||
|
||||
if(Objects.equals(entries.getInteger("type"), WxMsgType.扫码触发.getType()) ||
|
||||
Objects.equals(entries.getInteger("type"), WxMsgType.转账和收款.getType())){
|
||||
LINKED_BLOCKING_QUEUE_MON.add(entries);
|
||||
}else{
|
||||
LINKED_BLOCKING_QUEUE.add(entries);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
socket.handler(parser);
|
||||
});
|
||||
|
||||
Future<NetServer> listen = netServer.listen();
|
||||
listen.onComplete(event -> {
|
||||
boolean succeeded = event.succeeded();
|
||||
if (succeeded) {
|
||||
HttpSendUtil.开启hook(new OpenHook().setPort(InitWeChat.getVertxPort().toString()).setIp("127.0.0.1")
|
||||
.setEnableHttp(false)
|
||||
.setTimeout("5000"));
|
||||
// HttpAsyncUtil.exec(HttpAsyncUtil.Type.开启hook, new JsonObject().put("port", InitWeChat.getVertxPort().toString()).put("ip", "127.0.0.1"));
|
||||
startPromise.complete();
|
||||
} else {
|
||||
startPromise.fail(event.cause());
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
WxhkApplication.vertx.deployVerticle(this, new DeploymentOptions().setWorkerPoolSize(6));
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
package com.example.wxhk.util;
|
||||
|
||||
import com.example.wxhk.WxhkApplication;
|
||||
import com.example.wxhk.tcp.vertx.InitWeChat;
|
||||
import io.vertx.core.AsyncResult;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.Handler;
|
||||
import io.vertx.core.buffer.Buffer;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.ext.web.client.HttpResponse;
|
||||
import io.vertx.ext.web.client.WebClient;
|
||||
import io.vertx.ext.web.client.WebClientOptions;
|
||||
import org.dromara.hutool.log.Log;
|
||||
|
||||
/**
|
||||
* http异步请求
|
||||
*
|
||||
* @author wt
|
||||
* @date 2023/05/25
|
||||
*/
|
||||
public class HttpAsyncUtil {
|
||||
public static final WebClient client = WebClient.create(WxhkApplication.vertx, new WebClientOptions().setDefaultHost("localhost").setDefaultPort(InitWeChat.wxPort)
|
||||
.setConnectTimeout(10000).setMaxPoolSize(10).setPoolEventLoopSize(10));
|
||||
protected static final Log log = Log.get();
|
||||
|
||||
public static Future<HttpResponse<Buffer>> exec(Type type, JsonObject object) {
|
||||
return client.post(InitWeChat.wxPort, "localhost", "/api/" + type.getType())
|
||||
.sendJsonObject(object)
|
||||
.onSuccess(event ->
|
||||
{
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("type:{},{}", type.getType(), event.bodyAsJsonObject());
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public static Future<HttpResponse<Buffer>> exec(Type type, JsonObject object, Handler<AsyncResult<HttpResponse<Buffer>>> handler) {
|
||||
return client.post(InitWeChat.wxPort, "localhost", "/api/" + type.getType())
|
||||
.sendJsonObject(object)
|
||||
.onComplete(handler)
|
||||
;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
检查微信登陆("checkLogin"),
|
||||
获取登录信息("userInfo"),
|
||||
发送文本("sendTextMsg"),
|
||||
转发消息("forwardMsg"),
|
||||
发送at文本("sendAtText"),
|
||||
发送图片("5"),
|
||||
发送文件("sendFileMsg"),
|
||||
开启hook("hookSyncMsg"),
|
||||
关闭hook("unhookSyncMsg"),
|
||||
添加好友("20"),
|
||||
通过好友申请("23"),
|
||||
获取群成员("getMemberFromChatRoom"),
|
||||
获取群成员基础信息("getContactProfile"),
|
||||
获取群详情("getChatRoomDetailInfo"),
|
||||
添加群成员("addMemberToChatRoom"),
|
||||
修改群昵称("modifyNickname"),
|
||||
删除群成员("delMemberFromChatRoom"),
|
||||
置顶群消息("topMsg"),
|
||||
取消置顶群消息("removeTopMsg"),
|
||||
邀请入群("InviteMemberToChatRoom"),
|
||||
确认收款("45"),
|
||||
联系人列表("getContactList"),
|
||||
查询微信信息("55"),
|
||||
下载附件("downloadAttach"),
|
||||
解码("decodeImage"),
|
||||
|
||||
|
||||
;
|
||||
String type;
|
||||
|
||||
Type(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
package com.example.wxhk.util;
|
||||
|
||||
import com.example.wxhk.model.PrivateChatMsg;
|
||||
import com.example.wxhk.model.request.*;
|
||||
import com.example.wxhk.model.response.ContactList;
|
||||
import com.example.wxhk.model.response.GroupMembers;
|
||||
import com.example.wxhk.tcp.vertx.ArrHandle;
|
||||
import com.example.wxhk.tcp.vertx.InitWeChat;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import org.dromara.hutool.core.util.XmlUtil;
|
||||
import org.dromara.hutool.log.Log;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* 常见方法
|
||||
*
|
||||
* @author wt
|
||||
* @date 2023/05/29
|
||||
*/
|
||||
public class HttpSendUtil {
|
||||
|
||||
protected static final Log log = Log.get();
|
||||
|
||||
public static JsonObject 通过好友请求(PrivateChatMsg msg) {
|
||||
Document document = XmlUtil.parseXml(msg.getContent());
|
||||
String encryptusername = document.getDocumentElement().getAttribute("encryptusername");
|
||||
String ticket = document.getDocumentElement().getAttribute("ticket");
|
||||
return HttpSyncUtil.exec(HttpAsyncUtil.Type.通过好友申请, new JsonObject().put("v3", encryptusername).put("v4", ticket).put("permission", "0"));
|
||||
}
|
||||
|
||||
public static JsonObject 确认收款(PrivateChatMsg msg) {
|
||||
try {
|
||||
String content = msg.getContent();
|
||||
Document document = XmlUtil.parseXml(content);
|
||||
Node paysubtype = document.getElementsByTagName("paysubtype").item(0);
|
||||
if ("1".equals(paysubtype.getTextContent().trim())) {
|
||||
// 手机发出去的
|
||||
String textContent = document.getElementsByTagName("receiver_username").item(0).getTextContent();
|
||||
if (!InitWeChat.WXID_MAP.contains(textContent)) {
|
||||
return new JsonObject().put("spick", true);
|
||||
}
|
||||
Node transcationid = document.getDocumentElement().getElementsByTagName("transcationid").item(0);
|
||||
Node transferid = document.getDocumentElement().getElementsByTagName("transferid").item(0);
|
||||
return HttpSyncUtil.exec(HttpAsyncUtil.Type.确认收款, new JsonObject().put("wxid", msg.getFromUser())
|
||||
.put("transcationId", transcationid.getTextContent())
|
||||
.put("transferId", transferid.getTextContent()));
|
||||
|
||||
}
|
||||
// 如果是确认接受收款,则跳过
|
||||
return new JsonObject();
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static JsonObject 发送文本(String wxid, String msg) {
|
||||
return HttpSyncUtil.exec(HttpAsyncUtil.Type.发送文本, JsonObject.mapFrom(new SendMsg().setMsg(msg).setWxid(wxid)));
|
||||
}
|
||||
|
||||
public static JsonObject 发送文本(String msg) {
|
||||
return 发送文本(ArrHandle.getPriMsg().getFromUser(), msg);
|
||||
}
|
||||
|
||||
public static JsonObject 发送at文本(String chatRoomId, String wxids, String msg) {
|
||||
return HttpSyncUtil.exec(HttpAsyncUtil.Type.发送at文本, JsonObject.mapFrom(new SendMsg().setMsg(msg).setWxids(wxids).setChatRoomId(chatRoomId)));
|
||||
}
|
||||
|
||||
public static JsonObject 发送at文本(String wxids, String msg) {
|
||||
return 发送at文本(ArrHandle.getPriMsg().getFromGroup(), wxids, msg);
|
||||
}
|
||||
|
||||
public static JsonObject 发送图片(String wxid, String msg) {
|
||||
return HttpSyncUtil.exec(HttpAsyncUtil.Type.发送图片, JsonObject.mapFrom(new SendMsg().setImagePath(msg).setWxid(wxid)));
|
||||
}
|
||||
|
||||
public static JsonObject 发送图片(String msg) {
|
||||
return 发送图片(ArrHandle.getPriMsg().getFromUser(), msg);
|
||||
}
|
||||
|
||||
public static JsonObject 发送文件(String wxid, String msg) {
|
||||
return HttpSyncUtil.exec(HttpAsyncUtil.Type.发送文件, JsonObject.mapFrom(new SendMsg().setFilePath(msg).setWxid(wxid)));
|
||||
}
|
||||
|
||||
public static JsonObject 发送文件(String msg) {
|
||||
return 发送文件(ArrHandle.getPriMsg().getFromUser(), msg);
|
||||
}
|
||||
|
||||
public static JsonObject 添加好友(AddFriends p) {
|
||||
return HttpSyncUtil.exec(HttpAsyncUtil.Type.添加好友, p.toJson());
|
||||
}
|
||||
|
||||
|
||||
public static String 获取当前登陆微信id() {
|
||||
JsonObject exec = HttpSyncUtil.exec(HttpAsyncUtil.Type.获取登录信息, new JsonObject());
|
||||
return exec.getJsonObject("data").getString("wxid");
|
||||
}
|
||||
|
||||
public static ContactList 联系人列表(){
|
||||
JsonObject exec = HttpSyncUtil.exec(HttpAsyncUtil.Type.联系人列表, new JsonObject());
|
||||
return exec.mapTo(ContactList.class);
|
||||
}
|
||||
public static JsonObject 开启hook(OpenHook hook){
|
||||
JsonObject exec = HttpSyncUtil.exec(HttpAsyncUtil.Type.开启hook,hook.toJson());
|
||||
return exec;
|
||||
}
|
||||
public static JsonObject 关闭hook(){
|
||||
JsonObject exec = HttpSyncUtil.exec(HttpAsyncUtil.Type.关闭hook,new JsonObject());
|
||||
return exec;
|
||||
}
|
||||
|
||||
public static GroupMembers 获取群成员(GetGroupMembers p){
|
||||
return HttpSyncUtil.exec(HttpAsyncUtil.Type.获取群成员, p.toJson()).mapTo(GroupMembers.class);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static JsonObject 确认收款(ConfirmThePayment payment){
|
||||
return HttpSyncUtil.exec(HttpAsyncUtil.Type.确认收款, payment.toJson());
|
||||
}
|
||||
|
||||
|
||||
@Deprecated
|
||||
public static com.example.wxhk.infe.SendMsg of(HttpAsyncUtil.Type type) {
|
||||
switch (type) {
|
||||
|
||||
case 检查微信登陆 -> {
|
||||
|
||||
}
|
||||
case 获取登录信息 -> {
|
||||
}
|
||||
case 发送文本 -> {
|
||||
return new SendText();
|
||||
}
|
||||
case 发送at文本 -> {
|
||||
return new SendAtText();
|
||||
}
|
||||
case 发送图片 -> {
|
||||
return new SendImg();
|
||||
}
|
||||
case 发送文件 -> {
|
||||
return new SendFile();
|
||||
}
|
||||
|
||||
}
|
||||
return new SendText();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package com.example.wxhk.util;
|
||||
|
||||
import com.example.wxhk.tcp.vertx.InitWeChat;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import org.dromara.hutool.http.client.ClientConfig;
|
||||
import org.dromara.hutool.http.client.Request;
|
||||
import org.dromara.hutool.http.client.engine.ClientEngine;
|
||||
import org.dromara.hutool.http.client.engine.ClientEngineFactory;
|
||||
import org.dromara.hutool.http.meta.Method;
|
||||
import org.dromara.hutool.log.Log;
|
||||
|
||||
/**
|
||||
* http同步请求
|
||||
*
|
||||
* @author wt
|
||||
* @date 2023/05/25
|
||||
*/
|
||||
public class HttpSyncUtil {
|
||||
protected static final Log log = Log.get();
|
||||
static final ClientEngine engine;
|
||||
|
||||
static {
|
||||
ClientConfig clientConfig = ClientConfig.of()
|
||||
.setTimeout(30 * 1000);
|
||||
engine = ClientEngineFactory.createEngine(clientConfig);
|
||||
|
||||
}
|
||||
|
||||
public static JsonObject exec(HttpAsyncUtil.Type type, JsonObject obj) {
|
||||
String post = engine.send(Request.of("http://localhost:" + InitWeChat.wxPort + "/api/" + type.getType()).method(Method.POST).body(obj.encode())).bodyStr();
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("type:{},{}", type.getType(), post);
|
||||
}
|
||||
return new JsonObject(post);
|
||||
}
|
||||
}
|
4
java_client/src/main/resources/application.properties
Normal file
4
java_client/src/main/resources/application.properties
Normal file
@ -0,0 +1,4 @@
|
||||
wx.path=D:\\Program Files (x86)\\Tencent\\WeChat\\WeChat.exe
|
||||
wx.port=19088
|
||||
spring.profiles.active=local
|
||||
vertx.port=8080
|
BIN
java_client/src/main/resources/exec/c.exe
Normal file
BIN
java_client/src/main/resources/exec/c.exe
Normal file
Binary file not shown.
BIN
java_client/src/main/resources/exec/wxhelper.dll
Normal file
BIN
java_client/src/main/resources/exec/wxhelper.dll
Normal file
Binary file not shown.
171
java_client/src/main/resources/logback-spring.xml
Normal file
171
java_client/src/main/resources/logback-spring.xml
Normal file
@ -0,0 +1,171 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
|
||||
<!--日志格式应用spring boot默认的格式,也可以自己更改-->
|
||||
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
|
||||
|
||||
<!--定义日志存放的位置,默认存放在项目启动的相对路径的目录-->
|
||||
<springProperty scope="context" name="LOG_PATH" source="log.path" defaultValue="log"/>
|
||||
<property name="withLineNumber_debug"
|
||||
value="%clr(%d{HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) [%t] %replace(%caller{1}){'\t|Caller.{1}0|\r\n', ''} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
|
||||
|
||||
<property name="file_pattern"
|
||||
value="%d{MM-dd HH:mm:ss.SSS} %-5level [${PID:- } %thread] %logger{50}#%method,%line : %msg%n"/>
|
||||
|
||||
<!-- ****************************************************************************************** -->
|
||||
<!-- ****************************** 本地开发只在控制台打印日志 ************************************ -->
|
||||
<!-- ****************************************************************************************** -->
|
||||
<springProfile name="local">
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${withLineNumber_debug}</pattern>
|
||||
<charset>utf-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 日志记录器,日期滚动记录 -->
|
||||
<appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
|
||||
<!-- 正在记录的日志文件的路径及文件名 -->
|
||||
<file>log_error.log</file>
|
||||
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_PATH}/error/%d{yyyy-MM}/log_error-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
|
||||
<maxFileSize>50MB</maxFileSize>
|
||||
<maxHistory>100</maxHistory>
|
||||
</rollingPolicy>
|
||||
|
||||
<!-- 追加方式记录日志 -->
|
||||
<append>true</append>
|
||||
|
||||
<!-- 日志文件的格式 -->
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<pattern>${file_pattern}</pattern>
|
||||
<charset>utf-8</charset>
|
||||
</encoder>
|
||||
|
||||
<!-- 此日志文件只记录error级别的 -->
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>error</level>
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
|
||||
<!--默认所有的包以info-->
|
||||
<root level="info">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
|
||||
<!--各个服务的包在本地执行的时候,打开debug模式-->
|
||||
<logger name="com.example.wxhk" level="debug" additivity="false">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
<appender-ref ref="FILE_ERROR"/>
|
||||
</logger>
|
||||
<logger name="org.springframework" level="info" additivity="false">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</logger>
|
||||
</springProfile>
|
||||
|
||||
<!-- ********************************************************************************************** -->
|
||||
<!-- **** 放到服务器上不管在什么环境都只在文件记录日志,控制台(catalina.out)打印logback捕获不到的日志 **** -->
|
||||
<!-- ********************************************************************************************** -->
|
||||
<springProfile name="!local">
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
|
||||
<charset>utf-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 日志记录器,日期滚动记录 -->
|
||||
<appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
|
||||
<!-- 正在记录的日志文件的路径及文件名 -->
|
||||
<file>${LOG_PATH}/log_error.log</file>
|
||||
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_PATH}/error/%d{yyyy-MM}/log_error-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
|
||||
<maxFileSize>50MB</maxFileSize>
|
||||
<maxHistory>100</maxHistory>
|
||||
</rollingPolicy>
|
||||
|
||||
<!-- 追加方式记录日志 -->
|
||||
<append>true</append>
|
||||
|
||||
<!-- 日志文件的格式 -->
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<pattern>${file_pattern}</pattern>
|
||||
<charset>utf-8</charset>
|
||||
</encoder>
|
||||
|
||||
<!-- 此日志文件只记录error级别的 -->
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>error</level>
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
|
||||
<!-- 日志记录器,日期滚动记录 -->
|
||||
<appender name="FILE_ALL" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<!-- 正在记录的日志文件的路径及文件名 -->
|
||||
<file>${LOG_PATH}/log_total.log</file>
|
||||
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_PATH}/total/%d{yyyy-MM}/log_total-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
|
||||
<maxFileSize>50MB</maxFileSize>
|
||||
<maxHistory>100</maxHistory>
|
||||
</rollingPolicy>
|
||||
<!-- 追加方式记录日志 -->
|
||||
<append>true</append>
|
||||
<!-- 日志文件的格式 -->
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<pattern>${file_pattern}</pattern>
|
||||
<charset>utf-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
<!-- 业务错误 -->
|
||||
<appender name="business_log" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<!-- 正在记录的日志文件的路径及文件名 -->
|
||||
<file>${LOG_PATH}/log_business.log</file>
|
||||
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_PATH}/business/%d{yyyy-MM}/log_business-%d{yyyy-MM-dd}.%i.log.gz
|
||||
</fileNamePattern>
|
||||
<maxFileSize>50MB</maxFileSize>
|
||||
<maxHistory>100</maxHistory>
|
||||
</rollingPolicy>
|
||||
<!-- 追加方式记录日志 -->
|
||||
<append>true</append>
|
||||
<!-- 日志文件的格式 -->
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<pattern>${file_pattern}</pattern>
|
||||
<charset>utf-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="com.example.wxhk" level="info" additivity="false">
|
||||
<appender-ref ref="business_log"/>
|
||||
<appender-ref ref="FILE_ERROR"/>
|
||||
</logger>
|
||||
<logger name="p6spy" level="info" additivity="false">
|
||||
<appender-ref ref="business_log"/>
|
||||
</logger>
|
||||
<logger name="org.springframework" level="warn"/>
|
||||
|
||||
<!--记录到文件时,记录两类一类是error日志,一个是所有日志-->
|
||||
<root level="info">
|
||||
<appender-ref ref="FILE_ERROR"/>
|
||||
<appender-ref ref="FILE_ALL"/>
|
||||
</root>
|
||||
|
||||
|
||||
</springProfile>
|
||||
|
||||
</configuration>
|
||||
|
||||
|
10
java_client/src/main/resources/spy.properties
Normal file
10
java_client/src/main/resources/spy.properties
Normal file
@ -0,0 +1,10 @@
|
||||
logMessageFormat=com.p6spy.engine.spy.appender.CustomLineFormat
|
||||
# 使用Slf4J记录sql
|
||||
appender=com.p6spy.engine.spy.appender.Slf4JLogger
|
||||
# 是否开启慢SQL记录
|
||||
outagedetection=true
|
||||
# 慢SQL记录标准,单位秒
|
||||
outagedetectioninterval=2
|
||||
#日期格式
|
||||
dateformat=HH:mm:ss
|
||||
customLogMessageFormat=%(executionTime)|%(category)|connection%(connectionId)|%(sqlSingleLine)
|
@ -0,0 +1,13 @@
|
||||
package com.example.wxhk;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
class WxhkApplicationTests {
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.example.wxhk.tcp;
|
||||
|
||||
import com.example.wxhk.util.HttpAsyncUtil;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.buffer.Buffer;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.ext.web.client.HttpResponse;
|
||||
import org.dromara.hutool.core.lang.Console;
|
||||
import org.dromara.hutool.core.thread.ThreadUtil;
|
||||
import org.dromara.hutool.log.Log;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
class HttpAsyncUtilTest {
|
||||
|
||||
protected static final Log log = Log.get();
|
||||
|
||||
|
||||
@Test
|
||||
void exec() {
|
||||
Future<HttpResponse<Buffer>> exec = HttpAsyncUtil.exec(HttpAsyncUtil.Type.联系人列表, new JsonObject());
|
||||
exec.onSuccess(event -> {
|
||||
Console.log(event.bodyAsJsonObject());
|
||||
});
|
||||
}
|
||||
@Test
|
||||
void exec1() {
|
||||
|
||||
for(int i=0;i<10000;i++){
|
||||
int finalI = i;
|
||||
HttpAsyncUtil.exec(HttpAsyncUtil.Type.获取登录信息, new JsonObject(), event -> {
|
||||
if (event.succeeded()) {
|
||||
log.info("i:{},{}", finalI,event.result().bodyAsJsonObject());
|
||||
}else{
|
||||
event.cause().printStackTrace();
|
||||
}
|
||||
});
|
||||
log.info("发出请求:{}",i);
|
||||
}
|
||||
|
||||
ThreadUtil.sync(this);
|
||||
}
|
||||
@Test
|
||||
void exec2() {
|
||||
|
||||
}
|
||||
}
|
92
java_client/src/test/java/com/example/wxhk/tcp/XmlTest.java
Normal file
92
java_client/src/test/java/com/example/wxhk/tcp/XmlTest.java
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,49 @@
|
||||
package com.example.wxhk.util;
|
||||
|
||||
import com.example.wxhk.model.request.GetGroupMembers;
|
||||
import com.example.wxhk.model.response.ContactList;
|
||||
import com.example.wxhk.model.response.GroupMembers;
|
||||
import org.dromara.hutool.core.lang.Console;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@SpringBootTest
|
||||
class HttpSendUtilTest {
|
||||
|
||||
|
||||
@Test
|
||||
void 获取当前登陆微信id() {
|
||||
String s = HttpSendUtil.获取当前登陆微信id();
|
||||
}
|
||||
|
||||
@Test
|
||||
void 联系人列表() {
|
||||
ContactList contactList = HttpSendUtil.联系人列表();
|
||||
|
||||
List<ContactList.DataBean> data = contactList.getData();
|
||||
for (ContactList.DataBean datum : data) {
|
||||
Console.log(datum.getWxid(),datum.getUserName());
|
||||
}
|
||||
Console.log(contactList);
|
||||
}
|
||||
@Test
|
||||
void 开启hook() {
|
||||
|
||||
}
|
||||
@Test
|
||||
void 关闭ook() {
|
||||
HttpSendUtil.关闭hook();
|
||||
}
|
||||
|
||||
@Test
|
||||
void 获取群成员() {
|
||||
GroupMembers 获取群成员 = HttpSendUtil.获取群成员(new GetGroupMembers().setChatRoomId("24964676359@chatroom"));
|
||||
Console.log(获取群成员);
|
||||
|
||||
Duration between = Duration.between(LocalDateTime.now(), LocalDateTime.now());
|
||||
}
|
||||
}
|
26
nodejs_client/tcp_server.js
Normal file
26
nodejs_client/tcp_server.js
Normal file
@ -0,0 +1,26 @@
|
||||
const net = require('net')
|
||||
|
||||
const server = net.createServer(socket => {
|
||||
console.log('New client connected')
|
||||
|
||||
let data = Buffer.from('')
|
||||
|
||||
socket.on('data', data => {
|
||||
data = Buffer.concat([data, chunk])
|
||||
console.log(`Received data: ${data}`)
|
||||
})
|
||||
|
||||
socket.on('end', () => {
|
||||
const decodedData = data.toString('utf8')
|
||||
console.log(`Received data: ${decodedData}`)
|
||||
})
|
||||
|
||||
socket.on('close', () => {
|
||||
console.log('Client disconnected')
|
||||
})
|
||||
})
|
||||
|
||||
const port = 19099
|
||||
server.listen(port, () => {
|
||||
console.log(`Server listening on port ${port}`)
|
||||
})
|
493
python/3.9.5.81/http_client.py
Normal file
493
python/3.9.5.81/http_client.py
Normal file
@ -0,0 +1,493 @@
|
||||
import requests
|
||||
import json
|
||||
|
||||
|
||||
def checkLogin():
|
||||
url = "127.0.0.1:19088/api/checkLogin"
|
||||
payload = {}
|
||||
headers = {}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def userInfo():
|
||||
url = "127.0.0.1:19088/api/userInfo"
|
||||
payload = {}
|
||||
headers = {}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def sendTextMsg():
|
||||
url = "127.0.0.1:19088/api/sendTextMsg"
|
||||
payload = json.dumps({
|
||||
"wxid": "filehelper",
|
||||
"msg": "12www"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def sendImagesMsg():
|
||||
url = "127.0.0.1:19088/api/sendImagesMsg"
|
||||
print("modify imagePath")
|
||||
raise RuntimeError("modify imagePath then deleted me")
|
||||
payload = json.dumps({
|
||||
"wxid": "filehelper",
|
||||
"imagePath": "C:\\pic.png"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
print(response.text)
|
||||
|
||||
|
||||
def sendFileMsg():
|
||||
url = "127.0.0.1:19088/api/sendFileMsg"
|
||||
print("modify filePath")
|
||||
raise RuntimeError("modify filePath then deleted me")
|
||||
payload = json.dumps({
|
||||
"wxid": "filehelper",
|
||||
"filePath": "C:\\test.zip"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def hookSyncMsg():
|
||||
url = "127.0.0.1:19088/api/hookSyncMsg"
|
||||
print("modify ip port url ")
|
||||
raise RuntimeError("modify ip port url then deleted me")
|
||||
payload = json.dumps({
|
||||
"port": "19099",
|
||||
"ip": "127.0.0.1",
|
||||
"url": "http://localhost:8080",
|
||||
"timeout": "3000",
|
||||
"enableHttp": "0"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def unhookSyncMsg():
|
||||
url = "127.0.0.1:19088/api/unhookSyncMsg"
|
||||
payload = {}
|
||||
headers = {}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def getContactList():
|
||||
url = "127.0.0.1:19088/api/getContactList"
|
||||
payload = {}
|
||||
headers = {}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def getDBInfo():
|
||||
url = "127.0.0.1:19088/api/getDBInfo"
|
||||
payload = {}
|
||||
headers = {}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def execSql():
|
||||
url = "127.0.0.1:19088/api/execSql"
|
||||
print("modify dbHandle ")
|
||||
raise RuntimeError("modify dbHandle then deleted me")
|
||||
payload = json.dumps({
|
||||
"dbHandle": 1713425147584,
|
||||
"sql": "select * from MSG where localId =100;"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def getChatRoomDetailInfo():
|
||||
url = "127.0.0.1:19088/api/getChatRoomDetailInfo"
|
||||
print("modify chatRoomId ")
|
||||
raise RuntimeError("modify chatRoomId then deleted me")
|
||||
payload = json.dumps({
|
||||
"chatRoomId": "123333@chatroom"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def addMemberToChatRoom():
|
||||
url = "127.0.0.1:19088/api/addMemberToChatRoom"
|
||||
print("modify chatRoomId memberIds ")
|
||||
raise RuntimeError("modify chatRoomId memberIds then deleted me")
|
||||
payload = json.dumps({
|
||||
"chatRoomId": "123@chatroom",
|
||||
"memberIds": "wxid_123"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
print(response.text)
|
||||
|
||||
|
||||
def delMemberFromChatRoom():
|
||||
url = "127.0.0.1:19088/api/delMemberFromChatRoom"
|
||||
print("modify chatRoomId memberIds ")
|
||||
raise RuntimeError("modify chatRoomId memberIds then deleted me")
|
||||
payload = json.dumps({
|
||||
"chatRoomId": "21363231004@chatroom",
|
||||
"memberIds": "wxid_123"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def modifyNickname():
|
||||
url = "127.0.0.1:19088/api/modifyNickname"
|
||||
print("modify chatRoomId wxid nickName")
|
||||
raise RuntimeError("modify chatRoomId wxid nickName then deleted me")
|
||||
payload = json.dumps({
|
||||
"chatRoomId": "123@chatroom",
|
||||
"wxid": "wxid_123",
|
||||
"nickName": "test"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def getMemberFromChatRoom():
|
||||
print("modify chatRoomId ")
|
||||
raise RuntimeError("modify chatRoomId then deleted me")
|
||||
url = "127.0.0.1:19088/api/getMemberFromChatRoom"
|
||||
payload = json.dumps({
|
||||
"chatRoomId": "123@chatroom"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def topMsg():
|
||||
print("modify msgId ")
|
||||
raise RuntimeError("modify msgId then deleted me")
|
||||
url = "127.0.0.1:19088/api/topMsg"
|
||||
payload = json.dumps({
|
||||
"msgId": 1222222
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def removeTopMsg():
|
||||
print("modify msgId chatRoomId ")
|
||||
raise RuntimeError("modify msgId chatRoomId then deleted me")
|
||||
|
||||
url = "127.0.0.1:19088/api/removeTopMsg"
|
||||
|
||||
payload = json.dumps({
|
||||
"chatRoomId": "123@chatroom",
|
||||
"msgId": 123
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def InviteMemberToChatRoom():
|
||||
print("modify memberIds chatRoomId ")
|
||||
raise RuntimeError("modify memberIds chatRoomId then deleted me")
|
||||
|
||||
url = "127.0.0.1:19088/api/InviteMemberToChatRoom"
|
||||
|
||||
payload = json.dumps({
|
||||
"chatRoomId": "123@chatroom",
|
||||
"memberIds": "wxid_123"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def hookLog():
|
||||
url = "127.0.0.1:19088/api/hookLog"
|
||||
payload = {}
|
||||
headers = {}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def unhookLog():
|
||||
url = "127.0.0.1:19088/api/unhookLog"
|
||||
payload = {}
|
||||
headers = {}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def createChatRoom():
|
||||
print("modify memberIds ")
|
||||
raise RuntimeError("modify memberIds then deleted me")
|
||||
url = "127.0.0.1:19088/api/createChatRoom"
|
||||
|
||||
payload = json.dumps({
|
||||
"memberIds": "wxid_8yn4k908tdqp22,wxid_oyb662qhop4422"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
def quitChatRoom():
|
||||
print("modify chatRoomId ")
|
||||
raise RuntimeError("modify chatRoomId then deleted me")
|
||||
url = "127.0.0.1:19088/api/quitChatRoom"
|
||||
|
||||
payload = json.dumps({
|
||||
"chatRoomId": "123@chatroom"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
def forwardMsg():
|
||||
print("modify msgId ")
|
||||
raise RuntimeError("modify msgId then deleted me")
|
||||
url = "127.0.0.1:19088/api/forwardMsg"
|
||||
|
||||
payload = json.dumps({
|
||||
"wxid": "filehelper",
|
||||
"msgId": "12331"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
def getSNSFirstPage():
|
||||
url = "127.0.0.1:19088/api/getSNSFirstPage"
|
||||
|
||||
payload = {}
|
||||
headers = {}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
def getSNSNextPage():
|
||||
print("modify snsId ")
|
||||
raise RuntimeError("modify snsId then deleted me")
|
||||
url = "127.0.0.1:19088/api/getSNSNextPage"
|
||||
|
||||
payload = json.dumps({
|
||||
"snsId": ""
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
print(response.text)
|
||||
|
||||
def addFavFromMsg():
|
||||
print("modify msgId ")
|
||||
raise RuntimeError("modify msgId then deleted me")
|
||||
url = "127.0.0.1:19088/api/addFavFromMsg"
|
||||
|
||||
payload = json.dumps({
|
||||
"msgId": "1222222"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
print(response.text)
|
||||
|
||||
def addFavFromImage():
|
||||
print("modify wxid imagePath ")
|
||||
raise RuntimeError("modify wxid imagePath then deleted me")
|
||||
url = "127.0.0.1:19088/api/addFavFromImage"
|
||||
|
||||
payload = json.dumps({
|
||||
"wxid": "",
|
||||
"imagePath": ""
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
print(response.text)
|
||||
|
||||
def getContactProfile():
|
||||
print("modify wxid ")
|
||||
raise RuntimeError("modify wxid then deleted me")
|
||||
url = "127.0.0.1:19088/api/getContactProfile"
|
||||
|
||||
payload = json.dumps({
|
||||
"wxid": ""
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
print(response.text)
|
||||
|
||||
|
||||
def sendAtText():
|
||||
print("modify wxids chatRoomId")
|
||||
raise RuntimeError("modify wxids chatRoomId then deleted me")
|
||||
url = "127.0.0.1:19088/api/sendAtText"
|
||||
|
||||
payload = json.dumps({
|
||||
"wxids": "notify@all",
|
||||
"chatRoomId": "123@chatroom",
|
||||
"msg": "你好啊"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
print(response.text)
|
||||
|
||||
def forwardPublicMsg():
|
||||
print("modify param ")
|
||||
raise RuntimeError("modify param then deleted me")
|
||||
url = "127.0.0.1:19088/api/forwardPublicMsg"
|
||||
|
||||
payload = json.dumps({
|
||||
"appName": "",
|
||||
"userName": "",
|
||||
"title": "",
|
||||
"url": "",
|
||||
"thumbUrl": "",
|
||||
"digest": "",
|
||||
"wxid": "filehelper"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
print(response.text)
|
||||
|
||||
def forwardPublicMsgByMsgId():
|
||||
print("modify param ")
|
||||
raise RuntimeError("modify param then deleted me")
|
||||
url = "127.0.0.1:19088/api/forwardPublicMsgByMsgId"
|
||||
|
||||
payload = json.dumps({
|
||||
"msgId": 123,
|
||||
"wxid": "filehelper"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
print(response.text)
|
||||
|
||||
def downloadAttach():
|
||||
print("modify param ")
|
||||
raise RuntimeError("modify param then deleted me")
|
||||
url = "127.0.0.1:19088/api/downloadAttach"
|
||||
|
||||
payload = json.dumps({
|
||||
"msgId": 123
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
print(response.text)
|
||||
|
||||
|
||||
def decodeImage():
|
||||
print("modify param ")
|
||||
raise RuntimeError("modify param then deleted me")
|
||||
url = "127.0.0.1:19088/api/decodeImage"
|
||||
|
||||
payload = json.dumps({
|
||||
"filePath": "C:\\66664816980131.dat",
|
||||
"storeDir": "C:\\test"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
print(response.text)
|
||||
|
||||
|
||||
def getVoiceByMsgId():
|
||||
print("modify param ")
|
||||
raise RuntimeError("modify param then deleted me")
|
||||
url = "127.0.0.1:19088/api/getVoiceByMsgId"
|
||||
|
||||
payload = json.dumps({
|
||||
"msgId": 7880439644200,
|
||||
"storeDir": "c:\\test"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
print(response.text)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
checkLogin()
|
||||
# userInfo()
|
26
python/http_server.py
Normal file
26
python/http_server.py
Normal file
@ -0,0 +1,26 @@
|
||||
from fastapi import FastAPI, Request
|
||||
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
# pip install fastapi
|
||||
# run command :uvicorn test:app --reload
|
||||
# 127.0.0.1:8000/api
|
||||
|
||||
@app.post("/api")
|
||||
def create_item(request: Request):
|
||||
print("recv msg")
|
||||
return {"code": 0, "msg": "success"}
|
||||
|
||||
|
||||
@app.middleware("http")
|
||||
async def TestCustomMiddleware(request: Request, call_next):
|
||||
the_headers = request.headers
|
||||
the_body = await request.json()
|
||||
|
||||
print(the_headers)
|
||||
print(the_body)
|
||||
|
||||
response = await call_next(request)
|
||||
|
||||
return response
|
10
python/readme.md
Normal file
10
python/readme.md
Normal file
@ -0,0 +1,10 @@
|
||||
### 常用的一些工具
|
||||
|
||||
|
||||
client.py : 快速测试dll的http接口。
|
||||
|
||||
decrpt.py : 微信数据库解密工具。password 为dll个人信息里返回的dbkey。
|
||||
|
||||
http_server.py : 一个简单的http server,用来接收hook的消息。
|
||||
|
||||
tcpserver.py: 一个简单的tcp server,用来接收hook的消息。
|
@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.0.0)
|
||||
project(ConsoleApplication VERSION 1.0.0)
|
||||
project(injector VERSION 1.0.0)
|
||||
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
@ -9,12 +9,12 @@ 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})
|
||||
add_executable (injector ${INJECT_CPP_FILES})
|
||||
|
||||
SET_TARGET_PROPERTIES(ConsoleApplication PROPERTIES LINKER_LANGUAGE C
|
||||
SET_TARGET_PROPERTIES(injector 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"
|
||||
OUTPUT_NAME "injector"
|
||||
PREFIX "")
|
||||
|
@ -526,7 +526,7 @@ DWORD GetPIDForProcess(wchar_t* process)
|
||||
if (!hSnapshot) {
|
||||
return 0;
|
||||
}
|
||||
pe32.dwSize = sizeof(PROCESSENTRY32);
|
||||
pe32.dwSize = sizeof(PROCESSENTRY32W);
|
||||
for (working = Process32FirstW(hSnapshot, &pe32); working; working = Process32NextW(hSnapshot, &pe32))
|
||||
{
|
||||
if (!wcscmp(pe32.szExeFile, process))
|
||||
@ -934,6 +934,9 @@ int InjectDll(wchar_t* szPName, wchar_t* szDllPath)
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD dErrorCode = GetLastError();
|
||||
printf("dll inject fail");
|
||||
printf("error code : %d ", dErrorCode);
|
||||
VirtualFreeEx(hProcess, lpRemoteDllBase, ulDllLength, MEM_DECOMMIT | MEM_RELEASE);
|
||||
CloseHandle(hProcess);
|
||||
result = 0;
|
||||
@ -941,6 +944,9 @@ int InjectDll(wchar_t* szPName, wchar_t* szDllPath)
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD dErrorCode = GetLastError();
|
||||
printf("dll inject fail.VirtualAllocEx method fail.");
|
||||
printf("error code : %d ", dErrorCode);
|
||||
CloseHandle(hProcess);
|
||||
result = 0;
|
||||
}
|
||||
@ -981,11 +987,14 @@ int InjectDllByPid(unsigned int pid, wchar_t* szDllPath)
|
||||
OutputDebugStringA("[DBG] dll inject success");
|
||||
printf("dll inject success");
|
||||
printf("dll path : %s ", szDllPath);
|
||||
printf("pid : %d ", pid);
|
||||
printf("dll path : %d ", pid);
|
||||
result = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD dErrorCode = GetLastError();
|
||||
printf("dll inject fail");
|
||||
printf("error code : %d ", dErrorCode);
|
||||
VirtualFreeEx(hProcess, lpRemoteDllBase, ulDllLength, MEM_DECOMMIT | MEM_RELEASE);
|
||||
CloseHandle(hProcess);
|
||||
result = 0;
|
||||
@ -993,6 +1002,9 @@ int InjectDllByPid(unsigned int pid, wchar_t* szDllPath)
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD dErrorCode = GetLastError();
|
||||
printf("dll inject fail.VirtualAllocEx method fail.");
|
||||
printf("error code : %d ", dErrorCode);
|
||||
CloseHandle(hProcess);
|
||||
result = 0;
|
||||
}
|
1
spdlog
Submodule
1
spdlog
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit ad0e89cbfb4d0c1ce4d097e134eb7be67baebb36
|
@ -1,219 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "account_mgr.h"
|
||||
#include "easylogging++.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 + 0x304) == 0 ||
|
||||
*(DWORD *)(service_addr + 0x304 + 0x10) == 0) {
|
||||
out.head_img = string();
|
||||
} else {
|
||||
if (*(DWORD *)(service_addr + 0x304 + 0x14) == 0xF) {
|
||||
out.head_img = string((char *)(service_addr + 0x304),
|
||||
*(DWORD *)(service_addr + 0x304 + 0x10));
|
||||
} else {
|
||||
out.head_img = string(*(char **)(service_addr + 0x304),
|
||||
*(DWORD *)(service_addr + 0x304 + 0x10));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
} // namespace wxhelper
|
@ -1,19 +0,0 @@
|
||||
#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();
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
@ -1,78 +0,0 @@
|
||||
#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_HTTP_APIS,
|
||||
*PWECHAT_HTTP_APIS;
|
||||
|
||||
}
|
||||
#endif
|
@ -1,4 +1,4 @@
|
||||
#include "pch.h"
|
||||
#include "pch.h"
|
||||
/*
|
||||
base64.cpp and base64.h
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
|
||||
Version: 2.rc.08 (release candidate)
|
||||
|
||||
Copyright (C) 2004-2017, 2020, 2021 Ren¨¦ Nyffenegger
|
||||
Copyright (C) 2004-2017, 2020, 2021 Ren<EFBFBD><EFBFBD> Nyffenegger
|
||||
|
||||
This source code is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the author be held liable for any damages
|
||||
@ -28,7 +28,7 @@
|
||||
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Ren¨¦ Nyffenegger rene.nyffenegger@adp-gmbh.ch
|
||||
Ren<EFBFBD><EFBFBD> Nyffenegger rene.nyffenegger@adp-gmbh.ch
|
||||
|
||||
*/
|
||||
|
||||
@ -182,7 +182,7 @@ template <typename String>
|
||||
static std::string decode(String encoded_string, bool remove_linebreaks)
|
||||
{
|
||||
//
|
||||
// decode(¡) is templated so that it can be used with String = const std::string&
|
||||
// decode(<EFBFBD><EFBFBD>) is templated so that it can be used with String = const std::string&
|
||||
// or std::string_view (requires at least C++17)
|
||||
//
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// base64 encoding and decoding with C++.
|
||||
// Version: 2.rc.08 (release candidate)
|
||||
//
|
||||
|
@ -1,13 +0,0 @@
|
||||
#include "base_mgr.h"
|
||||
|
||||
namespace wxhelper{
|
||||
|
||||
BaseMgr::BaseMgr(DWORD base):base_addr_(base)
|
||||
{
|
||||
}
|
||||
|
||||
BaseMgr::~BaseMgr()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
#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,375 +0,0 @@
|
||||
#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
|
||||
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 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;
|
||||
}
|
||||
} // namespace wxhelper
|
@ -1,28 +0,0 @@
|
||||
#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);
|
||||
};
|
||||
} // namespace wxhelper
|
||||
#endif
|
@ -6,12 +6,9 @@ Config::Config(/* args */) {}
|
||||
|
||||
Config::~Config() {}
|
||||
|
||||
|
||||
void Config::Initialize() {
|
||||
port_ = GetPrivateProfileInt("config", "Port", 19088, "./config.ini");
|
||||
}
|
||||
int Config::GetPort(){
|
||||
return port_;
|
||||
}
|
||||
int Config::GetPort() { return port_; }
|
||||
|
||||
} // namespace wxhelper
|
@ -5,7 +5,7 @@ namespace wxhelper {
|
||||
|
||||
class Config {
|
||||
public:
|
||||
Config(/* args */);
|
||||
Config();
|
||||
~Config();
|
||||
void Initialize();
|
||||
int GetPort();
|
||||
|
@ -1,219 +0,0 @@
|
||||
#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_ + 0x758720;
|
||||
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 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};
|
||||
__asm {
|
||||
PUSHAD
|
||||
PUSHFD
|
||||
LEA ECX,helper_obj
|
||||
CALL new_helper_addr
|
||||
MOV ESI,0x0
|
||||
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
|
@ -1,21 +0,0 @@
|
||||
#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);
|
||||
};
|
||||
} // namespace wxhelper
|
||||
|
||||
#endif;
|
408
src/db.cc
408
src/db.cc
@ -2,27 +2,27 @@
|
||||
#include "db.h"
|
||||
|
||||
#include "base64.h"
|
||||
#include "easylogging++.h"
|
||||
|
||||
#include "wechat_function.h"
|
||||
#include "utils.h"
|
||||
using namespace std;
|
||||
|
||||
namespace offset = wxhelper::V3_9_5_81::offset;
|
||||
|
||||
|
||||
namespace wxhelper {
|
||||
|
||||
void DB::init(DWORD base) {
|
||||
void DB::init(UINT64 base) {
|
||||
base_addr_ = base;
|
||||
dbmap_ = {};
|
||||
dbs_ = {};
|
||||
}
|
||||
|
||||
void FreeResult(vector<vector<SqlResult>> &data) {
|
||||
void FreeResult(std::vector<std::vector<common::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];
|
||||
common::SqlResult *sr = (common::SqlResult *)&data[i][j];
|
||||
if (sr->column_name) {
|
||||
delete[] sr->column_name;
|
||||
sr->column_name = NULL;
|
||||
@ -37,36 +37,38 @@ void FreeResult(vector<vector<SqlResult>> &data) {
|
||||
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;
|
||||
int DB::SelectDataInner(UINT64 db, const char *sql,
|
||||
std::vector<std::vector<common::SqlResult>> &data) {
|
||||
common::sqlite3_prepare p_sqlite3_prepare =
|
||||
(common::sqlite3_prepare)(base_addr_ + offset::k_sqlite3_prepare);
|
||||
common::sqlite3_step p_sqlite3_step =
|
||||
(common::sqlite3_step)(base_addr_ + offset::k_sqlite3_step);
|
||||
common::sqlite3_column_count p_sqlite3_column_count =
|
||||
(common::sqlite3_column_count)(base_addr_ + offset::k_sqlite3_column_count);
|
||||
common::sqlite3_column_name p_sqlite3_column_name =
|
||||
(common::sqlite3_column_name)(base_addr_ + offset::k_sqlite3_column_name);
|
||||
common::sqlite3_column_type p_sqlite3_column_type =
|
||||
(common::sqlite3_column_type)(base_addr_ + offset::k_sqlite3_column_type);
|
||||
common::sqlite3_column_blob p_sqlite3_column_blob =
|
||||
(common::sqlite3_column_blob)(base_addr_ + offset::k_sqlite3_column_blob);
|
||||
common::sqlite3_column_bytes p_sqlite3_column_bytes =
|
||||
(common::sqlite3_column_bytes)(base_addr_ + offset::k_sqlite3_column_bytes);
|
||||
common::sqlite3_finalize p_sqlite3_finalize =
|
||||
(common::sqlite3_finalize)(base_addr_ + offset::k_sqlite3_finalize);
|
||||
UINT64 *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);
|
||||
std::vector<common::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);
|
||||
common::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);
|
||||
@ -94,13 +96,13 @@ int DB::SelectDataInner(DWORD db, const char *sql,
|
||||
}
|
||||
data.push_back(tempStruct);
|
||||
}
|
||||
p_Sqlite3_finalize(stmt);
|
||||
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 DB::Select(UINT64 db_hanle, const char *sql,
|
||||
std::vector<std::vector<std::string>> &query_result) {
|
||||
std::vector<std::vector<common::SqlResult>> data;
|
||||
int status = SelectDataInner(db_hanle, sql, data);
|
||||
if (status == 0) {
|
||||
return 0;
|
||||
@ -108,28 +110,28 @@ int DB::Select(DWORD db_hanle, const char *sql,
|
||||
if (data.size() == 0) {
|
||||
return 1;
|
||||
}
|
||||
vector<string> index;
|
||||
std::vector<std::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;
|
||||
std::vector<std::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);
|
||||
std::string content(it[i].content);
|
||||
item.push_back(content);
|
||||
} else {
|
||||
string base64_str =
|
||||
std::string base64_str =
|
||||
base64_encode((BYTE *)it[i].content, it[i].content_len);
|
||||
item.push_back(base64_str);
|
||||
}
|
||||
|
||||
} else {
|
||||
string b64_str =
|
||||
std::string b64_str =
|
||||
base64_encode((BYTE *)it[i].content, it[i].content_len);
|
||||
item.push_back(b64_str);
|
||||
}
|
||||
@ -141,9 +143,9 @@ int DB::Select(DWORD db_hanle, const char *sql,
|
||||
}
|
||||
|
||||
int SelectDbInfo(void *data, int argc, char **argv, char **name) {
|
||||
vector<SqlResult> result;
|
||||
std::vector<common::SqlResult> result;
|
||||
for (int i = 0; i < argc; i++) {
|
||||
SqlResult temp = {0};
|
||||
common::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]);
|
||||
@ -161,16 +163,16 @@ int SelectDbInfo(void *data, int argc, char **argv, char **name) {
|
||||
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);
|
||||
int DB::ExecuteSQL(UINT64 db, const char *sql, UINT64 callback, void *data) {
|
||||
UINT64 sqlite3_exec_addr = base_addr_ + offset::k_sqlite3_exec;
|
||||
common::sqlite3_exec fn_sqlite3_exec = (common::sqlite3_exec)sqlite3_exec_addr;
|
||||
int status = fn_sqlite3_exec(db, sql, (common::sqlite3_callback)callback, data, 0);
|
||||
return status;
|
||||
}
|
||||
|
||||
int GetDbInfo(void *data, int argc, char **argv, char **name) {
|
||||
DatabaseInfo *pdata = (DatabaseInfo *)data;
|
||||
TableInfo tb = {0};
|
||||
common::DatabaseInfo *pdata = (common::DatabaseInfo *)data;
|
||||
common::TableInfo tb = {0};
|
||||
if (argv[1]) {
|
||||
tb.name = new char[strlen(argv[1]) + 1];
|
||||
memcpy(tb.name, argv[1], strlen(argv[1]) + 1);
|
||||
@ -207,273 +209,215 @@ int GetDbInfo(void *data, int argc, char **argv, char **name) {
|
||||
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);
|
||||
UINT64 p_contact_addr = *(UINT64 *)(base_addr_ + offset::kGPInstance);
|
||||
UINT64 micro_msg_db_addr = *(UINT64 *)(p_contact_addr + offset::kMicroMsgDB);
|
||||
UINT64 chat_msg_db_addr = *(UINT64 *)(p_contact_addr + offset::kChatMsgDB);
|
||||
UINT64 misc_db_addr = *(UINT64 *)(p_contact_addr + offset::kMiscDB);
|
||||
UINT64 emotion_db_addr = *(UINT64 *)(p_contact_addr + offset::kEmotionDB);
|
||||
UINT64 media_db_addr = *(UINT64 *)(p_contact_addr + offset::kMediaDB);
|
||||
UINT64 bizchat_msg_db_addr =
|
||||
*(UINT64 *)(p_contact_addr + offset::kBizchatMsgDB);
|
||||
UINT64 function_msg_db_addr =
|
||||
*(UINT64 *)(p_contact_addr + offset::kFunctionMsgDB);
|
||||
|
||||
// microMsg.db
|
||||
DatabaseInfo micro_msg_db{0};
|
||||
common::DatabaseInfo micro_msg_db{0};
|
||||
micro_msg_db.db_name = (wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_MICRO_MSG_OFFSET + DB_NAME_OFFSET));
|
||||
UINT64 *)(p_contact_addr + offset::kMicroMsgDB + offset::kDBName));
|
||||
micro_msg_db.db_name_len =
|
||||
*(DWORD *)(p_contact_addr + DB_MICRO_MSG_OFFSET + DB_NAME_OFFSET + 0x4);
|
||||
*(DWORD *)(p_contact_addr + offset::kMicroMsgDB + offset::kDBName + 0x8);
|
||||
micro_msg_db.handle = micro_msg_db_addr;
|
||||
ExecuteSQL(micro_msg_db_addr,
|
||||
"select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, µ_msg_db);
|
||||
(UINT64)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)));
|
||||
std::wstring micro_msg_name = std::wstring((wchar_t *)(*(
|
||||
UINT64 *)(p_contact_addr + offset::kMicroMsgDB + offset::kDBName)));
|
||||
dbmap_[micro_msg_name] = micro_msg_db;
|
||||
|
||||
// chatMsg.db
|
||||
DatabaseInfo chat_msg_db{0};
|
||||
common::DatabaseInfo chat_msg_db{0};
|
||||
chat_msg_db.db_name = (wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_CHAT_MSG_OFFSET + DB_NAME_OFFSET));
|
||||
UINT64 *)(p_contact_addr + offset::kChatMsgDB + offset::kDBName));
|
||||
chat_msg_db.db_name_len =
|
||||
*(DWORD *)(p_contact_addr + DB_CHAT_MSG_OFFSET + DB_NAME_OFFSET + 0x4);
|
||||
*(DWORD *)(p_contact_addr + offset::kChatMsgDB + offset::kDBName + 0x8);
|
||||
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);
|
||||
(UINT64)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)));
|
||||
std::wstring chat_msg_name = std::wstring((wchar_t *)(*(
|
||||
UINT64 *)(p_contact_addr + offset::kChatMsgDB + offset::kDBName)));
|
||||
dbmap_[chat_msg_name] = chat_msg_db;
|
||||
|
||||
// misc.db
|
||||
DatabaseInfo misc_db{0};
|
||||
common::DatabaseInfo misc_db{0};
|
||||
misc_db.db_name =
|
||||
(wchar_t *)(*(DWORD *)(p_contact_addr + DB_MISC_OFFSET + DB_NAME_OFFSET));
|
||||
(wchar_t *)(*(UINT64 *)(p_contact_addr + offset::kMiscDB + offset::kDBName));
|
||||
misc_db.db_name_len =
|
||||
*(DWORD *)(p_contact_addr + DB_MISC_OFFSET + DB_NAME_OFFSET + 0x4);
|
||||
*(DWORD *)(p_contact_addr + offset::kMiscDB + offset::kDBName + 0x8);
|
||||
misc_db.handle = misc_db_addr;
|
||||
ExecuteSQL(misc_db_addr, "select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, &misc_db);
|
||||
(UINT64)GetDbInfo, &misc_db);
|
||||
dbs_.push_back(misc_db);
|
||||
wstring misc_name = wstring((
|
||||
wchar_t *)(*(DWORD *)(p_contact_addr + DB_MISC_OFFSET + DB_NAME_OFFSET)));
|
||||
std::wstring misc_name = std::wstring((
|
||||
wchar_t *)(*(UINT64 *)(p_contact_addr + offset::kMiscDB + offset::kDBName)));
|
||||
dbmap_[misc_name] = misc_db;
|
||||
|
||||
// emotion.db
|
||||
DatabaseInfo emotion_db{0};
|
||||
common::DatabaseInfo emotion_db{0};
|
||||
emotion_db.db_name = (wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_EMOTION_OFFSET + DB_NAME_OFFSET));
|
||||
UINT64 *)(p_contact_addr + offset::kEmotionDB + offset::kDBName));
|
||||
emotion_db.db_name_len =
|
||||
*(DWORD *)(p_contact_addr + DB_EMOTION_OFFSET + DB_NAME_OFFSET + 0x4);
|
||||
*(DWORD *)(p_contact_addr + offset::kEmotionDB + offset::kDBName + 0x8);
|
||||
emotion_db.handle = emotion_db_addr;
|
||||
ExecuteSQL(emotion_db_addr,
|
||||
"select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, &emotion_db);
|
||||
(UINT64)GetDbInfo, &emotion_db);
|
||||
dbs_.push_back(emotion_db);
|
||||
wstring emotion_name = wstring((wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_EMOTION_OFFSET + DB_NAME_OFFSET)));
|
||||
std::wstring emotion_name = std::wstring((wchar_t *)(*(
|
||||
UINT64 *)(p_contact_addr + offset::kEmotionDB + offset::kDBName)));
|
||||
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));
|
||||
common::DatabaseInfo media_db{0};
|
||||
media_db.db_name = (wchar_t *)(*(UINT64 *)(p_contact_addr + offset::kMediaDB +
|
||||
offset::kDBName));
|
||||
media_db.db_name_len =
|
||||
*(DWORD *)(p_contact_addr + DB_MEDIA_OFFSET + DB_NAME_OFFSET + 0x4);
|
||||
*(DWORD *)(p_contact_addr + offset::kMediaDB + offset::kDBName + 0x8);
|
||||
media_db.handle = media_db_addr;
|
||||
ExecuteSQL(media_db_addr, "select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, &media_db);
|
||||
(UINT64)GetDbInfo, &media_db);
|
||||
dbs_.push_back(media_db);
|
||||
wstring media_name = wstring((wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_MEDIA_OFFSET + DB_NAME_OFFSET)));
|
||||
std::wstring media_name = std::wstring((wchar_t *)(*(
|
||||
UINT64 *)(p_contact_addr + offset::kMediaDB + offset::kDBName)));
|
||||
dbmap_[media_name] = media_db;
|
||||
|
||||
// functionMsg.db
|
||||
DatabaseInfo function_msg_db{0};
|
||||
common::DatabaseInfo function_msg_db{0};
|
||||
function_msg_db.db_name = (wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET));
|
||||
UINT64 *)(p_contact_addr + offset::kFunctionMsgDB + offset::kDBName));
|
||||
function_msg_db.db_name_len = *(
|
||||
DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET + 0x4);
|
||||
DWORD *)(p_contact_addr + offset::kFunctionMsgDB + offset::kDBName + 0x8);
|
||||
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);
|
||||
(UINT64)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)));
|
||||
std::wstring function_msg_name = std::wstring((wchar_t *)(*(
|
||||
UINT64 *)(p_contact_addr + offset::kFunctionMsgDB + offset::kDBName)));
|
||||
dbmap_[function_msg_name] = function_msg_db;
|
||||
|
||||
if (bizchat_msg_db_addr) {
|
||||
// functionMsg.db maybe null
|
||||
DatabaseInfo bizchat_msg_db{0};
|
||||
common::DatabaseInfo bizchat_msg_db{0};
|
||||
bizchat_msg_db.db_name = (wchar_t *)(*(
|
||||
DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET));
|
||||
UINT64 *)(p_contact_addr + offset::kFunctionMsgDB + offset::kDBName));
|
||||
bizchat_msg_db.db_name_len =
|
||||
*(DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET +
|
||||
0x4);
|
||||
*(DWORD *)(p_contact_addr + offset::kFunctionMsgDB + offset::kDBName +
|
||||
0x8);
|
||||
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);
|
||||
(UINT64)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)));
|
||||
std::wstring bizchat_msg_name = std::wstring((wchar_t *)(*(
|
||||
UINT64 *)(p_contact_addr + offset::kFunctionMsgDB + offset::kDBName)));
|
||||
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;
|
||||
UINT64 multi_db_mgr_addr = base_addr_ + offset::kMultiDBMgr;
|
||||
UINT64 public_msg_mgr_addr = base_addr_ + offset::kPublicMsgMgr;
|
||||
UINT64 favorite_storage_mgr_addr = base_addr_ + offset::kFavoriteStorageMgr;
|
||||
|
||||
// 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);
|
||||
UINT64 wrap_ptr = *(UINT64 *)(multi_db_mgr_addr);
|
||||
UINT64 current_db_num = *(UINT64 *)(wrap_ptr + 0x68);
|
||||
UINT64 begin_ptr = *(UINT64 *)(wrap_ptr + 0x50);
|
||||
|
||||
for (unsigned int i = 0; i < current_db_num; i++) {
|
||||
DWORD next_addr = begin_ptr + i * 0x4;
|
||||
DWORD db_addr = *(DWORD *)next_addr;
|
||||
UINT64 next_addr = begin_ptr + i * 0x8;
|
||||
UINT64 db_addr = *(UINT64 *)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);
|
||||
UINT64 msg0_db_addr = *(UINT64 *)(db_addr + 0x78);
|
||||
common::DatabaseInfo msg0_db{0};
|
||||
msg0_db.db_name = (wchar_t *)(*(UINT64 *)(db_addr));
|
||||
msg0_db.db_name_len = *(DWORD *)(db_addr + 0x8);
|
||||
msg0_db.handle = msg0_db_addr;
|
||||
msg0_db.extrainfo = *(DWORD *)(*(DWORD *)(db_addr + 0x18) + 0x144);
|
||||
msg0_db.extrainfo = *(UINT64 *)(*(UINT64 *)(db_addr + 0x28) + 0x1E8);
|
||||
ExecuteSQL(msg0_db_addr,
|
||||
"select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, &msg0_db);
|
||||
(UINT64)GetDbInfo, &msg0_db);
|
||||
dbs_.push_back(msg0_db);
|
||||
wstring msg_db_name = wstring((wchar_t *)(*(DWORD *)(db_addr)));
|
||||
std::wstring msg_db_name = std::wstring(msg0_db.db_name,msg0_db.db_name_len);
|
||||
dbmap_[msg_db_name] = msg0_db;
|
||||
|
||||
// BufInfoStorage
|
||||
DWORD buf_info_addr = *(DWORD *)(db_addr + 0x14);
|
||||
UINT64 buf_info_addr = *(UINT64 *)(db_addr + 0x20);
|
||||
|
||||
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);
|
||||
UINT64 buf_info_handle = *(UINT64 *)(buf_info_addr + 0x50);
|
||||
common::DatabaseInfo media_msg0_db{0};
|
||||
media_msg0_db.db_name = (wchar_t *)(*(UINT64 *)(buf_info_addr + 0x78));
|
||||
media_msg0_db.db_name_len = *(DWORD *)(buf_info_addr + 0x80);
|
||||
media_msg0_db.handle = buf_info_handle;
|
||||
ExecuteSQL(buf_info_handle,
|
||||
"select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, &media_msg0_db);
|
||||
(UINT64)GetDbInfo, &media_msg0_db);
|
||||
dbs_.push_back(media_msg0_db);
|
||||
wstring media_msg_db_name =
|
||||
wstring((wchar_t *)(*(DWORD *)(buf_info_addr + 0x4C)));
|
||||
std::wstring media_msg_db_name =
|
||||
std::wstring(media_msg0_db.db_name,media_msg0_db.db_name_len);
|
||||
dbmap_[media_msg_db_name] = media_msg0_db;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// publicMsg.db
|
||||
DWORD public_msg_ptr = *(DWORD *)(*(DWORD *)(public_msg_mgr_addr) + 0x8);
|
||||
UINT64 public_msg_mgr_ptr =*(UINT64 *)(public_msg_mgr_addr);
|
||||
for (unsigned int i = 1; i < 4; i++) {
|
||||
UINT64 public_msg_ptr = *(UINT64 *)(public_msg_mgr_ptr + i * 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);
|
||||
UINT64 public_msg_db_addr = *(UINT64 *)(public_msg_ptr + 0x50);
|
||||
common::DatabaseInfo public_msg_db{0};
|
||||
public_msg_db.db_name = (wchar_t *)(*(UINT64 *)(public_msg_ptr + 0x78));
|
||||
public_msg_db.db_name_len = *(DWORD *)(public_msg_ptr + 0x80);
|
||||
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);
|
||||
(UINT64)GetDbInfo, &public_msg_db);
|
||||
dbs_.push_back(public_msg_db);
|
||||
wstring public_msg_db_name =
|
||||
wstring((wchar_t *)(*(DWORD *)(public_msg_ptr + 0x4C)));
|
||||
std::wstring public_msg_db_name =
|
||||
std::wstring(public_msg_db.db_name , public_msg_db.db_name_len);
|
||||
dbmap_[public_msg_db_name] = public_msg_db;
|
||||
}
|
||||
}
|
||||
|
||||
// Favorite.db
|
||||
DWORD favItems_ptr =
|
||||
*(DWORD *)(*(DWORD *)(*(DWORD *)(favorite_storage_mgr_addr) + 0x8) + 0x4);
|
||||
UINT64 favItems_ptr =
|
||||
*(UINT64 *)(*(UINT64 *)(*(UINT64 *)(favorite_storage_mgr_addr) + 0x10) + 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);
|
||||
UINT64 favorite_db_addr = *(UINT64 *)(favItems_ptr + 0x50);
|
||||
common::DatabaseInfo favorite_db{0};
|
||||
favorite_db.db_name = (wchar_t *)(*(UINT64 *)(favItems_ptr + 0x78));
|
||||
favorite_db.db_name_len = *(DWORD *)(favItems_ptr + 0x80);
|
||||
favorite_db.handle = favorite_db_addr;
|
||||
ExecuteSQL(favorite_db_addr,
|
||||
"select * from sqlite_master where type=\"table\";",
|
||||
(DWORD)GetDbInfo, &favorite_db);
|
||||
(UINT64)GetDbInfo, &favorite_db);
|
||||
dbs_.push_back(favorite_db);
|
||||
wstring public_msg_db_name =
|
||||
wstring((wchar_t *)(*(DWORD *)(favItems_ptr + 0x4C)));
|
||||
std::wstring public_msg_db_name =
|
||||
std::wstring(favorite_db.db_name,favorite_db.db_name_len);
|
||||
dbmap_[public_msg_db_name] = favorite_db;
|
||||
}
|
||||
|
||||
DatabaseInfo db_end = {0};
|
||||
common::DatabaseInfo db_end = {0};
|
||||
dbs_.push_back(db_end);
|
||||
#ifdef _DEBUG
|
||||
std::vector<void *> ret_array;
|
||||
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) {
|
||||
UINT64 DB::GetDbHandleByDbName(wchar_t *dbname) {
|
||||
if (dbmap_.size() == 0) {
|
||||
GetDbHandles();
|
||||
}
|
||||
@ -484,18 +428,18 @@ DWORD DB::GetDbHandleByDbName(wchar_t *dbname) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int DB::GetLocalIdByMsgId(ULONG64 msgid, int &dbIndex) {
|
||||
INT64 DB::GetLocalIdByMsgId(ULONG64 msgid, INT64 &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);
|
||||
UINT64 handle = GetDbHandleByDbName(dbname);
|
||||
if (handle == 0) {
|
||||
LOG(INFO) << "MSG db handle is null";
|
||||
SPDLOG_INFO("MSG db handle is null");
|
||||
return 0;
|
||||
}
|
||||
vector<vector<string>> result;
|
||||
std::vector<std::vector<std::string>> result;
|
||||
int ret = Select(handle, (const char *)sql, result);
|
||||
if (result.size() == 0) continue;
|
||||
dbIndex = dbmap_[dbname].extrainfo;
|
||||
@ -504,7 +448,7 @@ unsigned int DB::GetLocalIdByMsgId(ULONG64 msgid, int &dbIndex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
vector<string> DB::GetChatMsgByMsgId(ULONG64 msgid) {
|
||||
std::vector<std::string> DB::GetChatMsgByMsgId(ULONG64 msgid) {
|
||||
char sql[260] = {0};
|
||||
sprintf_s(sql,
|
||||
"select "
|
||||
@ -515,12 +459,12 @@ vector<string> DB::GetChatMsgByMsgId(ULONG64 msgid) {
|
||||
wchar_t dbname[20] = {0};
|
||||
for (int i = 0;; i++) {
|
||||
swprintf_s(dbname, L"MSG%d.db", i);
|
||||
DWORD handle = GetDbHandleByDbName(dbname);
|
||||
UINT64 handle = GetDbHandleByDbName(dbname);
|
||||
if (handle == 0) {
|
||||
LOG(INFO) << "MSG db handle is null";
|
||||
// LOG(INFO) << "MSG db handle is null";
|
||||
return {};
|
||||
}
|
||||
vector<vector<string>> result;
|
||||
std::vector<std::vector<std::string>> result;
|
||||
int ret = Select(handle, (const char *)sql, result);
|
||||
if (result.size() == 0) continue;
|
||||
return result[1];
|
||||
@ -534,16 +478,34 @@ std::string DB::GetVoiceBuffByMsgId(ULONG64 msgid) {
|
||||
wchar_t dbname[20] = {0};
|
||||
for (int i = 0;; i++) {
|
||||
swprintf_s(dbname, L"MediaMSG%d.db", i);
|
||||
DWORD handle = GetDbHandleByDbName(dbname);
|
||||
UINT64 handle = GetDbHandleByDbName(dbname);
|
||||
if (handle == 0) {
|
||||
LOG(INFO) << "Media db handle is null";
|
||||
// LOG(INFO) << "Media db handle is null";
|
||||
return "";
|
||||
}
|
||||
vector<vector<string>> result;
|
||||
std::vector<std::vector<std::string>> result;
|
||||
int ret = Select(handle, (const char *)sql, result);
|
||||
if (result.size() == 0) continue;
|
||||
return result[1][0];
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string DB::GetPublicMsgCompressContentByMsgId(ULONG64 msgid) {
|
||||
char sql[260] = {0};
|
||||
sprintf_s(sql, "SELECT CompressContent from PublicMsg WHERE MsgSvrID=%llu;", msgid);
|
||||
wchar_t dbname[20] = {0};
|
||||
swprintf_s( dbname, 20, L"%s", L"PublicMsg.db");
|
||||
UINT64 handle = GetDbHandleByDbName(dbname);
|
||||
if (handle == 0) {
|
||||
return "";
|
||||
}
|
||||
std::vector<std::vector<std::string>> result;
|
||||
int ret = Select(handle, (const char *)sql, result);
|
||||
if (result.size() == 0) {
|
||||
return "";
|
||||
}
|
||||
return result[1][0];
|
||||
}
|
||||
|
||||
} // namespace wxhelper
|
25
src/db.h
25
src/db.h
@ -3,34 +3,35 @@
|
||||
#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);
|
||||
void init(UINT64 base);
|
||||
int ExecuteSQL(UINT64 db, const char *sql, UINT64 callback, void *data);
|
||||
|
||||
int Select(DWORD db_hanle, const char *sql,
|
||||
int Select(UINT64 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);
|
||||
UINT64 GetDbHandleByDbName(wchar_t *dbname);
|
||||
INT64 GetLocalIdByMsgId(ULONG64 msgid, INT64 &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);
|
||||
std::string GetPublicMsgCompressContentByMsgId(ULONG64 msgid);
|
||||
|
||||
private:
|
||||
std::map<std::wstring, DatabaseInfo> dbmap_;
|
||||
std::vector<DatabaseInfo> dbs_;
|
||||
DWORD base_addr_;
|
||||
int SelectDataInner(UINT64 db, const char *sql,
|
||||
std::vector<std::vector<common::SqlResult>> &data);
|
||||
|
||||
private:
|
||||
std::map<std::wstring, common::DatabaseInfo> dbmap_;
|
||||
std::vector<common::DatabaseInfo> dbs_;
|
||||
UINT64 base_addr_;
|
||||
};
|
||||
|
||||
} // namespace wxhelper
|
||||
|
@ -1,14 +1,10 @@
|
||||
#include "pch.h"
|
||||
#include "hide_module.h"
|
||||
#include "global_context.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
using namespace wxhelper;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved) {
|
||||
switch (ul_reason_for_call) {
|
||||
|
3120
src/easylogging++.cc
3120
src/easylogging++.cc
File diff suppressed because it is too large
Load Diff
4576
src/easylogging++.h
4576
src/easylogging++.h
File diff suppressed because it is too large
Load Diff
61
src/export.asm
Normal file
61
src/export.asm
Normal file
@ -0,0 +1,61 @@
|
||||
;#################################################################
|
||||
|
||||
.code
|
||||
|
||||
|
||||
;#################################################################
|
||||
|
||||
|
||||
;#################################################################
|
||||
|
||||
;检测wechat登录状态
|
||||
;param: get_account_service_addr 函数地址
|
||||
|
||||
;#################################################################
|
||||
_GetAccountService PROC,
|
||||
get_account_service_addr:QWORD ; 函数地址
|
||||
sub rsp,28h
|
||||
call rcx
|
||||
add rsp,28h
|
||||
ret
|
||||
_GetAccountService ENDP
|
||||
|
||||
;#################################################################
|
||||
|
||||
;获取wechat数据保存路径
|
||||
;param: addr 函数地址
|
||||
;return:路径地址
|
||||
|
||||
;#################################################################
|
||||
_GetDataSavePath PROC,
|
||||
get_data_path_addr:QWORD, ; 函数地址
|
||||
out_path:QWORD ; 输出
|
||||
sub rsp,40h
|
||||
mov rax,rcx
|
||||
mov rcx,rdx
|
||||
call rax
|
||||
add rsp,40h
|
||||
ret
|
||||
_GetDataSavePath ENDP
|
||||
|
||||
|
||||
;#################################################################
|
||||
|
||||
;获取wechat当前数据保存路径
|
||||
;param: addr 函数地址
|
||||
;return:路径地址
|
||||
|
||||
;#################################################################
|
||||
_GetCurrentDataPath PROC,
|
||||
get_current_path_addr: QWORD, ; 函数地址
|
||||
out_path: QWORD ; 输出
|
||||
sub rsp,28h
|
||||
mov rax,rcx
|
||||
mov rcx,rdx
|
||||
call rax
|
||||
add rsp,28h
|
||||
ret
|
||||
_GetCurrentDataPath ENDP
|
||||
|
||||
|
||||
END
|
8
src/export.h
Normal file
8
src/export.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef WXHELPER_EXPORT_H_
|
||||
#define WXHELPER_EXPORT_H_
|
||||
|
||||
extern "C" UINT64 _GetAccountService(UINT64 addr);
|
||||
extern "C" UINT64 _GetDataSavePath(UINT64 addr,ULONG_PTR out);
|
||||
extern "C" UINT64 _GetCurrentDataPath(UINT64 addr,ULONG_PTR out);
|
||||
extern "C" UINT64 _SendTextMsg(UINT64 mgr_addr,UINT64 send_text_addr,UINT64 free_addr,UINT64 receiver,UINT64 msg,UINT64 chat_msg);
|
||||
#endif
|
@ -1,7 +0,0 @@
|
||||
#ifndef FRAMEWORK_H_
|
||||
#define FRAMEWORK_H_
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#endif
|
@ -1,39 +1,41 @@
|
||||
#include "pch.h"
|
||||
#include "global_context.h"
|
||||
#include "http_server.h"
|
||||
#include "easylogging++.h"
|
||||
#include "hooks.h"
|
||||
|
||||
#include "thread_pool.h"
|
||||
#include "db.h"
|
||||
|
||||
namespace wxhelper {
|
||||
|
||||
GlobalContext::~GlobalContext() {
|
||||
if (config.has_value()) {
|
||||
config.reset();
|
||||
}
|
||||
if (log.has_value()) {
|
||||
log.reset();
|
||||
}
|
||||
|
||||
}
|
||||
void GlobalContext::initialize(HMODULE module) {
|
||||
state =GlobalContextState::INITIALIZING;
|
||||
module_ = module;
|
||||
DWORD base = Utils::GetWeChatWinBase();
|
||||
#ifndef _DEBUG
|
||||
Utils::Hide(module);
|
||||
#endif
|
||||
UINT64 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();
|
||||
http_server = std::unique_ptr<HttpServer>( new HttpServer(config->GetPort()));
|
||||
http_server->HttpStart();
|
||||
ThreadPool::GetInstance().Create(2, 8);
|
||||
mgr = std::unique_ptr<Manager>(new Manager(base));
|
||||
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});
|
||||
state =GlobalContextState::INITIALIZED;
|
||||
}
|
||||
|
||||
void GlobalContext::finally() {
|
||||
HttpServer::GetInstance().HttpClose();
|
||||
hooks::UnHookLog();
|
||||
hooks::UnHookRecvMsg();
|
||||
hooks::UnHookSearchContact();
|
||||
if (http_server) {
|
||||
http_server->HttpClose();
|
||||
}
|
||||
}
|
||||
} // namespace wxhelper
|
@ -1,39 +1,30 @@
|
||||
#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"
|
||||
#include "manager.h"
|
||||
|
||||
namespace wxhelper {
|
||||
|
||||
enum class GlobalContextState { NOT_INITIALIZED, INITIALIZING, INITIALIZED };
|
||||
|
||||
class GlobalContext : public Singleton<GlobalContext> {
|
||||
friend class Singleton<GlobalContext>;
|
||||
~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;
|
||||
std::unique_ptr<HttpServer> http_server;
|
||||
std::unique_ptr<Manager> mgr;
|
||||
|
||||
GlobalContextState state = GlobalContextState::INITIALIZED;
|
||||
GlobalContextState state = GlobalContextState::NOT_INITIALIZED;
|
||||
|
||||
private:
|
||||
HMODULE module_;
|
||||
|
@ -1,10 +0,0 @@
|
||||
#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
|
@ -1,64 +0,0 @@
|
||||
#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
|
@ -1,48 +0,0 @@
|
||||
#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
|
677
src/hooks.cc
677
src/hooks.cc
@ -1,533 +1,316 @@
|
||||
#include <Ws2tcpip.h>
|
||||
#include <winsock2.h>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include "easylogging++.h"
|
||||
|
||||
#include "pch.h"
|
||||
#include "hooks.h"
|
||||
#include "thread_pool.h"
|
||||
#include "wechat_function.h"
|
||||
using namespace nlohmann;
|
||||
using namespace std;
|
||||
#include <WS2tcpip.h>
|
||||
#include "base64.h"
|
||||
#include "http_client.h"
|
||||
|
||||
namespace offset = wxhelper::V3_9_5_81::offset;
|
||||
namespace common = wxhelper::common;
|
||||
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 int kServerPort = 19099;
|
||||
static bool kMsgHookFlag = false;
|
||||
static char kServerIp[16] = "127.0.0.1";
|
||||
static bool kEnableHttp = false;
|
||||
static bool kLogHookFlag = false;
|
||||
|
||||
static char sns_asm_code_[5] = {0};
|
||||
static DWORD sns_back_addr_ = 0;
|
||||
static DWORD sns_next_addr_ = 0;
|
||||
static bool kSnsFinishHookFlag = false;
|
||||
|
||||
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;
|
||||
static UINT64 (*R_DoAddMsg)(UINT64, UINT64, UINT64) = (UINT64(*)(
|
||||
UINT64, UINT64, UINT64))(Utils::GetWeChatWinBase() + offset::kDoAddMsg);
|
||||
|
||||
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;
|
||||
static UINT64 (*R_Log)(UINT64, UINT64, UINT64, UINT64, UINT64, UINT64, UINT64,
|
||||
UINT64, UINT64, UINT64, UINT64, UINT64) =
|
||||
(UINT64(*)(UINT64, UINT64, UINT64, UINT64, UINT64, UINT64, UINT64, UINT64,
|
||||
UINT64, UINT64, UINT64,
|
||||
UINT64))(Utils::GetWeChatWinBase() + offset::kHookLog);
|
||||
|
||||
UserInfo userinfo = {};
|
||||
static UINT64 (*R_OnSnsTimeLineSceneFinish)(UINT64, UINT64, UINT64) =
|
||||
(UINT64(*)(UINT64, UINT64, UINT64))(Utils::GetWeChatWinBase() +
|
||||
offset::kOnSnsTimeLineSceneFinish);
|
||||
|
||||
void SendSocketMessage(InnerMessageStruct *msg) {
|
||||
VOID CALLBACK SendMsgCallback(PTP_CALLBACK_INSTANCE instance, PVOID context,
|
||||
PTP_WORK Work) {
|
||||
common::InnerMessageStruct *msg = (common::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);
|
||||
std::unique_ptr<common::InnerMessageStruct> sms(msg);
|
||||
nlohmann::json j_msg =
|
||||
nlohmann::json::parse(msg->buffer, msg->buffer + msg->length, nullptr, false);
|
||||
if (j_msg.is_discarded() == true) {
|
||||
return;
|
||||
}
|
||||
string jstr = j_msg.dump() + "\n";
|
||||
std::string jstr = j_msg.dump() + "\n";
|
||||
|
||||
if (server_port_ == 0) {
|
||||
LOG(INFO) << "http server port error :" << server_port_;
|
||||
if (kServerPort == 0) {
|
||||
SPDLOG_ERROR("http server port error :{}", kServerPort);
|
||||
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) {
|
||||
LOG(INFO) << "socket init fail";
|
||||
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);
|
||||
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) {
|
||||
LOG(INFO) << "socket connect fail";
|
||||
return;
|
||||
SPDLOG_ERROR("socket connect fail");
|
||||
goto clean;
|
||||
}
|
||||
char recv_buf[1024] = {0};
|
||||
int ret = send(client_socket, jstr.c_str(), jstr.size(), 0);
|
||||
if (ret == -1 || ret == 0) {
|
||||
LOG(INFO) << "socket send fail ,ret:" << ret;
|
||||
ret = send(client_socket, jstr.c_str(), static_cast<int>(jstr.size()) , 0);
|
||||
if (ret < 0) {
|
||||
SPDLOG_ERROR("socket send fail ,ret:{}", ret);
|
||||
goto clean;
|
||||
}
|
||||
ret = shutdown(client_socket, SD_SEND);
|
||||
if (ret == SOCKET_ERROR) {
|
||||
SPDLOG_ERROR("shutdown failed with erro:{}", ret);
|
||||
goto clean;
|
||||
}
|
||||
ret = recv(client_socket, recv_buf, sizeof(recv_buf), 0);
|
||||
if (ret < 0) {
|
||||
SPDLOG_ERROR("socket recv fail ,ret:{}", ret);
|
||||
goto clean;
|
||||
}
|
||||
clean:
|
||||
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) {
|
||||
LOG(INFO) << "socket recv fail ,ret:" << ret;
|
||||
}
|
||||
|
||||
VOID CALLBACK SendHttpMsgCallback(PTP_CALLBACK_INSTANCE instance, PVOID context,
|
||||
PTP_WORK Work) {
|
||||
common::InnerMessageStruct *msg = (common::InnerMessageStruct *)context;
|
||||
if (msg == NULL) {
|
||||
SPDLOG_INFO("http msg is null");
|
||||
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));
|
||||
std::unique_ptr<common::InnerMessageStruct> sms(msg);
|
||||
nlohmann::json j_msg =
|
||||
nlohmann::json::parse(msg->buffer, msg->buffer + msg->length, nullptr, false);
|
||||
if (j_msg.is_discarded() == true) {
|
||||
return;
|
||||
}
|
||||
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));
|
||||
std::string jstr = j_msg.dump() + "\n";
|
||||
HttpClient::GetInstance().SendRequest(jstr);
|
||||
}
|
||||
|
||||
int signature_len = *(DWORD *)(msg_addr + 0x1F4);
|
||||
if (signature_len > 0) {
|
||||
j_msg["signature"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x1F0));
|
||||
}
|
||||
void HandleSyncMsg(INT64 param1, INT64 param2, INT64 param3) {
|
||||
nlohmann::json msg;
|
||||
|
||||
string jstr = j_msg.dump() + '\n';
|
||||
InnerMessageStruct *inner_msg = new InnerMessageStruct;
|
||||
msg["pid"] = GetCurrentProcessId();
|
||||
msg["fromUser"] = Utils::ReadSKBuiltinString(*(INT64 *)(param2 + 0x18));
|
||||
msg["toUser"] = Utils::ReadSKBuiltinString(*(INT64 *)(param2 + 0x28));
|
||||
msg["content"] = Utils::ReadSKBuiltinString(*(INT64 *)(param2 + 0x30));
|
||||
msg["signature"] = Utils::ReadWeChatStr(*(INT64 *)(param2 + 0x48));
|
||||
msg["msgId"] = *(INT64 *)(param2 + 0x60);
|
||||
msg["msgSequence"] = *(DWORD *)(param2 + 0x5C);
|
||||
msg["createTime"] = *(DWORD *)(param2 + 0x58);
|
||||
msg["displayFullContent"] = Utils::ReadWeChatStr(*(INT64 *)(param2 + 0x50));
|
||||
DWORD type = *(DWORD *)(param2 + 0x24);
|
||||
msg["type"] = type;
|
||||
if (type == 3) {
|
||||
int a = 1;
|
||||
std::string img =
|
||||
Utils::ReadSKBuiltinBuffer(*(INT64 *)(param2 + 0x40));
|
||||
SPDLOG_INFO("encode size:{}",img.size());
|
||||
msg["base64Img"] = base64_encode(img);
|
||||
a = 2;
|
||||
}
|
||||
std::string jstr = msg.dump() + '\n';
|
||||
common::InnerMessageStruct *inner_msg = new common::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);
|
||||
if(kEnableHttp){
|
||||
bool add = ThreadPool::GetInstance().AddWork(SendHttpMsgCallback,inner_msg);
|
||||
SPDLOG_INFO("add http msg work:{}",add);
|
||||
}else{
|
||||
bool add = ThreadPool::GetInstance().AddWork(SendMsgCallback,inner_msg);
|
||||
SPDLOG_INFO("add msg work:{}",add);
|
||||
}
|
||||
R_DoAddMsg(param1,param2,param3);
|
||||
}
|
||||
|
||||
/// @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_
|
||||
UINT64 HandlePrintLog(UINT64 param1, UINT64 param2, UINT64 param3, UINT64 param4,
|
||||
UINT64 param5, UINT64 param6, UINT64 param7, UINT64 param8,
|
||||
UINT64 param9, UINT64 param10, UINT64 param11,
|
||||
UINT64 param12) {
|
||||
UINT64 p = R_Log(param1, param2, param3, param4, param5, param6, param7, param8, param9,
|
||||
param10, param11, param12);
|
||||
if(p== 0 || p == 1){
|
||||
return p;
|
||||
}
|
||||
char *msg = (char *)p;
|
||||
if (msg != NULL) {
|
||||
// INT64 size = *(INT64 *)(p - 0x8);
|
||||
std::string str(msg);
|
||||
std::wstring ws = Utils::UTF8ToWstring(str);
|
||||
std::string out = Utils::WstringToAnsi(ws, CP_ACP);
|
||||
spdlog::info("wechat log:{}", out);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void __cdecl OnSnsTimeLineMsg(DWORD msg_addr) {
|
||||
json j_sns;
|
||||
DWORD begin_addr = *(DWORD *)(msg_addr + 0x20);
|
||||
DWORD end_addr = *(DWORD *)(msg_addr + 0x24);
|
||||
void HandleSNSMsg(INT64 param1, INT64 param2, INT64 param3) {
|
||||
nlohmann::json j_sns;
|
||||
INT64 begin_addr = *(INT64 *)(param2 + 0x30);
|
||||
INT64 end_addr = *(INT64 *)(param2 + 0x38);
|
||||
if (begin_addr == 0) {
|
||||
j_sns = {{"data", json::array()}};
|
||||
j_sns = {{"data", nlohmann::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));
|
||||
|
||||
nlohmann::json j_item;
|
||||
j_item["snsId"] = *(UINT64 *)(begin_addr);
|
||||
j_item["createTime"] = *(DWORD *)(begin_addr + 0x38);
|
||||
j_item["senderId"] = Utils::ReadWstringThenConvert(begin_addr + 0x18);
|
||||
j_item["content"] = Utils::ReadWstringThenConvert(begin_addr + 0x48);
|
||||
j_item["xml"] = Utils::ReadWstringThenConvert(begin_addr + 0x580);
|
||||
j_sns["data"].push_back(j_item);
|
||||
begin_addr += 0xB48;
|
||||
begin_addr += 0x11E0;
|
||||
}
|
||||
}
|
||||
string jstr = j_sns.dump() + '\n';
|
||||
InnerMessageStruct *inner_msg = new InnerMessageStruct;
|
||||
std::string jstr = j_sns.dump() + '\n';
|
||||
common::InnerMessageStruct *inner_msg = new common::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);
|
||||
if (kEnableHttp) {
|
||||
bool add = ThreadPool::GetInstance().AddWork(SendHttpMsgCallback, inner_msg);
|
||||
SPDLOG_INFO("hook sns add http msg work:{}", add);
|
||||
} else {
|
||||
bool add = ThreadPool::GetInstance().AddWork(SendMsgCallback, inner_msg);
|
||||
SPDLOG_INFO("hook sns add msg work:{}", add);
|
||||
}
|
||||
R_OnSnsTimeLineSceneFinish(param1, param2, param3);
|
||||
}
|
||||
|
||||
/// @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 HookSyncMsg(std::string client_ip, int port, std::string url,
|
||||
uint64_t timeout, bool enable) {
|
||||
if (kMsgHookFlag) {
|
||||
SPDLOG_INFO("recv msg hook already called");
|
||||
return 2;
|
||||
}
|
||||
kEnableHttp = enable;
|
||||
if (kEnableHttp) {
|
||||
HttpClient::GetInstance().SetConfig(url, timeout);
|
||||
}
|
||||
if (client_ip.size() < 1) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
int HookRecvMsg(char *client_ip, int port) {
|
||||
server_port_ = port;
|
||||
strcpy_s(server_ip_, client_ip);
|
||||
DWORD base = Utils::GetWeChatWinBase();
|
||||
kServerPort = port;
|
||||
strcpy_s(kServerIp, client_ip.c_str());
|
||||
UINT64 base = Utils::GetWeChatWinBase();
|
||||
if (!base) {
|
||||
SPDLOG_INFO("base addr is null");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msg_hook_flag_) {
|
||||
return 2;
|
||||
// DetourRestoreAfterWith();
|
||||
DetourTransactionBegin();
|
||||
DetourUpdateThread(GetCurrentThread());
|
||||
DetourAttach(&(PVOID&)R_DoAddMsg, &HandleSyncMsg);
|
||||
LONG ret = DetourTransactionCommit();
|
||||
if(ret == NO_ERROR){
|
||||
kMsgHookFlag = true;
|
||||
}
|
||||
SPDLOG_INFO("hook sync {}",ret);
|
||||
DetourTransactionBegin();
|
||||
DetourUpdateThread(GetCurrentThread());
|
||||
DetourAttach(&(PVOID&)R_OnSnsTimeLineSceneFinish, &HandleSNSMsg);
|
||||
ret = DetourTransactionCommit();
|
||||
if(ret == NO_ERROR){
|
||||
kSnsFinishHookFlag = true;
|
||||
}
|
||||
SPDLOG_INFO("hook sns {}",ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
LOG(INFO) << "base" << base;
|
||||
LOG(INFO) << "msg_next_addr_" << msg_next_addr_;
|
||||
LOG(INFO) << "msg_back_addr_" << msg_back_addr_;
|
||||
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;
|
||||
LOG(INFO) << "base" << base;
|
||||
LOG(INFO) << "sns_next_addr_" << sns_next_addr_;
|
||||
LOG(INFO) << "sns_back_addr_" << sns_back_addr_;
|
||||
Utils::HookAnyAddress(hook_sns_msg_addr, (LPVOID)HandleSNSMsg, sns_asm_code_);
|
||||
|
||||
msg_hook_flag_ = true;
|
||||
return 1;
|
||||
int UnHookSyncMsg() {
|
||||
if (!kMsgHookFlag) {
|
||||
kMsgHookFlag = false;
|
||||
kEnableHttp = false;
|
||||
strcpy_s(kServerIp, "127.0.0.1");
|
||||
SPDLOG_INFO("hook sync msg reset");
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int UnHookRecvMsg() {
|
||||
server_port_ = 0;
|
||||
if (!msg_hook_flag_) {
|
||||
LOG(INFO) << "this port already hooked";
|
||||
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);
|
||||
delete[] w_msg;
|
||||
w_msg = NULL;
|
||||
LOG(INFO) << ansi_message;
|
||||
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_
|
||||
UINT64 base = Utils::GetWeChatWinBase();
|
||||
DetourTransactionBegin();
|
||||
DetourUpdateThread(GetCurrentThread());
|
||||
DetourDetach(&(PVOID&)R_DoAddMsg, &HandleSyncMsg);
|
||||
LONG ret = DetourTransactionCommit();
|
||||
if (ret == NO_ERROR) {
|
||||
kMsgHookFlag = false;
|
||||
kEnableHttp = false;
|
||||
strcpy_s(kServerIp, "127.0.0.1");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int HookLog() {
|
||||
DWORD base = Utils::GetWeChatWinBase();
|
||||
if (!base) {
|
||||
return -1;
|
||||
}
|
||||
if (log_hook_flag_) {
|
||||
if (kLogHookFlag) {
|
||||
SPDLOG_INFO("log hook already called");
|
||||
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;
|
||||
|
||||
UINT64 base = Utils::GetWeChatWinBase();
|
||||
if (!base) {
|
||||
SPDLOG_INFO("base addr is null");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// DetourRestoreAfterWith();
|
||||
DetourTransactionBegin();
|
||||
DetourUpdateThread(GetCurrentThread());
|
||||
UINT64 do_add_msg_addr = base + offset::kHookLog;
|
||||
DetourAttach(&(PVOID &)R_Log, &HandlePrintLog);
|
||||
LONG ret = DetourTransactionCommit();
|
||||
if (ret == NO_ERROR) {
|
||||
kLogHookFlag = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int UnHookLog() {
|
||||
if (!log_hook_flag_) {
|
||||
return 1;
|
||||
if (!kLogHookFlag) {
|
||||
kLogHookFlag = false;
|
||||
SPDLOG_INFO("hook log reset");
|
||||
return NO_ERROR;
|
||||
}
|
||||
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;
|
||||
UINT64 base = Utils::GetWeChatWinBase();
|
||||
DetourTransactionBegin();
|
||||
DetourUpdateThread(GetCurrentThread());
|
||||
UINT64 do_add_msg_addr = base + offset::kHookLog;
|
||||
DetourDetach(&(PVOID &)R_Log, &HandlePrintLog);
|
||||
LONG ret = DetourTransactionCommit();
|
||||
if (ret == NO_ERROR) {
|
||||
kLogHookFlag = false;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SetErrorCode(int code) { userinfo.error_code = code; }
|
||||
|
||||
void SetUserInfoDetail(DWORD address) {
|
||||
LOG(INFO) << "hook userinfo addr" <<&userinfo;
|
||||
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 + 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));
|
||||
}
|
||||
|
||||
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 + 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.nickname) {
|
||||
delete userinfo.nickname;
|
||||
}
|
||||
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
|
14
src/hooks.h
14
src/hooks.h
@ -4,20 +4,16 @@
|
||||
#include "wechat_function.h"
|
||||
namespace wxhelper {
|
||||
namespace hooks {
|
||||
extern UserInfo userinfo;
|
||||
extern bool user_info_flag_ ;
|
||||
|
||||
int HookRecvMsg(char* client_ip, int port);
|
||||
int HookSyncMsg(std::string client_ip, int port, std::string url, uint64_t timeout,
|
||||
bool enable);
|
||||
|
||||
int UnHookRecvMsg();
|
||||
|
||||
void SendSocketMessage(InnerMessageStruct* msg);
|
||||
int UnHookSyncMsg();
|
||||
|
||||
int HookLog();
|
||||
|
||||
int UnHookLog();
|
||||
int HookSearchContact();
|
||||
int UnHookSearchContact();
|
||||
void DeleteUserInfoCache();
|
||||
|
||||
} // namespace hooks
|
||||
} // namespace wxhelper
|
||||
#endif
|
65
src/http_client.cc
Normal file
65
src/http_client.cc
Normal file
@ -0,0 +1,65 @@
|
||||
#include "pch.h"
|
||||
#include "http_client.h"
|
||||
namespace wxhelper {
|
||||
|
||||
void HttpClient::SendRequest(std::string content) {
|
||||
struct mg_mgr mgr;
|
||||
Data data ;
|
||||
data.done = false;
|
||||
data.post_data = content;
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_connect(&mgr, url_.c_str(), OnHttpEvent, &data);
|
||||
while (!data.done){
|
||||
mg_mgr_poll(&mgr, 500);
|
||||
}
|
||||
mg_mgr_free(&mgr);
|
||||
}
|
||||
|
||||
|
||||
void HttpClient::OnHttpEvent(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
const char * s_url = GetInstance().url_.c_str();
|
||||
Data data = *(Data*)fn_data;
|
||||
if (ev == MG_EV_OPEN) {
|
||||
// Connection created. Store connect expiration time in c->data
|
||||
*(uint64_t *) c->data = mg_millis() + GetInstance().timeout_;
|
||||
} else if (ev == MG_EV_POLL) {
|
||||
if (mg_millis() > *(uint64_t *) c->data &&
|
||||
(c->is_connecting || c->is_resolving)) {
|
||||
mg_error(c, "Connect timeout");
|
||||
}
|
||||
} else if (ev == MG_EV_CONNECT) {
|
||||
struct mg_str host = mg_url_host(s_url);
|
||||
if (mg_url_is_ssl(s_url)) {
|
||||
// no implement
|
||||
}
|
||||
|
||||
// Send request
|
||||
size_t content_length = data.post_data.size();
|
||||
mg_printf(c,
|
||||
"POST %s HTTP/1.0\r\n"
|
||||
"Host: %.*s\r\n"
|
||||
"Content-Type: application/json\r\n"
|
||||
"Content-Length: %d\r\n"
|
||||
"\r\n",
|
||||
mg_url_uri(s_url), (int) host.len,
|
||||
host.ptr, content_length);
|
||||
mg_send(c, data.post_data.c_str(), content_length);
|
||||
} else if (ev == MG_EV_HTTP_MSG) {
|
||||
// Response is received. Print it
|
||||
#ifdef _DEBUG
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
printf("%.*s", (int) hm->message.len, hm->message.ptr);
|
||||
#endif
|
||||
c->is_closing = 1; // Tell mongoose to close this connection
|
||||
data.done = true; // Tell event loop to stops
|
||||
} else if (ev == MG_EV_ERROR) {
|
||||
data.done = true; // Error, tell event loop to stop
|
||||
}
|
||||
}
|
||||
|
||||
void HttpClient::SetConfig(std::string url,uint64_t timeout){
|
||||
url_=url;
|
||||
timeout_=timeout;
|
||||
}
|
||||
|
||||
} // namespace wxhelper
|
24
src/http_client.h
Normal file
24
src/http_client.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef WXHELPER_HTTP_CLIENT_H_
|
||||
#define WXHELPER_HTTP_CLIENT_H_
|
||||
#include "mongoose.h"
|
||||
#include "singleton.h"
|
||||
|
||||
namespace wxhelper {
|
||||
struct Data {
|
||||
bool done;
|
||||
std::string post_data;
|
||||
};
|
||||
class HttpClient : public Singleton<HttpClient> {
|
||||
public:
|
||||
void SendRequest(std::string content);
|
||||
void SetConfig(std::string url,uint64_t timeout);
|
||||
|
||||
static void OnHttpEvent(struct mg_connection *c, int ev, void *ev_data,
|
||||
void *fn_data);
|
||||
private:
|
||||
std::string url_;
|
||||
uint64_t timeout_;
|
||||
};
|
||||
|
||||
} // namespace wxhelper
|
||||
#endif
|
@ -1,598 +0,0 @@
|
||||
#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 "easylogging++.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)},
|
||||
};
|
||||
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 success = g_context.contact_mgr->VerifyApply(WS2LPWS(v3),WS2LPWS(v4));
|
||||
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;
|
||||
}
|
||||
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
|
@ -1,17 +0,0 @@
|
||||
#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
|
@ -1,31 +1,20 @@
|
||||
#include "pch.h"
|
||||
#include "pch.h"
|
||||
#include "http_server_callback.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) {
|
||||
HttpServer::HttpServer(int port) {
|
||||
port_ = port;
|
||||
running_ = false;
|
||||
http_handler_ = new HttpHandler();
|
||||
mg_mgr_init(&mgr_);
|
||||
|
||||
}
|
||||
|
||||
HttpServer::~HttpServer() {
|
||||
if (thread_ != nullptr) {
|
||||
CloseHandle(thread_);
|
||||
}
|
||||
mg_mgr_free(&mgr_);
|
||||
delete http_handler_;
|
||||
}
|
||||
|
||||
bool HttpServer::HttpStart() {
|
||||
@ -36,51 +25,11 @@ bool HttpServer::HttpStart() {
|
||||
Utils::CreateConsole();
|
||||
#endif
|
||||
running_ = true;
|
||||
thread_ = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)StartHttpServer, NULL,
|
||||
thread_ = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)StartHttpServer, this,
|
||||
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;
|
||||
@ -97,4 +46,9 @@ bool HttpServer::HttpClose() {
|
||||
return true;
|
||||
}
|
||||
|
||||
int HttpServer::GetPort() { return port_; }
|
||||
bool HttpServer::GetRunning() { return running_; }
|
||||
|
||||
const mg_mgr* HttpServer::GetMgr() { return &mgr_; }
|
||||
|
||||
} // namespace wxhelper
|
@ -1,33 +1,27 @@
|
||||
#ifndef WXHELPER_HTTP_SERVER_H_
|
||||
#ifndef WXHELPER_HTTP_SERVER_H_
|
||||
#define WXHELPER_HTTP_SERVER_H_
|
||||
|
||||
#include <mongoose.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(){};
|
||||
explicit HttpServer(int port);
|
||||
HttpServer(const HttpServer&) = delete;
|
||||
HttpServer(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);
|
||||
|
||||
bool HttpStart();
|
||||
bool HttpClose();
|
||||
int GetPort();
|
||||
bool GetRunning();
|
||||
const mg_mgr* GetMgr();
|
||||
|
||||
private:
|
||||
int port_;
|
||||
bool running_;
|
||||
struct mg_mgr mgr_;
|
||||
HttpHandler *http_handler_;
|
||||
HANDLE thread_;
|
||||
};
|
||||
} // namespace wxhelper
|
||||
|
615
src/http_server_callback.cc
Normal file
615
src/http_server_callback.cc
Normal file
@ -0,0 +1,615 @@
|
||||
#include "pch.h"
|
||||
#include "http_server_callback.h"
|
||||
#include "http_server.h"
|
||||
#include "export.h"
|
||||
#include "global_context.h"
|
||||
#include "hooks.h"
|
||||
#include "db.h"
|
||||
|
||||
|
||||
#define STR2ULL(str) (wxhelper::Utils::IsDigit(str) ? stoull(str) : 0)
|
||||
#define STR2LL(str) (wxhelper::Utils::IsDigit(str) ? stoll(str) : 0)
|
||||
#define STR2I(str) (wxhelper::Utils::IsDigit(str) ? stoi(str) : 0)
|
||||
namespace common = wxhelper::common;
|
||||
|
||||
int GetIntParam(nlohmann::json data, std::string key) {
|
||||
int result;
|
||||
try {
|
||||
result = data[key].get<int>();
|
||||
} catch (nlohmann::json::exception) {
|
||||
result = STR2I(data[key].get<std::string>());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
INT64 GetINT64Param(nlohmann::json data, std::string key) {
|
||||
INT64 result;
|
||||
try {
|
||||
result = data[key].get<INT64>();
|
||||
} catch (nlohmann::json::exception) {
|
||||
result = STR2LL(data[key].get<std::string>());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
INT64 GetUINT64Param(nlohmann::json data, std::string key) {
|
||||
UINT64 result;
|
||||
try {
|
||||
result = data[key].get<UINT64>();
|
||||
} catch (nlohmann::json::exception) {
|
||||
result = STR2ULL(data[key].get<std::string>());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string GetStringParam(nlohmann::json data, std::string key) {
|
||||
return data[key].get<std::string>();
|
||||
}
|
||||
|
||||
std::wstring GetWStringParam(nlohmann::json data, std::string key) {
|
||||
return wxhelper::Utils::UTF8ToWstring(data[key].get<std::string>());
|
||||
}
|
||||
|
||||
std::vector<std::wstring> GetArrayParam(nlohmann::json data, std::string key) {
|
||||
std::vector<std::wstring> result;
|
||||
std::wstring param = GetWStringParam(data, key);
|
||||
result = wxhelper::Utils::split(param, L',');
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void StartHttpServer(wxhelper::HttpServer *server) {
|
||||
int port = server->GetPort();
|
||||
std::string lsten_addr = "http://0.0.0.0:" + std::to_string(port);
|
||||
if (mg_http_listen(const_cast<mg_mgr *>(server->GetMgr()), lsten_addr.c_str(),
|
||||
EventHandler,
|
||||
const_cast<mg_mgr *>(server->GetMgr())) == NULL) {
|
||||
SPDLOG_INFO("http server listen fail.port:{}", port);
|
||||
#ifdef _DEBUG
|
||||
MG_INFO(("http server listen fail.port: %d", port));
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
for (;;) {
|
||||
mg_mgr_poll(const_cast<mg_mgr *>(server->GetMgr()), 1000);
|
||||
}
|
||||
}
|
||||
|
||||
void EventHandler(struct mg_connection *c, int ev, void *ev_data,
|
||||
void *fn_data) {
|
||||
if (ev == MG_EV_OPEN) {
|
||||
} 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/*")) {
|
||||
HandleHttpRequest(c, hm);
|
||||
} else {
|
||||
nlohmann::json res = {{"code", 400},
|
||||
{"msg", "invalid url, please check url"},
|
||||
{"data", NULL}};
|
||||
std::string ret = res.dump();
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "%s\n",
|
||||
ret.c_str());
|
||||
}
|
||||
} else if (ev == MG_EV_WS_MSG) {
|
||||
HandleWebsocketRequest(c, ev_data);
|
||||
}
|
||||
(void)fn_data;
|
||||
}
|
||||
|
||||
void HandleHttpRequest(struct mg_connection *c, void *ev_data) {
|
||||
struct mg_http_message *hm = (struct mg_http_message *)ev_data;
|
||||
std::string ret = R"({"code":200,"msg":"success"})";
|
||||
try {
|
||||
ret = HttpDispatch(c, hm);
|
||||
} catch (nlohmann::json::exception &e) {
|
||||
nlohmann::json res = {{"code", "500"}, {"msg", e.what()}, {"data", NULL}};
|
||||
ret = res.dump();
|
||||
}
|
||||
if (ret != "") {
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "%s\n",
|
||||
ret.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void 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);
|
||||
}
|
||||
|
||||
std::string HttpDispatch(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
std::string ret;
|
||||
if (mg_vcasecmp(&hm->method, "GET") == 0) {
|
||||
nlohmann::json ret_data = {{"code", 200},
|
||||
{"data", {}},
|
||||
{"msg", "not support get method,use post."}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
}
|
||||
|
||||
nlohmann::json j_param = nlohmann::json::parse(
|
||||
hm->body.ptr, hm->body.ptr + hm->body.len, nullptr, false);
|
||||
if (hm->body.len != 0 && j_param.is_discarded() == true) {
|
||||
nlohmann::json ret_data = {
|
||||
{"code", 200}, {"data", {}}, {"msg", "json string is invalid."}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
}
|
||||
if (wxhelper::GlobalContext::GetInstance().state !=
|
||||
wxhelper::GlobalContextState::INITIALIZED) {
|
||||
nlohmann::json ret_data = {
|
||||
{"code", 200}, {"data", {}}, {"msg", "global context is initializing"}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
}
|
||||
if (mg_http_match_uri(hm, "/api/checkLogin")) {
|
||||
INT64 success = wxhelper::GlobalContext::GetInstance().mgr->CheckLogin();
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"data", {}}, {"msg", "success"}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/userInfo")) {
|
||||
common::SelfInfoInner self_info;
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->GetSelfInfo(self_info);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"data", {}}, {"msg", "success"}};
|
||||
if (success) {
|
||||
nlohmann::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();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/sendTextMsg")) {
|
||||
std::wstring wxid = GetWStringParam(j_param, "wxid");
|
||||
std::wstring msg = GetWStringParam(j_param, "msg");
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->SendTextMsg(wxid, msg);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"data", {}}, {"msg", "success"}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/hookSyncMsg")) {
|
||||
int port = GetIntParam(j_param, "port");
|
||||
std::string ip = GetStringParam(j_param, "ip");
|
||||
int enable = GetIntParam(j_param, "enableHttp");
|
||||
std::string url = "";
|
||||
int timeout = 0;
|
||||
if (enable) {
|
||||
url = GetStringParam(j_param, "url");
|
||||
timeout = GetIntParam(j_param, "timeout");
|
||||
}
|
||||
INT64 success =
|
||||
wxhelper::hooks::HookSyncMsg(ip, port, url, timeout, enable);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"data", {}}, {"msg", "success"}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/sendImagesMsg")) {
|
||||
std::wstring wxid = GetWStringParam(j_param, "wxid");
|
||||
std::wstring path = GetWStringParam(j_param, "imagePath");
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->SendImageMsg(wxid, path);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"data", {}}, {"msg", "success"}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/sendFileMsg")) {
|
||||
std::wstring wxid = GetWStringParam(j_param, "wxid");
|
||||
std::wstring path = GetWStringParam(j_param, "filePath");
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->SendFileMsg(wxid, path);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"data", {}}, {"msg", "success"}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/getContactList")) {
|
||||
std::vector<common::ContactInner> vec;
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->GetContacts(vec);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"data", {}}, {"msg", "success"}};
|
||||
for (unsigned int i = 0; i < vec.size(); i++) {
|
||||
nlohmann::json item = {
|
||||
{"customAccount", vec[i].custom_account},
|
||||
{"encryptName", vec[i].encrypt_name},
|
||||
{"type", vec[i].type},
|
||||
{"verifyFlag", vec[i].verify_flag},
|
||||
{"wxid", vec[i].wxid},
|
||||
{"nickname", vec[i].nickname},
|
||||
{"pinyin", vec[i].pinyin},
|
||||
{"pinyinAll", vec[i].pinyin_all},
|
||||
{"reserved1", vec[i].reserved1},
|
||||
{"reserved2", vec[i].reserved2},
|
||||
};
|
||||
ret_data["data"].push_back(item);
|
||||
}
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/unhookSyncMsg")) {
|
||||
INT64 success = wxhelper::hooks::UnHookSyncMsg();
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"data", {}}, {"msg", "success"}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/getDBInfo")) {
|
||||
std::vector<void *> v_ptr = wxhelper::DB::GetInstance().GetDbHandles();
|
||||
nlohmann::json ret_data = {{"data", nlohmann::json::array()}};
|
||||
for (unsigned int i = 0; i < v_ptr.size(); i++) {
|
||||
nlohmann::json db_info;
|
||||
db_info["tables"] = nlohmann::json::array();
|
||||
common::DatabaseInfo *db =
|
||||
reinterpret_cast<common::DatabaseInfo *>(v_ptr[i]);
|
||||
db_info["handle"] = db->handle;
|
||||
std::wstring dbname(db->db_name);
|
||||
db_info["databaseName"] = wxhelper::Utils::WstringToUTF8(dbname);
|
||||
for (auto table : db->tables) {
|
||||
nlohmann::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_data["code"] = 1;
|
||||
ret_data["msg"] = "success";
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/execSql")) {
|
||||
UINT64 db_handle = GetINT64Param(j_param, "dbHandle");
|
||||
std::string sql = GetStringParam(j_param, "sql");
|
||||
std::vector<std::vector<std::string>> items;
|
||||
int success =
|
||||
wxhelper::DB::GetInstance().Select(db_handle, sql.c_str(), items);
|
||||
nlohmann::json ret_data = {{"data", nlohmann::json::array()},
|
||||
{"code", success},
|
||||
{"msg", "success"}};
|
||||
if (success == 0) {
|
||||
ret_data["msg"] = "no data";
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
}
|
||||
for (auto it : items) {
|
||||
nlohmann::json temp_arr = nlohmann::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();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/getChatRoomDetailInfo")) {
|
||||
std::wstring chat_room_id = GetWStringParam(j_param, "chatRoomId");
|
||||
common::ChatRoomInfoInner chat_room_detail;
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->GetChatRoomDetailInfo(
|
||||
chat_room_id, chat_room_detail);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
|
||||
nlohmann::json detail = {
|
||||
{"chatRoomId", chat_room_detail.chat_room_id},
|
||||
{"notice", chat_room_detail.notice},
|
||||
{"admin", chat_room_detail.admin},
|
||||
{"xml", chat_room_detail.xml},
|
||||
};
|
||||
ret_data["data"] = detail;
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/addMemberToChatRoom")) {
|
||||
std::wstring room_id = GetWStringParam(j_param, "chatRoomId");
|
||||
std::vector<std::wstring> wxids = GetArrayParam(j_param, "memberIds");
|
||||
std::vector<std::wstring> wxid_list;
|
||||
for (unsigned int i = 0; i < wxids.size(); i++) {
|
||||
wxid_list.push_back(wxids[i]);
|
||||
}
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->AddMemberToChatRoom(
|
||||
room_id, wxid_list);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/modifyNickname")) {
|
||||
std::wstring room_id = GetWStringParam(j_param, "chatRoomId");
|
||||
std::wstring wxid = GetWStringParam(j_param, "wxid");
|
||||
std::wstring nickName = GetWStringParam(j_param, "nickName");
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->ModChatRoomMemberNickName(
|
||||
room_id, wxid, nickName);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/delMemberFromChatRoom")) {
|
||||
std::wstring room_id = GetWStringParam(j_param, "chatRoomId");
|
||||
std::vector<std::wstring> wxids = GetArrayParam(j_param, "memberIds");
|
||||
std::vector<std::wstring> wxid_list;
|
||||
for (unsigned int i = 0; i < wxids.size(); i++) {
|
||||
wxid_list.push_back(wxids[i]);
|
||||
}
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->DelMemberFromChatRoom(
|
||||
room_id, wxid_list);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/getMemberFromChatRoom")) {
|
||||
std::wstring room_id = GetWStringParam(j_param, "chatRoomId");
|
||||
common::ChatRoomMemberInner member;
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->GetMemberFromChatRoom(
|
||||
room_id, member);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
if (success >= 0) {
|
||||
nlohmann::json member_info = {
|
||||
{"admin", member.admin},
|
||||
{"chatRoomId", member.chat_room_id},
|
||||
{"members", member.member},
|
||||
{"adminNickname", member.admin_nickname},
|
||||
{"memberNickname", member.member_nickname},
|
||||
};
|
||||
ret_data["data"] = member_info;
|
||||
}
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/topMsg")) {
|
||||
INT64 msg_id = GetINT64Param(j_param, "msgId");
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->SetTopMsg(msg_id);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/removeTopMsg")) {
|
||||
std::wstring room_id = GetWStringParam(j_param, "chatRoomId");
|
||||
INT64 msg_id = GetINT64Param(j_param, "msgId");
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->RemoveTopMsg(room_id,msg_id);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/InviteMemberToChatRoom")) {
|
||||
std::wstring room_id = GetWStringParam(j_param, "chatRoomId");
|
||||
std::vector<std::wstring> wxids = GetArrayParam(j_param, "memberIds");
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->InviteMemberToChatRoom(
|
||||
room_id, wxids);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/hookLog")) {
|
||||
int success = wxhelper::hooks::HookLog();
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/unhookLog")) {
|
||||
int success = wxhelper::hooks::UnHookLog();
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/createChatRoom")) {
|
||||
std::vector<std::wstring> wxids = GetArrayParam(j_param, "memberIds");
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->CreateChatRoom(wxids);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/quitChatRoom")) {
|
||||
std::wstring room_id = GetWStringParam(j_param, "chatRoomId");
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->QuitChatRoom(room_id);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/forwardMsg")) {
|
||||
INT64 msg_id = GetINT64Param(j_param, "msgId");
|
||||
std::wstring wxid = GetWStringParam(j_param, "wxid");
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->ForwardMsg(msg_id,wxid);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/getSNSFirstPage")) {
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->GetSNSFirstPage();
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/getSNSNextPage")) {
|
||||
UINT64 snsid = GetUINT64Param(j_param, "snsId");
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->GetSNSNextPage(snsid);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/addFavFromMsg")) {
|
||||
UINT64 msg_id = GetUINT64Param(j_param, "msgId");
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->AddFavFromMsg(msg_id);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/addFavFromImage")) {
|
||||
std::wstring wxid = GetWStringParam(j_param, "wxid");
|
||||
std::wstring image_path = GetWStringParam(j_param, "imagePath");
|
||||
INT64 success = wxhelper::GlobalContext::GetInstance().mgr->AddFavFromImage(
|
||||
wxid, image_path);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/sendAtText")) {
|
||||
std::wstring chat_room_id = GetWStringParam(j_param, "chatRoomId");
|
||||
std::vector<std::wstring> wxids = GetArrayParam(j_param, "wxids");
|
||||
std::wstring msg = GetWStringParam(j_param, "msg");
|
||||
std::vector<std::wstring> wxid_list;
|
||||
for (unsigned int i = 0; i < wxids.size(); i++) {
|
||||
wxid_list.push_back(wxids[i]);
|
||||
}
|
||||
INT64 success = wxhelper::GlobalContext::GetInstance().mgr->SendAtText(
|
||||
chat_room_id, wxid_list, msg);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/getContactProfile")) {
|
||||
std::wstring wxid = GetWStringParam(j_param, "wxid");
|
||||
common::ContactProfileInner profile;
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->GetContactByWxid(wxid,
|
||||
profile);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
if (success == 1) {
|
||||
nlohmann::json contact_profile = {
|
||||
{"account", profile.account}, {"headImage", profile.head_image},
|
||||
{"nickname", profile.nickname}, {"v3", profile.v3},
|
||||
{"wxid", profile.wxid},
|
||||
};
|
||||
ret_data["data"] = contact_profile;
|
||||
}
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/downloadAttach")) {
|
||||
UINT64 msg_id = GetUINT64Param(j_param, "msgId");
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->DoDownloadTask(msg_id);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/forwardPublicMsg")) {
|
||||
std::wstring wxid = GetWStringParam(j_param, "wxid");
|
||||
std::wstring appname = GetWStringParam(j_param, "appName");
|
||||
std::wstring username = GetWStringParam(j_param, "userName");
|
||||
std::wstring title = GetWStringParam(j_param, "title");
|
||||
std::wstring url = GetWStringParam(j_param, "url");
|
||||
std::wstring thumburl = GetWStringParam(j_param, "thumbUrl");
|
||||
std::wstring digest = GetWStringParam(j_param, "digest");
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->ForwardPublicMsg(
|
||||
wxid, title, url, thumburl, username, appname, digest);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/forwardPublicMsgByMsgId")) {
|
||||
std::wstring wxid = GetWStringParam(j_param, "wxid");
|
||||
UINT64 msg_id = GetUINT64Param(j_param, "msgId");
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->ForwardPublicMsgByMsgId(
|
||||
wxid, msg_id);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/decodeImage")) {
|
||||
std::wstring file_path = GetWStringParam(j_param, "filePath");
|
||||
std::wstring store_dir = GetWStringParam(j_param, "storeDir");
|
||||
INT64 success = wxhelper::GlobalContext::GetInstance().mgr->DecodeImage(
|
||||
file_path, store_dir);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/getVoiceByMsgId")) {
|
||||
UINT64 msg_id = GetUINT64Param(j_param, "msgId");
|
||||
std::wstring store_dir = GetWStringParam(j_param, "storeDir");
|
||||
INT64 success = wxhelper::GlobalContext::GetInstance().mgr->GetVoiceByDB(
|
||||
msg_id, store_dir);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/sendCustomEmotion")) {
|
||||
std::wstring wxid = GetWStringParam(j_param, "wxid");
|
||||
std::wstring file_path = GetWStringParam(j_param, "filePath");
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->SendCustomEmotion(file_path,
|
||||
wxid);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/sendApplet")) {
|
||||
std::wstring wxid = GetWStringParam(j_param, "wxid");
|
||||
std::wstring waid_concat = GetWStringParam(j_param, "waidConcat");
|
||||
std::string waid = GetStringParam(j_param, "waid");
|
||||
std::string app_wxid = GetStringParam(j_param, "appletWxid");
|
||||
std::string json_param = GetStringParam(j_param, "jsonParam");
|
||||
std::string head_url = GetStringParam(j_param, "headImgUrl");
|
||||
std::string main_img = GetStringParam(j_param, "mainImg");
|
||||
std::string index_page = GetStringParam(j_param, "indexPage");
|
||||
|
||||
std::wstring waid_w = wxhelper::Utils::UTF8ToWstring(waid);
|
||||
|
||||
INT64 success = wxhelper::GlobalContext::GetInstance().mgr->SendApplet(
|
||||
wxid, waid_concat, waid_w, waid, app_wxid, json_param, head_url,
|
||||
main_img, index_page);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/sendPatMsg")) {
|
||||
std::wstring room_id = GetWStringParam(j_param, "receiver");
|
||||
std::wstring wxid = GetWStringParam(j_param, "wxid");
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->SendPatMsg(room_id, wxid);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/ocr")) {
|
||||
std::wstring image_path = GetWStringParam(j_param, "imagePath");
|
||||
std::string text("");
|
||||
INT64 success = wxhelper::GlobalContext::GetInstance().mgr->DoOCRTask(image_path,text);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", text}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/test")) {
|
||||
INT64 success = wxhelper::GlobalContext::GetInstance().mgr->Test();
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else {
|
||||
nlohmann::json ret_data = {
|
||||
{"code", 200}, {"data", {}}, {"msg", "not support url"}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
}
|
||||
nlohmann::json ret_data = {
|
||||
{"code", 200}, {"data", {}}, {"msg", "unreachable code."}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
}
|
17
src/http_server_callback.h
Normal file
17
src/http_server_callback.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef WXHELPER_HTTP_SERVER_CALLBACK_H_
|
||||
#define WXHELPER_HTTP_SERVER_CALLBACK_H_
|
||||
#include <string>
|
||||
|
||||
#include "http_server.h"
|
||||
#include "mongoose.h"
|
||||
|
||||
|
||||
void StartHttpServer(wxhelper::HttpServer *server);
|
||||
|
||||
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);
|
||||
std::string HttpDispatch(struct mg_connection *c, struct mg_http_message *hm);
|
||||
|
||||
#endif
|
40
src/log.cc
40
src/log.cc
@ -1,37 +1,21 @@
|
||||
#include "log.h"
|
||||
#include "pch.h"
|
||||
#include "log.h"
|
||||
|
||||
#include "easylogging++.h"
|
||||
INITIALIZE_EASYLOGGINGPP
|
||||
|
||||
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO
|
||||
namespace wxhelper {
|
||||
Log::Log(/* args */) {}
|
||||
Log::Log() {}
|
||||
|
||||
Log::~Log() {}
|
||||
|
||||
void Log::Initialize() {
|
||||
|
||||
el::Configurations conf;
|
||||
// 启用日志
|
||||
conf.setGlobally(el::ConfigurationType::Enabled, "true");
|
||||
// 设置日志文件目录以及文件名
|
||||
conf.setGlobally(el::ConfigurationType::Filename,
|
||||
"log\\log_%datetime{%Y%M%d %H%m%s}.log");
|
||||
// 设置日志文件最大文件大小
|
||||
conf.setGlobally(el::ConfigurationType::MaxLogFileSize, "20971520");
|
||||
// 是否写入文件
|
||||
conf.setGlobally(el::ConfigurationType::ToFile, "true");
|
||||
// 是否输出控制台
|
||||
conf.setGlobally(el::ConfigurationType::ToStandardOutput, "true");
|
||||
// 设置日志输出格式
|
||||
conf.setGlobally(el::ConfigurationType::Format,
|
||||
"[%datetime] [%thread] [%loc] [%level] : %msg");
|
||||
// 设置日志文件写入周期,如下每100条刷新到输出流中
|
||||
#ifdef _DEBUG
|
||||
conf.setGlobally(el::ConfigurationType::LogFlushThreshold, "1");
|
||||
#else
|
||||
conf.setGlobally(el::ConfigurationType::LogFlushThreshold, "100");
|
||||
#endif
|
||||
// 设置配置文件
|
||||
el::Loggers::reconfigureAllLoggers(conf);
|
||||
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
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user