提交 3b38f66f 编写于 作者: L ljc545w

优化获取通讯录接口

上级 35663e4f
......@@ -70,12 +70,6 @@ void ReadFriendMessageByAddress(WxFriendAddrStruct* lpWxFriendAddr, WxFriendStru
ZeroMemory(lpWxFriend->wxRemark, sizeof(wchar_t) * (length + 1));
ReadProcessMemory(hProcess, (LPCVOID)lpWxFriendAddr->wxRemarkAddr, &bufferaddr, sizeof(DWORD), 0);
ReadProcessMemory(hProcess, (LPCVOID)bufferaddr, lpWxFriend->wxRemark, length * sizeof(wchar_t), 0);
wstring wswxRemark = wreplace(lpWxFriend->wxRemark,L'\"',L"\\\"");
delete[] lpWxFriend->wxRemark;
lpWxFriend->wxRemark = new wchar_t[wswxRemark.length() + 1];
ZeroMemory(lpWxFriend->wxRemark, sizeof(wchar_t) * (wswxRemark.length() + 1));
memcpy(lpWxFriend->wxRemark, wswxRemark.c_str(), wswxRemark.length() * 2);
wcout << lpWxFriend->wxRemark << endl;
}
}
else {
......@@ -100,7 +94,87 @@ void FreeWxFriend(int index) {
};
}
std::wstring GetFriendList() {
SAFEARRAY* CreateFriendArray(int FriendCount) {
HRESULT hr = S_OK;
SAFEARRAY* psaValue;
vector<wstring> FriendInfoKey = {
L"wxid",
L"wxNumber",
L"wxNickName",
L"wxRemark",
};
SAFEARRAYBOUND rgsaBound[3] = { {(ULONG)FriendCount,0},{FriendInfoKey.size(),0},{2,0} };
psaValue = SafeArrayCreate(VT_VARIANT, 3, rgsaBound);
for (long x = 0; x < FriendCount; x++) {
vector<wstring> FriendInfoValue = { WxFriendList[x].wxId,WxFriendList[x].wxNumber,WxFriendList[x].wxNickName,WxFriendList[x].wxRemark };
for (unsigned long i = 0; i < FriendInfoKey.size(); i++)
{
long keyIndex[3] = { x,(long)i,0 };
hr = SafeArrayPutElement(psaValue, keyIndex, &(_variant_t)FriendInfoKey[i].c_str());
long valueIndex[3] = { x,(long)i,1 };
hr = SafeArrayPutElement(psaValue, valueIndex, &(_variant_t)FriendInfoValue[i].c_str());
}
FriendInfoValue.clear();
}
return psaValue;
}
SAFEARRAY* GetFriendList() {
if (!hProcess)
return NULL;
DWORD GetFriendListInitAddr = GetWeChatRobotBase() + GetFriendListInitOffset;
DWORD GetFriendListRemoteAddr = GetWeChatRobotBase() + GetFriendListRemoteOffset;
DWORD GetFriendListFinishAddr = GetWeChatRobotBase() + GetFriendListFinishOffset;
DWORD FriendCount = 0;
DWORD dwId, dwHandle = 0;
// 获取好友列表的长度
HANDLE hThread = ::CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)GetFriendListInitAddr, NULL, 0, &dwId);
if (hThread) {
WaitForSingleObject(hThread, INFINITE);
GetExitCodeThread(hThread, &FriendCount);
CloseHandle(hThread);
}
// 获取保存第一个好友的数据指针的结构体首地址
hThread = ::CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)GetFriendListRemoteAddr, NULL, 0, &dwId);
if (hThread) {
WaitForSingleObject(hThread, INFINITE);
GetExitCodeThread(hThread, &dwHandle);
CloseHandle(hThread);
}
WxFriendAddrStruct WxFriendAddr = { 0 };
// 根据好友数量初始化全局变量
WxFriendList = new WxFriendStruct[FriendCount];
if (dwHandle) {
for (unsigned int i = 0; i < FriendCount; i++) {
WxFriendList[i] = { 0 };
ZeroMemory(&WxFriendAddr, sizeof(WxFriendAddrStruct));
ReadProcessMemory(hProcess, (LPCVOID)dwHandle, &WxFriendAddr, sizeof(WxFriendAddrStruct), 0);
ReadFriendMessageByAddress(&WxFriendAddr, &WxFriendList[i]);
// 保存下一个好友数据的结构体
dwHandle += sizeof(WxFriendAddrStruct);
}
}
else {
return NULL;
}
// 清除微信进程空间中的缓存
hThread = ::CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)GetFriendListFinishAddr, NULL, 0, &dwId);
if (hThread) {
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
}
SAFEARRAY* psaValue = CreateFriendArray(FriendCount);
for (unsigned int i = 0; i < FriendCount; i++) {
FreeWxFriend(i);
}
delete[] WxFriendList;
WxFriendList = NULL;
return psaValue;
}
std::wstring GetFriendListString() {
if (!hProcess)
return L"[]";
DWORD GetFriendListInitAddr = GetWeChatRobotBase() + GetFriendListInitOffset;
......
......@@ -2,4 +2,5 @@
#include<windows.h>
#include<iostream>
using namespace std;
std::wstring GetFriendList();
\ No newline at end of file
SAFEARRAY* GetFriendList();
std::wstring GetFriendListString();
\ No newline at end of file
......@@ -76,9 +76,23 @@ STDMETHODIMP CWeChatRobot::CSendCard(BSTR receiver, BSTR sharedwxid, BSTR nickna
/*
* 参数1:预返回的值,调用时无需提供
* 返回一个三维数组,python的comtypes包会将其解析为元组
*/
STDMETHODIMP CWeChatRobot::CGetFriendList(BSTR* __result) {
string smessage = _com_util::ConvertBSTRToString((BSTR)(GetFriendList().c_str()));
STDMETHODIMP CWeChatRobot::CGetFriendList(VARIANT* __result) {
VARIANT vsaValue;
vsaValue.vt = VT_ARRAY | VT_VARIANT;
V_ARRAY(&vsaValue) = GetFriendList();
*__result = vsaValue;
return S_OK;
}
/*
* 参数1:预返回的值,调用时无需提供
返回构造好的json串,在反序列化时需考虑好友信息中是否存在json字符
(考虑到从SAFEARRAY转换到适当变量可能较为繁琐,故保留此接口)
*/
STDMETHODIMP CWeChatRobot::CGetFriendListString(BSTR* __result) {
string smessage = _com_util::ConvertBSTRToString((BSTR)(GetFriendListString().c_str()));
*__result = _com_util::ConvertStringToBSTR(smessage.c_str());
return S_OK;
}
......
......@@ -58,7 +58,8 @@ public:
STDMETHODIMP CSendFile(BSTR wxid, BSTR filepath, int* __result);
STDMETHODIMP CSendArticle(BSTR wxid, BSTR title, BSTR abstract, BSTR url, int* __result);
STDMETHODIMP CSendCard(BSTR receiver, BSTR sharedwxid, BSTR nickname, int* __result);
STDMETHODIMP CGetFriendList(BSTR* __result);
STDMETHODIMP CGetFriendList(VARIANT* __result);
STDMETHODIMP CGetFriendListString(BSTR* __result);
STDMETHODIMP CGetWxUserInfo(BSTR wxid, BSTR* __result);
STDMETHODIMP CGetSelfInfo(BSTR* __result);
STDMETHODIMP CCheckFriendStatusInit(int* __result);
......
......@@ -23,13 +23,14 @@ interface IWeChatRobot : IDispatch
[id(5)] HRESULT CSendFile([in] BSTR wxid, [in] BSTR filepath, [out, retval] int* __result);
[id(6)] HRESULT CSendArticle([in] BSTR wxid, [in] BSTR title, [in] BSTR abstract, [in] BSTR url, [out, retval] int* __result);
[id(7)] HRESULT CSendCard([in] BSTR receiver, [in] BSTR sharedwxid, [in] BSTR nickname, [out, retval] int* __result);
[id(8)] HRESULT CGetFriendList([out, retval] BSTR* __result);
[id(9)] HRESULT CGetWxUserInfo([in] BSTR wxid, [out, retval] BSTR* __result);
[id(10)] HRESULT CGetSelfInfo([out, retval] BSTR* __result);
[id(11)] HRESULT CCheckFriendStatusInit([out, retval] int* __result);
[id(12)] HRESULT CCheckFriendStatus([in] BSTR wxid, [out, retval] int* __result);
[id(13)] HRESULT CCheckFriendStatusFinish([out, retval] int* __result);
[id(14)] HRESULT CGetComWorkPath([out, retval] BSTR* __result);
[id(8)] HRESULT CGetFriendList([out, retval] VARIANT* __result);
[id(9)] HRESULT CGetFriendListString([out, retval] BSTR* __result);
[id(10)] HRESULT CGetWxUserInfo([in] BSTR wxid, [out, retval] BSTR* __result);
[id(11)] HRESULT CGetSelfInfo([out, retval] BSTR* __result);
[id(12)] HRESULT CCheckFriendStatusInit([out, retval] int* __result);
[id(13)] HRESULT CCheckFriendStatus([in] BSTR wxid, [out, retval] int* __result);
[id(14)] HRESULT CCheckFriendStatusFinish([out, retval] int* __result);
[id(15)] HRESULT CGetComWorkPath([out, retval] BSTR* __result);
};
[
uuid(721abb35-141a-4aa2-94f2-762e2833fa6c),
......
......@@ -123,6 +123,9 @@ EXTERN_C const IID IID_IWeChatRobot;
/* [retval][out] */ int *__result) = 0;
virtual /* [id] */ HRESULT STDMETHODCALLTYPE CGetFriendList(
/* [retval][out] */ VARIANT *__result) = 0;
virtual /* [id] */ HRESULT STDMETHODCALLTYPE CGetFriendListString(
/* [retval][out] */ BSTR *__result) = 0;
virtual /* [id] */ HRESULT STDMETHODCALLTYPE CGetWxUserInfo(
......@@ -245,6 +248,10 @@ EXTERN_C const IID IID_IWeChatRobot;
/* [retval][out] */ int *__result);
/* [id] */ HRESULT ( STDMETHODCALLTYPE *CGetFriendList )(
IWeChatRobot * This,
/* [retval][out] */ VARIANT *__result);
/* [id] */ HRESULT ( STDMETHODCALLTYPE *CGetFriendListString )(
IWeChatRobot * This,
/* [retval][out] */ BSTR *__result);
......@@ -334,6 +341,9 @@ EXTERN_C const IID IID_IWeChatRobot;
#define IWeChatRobot_CGetFriendList(This,__result) \
( (This)->lpVtbl -> CGetFriendList(This,__result) )
#define IWeChatRobot_CGetFriendListString(This,__result) \
( (This)->lpVtbl -> CGetFriendListString(This,__result) )
#define IWeChatRobot_CGetWxUserInfo(This,wxid,__result) \
( (This)->lpVtbl -> CGetWxUserInfo(This,wxid,__result) )
......@@ -389,11 +399,21 @@ unsigned char * __RPC_USER BSTR_UserMarshal( unsigned long *, unsigned char *,
unsigned char * __RPC_USER BSTR_UserUnmarshal(unsigned long *, unsigned char *, BSTR * );
void __RPC_USER BSTR_UserFree( unsigned long *, BSTR * );
unsigned long __RPC_USER VARIANT_UserSize( unsigned long *, unsigned long , VARIANT * );
unsigned char * __RPC_USER VARIANT_UserMarshal( unsigned long *, unsigned char *, VARIANT * );
unsigned char * __RPC_USER VARIANT_UserUnmarshal(unsigned long *, unsigned char *, VARIANT * );
void __RPC_USER VARIANT_UserFree( unsigned long *, VARIANT * );
unsigned long __RPC_USER BSTR_UserSize64( unsigned long *, unsigned long , BSTR * );
unsigned char * __RPC_USER BSTR_UserMarshal64( unsigned long *, unsigned char *, BSTR * );
unsigned char * __RPC_USER BSTR_UserUnmarshal64(unsigned long *, unsigned char *, BSTR * );
void __RPC_USER BSTR_UserFree64( unsigned long *, BSTR * );
unsigned long __RPC_USER VARIANT_UserSize64( unsigned long *, unsigned long , VARIANT * );
unsigned char * __RPC_USER VARIANT_UserMarshal64( unsigned long *, unsigned char *, VARIANT * );
unsigned char * __RPC_USER VARIANT_UserUnmarshal64(unsigned long *, unsigned char *, VARIANT * );
void __RPC_USER VARIANT_UserFree64( unsigned long *, VARIANT * );
/* end of Additional Prototypes */
#ifdef __cplusplus
......
此差异已折叠。
......@@ -169,17 +169,4 @@ wstring GetComWorkPath() {
int pos = wpath.find_last_of(L"\\");
wpath = wpath.substr(0,pos);
return wpath;
}
wstring wreplace(wstring source, wchar_t replaced, wstring replaceto) {
wstring temp = L"";
wchar_t* buffer = (wchar_t*)source.c_str();
for (unsigned int i = 0; i < source.length(); i++) {
if (buffer[i] == replaced) {
temp += replaceto;
continue;
}
temp += buffer[i];
}
return temp;
}
\ No newline at end of file
......@@ -21,6 +21,7 @@
#include <tchar.h>
#include <sys/stat.h>
#include <direct.h>
#include <vector>
#include <comutil.h>
#pragma comment(lib, "comsuppw.lib")
......@@ -28,6 +29,10 @@
#include "robotdata.h"
using namespace std;
struct testStruct {
DWORD type;
wchar_t* desc;
};
bool isFileExists_stat(string& name);
DWORD GetWeChatRobotBase();
......@@ -35,5 +40,4 @@ DWORD GetWeChatPid();
DWORD StartRobotService();
DWORD StopRobotService();
BOOL CreateConsole();
wstring GetComWorkPath();
wstring wreplace(wstring source, wchar_t replaced, wstring replaceto);
\ No newline at end of file
wstring GetComWorkPath();
\ No newline at end of file
......@@ -8,6 +8,7 @@ struct SelfInfoStruct {
DWORD length;
} ret;
DWORD GetSelfInfoRemote() {
DWORD WeChatWinBase = GetWeChatWinBase();
vector<DWORD> SelfInfoAddr = {
......
......@@ -10,6 +10,14 @@ PC微信机器人,实现获取通讯录、发送文本、图片、文件、xml
# 原理
通过逆向PC微信,定位到关键CALL,dll内联汇编调用
注册32位COM组件,供64位/32位进程外部调用
# 目录说明
`./CWeChatRobot`:COM组件的实现代码
`./DWeChatRobot`:注入的DLL实现代码
`./wxRobot`: 包含C#的调用示例
`./wxRobot.py`:python示例文件
`./Release/CWeChatRobot.exe`:编译的COM组件
`./Release/DWeChatRobot.dll`:编译的动态库
`./Release/WeChatTools.exe`:用与调试时注入或卸载DLL程序,具体参加相关代码
# 注册COM
以管理员权限执行以下命令:
```shell
......@@ -19,25 +27,10 @@ CWeChatRobot.exe /regserver
CWeChatRobot.exe /unregserver
```
# 调用
Python:
**Python:**
参考[wxRobot.py](/wxRobot.py)
C#(参考如下代码):
```csharp
System.Type wxProtId = Type.GetTypeFromProgID("WeChatRobot.CWeChatRobot");
if (wxProtId == null)
return;
string workpath = System.AppDomain.CurrentDomain.BaseDirectory;
string basePath = workpath.Replace("wxRobot\\bin\\Release\\","");
dynamic wx = Activator.CreateInstance(wxProtId);
wx.CStartRobotService();
wx.CSendText("filehelper", "来自C艹艹的消息");
wx.CSendImage("filehelper", basePath + "test\\测试图片.png");
wx.CSendFile("filehelper", basePath + "test\\测试文件");
wx.CSendArticle("filehelper","PC微信逆向--获取通讯录", "确定不来看看么?", "https://www.ljczero.top/article/2022/3/13/133.html");
string selfinfo = wx.CGetSelfInfo();
Console.WriteLine(selfinfo);
wx.CStopRobotService();
```
**C#:**
参考[Program.cs](/wxRobot/Program.cs)
# 更多功能
目前没有添加更多功能的计划
已找到如下功能的CALL或HOOK位置:
......@@ -49,10 +42,15 @@ wx.CStopRobotService();
6. 微信Duilib界面xml文件
暂时没有空闲时间继续开发,如果想开发相关功能请发邮件到ljc545w@qq.com
**也欢迎您提交PR**
# 已知BUG
~~获取个人信息的接口不能很好的工作,因为需要判断数据是否是一个指针。~~
~~使用该接口将导致微信崩溃。~~
已对个人信息接口做了简单的修复,如果还有问题可报issue或搜索报错解决。
# 2022.04.01更新
1. 使用SAFEARRAY返回通讯录列表,可正确显示好友昵称中的特殊符号
2. README中添加目录说明
3. 更新C#示例代码,添加好友列表的遍历示例
# 打赏作者
请给作者一个star,感谢感谢
# 免责声明
......
......@@ -6,6 +6,7 @@ Created on Thu Feb 24 16:19:48 2022
"""
# Before use,execute `CWeChatRebot.exe /regserver` in cmd by admin user
# need `pip install comtypes`
import comtypes.client
import ast
......@@ -59,9 +60,11 @@ class WeChatRobot():
return self.robot.CStopRobotService()
def GetAddressBook(self):
AddressBookString = self.robot.CGetFriendList()
AddressBookString = AddressBookString.replace("\n","\\n")
self.AddressBook = ast.literal_eval(AddressBookString)
try:
FriendTuple = self.robot.CGetFriendList()
self.AddressBook = [dict(i) for i in list(FriendTuple)]
except IndexError:
self.AddressBook = []
return self.AddressBook
def GetFriendList(self):
......
......@@ -4,7 +4,7 @@ namespace wxRobot
{
class Program
{
static void Main(string[] args)
static void Main()
{
System.Type wxProtId = Type.GetTypeFromProgID("WeChatRobot.CWeChatRobot");
if (wxProtId == null)
......@@ -19,6 +19,11 @@ namespace wxRobot
wx.CSendArticle("filehelper","PC微信逆向--获取通讯录", "确定不来看看么?", "https://www.ljczero.top/article/2022/3/13/133.html");
string selfinfo = wx.CGetSelfInfo();
Console.WriteLine(selfinfo);
System.Object[,,] FriendList = wx.CGetFriendList();
int length = FriendList.GetLength(0);
for (int i = 0; i < 1/*length*/; i++) {
Console.WriteLine(FriendList[i, 0, 1]);
}
wx.CStopRobotService();
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册