当前位置:   article > 正文

12306新版抢票之逻辑分析_js 抢票12306

js 抢票12306

前言


新版的12306大概是前天上线的吧,因为我前天想抢票的时候发现之前写的程序已经无法正常工作了。

登陆的时候就会报错——“非法请求”,很纳闷,莫非是12306改了逻辑?

不过经过这两天的研究,已经又搞出了新版的抢票软件,嘿嘿,感觉值得骄傲一下~好了,不嘚瑟了

下面先从登陆入手,来剖析新版添加的dynamicJs(这个名字还挺贴切,就这么叫了)



一窥新版猫腻


下面就是新版的12306登陆所传的参数



根据我上版抢票软件的经验,其中后三个参数都是新添加的,并且其中用红框框中的那个参数的key和value都是不固定的~另外两个倒是简单,也不影响登陆的成功与否。

那么这个动态变化的参数到底是怎么来的呢?这大概就是12306这版的“骄傲”了吧——dynamicJs。从12306官网分析找到这个dynamicJs:




该js文件中对于生成动态key-value的关键片段(以及后面的gc()函数)如下:


  1. function() {
  2. (function() {
  3. var form = document.forms[0];
  4. var oldSubmit;
  5. if (null != form && form != 'undefined'
  6. && form.id == 'loginForm') {
  7. form.oldSubmit = form.submit;
  8. submitForm = function() {
  9. var keyVlues = gc().split(':');
  10. var inputObj = $('<input type="hidden" name="'
  11. + keyVlues[0]
  12. + '" value="'
  13. + encode32(bin216(Base32.encrypt(
  14. keyVlues[1], keyVlues[0])))
  15. + '" />');
  16. var myObj = $('<input type="hidden" name="myversion" value="' + window.helperVersion + '" />');
  17. inputObj.appendTo($(form));
  18. myObj.appendTo($(form));
  19. delete inputObj;
  20. delete myObj;
  21. }
  22. } else {
  23. submitForm = function() {
  24. var keyVlues = gc().split(':');
  25. return keyVlues[0]
  26. + ",-,"
  27. + encode32(bin216(Base32.encrypt(
  28. keyVlues[1], keyVlues[0])))
  29. + ":::" + 'myversion' + ",-,"
  30. + window.helperVersion;
  31. };
  32. }
  33. })();
  34. });

核心就是submitForm这个function,它会在登陆按钮click的时候触发(其实是提交表单的时候都会触发,只是这里先只关注登陆)

可以看到上面的if-else判断中,对于form是有做区分的:分成2类,一类是id为loginForm的Form(也就是登陆表单),其余的则归为另一类。

这两类处理的逻辑不同,对于loginForm,它会在页面上插入2个隐藏域来顺着表单的提交而提交。而对于另一类,则生成2组key-value并用":::"join起来。

不过这里要小小的 吐槽一下12306一下,就是不管登陆成功与否,这两个隐藏域都会被插入,我们可以做个试验来看看,下图就是我N次登陆不成功时所发生的事情:




呵呵~这不是我们的重点。还是分析那个动态的key和value是怎么来的。由于我们只关注登陆,可以将之前的js代码精简一下:

  1. if (null != form && form != 'undefined'
  2. && form.id == 'loginForm') {
  3. form.oldSubmit = form.submit;
  4. submitForm = function() {
  5. var keyVlues = gc().split(':');
  6. var inputObj = $('<input type="hidden" name="'
  7. + keyVlues[0]
  8. + '" value="'
  9. + encode32(bin216(Base32.encrypt(
  10. keyVlues[1], keyVlues[0])))
  11. + '" />');
  12. var myObj = $('<input type="hidden" name="myversion" value="'
  13. + window.helperVersion + '" />');
  14. inputObj.appendTo($(form));
  15. myObj.appendTo($(form));
  16. delete inputObj;
  17. delete myObj;
  18. }
  19. }


其中一个参数的key是keyValues[0],而value则是用keyValue[0]和keyValue[1]经过某些加密运算得到的值,这就是我们要找的目标参数。

