网上投票作弊的技术实现(纯技术交流,勿用作他途!!)

原创 2002年01月10日 14:27:00

申明:纯技术交流,勿用作他途!!

    文章中所讨论的技术应用范围其实还是比较广的,除了投票这种比较阴的应用,还可以完成比如自动填写表单、邮箱自动申请、网站注册等功能。

    这里提供的方法有两种:

        方法1: 通过IE控件提供的COM接口实现。这种方法是通过IHTMLDocument2接口编辑网页表单(有时得修改网页代码),然后触发一个事件提交网页。 这种方法由于使用了IE控件,打开网页时会下载很多与应用无关的数据,如图片等(当然你可以在IE中把图片之类的选项关掉),效率很低,而且每投一票就得开一个IE控件,如果你的机子差些,等着按Reset吧~~。另外,这种方法编码比较多,挺烦。

        方法2: 通过WinInet API来实现表单提交的工作。这种方法要比前面那种方法高明多了,不但执行效率高,耗资源少,而且具体实现起来也比上一种简单。

    下面分别把两种方法介绍一下:

        方法1:通过IE控件提供的COM接口实现

       1、我的程序是基于对话框的,不是用的HtmlView,所以要先在对话框上放一个IE控件(Insert ActiveX Control,里面有一个Microsoft Web浏览器),给这个IE控件起个名字,比如m_ctrlWeb。另外要记着加上<mshtml.h>头文件,IE COM接口的东西都在里面放着。<comdef.h>和<atlbase.h>如果没有的话也要加上。

       2、用ClassWizard加入DownloadComplete事件的响应,这样网页下载完了你就可以做填表单之类的工作了。当然你也可以在ProgressChange之类的事件中作这些操作了,不过这样你就得判断网页是不是差不多下载到合适的位置了,要图省事,直接用DownloadComplete算了。

       3、下一步就是用这个控件打开目标网页了,什么时候打开你自己看着办,我是在InitDialog里面打开的,代码如下:
    COleVariant vaUrl="http://www.onlytest.net";
    m_ctrlWeb.Navigate2(&vaUrl, &vtMissing, &vtMissing, &vtMissing, &vtMissing);
    其中那个vtMissing是用作缺省参数的。

       4、然后就是主要的操作了。这些操作都放在OnDownloadCompleteExplorer里。为了方便,我写了几个函数用来完成特定的功能,在具体说明OnDownloadCompleteExplorer中进行的操作之前,先把这几个函数解释一下。

            //功能:判断网页里是不是有strName指定的元素
            //参数: pobjAllElement:网页中所有元素的集合
            // strName:网页中元素的id或name
           bool HasItem(IHTMLElementCollection *pobjAllElement,CString strName)
           {
               CComPtr<IDispatch>pDisp;
               pobjAllElement->item(COleVariant(strName),COleVariant((long)0),&pDisp);
               if(pDisp==NULL)
                   return false;
               else
                   return true;
           }

            //功能:在网页的文本框中输入字符串
            //参数: pobjAllElement:网页中所有元素的集合
            // strName:要编辑的文本框的id或name
            // strText:要在文本框中写入的内容
           void PutIEText(IHTMLElementCollection *pobjAllElement,CString strName,CString strText)
           {
               CComPtr pDisp;
                pobjAllElement->item(COleVariant(strName),COleVariant((long)0),&pDisp);
                CComQIPtr pElement;
                if(pDisp==NULL)
                {
                    AfxMessageBox(strName + "没有找到!");
                }
                else
                {
                    pElement=pDisp;
                    pElement->put_value(strText.AllocSysString());
                }
            }

            //功能:提交一个网页的Form
            //参数: pobjAllElement:网页中所有元素的集合
            // strName:可以提交Form的按钮的id或name(也可以直接Form的submit提交)
           void SubmitPage(IHTMLElementCollection *pobjAllElement,CString strName)
           {
               CComPtrpDisp;
               pobjAllElement->item(COleVariant(strName),COleVariant((long)0),&pDisp);
               CComQIPtrpElement;
               if(pDisp==NULL)
               {
                   AfxMessageBox(strName + "没有找到!");
               }
               else
               {
                    pElement=pDisp;
                    pElement->click();
               }
            }

            //功能:选中网页中的一个CheckBox (其实就是点击)
            //参数: pobjAllElement:网页中所有元素的集合
            // strName:要选中的CheckBox的id或name
           void CheckItem(IHTMLElementCollection *pobjAllElement,CString strName)
           {
               CComPtr pDisp;
               pobjAllElement->item(COleVariant(strName),COleVariant((long)0),&pDisp);
               CComQIPtr<IHTMLElement, &IID_IHTMLElement>pElement;
               if(pDisp==NULL)
               {
                   AfxMessageBox(strName + "没有找到!");
               }
               else
               {
                   pElement=pDisp;
                   pElement->click();
               }
           }
