由于一个爬虫项目需要爬取QQ邮箱的邮件数据,给定QQ的邮箱账户和密码,模拟浏览器登录爬取邮件文件。
首先通过使用Fiddler抓取QQ邮箱登录的HTTP请求包,很显然其密码是通过某种变换而来,不像有的邮箱(网易等)是明文传递。
QQ邮箱的密码生成方法可以通过其JS脚本得到,但项目使用c开发,需要转换为c代码。
下面是QQ邮箱密码生成方法:
要生成QQ密码,需要三个元素值,分别是pwd,vcode,salt,其中pwd是已知的,vcode和salt的值需要get一个url地址,从response中分析得到,该url为:
https://ssl.ptlogin2.qq.com/check?regmaster=&pt_tea=1&pt_vcode=0&uin=12345678&appid=522005705&js_ver=10151&js_type=1&login_sig=&u1=https%3A%2F%2Fmail.qq.com%2Fcgi-bin%2Flogin%3Fvt%3Dpassport%26vm%3Dwpt%26ft%3Dloginpage%26target%3D&r=0.31754892738536
Reponse为:
ptui_checkVC('1','UXxxRXX9kkbgJhpmjhduxDBec60BihrFZB1VTMTiB9foqu81TEZImQ**','\x81\x5d\x88\x42\x9e\xd0\x8b\x90','','1');
括号中的第一个参数指定是否需要验证码,第二个参数为vcode,第三个参数为salt的值,第四个参数为一个session值,在发送登录请求时会用到;如果第一个参数值为1,则意味着登录需要验证码,在项目中,我用了一个Dialog展示验证码图片,等待用户输入图片中的验证码,这里获取验证码图片的url为:
https://ssl.captcha.qq.com/getimage?uin=_qq&aid=522005705&cap_cd=verify_cap_cd&0.7659631329588592
这里的_qq为QQ邮箱账户名,verify_cap_cd为vcode的值,图片中的验证码即为新的vcode的值,作为后面运算的参数;
pwd_md5_bytes: 计算得到账户密码的md5值,字节类型,16字节长度;
salt_bytes: salt为字符串,形如:“\x81\x5d\x88\x42\x9e\xd0\x8b\x90”,需要将其转换为:“81 5d 88 42 9e d0 8b 90”,这就是在内存中的保存的数据;
pwd_salt_string: 计算pwd_md5_bytes + salt_bytes的md5值,字符串类型,32字节长度;
rsa_modulus: RSA的模数,值为:
F20CE00BAE5361F8FA3AE9CEFA495362FF7DA1BA628F64A347F0A8C012BF0B254A30CD92ABFFE7A6EE0DC424CB6166F8819EFA5BCCB20EDFB4AD02E412CCF579B1CA711D55B8B0B3AEB60153D5E0693A2A86F3167D7847A0CB8B00004716A9095D9BADC977CBB804DBDCBA6029A9710869A453F27DFDDF83C016D928B3CBF4C7
该值为十六进制字符串,需要将其转换为字节序;
rsa_exponent: RSA的指数,值为:3,转换为真实字节序;
rsa_pub_key: 根据模数rsa_modulus和指数rsa_exponent计算出公钥,依赖openssl库,如下:
RSA *pub_key = RSA_new();
pub_key->n = BN_bin2bn((unsigned char *)sn_hex, 128, pub_key->n);
pub_key->e = BN_bin2bn((unsigned char *)se_hex, 1, pub_key->e);
rsa_data_string: 使用上面的公钥rsa_pub_key对密码的MD5值,即:pwd_md5_bytes 进行加密,并将密文转换为十六进制的字符串形式;
int rsa_len = RSA_public_encrypt(16, (unsigned char *)passHash, (unsigned char *)rsa_outbuf, pub_key, RSA_PKCS1_PADDING);
rsa_datalen_string: 用公钥加密后的数据的长度,转为十六进制字符串形式;
vcode_string: 将vcode值转换为十六进制字符串形式;
vcode_len_string: 将vcode的长度转换为十六进制的字符串形式;
salt_bytes_string: 将salt_bytes转换为十六进制字符串形式;
tea_string: 将rsa_datalen_string + rsa_data_string + salt_bytes_string + vcode_len_string + vcode_string 合并进行TEA加密运算;
pwd_p: 对tea_string做base64编码运算,将输出的编码文本中的'/', '+', '='分别替换为'-', '*', '_',最终得到QQ登录密码;
登录请求地址:
https://ssl.ptlogin2.qq.com/login?u=_qq&verifycode=verify_code&pt_vcode_v1=0&pt_verifysession_v1=verify_session&p=pwd_p&pt_randsalt=0&u1=https%3A%2F%2Fmail.qq.com%2Fcgi-bin%2Flogin%3Fvt%3Dpassport%26vm%3Dwpt%26ft%3Dloginpage%26target%3D%26account%3D_qq&ptredirect=1&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=3-27-1457499465993&js_ver=10151&js_type=1&login_sig=&pt_uistyle=25&aid=522005705&daid=4&
登录后的response:
ptuiCB('0','0','https://ssl.ptlogin2.mail.qq.com/check_sig?pttype=1&uin=12345678&service=login&nodirect=0&ptsigx=78563bc9efeaed18a201f0360c30c1412f60aa236130eb21a449d87632e32b71254dbeb13fb01bf51497bcb291d499b33abe2bb7081a1be28e2d4922b61e8cd1&s_url=https%3A%2F%2Fmail.qq.com%2Fcgi-bin%2Flogin%3Fvt%3Dpassport%26vm%3Dwpt%26ft%3Dloginpage%26target%3D%26account%3D12345678&f_url=&ptlang=2052&ptredirect=101&aid=522005705&daid=4&j_later=0&low_login_hour=0®master=0&pt_login_type=1&pt_aid=0&pt_aaid=0&pt_light=0&pt_3rd_aid=0','1','登录成功!', 'qq_nick');
等看到登录成功字样,就意味着成功登录!