好了,可以看到keyValues这个数组是通过gc()这个函数的返回值split出来的,那么看看gc()是什么:


  1. function gc() {
  2. var key = 'MTk0MTEw';
  3. var value = '';
  4. var cssArr = [ 'selectSeatType', 'ev_light', 'ev_light',
  5. 'fishTimeRangePicker', 'updatesFound', 'tipScript',
  6. 'refreshButton', 'fish_clock', 'refreshStudentButton',
  7. 'btnMoreOptions', 'btnAutoLogin', 'fish_button',
  8. 'defaultSafeModeTime', 'ticket-navigation-item' ];
  9. var csschek = false;
  10. if (cssArr && cssArr.length > 0) {
  11. for ( var i = 0; i < cssArr.length; i++) {
  12. if ($('.' + cssArr[i]).length > 0) {
  13. csschek = true;
  14. break;
  15. }
  16. }
  17. }
  18. if (csschek) {
  19. value += '0';
  20. } else {
  21. value += '1';
  22. }
  23. var idArr = [ 'btnMoreOptions', 'refreshStudentButton',
  24. 'fishTimeRangePicker', 'helpertooltable', 'outerbox',
  25. 'updateInfo', 'fish_clock', 'refreshStudentButton',
  26. 'btnAutoRefresh', 'btnAutoSubmit', 'btnRefreshPassenger',
  27. 'autoLogin', 'bnAutoRefreshStu', 'orderCountCell',
  28. 'refreshStudentButton', 'enableAdvPanel', 'autoDelayInvoke',
  29. 'refreshButton', 'refreshTimesBar', 'chkAllSeat' ];
  30. var idchek = false;
  31. for ( var i = 0; i < idArr.length; i++) {
  32. if ($('#' + idArr[i])[0]) {
  33. idchek = true;
  34. break;
  35. }
  36. }
  37. if (idchek) {
  38. value += '0';
  39. } else {
  40. value += '1';
  41. }
  42. var attrArr = [ 'helperVersion' ];
  43. var attrLen = attrArr ? attrArr.length : 0;
  44. var attrchek = false;
  45. for ( var p in parent) {
  46. if (!attrchek) {
  47. for ( var k = 0; k < attrLen; k++) {
  48. if (String(p).indexOf(attrArr[k]) > -1) {
  49. attrchek = true;
  50. break;
  51. }
  52. }
  53. } else
  54. break;
  55. }
  56. for ( var p in window) {
  57. if (!attrchek) {
  58. for ( var k = 0; k < attrLen; k++) {
  59. if (String(p).indexOf(attrArr[k]) > -1) {
  60. attrchek = true;
  61. break;
  62. }
  63. }
  64. } else
  65. break;
  66. }
  67. var styleArr = [ '.enter_right>.enter_enw>.enter_rtitle', '.objbox td' ];
  68. var stylechek = false;
  69. if (styleArr && styleArr.length > 0) {
  70. for ( var i = 0; i < styleArr.length; i++) {
  71. var tempStyle = $(styleArr[i]);
  72. if (tempStyle[0]) {
  73. for ( var k = 0; k < tempStyle.length > 0; k++) {
  74. if (tempStyle.eq(k).attr('style')) {
  75. stylechek = true;
  76. break;
  77. }
  78. }
  79. }
  80. }
  81. }
  82. if (stylechek) {
  83. value += '0';
  84. } else {
  85. value += '1';
  86. }
  87. var keywordArr = [ {
  88. key : ".enter_right",
  89. values : [ "亲", "抢票", "助手" ]
  90. }, {
  91. key : ".cx_form",
  92. values : [ "点发车", "刷票" ]
  93. }, {
  94. key : "#gridbox",
  95. values : [ "只选", "仅选", "checkBox", "checkbox" ]
  96. }, {
  97. key : ".enter_w",
  98. values : [ "助手" ]
  99. } ];
  100. var keywordchek = false;
  101. if (keywordArr && keywordArr.length > 0) {
  102. for ( var i = 0; i < keywordArr.length; i++) {
  103. var kw = keywordArr[i];
  104. if (fw(kw)) {
  105. keywordchek = true;
  106. break;
  107. }
  108. }
  109. }
  110. if (keywordchek) {
  111. value += '0';
  112. } else {
  113. value += '1';
  114. }
  115. if (value.indexOf('0') > -1) {
  116. aj();
  117. }
  118. return key + ':' + value;
  119. }


可以看到key无需计算,而value是经过计算得到的:具体的就是在页面上找是否有指定class的元素,是否有指定id的元素........也不知道12306是要干嘛,反正我是没理解这块的真正含义?但是可以分析出来,value最后的结果必然是“xxxx”,x代表0或1,但是显然12306不希望value中包含‘0’。那么也许可以直接用‘1111’来代替value吧~

到这里,登陆的逻辑就分析完了,想模拟登陆的童鞋可以自己动手试试了,这里提供一个思路吧,可以把encode32等函数拿到本地,然后用Java提供的js引擎执行一下~那么这个value就出来。



更深入


其实不仅仅是登陆,在各种提交表单的地方都加入了这么一个动态的key-value,具体的流程是这样的:

1、首先在加载页面时会引入一个动态的js文件,通过这个主要是拿到动态的key值,而计算value的逻辑都一样

2、在提交表单的时候会将这个动态的key和value也一并提交上去,若该参数出错,则会报“非法请求”错误

掌握了这些,从老版抢票软件升级到新版也不是什么难事了吧~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/632046
推荐阅读
相关标签
  

闽ICP备14008679号