使用这几个函数可以很轻松地完成投票操作。下面列出OnDownloadCompleteExplorer中的代码。
另假设投票页面为http://www.onlytest.com/vote.htm,数据提交到http://www.onlytest.com /vote2.asp
void CVoteDlg::OnDownloadCompleteExplorer()
{
    // TODO: Add your control notification handler code here
    IHTMLElementCollection *objAllElement=NULL;
    IHTMLDocument2 *objDocument=NULL;
    CString strUrl,strTemp;
    strUrl=m_ctrlWeb.GetLocationURL();//得到当前网页的URL
    if(strUrl.IsEmpty())
        return;
    objDocument=(IHTMLDocument2 *)m_ctrlWeb.GetDocument(); //由控件得到IHTMLDocument2接口指针
    objDocument->get_all(&objAllElement); //得到网页所有元素的集合
    //由于所有页面下载完后都会执行这个函数,所以必须根据URL判断消息来源网页
    if(strUrl=="http://www.onlytest.com/vote.htm")
    {
        CComPtr<IDispatch>pDisp;
        if(HasItem(objAllElement,"voteform")==true) //voteform为投票选项所在的Form
        {
            objAllElement->item(COleVariant("voteform"),COleVariant((long)0),&pDisp);
            CComQIPtr<IHTMLFormElement , &IID_IHTMLFormElement >pElement;
            if(pDisp==NULL)
            {
                //接口指针获取失败,结束程序,不另外作处理,原因见后
                EndDialog(IDOK);
                return;
            }
            else
            {
                //如果投票结果在新窗口打开,则应该修改网页代码,让结果在本控件中显示
                pElement=pDisp;
                pElement->put_target(CComBSTR("_self")); //等效于target="_self"
                pElement->put_action(CComBSTR("vote2.asp"));//等效于action="vote2.asp"
            }
            CheckItem(objAllElement,"chk2"); //将form中id为chk2的CheckBox选中
            SubmitPage(objAllElement,"vote"); //提交网页,vote为submit按钮的id或name
        }
    }
    else if(strUrl=="http://www.onlytest.com/vote2.asp")
    {
        EndDialog(IDOK); //如果投票处理页面已经下载完毕,则结束程序,原因见后。
    }
}

现在票已经投出去了,但看过程序你可能会奇怪,为什么投完票或中间出了错要用EndDialog结束程序,而不是继续投票呢?事情是这样的,有些网站一个session只能投一票,而一个IE控件创建好,与服务器连接后(有了Session),那个Session Key就定好了(一家之言),所以如果继续用这个IE控件投票,服务器会告诉你你已经投过票了(当然如果投票程序写的笨,没管这个,那就简单多了)。这个问题本来我想通过分析WinInet API的运行过程对付的,可是好像很麻烦,所以用了一个很笨的但简单的方法:投票程序作为一个程序,然后另一个程序调用这个投票程序,投完票后投票程序结束,主程序再次运行投票程序,如此反复。至于投票程序数量的限制之类的东西,用共享内存段是最简单的(一家之言),具体就不在这里讨论了。


        方法2:通过WinInet API来实现表单提交的工作

    这种方法实现代码量很少,而且由于不需要下载太多的无用数据(如图片等),form所在的页面也不需要下载,所以效率要高得多,另外实现代码是一个函数,很适合用在线程中。
    用这种方法关键是要知道应该给服务器提交些什么数据如果自己去看网页文件,然后分析应该向服务器提交什么数据,网页很简单时还差不多,如果网页很复杂,那就属于费力不讨好的事。现在不是考试,那种事情我们就不做了,现在有一个更简单的办法,就是用Win2000下的网络监视器,手工投一票看看向服务器提交了些什么数据。这样我们就可以把那数据中属于HTTP协议的部分Copy下来。直接从监视器里拷出来的数据是没法用的,因为监视器显示文本的部分把回车换行之类的字符都用小数点代替了,这些部分要先改回原来的回车、换行(HTTP头部分的就可以不用管了,只要你能分清边界就可以了)。另外注意,提交信息中可能会有Content-Length这个信息,如果你修改了提交数据的内容,而且数据长度发生了变化,Content-Length项的值一定要跟着改。比如Content-Length原来的值是100,数据中有一条数据“1”,你现在改成了“12”,则Content-Length一定要改成101,否则服务器会返回错误。

