PC 端微信逆向分析
關鍵字: 微信、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指標,再透過虛擬函式地址表就能找到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
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
if (!pThis)
{
TRACE_LOG_INFO(_T(“%s”), _T(“Get CWindowWnd Pointer Error 。。。”));
return 0;
}
HWND *phWnd = reinterpret_cast
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
INotifyUI *pNotifyThis = static_cast
CHookNotify::pfn_Notify *p_pfn_oldnotify = *reinterpret_cast
//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;
}
最後來一張效果圖
本文由看雪論壇 tongzeyu 原創 轉載請註明來自看雪社群
上一篇:在考編這條路,還應該繼續堅持嘛?
下一篇:請問電渣壓力焊是壓焊還是熔焊?