看雪论坛
发新帖

[原创]pc端微信逆向分析

tongzeyu 2017-9-1 13:56 5044

关键字: 微信、duilib库hook,duilib模拟点击。


最近有朋友问我libcef如何注入js,然后又谈到微信用了libcef云云。

捣腾了一下午,知道怎么注入js后,发现朋友是需要auto control ui

瞬间崩溃。。。。

诚然微信有些浏览器功能用到了cef,但是主界面是duilib写的

跟cef没毛关系,(libcef封装到qbcore.dll里面,想注入js需要hook libcef的导出函数

拿到browser,替换callback……)


话题回到pc端微信怎么auto control ui,以及如何拿到”控件“上面的信息


下面为原理截图,看不懂请参考duilib源码


CWindowWnd 指针可以通过GetWindowLongPtr获取



CWindowWnd指针 == WindowImplBase指针

然后通过

static_cast<INotifyUI *>(pWinImplBase)

转换得到INotifyUI指针,再通过虚函数地址表就能找到Notify指针

最后替换Notify指针就能监控到所有duilib事件了


事件结构体,pSender是事件的触发者,我们后面通过获取root节点就能得到所有CControlUI

这个结构我们可以伪造出来,然后直接调用原始Notify回调就能模拟界面操作了


每一个xml创建CControlUI 树的时候,都会调用CDialogBuilder::Create

我们通过hook这个函数,返回就能得到root节点

这里是duilib的container节点原理,如果父亲是一个容器节点,就把自己添加到父亲里面


得到节点树之后,我们需要枚举所有节点

看看这些虚函数是不是很可爱,很方便,有没有想到com技术

这个虚函数更可爱,哈哈

可爱到我不需要判断数量,只需要判断结果是否为NULL就能知道是否枚举结束


原理图都贴了,最好自己看看duilib源码,pc端微信界面是duilib写的,基本的虚函数偏移没有变化,说明腾讯没有大改动duilib(添加虚函数)

当然,我发现有些结构被改动过,这里就不提了。

关于duilib的消息流动,自己可以好好看看源码。


以下为部分代码,自行完成完整版

//hook CDialogBuilder::Create
/*
CControlUI* CDialogBuilder::Create(IDialogBuilderCallback* pCallback, CPaintManagerUI* pManager, CControlUI* pParent)
*/
VOID WINAPI CDialogBuilder_Create_Ret(CControlUI* pControlUI)
{
	TRACE_LOG_INFO(_T("CDialogBuilder::Create Ret ..."));
	if (pControlUI)
		enumContainer(pControlUI);
}
//遍历控件的信息
void enumContainer(CControlUI * pControlUI)
{
	LPCTSTR lpcszClass = pControlUI->GetClass();
	LPCTSTR lpcszName = pControlUI->GetName();
	LPCTSTR lpcszText = pControlUI->GetText();
	if (lpcszClass)
		TRACE_LOG_INFO(_T("%s"), lpcszClass);
	if (lpcszName)
		TRACE_LOG_INFO(_T("%s"), lpcszName);
	if (lpcszText)
		TRACE_LOG_INFO(_T("%s"), lpcszText);
	if (CDuiString(_T("session_list")) == pControlUI->GetName())
	{
		g_session_list = pControlUI;
	}
	if (CDuiString(_T("contact_list")) == pControlUI->GetName())
	{
		g_contact_list = pControlUI;
	}
	
	IContainerUI *pContainerUI = static_cast<IContainerUI *>(pControlUI->GetInterface(_T("IContainer")));
	if (pContainerUI)
	{
		int i = 0;
		CControlUI * pControlIter = NULL;
		while (pControlIter = pContainerUI->GetItemAt(i++))
		{
			enumContainer(pControlIter);
		}
	}
}
//hook event notify
class CHookNotify : INotifyUI
{
public:
	typedef void(CHookNotify::*pfn_Notify)(TNotifyUI& msg);
	void Notify(TNotifyUI& msg)
	{
		extern CHookNotify::pfn_Notify g_pfn_oldnotify;
		
		
		return (this->*g_pfn_oldnotify)(msg);
	}
};
CHookNotify::pfn_Notify g_pfn_oldnotify = NULL;
DWORD WINAPI test_thread(
	LPVOID lpThreadParameter
	)
{
	MessageBox(NULL, NULL, NULL, MB_OK);
	HWND hMainWnd = FindWindow(_T("WeChatMainWndForPC"), NULL);
	if (!hMainWnd)
	{
		TRACE_LOG_INFO(_T("%s"), _T("FindWindow Error ..."));
		return 0;
	}
	CWindowWnd *pThis = reinterpret_cast<CWindowWnd*>(::GetWindowLongPtr(hMainWnd, GWLP_USERDATA));
	if (!pThis)
	{
		TRACE_LOG_INFO(_T("%s"), _T("Get CWindowWnd Pointer Error ..."));
		return 0;
	}
	HWND *phWnd = reinterpret_cast<HWND *>(((uintptr_t)pThis + sizeof(uintptr_t)));
	if (IsBadReadPtr(phWnd, sizeof(HWND)))
	{
		TRACE_LOG_INFO(_T("%s"), _T("Pointer Invalid Error ..."));
		return 0;
	}
	if (*phWnd != hMainWnd)
	{
		TRACE_LOG_INFO(_T("%s"), _T("Invalid CWindowWnd Pointer Error ..."));
		return 0;
	}
	//WindowImplBase * == CWindowWnd *
	WindowImplBase *pWinImplBase = reinterpret_cast<WindowImplBase *>(pThis);
	INotifyUI *pNotifyThis = static_cast<INotifyUI *>(pWinImplBase);
	CHookNotify::pfn_Notify *p_pfn_oldnotify = *reinterpret_cast<CHookNotify::pfn_Notify **>(pNotifyThis);
	//set virtual table hook
	g_pfn_oldnotify = *p_pfn_oldnotify;
	CHookNotify::pfn_Notify temp;
	__asm push CHookNotify::Notify;
	__asm pop temp;
	DWORD dwOldProtect = 0;
	VirtualProtect(p_pfn_oldnotify, sizeof(void *), PAGE_EXECUTE_READWRITE, &dwOldProtect);
	*p_pfn_oldnotify = temp;

	return 0;
}