下面列出的就是投票函数:
UINT Vote(LPVOID)
{
    CInternetSession session;
    theApp.m_nThreads++; //用来记录投票线程数的
    try
    {
        CHttpConnection* pConnection =session.GetHttpConnection("www.onlytest.net"); //网站服务器
        CHttpFile* pFile = pConnection->OpenRequest(CHttpConnection::HTTP_VERB_POST,"vote2.asp"); //直接向投票处理页面提交数据
        //下面向提交数据中添加HTTP头,这些可以由网络监视器得到
        pFile->AddRequestHeaders("Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */*");
        pFile->AddRequestHeaders("Referer: http://www.onlytest.net/vote.htm");
        pFile->AddRequestHeaders("Accept-Language: zh-cn");
        pFile->AddRequestHeaders("Content-Type: multipart/form-data; boundary=---------------------------7d11dc24268052c");
        pFile->AddRequestHeaders("Accept-Encoding: gzip, deflate");
        pFile->AddRequestHeaders("User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)");
        pFile->AddRequestHeaders("Content-Length: 1351");
        pFile->AddRequestHeaders("Connection: Keep-Alive");
        pFile->AddRequestHeaders("Cache-Control: no-cache");
        //HTTP头后面就应该是真正的数据了,下面theApp.m_strFormData中就是要提交的数据,服务器处理返回的信息在pFile中
        pFile->SendRequest(NULL,0,theApp.m_strFormData.GetBuffer(0),theApp.m_strFormData.GetLength()); //提交所有数据


        //其实到这里投票已经可以结束了,不过你如果想看看成果,完全可以把返回的页面分析分析,得到些数据
        char szBuffer[11001]; //用来存放返回的处理页面,要多大看实际情况。当然也可以动态分配,不嫌累的话
        int nLen=pFile->Read(szBuffer,11000);//读取返回的内容,其实是投票结果页面的HTML代码
        szBuffer[nLen]=0;
        CString strTemp=szBuffer; //CString虽然滥了些,但用着就是方便,嘿嘿~
        pFile->Close(); //数据读出来后把该关闭的东西都关掉
        pConnection->Close();
        delete pFile;
        delete pConnection;
        session.Close();
        //下面的代码就是用来分析HTML代码来得到你感兴趣的数据了,和投票没什么关系,就不详细解释了
        int nPos=strTemp.Find("选项A");
        int nTempPos=nPos;
        if(nPos==-1)
        {
            theApp.m_nThreads--;
            return 0;
        }
        nPos=strTemp.Find("table width=100><tr><td align=right>",nPos)+36;
        int nEndPos=strTemp.Find("票",nPos);
        m_nOurNum=atoi(strTemp.Mid(nPos,nEndPos-nPos));
        nPos=strTemp.Find("<tr bgcolor=#DEE6EB><td align=center width=50>1</td>");
        nPos=strTemp.Find("table width=100><tr><td align=right>",nPos)+36;
        nEndPos=strTemp.Find("票",nPos);
        m_nDiff=atoi(strTemp.Mid(nPos,nEndPos-nPos))-m_nOurNum;
        m_nVote++;
    }
    catch(...)
    {
    }
    theApp.m_nThreads--;
    return 0;
}

可以看到,关键代码就那么几行,如果不分析投票结果,比方法1少多了,而且看着也没方法1那么乱。不过这种方法同样存在方法1说的那个Session重复问题。而且据我尝试,新开启线程Session也是重复。所以我估计那个Session Key是根据Process ID决定的(一家之言,欢迎大家讨论)。不过如果你同时启动N个线程,着N个线程都可以成功的把票投进去,而不会说“您已经投过票了”。估计是因为这些信息是同时提交上去的,服务器在处理一条信息时还不知道这个Session其实已经投过票了。是不是这个原因我也不清楚,大家可以讨论一下。


     两种程序投票的方法就写到这里了。本人的水平实在一般,所以文章中有错误的话大家千万不要不屑一说啊,把错误指出来大家一起讨论一下。另外文中说到的那个Session的问题也希望大家讨论一下。

