模拟网页行为之实践四
生活随笔
收集整理的這篇文章主要介紹了
模拟网页行为之实践四
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
這篇談下c++如何hook網(wǎng)頁中的JS函數(shù),即網(wǎng)頁可以執(zhí)行我們修改的JS函數(shù)。
相應的步驟可分為:
1.找到需要修改函數(shù)的時機。
2.得到需要修改函數(shù)的com對象。
3.將我們新的com對象替換修改函數(shù)。
第一步,找到需要修改函數(shù)的時機,在談這個問題之前,需要搞清楚JS執(zhí)行發(fā)生在什么時候。
我們知道在網(wǎng)頁加載過程中,會根據(jù)接收到的html文本,去解析對應里面的腳本和樣式以及js。
譬如:
<head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>了解html頁面的渲染過程 - yuezk - 博客園</title> <link type="text/css" rel="stylesheet" href="/bundles/blog-common.css?v=Rdf1BBttS5_qVaET1myrajVTd62BSCCoJA9fZxGv1ZM1"> <link id="MainCss" type="text/css" rel="stylesheet" href="/skins/LessIsMoreRight/bundle-LessIsMoreRight.css?v=XnHJrmT6UJMtyGfeJjiTUm7BxKWcwdJrxKsGy7z3YZ81"> <link id="mobile-style" media="only screen and (max-width: 768px)" type="text/css" rel="stylesheet" href="/skins/LessIsMoreRight/bundle-LessIsMoreRight-mobile.css?v=9qDppl1UU68AUflWXI5a_NeoqamVC_84o7AG1HNc4Pg1"> <link title="RSS" type="application/rss+xml" rel="alternate" href="http://www.cnblogs.com/yuezk/rss"> <link title="RSD" type="application/rsd+xml" rel="EditURI" href="http://www.cnblogs.com/yuezk/rsd.xml"> <link type="application/wlwmanifest+xml" rel="wlwmanifest" href="http://www.cnblogs.com/yuezk/wlwmanifest.xml"> <script type="text/javascript" src="http://common.cnblogs.com/script/encoder.js"></script><script src="//common.cnblogs.com/script/jquery.js" type="text/javascript"></script> <script type="text/javascript">var currentBlogApp = 'yuezk', cb_enable_mathjax=false;var isLogined=false;</script> <script src="/bundles/blog-common.js?v=hH1lCMV8WaIu271Nx7jPuv36TENW9-RsSxziLxUpjtc1" type="text/javascript"></script> </head>在網(wǎng)頁加載渲染過程中,本地會逐行解析腳本,css和繪制不是我們這里討論的,略過,當執(zhí)行到<scrpt>一行時,網(wǎng)頁會停止創(chuàng)建DOM樹,開始加載對應的js,加載過程就是把encoder.js和jquery.js里面的對象(也包括函數(shù))會一并創(chuàng)建。如果我們需要修改的js函數(shù)在就是在類似的這樣的頭里面創(chuàng)建的,那么很簡單了,我們只要找一個加載點沒執(zhí)行修改函數(shù)就行,然后執(zhí)行我們的第二步。在MFC中,一般考慮OnDocumentComplete函數(shù)作為我們修改函數(shù)的時機。具體函數(shù)實現(xiàn)如下:void CWebLoginDlg::OnDocumentComplete(LPDISPATCH pDisp, LPCTSTR szUrl) {CDHtmlDialog::OnDocumentComplete(pDisp, szUrl);// TODO: Add your specialized code here and/or call the base classIUnknown* pUnk;LPDISPATCH lpWBDisp;HRESULT hr;pUnk = m_wndBrowser.GetControlUnknown();ASSERT(pUnk);hr = pUnk->QueryInterface(IID_IDispatch, (void**)&lpWBDisp);ASSERT(SUCCEEDED(hr));CComPtr<IHTMLDocument2> sphtmlDoc;GetDHtmlDocument(&sphtmlDoc);if (sphtmlDoc != NULL){CWebPage web;VARIANT testV;web.SetDocument(sphtmlDoc);CComPtr<IDispatch> pDispatch = NULL;web.GetJScript(pDispatch);HRESULT result = GetProperty(pDispatch, L"TK_installPage", &testV); //得到修改函數(shù)的com對象if (result == S_OK){VARIANT params;params.vt = VT_DISPATCH;params.pdispVal = new JsFunction(button1_onclick);result = SetProperty(pDispatch, L"TK_installPage", ?ms);//將我們的button1_onclick函數(shù)替換修改函數(shù)}}if (pDisp == lpWBDisp ){// Top-level Window object, so document has been loadedTRACE("Web document is finished downloading\n");}lpWBDisp->Release();
第二步,得到修改函數(shù)的com對象。這里TK_installPage函數(shù)就是我們的要修改的函數(shù)。首先獲取doc對象,然后根據(jù)doc對象通過GetJScript獲得腳本對象,再次在腳本對象上通過名字TK_installPage得到js對象。具體代碼如下:
bool CWebPage::SetDocument(IDispatch* pDisp) {CHECK_POINTER(pDisp);m_spDoc = NULL;CComPtr<IDispatch> spDisp = pDisp;HRESULT hr = spDisp->QueryInterface(IID_IHTMLDocument2,(void**)&m_spDoc);if(FAILED(hr)){ShowError(L"Failed to get HTML document COM object");return false;}return true; }bool CWebPage::GetJScript(CComPtr<IDispatch>& spDisp) {CHECK_POINTER(m_spDoc);HRESULT hr = m_spDoc->get_Script(&spDisp);ATLASSERT(SUCCEEDED(hr));return SUCCEEDED(hr); }DISPID CWebLoginDlg::FindId( IDispatch *pObj, LPOLESTR pName ) {DISPID id = 0;if(FAILED(pObj->GetIDsOfNames(IID_NULL,&pName,1,LOCALE_SYSTEM_DEFAULT,&id))) id = -1;return id; }HRESULT CWebLoginDlg::GetProperty( IDispatch *pObj, LPOLESTR pName, VARIANT *pValue ) {DISPID dispid = FindId(pObj, pName);if(dispid == -1) return E_FAIL;DISPPARAMS ps;ps.cArgs = 0;ps.rgvarg = NULL;ps.cNamedArgs = 0;ps.rgdispidNamedArgs = NULL;return pObj->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &ps, pValue, NULL, NULL); }
首先需要構(gòu)造我們新的com對象,
typedef void _stdcall JsFunction_Callback();class JsFunction:public IDispatch {long _refNum;JsFunction_Callback *m_pCallback; public:JsFunction(JsFunction_Callback *pCallback){_refNum = 1;m_pCallback = pCallback;}~JsFunction(void){} public:// IUnknown MethodsSTDMETHODIMP QueryInterface(REFIID iid,void**ppvObject){*ppvObject = NULL;if (iid == IID_IOleClientSite) *ppvObject = (IOleClientSite*)this;else if (iid == IID_IUnknown) *ppvObject = this;if(*ppvObject){AddRef();return S_OK;}return E_NOINTERFACE;}STDMETHODIMP_(ULONG) AddRef(){return ::InterlockedIncrement(&_refNum);}STDMETHODIMP_(ULONG) Release(){::InterlockedDecrement(&_refNum);if(_refNum == 0){delete this;}return _refNum;}// IDispatch MethodsHRESULT _stdcall GetTypeInfoCount(unsigned int * pctinfo) {return E_NOTIMPL;}HRESULT _stdcall GetTypeInfo(unsigned int iTInfo,LCID lcid,ITypeInfo FAR* FAR* ppTInfo) {return E_NOTIMPL;}HRESULT _stdcall GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgDispId ){//令人費解的是,網(wǎng)頁調(diào)用函數(shù)的call方法時,沒有調(diào)用GetIDsOfNames獲取call的ID,而是直接調(diào)用Invokereturn E_NOTIMPL;}HRESULT _stdcall Invoke(DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS* pDispParams,VARIANT* pVarResult,EXCEPINFO* pExcepInfo,unsigned int* puArgErr){//這里執(zhí)行我們的替換函數(shù)m_pCallback();return S_OK;} };static void _stdcall button1_onclick() {ATLTRACE("test"); }
其次,通過com對象的invoke函數(shù)進行替換。代碼如下:
HRESULT CWebLoginDlg::SetProperty( IDispatch *pObj, LPOLESTR pName, VARIANT *pValue ) {DISPID dispid = FindId(pObj, pName);if(dispid == -1) return E_FAIL;DISPID dispidNamed = DISPID_PROPERTYPUT;DISPPARAMS ps;ps.cArgs = 1;ps.rgvarg = pValue;ps.cNamedArgs = 1;ps.rgdispidNamedArgs = &dispidNamed;return pObj->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYPUT, &ps, NULL, NULL, NULL); }最終效果,在網(wǎng)頁在執(zhí)行TK_installPage函數(shù)時候,實際上是執(zhí)行的我們的函數(shù)button1_onclick。
總結(jié)
以上是生活随笔為你收集整理的模拟网页行为之实践四的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: STM32的ADC通道间干扰的问题
- 下一篇: 奇妙的安全旅行之国密算法