最后来一张效果图


本主题帖已收到 1 次赞赏,累计¥1.00
最新回复 (31)
zhhigh 2017-9-1 16:00
2
牛,谢谢大神
coolsnake 2017-9-1 16:28
3
非常感谢。
cattyabcd 2017-9-2 12:11
4
大神能否给出完整源码以供学习
川美 2017-9-2 14:48
5
高级的编程,分析得很到位
saloyun 2017-9-2 16:08
6
1.发送和接收人的帐号信息没有。
2.发送和接收敏感消息或文件时,没有办法阻断。
3.切换Tab时没办法对消息去重。
4.没办法群发消息,或发消息给指定的账户。

从UI入手,能实现的效果实在有限的。
hanhaochi 2017-9-4 10:57
7
就服你这个马赛克
zhousilai 2017-9-4 18:43
8
学习了
youxiaxy 2017-9-4 19:16
9
就服你这个马赛克
MaYil 2017-9-5 10:20
10
竟然还有这种操作
Rookietp 2017-9-5 17:52
11
它内存中应该有类似的结构体吗?
聖blue 2017-9-5 21:20
12
不错!!!!!!
wx_XL 2017-9-5 23:46
13
接反编译码...  报酬高  有意16588427
livewonder 2017-9-6 09:06
14
PC微信用的是duilib,没有大改,也是醉了。           
2
地狱怪客 2017-9-6 17:03
15
厉害看到了mj...
tongzeyu 2017-9-7 11:01
16
livewonder PC微信用的是duilib,没有大改,也是醉了。
是的,不过还是有些改动,有些虚函数偏移也变化了,成员变量偏移也变化了
tongzeyu 2017-9-7 11:03
17
Rookietp 它内存中应该有类似的结构体吗?
界面上的数据显示,应该都是存放在自己定义的结构里面,然后这些结构的制作应该会存放在ui的一些保留位置,方便显示
tongzeyu 2017-9-7 11:04
18
saloyun 1.发送和接收人的帐号信息没有。 2.发送和接收敏感消息或文件时,没有办法阻断。 3.切换Tab时没办法对消息去重。 4.没办法群发消息,或发消息给指定的账户。 从UI入手,能实现的效果实 ...
老司机开车了
wx_ _438180 2017-9-8 07:22
19
basketwill 2017-9-8 09:02
20
tongzeyu 界面上的数据显示,应该都是存放在自己定义的结构里面,然后这些结构的制作应该会存放在ui的一些保留位置,方便显示
pc端微信内存结构我已经分析出来了。。。并且劫持了
iceway 2017-9-10 01:47
21
......我丢,根本不用HOOK  cef。你直接编译一个官方的cefdll替换他的,然后它微信就自动变成ie内核的了,随便i搞了
wx_dl 2017-9-10 08:01
22
有能解决的联系我,付费
tongzeyu 2017-9-10 17:44
23
iceway ......我丢,根本不用HOOK cef。你直接编译一个官方的cefdll替换他的,然后它微信就自动变成ie内核的了,随便i搞了
cef不能替换的,静态编译进去了,就算能替换,跟ie核也没有半毛钱关系
冷域 2017-9-10 20:41
24
反正我就没完全看懂,没办法技术积累不够
zhuangbx 2017-9-10 21:36
25
非常感谢,正在也想研究它
lynxtang 2017-9-10 23:25
26
好高级的马赛克,哈哈
wx_岁月无声 2017-9-11 23:13
27
顶,求代码!
PPTV 2017-9-11 23:14
28
直接分析内存数据可能更简单强大,好像也比这难不了多少吧,那帮子人早就想到开源库容易破解,所以微信PC端的很多功能都没有
wpsys 2017-9-13 10:32
29
谢谢分享!学习了!
gogogoyouxi 2017-9-16 08:24
30
高人们,请问有搞定协议的吗
npnp 2017-9-16 13:26
31
谢谢分享!学习了!
clong 6天前
32
学习一下,感谢分享!
返回



©2000-2017 看雪学院 | Based on Xiuno BBS | 域名 加速乐 保护 | SSL证书 又拍云 提供 | 微信公众号:ikanxue
Time: 0.017, SQL: 16 / 京ICP备10040895号-17