模拟网页行为之实践四

这篇谈下c++如何hook网页中的JS函数,即网页可以执行我们修改的JS函数。

相应的步骤可分为:

1.找到需要修改函数的时机。

2.得到需要修改函数的com对象。

3.将我们新的com对象替换修改函数。


第一步,找到需要修改函数的时机,在谈这个问题之前,需要搞清楚JS执行发生在什么时候。

我们知道在网页加载过程中,会根据接收到的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>
在网页加载渲染过程中,本地会逐行解析脚本,css和绘制不是我们这里讨论的,略过,当执行到<scrpt>一行时,网页会停止创建DOM树,开始加载对应的js,加载过程就是把encoder.js和jquery.js里面的对象(也包括函数)会一并创建。如果我们需要修改的js函数在就是在类似的这样的头里面创建的,那么很简单了,我们只要找一个加载点没执行修改函数就行,然后执行我们的第二步。在MFC中,一般考虑OnDocumentComplete函数作为我们修改函数的时机。具体函数实现如下:

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); //得到修改函数的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函数替换修改函数}}if (pDisp == lpWBDisp ){// Top-level Window object, so document has been loadedTRACE("Web document is finished downloading\n");}lpWBDisp->Release();


第二步,得到修改函数的com对象。这里TK_installPage函数就是我们的要修改的函数。首先获取doc对象,然后根据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);
}


第三步,将我们新的com对象替换修改函数。

首先需要构造我们新的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 ){//令人费解的是,网页调用函数的call方法时,没有调用GetIDsOfNames获取call的ID,而是直接调用Invokereturn E_NOTIMPL;}HRESULT _stdcall Invoke(DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS* pDispParams,VARIANT* pVarResult,EXCEPINFO* pExcepInfo,unsigned int* puArgErr){//这里执行我们的替换函数m_pCallback();return S_OK;}
};static void _stdcall button1_onclick()
{ATLTRACE("test");
}


其次,通过com对象的invoke函数进行替换。代码如下:

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);
}

最终效果,在网页在执行TK_installPage函数时候,实际上是执行的我们的函数button1_onclick。





本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/499619.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SHA-256算法实现

SHA-256 算法输入报文的最大长度不超过2^64 bit&#xff0c;输入按512-bit 分组进行处理&#xff0c;产生 的输出是一个256-bit 的报文摘要。该算法处理包括以下几步&#xff1a; STEP1&#xff1a;附加填充比特。对报文进行填充使报文长度与448 模512 同余&#xff08;长度…

RSA算法演绎

RSA是第一个也是使用的最广发的公钥加密算法&#xff0c;在1978年由R.Rivest、AdiShamir和Adleman三人发明&#xff0c;并以他们的名字命名。RSA算法的安全性基于大数因子分解的困难性&#xff0c;下面介绍一下它的基本原理&#xff1a; 1、生成公钥和私钥 (1) 选取两个大素数…

分数的乘法逆元和负数的取模运算

1.乘法逆元 A.定义 如果ax≡1 (mod p),且gcd(a,p)1&#xff08;a与p互质&#xff09;&#xff0c;则称a关于模p的乘法逆元为x。 既然有ax≡1 (mod p)&#xff0c;那么有ax - py 1,x是a关于模p的乘法逆元。 B.分数的乘法逆元 对于实数域&#xff0c;一个数的乘法逆元就是其倒数…

ecc算法入门介绍

一、从平行线谈起。 平行线&#xff0c;永不相交。没有人怀疑把&#xff1a;&#xff09;不过到了近代这个结论遭到了质疑。平行线会不会在很远很远的地方相交了&#xff1f;事实上没有人见到过。所以“平行线&#xff0c;永不相交”只是假设&#xff08;大家想想初中学习的平行…

Intel Hex概述

什么是Intel Hex文件 Intel HEX文件时遵循Intel HEX文件格式的ASCII文本文件。在Intel HEX文件的每一行都包含了 一个HEX记录。这些记录是由一些代表机器语言代码和常量的16进制数据组成的。Intel HEX文件常用来传输要存储在ROM 或者 EPROM中的程序和数据。大部分的EPROM编程器…

AndroidStudio+ideasmali动态调试smali汇编

0x00 前言 之前对于app反编译的smali汇编语言都是静态分析为主&#xff0c;加上一点ida6.6的动态调试&#xff0c;但是ida的调试smali真的像鸡肋一样&#xff0c;各种不爽&#xff0c;遇到混淆过的java代码就欲哭无泪了。后来知道IDEA用一款插件也可以实现smali的动态调试&a…

使用IDA Pro动态调试SO文件

&#xff08;1&#xff09;在IDA的安装路径中找到android_server文件。 &#xff08;2&#xff09;将android_server拷贝到手机的/data/local/tmp目录下面。 &#xff08;3&#xff09; 将手机插上电脑&#xff0c;打开命令提示符&#xff0c; 先输入”adb shell”,然后输入”…

c#调用c++dll接口及回调函数

