从“香港西九龙”到12306协议

从“香港西九龙”到12306协议



经过了乱七八糟的问题,质疑和风浪之后,香港西九龙终于开通在即了。

先来个小笑话:

这票二维码是和票面信息完全不符……槽点满满。

XJA-IZQ:香港西九龙——广州南

二维码上购票人姓名和票面购票人姓名不同,车次G9994是要干什么么……更别说时间日期以及票号等等等等了……车厢,座位号和证件倒是对的。

当然,也许二维码上这个日期和时间是原预定开通时间,然后原预定开通为香港西九龙——广州南,并且车次为G9994次……完全瞎猜。如有雷同,实属巧合。不接受跨省追捕。

回到正题:

现在这几天车迷圈儿除了香港西九龙就是香港西九龙,感觉什么都见不到。某微博(实在想不起来名字了)的香港西九龙至各地的时刻表传的圈子内(当然我也可以假设圈子外也是)基本无人不知无人不晓。

有意思的是,现在12306官网还没有把香港西九龙站上表——而APP已经这么做了。

作为kelibiao.com的站长,每次有新站上客里表的时候都必须得看一眼数据。明显,香港西九龙还没有上表,但是总是可以一探究竟的。毕竟数据需要及时更新,才能够吸引到更多用户么(说得跟用户有多少一样)。

正好有人跟我讲到香港西九龙上了APP的站名表,并且听说电报码是-XJA;同时有个叫做“边界”的“车站”,电报码为-XBA,希望我能求证。于是,我便开始了折腾一天的求证之旅。

 

首先,第一个想法就是进行http嗅探。作为昔日piao.today的站长,12306前端怎么工作我还是比较了解的。APP和网站很类似——APP其实就是个h5配上app的壳做成的WebAPP而已。但是我也早在那时候就知道APP的通讯也是https的。这就导致了嗅探起来比较麻烦。

当然,麻烦不代表做不了。大概有以下几种方法:

  1. 找个树莓派弄成路由器然后中间层攻击(真的懒得再碰树莓派了)
  2. 反编译app(这不是扯淡呢么,最麻烦的方法——写在这儿凑数的。两条还搞个list真的不好看)
  3. 手机层面上想办法。

嗅探么,一直在安卓上用一款叫做wicap的软件。Google Play也推送了剩下三个他家的软件——其中有一个叫做Proxymon。一看,正是我想要的:它会在手机上安装一个根证书,然后手机上的网络全走这上面一圈儿(中间层了么这不就是),然后解压。

于是,我便开始了我的折腾之旅。

第一件事儿,打开手机。发现手机0%电。小米手机这点好:插上电源0%也能开机——不像苹果必须达到一个安全值后才可以开机。

之前root过的手机不知道怎么回事儿root还给关了。幸亏早就刷了自定义的Discovery系统,很快重新root了。

打开Wicap和Proxymon,下载了12306,查询香港西九龙至随便点了一站。这样的话,APP会提交一个http请求,并且在里面显示出发到站和请求的出发日期。

很快,通过Proxymon我就读到了我需要的数据:

OK,from_station=XJA,看来香港西九龙的电报码是XJA无误了。

那既然这样了,我为什么不直接顺便把整个请求链抓下来呢?Proxymon是我第一次使用,之前没有购买过,而免费版只会记录256kb的数据。准备购买完整版,却在支付的时候被Google Play拦截了,死活无法支付——从信用卡到PayPal到礼品卡都无法支付。给Google打电话用了45分钟才把问题解决好——因为我需要重新验证我的身份(安全是安全,但是真耽误事儿啊)。

很快,我得到了一堆(解密过的)数据包。dump到电脑后,发现里面所有Content-Encoding: gzip的response无法被解压——原因不得而知。试用了直接将response体存为文件用gzip解压,失败;用python找zlib库解压,失败;甚至直接用之前的代码套了个http server(dump下来的是http请求体和返回体如同上图,所以该有的header等都有)直接返回到浏览器或者给curl解压,也失败。得到的城市数据库等都无法被成功解压成response里所说的text/plain或者application/json(说白了还是text)格式,都是一大堆二进制数据。套了http server之后让浏览器自动解gzip失败后它自动把二进制数据下载了下来,大小和chunked里面描述的大小完全一样;同理,对于request请求体,很多写了Content-Type: application/json的也是一片乱码。用TridNet来分析response返回来的二进制文件也无法分析出是gzip格式。估计是12306学聪明了,把请求加密了一些。具体怎么解密,估计就不是今天能解决得了的事儿了。

此路不通,总有留爷处么(什么鬼混搭)。决定从APP入手。毕竟12306只需要从网上get一次基础数据,以后都可以用了就——这说明,他们肯定是有持久化存储的。果不其然,在文件系统的data目录里找到了12306的数据库——看到扩展名为db,第一个想法就是“这八成是SQLite吧”……把文件传到了电脑上,读取了一下——果然是SQLite!

好了,那就搜索一下就好了么……

有意思的是,香港西九龙在12306 APP上的拼音的确为HKWestKowloon。这要是真的输拼音进去然后找不到香港西九龙该多尴尬啊……

这是谁才能想得到这个站的拼音叫做HKWestKowloon,然后拼音缩写还是xg……

证明一下:

同时,对id的搜索并未找到有电报码为-XBA的车站,也无法找到名为“边界”的车站。说明“边界”站未上表(比如不办理客运业务等)。根据这位提问者的说法,有TRS数据事实证明该站存在(注:TRS为中国铁路的售票系统,就是你去车站买票的时候车站售票人员用的那个软件)。他推测的本站定性为:“广深港高速线深港段的分界站,划定内地和香港铁路资产范围”。但是无论如何,我个人还是认为眼见为实的。目前来说我没有看到该站直接事实存在的证据,而该车站存在的方式也不好说(真的是个“站”是不可能了,没准就是个什么标记啥的呢。参考海岫铁路的那一堆车站,一个没见到影。跟着高德地图去了一趟所谓的析(shi2)木站,真的是什么标记都没有,周边都是玉米地)。

无论如何,任务完成了。上面提到的无法gzip解压(也许是解密)的问题以后可以再说。

今天一整天都耗在这上面了,连午饭都没吃就到了晚饭的点儿了。抛砖引玉,希望各位能够对12306的底层协议和数据结构等发展出更深刻的了解吧。

4 Replies to “从“香港西九龙”到12306协议”

    1. 那就看你自己技术上的修行了……为了避免争议,我还是不要把具体方法暴露出来比较好……
      说真的,稍微对这方面懂点儿行应该都能解决得了的~

Leave a Reply

Your email address will not be published. Required fields are marked *