在之前的一篇博客里(http://blog.csdn.net/wangjiannuaa/article/details/6689906)分析了如何使用了C#登录网页。有的人如果密码就是纯数字,那么用这种方法就可以暴力简单得破解了。不过笔者前几天发现,用于实验的人人网登录需要了验证码,用户是觉得烦了,诸不知这也算是保护措施吧。
第一次使用WinInet编程是去年,用于抓取网页的股票数据(http://blog.csdn.net/wangjiannuaa/article/details/5959375),最近搜索这方面知识的时候再网上找到了新浪邮箱的自动登录程序,那么就以此展开,演示如何使用WinInet 登录web。原文地址:http://www.cctry.com/thread-1181-1-1.html。
经过分析,文章中的表单地址并非正统的 http://mail.sina.com.cn/ 而是 http://mail.sina.com.cn/cgi-bin/login.php 如下图所示。这样做的好处个人认为是规避了安全性的障碍,没有多少js,各种花哨,没有验证码……
我相信作者尝试过http://mail.sina.com.cn/,比http://mail.sina.com.cn/cgi-bin/login.php烦恼许多。
好了页面如下所示:
测试用户名和密码:jimmy_cmd@sina.com,密码123abc,拜托读者别干坏事改我密码。自己申请即可。
打开Fidder抓包工具,然后点击登录。
抓包工具分析内容如下:
对照的文本如下:
POST http://mail.sina.com.cn/cgi-bin/login.php HTTP/1.1
Accept: text/html, application/xhtml+xml, */*Referer: http://mail.sina.com.cn/cgi-bin/login.php
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; MAAU)
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Host: mail.sina.com.cn
Content-Length: 76
Connection: Keep-Alive
Pragma: no-cache
Cookie: freeName=w_wangj_jian@sina.com; SINAMAIL-WEBFACE-SESSID=f4762bf7601ac04e5c03a344f5160a59; UOR=,,; U_TRS1=000000b4.2d6a4a30.4dbeccdf.f7085a45; vjuids=-8a3c2a43b.12f673b30db.0.8ab6cd7a91ca3; vjlast=1304434711; SINAGLOBAL=00000049.c6df3442.4e8ecea8.c10d0d3d; ULV=1320734979210:14:4:4:00000042.bb0b52da.4eb8d102.c45af59b:1320732064442; ALLYESID4=00110503104143503706036; SGUP=0; FocusMediaIpCgiCookie=%u6C5F%u82CF%7C%7C%u5357%u4EAC; FocusMediaRotatorInputCookie=9; FocusMediaRotatorCookie=3; mvsign=v%3D%2Atz%3Cc5uhs4CE5F_%24Uf5%3E; loginType=freemail; SHOW_TIP_BOX=1; Apache=00000042.bb0b52da.4eb8d102.c45af59b; _s_upa=7; ULOGIN_IMG=13207484207872; U_TRS2=000000a2.96d8223d.4eb8dfc0.1bfdd2e1; SID=BVmfqfgs-93K99ffg3qrKL3f97qLf-3fKqfKqkqfgfqapWkm3L9RK9q; SPRIAL=d38fb34629f58bca2d47db89f8bcc1f5; SINA_USER=jimmy_cmd
logintype=uid&u=jimmy_cmd&psw=123abc&product=mail&%B5%C7%C2%BC=%B5%C7+%C2%BC
InternetOpen->InternetConnect->HttpOpenRequest->HttpSendRequest系统中顺序调用上面这四个WinInet API完成一次Http请求.
下面,对照以上红色字体的说明,代码改写如下:
#include<windows.h>
#include<wininet.h>
#pragma comment(lib,"wininet.lib")
void main()
{
HINTERNET hSession = NULL;
HINTERNET hConnect = NULL;
HINTERNET hRequest = NULL;
//InternetOpenA
LPCSTR lpszAgent = "Application";
DWORD dwAccessType = INTERNET_OPEN_TYPE_PRECONFIG;
hSession = InternetOpenA(lpszAgent,dwAccessType,NULL,NULL,0);
if (!hSession)
{
return ;
}
//InternetConnectA
LPCSTR lpszServerName = "mail.sina.com.cn";
INTERNET_PORT nServerPort = INTERNET_DEFAULT_HTTP_PORT;
DWORD dwService = INTERNET_SERVICE_HTTP;
hConnect = InternetConnectA(hSession,lpszServerName,nServerPort,NULL,NULL,dwService,0,1);
if (!hConnect)
{
return ;
}
//HttpOpenRequestA
LPCSTR lpszVerb = "POST";
LPCSTR lpszObjectName = "cgi-bin/login.php"; //网站的对象名,网址在InternetConnectA第二个参数指定
LPCSTR lpszVersion = "HTTP/1.1";
LPCSTR lpszReferrer = "Referer: http://mail.sina.com.cn/cgi-bin/login.php";
LPCSTR lpszAcceptTypes = "Accept: text/html, application/xhtml+xml, */*";
DWORD dwFlags = INTERNET_FLAG_RELOAD;
hRequest = HttpOpenRequestA(hConnect,lpszVerb,lpszObjectName,lpszVersion,lpszReferrer,&lpszAcceptTypes,dwFlags,1);
if (!hRequest)
{
return;
}
//HttpSendRequestA
LPCSTR lpszHeaders = "Content-Type: application/x-www-form-urlencoded\r\n";
DWORD dwHeadersLength=-1L;
char szFormData[1024]={0};
strcpy(szFormData,"logintype=uid&u=jimmy_cmd&psw=123abc&product=mail&%B5%C7%C2%BC=%B5%C7+%C2%BC\r\n");
LPVOID pBuf = (LPVOID)szFormData;
BOOL bReturn = HttpSendRequestA(hRequest,lpszHeaders,dwHeadersLength,pBuf,strlen(szFormData));
if(!bReturn)
{
return;
}
char szRecvBuf[1024+1]; // 接受数据缓冲区
DWORD dwNumberOfBytesRead; // 服务器返回大小
DWORD dwRecvTotalSize=0; // 接受数据总大小
DWORD dwRecvBuffSize=0; // 接受数据buf的大小
memset(szRecvBuf,0,1024+1);
LPCSTR lpFileName = "recv.html";
DWORD dwNumberOfBytesWritten ;
HANDLE hOpenFile = (HANDLE)CreateFileA(lpFileName,GENERIC_WRITE,0,NULL,OPEN_ALWAYS,NULL,NULL);
if (hOpenFile == INVALID_HANDLE_VALUE)
{
hOpenFile = NULL;
return ;
}
do
{
bReturn = InternetReadFile(hRequest,szRecvBuf,1024,&dwNumberOfBytesRead);
if(!bReturn)
{
break;
}
// 统计接受数据的大小
szRecvBuf[dwNumberOfBytesRead] = '\0';
dwRecvTotalSize += dwNumberOfBytesRead;
dwRecvBuffSize += strlen(szRecvBuf);
WriteFile(hOpenFile,szRecvBuf,dwNumberOfBytesRead,&dwNumberOfBytesWritten,NULL);
} while (dwNumberOfBytesRead !=0);
CloseHandle(hOpenFile);
InternetCloseHandle(hSession);
InternetCloseHandle(hConnect);
InternetCloseHandle(hRequest);
}
对WinInet API的理解,可以去 http://msdn.microsoft.com/zh-cn/default.aspx 搜索查看。
忘了贴结果了!双击接收到的文件,如下所示,可以看出来是想要的结果~