在合作开发时&#xff0c;C#时常需要调用CDLL&#xff0c;当传递参数时时常遇到问题&#xff0c;尤其是传递和返回字符串是&#xff0c;现总结一下&#xff0c;分享给大家&#xff1a;VC中主要字符串类型为&#xff1a;LPSTR,LPCSTR, LPCTSTR, string, CString, LPCWSTR, LPWST…

机器学习或深度学习的数据读取工作(大数据处理)

机器学习或深度学习的数据读取工作&#xff08;大数据处理&#xff09;主要是.split和re.findall和glob.glob运用。 读取文件的路径&#xff08;为了获得文件内容&#xff09;和提取文件路径中感兴趣的东西(标签) 1&#xff0c;“glob.glob”用于读取文件路径 2&#xff0c;“.…

windows平台下的反调试技术

在调试一些病毒程序的时候&#xff0c;可能会碰到一些反调试技术&#xff0c;也就是说&#xff0c;被调试的程序可以检测到自己是否被调试器附加了&#xff0c;如果探知自己正在被调试&#xff0c;肯定是有人试图反汇编啦之类的方法破解自己。为了了解如何破解反调试技术&#…

SQLite加解密

0x00 SQLite概述 SQLite是一个轻量级、跨平台的&#xff0c;开源的数据库引擎&#xff0c;它在读写效率&#xff0c;消耗总量、延迟时间和整体简单性上具有的优越性&#xff0c;使其成为移动平台数据库的最佳解决方案。 然而免费版的SQLite有一个致命缺点&#xff1a;不支持加…

android和linux操作系统的区别

Android是由Google为移动设备开发的开源操作系统。Android软件的原始开发商Android公司是由Google&#xff0c;Inc.于2005年购买的。它是基于Linux 2.6内核开发的。Linux操作系统于1991年由Linus Torvalds作为台式计算机的开源操作系统开发。Linux操作系统是作为MINIX操作系统开…

Android系统架构图

一、Aplications&#xff08;应用层&#xff09; 应用是用Java语言编写的云新在虚拟机上的程序。 二、Application Framework&#xff08;应用框架层&#xff09; 这一层是编写Google发布的核心应用时所使用的API框架&#xff0c;开发人员可以使用这些框架来开发自己的应用。 V…

SHA1算法实现及详解

1 SHA1算法简介 安全哈希算法&#xff08;Secure Hash Algorithm&#xff09;主要适用于数字签名标准&#xff08;Digital Signature Standard DSS&#xff09;里面定义的数字签名算法&#xff08;Digital Signature Algorithm DSA&#xff09;。对于长度小于2^64位的消息&…

CRC32算法实现

CRC32 检错能力极强&#xff0c;开销小&#xff0c;易于用编码器及检测电路实现。从其检错能力来看&#xff0c;它所不能发现的错误的几率仅为0.0047%以下。从性能上和开销上考虑&#xff0c;均远远优于奇偶校验及算术和校验等方式。因而&#xff0c;在数据存储和数据通讯领域&…

AES算法重点详解和实现

可以看到&#xff0c;在原始数据长度为16的整数倍时&#xff0c;假如原始数据长度等于16*n&#xff0c;则使用NoPadding时加密后数据长度等于16*n&#xff0c;其它情况下加密数据长度等于16*(n1)。在不足16的整数倍的情况下&#xff0c;假如原始数据长度等于16*nm[其中m小于16]…

protobuf流的反解析Message

0x01 protobuf的基本概念 protobuf通过定义".proto"文件来描述数据的结构。.proto文件中用"Message"所表示所需要序列化的数据的格式。Message由field组成&#xff0c;Field类似JAVA或者C中成员变量&#xff0c;通常一个field的定义包含修饰符、类型、名称…

勒索病毒傀儡进程脱壳

样本是&#xff1a;wallet勒索病毒 环境&#xff1a;虚拟机VMWARE win7 32位 工具&#xff1a;OD&#xff0c;winhex 初次拿到样本&#xff0c;先用火绒剑工具监控下病毒样本的流程&#xff0c;可以看到有一个自创建进程的行为。 我们等找到OEP后&#xff0c;在CreateProcessA下…

arm64动态链接库通过函数名获取函数偏移

基本思路是分析elf文件, 首先遍历节区头部Elf32_Shdr查看sh_type属性值&#xff0c;得到属性值为SHT_DYNSYM的节区。 其次通过名字遍历节区结点&#xff0c;找到类型为STT_FUNC并且名字与其相同的结点。 代码如下&#xff1a; static void * xmalloc(size_t size) {void *p…

arm32和arm64常用指令B BL BLX机器码计算

现在大部分手机cpu架构是ARM v7-A和ARMV8-A,&#xff0c;在ARM-v7A中常使用32位ARM指令集并且支持thumb指令集与arm的切换&#xff0c;而在ARMV8中使用的是64位ARM指令集且不再有thumb指令集状态的切换了。在调用函数时&#xff0c;会有常用的调用方式&#xff1a;BL和B&#x…