feat: 新增数据库查询

This commit is contained in:
hugy 2023-07-02 17:04:35 +08:00
parent 272d62b0e9
commit 539d026146
9 changed files with 916 additions and 24 deletions

View File

@ -77,7 +77,8 @@ data 接口返回的数据
``` javascript
{
"code": 1,
"result": "ok"
"msg": "success",
"data":null
}
```
@ -102,18 +103,18 @@ data 接口返回的数据
|code|int|返回状态,1 成功, 0失败|
|result|string|成功提示|
|data|object|响应内容|
|account|string|账号|
|headImage|string|头像|
|city|string|城市|
|country|string|国家|
|currentDataPath|string|当前数据目录,登录的账号目录|
|dataSavePath|string|微信保存目录|
|mobile|string|手机|
|name|string|昵称|
|province|string|省|
|wxid|string|wxid|
|signature|string|个人签名|
|dbKey|string|数据库的SQLCipher的加密key可以使用该key配合decrypt.py解密数据库
|  account|string|账号|
|  headImage|string|头像|
|  city|string|城市|
|  country|string|国家|
|  currentDataPath|string|当前数据目录,登录的账号目录|
|  dataSavePath|string|微信保存目录|
|  mobile|string|手机|
|  name|string|昵称|
|  province|string|省|
|  wxid|string|wxid|
|  signature|string|个人签名|
|  dbKey|string|数据库的SQLCipher的加密key可以使用该key配合decrypt.py解密数据库
###### 接口示例
入参:
@ -204,8 +205,9 @@ enableHttp=0时使用ipport的tcp服务回传消息。
###### 返回字段
|返回字段|字段类型|说明 |
|---|---|---|
|code|int|返回状态,1成功, 0失败|
|result|string|成功提示|
|code|int|返回状态,0成功, 非0失败|
|data|object|null|
|msg|string|成功提示|
###### 接口示例
@ -221,5 +223,155 @@ enableHttp=0时使用ipport的tcp服务回传消息。
```
响应:
``` javascript
{"code":200,"msg":"success","data":null}
{"code":0,"msg":"success","data":null}
```
#### 4.取消hook消息**
###### 接口功能
> 取消hook消息
###### 接口地址
> [/api/unhookSyncMsg](/api/unhookSyncMsg)
###### HTTP请求方式
> POST JSON
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
###### 返回字段
|返回字段|字段类型|说明 |
|---|---|---|
|code|int|返回状态,0成功, 非0失败|
|data|object|null|
|msg|string|成功提示|
###### 接口示例
入参:
``` javascript
```
响应:
``` javascript
{"code":0,"msg":"success","data":null}
```
#### 5.好友列表**
###### 接口功能
> 好友列表
###### 接口地址
> [/api/getContactList](/api/getContactList)
###### HTTP请求方式
> POST JSON
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
###### 返回字段
|返回字段|字段类型|说明 |
|---|---|---|
|code|int|返回状态,0成功, 非0失败|
|data|object|好友信息|
|  customAccount|string|自定义账号|
|  encryptName|string|昵称|
|  nickname|string|昵称|
|  pinyin|string|简拼|
|  pinyinAll|string|全拼|
|  reserved1|number|未知|
|  reserved2|number|未知|
|  type|number|未知|
|  verifyFlag|number|未知|
|  wxid|string|wxid|
|msg|string|成功提示|
###### 接口示例
入参:
``` javascript
```
响应:
``` javascript
{
"code": 1,
"data": [
{
"customAccount": "",
"encryptName": "v3_020b3826fd03010000000000e04128fddf4d90000000501ea9a3dba12f95f6b60a0536a1adb6b40fc4086288f46c0b89e6c4eb8062bb1661b4b6fbab708dc4f89d543d7ade135b2be74c14b9cfe3accef377b9@stranger",
"nickname": "文件传输助手",
"pinyin": "WJCSZS",
"pinyinAll": "wenjianchuanshuzhushou",
"reserved1": 1,
"reserved2": 1,
"type": 3,
"verifyFlag": 0,
"wxid": "filehelper"
}
].
"msg": "success"
```
#### 6.获取数据库信息**
###### 接口功能
> 获取数据库信息和句柄
###### 接口地址
> [/api/getDBInfo](/api/getDBInfo)
###### HTTP请求方式
> POST JSON
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
###### 返回字段
|返回字段|字段类型|说明 |
|---|---|---|
|code|int|返回状态,0成功, 非0失败|
|msg|string|返回信息|
|data|array|好友信息|
|  databaseName|string|数据库名称|
|  handle|number|句柄|
|  tables|array|表信息|
|    name|string|表名|
|    rootpage|string|rootpage|
|    sql|string|ddl语句|
|    tableName|string|表名|
###### 接口示例
入参:
``` javascript
```
响应:
``` javascript
{
"code": 1,
"data": [
{
"databaseName": "MicroMsg.db",
"handle": 1755003930784,
"tables": [
{
"name": "Contact",
"rootpage": "2",
"sql": "CREATE TABLE Contact(UserName TEXT PRIMARY KEY ,Alias TEXT,EncryptUserName TEXT,DelFlag INTEGER DEFAULT 0,Type INTEGER DEFAULT 0,VerifyFlag INTEGER DEFAULT 0,Reserved1 INTEGER DEFAULT 0,Reserved2 INTEGER DEFAULT 0,Reserved3 TEXT,Reserved4 TEXT,Remark TEXT,NickName TEXT,LabelIDList TEXT,DomainList TEXT,ChatRoomType int,PYInitial TEXT,QuanPin TEXT,RemarkPYInitial TEXT,RemarkQuanPin TEXT,BigHeadImgUrl TEXT,SmallHeadImgUrl TEXT,HeadImgMd5 TEXT,ChatRoomNotify INTEGER DEFAULT 0,Reserved5 INTEGER DEFAULT 0,Reserved6 TEXT,Reserved7 TEXT,ExtraBuf BLOB,Reserved8 INTEGER DEFAULT 0,Reserved9 INTEGER DEFAULT 0,Reserved10 TEXT,Reserved11 TEXT)",
"tableName": "Contact"
}
]
}
],
"msg":"success"
}
```

510
src/db.cc Normal file
View File

@ -0,0 +1,510 @@
#include "pch.h"
#include "db.h"
#include "base64.h"
#include "wechat_function.h"
#include "utils.h"
namespace offset = wxhelper::V3_9_5_81::offset;
namespace wxhelper {
void DB::init(UINT64 base) {
base_addr_ = base;
dbmap_ = {};
dbs_ = {};
}
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++) {
common::SqlResult *sr = (common::SqlResult *)&data[i][j];
if (sr->column_name) {
delete[] sr->column_name;
sr->column_name = NULL;
}
if (sr->content) {
delete[] sr->content;
sr->content = NULL;
}
}
data[i].clear();
}
data.clear();
}
int DB::SelectDataInner(UINT64 db, const char *sql,
std::vector<std::vector<common::SqlResult>> &data) {
common::sqlite3_prepare p_sqlite3_prepare =
(common::sqlite3_prepare)(this->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++) {
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);
temp.content_len = nLength;
switch (nType) {
case SQLITE_BLOB: {
temp.content = new char[nLength];
memcpy(temp.content, pReadBlobData, nLength);
temp.is_blob = true;
break;
}
default: {
if (nLength != 0) {
temp.content = new char[nLength + 1];
memcpy(temp.content, pReadBlobData, nLength + 1);
} else {
temp.content = new char[2];
ZeroMemory(temp.content, 2);
}
temp.is_blob = false;
break;
}
}
tempStruct.push_back(temp);
}
data.push_back(tempStruct);
}
p_sqlite3_finalize(stmt);
return 1;
}
int DB::Select(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;
}
if (data.size() == 0) {
return 1;
}
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) {
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) {
std::string content(it[i].content);
item.push_back(content);
} else {
std::string base64_str =
base64_encode((BYTE *)it[i].content, it[i].content_len);
item.push_back(base64_str);
}
} else {
std::string b64_str =
base64_encode((BYTE *)it[i].content, it[i].content_len);
item.push_back(b64_str);
}
}
query_result.push_back(item);
}
FreeResult(data);
return 1;
}
int SelectDbInfo(void *data, int argc, char **argv, char **name) {
std::vector<common::SqlResult> result;
for (int i = 0; i < argc; i++) {
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]);
if (argv[i]) {
temp.content = new char[strlen(argv[i]) + 1];
memcpy(temp.content, argv[i], strlen(argv[i]) + 1);
temp.content_len = strlen(argv[i]);
} else {
temp.content = new char[2];
ZeroMemory(temp.content, 2);
temp.content_len = 0;
}
result.push_back(temp);
}
return 1;
}
int DB::ExecuteSQL(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) {
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);
} else {
tb.name = (char *)"NULL";
}
if (argv[2]) {
tb.table_name = new char[strlen(argv[2]) + 1];
memcpy(tb.table_name, argv[2], strlen(argv[2]) + 1);
} else {
tb.table_name = (char *)"NULL";
}
if (argv[3]) {
tb.rootpage = new char[strlen(argv[3]) + 1];
memcpy(tb.rootpage, argv[3], strlen(argv[3]) + 1);
} else {
tb.rootpage = (char *)"NULL";
}
if (argv[4]) {
tb.sql = new char[strlen(argv[4]) + 1];
memcpy(tb.sql, argv[4], strlen(argv[4]) + 1);
} else {
tb.sql = (char *)"NULL";
}
tb.name_len = strlen(tb.name);
tb.table_name_len = strlen(tb.table_name);
tb.sql_len = strlen(tb.sql);
tb.rootpage_len = strlen(tb.rootpage);
pdata->tables.push_back(tb);
pdata->count = pdata->tables.size();
return 0;
}
std::vector<void *> DB::GetDbHandles() {
dbs_.clear();
dbmap_.clear();
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
common::DatabaseInfo micro_msg_db{0};
micro_msg_db.db_name = (wchar_t *)(*(
UINT64 *)(p_contact_addr + offset::kMicroMsgDB + offset::kDBName));
micro_msg_db.db_name_len =
*(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\";",
(UINT64)GetDbInfo, &micro_msg_db);
dbs_.push_back(micro_msg_db);
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
common::DatabaseInfo chat_msg_db{0};
chat_msg_db.db_name = (wchar_t *)(*(
UINT64 *)(p_contact_addr + offset::kChatMsgDB + offset::kDBName));
chat_msg_db.db_name_len =
*(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\";",
(UINT64)GetDbInfo, &chat_msg_db);
dbs_.push_back(chat_msg_db);
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
common::DatabaseInfo misc_db{0};
misc_db.db_name =
(wchar_t *)(*(UINT64 *)(p_contact_addr + offset::kMiscDB + offset::kDBName));
misc_db.db_name_len =
*(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\";",
(UINT64)GetDbInfo, &misc_db);
dbs_.push_back(misc_db);
std::wstring misc_name = std::wstring((
wchar_t *)(*(UINT64 *)(p_contact_addr + offset::kMiscDB + offset::kDBName)));
dbmap_[misc_name] = misc_db;
// emotion.db
common::DatabaseInfo emotion_db{0};
emotion_db.db_name = (wchar_t *)(*(
UINT64 *)(p_contact_addr + offset::kEmotionDB + offset::kDBName));
emotion_db.db_name_len =
*(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\";",
(UINT64)GetDbInfo, &emotion_db);
dbs_.push_back(emotion_db);
std::wstring emotion_name = std::wstring((wchar_t *)(*(
UINT64 *)(p_contact_addr + offset::kEmotionDB + offset::kDBName)));
dbmap_[emotion_name] = emotion_db;
// media.db
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 + offset::kMediaDB + offset::kDBName + 0x8);
media_db.handle = media_db_addr;
ExecuteSQL(media_db_addr, "select * from sqlite_master where type=\"table\";",
(UINT64)GetDbInfo, &media_db);
dbs_.push_back(media_db);
std::wstring media_name = std::wstring((wchar_t *)(*(
UINT64 *)(p_contact_addr + offset::kMediaDB + offset::kDBName)));
dbmap_[media_name] = media_db;
// functionMsg.db
common::DatabaseInfo function_msg_db{0};
function_msg_db.db_name = (wchar_t *)(*(
UINT64 *)(p_contact_addr + offset::kFunctionMsgDB + offset::kDBName));
function_msg_db.db_name_len = *(
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\";",
(UINT64)GetDbInfo, &function_msg_db);
dbs_.push_back(function_msg_db);
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
common::DatabaseInfo bizchat_msg_db{0};
bizchat_msg_db.db_name = (wchar_t *)(*(
UINT64 *)(p_contact_addr + offset::kFunctionMsgDB + offset::kDBName));
bizchat_msg_db.db_name_len =
*(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\";",
(UINT64)GetDbInfo, &bizchat_msg_db);
dbs_.push_back(bizchat_msg_db);
std::wstring bizchat_msg_name = std::wstring((wchar_t *)(*(
UINT64 *)(p_contact_addr + offset::kFunctionMsgDB + offset::kDBName)));
dbmap_[bizchat_msg_name] = bizchat_msg_db;
}
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
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++) {
UINT64 next_addr = begin_ptr + i * 0x8;
UINT64 db_addr = *(UINT64 *)next_addr;
if (db_addr) {
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;
ExecuteSQL(msg0_db_addr,
"select * from sqlite_master where type=\"table\";",
(UINT64)GetDbInfo, &msg0_db);
dbs_.push_back(msg0_db);
std::wstring msg_db_name = std::wstring(msg0_db.db_name,msg0_db.db_name_len);
dbmap_[msg_db_name] = msg0_db;
// BufInfoStorage
UINT64 buf_info_addr = *(UINT64 *)(db_addr + 0x20);
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\";",
(UINT64)GetDbInfo, &media_msg0_db);
dbs_.push_back(media_msg0_db);
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
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) {
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\";",
(UINT64)GetDbInfo, &public_msg_db);
dbs_.push_back(public_msg_db);
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
UINT64 favItems_ptr =
*(UINT64 *)(*(UINT64 *)(*(UINT64 *)(favorite_storage_mgr_addr) + 0x10) + 0x8);
if (favItems_ptr) {
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\";",
(UINT64)GetDbInfo, &favorite_db);
dbs_.push_back(favorite_db);
std::wstring public_msg_db_name =
std::wstring(favorite_db.db_name,favorite_db.db_name_len);
dbmap_[public_msg_db_name] = favorite_db;
}
common::DatabaseInfo db_end = {0};
dbs_.push_back(db_end);
std::vector<void *> ret_array;
for (unsigned int i = 0; i < dbs_.size() - 1; i++){
ret_array.push_back(&dbs_[i]);
}
return ret_array;
}
UINT64 DB::GetDbHandleByDbName(wchar_t *dbname) {
if (dbmap_.size() == 0) {
GetDbHandles();
}
if (dbmap_.find(dbname) != dbmap_.end()) {
return dbmap_[dbname].handle;
}
return 0;
}
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);
UINT64 handle = GetDbHandleByDbName(dbname);
if (handle == 0) {
SPDLOG_INFO("MSG db handle is null");
return 0;
}
std::vector<std::vector<std::string>> result;
int ret = Select(handle, (const char *)sql, result);
if (result.size() == 0) continue;
dbIndex = dbmap_[dbname].extrainfo;
return stoi(result[1][0]);
}
return 0;
}
std::vector<std::string> DB::GetChatMsgByMsgId(ULONG64 msgid) {
char sql[260] = {0};
sprintf_s(sql,
"select "
"localId,TalkerId,MsgSvrID,Type,SubType,IsSender,CreateTime,"
"Sequence,StatusEx,FlagEx,Status,MsgServerSeq,MsgSequence,"
"StrTalker,StrContent,BytesExtra from MSG where MsgSvrID=%llu;",
msgid);
wchar_t dbname[20] = {0};
for (int i = 0;; i++) {
swprintf_s(dbname, L"MSG%d.db", i);
DWORD handle = GetDbHandleByDbName(dbname);
if (handle == 0) {
// LOG(INFO) << "MSG db handle is null";
return {};
}
std::vector<std::vector<std::string>> result;
int ret = Select(handle, (const char *)sql, result);
if (result.size() == 0) continue;
return result[1];
}
return {};
}
std::string DB::GetVoiceBuffByMsgId(ULONG64 msgid) {
char sql[260] = {0};
sprintf_s(sql, "SELECT Buf from Media WHERE Reserved0=%llu;", msgid);
wchar_t dbname[20] = {0};
for (int i = 0;; i++) {
swprintf_s(dbname, L"MediaMSG%d.db", i);
UINT64 handle = GetDbHandleByDbName(dbname);
if (handle == 0) {
// LOG(INFO) << "Media db handle is null";
return "";
}
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

39
src/db.h Normal file
View File

@ -0,0 +1,39 @@
#ifndef WXHELPER_DB_H_
#define WXHELPER_DB_H_
#include <string>
#include <vector>
#include "wechat_function.h"
#include "windows.h"
#include "singleton.h"
namespace wxhelper {
class DB :public Singleton<DB>{
public:
void init(UINT64 base);
int ExecuteSQL(UINT64 db, const char *sql, UINT64 callback, void *data);
int Select(UINT64 db_hanle, const char *sql,
std::vector<std::vector<std::string>> &query_result);
std::vector<void *> GetDbHandles();
UINT64 GetDbHandleByDbName(wchar_t *dbname);
INT64 GetLocalIdByMsgId(ULONG64 msgid, INT64 &dbIndex);
std::vector<std::string> GetChatMsgByMsgId(ULONG64 msgid);
std::string GetVoiceBuffByMsgId(ULONG64 msgid);
std::string GetPublicMsgCompressContentByMsgId(ULONG64 msgid);
private:
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
#endif

View File

@ -1,6 +1,7 @@
#include "pch.h"
#include "global_context.h"
#include "thread_pool.h"
#include "db.h"
namespace wxhelper {
@ -26,6 +27,7 @@ void GlobalContext::initialize(HMODULE module) {
http_server->HttpStart();
ThreadPool::GetInstance().Create(2, 8);
mgr = std::unique_ptr<Manager>(new Manager(base));
DB::GetInstance().init(base);
state =GlobalContextState::INITIALIZED;
}

View File

@ -172,7 +172,27 @@ int HookSyncMsg(std::string client_ip, int port, std::string url,
return ret;
}
int UnHookSyncMsg() { 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;
}
UINT64 base = Utils::GetWeChatWinBase();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
UINT64 do_add_msg_addr = base + offset::kDoAddMsg;
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;
}
} // namespace hooks
} // namespace wxhelper

View File

@ -4,6 +4,7 @@
#include "export.h"
#include "global_context.h"
#include "hooks.h"
#include "db.h"
namespace common = wxhelper::common;
@ -179,6 +180,36 @@ std::string HttpDispatch(struct mg_connection *c, struct mg_http_message *hm) {
}
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 {
nlohmann::json ret_data = {
{"code", 200}, {"data", {}}, {"msg", "not support url"}};

View File

@ -23,7 +23,7 @@ std::string Utils::WstringToUTF8(const std::wstring &str) {
return Utils::WstringToAnsi(str, CP_UTF8);
}
std::wstring Utils::AnsiToWstring(const std::string &input, DWORD locale) {
std::wstring Utils::AnsiToWstring(const std::string &input, INT64 locale) {
int wchar_len = MultiByteToWideChar(locale, 0, input.c_str(), -1, NULL, 0);
if (wchar_len > 0) {
std::vector<wchar_t> temp(wchar_len);
@ -34,7 +34,7 @@ std::wstring Utils::AnsiToWstring(const std::string &input, DWORD locale) {
return std::wstring();
}
std::string Utils::WstringToAnsi(const std::wstring &input, DWORD locale) {
std::string Utils::WstringToAnsi(const std::wstring &input, INT64 locale) {
int char_len = WideCharToMultiByte(locale, 0, input.c_str(), -1, 0, 0, 0, 0);
if (char_len > 0) {
std::vector<char> temp(char_len);
@ -184,7 +184,7 @@ std::string Utils::WCharToUTF8(wchar_t *wstr) {
return std::string();
}
bool Utils::IsTextUtf8(const char *str,int length) {
bool Utils::IsTextUtf8(const char *str,INT64 length) {
char endian = 1;
bool littlen_endian = (*(char *)&endian == 1);

View File

@ -6,7 +6,6 @@
#include <vector>
#define STRING2INT(str) (Utils::IsDigit(str) ? stoi(str) : 0)
#define WS2LPWS(wstr) (LPWSTR) wstr.c_str()
#define READ_WSTRING(addr, offset) ((*(DWORD *)(addr + offset + 0x4) == 0) ? std::wstring(L"") : std::wstring((wchar_t *)(*(DWORD *)(addr + offset)), *(DWORD *)(addr + offset + 0x4)))
namespace wxhelper {
@ -18,10 +17,10 @@ class Utils {
static std::string WstringToUTF8(const std::wstring &str);
static std::wstring AnsiToWstring(const std::string &input,
DWORD locale = CP_ACP);
INT64 locale = CP_ACP);
static std::string WstringToAnsi(const std::wstring &input,
DWORD locale = CP_ACP);
INT64 locale = CP_ACP);
static UINT64 GetWeChatWinBase();
@ -47,7 +46,7 @@ class Utils {
static std::string WCharToUTF8(wchar_t *wstr);
static bool IsTextUtf8(const char * str,int length) ;
static bool IsTextUtf8(const char * str,INT64 length) ;
static void Hide(HMODULE module);

View File

@ -3,6 +3,113 @@
namespace wxhelper {
namespace common {
/***************************sqlite3***************************************/
#define SQLITE_OK 0 /* Successful result */
/* beginning-of-error-codes */
#define SQLITE_ERROR 1 /* Generic error */
#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */
#define SQLITE_PERM 3 /* Access permission denied */
#define SQLITE_ABORT 4 /* Callback routine requested an abort */
#define SQLITE_BUSY 5 /* The database file is locked */
#define SQLITE_LOCKED 6 /* A table in the database is locked */
#define SQLITE_NOMEM 7 /* A malloc() failed */
#define SQLITE_READONLY 8 /* Attempt to write a readonly database */
#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/
#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */
#define SQLITE_CORRUPT 11 /* The database disk image is malformed */
#define SQLITE_NOTFOUND 12 /* Unknown opcode in sqlite3_file_control() */
#define SQLITE_FULL 13 /* Insertion failed because database is full */
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
#define SQLITE_EMPTY 16 /* Internal use only */
#define SQLITE_SCHEMA 17 /* The database schema changed */
#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */
#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */
#define SQLITE_MISMATCH 20 /* Data type mismatch */
#define SQLITE_MISUSE 21 /* Library used incorrectly */
#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
#define SQLITE_AUTH 23 /* Authorization denied */
#define SQLITE_FORMAT 24 /* Not used */
#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */
#define SQLITE_NOTADB 26 /* File opened that is not a database file */
#define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */
#define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */
#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */
#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
/* end-of-error-codes */
#define SQLITE_INTEGER 1
#define SQLITE_FLOAT 2
#define SQLITE_BLOB 4
#define SQLITE_NULL 5
#define SQLITE_TEXT 3
typedef int (*sqlite3_callback)(void*, int, char**, char**);
typedef int(__cdecl* sqlite3_exec)(UINT64, /* An open database */
const char* sql, /* SQL to be evaluated */
sqlite3_callback, /* Callback function */
void*, /* 1st argument to callback */
char** errmsg /* Error msg written here */
);
typedef int(__cdecl* sqlite3_prepare)(
UINT64 db, /* Database handle */
const char* zSql, /* SQL statement, UTF-8 encoded */
int nByte, /* Maximum length of zSql in bytes. */
UINT64** ppStmt, /* OUT: Statement handle */
const char** pzTail /* OUT: Pointer to unused portion of zSql */
);
typedef int(__cdecl* sqlite3_open)(const char* filename, UINT64** ppDb);
typedef int(__cdecl* sqlite3_sleep)(int);
typedef int(__cdecl* sqlite3_errcode)(UINT64* db);
typedef int(__cdecl* sqlite3_close)(UINT64*);
typedef int(__cdecl* sqlite3_step)(UINT64*);
typedef int(__cdecl* sqlite3_column_count)(UINT64* pStmt);
typedef const char*(__cdecl* sqlite3_column_name)(UINT64*, int N);
typedef int(__cdecl* sqlite3_column_type)(UINT64*, int iCol);
typedef const void*(__cdecl* sqlite3_column_blob)(UINT64*, int iCol);
typedef int(__cdecl* sqlite3_column_bytes)(UINT64*, int iCol);
typedef int(__cdecl* sqlite3_finalize)(UINT64* pStmt);
/***************************sqlite3 end*************************************/
struct TableInfo {
char *name;
INT64 name_len;
char *table_name;
INT64 table_name_len;
char *sql;
INT64 sql_len;
char *rootpage;
INT64 rootpage_len;
};
struct DatabaseInfo {
UINT64 handle = 0;
wchar_t *db_name = NULL;
INT64 db_name_len = 0;
std::vector<TableInfo> tables;
INT64 count = 0;
INT64 extrainfo = 0;
};
struct SqlResult {
char *column_name;
INT64 column_name_len;
char *content;
INT64 content_len;
BOOL is_blob;
};
struct InnerMessageStruct {
char *buffer;
int length;
@ -57,6 +164,8 @@ struct ContactInner {
} // namespace common
namespace V3_9_5_81 {
namespace function {
typedef UINT64(*__GetAccountService)();
typedef UINT64(*__GetDataSavePath)(UINT64);
typedef UINT64(*__GetCurrentDataPath)(UINT64);
@ -131,6 +240,36 @@ const UINT64 kGetAppMsgMgr = 0x8c33f0;
const UINT64 kGetContactMgr = 0x8ae3d0;
const UINT64 kGetContactList = 0xeab270;
const UINT64 k_sqlite3_exec = 0x252e340;
const UINT64 k_sqlite3_prepare = 0x2535eb0;
const UINT64 k_sqlite3_open = 0x256d6b0;
const UINT64 k_sqlite3_backup_init= 0x24e8450;
const UINT64 k_sqlite3_errcode = 0x256bfb0;
const UINT64 k_sqlite3_close = 0x256a110;
const UINT64 k_sqlite3_step = 0x24f2350;
const UINT64 k_sqlite3_column_count = 0x1df3c80;
const UINT64 k_sqlite3_column_name = 0x24f3570;
const UINT64 k_sqlite3_column_type = 0x24f33c0;
const UINT64 k_sqlite3_column_blob = 0x24f2ba0;
const UINT64 k_sqlite3_column_bytes = 0x24f2c90;
const UINT64 k_sqlite3_finalize = 0x24f1400;
const UINT64 kGPInstance = 0x3a6f908;
const UINT64 kMicroMsgDB= 0xb8;
const UINT64 kChatMsgDB = 0x2c8;
const UINT64 kMiscDB = 0x5f0;
const UINT64 kEmotionDB = 0x838;
const UINT64 kMediaDB = 0xef8;
const UINT64 kBizchatMsgDB = 0x1a70;
const UINT64 kFunctionMsgDB = 0x1b48;
const UINT64 kDBName = 0x28;
const UINT64 kStorageStart = 0x0;
const UINT64 kStorageEnd= 0x0;
const UINT64 kMultiDBMgr= 0x3acfb68;
const UINT64 kPublicMsgMgr= 0x3acc268;
const UINT64 kFavoriteStorageMgr= 0x3acf0d0;
const UINT64 kFTSFavoriteMgr= 0x24f1400;
} // namespace offset
} // namespace V3_9_5_81