有些时候一些直觉还是很有用的,或许人的直觉本就是经过长时间的学习具有了用现有信息推导结论的能力,只是你没有意识到你是怎么推导的而已,算是内隐记忆吧。
好了,我就做这些,剩下的大家尽情发挥吧。。。
By:小宗
这篇文章似乎是带着悲伤的心情写的,这几天也没发生什么特别的事情,但是心里却不知为什么有着淡淡的忧伤
上次说的自己改hdget的参数的问题,我脑残的在firefox网络分析的地方重发请求,可是后来才发现,这个重发是不带cookie的(说是为了安全性,能想要做cookie欺骗的人不会被这么点儿小麻烦难倒吧),导致服务器不给我返回数据。。。囧。。。
其实我一直不知道小米的getmode请求到底是干什么的,但是我知道mode应该与取模有关,但是是对什么取模呢?取模是有什么用呢?18号抢小米的时候突然意识到验证码全部是数字,那么验证码是不是某个数字对返回值取模的结果呢?18号getmode请求的返回结果是:
getmode({"mod":2675})
18号我的验证码是2080,那么取模的数字最后一位应该是0或5,与数字有关的我第一个想到的是时间戳,可是我浏览器发送的所有时间戳都没有以0或5结尾的(算是我的幸运吧),然后我突然想到还有一个数字那就是小米的ID(谁让你把它摆在这么明显的位置呢^_^),结果计算表明,验证码确实就是小米的ID对2675取模,万分之一的错误概率,所以我就去看有关验证码的函数
好吧,现在看一下小米的代码getmode函数和调用的函数吧。
function getmode(json) {
if (json.mod !== 0) {
Util.countFk(json.mod); //json.mod就是返回的2675
if (window.getmodeTimer) {
clearInterval(window.getmodeTimer)
};
if (window.getmodeTimeout) {
clearTimeout(window.getmodeTimeout)
}
}
};
//countFk函数,Util的方法
countFk: function (mod) {
if (!mod || mod === 0) {
return false
};
var uid = m.cookie(CONFIG.cookies.userid), //uid就是小米ID
num = (uid % mod) .toString() .substr( - 4, 4);//取模哦
switch (num.length) {
case 1:
CONFIG.fkNum = _$[261] + num; //_$[261]=='000'
this.formatFk();
break;
case 2:
CONFIG.fkNum = _$[262] + num; //_$[262]=='00'
this.formatFk();
break;
case 3:
CONFIG.fkNum = _$[263] + num; //_$[263]=='0'
this.formatFk();
break;
case 4:
CONFIG.fkNum = num;
this.formatFk();
break
} //就是把验证码放在了fkNum中
},
还有一个checkFk的函数,是验证输入的验证码的,基本内容就是看一下输入的验证码是否和fkNum相同,知道大家都不喜欢看代码,就不贴出来了。
如前面所说,抢购开始后会发送这么几条请求,hdinfo,getmode和hdget,前面两个算是介绍过了吧,下面看一下hdget请求的返回数据
hdcontrol(
{"stime":1395115250, //服务器时间
"d22a51":5, //自动发hdget请求的时间(秒),不知道为什么取了这么一个名字
"login":true, //是否登录了
"pmstart":false,
"status":{
"miphone":{ //手机的抢购状态
"hdstart":true, //抢购是否开始
"hdstop":false, //抢购是否结束
"hdurl":"", //抢购成功后自动跳转的URL
"duration":null,//未知,想知道的自己去看小米源码,反正我不想看
"reg":true}, //未知
//下面个miphone类似
"mitv":{"hdstart":true,"hdstop":false,"hdurl":"","duration":null,"reg":true}
}})
看一下hdcontrol的关键代码吧。
function hdcontrol(json) {
//………………………………
var jsonStr = json.status,phoneUrl,
powerUrl,
tvUrl,
//……………………………………
if (CONFIG.onSale.phone === true) {
phoneUrl = jsonStr.miphone.hdurl
};
//………………………………
if (CONFIG.proType === _$[71] && phoneUrl) { //判断抢购的东西和url是否为空
m.locationNext(phoneUrl)
} else if (CONFIG.proType === _$[72] && powerUrl)
//………………………………
//抢其他东西的代码
//………………………………
getPermit.hdStatus(json)
};
locationNext: function (str) {
if (str == null || str == _$[66]) {//其实这个判断基本没有用,在调用前就判断过str是否为null或是‘’ _$[66]==''
window.location.reload()
} else { //_$[67]=='http://t.hd.xiaomi.com/s/'
location.href = _$[67] + str //不为空则页面跳转到。。。
}
}
………………………………………………这就是小米的抢购页面,我该说什么好呢。。。。。。
根据firefox的网络分析来看,抢购开始之后就发送了这么几条请求,
1、hdinfo;2、getmode;3、hdget;
至于参数是什么,不说了,原本截了张图的,可是没有重命名,后来玩2048的时候又截图给大师姐显摆,结果给覆盖掉了。。。臭显摆害死人啊。
好吧,下面说一下结论。。。结论就是一段脚本
自己保存成html后缀的试试吧,再次声明,未经实际验证,要验证要等到25号,到时候我也不一定会验证,因为已经抢到了,万一被视为作弊封号什么的也别来找我。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh" xml:lang="zh">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>小米抢购</title>
</head>
<body id="body">
<h1>小米抢购</h1>
<p>该代码是18号之后写的,未实际验证</p>
<p>首先打开小米抢购页面,登录后,根据倒计时时间调整准系统时间后,刷新页面</p>
<p>填好下面几项</p>
<p>小米ID为小米个人中心里的那个ID号</p>
<p>在小米抢购页面的地址栏输入(区分大小写):javascript:alert(CONFIG.srcs.hdinfo)将显示的最后一串数字填入刷新时间(不要复制了多余的字符比如空格等),关掉对话框,不要再刷新页面</p>
<p>等到小米的抢购时间一到,立即点击“开始”按钮</p>
<p>只针对小米2014/03/04-2014/03/18的页面,对后续页面情况未知</p>
<p>不保证能100%抢到,但是该程序具有自动识别验证码的作用</p>
<p>本文件不做任何验证,出错不会有提示,请输入准确后再提交</p>
<p>该脚本之在FireFox下验证有效,其他浏览器未验证,应该也可以</p>
<p>没有像小米页面那样重发hdget,因为我觉得第一次没有抢到后面抢到的概率也不大</p>
<p>没有整理房间的,页面简陋,海涵</p>
<p>MadeBy zong</p>
<form>
<label for="miid">输入您的小米ID:</label><input type="text" id="miid" name="miid" size=20/><br />
<label for="time1">刷新时间:</label><input type="text" id="time1" name="time1" size=20/><br />
</form>
<button οnclick="buy()">开始</button>
<script>
var url; //保存hdget的url
var miid; //保存小米ID
var time1;
//最后一次刷新时间,因为我不知道服务器是否验证这个参数,所以还是用实际的
var time2;
//原本是想伪造一个时间戳2的,
//后来想既然调整了系统时间和自动计算验证码,还是直接用Date类获得靠谱一些
function hdcontrol(json)
{
p=json.status.miphone.hdurl;
if(p==null || p=="")
{
alert("很遗憾,您可以多次刷新下面的页面来抢购\n");
location.href=url;
}
else
{
location.href="http://t.hd.xiaomi.com/s/"+p;
}
return;
}
function getmode(json)
{ //参考自小米countfk,生成验证码
var fk=(miid%json.mod).toString().substr(-4,4);
switch (fk.length) {
case 1:
fk='000'+fk;
break;
case 2:
fk='00'+fk;
break;
case 3:
fk='0'+fk;
break;
}
var script = document.createElement("script");
url="http://tc.hd.xiaomi.com/hdget?product=phone&fk={{fk}}&_="+time1+new Date().getTime();
url=url.replace('{{fk}}',fk.toString());
script.src =url;
script.id = "hdget";
document.getElementById("body").appendChild(script)
//正确加载后将执行hdcontrol函数,没有做错误处理,参考自小米页面
}
function hdinfo(json)
{
var script = document.createElement("script");
//生成请求germode的url
script.src = "http://tc.hd.xiaomi.com/getmode?_="+time1+new Date().getTime();
script.id = "getmode";
document.getElementById("body").appendChild(script);
//正确加载后将执行getmode函数,没有做错误处理,参考自小米页面
return;
}
function buy(){
time1=document.getElementById("time1").value;
//保存第一个时间戳1
miid=document.getElementById("miid").value;
//保存小米ID
var script = document.createElement("script");
//生成请求hdinfo的url,其实这条请求可以不发送
script.src = "http://tc.hd.xiaomi.com/hdinfo?callback=hdinfo&_="+time1+new Date().getTime();
script.id = "hdinfo";
document.getElementById("body").appendChild(script);
//正确加载后将执行hdinfo函数,没有做错误处理,参考自小米页面
}
//每条请求的返回值示例
//hdinfo
//hdinfo({"stime":1395115208,"d22a51":5,"login":true,"pmstart":false,"status":{"miphone":{"hdstart":true,"hdstop":false,"hdurl":"","duration":null,"reg":true},"mitv":{"hdstart":true,"hdstop":false,"hdurl":"","duration":null,"reg":true}}})
//getmode
//getmode({"mod":2675})
//hdget
//hdcontrol({"stime":1395115250,"d22a51":5,"login":true,"pmstart":false,"status":{"miphone":{"hdstart":true,"hdstop":false,"hdurl":"","duration":null,"reg":true},"mitv":{"hdstart":true,"hdstop":false,"hdurl":"","duration":null,"reg":true}}})
</script>
</body>
</html>
好了,我就做这些,剩下的大家尽情发挥吧。。。