提交 c3c6a810 编写于 作者: L ljc545w

添加数据库相关接口

上级 46f1c29b
......@@ -11,3 +11,4 @@
*/obj/
/wxRobot/bin/Debug/
/wxRobot/bin/Release/*.pdb
*/__pycache__/
#include "pch.h"
// DLLӿʱIJ
struct BackupParams {
DWORD ptrDb;
DWORD savepath;
};
BOOL BackupSQLiteDB(DWORD DbHandle, BSTR savepath) {
if (!hProcess)
return 0;
DWORD dwHandle = 0x0;
DWORD dwId = 0x0;
DWORD dwWriteSize = 0x0;
LPVOID savepathAddr = VirtualAllocEx(hProcess, NULL, 1, MEM_COMMIT, PAGE_READWRITE);
BackupParams* paramAndFunc = (BackupParams*)::VirtualAllocEx(hProcess, 0, sizeof(BackupParams), MEM_COMMIT, PAGE_READWRITE);
if (!savepathAddr || !paramAndFunc)
return 0;
char* a_savepath = _com_util::ConvertBSTRToString(savepath);
if (savepathAddr)
WriteProcessMemory(hProcess, savepathAddr, a_savepath, strlen(a_savepath) + 1, &dwWriteSize);
BackupParams param = { 0 };
param.ptrDb = DbHandle;
param.savepath = (DWORD)savepathAddr;
if (paramAndFunc)
WriteProcessMemory(hProcess, paramAndFunc, &param, sizeof(BackupParams), &dwWriteSize);
DWORD BackupSQLiteDBRemoteAddr = GetWeChatRobotBase() + BackupSQLiteDBRemoteOffset;
HANDLE hThread = ::CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)BackupSQLiteDBRemoteAddr, (LPVOID)paramAndFunc, 0, &dwId);
if (hThread) {
WaitForSingleObject(hThread, INFINITE);
GetExitCodeThread(hThread, &dwHandle);
CloseHandle(hThread);
}
else {
return 0;
}
VirtualFreeEx(hProcess, savepathAddr, 0, MEM_RELEASE);
VirtualFreeEx(hProcess, paramAndFunc, 0, MEM_RELEASE);
return dwHandle == 1;
}
\ No newline at end of file
#pragma once
#include<windows.h>
BOOL BackupSQLiteDB(DWORD DbHandle, BSTR savepath);
\ No newline at end of file
#include "pch.h"
// 调用DLL接口时的参数
struct executeParams {
DWORD ptrDb;
DWORD ptrSql;
};
// 接收DLL的返回数据,包括动态数组首地址和数组长度
struct executeResult {
DWORD SQLResultData;
DWORD length;
};
// 保存ReadProcessMemory读出的结构体
struct SQLResultAddrStruct {
DWORD ColName;
DWORD l_ColName;
DWORD content;
DWORD l_content;
};
// vector的数据结构
struct VectorStruct {
#ifdef _DEBUG
DWORD v_head;
#endif
DWORD v_data;
DWORD v_end1;
DWORD v_end2;
};
// 保存SQL查询结构的基础结构
struct SQLResultStruct {
wchar_t* ColName;
wchar_t* content;
};
// 查询结果是一个二维数组
vector<vector<SQLResultStruct>> SQLResult;
// 每次查询前清空前一次查询到的结果
void ClearResultArray() {
if (SQLResult.size() == 0)
return;
for (unsigned int i = 0; i < SQLResult.size(); i++) {
for (unsigned j = 0; j < SQLResult[i].size(); j++) {
SQLResultStruct* sr = (SQLResultStruct*)&SQLResult[i][j];
if (sr->ColName) {
delete sr->ColName;
sr->ColName = NULL;
}
if (sr->content) {
delete sr->content;
sr->content = NULL;
}
}
SQLResult[i].clear();
}
SQLResult.clear();
}
// 遍历查询结果,构造SAFEARRAY
SAFEARRAY* CreateSQLResultSafeArray() {
if (SQLResult.size() == 0 || SQLResult[0].size() == 0)
return NULL;
SAFEARRAYBOUND rgsaBound[2] = { {SQLResult.size() + 1,0},{SQLResult[0].size(),0}};
SAFEARRAY* psaValue = SafeArrayCreate(VT_VARIANT, 2, rgsaBound);
HRESULT hr = S_OK;
long Index[2] = { 0,0 };
for (unsigned int i = 0; i < SQLResult.size(); i++) {
for (unsigned int j = 0; j < SQLResult[i].size(); j++) {
SQLResultStruct* ptrResult = (SQLResultStruct*)&SQLResult[i][j];
if (i == 0)
{
Index[0] = 0; Index[1] = j;
hr = SafeArrayPutElement(psaValue, Index, &(_variant_t)ptrResult->ColName);
}
Index[0] = i + 1; Index[1] = j;
hr = SafeArrayPutElement(psaValue, Index, &(_variant_t)ptrResult->content);
}
}
return psaValue;
}
// 读出查询结果
VOID ReadSQLResultFromWeChatProcess(DWORD dwHandle) {
executeResult result = { 0 };
ReadProcessMemory(hProcess, (LPCVOID)dwHandle, &result, sizeof(executeResult), 0);
for (unsigned int i = 0; i < result.length; i++) {
VectorStruct v_temp = { 0 };
vector<SQLResultStruct> s_temp;
ReadProcessMemory(hProcess, (LPCVOID)result.SQLResultData, &v_temp, sizeof(VectorStruct), 0);
while (v_temp.v_data < v_temp.v_end1) {
SQLResultAddrStruct sqlresultAddr = { 0 };
SQLResultStruct sqlresult = { 0 };
ReadProcessMemory(hProcess, (LPCVOID)v_temp.v_data, &sqlresultAddr, sizeof(SQLResultAddrStruct), 0);
char* ColName = new char[sqlresultAddr.l_ColName + 1];
sqlresult.ColName = new wchar_t[sqlresultAddr.l_ColName + 1];
ReadProcessMemory(hProcess, (LPCVOID)sqlresultAddr.ColName, ColName, sqlresultAddr.l_ColName + 1, 0);
MultiByteToWideChar(CP_ACP,0,ColName,-1,sqlresult.ColName,strlen(ColName) + 1);
char* content = new char[sqlresultAddr.l_content + 1];
sqlresult.content = new wchar_t[sqlresultAddr.l_content + 1];
ReadProcessMemory(hProcess, (LPCVOID)sqlresultAddr.content, content, sqlresultAddr.l_content + 1, 0);
MultiByteToWideChar(CP_UTF8, 0, content, -1, sqlresult.content, strlen(content) + 1);
delete[] ColName;
ColName = NULL;
delete[] content;
content = NULL;
v_temp.v_data += sizeof(SQLResultAddrStruct);
s_temp.push_back(sqlresult);
}
SQLResult.push_back(s_temp);
result.SQLResultData += sizeof(VectorStruct);
}
}
SAFEARRAY* ExecuteSQL(DWORD DbHandle,BSTR sql) {
if (!hProcess)
return NULL;
ClearResultArray();
DWORD dwHandle = 0x0;
DWORD dwId = 0x0;
DWORD dwWriteSize = 0x0;
LPVOID sqlAddr = VirtualAllocEx(hProcess, NULL, 1, MEM_COMMIT, PAGE_READWRITE);
executeParams* paramAndFunc = (executeParams*)::VirtualAllocEx(hProcess, 0, sizeof(executeParams), MEM_COMMIT, PAGE_READWRITE);
if (!sqlAddr || !paramAndFunc)
return NULL;
char* a_sql = _com_util::ConvertBSTRToString(sql);
if(sqlAddr)
WriteProcessMemory(hProcess, sqlAddr, a_sql, strlen(a_sql) + 1, &dwWriteSize);
executeParams param = { 0 };
param.ptrDb = DbHandle;
param.ptrSql = (DWORD)sqlAddr;
if(paramAndFunc)
WriteProcessMemory(hProcess, paramAndFunc, &param, sizeof(executeParams), &dwWriteSize);
DWORD ExecuteSQLRemoteAddr = GetWeChatRobotBase() + ExecuteSQLRemoteOffset;
HANDLE hThread = ::CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)ExecuteSQLRemoteAddr, (LPVOID)paramAndFunc, 0, &dwId);
if (hThread) {
WaitForSingleObject(hThread, INFINITE);
GetExitCodeThread(hThread, &dwHandle);
CloseHandle(hThread);
}
else {
return NULL;
}
if (!dwHandle)
return NULL;
ReadSQLResultFromWeChatProcess(dwHandle);
SAFEARRAY* psaValue = CreateSQLResultSafeArray();
VirtualFreeEx(hProcess, sqlAddr, 0, MEM_RELEASE);
VirtualFreeEx(hProcess, paramAndFunc, 0, MEM_RELEASE);
return psaValue;
}
\ No newline at end of file
#pragma once
#include<windows.h>
SAFEARRAY* ExecuteSQL(DWORD DbHandle, BSTR sql);
\ No newline at end of file
#include "pch.h"
struct TableInfoAddrStruct {
DWORD name;
DWORD l_name;
DWORD tbl_name;
DWORD l_tbl_name;
DWORD sql;
DWORD l_sql;
DWORD rootpage;
DWORD l_rootpage;
};
struct DbInfoAddrStruct {
DWORD handle;
DWORD dbname;
DWORD l_dbname;
// vectorݽṹ
#ifdef _DEBUG
DWORD v_head;
#endif
DWORD v_data;
DWORD v_end1;
DWORD v_end2;
//
DWORD count;
};
struct TableInfoStruct {
char* name;
char* tbl_name;
char* sql;
char* rootpage;
};
struct DbInfoStruct {
DWORD handle;
wchar_t* dbname;
vector<TableInfoStruct> tables;
DWORD count;
};
vector<DbInfoStruct> dbs;
SAFEARRAY* CreateDbInfoSafeArray() {
SAFEARRAY* psaValue;
ULONG count = 0;
HRESULT hr = S_OK;
for (unsigned int i = 0; i < dbs.size(); i++) {
count += dbs[i].count;
}
SAFEARRAYBOUND rgsaBound[3] = { {count,0},{6,0},{2,0} };
psaValue = SafeArrayCreate(VT_VARIANT, 3, rgsaBound);
long index = 0;
for (unsigned int i = 0; i < dbs.size(); i++) {
for (unsigned int j = 0; j < dbs[i].tables.size(); j++) {
LONG ArrayIndex[3] = { index,0,0 };
ArrayIndex[1] = 0; ArrayIndex[2] = { 0 };
hr = SafeArrayPutElement(psaValue, ArrayIndex, &(_variant_t)L"dbname");
ArrayIndex[1] = 0; ArrayIndex[2] = { 1 };
hr = SafeArrayPutElement(psaValue, ArrayIndex, &(_variant_t)dbs[i].dbname);
ArrayIndex[1] = 1; ArrayIndex[2] = { 0 };
hr = SafeArrayPutElement(psaValue, ArrayIndex, &(_variant_t)L"Handle");
ArrayIndex[1] = 1; ArrayIndex[2] = { 1 };
hr = SafeArrayPutElement(psaValue, ArrayIndex, &(_variant_t)dbs[i].handle);
ArrayIndex[1] = 2; ArrayIndex[2] = { 0 };
hr = SafeArrayPutElement(psaValue, ArrayIndex, &(_variant_t)L"name");
ArrayIndex[1] = 2; ArrayIndex[2] = { 1 };
hr = SafeArrayPutElement(psaValue, ArrayIndex, &(_variant_t)dbs[i].tables[j].name);
ArrayIndex[1] = 3; ArrayIndex[2] = { 0 };
hr = SafeArrayPutElement(psaValue, ArrayIndex, &(_variant_t)L"tbl_name");
ArrayIndex[1] = 3; ArrayIndex[2] = { 1 };
hr = SafeArrayPutElement(psaValue, ArrayIndex, &(_variant_t)dbs[i].tables[j].tbl_name);
ArrayIndex[1] = 4; ArrayIndex[2] = { 0 };
hr = SafeArrayPutElement(psaValue, ArrayIndex, &(_variant_t)L"rootpage");
ArrayIndex[1] = 4; ArrayIndex[2] = { 1 };
hr = SafeArrayPutElement(psaValue, ArrayIndex, &(_variant_t)dbs[i].tables[j].rootpage);
ArrayIndex[1] = 5; ArrayIndex[2] = { 0 };
hr = SafeArrayPutElement(psaValue, ArrayIndex, &(_variant_t)L"sql");
ArrayIndex[1] = 5; ArrayIndex[2] = { 1 };
hr = SafeArrayPutElement(psaValue, ArrayIndex, &(_variant_t)dbs[i].tables[j].sql);
index++;
}
}
return psaValue;
}
SAFEARRAY* GetDbHandles() {
if (!hProcess)
return NULL;
DWORD dwHandle = 0x0;
DWORD dwId = 0x0;
DWORD GetDbHandlesRemoteAddr = GetWeChatRobotBase() + GetDbHandlesRemoteOffset;
HANDLE hThread = ::CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)GetDbHandlesRemoteAddr, NULL, 0, &dwId);
if (hThread) {
WaitForSingleObject(hThread, INFINITE);
GetExitCodeThread(hThread, &dwHandle);
CloseHandle(hThread);
}
else {
return NULL;
}
if (!dwHandle)
return NULL;
while (1) {
DbInfoAddrStruct dbaddr = { 0 };
ReadProcessMemory(hProcess, (LPCVOID)dwHandle, &dbaddr, sizeof(DbInfoAddrStruct), 0);
if (dbaddr.handle == 0)
break;
DbInfoStruct db = { 0 };
db.handle = dbaddr.handle;
db.count = dbaddr.count;
db.dbname = new wchar_t[dbaddr.l_dbname + 1];
ReadProcessMemory(hProcess, (LPCVOID)dbaddr.dbname, db.dbname, sizeof(wchar_t) * (dbaddr.l_dbname + 1), 0);
DWORD db_table_start_addr = dbaddr.v_data;
while (db_table_start_addr < dbaddr.v_end1) {
TableInfoAddrStruct tbaddr = { 0 };
TableInfoStruct tb = { 0 };
ReadProcessMemory(hProcess, (LPCVOID)db_table_start_addr, &tbaddr, sizeof(TableInfoAddrStruct), 0);
tb.name = new char[tbaddr.l_name + 1];
ReadProcessMemory(hProcess, (LPCVOID)tbaddr.name, tb.name, tbaddr.l_name + 1, 0);
tb.tbl_name = new char[tbaddr.l_tbl_name + 1];
ReadProcessMemory(hProcess, (LPCVOID)tbaddr.tbl_name, tb.tbl_name, tbaddr.l_tbl_name + 1, 0);
tb.rootpage = new char[tbaddr.l_rootpage + 1];
ReadProcessMemory(hProcess, (LPCVOID)tbaddr.rootpage, tb.rootpage, tbaddr.l_rootpage + 1, 0);
tb.sql = new char[tbaddr.l_sql + 1];
ReadProcessMemory(hProcess, (LPCVOID)tbaddr.sql, tb.sql, tbaddr.l_sql + 1, 0);
db.tables.push_back(tb);
db_table_start_addr += sizeof(TableInfoAddrStruct);
}
dbs.push_back(db);
dwHandle += sizeof(DbInfoAddrStruct);
}
SAFEARRAY* psaValue = CreateDbInfoSafeArray();
return psaValue;
}
\ No newline at end of file
#pragma once
#include <windows.h>
SAFEARRAY* GetDbHandles();
\ No newline at end of file
......@@ -205,4 +205,39 @@ STDMETHODIMP CWeChatRobot::CGetChatRoomMembers(BSTR chatroomid,VARIANT* __result
V_ARRAY(&vsaValue) = GetChatRoomMembers(chatroomid);
*__result = vsaValue;
return S_OK;
}
/*
* 参数1:预返回的值,调用时无需提供
*/
STDMETHODIMP CWeChatRobot::CGetDbHandles(VARIANT* __result) {
VARIANT vsaValue;
vsaValue.vt = VT_ARRAY | VT_VARIANT;
V_ARRAY(&vsaValue) = GetDbHandles();
*__result = vsaValue;
return S_OK;
}
/*
* 参数1:数据库句柄
* 参数2:要执行的SQL语句
* 参数3:预返回的值,调用时无需提供
*/
STDMETHODIMP CWeChatRobot::CExecuteSQL(DWORD DbHandle,BSTR sql,VARIANT* __result) {
VARIANT vsaValue;
vsaValue.vt = VT_ARRAY | VT_VARIANT;
vsaValue.intVal = 0;
V_ARRAY(&vsaValue) = ExecuteSQL(DbHandle, sql);
*__result = vsaValue;
return S_OK;
}
/*
* 参数1:数据库句柄
* 参数2:备份保存路径
* 参数3:预返回的值,调用时无需提供
*/
STDMETHODIMP CWeChatRobot::CBackupSQLiteDB(DWORD DbHandle, BSTR savepath, int* __result) {
*__result = BackupSQLiteDB(DbHandle, savepath);
return S_OK;
}
\ No newline at end of file
......@@ -71,6 +71,9 @@ public:
STDMETHODIMP CReceiveMessage(VARIANT* __result);
STDMETHODIMP CStopReceiveMessage(int* __result);
STDMETHODIMP CGetChatRoomMembers(BSTR chatroomid, VARIANT* __result);
STDMETHODIMP CGetDbHandles(VARIANT* __result);
STDMETHODIMP CExecuteSQL(DWORD DbHandle, BSTR sql, VARIANT* __result);
STDMETHODIMP CBackupSQLiteDB(DWORD DbHandle, BSTR savepath, int* __result);
};
OBJECT_ENTRY_AUTO(__uuidof(WeChatRobot), CWeChatRobot)
......@@ -36,6 +36,9 @@ interface IWeChatRobot : IDispatch
[id(18)] HRESULT CStopReceiveMessage([out, retval] int* __result);
[id(19)] HRESULT CSendAtText([in] BSTR chatroomid, [in] VARIANT* wxid, [in] BSTR wxmsg, [out, retval] int* __result);
[id(20)] HRESULT CGetChatRoomMembers([in] BSTR chatroomid, [out, retval] VARIANT* __result);
[id(21)] HRESULT CGetDbHandles([out, retval] VARIANT* __result);
[id(22)] HRESULT CExecuteSQL([in] DWORD DbHandle, [in] BSTR sql, [out, retval] VARIANT* __result);
[id(23)] HRESULT CBackupSQLiteDB([in] DWORD DbHandle, [in] BSTR savepath, [out, retval] int* __result);
};
[
uuid(721abb35-141a-4aa2-94f2-762e2833fa6c),
......
......@@ -212,9 +212,12 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="CheckFriendStatus.h" />
<ClInclude Include="DbBackup.h" />
<ClInclude Include="DbExecuteSql.h" />
<ClInclude Include="framework.h" />
<ClInclude Include="FriendList.h" />
<ClInclude Include="GetChatRoomMembers.h" />
<ClInclude Include="GetDbHandles.h" />
<ClInclude Include="InjertDll.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="ReceiveMessage.h" />
......@@ -235,8 +238,11 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="CheckFriendStatus.cpp" />
<ClCompile Include="DbBackup.cpp" />
<ClCompile Include="DbExecuteSql.cpp" />
<ClCompile Include="FriendList.cpp" />
<ClCompile Include="GetChatRoomMembers.cpp" />
<ClCompile Include="GetDbHandles.cpp" />
<ClCompile Include="InjertDll.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
......
......@@ -65,6 +65,18 @@
<Filter Include="群相关\获取群成员">
<UniqueIdentifier>{dce4ab67-7d14-41b1-8e89-cbf9a8315a3a}</UniqueIdentifier>
</Filter>
<Filter Include="数据库">
<UniqueIdentifier>{c41b73aa-9ccc-4cfe-88e5-6b2849fa1fae}</UniqueIdentifier>
</Filter>
<Filter Include="数据库\获取句柄">
<UniqueIdentifier>{117e40dc-e3d0-41b7-a215-50e974b3adb0}</UniqueIdentifier>
</Filter>
<Filter Include="数据库\执行SQL">
<UniqueIdentifier>{c619874d-ac89-42cc-b12b-c64662f4951e}</UniqueIdentifier>
</Filter>
<Filter Include="数据库\数据库备份">
<UniqueIdentifier>{f34f7c72-a310-4c23-b153-681307fb6277}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="framework.h">
......@@ -130,6 +142,15 @@
<ClInclude Include="GetChatRoomMembers.h">
<Filter>群相关\获取群成员</Filter>
</ClInclude>
<ClInclude Include="GetDbHandles.h">
<Filter>数据库\获取句柄</Filter>
</ClInclude>
<ClInclude Include="DbExecuteSql.h">
<Filter>数据库\执行SQL</Filter>
</ClInclude>
<ClInclude Include="DbBackup.h">
<Filter>数据库\数据库备份</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="WeChatRobotCOM.cpp">
......@@ -186,6 +207,15 @@
<ClCompile Include="GetChatRoomMembers.cpp">
<Filter>群相关\获取群成员</Filter>
</ClCompile>
<ClCompile Include="GetDbHandles.cpp">
<Filter>数据库\获取句柄</Filter>
</ClCompile>
<ClCompile Include="DbExecuteSql.cpp">
<Filter>数据库\执行SQL</Filter>
</ClCompile>
<ClCompile Include="DbBackup.cpp">
<Filter>数据库\数据库备份</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="WeChatRobotCOM.rc">
......
......@@ -167,6 +167,19 @@ EXTERN_C const IID IID_IWeChatRobot;
/* [in] */ BSTR chatroomid,
/* [retval][out] */ VARIANT *__result) = 0;
virtual /* [id] */ HRESULT STDMETHODCALLTYPE CGetDbHandles(
/* [retval][out] */ VARIANT *__result) = 0;
virtual /* [id] */ HRESULT STDMETHODCALLTYPE CExecuteSQL(
/* [in] */ DWORD DbHandle,
/* [in] */ BSTR sql,
/* [retval][out] */ VARIANT *__result) = 0;
virtual /* [id] */ HRESULT STDMETHODCALLTYPE CBackupSQLiteDB(
/* [in] */ DWORD DbHandle,
/* [in] */ BSTR savepath,
/* [retval][out] */ int *__result) = 0;
};
......@@ -324,6 +337,22 @@ EXTERN_C const IID IID_IWeChatRobot;
/* [in] */ BSTR chatroomid,
/* [retval][out] */ VARIANT *__result);
/* [id] */ HRESULT ( STDMETHODCALLTYPE *CGetDbHandles )(
IWeChatRobot * This,
/* [retval][out] */ VARIANT *__result);
/* [id] */ HRESULT ( STDMETHODCALLTYPE *CExecuteSQL )(
IWeChatRobot * This,
/* [in] */ DWORD DbHandle,
/* [in] */ BSTR sql,
/* [retval][out] */ VARIANT *__result);
/* [id] */ HRESULT ( STDMETHODCALLTYPE *CBackupSQLiteDB )(
IWeChatRobot * This,
/* [in] */ DWORD DbHandle,
/* [in] */ BSTR savepath,
/* [retval][out] */ int *__result);
END_INTERFACE
} IWeChatRobotVtbl;
......@@ -420,6 +449,15 @@ EXTERN_C const IID IID_IWeChatRobot;
#define IWeChatRobot_CGetChatRoomMembers(This,chatroomid,__result) \
( (This)->lpVtbl -> CGetChatRoomMembers(This,chatroomid,__result) )
#define IWeChatRobot_CGetDbHandles(This,__result) \
( (This)->lpVtbl -> CGetDbHandles(This,__result) )
#define IWeChatRobot_CExecuteSQL(This,DbHandle,sql,__result) \
( (This)->lpVtbl -> CExecuteSQL(This,DbHandle,sql,__result) )
#define IWeChatRobot_CBackupSQLiteDB(This,DbHandle,savepath,__result) \
( (This)->lpVtbl -> CBackupSQLiteDB(This,DbHandle,savepath,__result) )
#endif /* COBJMACROS */
......
......@@ -49,7 +49,7 @@
#include "WeChatRobotCOM_i.h"
#define TYPE_FORMAT_STRING_SIZE 1239
#define PROC_FORMAT_STRING_SIZE 835
#define PROC_FORMAT_STRING_SIZE 967
#define EXPR_FORMAT_STRING_SIZE 1
#define TRANSMIT_AS_TABLE_SIZE 0
#define WIRE_MARSHAL_TABLE_SIZE 2
......@@ -834,6 +834,123 @@ static const WeChatRobotCOM_MIDL_PROC_FORMAT_STRING WeChatRobotCOM__MIDL_ProcFor
/* 832 */ 0x8, /* FC_LONG */
0x0, /* 0 */
/* Procedure CGetDbHandles */
/* 834 */ 0x33, /* FC_AUTO_HANDLE */
0x6c, /* Old Flags: object, Oi2 */
/* 836 */ NdrFcLong( 0x0 ), /* 0 */
/* 840 */ NdrFcShort( 0x1b ), /* 27 */
/* 842 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */
/* 844 */ NdrFcShort( 0x0 ), /* 0 */
/* 846 */ NdrFcShort( 0x8 ), /* 8 */
/* 848 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */
0x2, /* 2 */
/* 850 */ 0x8, /* 8 */
0x43, /* Ext Flags: new corr desc, clt corr check, has range on conformance */
/* 852 */ NdrFcShort( 0x1 ), /* 1 */
/* 854 */ NdrFcShort( 0x0 ), /* 0 */
/* 856 */ NdrFcShort( 0x0 ), /* 0 */
/* Parameter __result */
/* 858 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */
/* 860 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */
/* 862 */ NdrFcShort( 0x4ac ), /* Type Offset=1196 */
/* Return value */
/* 864 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */
/* 866 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */
/* 868 */ 0x8, /* FC_LONG */
0x0, /* 0 */
/* Procedure CExecuteSQL */
/* 870 */ 0x33, /* FC_AUTO_HANDLE */
0x6c, /* Old Flags: object, Oi2 */
/* 872 */ NdrFcLong( 0x0 ), /* 0 */
/* 876 */ NdrFcShort( 0x1c ), /* 28 */
/* 878 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */
/* 880 */ NdrFcShort( 0x8 ), /* 8 */
/* 882 */ NdrFcShort( 0x8 ), /* 8 */
/* 884 */ 0x47, /* Oi2 Flags: srv must size, clt must size, has return, has ext, */
0x4, /* 4 */
/* 886 */ 0x8, /* 8 */
0x47, /* Ext Flags: new corr desc, clt corr check, srv corr check, has range on conformance */
/* 888 */ NdrFcShort( 0x1 ), /* 1 */
/* 890 */ NdrFcShort( 0x1 ), /* 1 */
/* 892 */ NdrFcShort( 0x0 ), /* 0 */
/* Parameter DbHandle */
/* 894 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */
/* 896 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */
/* 898 */ 0x8, /* FC_LONG */
0x0, /* 0 */
/* Parameter sql */
/* 900 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */
/* 902 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */
/* 904 */ NdrFcShort( 0x2a ), /* Type Offset=42 */
/* Parameter __result */
/* 906 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */
/* 908 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */
/* 910 */ NdrFcShort( 0x4ac ), /* Type Offset=1196 */
/* Return value */
/* 912 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */
/* 914 */ NdrFcShort( 0x10 ), /* x86 Stack size/offset = 16 */
/* 916 */ 0x8, /* FC_LONG */
0x0, /* 0 */
/* Procedure CBackupSQLiteDB */
/* 918 */ 0x33, /* FC_AUTO_HANDLE */
0x6c, /* Old Flags: object, Oi2 */
/* 920 */ NdrFcLong( 0x0 ), /* 0 */
/* 924 */ NdrFcShort( 0x1d ), /* 29 */
/* 926 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */
/* 928 */ NdrFcShort( 0x8 ), /* 8 */
/* 930 */ NdrFcShort( 0x24 ), /* 36 */
/* 932 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */
0x4, /* 4 */
/* 934 */ 0x8, /* 8 */
0x45, /* Ext Flags: new corr desc, srv corr check, has range on conformance */
/* 936 */ NdrFcShort( 0x0 ), /* 0 */
/* 938 */ NdrFcShort( 0x1 ), /* 1 */
/* 940 */ NdrFcShort( 0x0 ), /* 0 */
/* Parameter DbHandle */
/* 942 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */
/* 944 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */
/* 946 */ 0x8, /* FC_LONG */
0x0, /* 0 */
/* Parameter savepath */
/* 948 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */
/* 950 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */
/* 952 */ NdrFcShort( 0x2a ), /* Type Offset=42 */
/* Parameter __result */
/* 954 */ NdrFcShort( 0x2150 ), /* Flags: out, base type, simple ref, srv alloc size=8 */
/* 956 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */
/* 958 */ 0x8, /* FC_LONG */
0x0, /* 0 */
/* Return value */
/* 960 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */
/* 962 */ NdrFcShort( 0x10 ), /* x86 Stack size/offset = 16 */
/* 964 */ 0x8, /* FC_LONG */
0x0, /* 0 */
0x0
}
};
......@@ -1698,7 +1815,10 @@ static const unsigned short IWeChatRobot_FormatStringOffsetTable[] =
666,
702,
738,
792
792,
834,
870,
918
};
static const MIDL_STUBLESS_PROXY_INFO IWeChatRobot_ProxyInfo =
......@@ -1722,7 +1842,7 @@ static const MIDL_SERVER_INFO IWeChatRobot_ServerInfo =
0,
0,
0};
CINTERFACE_PROXY_VTABLE(27) _IWeChatRobotProxyVtbl =
CINTERFACE_PROXY_VTABLE(30) _IWeChatRobotProxyVtbl =
{
&IWeChatRobot_ProxyInfo,
&IID_IWeChatRobot,
......@@ -1752,7 +1872,10 @@ CINTERFACE_PROXY_VTABLE(27) _IWeChatRobotProxyVtbl =
(void *) (INT_PTR) -1 /* IWeChatRobot::CReceiveMessage */ ,
(void *) (INT_PTR) -1 /* IWeChatRobot::CStopReceiveMessage */ ,
(void *) (INT_PTR) -1 /* IWeChatRobot::CSendAtText */ ,
(void *) (INT_PTR) -1 /* IWeChatRobot::CGetChatRoomMembers */
(void *) (INT_PTR) -1 /* IWeChatRobot::CGetChatRoomMembers */ ,
(void *) (INT_PTR) -1 /* IWeChatRobot::CGetDbHandles */ ,
(void *) (INT_PTR) -1 /* IWeChatRobot::CExecuteSQL */ ,
(void *) (INT_PTR) -1 /* IWeChatRobot::CBackupSQLiteDB */
};
......@@ -1781,6 +1904,9 @@ static const PRPC_STUB_FUNCTION IWeChatRobot_table[] =
NdrStubCall2,
NdrStubCall2,
NdrStubCall2,
NdrStubCall2,
NdrStubCall2,
NdrStubCall2,
NdrStubCall2
};
......@@ -1788,7 +1914,7 @@ CInterfaceStubVtbl _IWeChatRobotStubVtbl =
{
&IID_IWeChatRobot,
&IWeChatRobot_ServerInfo,
27,
30,
&IWeChatRobot_table[-3],
CStdStubBuffer_DELEGATING_METHODS
};
......
......@@ -31,6 +31,10 @@ DWORD PopHeadMessageRemoteOffset = 0x0;
DWORD GetChatRoomMembersRemoteOffset = 0x0;
DWORD GetDbHandlesRemoteOffset = 0x0;
DWORD ExecuteSQLRemoteOffset = 0x0;
DWORD BackupSQLiteDBRemoteOffset = 0x0;
wstring SelfInfoString = L"";
HANDLE hProcess = NULL;
......@@ -139,6 +143,13 @@ void GetProcOffset(wchar_t* workPath) {
DWORD GetChatRoomMembersRemoteAddr = (DWORD)GetProcAddress(hd, GetChatRoomMembersRemote);
GetChatRoomMembersRemoteOffset = GetChatRoomMembersRemoteAddr - WeChatBase;
DWORD GetDbHandlesRemoteAddr = (DWORD)GetProcAddress(hd, GetDbHandlesRemote);
GetDbHandlesRemoteOffset = GetDbHandlesRemoteAddr - WeChatBase;
DWORD ExecuteSQLRemoteAddr = (DWORD)GetProcAddress(hd, ExecuteSQLRemote);
ExecuteSQLRemoteOffset = ExecuteSQLRemoteAddr - WeChatBase;
DWORD BackupSQLiteDBRemoteAddr = (DWORD)GetProcAddress(hd, BackupSQLiteDBRemote);
BackupSQLiteDBRemoteOffset = BackupSQLiteDBRemoteAddr - WeChatBase;
FreeLibrary(hd);
delete[] dllpath;
dllpath = NULL;
......
......@@ -12,6 +12,9 @@
#include "CheckFriendStatus.h"
#include "ReceiveMessage.h"
#include "GetChatRoomMembers.h"
#include "GetDbHandles.h"
#include "DbExecuteSql.h"
#include "DbBackup.h"
extern HANDLE hProcess;
extern DWORD SendImageOffset;
......@@ -43,6 +46,10 @@ extern DWORD PopHeadMessageRemoteOffset;
extern DWORD GetChatRoomMembersRemoteOffset;
extern DWORD GetDbHandlesRemoteOffset;
extern DWORD ExecuteSQLRemoteOffset;
extern DWORD BackupSQLiteDBRemoteOffset;
#define dllname L"DWeChatRobot.dll"
......@@ -72,4 +79,8 @@ extern DWORD GetChatRoomMembersRemoteOffset;
#define GetHeadMessageRemote "GetHeadMessage"
#define PopHeadMessageRemote "PopHeadMessage"
#define GetChatRoomMembersRemote "GetChatRoomMembersRemote"
\ No newline at end of file
#define GetChatRoomMembersRemote "GetChatRoomMembersRemote"
#define GetDbHandlesRemote "GetDbHandlesRemote"
#define ExecuteSQLRemote "ExecuteSQLRemote"
#define BackupSQLiteDBRemote "BackupSQLiteDBRemote"
\ No newline at end of file
......@@ -155,9 +155,12 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="CheckFriendStatus.h" />
<ClInclude Include="DbBackup.h" />
<ClInclude Include="DbExecuteSql.h" />
<ClInclude Include="framework.h" />
<ClInclude Include="FriendList.h" />
<ClInclude Include="GetChatRoomMembers.h" />
<ClInclude Include="GetDbHandles.h" />
<ClInclude Include="LogMsgInfo.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="ReceiveMessage.h" />
......@@ -172,9 +175,12 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="CheckFriendStatus.cpp" />
<ClCompile Include="DbBackup.cpp" />
<ClCompile Include="DbExecuteSql.cpp" />
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="FriendList.cpp" />
<ClCompile Include="GetChatRoomMemebers.cpp" />
<ClCompile Include="GetDbHandles.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
......
......@@ -64,6 +64,18 @@
<Filter Include="群相关\获取群成员">
<UniqueIdentifier>{fabe98aa-4f28-4bc6-b368-68808145a135}</UniqueIdentifier>
</Filter>
<Filter Include="数据库">
<UniqueIdentifier>{430d3dd8-bbd5-4ec2-85dc-7d853ea0096d}</UniqueIdentifier>
</Filter>
<Filter Include="数据库\获取句柄">
<UniqueIdentifier>{c7530a89-ce8c-4a36-95c9-b573d2b305f6}</UniqueIdentifier>
</Filter>
<Filter Include="数据库\执行SQL">
<UniqueIdentifier>{af9a0b81-49b3-4029-a4e4-2a5559f26d32}</UniqueIdentifier>
</Filter>
<Filter Include="数据库\数据库备份">
<UniqueIdentifier>{59e555da-03e8-41d4-bd90-53e1b02fb30d}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="framework.h">
......@@ -111,6 +123,15 @@
<ClInclude Include="GetChatRoomMembers.h">
<Filter>群相关\获取群成员</Filter>
</ClInclude>
<ClInclude Include="DbExecuteSql.h">
<Filter>数据库\执行SQL</Filter>
</ClInclude>
<ClInclude Include="GetDbHandles.h">
<Filter>数据库\获取句柄</Filter>
</ClInclude>
<ClInclude Include="DbBackup.h">
<Filter>数据库\数据库备份</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">
......@@ -158,5 +179,14 @@
<ClCompile Include="GetChatRoomMemebers.cpp">
<Filter>群相关\获取群成员</Filter>
</ClCompile>
<ClCompile Include="DbExecuteSql.cpp">
<Filter>数据库\执行SQL</Filter>
</ClCompile>
<ClCompile Include="GetDbHandles.cpp">
<Filter>数据库\获取句柄</Filter>
</ClCompile>
<ClCompile Include="DbBackup.cpp">
<Filter>数据库\数据库备份</Filter>
</ClCompile>
</ItemGroup>
</Project>
\ No newline at end of file
#include "pch.h"
#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 IDA_BASE 0x10000000
BOOL SQLite3_Backup_Init_Patched = FALSE;
typedef int(__cdecl* Sqlite3_open)(const char*, DWORD*);
typedef DWORD(__cdecl* Sqlite3_backup_init)(DWORD, const char*, DWORD, const char*);
typedef int(__cdecl* Sqlite3_backup_step)(DWORD, int);
typedef int(__cdecl* Sqlite3_backup_remaining)(DWORD);
typedef int(__cdecl* Sqlite3_backup_pagecount)(DWORD);
typedef int(__cdecl* Sqlite3_sleep)(int);
typedef int(__cdecl* Sqlite3_backup_finish)(DWORD);
typedef int(__cdecl* Sqlite3_errcode)(DWORD);
typedef int(__cdecl* Sqlite3_close)(DWORD);
DWORD OffsetFromIdaAddr(DWORD idaAddr) {
return idaAddr - IDA_BASE;
}
int __cdecl backupDb(
DWORD pDb, /* Database to back up */
const char* zFilename, /* Name of file to back up to */
DWORD myMain,
int address_sqlite3_open,
int address_sqlite3_backup_init,
int address_sqlite3_backup_step,
int address_sqlite3_backup_remaining,
int address_sqlite3_backup_pagecount,
int address_sqlite3_sleep,
int address_sqlite3_backup_finish,
int address_sqlite3_errcode,
int address_sqlite3_close,
void(*xProgress)(int, int) /* Progress function to invoke */
) {
int rc; /* Function return code */
DWORD pFile = 0; /* Database connection opened on zFilename */
DWORD pBackup = 0; /* Backup handle used to copy data */
Sqlite3_open p_Sqlite3_open = (Sqlite3_open)address_sqlite3_open;
Sqlite3_backup_init p_Sqlite3_backup_init = (Sqlite3_backup_init)address_sqlite3_backup_init;
Sqlite3_backup_step p_Sqlite3_backup_step = (Sqlite3_backup_step)address_sqlite3_backup_step;
Sqlite3_backup_remaining p_Sqlite3_backup_remaining = (Sqlite3_backup_remaining)address_sqlite3_backup_remaining;
Sqlite3_backup_pagecount p_Sqlite3_backup_pagecount = (Sqlite3_backup_pagecount)address_sqlite3_backup_pagecount;
Sqlite3_sleep p_Sqlite3_sleep = (Sqlite3_sleep)address_sqlite3_sleep;
Sqlite3_backup_finish p_Sqlite3_backup_finish = (Sqlite3_backup_finish)address_sqlite3_backup_finish;
Sqlite3_errcode p_Sqlite3_errcode = (Sqlite3_errcode)address_sqlite3_errcode;
Sqlite3_close p_Sqlite3_close = (Sqlite3_close)address_sqlite3_close;
rc = p_Sqlite3_open((const char*)zFilename, &pFile);
if (rc == SQLITE_OK) {
pBackup = p_Sqlite3_backup_init(pFile, (const char*)myMain, pDb, (const char*)myMain);
if (pBackup) {
do {
rc = p_Sqlite3_backup_step(pBackup, 5);
xProgress(
p_Sqlite3_backup_remaining(pBackup),
p_Sqlite3_backup_pagecount(pBackup)
);
if (rc == SQLITE_OK || rc == SQLITE_BUSY || rc == SQLITE_LOCKED) {
p_Sqlite3_sleep(50);
}
} while (rc == SQLITE_OK || rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
(void)p_Sqlite3_backup_finish(pBackup);
}
rc = p_Sqlite3_errcode(pFile);
}
(void)p_Sqlite3_close(pFile);
return rc;
}
VOID PatchSQLite3_Backup_Init() {
if (SQLite3_Backup_Init_Patched)
return;
// patch掉这块指令,绕过`backup is not supported with encrypted databases`
DWORD address_sqlite3_backup_init_patch_offset = OffsetFromIdaAddr(0x1131C110 + 0x52);
DWORD patchAddress = GetWeChatWinBase() + address_sqlite3_backup_init_patch_offset;
const int nopLen = 22;
BYTE nopData[nopLen];
for (int i = 0; i < nopLen; i++) {
nopData[i] = 0x90;
}
WriteProcessMemory(GetCurrentProcess(), (LPVOID)patchAddress, nopData, nopLen, 0);
SQLite3_Backup_Init_Patched = TRUE;
return;
}
void XProgress(int a, int b)
{
#ifdef _DEBUG
printf("备份进度: %d/%d\n", b - a, b);
#endif
return;
}
int BackupSQLiteDB(DWORD DbHandle,const char* BackupFile)
{
DWORD wxBaseAddress = GetWeChatWinBase();
PatchSQLite3_Backup_Init();
// 请不要注释掉这一行,也不要对其做任何改动,如果你不希望备份完成后微信崩溃
cout << "开始备份,文件保存至: " << BackupFile << endl;
DWORD address_sqlite3_open = wxBaseAddress + OffsetFromIdaAddr(0x1138ACD0);
DWORD address_sqlite3_backup_init = wxBaseAddress + OffsetFromIdaAddr(0x1131C110);
DWORD address_sqlite3_backup_step = wxBaseAddress + OffsetFromIdaAddr(0x1131C510);
DWORD address_sqlite3_sleep = wxBaseAddress + OffsetFromIdaAddr(0x1138B510);
DWORD address_sqlite3_backup_finish = wxBaseAddress + OffsetFromIdaAddr(0x1131CB50);
DWORD address_sqlite3_close = wxBaseAddress + OffsetFromIdaAddr(0x113880A0);
DWORD address_sqlite3_backup_remaining = wxBaseAddress + OffsetFromIdaAddr(0x1131CC50);
DWORD address_sqlite3_backup_pagecount = wxBaseAddress + OffsetFromIdaAddr(0x1131CC60);
DWORD address_sqlite3_errcode = wxBaseAddress + OffsetFromIdaAddr(0x11356570);
const char* myMain = "main";
int rc = backupDb(
DbHandle,
BackupFile,
(DWORD)myMain,
address_sqlite3_open,
address_sqlite3_backup_init,
address_sqlite3_backup_step,
address_sqlite3_backup_remaining,
address_sqlite3_backup_pagecount,
address_sqlite3_sleep,
address_sqlite3_backup_finish,
address_sqlite3_errcode,
address_sqlite3_close,
XProgress);
cout << "备份完成: " << BackupFile << endl;
return rc == 1;
}
BOOL BackupSQLiteDBRemote(LPVOID lpParameter) {
BackupStruct* param = (BackupStruct*)lpParameter;
int rc = BackupSQLiteDB(param->DbHandle,(const char*)param->BackupFile);
return rc;
}
\ No newline at end of file
#pragma once
#include<windows.h>
struct BackupStruct {
DWORD DbHandle;
char* BackupFile;
};
int BackupSQLiteDB(DWORD DbHandle, const char* BackupFile);
extern "C" __declspec(dllexport) BOOL BackupSQLiteDBRemote(LPVOID lpParameter);
\ No newline at end of file
#include "pch.h"
#define sqlite3_execOffset 0x66176570 - 0x64E20000
typedef int(*sqlite3_callback)(
void*,
int,
char**,
char**
);
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 */
);
DWORD WeChatWinBase = GetWeChatWinBase();
DWORD sqlite3_execAddr = WeChatWinBase + sqlite3_execOffset;
struct executeParams {
DWORD ptrDb;
DWORD ptrSql;
};
struct SQLResultStruct {
char* ColName;
DWORD l_ColName;
char* content;
DWORD l_content;
};
struct executeResult {
DWORD SQLResultAddr;
DWORD length;
};
executeResult result = { 0 };
vector <vector<SQLResultStruct>> SQLResult;
int GetDbInfo(void* data,int argc,char** argv,char** azColName) {
DbInfoStruct* pdata = (DbInfoStruct*)data;
TableInfoStruct 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.tbl_name = new char[strlen(argv[2]) + 1];
memcpy(tb.tbl_name, argv[2], strlen(argv[2]) + 1);
}
else {
tb.tbl_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.l_name = strlen(tb.name);
tb.l_tbl_name = strlen(tb.tbl_name);
tb.l_sql = strlen(tb.sql);
tb.l_rootpage = strlen(tb.rootpage);
pdata->tables.push_back(tb);
pdata->count = pdata->tables.size();
return 0;
}
int query(void* data, int argc, char** argv, char** azColName) {
for (int i = 0; i < argc; i++) {
string content = argv[i] ? UTF8ToGBK(argv[i]) : "NULL";
cout << azColName[i] << " = " << content << endl;
}
printf("\n");
return 0;
}
int select(void* data, int argc, char** argv, char** azColName) {
executeResult* pdata = (executeResult*)data;
vector<SQLResultStruct> tempStruct;
for (int i = 0; i < argc; i++) {
SQLResultStruct temp = { 0 };
temp.ColName = new char[strlen(azColName[i]) + 1];
memcpy(temp.ColName, azColName[i], strlen(azColName[i]) + 1);
temp.l_ColName = strlen(azColName[i]);
if (argv[i]) {
temp.content = new char[strlen(argv[i]) + 1];
memcpy(temp.content, argv[i], strlen(argv[i]) + 1);
temp.l_content = strlen(argv[i]);
}
else {
temp.content = new char[2];
ZeroMemory(temp.content, 2);
temp.l_content = 0;
}
tempStruct.push_back(temp);
}
SQLResult.push_back(tempStruct);
pdata->length++;
return 0;
}
void ClearResultArray() {
if (SQLResult.size() == 0)
return;
for(unsigned int i = 0; i < SQLResult.size(); i++) {
for (unsigned j = 0; j < SQLResult[i].size(); j++) {
SQLResultStruct* sr = (SQLResultStruct*)&SQLResult[i][j];
if (sr->ColName) {
delete sr->ColName;
sr->ColName = NULL;
}
if (sr->content) {
delete sr->content;
sr->content = NULL;
}
}
SQLResult[i].clear();
}
SQLResult.clear();
result.SQLResultAddr = 0;
result.length = 0;
}
BOOL ExecuteSQL(DWORD ptrDb,const char* sql,DWORD callback,void* data) {
Sqlite3_exec p_Sqlite3_exec = (Sqlite3_exec)sqlite3_execAddr;
int status = p_Sqlite3_exec(ptrDb,sql, (sqlite3_callback)callback,data,0);
return status == 0;
}
DWORD ExecuteSQLRemote(LPVOID lpParameter){
ClearResultArray();
executeParams* sqlparam = (executeParams*)lpParameter;
BOOL status = ExecuteSQL(sqlparam->ptrDb, (const char*)sqlparam->ptrSql, (DWORD)select, &result);
if (status) {
result.SQLResultAddr = (DWORD)SQLResult.data();
return (DWORD)&result;
}
else {
result.length = 0;
}
return 0;
}
\ No newline at end of file
#pragma once
#include<windows.h>
int GetDbInfo(void* data, int argc, char** argv, char** azColName);
int select(void* data, int argc, char** argv, char** azColName);
int query(void* data, int argc, char** argv, char** azColName);
extern "C" __declspec(dllexport) DWORD ExecuteSQLRemote(LPVOID lpParameter);
BOOL ExecuteSQL(DWORD ptrDb, const char* sql, DWORD callback, void* data);
#include "pch.h"
#define SqlHandleBaseOffset 0x6704F3FC - 0x64E20000
vector<DbInfoStruct> dbs;
DWORD GetDbHandleByDbName(wchar_t* dbname) {
if (dbs.size() == 0)
GetDbHandles();
for (unsigned int i = 0; i < dbs.size() - 1; i++) {
if (!lstrcmpW(dbs[i].dbname, dbname))
return dbs[i].handle;
}
return 0;
}
DWORD GetDbHandlesRemote() {
if (dbs.size() == 0)
GetDbHandles();
return (DWORD)dbs.data() ;
}
void GetDbHandles() {
dbs.clear();
DWORD WeChatWinBase = GetWeChatWinBase();
DWORD SqlHandleBaseAddr = WeChatWinBase + SqlHandleBaseOffset;
DWORD SqlHandleBeginAddr = 0x0;
DWORD SqlHandleEndAddr = 0x0;
__asm {
mov eax, [SqlHandleBaseAddr];
mov ecx, [eax];
add ecx, 0x1888;
mov eax, [ecx];
mov SqlHandleBeginAddr, eax;
mov eax, [ecx + 0x4];
mov SqlHandleEndAddr, eax;
}
wstring dbnames = L"";
while (SqlHandleBeginAddr < SqlHandleEndAddr) {
DWORD dwHandle = *(DWORD*)SqlHandleBeginAddr;
SqlHandleBeginAddr += 0x4;
if (SqlHandleBeginAddr == SqlHandleEndAddr)
break;
if(dbnames.find((wchar_t*)(*(DWORD*)(dwHandle + 0x78)),0) != wstring::npos)
continue;
DbInfoStruct db = { 0 };
dbnames += (wchar_t*)(*(DWORD*)(dwHandle + 0x78));
db.dbname = (wchar_t*)(*(DWORD*)(dwHandle + 0x78));
db.l_dbname = wcslen(db.dbname);
db.handle = *(DWORD*)(dwHandle + 0x64);
ExecuteSQL(*(DWORD*)(dwHandle + 0x64), "select * from sqlite_master where type=\"table\";",(DWORD)GetDbInfo,&db);
dbs.push_back(db);
}
// 添加一个空结构体,作为读取结束标志
DbInfoStruct db_end = { 0 };
dbs.push_back(db_end);
#ifdef _DEBUG
for (unsigned int i = 0; i < dbs.size() - 1; i++) {
printf("dbname = %ws,handle = 0x%08X,table_count:%d\n",dbs[i].dbname,dbs[i].handle,dbs[i].tables.size());
for (unsigned int j = 0; j < dbs[i].tables.size();j++) {
cout << "name = " << dbs[i].tables[j].name << endl;
cout << "tbl_name = " << dbs[i].tables[j].tbl_name << endl;
cout << "rootpage = " << dbs[i].tables[j].rootpage << endl;
cout << "sql = " << dbs[i].tables[j].sql << endl;
cout << endl;
}
cout << endl;
}
#endif
}
\ No newline at end of file
#pragma once
#include<windows.h>
#include<vector>
struct TableInfoStruct {
char* name;
DWORD l_name;
char* tbl_name;
DWORD l_tbl_name;
char* sql;
DWORD l_sql;
char* rootpage;
DWORD l_rootpage;
};
struct DbInfoStruct {
DWORD handle;
wchar_t* dbname;
DWORD l_dbname;
vector<TableInfoStruct> tables;
DWORD count;
};
void GetDbHandles();
extern "C" __declspec(dllexport) DWORD GetDbHandlesRemote();
DWORD GetDbHandleByDbName(wchar_t* dbname);
\ No newline at end of file
......@@ -22,6 +22,8 @@ BOOL APIENTRY DllMain( HMODULE hModule,
printf("SendCard 0x%08X\n", (DWORD)SendCard);
printf("CheckFriendStatus 0x%08X\n", (DWORD)CheckFriendStatus);
printf("GetChatRoomMembers 0x%08X\n", (DWORD)GetChatRoomMembers);
printf("ExecuteSql 0x%08X\n", (DWORD)ExecuteSQL);
printf("BackupSQLiteDB 0x%08X\n", (DWORD)BackupSQLiteDB);
#endif
break;
}
......
......@@ -31,6 +31,24 @@ void Wchar_tToString(std::string& szDst, wchar_t* wchar)
delete[]psText;// psText的清除
}
string UTF8ToGBK(const std::string& strUTF8)
{
int len = MultiByteToWideChar(CP_UTF8, 0, strUTF8.c_str(), -1, NULL, 0);
wchar_t* wszGBK = new wchar_t[len + 1];
memset(wszGBK, 0, len * 2 + 2);
MultiByteToWideChar(CP_UTF8, 0, strUTF8.c_str(), -1, wszGBK, len);
len = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL);
char* szGBK = new char[len + 1];
memset(szGBK, 0, len + 1);
WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, szGBK, len, NULL, NULL);
//strUTF8 = szGBK;
std::string strTemp(szGBK);
delete[]szGBK;
delete[]wszGBK;
return strTemp;
}
void HookAnyAddress(DWORD dwHookAddr, LPVOID dwJmpAddress,char* originalRecieveCode)
{
//组装跳转数据
......
......@@ -24,6 +24,10 @@
#include "ReceiveMessage.h"
#include "SendAtText.h"
#include "GetChatRoomMembers.h"
#include "GetDbHandles.h"
#include "DbExecuteSql.h"
#include "DbBackup.h"
#include <vector>
#endif //PCH_H
using namespace std;
......@@ -55,10 +59,10 @@ struct WxString
DWORD fill2 = 0;
};
BOOL CreateConsole(void);
DWORD GetWeChatWinBase();
void Wchar_tToString(std::string& szDst, wchar_t* wchar);
string UTF8ToGBK(const std::string& strUTF8);
void HookAnyAddress(DWORD dwHookAddr, LPVOID dwJmpAddress, char* originalRecieveCode);
void UnHookAnyAddress(DWORD dwHookAddr, char* originalRecieveCode);
DLLEXPORT void UnHookAll();
......
comtypes==1.1.11
\ No newline at end of file
# -*- coding: utf-8 -*-
"""
Created on Sat Apr 16 14:06:24 2022
@author: lijinchao-002
"""
import time
from wxRobot import WeChatRobot
# 一个示例回调,将收到的文本消息转发给filehelper
def ReceiveMessageCallBack(robot,message):
if message['type'] == 1 and message['sender'] != 'filehelper':
robot.robot.CSendText('filehelper',message['message'])
wxSender = robot.GetWxUserInfo(message['sender'])
sender = wxSender['wxNickName'] if wxSender['wxNickName'] != 'null' else message['sender']
if '@chatroom' in message['sender']:
wxUser = robot.GetWxUserInfo(message['wxid'])
print("来自 {} {},type {}".format(sender,wxUser['wxNickName'],message['type']))
else:
print("来自 {},type {}".format(sender,message['type']))
if message['type'] == 1:
print(message['message'])
elif message['type'] == 3:
print(message['message'])
print(message['filepath'])
elif message['type'] == 49:
print(message['message'])
if not message['filepath']: print(message['filepath'])
else:
print(message['message'])
def test_SendText():
import os
path = os.path.split(os.path.realpath(__file__))[0]
# image full path
imgpath = os.path.join(path,'test\\测试图片.png')
# file full path
filepath = os.path.join(path,'test\\测试文件')
wx = WeChatRobot()
wx.StartService()
myinfo = wx.GetSelfInfo()
chatwith = wx.GetFriendByWxNickName("文件传输助手")
session = wx.GetChatSession(chatwith.get('wxid'))
filehelper = wx.GetWxUserInfo(chatwith.get('wxid'))
session.SendText('个人信息:{}'.format(str(myinfo.get('wxNickName'))))
session.SendText('好友信息:{}'.format(str(filehelper.get('wxNickName'))))
if os.path.exists(imgpath): session.SendImage(imgpath)
if os.path.exists(filepath): session.SendFile(filepath)
session.SendArticle("天气预报","点击查看","http://www.baidu.com")
shared = wx.GetFriendByWxNickName("码农翻身")
if shared: session.SendCard(shared.get('wxid'),shared.get('wxNickName'))
wx.StopService()
def test_FriendStatus():
f = open('Friendstatus.txt','wt',encoding = 'utf-8')
wx = WeChatRobot()
wx.StartService()
FriendList = wx.GetFriendList()
wx.CheckFriendStatusInit()
index = "\t".join(['微信号','昵称','备注','状态','\n'])
f.writelines(index)
for Friend in FriendList:
result = '\t'.join(
[Friend.get('wxNumber'),Friend.get('wxNickName'),Friend.get('wxRemark'),
wx.CheckFriendStatus(Friend.get('wxid'))])
print(result)
result += '\n'
f.writelines(result)
time.sleep(1)
break
f.close()
wx.StopService()
def test_ReceiveMessage():
wx = WeChatRobot()
wx.StartService()
wx.StartReceiveMessage(CallBackFunc = ReceiveMessageCallBack)
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
pass
wx.StopService(wx)
def test_ExecuteSQL():
wx = WeChatRobot()
wx.StartService()
try:
dbs = wx.GetDbHandles()
dbname = 'MicroMsg.db'
handle = dbs.get(dbname).get('Handle')
sql = 'select a.UserName as `wxID`,a.Alias as `微信号`,a.EncryptUserName as `V3数据`,\
a.Type as `联系人类型`,a.VerifyFlag as `添加方式`,a.Remark as `备注`,a.NickName as `昵称`,b.bigHeadImgUrl as `头像` \
from Contact a inner join ContactHeadImgUrl b where a.UserName=b.usrName and a.Type=3 limit 10'
result = wx.ExecuteSQL(handle,sql)
print(result)
except:
pass
wx.StopService()
def test_BackupDb():
wx = WeChatRobot()
wx.StartService()
try:
dbs = wx.GetDbHandles()
dbname = 'MicroMsg.db'
handle = dbs.get(dbname).get('Handle')
rc = wx.BackupSQLiteDB(handle,'D:\\WeChatBackup\\{}'.format(dbname))
print(rc)
except:
pass
wx.StopService()
if __name__ == '__main__':
test_BackupDb()
\ No newline at end of file
......@@ -9,6 +9,7 @@ Created on Thu Feb 24 16:19:48 2022
# need `pip install comtypes`
import comtypes.client
import ast
import os
import threading
import time
......@@ -26,7 +27,6 @@ class ChatSession():
def SendFile(self,filepath):
return self.robot.CSendFile(self.chatwith,filepath)
# 其实发送图片的函数比较智能,也可以发送视频和文件
def SendMp4(self,mp4path):
return self.robot.CSendImage(self.chatwith,mp4path)
......@@ -197,7 +197,32 @@ class WeChatRobot():
self.ReceiveMessageThread.daemon = True
self.ReceiveMessageThread.start()
return status
def GetDbHandles(self):
tablesTuple = self.robot.CGetDbHandles()
tables = [dict(i) for i in tablesTuple]
dbs = {}
for table in tables:
dbname = table['dbname']
if dbname not in dbs.keys():
dbs[dbname] = {'Handle':table['Handle'],'tables':[]}
dbs[dbname]['tables'].append(
{'name': table['name'],'tbl_name': table['tbl_name'],
'rootpage': table['rootpage'],'sql': table['sql']}
)
return dbs
def ExecuteSQL(self,handle,sql):
result = self.robot.CExecuteSQL(handle,sql)
return result
def BackupSQLiteDB(self,handle,BackupFile):
BackupFile = BackupFile.replace('/','\\')
savepath = BackupFile.replace(BackupFile.split('\\')[-1],'')
if not os.path.exists(savepath):
os.makedirs(savepath)
return self.robot.CBackupSQLiteDB(handle,BackupFile)
def StopReceiveMessage(self):
self.ReceiveMessageStarted = False
try:
......@@ -205,82 +230,4 @@ class WeChatRobot():
except:
pass
status = self.robot.CStopReceiveMessage()
return status
# 一个示例回调,将收到的文本消息转发给filehelper
def ReceiveMessageCallBack(robot,message):
if message['type'] == 1 and message['sender'] != 'filehelper':
robot.robot.CSendText('filehelper',message['message'])
wxSender = robot.GetWxUserInfo(message['sender'])
sender = wxSender['wxNickName'] if wxSender['wxNickName'] != 'null' else message['sender']
if '@chatroom' in message['sender']:
wxUser = robot.GetWxUserInfo(message['wxid'])
print("来自 {} {},type {}".format(sender,wxUser['wxNickName',message['type']]))
else:
print("来自 {},type {}".format(sender,message['type']))
if message['type'] == 1:
print(message['message'])
elif message['type'] == 3:
print(message['message'])
print(message['filepath'])
elif message['type'] == 49:
print(message['message'])
if not message['filepath']: print(message['filepath'])
else:
print(message['message'])
def test_SendText():
import os
path = os.path.split(os.path.realpath(__file__))[0]
# image full path
imgpath = os.path.join(path,'test\\测试图片.png')
# file full path
filepath = os.path.join(path,'test\\测试文件')
wx = WeChatRobot()
wx.StartService()
myinfo = wx.GetSelfInfo()
chatwith = wx.GetFriendByWxNickName("文件传输助手")
session = wx.GetChatSession(chatwith.get('wxid'))
filehelper = wx.GetWxUserInfo(chatwith.get('wxid'))
session.SendText('个人信息:{}'.format(str(myinfo.get('wxNickName'))))
session.SendText('好友信息:{}'.format(str(filehelper.get('wxNickName'))))
if os.path.exists(imgpath): session.SendImage(imgpath)
if os.path.exists(filepath): session.SendFile(filepath)
session.SendArticle("天气预报","点击查看","http://www.baidu.com")
shared = wx.GetFriendByWxNickName("码农翻身")
if shared: session.SendCard(shared.get('wxid'),shared.get('wxNickName'))
wx.StopService()
def test_FriendStatus():
f = open('Friendstatus.txt','wt',encoding = 'utf-8')
wx = WeChatRobot()
wx.StartService()
FriendList = wx.GetFriendList()
wx.CheckFriendStatusInit()
index = "\t".join(['微信号','昵称','备注','状态','\n'])
f.writelines(index)
for Friend in FriendList:
result = '\t'.join(
[Friend.get('wxNumber'),Friend.get('wxNickName'),Friend.get('wxRemark'),
wx.CheckFriendStatus(Friend.get('wxid'))])
print(result)
result += '\n'
f.writelines(result)
time.sleep(1)
break
f.close()
wx.StopService()
def test_ReceiveMessage():
wx = WeChatRobot()
wx.StartService()
wx.StartReceiveMessage(CallBackFunc = ReceiveMessageCallBack)
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
pass
wx.StopService()
if __name__ == '__main__':
test_ReceiveMessage()
return status
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册