时效性 本文内容具有极强的时效性, 仅供娱乐
目标 模拟手机 app 登录熊猫直播
实现 分析 大致思路: 抓包, 分析请求(headers, datas…….), 模拟请求
实战 1. fiddler 抓 HTTPS 比较费劲, 我的安卓机需要手动安装 fiddler 提供的证书才能避免 ssl 错误, 这里只说两个需要注意的地方:
### 证书下载 ###
当你的手机成功连接上电脑端 fiddler 代理时, 手机访问 http://ipv4.fiddler:8888/ 如图, 选择下载 fiddler 证书
{% asset_img echo_service.jpg echo_service %}
### 证书类型选择(Android7) ###
我的机器系统版本是 Android7, 有一个小坑在证书类型选择, 一定要选第一个 `VPN和应用`, 如图
{% asset_img cert_type_select.jpg cert_type_select %}
2. 通过抓包发现关键请求有两个 1 2 GET /ajax_aeskey GET /ajax_login
猜测登录经过了 aes 加密, 搜索 js 代码发现关键方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function (t ) { var n = $.Deferred (); return o ("ajax_aeskey" , { "__guid" : t.__guid }).then (function (r ) { var i = r.data || "" ; i = c.enc .Utf8 .parse (i); var o = c.enc .Utf8 .parse ("995d1b5ebbac3761" ) , a = c.AES .encrypt (t.password , i, { "iv" : o, "mode" : c.mode .CBC , "padding" : c.pad .ZeroPadding }).toString (); n.resolve (a) }).fail (function (t ) { t.errmsg = s.commonError , n.reject (t) }), n.promise () }
发现关键字 enc.Utf8.parse
, 搜索后得知是 crypto-js
库, 简单查看其各个参数含义 通过 c.pad.ZeroPadding
得知是 b'\0'
填充 通过 c.mode.CBC
得知 mode=AES.MODE_CBC
通过 "iv": o
得知 IV='995d1b5ebbac3761'
快速写出 python 实现 1 2 3 4 5 6 7 def encrypt (text, key, iv='995d1b5ebbac3761' ): cryptor = AES.new(key, mode=AES.MODE_CBC, IV=iv) text = text.encode("utf-8" ) add = 16 - (len (text) % 16 ) text = text + (b'\0' * add) ciphertext = cryptor.encrypt(text) return b64encode(ciphertext).decode()
3. 解决了加密部分, 接下来的就是小把戏了 在最终登录的时候经过尝试, 需要加上 pdft
和 __plat
这两个参数 猜测是唯一设备标示, 用来验证是否在常用设备登录
源码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 import reimport requestsfrom Crypto.Cipher import AESfrom base64 import b64encodeaccount = '' password = '' def encrypt (text, key, iv='995d1b5ebbac3761' ): cryptor = AES.new(key, mode=AES.MODE_CBC, IV=iv) text = text.encode("utf-8" ) add = 16 - (len (text) % 16 ) text = text + (b'\0' * add) ciphertext = cryptor.encrypt(text) return b64encode(ciphertext).decode() opener = requests.session() res = opener.get('https://u.panda.tv/ajax_aeskey' ).json() res = opener.get('https://u.panda.tv/ajax_login' , params={ 'regionId' : '86' , 'account' : account, 'password' : encrypt(password, res['data' ]), 'pdft' : '' , '__plat' : 'android' }).json() if res['errno' ] != 0 : print (res) res = opener.get('https://m.panda.tv/sign/index' ).text token = re.search(r'name="token"\s+value="(\w+)"' , res) lottery_param = re.search(r'"key":\s*"(?P<app>[\w-]+)",\s*"date":\s*"(?P<validate>[\d-]+)"' , res) res = opener.get('https://m.panda.tv/api/sign/apply_sign' , params={ 'token' : token.group(1 ) }).json() if res['errno' ] != 0 : print (res) res = opener.get('https://roll.panda.tv/ajax_roll_draw' , params={ 'app' : lottery_param.group('app' ), 'validate' : lottery_param.group('validate' ) }).json() if res['errno' ] != 0 : print (res)
总结
refs http://docs.telerik.com/fiddler/Configure-Fiddler/Tasks/ConfigureForAndroid https://blog.zhengxianjun.com/2015/05/javascript-crypto-js/ http://blog.csdn.net/leak235/article/details/50466213