Impl execute sql
This commit is contained in:
parent
9f4ad1fba0
commit
4e7592ca1b
53
App/App.cpp
53
App/App.cpp
@ -10,6 +10,10 @@
|
|||||||
等效为在属性,链接,输入中添加该依赖
|
等效为在属性,链接,输入中添加该依赖
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
typedef map<int, wstring> 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)
|
void printContacts(ContactMap_t contacts)
|
||||||
{
|
{
|
||||||
wprintf(L"contacts number: %ld\n", contacts.size());
|
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)
|
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);
|
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 content = L"这里填写消息内容";
|
||||||
wstring img_path = L"test.jpg";
|
wstring img_path = L"test.jpg";
|
||||||
|
|
||||||
_wsetlocale(LC_ALL, L"chs"); // 这是个大坑,不设置中文直接不见了。。。
|
setlocale(LC_ALL, "chs"); // 这是个大坑,不设置中文直接不见了。。。
|
||||||
|
|
||||||
wprintf(L"WxInitSDK: ");
|
wprintf(L"WxInitSDK: ");
|
||||||
status = WxInitSDK();
|
status = WxInitSDK();
|
||||||
@ -95,8 +139,13 @@ int main()
|
|||||||
Sleep(1000); // 等待1秒
|
Sleep(1000); // 等待1秒
|
||||||
|
|
||||||
// 测试获取数据库中的表
|
// 测试获取数据库中的表
|
||||||
auto vDbTables = WxGetDbTables(L"ChatMsg.db");
|
auto vDbTables = WxGetDbTables(L"MicroMsg.db");
|
||||||
printDbTables(vDbTables);
|
printDbTables(vDbTables);
|
||||||
|
Sleep(1000); // 等待1秒
|
||||||
|
|
||||||
|
// 测试执行 SQL
|
||||||
|
auto vvResults = WxExecDbQuery(L"MicroMsg.db", L"SELECT * FROM Contact LIMIT 1;");
|
||||||
|
printDbResults(vvResults);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
Sleep(10000); // 休眠,释放CPU
|
Sleep(10000); // 休眠,释放CPU
|
||||||
|
12
Rpc/rpc.idl
12
Rpc/rpc.idl
@ -46,6 +46,15 @@ interface ISpy
|
|||||||
typedef RpcTables_t *PRpcTables;
|
typedef RpcTables_t *PRpcTables;
|
||||||
typedef RpcTables_t **PPRpcTables;
|
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 IsLogin();
|
||||||
int SendTextMsg([ in, string ] const wchar_t *wxid, [ in, string ] const wchar_t *msg,
|
int SendTextMsg([ in, string ] const wchar_t *wxid, [ in, string ] const wchar_t *msg,
|
||||||
[ in, unique, string ] const wchar_t *atWxids);
|
[ 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 GetContacts([out] int *pNum, [ out, size_is(, *pNum) ] PPRpcContact *contacts);
|
||||||
int GetDbNames([out] int *pNum, [ out, size_is(, *pNum) ] BSTR **dbs);
|
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 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 EnableReceiveMsg();
|
||||||
void DisableReceiveMsg();
|
void DisableReceiveMsg();
|
||||||
|
@ -212,6 +212,27 @@ PPRpcTables RpcGetDbTables(const wchar_t *db, int *pNum)
|
|||||||
return ppRpcTables;
|
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)
|
int server_ReceiveMsg(RpcMessage_t rpcMsg)
|
||||||
{
|
{
|
||||||
WxMessage_t msg;
|
WxMessage_t msg;
|
||||||
|
@ -14,3 +14,4 @@ PPRpcIntBstrPair RpcGetMsgTypes(int *pNum);
|
|||||||
PPRpcContact RpcGetContacts(int *pNum);
|
PPRpcContact RpcGetContacts(int *pNum);
|
||||||
BSTR *RpcGetDbNames(int *pNum);
|
BSTR *RpcGetDbNames(int *pNum);
|
||||||
PPRpcTables RpcGetDbTables(const wchar_t *db, int *pNum);
|
PPRpcTables RpcGetDbTables(const wchar_t *db, int *pNum);
|
||||||
|
PPPRpcSqlResult RpcExecDbQuery(const wchar_t *db, const wchar_t *sql, int *row, int *col);
|
||||||
|
25
SDK/sdk.cpp
25
SDK/sdk.cpp
@ -237,3 +237,28 @@ DbTableVector_t WxGetDbTables(wstring db)
|
|||||||
|
|
||||||
return vTables;
|
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<vector<WxSqlResult_t>> vvResults;
|
||||||
|
for (int r = 0; r < row; r++) {
|
||||||
|
vector<WxSqlResult_t> 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;
|
||||||
|
}
|
||||||
|
@ -8,4 +8,5 @@
|
|||||||
WxSendImageMsg
|
WxSendImageMsg
|
||||||
WxGetContacts
|
WxGetContacts
|
||||||
WxGetDbNames
|
WxGetDbNames
|
||||||
WxGetDbTables
|
WxGetDbTables
|
||||||
|
WxExecDbQuery
|
||||||
|
@ -33,9 +33,16 @@ typedef struct WxDbTable {
|
|||||||
wstring sql; // 建表 SQL
|
wstring sql; // 建表 SQL
|
||||||
} WxDbTable_t;
|
} WxDbTable_t;
|
||||||
|
|
||||||
|
typedef struct WxSqlResult {
|
||||||
|
int type;
|
||||||
|
wstring column;
|
||||||
|
string content;
|
||||||
|
} WxSqlResult_t;
|
||||||
|
|
||||||
typedef map<int, wstring> MsgTypesMap_t;
|
typedef map<int, wstring> MsgTypesMap_t;
|
||||||
typedef map<wstring, WxContact_t> ContactMap_t;
|
typedef map<wstring, WxContact_t> ContactMap_t;
|
||||||
typedef vector<WxDbTable_t> DbTableVector_t;
|
typedef vector<WxDbTable_t> DbTableVector_t;
|
||||||
|
typedef vector<vector<WxSqlResult_t>> SqlRetVector_t;
|
||||||
|
|
||||||
int WxInitSDK();
|
int WxInitSDK();
|
||||||
int WxDestroySDK();
|
int WxDestroySDK();
|
||||||
@ -47,3 +54,4 @@ ContactMap_t WxGetContacts();
|
|||||||
MsgTypesMap_t WxGetMsgTypes();
|
MsgTypesMap_t WxGetMsgTypes();
|
||||||
vector<wstring> WxGetDbNames();
|
vector<wstring> WxGetDbNames();
|
||||||
DbTableVector_t WxGetDbTables(wstring db);
|
DbTableVector_t WxGetDbTables(wstring db);
|
||||||
|
SqlRetVector_t WxExecDbQuery(wstring db, wstring sql);
|
||||||
|
45
SDK/util.cpp
45
SDK/util.cpp
@ -1,5 +1,7 @@
|
|||||||
#include "Shlwapi.h"
|
#include "Shlwapi.h"
|
||||||
#include "framework.h"
|
#include "framework.h"
|
||||||
|
#include <codecvt>
|
||||||
|
#include <locale>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <strsafe.h>
|
#include <strsafe.h>
|
||||||
#include <tlhelp32.h>
|
#include <tlhelp32.h>
|
||||||
@ -12,6 +14,11 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
static wstring_convert<codecvt_utf8<wchar_t>, 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)
|
static int GetWeChatPath(wchar_t *path)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
@ -221,6 +228,44 @@ BSTR GetBstrFromWstring(wstring ws)
|
|||||||
return NULL;
|
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)
|
void GetRpcMessage(WxMessage_t *wxMsg, RpcMessage_t rpcMsg)
|
||||||
{
|
{
|
||||||
wxMsg->self = rpcMsg.self;
|
wxMsg->self = rpcMsg.self;
|
||||||
|
@ -17,10 +17,15 @@
|
|||||||
int OpenWeChat(DWORD *pid);
|
int OpenWeChat(DWORD *pid);
|
||||||
int GetWeChatVersion(wchar_t *version);
|
int GetWeChatVersion(wchar_t *version);
|
||||||
int GetWstringByAddress(DWORD address, wchar_t *buffer, DWORD buffer_size);
|
int GetWstringByAddress(DWORD address, wchar_t *buffer, DWORD buffer_size);
|
||||||
BSTR GetBstrByAddress(DWORD address);
|
|
||||||
void GetRpcMessage(WxMessage_t *wxMsg, RpcMessage_t rpcMsg);
|
void GetRpcMessage(WxMessage_t *wxMsg, RpcMessage_t rpcMsg);
|
||||||
DWORD GetMemoryIntByAddress(HANDLE hProcess, DWORD address);
|
DWORD GetMemoryIntByAddress(HANDLE hProcess, DWORD address);
|
||||||
std::wstring GetWstringFromBstr(BSTR p);
|
BSTR GetBstrByAddress(DWORD address);
|
||||||
BSTR GetBstrFromString(const char *str);
|
BSTR GetBstrFromString(const char *str);
|
||||||
BSTR GetBstrFromWstring(std::wstring ws);
|
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 GetUnicodeInfoByAddress(HANDLE hProcess, DWORD address);
|
||||||
|
std::wstring String2Wstring(std::string s);
|
||||||
|
std::string Wstring2String(std::wstring ws);
|
||||||
|
@ -157,9 +157,11 @@
|
|||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\SDK\sdk.h" />
|
<ClInclude Include="..\SDK\sdk.h" />
|
||||||
|
<ClInclude Include="..\SDK\util.h" />
|
||||||
<ClInclude Include="framework.h" />
|
<ClInclude Include="framework.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\SDK\util.cpp" />
|
||||||
<ClCompile Include="sdkpy.cpp" />
|
<ClCompile Include="sdkpy.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
@ -21,10 +21,16 @@
|
|||||||
<ClInclude Include="..\SDK\sdk.h">
|
<ClInclude Include="..\SDK\sdk.h">
|
||||||
<Filter>头文件</Filter>
|
<Filter>头文件</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\SDK\util.h">
|
||||||
|
<Filter>头文件</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="sdkpy.cpp">
|
<ClCompile Include="sdkpy.cpp">
|
||||||
<Filter>源文件</Filter>
|
<Filter>源文件</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\SDK\util.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -1,12 +1,48 @@
|
|||||||
#include <pybind11/functional.h>
|
#include <pybind11/functional.h>
|
||||||
#include <pybind11/pybind11.h>
|
#include <pybind11/pybind11.h>
|
||||||
#include <pybind11/stl.h>
|
#include <pybind11/stl.h>
|
||||||
|
|
||||||
#include "sdk.h"
|
#include "sdk.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
namespace py = pybind11;
|
namespace py = pybind11;
|
||||||
|
|
||||||
int WxEnableRecvMsgPy(const std::function<int(WxMessage_t)>& onMsg) { return WxEnableRecvMsg(onMsg); }
|
int WxEnableRecvMsgPy(const std::function<int(WxMessage_t)> &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)
|
PYBIND11_MODULE(wcferry, m)
|
||||||
{
|
{
|
||||||
@ -29,21 +65,22 @@ PYBIND11_MODULE(wcferry, m)
|
|||||||
.def_readonly("wxCountry", &WxContact::wxCountry)
|
.def_readonly("wxCountry", &WxContact::wxCountry)
|
||||||
.def_readonly("wxProvince", &WxContact::wxProvince)
|
.def_readonly("wxProvince", &WxContact::wxProvince)
|
||||||
.def_readonly("wxCity", &WxContact::wxCity)
|
.def_readonly("wxCity", &WxContact::wxCity)
|
||||||
.def_readonly("wxGender", &WxContact::wxGender);
|
.def_readonly("wxGender", &WxContact::wxGender);
|
||||||
|
|
||||||
py::class_<WxDbTable>(m, "WxDbTable")
|
py::class_<WxDbTable>(m, "WxDbTable").def_readonly("table", &WxDbTable::table).def_readonly("sql", &WxDbTable::sql);
|
||||||
.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("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("WxEnableRecvMsg", &WxEnableRecvMsgPy, "Enable message receiving and provide a callback", py::arg("onMsg"));
|
||||||
m.def("WxDisableRecvMsg", &WxDisableRecvMsg, "Disable message receiving.");
|
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("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("WxGetContacts", &WxGetContacts, py::return_value_policy::reference, "Get contact list.");
|
||||||
m.def("WxGetMsgTypes", &WxGetMsgTypes, py::return_value_policy::reference, "Get message types.");
|
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("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("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
|
#ifdef VERSION_INFO
|
||||||
m.attr("__version__") = VERSION_INFO;
|
m.attr("__version__") = VERSION_INFO;
|
||||||
|
127
Spy/exec_sql.cpp
127
Spy/exec_sql.cpp
@ -7,6 +7,44 @@
|
|||||||
|
|
||||||
using namespace std;
|
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 WxCalls_t g_WxCalls;
|
||||||
extern DWORD g_WeChatWinDllAddr;
|
extern DWORD g_WeChatWinDllAddr;
|
||||||
|
|
||||||
@ -23,6 +61,14 @@ typedef int(__cdecl *Sqlite3_exec)(DWORD, /* The database on which th
|
|||||||
void *, /* First argument to xCallback() */
|
void *, /* First argument to xCallback() */
|
||||||
char ** /* Write error messages here */
|
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)
|
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;
|
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<wstring> GetDbNames()
|
vector<wstring> GetDbNames()
|
||||||
{
|
{
|
||||||
vector<wstring> vDbs;
|
vector<wstring> vDbs;
|
||||||
if (dbMap.empty()) {
|
if (dbMap.empty()) {
|
||||||
DWORD sqlHandleBaseAddr = *(DWORD *)(g_WeChatWinDllAddr + g_WxCalls.sql.base);
|
dbMap = GetDbHandles();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for (auto it = dbMap.begin(); it != dbMap.end(); it++) {
|
for (auto it = dbMap.begin(); it != dbMap.end(); it++) {
|
||||||
vDbs.push_back(it->first);
|
vDbs.push_back(it->first);
|
||||||
@ -65,6 +125,10 @@ vector<RpcTables_t> GetDbTables(wstring db)
|
|||||||
const char *sql = "select * from sqlite_master where type=\"table\";";
|
const char *sql = "select * from sqlite_master where type=\"table\";";
|
||||||
Sqlite3_exec p_Sqlite3_exec = (Sqlite3_exec)(g_WeChatWinDllAddr + g_WxCalls.sql.exec);
|
Sqlite3_exec p_Sqlite3_exec = (Sqlite3_exec)(g_WeChatWinDllAddr + g_WxCalls.sql.exec);
|
||||||
|
|
||||||
|
if (dbMap.empty()) {
|
||||||
|
dbMap = GetDbHandles();
|
||||||
|
}
|
||||||
|
|
||||||
auto it = dbMap.find(db);
|
auto it = dbMap.find(db);
|
||||||
if (it != dbMap.end()) {
|
if (it != dbMap.end()) {
|
||||||
p_Sqlite3_exec(it->second, sql, (sqlite3_callback)cbGetTables, &vTables, 0);
|
p_Sqlite3_exec(it->second, sql, (sqlite3_callback)cbGetTables, &vTables, 0);
|
||||||
@ -72,3 +136,48 @@ vector<RpcTables_t> GetDbTables(wstring db)
|
|||||||
|
|
||||||
return vTables;
|
return vTables;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vector<vector<RpcSqlResult_t>> ExecDbQuery(wstring db, wstring sql)
|
||||||
|
{
|
||||||
|
vector<vector<RpcSqlResult_t>> 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<RpcSqlResult_t> 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;
|
||||||
|
}
|
||||||
|
@ -7,3 +7,4 @@
|
|||||||
|
|
||||||
std::vector<std::wstring> GetDbNames();
|
std::vector<std::wstring> GetDbNames();
|
||||||
std::vector<RpcTables_t> GetDbTables(std::wstring db);
|
std::vector<RpcTables_t> GetDbTables(std::wstring db);
|
||||||
|
std::vector<std::vector<RpcSqlResult_t>> ExecDbQuery(std::wstring db, std::wstring sql);
|
||||||
|
@ -22,6 +22,58 @@ extern const MsgTypesMap_t g_WxMsgTypes; // Map of WeChat Message types
|
|||||||
|
|
||||||
static BOOL listenMsgFlag = false;
|
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>((RPC_WSTR)L"ncalrpc"), // Use TCP/IP protocol
|
||||||
|
RPC_C_LISTEN_MAX_CALLS_DEFAULT, // Backlog queue length for TCP/IP.
|
||||||
|
reinterpret_cast<RPC_WSTR>((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(); }
|
int server_IsLogin() { return IsLogin(); }
|
||||||
|
|
||||||
void server_EnableReceiveMsg()
|
void server_EnableReceiveMsg()
|
||||||
@ -179,54 +231,49 @@ int server_GetDbTables(const wchar_t *db, int *pNum, PPRpcTables *tbls)
|
|||||||
return 0;
|
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.
|
vector<vector<RpcSqlResult_t>> vvSqlResult = ExecDbQuery(db, sql);
|
||||||
}
|
if (vvSqlResult.empty()) {
|
||||||
|
*pRow = *pCol = 0;
|
||||||
int RpcStartServer()
|
ret = NULL;
|
||||||
{
|
return -1;
|
||||||
RPC_STATUS status;
|
|
||||||
// Uses the protocol combined with the endpoint for receiving
|
|
||||||
// remote procedure calls.
|
|
||||||
status = RpcServerUseProtseqEp(reinterpret_cast<RPC_WSTR>((RPC_WSTR)L"ncalrpc"), // Use TCP/IP protocol
|
|
||||||
RPC_C_LISTEN_MAX_CALLS_DEFAULT, // Backlog queue length for TCP/IP.
|
|
||||||
reinterpret_cast<RPC_WSTR>((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
|
|
||||||
}
|
}
|
||||||
|
*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;
|
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;
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user