diff --git a/App/App.cpp b/App/App.cpp index 1b7c148..096a37b 100644 --- a/App/App.cpp +++ b/App/App.cpp @@ -13,7 +13,7 @@ void printContacts(ContactMap_t contacts) { wprintf(L"contacts number: %ld\n", contacts.size()); - for (auto it = contacts.begin(); it != contacts.end(); ++it) { + for (auto it = contacts.begin(); it != contacts.end(); it++) { wprintf(L"%s\t%s\t%s\t%s\t%s\t%s\t%s\r\n", it->second.wxId.c_str(), it->second.wxCode.c_str(), it->second.wxName.c_str(), it->second.wxGender.c_str(), it->second.wxCountry.c_str(), it->second.wxProvince.c_str(), it->second.wxCity.c_str()); @@ -23,11 +23,19 @@ void printContacts(ContactMap_t contacts) void printDbNames(vector vDbs) { wprintf(L"db numbers: %ld\n", vDbs.size()); - for (auto it = vDbs.begin(); it != vDbs.end(); ++it) { + for (auto it = vDbs.begin(); it != vDbs.end(); it++) { wprintf(L"%s\n", (*it).c_str()); } } +void printDbTables(DbTableVector_t tables) +{ + wprintf(L"table numbers: %ld\n", tables.size()); + for (auto it = tables.begin(); it != tables.end(); it++) { + wprintf(L"%s\n%s\n\n", (it->table).c_str(), (it->sql).c_str()); + } +} + int onTextMsg(WxMessage_t msg) { wprintf(L"%s msgType: %d, msgSource: %d, isSelf: %d\n", msg.id.c_str(), msg.type, msg.source, msg.self); @@ -84,6 +92,11 @@ int main() // 测试获取数据库名 auto vDbNames = WxGetDbNames(); printDbNames(vDbNames); + Sleep(1000); // 等待1秒 + + // 测试获取数据库中的表 + auto vDbTables = WxGetDbTables(L"ChatMsg.db"); + printDbTables(vDbTables); while (1) { Sleep(10000); // 休眠,释放CPU diff --git a/Rpc/rpc.idl b/Rpc/rpc.idl index 138dede..cafe7cf 100644 --- a/Rpc/rpc.idl +++ b/Rpc/rpc.idl @@ -39,6 +39,13 @@ interface ISpy typedef RpcContact_t *PRpcContact; typedef RpcContact_t **PPRpcContact; + typedef struct RpcTables { + BSTR table; // 表名 + BSTR sql; // 建表 SQL + } RpcTables_t; + typedef RpcTables_t *PRpcTables; + typedef RpcTables_t **PPRpcTables; + int IsLogin(); int SendTextMsg([ in, string ] const wchar_t *wxid, [ in, string ] const wchar_t *at_wxid, [ in, string ] const wchar_t *msg); @@ -46,6 +53,7 @@ interface ISpy int GetMsgTypes([out] int *pNum, [ out, size_is(, *pNum) ] PPRpcIntBstrPair *msgTypes); int GetContacts([out] int *pNum, [ out, size_is(, *pNum) ] PPRpcContact *contacts); int GetDbNames([out] int *pNum, [ out, size_is(, *pNum) ] BSTR **dbs); + int GetDbTables([ in, string ] const wchar_t *db, [out] int *pNum, [ out, size_is(, *pNum) ] PPRpcTables *tbls); void EnableReceiveMsg(); [callback] int ReceiveMsg([in] RpcMessage_t rpcMsg); diff --git a/SDK/rpc_client.cpp b/SDK/rpc_client.cpp index ced9cc7..ea3b1f2 100644 --- a/SDK/rpc_client.cpp +++ b/SDK/rpc_client.cpp @@ -174,6 +174,27 @@ BSTR *RpcGetDbNames(int *pNum) return pBstr; } +PPRpcTables RpcGetDbTables(const wchar_t *db, int *pNum) +{ + int ret = 0; + unsigned long ulCode = 0; + PPRpcTables ppRpcTables = NULL; + + RpcTryExcept { ret = client_GetDbTables(db, pNum, &ppRpcTables); } + RpcExcept(1) + { + ulCode = RpcExceptionCode(); + printf("RpcGetDbTables exception 0x%lx = %ld\n", ulCode, ulCode); + } + RpcEndExcept; + if (ret != 0) { + printf("RpcGetDbTables Failed: %d\n", ret); + return NULL; + } + + return ppRpcTables; +} + int server_ReceiveMsg(RpcMessage_t rpcMsg) { WxMessage_t msg; diff --git a/SDK/rpc_client.h b/SDK/rpc_client.h index 8e9c9b2..0f3b5f8 100644 --- a/SDK/rpc_client.h +++ b/SDK/rpc_client.h @@ -12,3 +12,4 @@ int RpcSendImageMsg(const wchar_t *wxid, const wchar_t *path); PPRpcIntBstrPair RpcGetMsgTypes(int *pNum); PPRpcContact RpcGetContacts(int *pNum); BSTR *RpcGetDbNames(int *pNum); +PPRpcTables RpcGetDbTables(const wchar_t *db, int *pNum); diff --git a/SDK/sdk.cpp b/SDK/sdk.cpp index f773100..c049144 100644 --- a/SDK/sdk.cpp +++ b/SDK/sdk.cpp @@ -187,3 +187,24 @@ std::vector WxGetDbNames() return vDbs; } + +DbTableVector_t WxGetDbTables(wstring db) +{ + DbTableVector_t vTables; + int size = 0; + PPRpcTables pp = RpcGetDbTables(db.c_str(), &size); + for (int i = 0; i < size; i++) { + WxDbTable_t tbl; + tbl.table = GetWstringFromBstr(pp[i]->table); + tbl.sql = GetWstringFromBstr(pp[i]->sql); + + vTables.push_back(tbl); + midl_user_free(pp[i]); + } + + if (pp) { + midl_user_free(pp); + } + + return vTables; +} diff --git a/SDK/sdk.def b/SDK/sdk.def index 0ab525a..ed80cec 100644 --- a/SDK/sdk.def +++ b/SDK/sdk.def @@ -5,4 +5,5 @@ WxGetMsgTypes WxSendImageMsg WxGetContacts - WxGetDbNames + WxGetDbNames + WxGetDbTables diff --git a/SDK/sdk.h b/SDK/sdk.h index f748d21..8385482 100644 --- a/SDK/sdk.h +++ b/SDK/sdk.h @@ -28,8 +28,14 @@ typedef struct WxContact { wstring wxGender; // 性别 } WxContact_t; +typedef struct WxDbTable { + wstring table; // 表名 + wstring sql; // 建表 SQL +} WxDbTable_t; + typedef map MsgTypesMap_t; typedef map ContactMap_t; +typedef vector DbTableVector_t; int WxInitSDK(); int WxSetTextMsgCb(const std::function &onMsg); @@ -38,3 +44,4 @@ int WxSendImageMsg(wstring wxid, wstring path); ContactMap_t WxGetContacts(); MsgTypesMap_t WxGetMsgTypes(); vector WxGetDbNames(); +DbTableVector_t WxGetDbTables(wstring db); diff --git a/SDK/util.cpp b/SDK/util.cpp index b3731de..5633e31 100644 --- a/SDK/util.cpp +++ b/SDK/util.cpp @@ -187,6 +187,15 @@ wstring GetWstringFromBstr(BSTR p) return ws; } +BSTR GetBstrFromString(const char *str) +{ + int wslen = MultiByteToWideChar(CP_ACP, 0, str, strlen(str), 0, 0); + BSTR bstr = SysAllocStringLen(0, wslen); + MultiByteToWideChar(CP_ACP, 0, str, strlen(str), bstr, wslen); + + return bstr; +} + BSTR GetBstrFromWstring(wstring ws) { if (!ws.empty()) { diff --git a/SDK/util.h b/SDK/util.h index 15194d1..33e44e7 100644 --- a/SDK/util.h +++ b/SDK/util.h @@ -24,5 +24,6 @@ BSTR GetBstrByAddress(DWORD address); void GetRpcMessage(WxMessage_t *wxMsg, RpcMessage_t rpcMsg); DWORD GetMemoryIntByAddress(HANDLE hProcess, DWORD address); std::wstring GetWstringFromBstr(BSTR p); +BSTR GetBstrFromString(const char *str); BSTR GetBstrFromWstring(std::wstring ws); std::wstring GetUnicodeInfoByAddress(HANDLE hProcess, DWORD address); diff --git a/Spy/exec_sql.cpp b/Spy/exec_sql.cpp index f2f4d3e..55cec26 100644 --- a/Spy/exec_sql.cpp +++ b/Spy/exec_sql.cpp @@ -3,6 +3,7 @@ #include "exec_sql.h" #include "load_calls.h" +#include "util.h" using namespace std; @@ -12,6 +13,32 @@ extern DWORD g_WeChatWinDllAddr; typedef map dbMap_t; static dbMap_t dbMap; +// 回调函数指针 +typedef int (*sqlite3_callback)(void *, int, char **, char **); + +// sqlite3_exec函数指针 +typedef int(__cdecl *Sqlite3_exec)(DWORD, /* The database on which the SQL executes */ + const char *, /* The SQL to be executed */ + sqlite3_callback, /* Invoke this callback routine */ + void *, /* First argument to xCallback() */ + char ** /* Write error messages here */ +); + +static int cbGetTables(void *ret, int argc, char **argv, char **azColName) +{ + vector *p = (vector *)ret; + RpcTables_t tbl = { 0 }; + for (int i = 0; i < argc; i++) { + if (strcmp(azColName[i], "name") == 0) { + tbl.table = argv[i] ? GetBstrFromString(argv[i]) : NULL; + } else if (strcmp(azColName[i], "sql") == 0) { + tbl.sql = argv[i] ? GetBstrFromString(argv[i]) : NULL; + } + } + p->push_back(tbl); + return 0; +} + vector GetDbNames() { vector vDbs; @@ -31,3 +58,17 @@ vector GetDbNames() } return vDbs; } + +vector GetDbTables(wstring db) +{ + vector vTables; + const char *sql = "select * from sqlite_master where type=\"table\";"; + Sqlite3_exec p_Sqlite3_exec = (Sqlite3_exec)(g_WeChatWinDllAddr + g_WxCalls.sql.exec); + + auto it = dbMap.find(db); + if (it != dbMap.end()) { + p_Sqlite3_exec(it->second, sql, (sqlite3_callback)cbGetTables, &vTables, 0); + } + + return vTables; +} diff --git a/Spy/exec_sql.h b/Spy/exec_sql.h index d004b23..4b65d76 100644 --- a/Spy/exec_sql.h +++ b/Spy/exec_sql.h @@ -6,3 +6,4 @@ #include "rpc_h.h" std::vector GetDbNames(); +std::vector GetDbTables(std::wstring db); diff --git a/Spy/rpc_server.cpp b/Spy/rpc_server.cpp index d6e9a97..8c590cb 100644 --- a/Spy/rpc_server.cpp +++ b/Spy/rpc_server.cpp @@ -139,6 +139,29 @@ int server_GetDbNames(int *pNum, BSTR **dbs) return 0; } +int server_GetDbTables(const wchar_t *db, int *pNum, PPRpcTables *tbls) +{ + vector tables = GetDbTables(db); + *pNum = tables.size(); + PPRpcTables pp = (PPRpcTables)midl_user_allocate(*pNum * sizeof(RpcTables_t)); + if (pp == NULL) { + printf("server_GetMsgTypes midl_user_allocate Failed for pp\n"); + return -2; + } + + int index = 0; + for (auto it = tables.begin(); it != tables.end(); it++) { + PRpcTables p = (PRpcTables)midl_user_allocate(sizeof(RpcTables_t)); + p->table = it->table; + p->sql = it->sql; + pp[index++] = p; + } + + *tbls = pp; + + return 0; +} + RPC_STATUS CALLBACK SecurityCallback(RPC_IF_HANDLE /*hInterface*/, void * /*pBindingHandle*/) { return RPC_S_OK; // Always allow anyone.