模拟网页行为之实践篇

无论是模拟网页点击还是直接协议发包,都有其适用的环境。不同的需求选择不同的方案。如果只是简单的获取类似网页IP地址的需求,实际上协议发包是最简单的。但如果是用户名网页登陆等稍微复杂的登陆要求,则直接填写表单,并获取按钮元素来模拟点击这个方案来讲相对简单。但需求若稍微再变化一点,要求效率多线程,这个时候又是协议发包会作为首选,哪怕需要用户名网页登陆。没有最好的方案只有更合适的方案。这点很重要。


先说模拟网页点击方式,一般我采用的是继承MFC里面的CDHtmlDialog类自己命名为CWebLoginDlg,选择MFC并不是说有多好用,而是本人对于MFC使用更熟悉,学习成本更低,仅此而已。

模拟网页逻辑就是个状态机的处理,而状态的获取,一个可以通过获取网页源码判断特征字符串的方式,还有个可以通过XMLHttpRequest的回包判断数据的方式,再有也可以通过获取网页元素com组件对象是否存在的方式。

先说获取网页源码,基本原理是先获取网页DOC对象, 然后遍历DOC里面的元素,找到TAG为html的元素 get_outerHTML,c++代码如下:

std::wstring CWebLoginDlg::GetHtmlSource()
{CComPtr<IHTMLDocument2> sphtmlDoc;CComPtr<IHTMLElementCollection> pIHTMLElementCollect;GetDHtmlDocument(&sphtmlDoc);if (!sphtmlDoc){return L"";}sphtmlDoc->get_all(&pIHTMLElementCollect);long iCount;pIHTMLElementCollect->get_length(&iCount);CComBSTR data;for (int i = 0; i < iCount; i++){CComVariant v3,v4;v3=(long)i;v4.vt=VT_I4;v4=(long)0;CComPtr<IDispatch> pDisp;HRESULT hr = pIHTMLElementCollect->item(v3,v4,&pDisp);if (!SUCCEEDED(hr)){continue;}CComQIPtr<IHTMLElement, &IID_IHTMLElement> pHTMLElement(pDisp);if(pHTMLElement == NULL){continue;}CComBSTR strTagName;hr = pHTMLElement->get_tagName(&strTagName);if(!SUCCEEDED(hr)){continue;}CString strTag=strTagName;strTag.MakeLower();if(strTag!="html"){continue;}hr = pHTMLElement->get_outerHTML(&data);if(!SUCCEEDED(hr)){return L"";}break;}std::wstring source = data.m_str;return source;
}


再说XMLHttpRequest, XMLHttpRequest是对ajax技术的实现,重点体现在包头的Content-Type字段,这个字段值为application/x-www-form-urlencoded,例如网页代码:

function syncGameInfoAgent () {$.ajax({url : "/api/web/syncGameInfoAgent",type : "GET",cache : false,async : false,success : function(data, textStatus, jqXHR) {}});}

这种方式的ajax还会多个X-Requested-With字段,值为XMLHttpRequest,回包数据都为json格式,还有一种网页代码:

