From 4e7592ca1b249f8ef37eb659c6d6cffaadd0f7ea Mon Sep 17 00:00:00 2001 From: Changhua Date: Sat, 20 Aug 2022 22:10:11 +0800 Subject: [PATCH] Impl execute sql --- App/App.cpp | 53 +++++++++++++- Rpc/rpc.idl | 12 ++++ SDK/rpc_client.cpp | 21 ++++++ SDK/rpc_client.h | 1 + SDK/sdk.cpp | 25 +++++++ SDK/sdk.def | 3 +- SDK/sdk.h | 8 +++ SDK/util.cpp | 45 ++++++++++++ SDK/util.h | 9 ++- SDKpy/SDKpy.vcxproj | 2 + SDKpy/SDKpy.vcxproj.filters | 6 ++ SDKpy/sdkpy.cpp | 57 ++++++++++++--- Spy/exec_sql.cpp | 127 +++++++++++++++++++++++++++++--- Spy/exec_sql.h | 1 + Spy/rpc_server.cpp | 139 ++++++++++++++++++++++++------------ 15 files changed, 439 insertions(+), 70 deletions(-) diff --git a/App/App.cpp b/App/App.cpp index d301240..c4dd8a0 100644 --- a/App/App.cpp +++ b/App/App.cpp @@ -10,6 +10,10 @@ 等效为在属性,链接,输入中添加该依赖 */ +typedef map sqlTypes_t; +static sqlTypes_t sqlTypes + = sqlTypes_t { { 1, L"INTEGER" }, { 2, L"FLOAT" }, { 3, L"TEXT" }, { 4, L"BLOB" }, { 5, L"NULL" } }; + void printContacts(ContactMap_t contacts) { wprintf(L"contacts number: %ld\n", contacts.size()); @@ -36,6 +40,46 @@ void printDbTables(DbTableVector_t tables) } } +void printDbResults(SqlRetVector_t vvResults) +{ + int rows = vvResults.size(); + printf("vvResults.size: %d\n", rows); + rows = 0; + for (auto vv = vvResults.begin(); vv != vvResults.end(); vv++) { + printf("Row %d\n", rows++); + for (auto v = vv->begin(); v != vv->end(); v++) { + wprintf(L"%s[%s]: ", v->column.c_str(), sqlTypes[v->type].c_str()); + switch (v->type) { + case 1: { + printf("%d\n", stoi(v->content.c_str())); + break; + } + case 2: { + printf("%f\n", stof(v->content.c_str())); + break; + } + case 3: { + printf("%s\n", v->content.c_str()); + break; + } + case 4: { + byte *p = (byte *)(v->content.c_str()); + for (unsigned int i = 0; i < v->content.size(); i++) { + printf("%02X ", p[i]); + } + printf("\n"); + break; + } + default: { + printf("\n"); + break; + } + } + } + } + printf("\n"); +} + 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); @@ -53,7 +97,7 @@ int main() wstring content = L"这里填写消息内容"; wstring img_path = L"test.jpg"; - _wsetlocale(LC_ALL, L"chs"); // 这是个大坑,不设置中文直接不见了。。。 + setlocale(LC_ALL, "chs"); // 这是个大坑,不设置中文直接不见了。。。 wprintf(L"WxInitSDK: "); status = WxInitSDK(); @@ -95,8 +139,13 @@ int main() Sleep(1000); // 等待1秒 // 测试获取数据库中的表 - auto vDbTables = WxGetDbTables(L"ChatMsg.db"); + auto vDbTables = WxGetDbTables(L"MicroMsg.db"); printDbTables(vDbTables); + Sleep(1000); // 等待1秒 + + // 测试执行 SQL + auto vvResults = WxExecDbQuery(L"MicroMsg.db", L"SELECT * FROM Contact LIMIT 1;"); + printDbResults(vvResults); while (1) { Sleep(10000); // 休眠,释放CPU diff --git a/Rpc/rpc.idl b/Rpc/rpc.idl index 99f8f5a..f7e77f0 100644 --- a/Rpc/rpc.idl +++ b/Rpc/rpc.idl @@ -46,6 +46,15 @@ interface ISpy typedef RpcTables_t *PRpcTables; typedef RpcTables_t **PPRpcTables; + typedef struct RpcSqlResult { + int type; + BSTR column; + BSTR content; + } RpcSqlResult_t; + typedef RpcSqlResult_t *PRpcSqlResult; + typedef RpcSqlResult_t **PPRpcSqlResult; + typedef RpcSqlResult_t ***PPPRpcSqlResult; + int IsLogin(); int SendTextMsg([ in, string ] const wchar_t *wxid, [ in, string ] const wchar_t *msg, [ in, unique, string ] const wchar_t *atWxids); @@ -54,6 +63,9 @@ interface ISpy 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); + int ExecDbQuery([ in, string ] const wchar_t *db, + [ in, string ] const wchar_t *sql, [out] int *pRow, [out] int *pCol, + [ out, size_is(, *pRow, *pCol) ] PPPRpcSqlResult *ret); void EnableReceiveMsg(); void DisableReceiveMsg(); diff --git a/SDK/rpc_client.cpp b/SDK/rpc_client.cpp index bf48835..eb802ff 100644 --- a/SDK/rpc_client.cpp +++ b/SDK/rpc_client.cpp @@ -212,6 +212,27 @@ PPRpcTables RpcGetDbTables(const wchar_t *db, int *pNum) return ppRpcTables; } +PPPRpcSqlResult RpcExecDbQuery(const wchar_t *db, const wchar_t *sql, int *pRow, int *pCol) +{ + int ret = 0; + unsigned long ulCode = 0; + PPPRpcSqlResult pppRpcSqlResult = NULL; + + RpcTryExcept { ret = client_ExecDbQuery(db, sql, pRow, pCol, &pppRpcSqlResult); } + RpcExcept(1) + { + ulCode = RpcExceptionCode(); + printf("RpcExecDbQuery exception 0x%lx = %ld\n", ulCode, ulCode); + } + RpcEndExcept; + if (ret != 0) { + printf("RpcExecDbQuery Failed: %d\n", ret); + return NULL; + } + + return pppRpcSqlResult; +} + int server_ReceiveMsg(RpcMessage_t rpcMsg) { WxMessage_t msg; diff --git a/SDK/rpc_client.h b/SDK/rpc_client.h index 002cb9f..1133dfe 100644 --- a/SDK/rpc_client.h +++ b/SDK/rpc_client.h @@ -14,3 +14,4 @@ PPRpcIntBstrPair RpcGetMsgTypes(int *pNum); PPRpcContact RpcGetContacts(int *pNum); BSTR *RpcGetDbNames(int *pNum); PPRpcTables RpcGetDbTables(const wchar_t *db, int *pNum); +PPPRpcSqlResult RpcExecDbQuery(const wchar_t *db, const wchar_t *sql, int *row, int *col); diff --git a/SDK/sdk.cpp b/SDK/sdk.cpp index 10ae259..ef0c302 100644 --- a/SDK/sdk.cpp +++ b/SDK/sdk.cpp @@ -237,3 +237,28 @@ DbTableVector_t WxGetDbTables(wstring db) return vTables; } + +SqlRetVector_t WxExecDbQuery(wstring db, wstring sql) +{ + int row, col = 0; + PPPRpcSqlResult ppp = RpcExecDbQuery(db.c_str(), sql.c_str(), &row, &col); + vector> vvResults; + for (int r = 0; r < row; r++) { + vector vResult; + for (int c = 0; c < col; c++) { + WxSqlResult_t result = { 0 }; + result.type = ppp[r][c]->type; + result.column = GetWstringFromBstr(ppp[r][c]->column); + result.content = GetBytesFromBstr(ppp[r][c]->content); + vResult.push_back(result); + midl_user_free(ppp[r][c]); + } + vvResults.push_back(vResult); + midl_user_free(ppp[r]); + } + if (ppp) { + midl_user_free(ppp); + } + + return vvResults; +} diff --git a/SDK/sdk.def b/SDK/sdk.def index 8678b85..7e215b2 100644 --- a/SDK/sdk.def +++ b/SDK/sdk.def @@ -8,4 +8,5 @@ WxSendImageMsg WxGetContacts WxGetDbNames - WxGetDbTables + WxGetDbTables + WxExecDbQuery diff --git a/SDK/sdk.h b/SDK/sdk.h index f73b430..deb3981 100644 --- a/SDK/sdk.h +++ b/SDK/sdk.h @@ -33,9 +33,16 @@ typedef struct WxDbTable { wstring sql; // 建表 SQL } WxDbTable_t; +typedef struct WxSqlResult { + int type; + wstring column; + string content; +} WxSqlResult_t; + typedef map MsgTypesMap_t; typedef map ContactMap_t; typedef vector DbTableVector_t; +typedef vector> SqlRetVector_t; int WxInitSDK(); int WxDestroySDK(); @@ -47,3 +54,4 @@ ContactMap_t WxGetContacts(); MsgTypesMap_t WxGetMsgTypes(); vector WxGetDbNames(); DbTableVector_t WxGetDbTables(wstring db); +SqlRetVector_t WxExecDbQuery(wstring db, wstring sql); diff --git a/SDK/util.cpp b/SDK/util.cpp index 9e57a04..faecc7d 100644 --- a/SDK/util.cpp +++ b/SDK/util.cpp @@ -1,5 +1,7 @@ #include "Shlwapi.h" #include "framework.h" +#include +#include #include #include #include @@ -12,6 +14,11 @@ using namespace std; +static wstring_convert, wchar_t> S_WS_Converter; + +wstring String2Wstring(string s) { return S_WS_Converter.from_bytes(s); } +string Wstring2String(wstring ws) { return S_WS_Converter.to_bytes(ws); } + static int GetWeChatPath(wchar_t *path) { int ret = -1; @@ -221,6 +228,44 @@ BSTR GetBstrFromWstring(wstring ws) return NULL; } +BSTR GetBstrFromStringBuffer(const char *str, int length) +{ + int wslen = MultiByteToWideChar(CP_ACP, 0, str, length, 0, 0); + BSTR bstr = SysAllocStringLen(0, wslen); + MultiByteToWideChar(CP_ACP, 0, str, length, bstr, wslen); + + return bstr; +} + +BSTR GetBstrFromByteArray(const byte *b, int len) +{ + BSTR bstr = SysAllocStringLen(0, len); + if (bstr == NULL) { + return NULL; + } + memcpy((byte *)bstr, b, len); + + return bstr; +} + +string GetBytesFromBstr(BSTR bstr) +{ + string s = ""; + if (bstr) { + int len = SysStringByteLen(bstr) / 2; + char *tmp = new char[len]; + char *p = (char *)bstr; + for (int i = 0; i < len; i++) { + tmp[i] = p[i]; + } + SysFreeString(bstr); + s = string(tmp, len); + delete[] tmp; + } + + return s; +} + void GetRpcMessage(WxMessage_t *wxMsg, RpcMessage_t rpcMsg) { wxMsg->self = rpcMsg.self; diff --git a/SDK/util.h b/SDK/util.h index b8c4ba9..7c52791 100644 --- a/SDK/util.h +++ b/SDK/util.h @@ -17,10 +17,15 @@ int OpenWeChat(DWORD *pid); int GetWeChatVersion(wchar_t *version); int GetWstringByAddress(DWORD address, wchar_t *buffer, DWORD buffer_size); -BSTR GetBstrByAddress(DWORD address); void GetRpcMessage(WxMessage_t *wxMsg, RpcMessage_t rpcMsg); DWORD GetMemoryIntByAddress(HANDLE hProcess, DWORD address); -std::wstring GetWstringFromBstr(BSTR p); +BSTR GetBstrByAddress(DWORD address); BSTR GetBstrFromString(const char *str); BSTR GetBstrFromWstring(std::wstring ws); +BSTR GetBstrFromByteArray(const byte *b, int len); +BSTR GetBstrFromStringBuffer(const char *str, int length); +std::string GetBytesFromBstr(BSTR bstr); +std::wstring GetWstringFromBstr(BSTR bstr); std::wstring GetUnicodeInfoByAddress(HANDLE hProcess, DWORD address); +std::wstring String2Wstring(std::string s); +std::string Wstring2String(std::wstring ws); diff --git a/SDKpy/SDKpy.vcxproj b/SDKpy/SDKpy.vcxproj index 939c586..438af2e 100644 --- a/SDKpy/SDKpy.vcxproj +++ b/SDKpy/SDKpy.vcxproj @@ -157,9 +157,11 @@ + + diff --git a/SDKpy/SDKpy.vcxproj.filters b/SDKpy/SDKpy.vcxproj.filters index ead8662..fd4a0d2 100644 --- a/SDKpy/SDKpy.vcxproj.filters +++ b/SDKpy/SDKpy.vcxproj.filters @@ -21,10 +21,16 @@ 头文件 + + 头文件 + 源文件 + + 源文件 + \ No newline at end of file diff --git a/SDKpy/sdkpy.cpp b/SDKpy/sdkpy.cpp index 32f484c..a7081ec 100644 --- a/SDKpy/sdkpy.cpp +++ b/SDKpy/sdkpy.cpp @@ -1,12 +1,48 @@ -#include +#include #include #include #include "sdk.h" +#include "util.h" namespace py = pybind11; -int WxEnableRecvMsgPy(const std::function& onMsg) { return WxEnableRecvMsg(onMsg); } +int WxEnableRecvMsgPy(const std::function &onMsg) { return WxEnableRecvMsg(onMsg); } + +py::object WxExecDbQueryPy(std::wstring db, std::wstring sql) +{ + py::list results; + SqlRetVector_t cResults = WxExecDbQuery(db, sql); + for (auto vv = cResults.begin(); vv != cResults.end(); vv++) { + py::dict row; + for (auto v = vv->begin(); v != vv->end(); v++) { + switch (v->type) { + case 1: { // SQLITE_INTEGER + row[py::cast(v->column)] = stoi(v->content); + break; + } + case 2: { // SQLITE_FLOAT + row[py::cast(v->column)] = stof(v->content); + break; + } + case 3: { // SQLITE_TEXT + row[py::cast(v->column)] = String2Wstring(v->content); + break; + } + case 4: { // SQLITE_BLOB + row[py::cast(v->column)] = py::bytes(v->content.c_str(), v->content.size()); + break; + } + default: { + row[py::cast(v->column)] = ""; + break; + } + } + } + results.append(row); + } + return results; +} PYBIND11_MODULE(wcferry, m) { @@ -29,21 +65,22 @@ PYBIND11_MODULE(wcferry, m) .def_readonly("wxCountry", &WxContact::wxCountry) .def_readonly("wxProvince", &WxContact::wxProvince) .def_readonly("wxCity", &WxContact::wxCity) - .def_readonly("wxGender", &WxContact::wxGender); - - py::class_(m, "WxDbTable") - .def_readonly("table", &WxDbTable::table) - .def_readonly("sql", &WxDbTable::sql); + .def_readonly("wxGender", &WxContact::wxGender); + + py::class_(m, "WxDbTable").def_readonly("table", &WxDbTable::table).def_readonly("sql", &WxDbTable::sql); m.def("WxInitSDK", &WxInitSDK, "Initiate SDK. Return 0 on success,else on failure."); m.def("WxEnableRecvMsg", &WxEnableRecvMsgPy, "Enable message receiving and provide a callback", py::arg("onMsg")); m.def("WxDisableRecvMsg", &WxDisableRecvMsg, "Disable message receiving."); - m.def("WxSendTextMsg", &WxSendTextMsg, "Send text message.", py::arg("wxid"), py::arg("msg"), py::arg("atWxids")=L""); + m.def("WxSendTextMsg", &WxSendTextMsg, "Send text message.", py::arg("wxid"), py::arg("msg"), + py::arg("atWxids") = L""); m.def("WxSendImageMsg", &WxSendImageMsg, "Send image message.", py::arg("wxid"), py::arg("path")); m.def("WxGetContacts", &WxGetContacts, py::return_value_policy::reference, "Get contact list."); - m.def("WxGetMsgTypes", &WxGetMsgTypes, py::return_value_policy::reference, "Get message types."); - m.def("WxGetDbNames", &WxGetDbNames, py::return_value_policy::reference, "Get DB names."); + m.def("WxGetMsgTypes", &WxGetMsgTypes, py::return_value_policy::reference, "Get message types."); + m.def("WxGetDbNames", &WxGetDbNames, py::return_value_policy::reference, "Get DB names."); m.def("WxGetDbTables", &WxGetDbTables, py::return_value_policy::reference, "Get DB tables.", py::arg("db")); + m.def("WxExecDbQuery", &WxExecDbQueryPy, py::return_value_policy::reference, "Get DB tables.", py::arg("db"), + py::arg("sql")); #ifdef VERSION_INFO m.attr("__version__") = VERSION_INFO; diff --git a/Spy/exec_sql.cpp b/Spy/exec_sql.cpp index 55cec26..4d82c22 100644 --- a/Spy/exec_sql.cpp +++ b/Spy/exec_sql.cpp @@ -7,6 +7,44 @@ using namespace std; +#define SQLITE_OK 0 /* Successful result */ +#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 */ + +#define SQLITE_INTEGER 1 +#define SQLITE_FLOAT 2 +#define SQLITE_TEXT 3 +#define SQLITE_BLOB 4 +#define SQLITE_NULL 5 + extern WxCalls_t g_WxCalls; extern DWORD g_WeChatWinDllAddr; @@ -23,6 +61,14 @@ typedef int(__cdecl *Sqlite3_exec)(DWORD, /* The database on which th void *, /* First argument to xCallback() */ char ** /* Write error messages here */ ); +typedef int(__cdecl *Sqlite3_prepare)(DWORD, const char *, int, DWORD **, int); +typedef int(__cdecl *Sqlite3_step)(DWORD *); +typedef int(__cdecl *Sqlite3_column_count)(DWORD *); +typedef const char *(__cdecl *Sqlite3_column_name)(DWORD *, int); +typedef int(__cdecl *Sqlite3_column_type)(DWORD *, int); +typedef const void *(__cdecl *Sqlite3_column_blob)(DWORD *, int); +typedef int(__cdecl *Sqlite3_column_bytes)(DWORD *, int); +typedef int(__cdecl *Sqlite3_finalize)(DWORD *); static int cbGetTables(void *ret, int argc, char **argv, char **azColName) { @@ -39,19 +85,33 @@ static int cbGetTables(void *ret, int argc, char **argv, char **azColName) return 0; } +dbMap_t GetDbHandles() +{ + if (!dbMap.empty()) + return dbMap; + + g_WeChatWinDllAddr = (DWORD)GetModuleHandle(L"WeChatWin.dll"); + DWORD sqlHandleBaseAddr = *(DWORD *)(g_WeChatWinDllAddr + g_WxCalls.sql.base); + DWORD sqlHandleBeginAddr = *(DWORD *)(sqlHandleBaseAddr + g_WxCalls.sql.start); + DWORD sqlHandleEndAddr = *(DWORD *)(sqlHandleBaseAddr + g_WxCalls.sql.end); + while (sqlHandleBeginAddr < sqlHandleEndAddr) { + DWORD dwHandle = *(DWORD *)sqlHandleBeginAddr; + wstring dbName = wstring((wchar_t *)(*(DWORD *)(dwHandle + g_WxCalls.sql.name))); + DWORD handle = *(DWORD *)(dwHandle + g_WxCalls.sql.slot); + if (handle) { + dbMap[dbName] = handle; + } + + sqlHandleBeginAddr += 0x04; + } + return dbMap; +} + vector GetDbNames() { vector vDbs; if (dbMap.empty()) { - DWORD sqlHandleBaseAddr = *(DWORD *)(g_WeChatWinDllAddr + g_WxCalls.sql.base); - DWORD sqlHandleBeginAddr = *(DWORD *)(sqlHandleBaseAddr + g_WxCalls.sql.start); - DWORD sqlHandleEndAddr = *(DWORD *)(sqlHandleBaseAddr + g_WxCalls.sql.end); - while (sqlHandleBeginAddr < sqlHandleEndAddr) { - DWORD dwHandle = *(DWORD *)sqlHandleBeginAddr; - dbMap[wstring((wchar_t *)(*(DWORD *)(dwHandle + g_WxCalls.sql.name)))] - = *(DWORD *)(dwHandle + g_WxCalls.sql.slot); - sqlHandleBeginAddr += 0x04; - } + dbMap = GetDbHandles(); } for (auto it = dbMap.begin(); it != dbMap.end(); it++) { vDbs.push_back(it->first); @@ -65,6 +125,10 @@ vector GetDbTables(wstring db) const char *sql = "select * from sqlite_master where type=\"table\";"; Sqlite3_exec p_Sqlite3_exec = (Sqlite3_exec)(g_WeChatWinDllAddr + g_WxCalls.sql.exec); + if (dbMap.empty()) { + dbMap = GetDbHandles(); + } + auto it = dbMap.find(db); if (it != dbMap.end()) { p_Sqlite3_exec(it->second, sql, (sqlite3_callback)cbGetTables, &vTables, 0); @@ -72,3 +136,48 @@ vector GetDbTables(wstring db) return vTables; } + +vector> ExecDbQuery(wstring db, wstring sql) +{ + vector> vvSqlResult; + + Sqlite3_prepare func_prepare = (Sqlite3_prepare)(g_WeChatWinDllAddr + 0x14227F0); + Sqlite3_step func_step = (Sqlite3_step)(g_WeChatWinDllAddr + 0x13EA780); + Sqlite3_column_count func_column_count = (Sqlite3_column_count)(g_WeChatWinDllAddr + 0x13EACD0); + Sqlite3_column_name func_column_name = (Sqlite3_column_name)(g_WeChatWinDllAddr + 0x13EB630); + Sqlite3_column_type func_column_type = (Sqlite3_column_type)(g_WeChatWinDllAddr + 0x13EB470); + Sqlite3_column_blob func_column_blob = (Sqlite3_column_blob)(g_WeChatWinDllAddr + 0x13EAD10); + Sqlite3_column_bytes func_column_bytes = (Sqlite3_column_bytes)(g_WeChatWinDllAddr + 0x13EADD0); + Sqlite3_finalize func_finalize = (Sqlite3_finalize)(g_WeChatWinDllAddr + 0x13E9730); + + if (dbMap.empty()) { + dbMap = GetDbHandles(); + } + + DWORD *stmt; + int rc = func_prepare(dbMap[db], Wstring2String(sql).c_str(), -1, &stmt, 0); + if (rc != SQLITE_OK) { + return vvSqlResult; + } + + wchar_t buffer[128] = { 0 }; + while (func_step(stmt) == SQLITE_ROW) { + vector vResult; + int col_count = func_column_count(stmt); + for (int i = 0; i < col_count; i++) { + RpcSqlResult_t result = { 0 }; + result.type = func_column_type(stmt, i); + result.column = GetBstrFromString(func_column_name(stmt, i)); + int length = func_column_bytes(stmt, i); + const void *blob = func_column_blob(stmt, i); + if (length && (result.type != 5)) { + result.content = GetBstrFromByteArray((byte *)blob, length); + } + + vResult.push_back(result); + } + vvSqlResult.push_back(vResult); + } + + return vvSqlResult; +} diff --git a/Spy/exec_sql.h b/Spy/exec_sql.h index 4b65d76..70b67fb 100644 --- a/Spy/exec_sql.h +++ b/Spy/exec_sql.h @@ -7,3 +7,4 @@ std::vector GetDbNames(); std::vector GetDbTables(std::wstring db); +std::vector> ExecDbQuery(std::wstring db, std::wstring sql); diff --git a/Spy/rpc_server.cpp b/Spy/rpc_server.cpp index fd773cf..1f70df7 100644 --- a/Spy/rpc_server.cpp +++ b/Spy/rpc_server.cpp @@ -22,6 +22,58 @@ extern const MsgTypesMap_t g_WxMsgTypes; // Map of WeChat Message types static BOOL listenMsgFlag = false; +RPC_STATUS CALLBACK SecurityCallback(RPC_IF_HANDLE /*hInterface*/, void * /*pBindingHandle*/) +{ + return RPC_S_OK; // Always allow anyone. +} + +int RpcStartServer() +{ + RPC_STATUS status; + // Uses the protocol combined with the endpoint for receiving + // remote procedure calls. + status = RpcServerUseProtseqEp(reinterpret_cast((RPC_WSTR)L"ncalrpc"), // Use TCP/IP protocol + RPC_C_LISTEN_MAX_CALLS_DEFAULT, // Backlog queue length for TCP/IP. + reinterpret_cast((RPC_WSTR)L"wcferry"), // TCP/IP port to use + NULL // No security + ); + + if (status) + return status; + + // Registers the interface and auto listen + // Equal to RpcServerRegisterIf + RpcServerListen + status = RpcServerRegisterIf2(server_ISpy_v1_0_s_ifspec, // Interface to register. + NULL, // Use the MIDL generated entry-point vector. + NULL, // Use the MIDL generated entry-point vector. + RPC_IF_ALLOW_LOCAL_ONLY | RPC_IF_AUTOLISTEN, // Forces use of security callback. + RPC_C_LISTEN_MAX_CALLS_DEFAULT, // Use default number of concurrent calls. + (unsigned)-1, // Infinite max size of incoming data blocks. + SecurityCallback); // Naive security callback. + + while (g_rpcKeepAlive) { + Sleep(1000); // 休眠,释放CPU + } + + return 0; +} + +int RpcStopServer() +{ + RPC_STATUS status; + + UnListenMessage(); + + listenMsgFlag = false; + g_rpcKeepAlive = false; + status = RpcMgmtStopServerListening(NULL); + if (status) + return status; + + status = RpcServerUnregisterIf(server_ISpy_v1_0_s_ifspec, NULL, 0); + return status; +} + int server_IsLogin() { return IsLogin(); } void server_EnableReceiveMsg() @@ -179,54 +231,49 @@ int server_GetDbTables(const wchar_t *db, int *pNum, PPRpcTables *tbls) return 0; } -RPC_STATUS CALLBACK SecurityCallback(RPC_IF_HANDLE /*hInterface*/, void * /*pBindingHandle*/) +int server_ExecDbQuery(const wchar_t *db, const wchar_t *sql, int *pRow, int *pCol, PPPRpcSqlResult *ret) { - return RPC_S_OK; // Always allow anyone. -} - -int RpcStartServer() -{ - RPC_STATUS status; - // Uses the protocol combined with the endpoint for receiving - // remote procedure calls. - status = RpcServerUseProtseqEp(reinterpret_cast((RPC_WSTR)L"ncalrpc"), // Use TCP/IP protocol - RPC_C_LISTEN_MAX_CALLS_DEFAULT, // Backlog queue length for TCP/IP. - reinterpret_cast((RPC_WSTR)L"wcferry"), // TCP/IP port to use - NULL // No security - ); - - if (status) - return status; - - // Registers the interface and auto listen - // Equal to RpcServerRegisterIf + RpcServerListen - status = RpcServerRegisterIf2(server_ISpy_v1_0_s_ifspec, // Interface to register. - NULL, // Use the MIDL generated entry-point vector. - NULL, // Use the MIDL generated entry-point vector. - RPC_IF_ALLOW_LOCAL_ONLY | RPC_IF_AUTOLISTEN, // Forces use of security callback. - RPC_C_LISTEN_MAX_CALLS_DEFAULT, // Use default number of concurrent calls. - (unsigned)-1, // Infinite max size of incoming data blocks. - SecurityCallback); // Naive security callback. - - while (g_rpcKeepAlive) { - Sleep(1000); // 休眠,释放CPU + vector> vvSqlResult = ExecDbQuery(db, sql); + if (vvSqlResult.empty()) { + *pRow = *pCol = 0; + ret = NULL; + return -1; } + *pRow = vvSqlResult.size(); + *pCol = vvSqlResult[0].size(); + PPPRpcSqlResult ppp = (PPPRpcSqlResult)midl_user_allocate(*pRow * sizeof(PPRpcSqlResult)); + if (ppp == NULL) { + printf("server_ExecDbQuery midl_user_allocate Failed for ppp\n"); + return -2; + } + + for (int r = 0; r < *pRow; r++) { + PPRpcSqlResult pp = (PPRpcSqlResult)midl_user_allocate(*pCol * sizeof(PRpcSqlResult)); + if (pp == NULL) { + midl_user_free(ppp); + printf("server_ExecDbQuery midl_user_allocate Failed for pp\n"); + return -2; + } + + for (int c = 0; c < *pCol; c++) { + PRpcSqlResult p = (PRpcSqlResult)midl_user_allocate(sizeof(RpcSqlResult_t)); + if (p == NULL) { + midl_user_free(pp); + printf("server_ExecDbQuery midl_user_allocate Failed for p\n"); + return -2; + } + + p->type = vvSqlResult[r][c].type; + p->column = vvSqlResult[r][c].column; + p->content = vvSqlResult[r][c].content; + + pp[c] = p; + } + + ppp[r] = pp; + } + + *ret = ppp; return 0; } - -int RpcStopServer() -{ - RPC_STATUS status; - - UnListenMessage(); - - listenMsgFlag = false; - g_rpcKeepAlive = false; - status = RpcMgmtStopServerListening(NULL); - if (status) - return status; - - status = RpcServerUnregisterIf(server_ISpy_v1_0_s_ifspec, NULL, 0); - return status; -}