另外打个小广告:http://www.baizhuang.net,嘿嘿~~

网络投票中的作弊与反作弊

校园网络投票现在已经是征询师生意见的一种主流方式了,所有的数据都通过计算机统计,貌似公平而有效。然而,在看似公平的背后其实往往存在着巨大的漏洞,通过黑客工具的使用,公平在一瞬间就被黑客技术左右了…… ...
  • cluzax
  • cluzax
  • 2014年12月18日 22:16
  • 1795

如何做网络投票的刷票外挂(一)

其实刷票软件本身是比较容易实现的,相对于广大初级程序员来说,在知道原来并且给出解决关键问题的方案后,写个刷票的外挂程序还是比较容易实现的。真正的难点在于绕过投票网站的种种限制,比如:每个IP每天只能投...
  • ialong
  • ialong
  • 2013年09月05日 22:21
  • 2982

jsp mysql s2sh实现的投票管理系统源码

大家好,今天给大家演示一下由jsp、mysql、s2sh框架实现的一款非常简单的投票管理系统,这款系统非常简单,但是用到了框架的基本功能,可谓是麻雀虽小五脏俱全,是学习Java web非常好的参考资料...
  • icelikejia
  • icelikejia
  • 2018年01月04日 12:23
  • 36

数据结构课程设计代码--电子投票系统

/*********************************************************** * 版权所有 (C)2015, LiuQiang。 * * 文件名称: hea...
  • shellingfordisme
  • shellingfordisme
  • 2015年12月25日 13:33
  • 1308

简易在线投票系统(php)——前端设计(发布投票页面的源码)

发布投票页面的源码 发布 网上电子投票系统 (注销)-->登录 | 注册 ...
  • tianyao9hen
  • tianyao9hen
  • 2016年01月10日 16:29
  • 1151

简单的JavaWeb投票系统

目的帮她完成JavaWeb课程设计,也做为练手的小项目;功能1、可以实现在个人登陆,在线投票,票数统计的功能; 2、规定每个投票者每天只能投一票,并要求登录成功后才可以投票;分块1、Login类:实...
  • Run_the_youth
  • Run_the_youth
  • 2016年12月23日 19:46
  • 7458

简易在线投票系统(php)——发布投票页面

发布页面是在用户登录的状态下才能进行的所以要先检测是否处在登录状态,确定后再允许发布投票 注意:一旦发布将不能修改! 用户输入的信息会以post的格式发布到后台。 ...
  • tianyao9hen
  • tianyao9hen
  • 2016年01月10日 21:39
  • 1508

如无必要,勿增实体

今天评教的时候,米老师说了一句话:“如无必要,勿增实体。“一开始没有听太懂,后来查了一下,原来这是一个应用很广泛的理论,下面,请大家看一下这个故事:          如无必要,勿增实体。  ...
  • u013036688
  • u013036688
  • 2015年05月31日 20:34
  • 3349

勿在浮沙筑高台

研究底层的程序员往往会容易产生浮躁心理。因为底层的东西往往很难,学习周期太长,至少要个三五年才会有所成就。并且在学习过程中可能连续几个星期都看不到任何效果是很正常的。这就是内力的修炼与上层武功的区别。...
  • faileast_weiwei
  • faileast_weiwei
  • 2015年01月03日 14:40
  • 927

途牛旅游网又暴力裁员,用这方法止损最不道德

不久前,我接到途牛一个“被离职员工”的爆料,他曾经就职于一家国企,随后跳槽到途牛,在工作了几个月后,途牛以“不适合该公司”的理由将其辞退,且没有任何说法。这位员工在本次离职过程中前后手续办完一个小时都...
  • kwame211
  • kwame211
  • 2017年12月22日 11:44
  • 504
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:网上投票作弊的技术实现(纯技术交流,勿用作他途!!)
举报原因:
原因补充:

(最多只允许输入30个字)