var loadLoginInfo = function() {$.ajax({url : getDomain() + "rest/user",type : "GET",data : {"fields" : "isNameCheck,charCount,isBlocked,isGameBlocked,extAccountInfo"},cache : false,async : true,dataType : "jsonp",success : function(response) {  ...

这种方式ajax没有X-Requested_With字段,回包数据为网页数据。c++实现方式如下:

MSXML2::IXMLHTTPRequestPtr m_pIXMLHTTPRequest;m_pIXMLHTTPRequest.CreateInstance("Msxml2.XMLHTTP.6.0");std::wstring CWebLoginDlg::XMLHttpRequest( std::wstring url , std::string requestType/* = "GET"*/)
{BSTR bstrString = NULL;HRESULT hr=m_pIXMLHTTPRequest->open(requestType.c_str(), url.c_str(), false);SUCCEEDED(hr) ? 0 : throw hr;m_pIXMLHTTPRequest->setRequestHeader("X-Requested-With", "XMLHttpRequest"); //这里第二种情况则不能带有此字段m_pIXMLHTTPRequest->setRequestHeader("Content-Type", "application/x-www-form-urlencoded");hr=m_pIXMLHTTPRequest->send();SUCCEEDED(hr) ? 0 : throw hr;bstrString=m_pIXMLHTTPRequest->responseText; //第二种情况则m_pIXMLHTTPRequest->responseBodystd::wstring freePayString = bstrString;if (bstrString){SysFreeString(bstrString);bstrString = NULL;}return freePayString;
}


这里提供一个技巧,找到ajax代码的实现,可以先抓包得到http header里面的request url的url字符串,然后在脚本里面去查找字符串,一般字符串就在ajax代码

url : getDomain() + "rest/user"里面搜索到,搜索到后可以看代码对于返回值的处理,这样才好方便写逻辑。


最后说下获取网页元素,一般来说网页元素都会带有ID或者带有ClassName,例如网页代码:

<input type="password" id="pwd" name="password" class="user_pw" maxlength="16" size="12" autocomplete="off" title="???? ??">

如果想通过ID获取网页对象,简单的可以直接通过GetElement函数来实现,C++代码如下:

IHTMLElement *id = NULL;
this->GetElement(TEXT("id"), &id);
如果想通过ClassName类名来获取网页对象,C++代码如下:

CComQIPtr< IHTMLElement > CWebLoginDlg::GetElementByClassName( std::wstring className )
{CComPtr<IHTMLDocument2> pIHTMLDocument2;GetDHtmlDocument(&pIHTMLDocument2);HRESULT hr;  CComQIPtr< IHTMLElementCollection > spElementCollection;  hr = pIHTMLDocument2->get_all( &spElementCollection ); //取得表单集合  if ( FAILED( hr ) )  {ATLTRACE("获取集合 IHTMLElementCollection 错误");}  long nFormCount=0;hr = spElementCollection->get_length( &nFormCount );  if ( FAILED( hr ) )  {ATLTRACE("获取数目错误");}  IDispatch *pDisp = NULL;CComQIPtr< IHTMLElement > ret = pDisp;for(long i=0; i<nFormCount; i++)  {  pDisp = NULL;hr = spElementCollection->item( CComVariant( i ), CComVariant(), &pDisp );  if ( FAILED( hr ) )  {continue;}CComQIPtr< IHTMLElement > pElement = pDisp;pDisp->Release();CComBSTR varRet;hr = pElement->get_className(&varRet);if (FAILED(hr)){continue;}if (varRet == NULL){continue;}LPCTSTR lpName = OLE2CT( varRet );if (std::wstring(lpName) == className){ret = pElement;break;}}return ret;
}


以上就是模拟网页中获取网页状态的基本函数,有了这几个函数网页模拟方式的基本框架基本都可以搭建起来了。

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

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

相关文章

模拟网页行为之实践篇二

在模拟网页行为中&#xff0c;最常用的就是提交表单了&#xff0c;其次就是获取验证图片数据&#xff0c;再次hook网页中的js代码的实现。 先说具体的应用场景&#xff0c;简单的场景&#xff0c;如填写用户名密码登陆&#xff0c;这里就涉及到获取表单&#xff0c;填写表单数据…

模拟网页行为之实践篇三

现在来谈下验证码图片的获取方式&#xff0c;带有验证码的地方都会附带有个刷新按钮&#xff0c;而刷新按钮的地方就是获取验证码网址代码。如果看过前面写的《模拟网页行为之工具篇》就会很容易定位到代码位置。定位到代码位置后看下图&#xff1a; 基本可以看到的是获取验证码…

调试某游戏副本中的加亮提示信息思路

对于经常玩游戏的人比较容易知道&#xff0c;在副本里面&#xff0c;当进行到某个步骤或者当队员站位触发某个情景时&#xff0c;游戏界面中央会出现字体提示字符&#xff0c;可能是BOSS跟你的对话也有可能是游戏给你的下一步提示。让我们分析下&#xff0c;这个情景到底是本地…

RC4算法实现

1、密钥流&#xff1a;RC4算法的关键是根据明文和密钥生成相应的密钥流&#xff0c;密钥流的长度和明文的长度是对应的&#xff0c;也就是说明文的长度是500字节&#xff0c;那么密钥流也是500字节。当然&#xff0c;加密生成的密文也是500字节&#xff0c;因为密文第i字节明文…

模拟网页行为之实践四

这篇谈下c如何hook网页中的JS函数&#xff0c;即网页可以执行我们修改的JS函数。 相应的步骤可分为&#xff1a; 1.找到需要修改函数的时机。 2.得到需要修改函数的com对象。 3.将我们新的com对象替换修改函数。 第一步&#xff0c;找到需要修改函数的时机&#xff0c;在谈…

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;在数据存储和数据通讯领域&…