Js逆向之远程调用(rpc)免去抠代码补环境
目前现在大多数站点都有多多少少的请求签名校验,只有携带签名参数后端校验通过后才会返回数据,这也是最基本的风控规则了。
那对于js逆向来说,比较麻烦的就是扣算法的代码,代码扣下来还需要补环境信息,各种调试比较麻烦。接下来介绍个比较简单也是比较通用的解决方案,并且有搭建好的免费Java后端服务API供调用。
目标站点
https://www.iesdouyin.com/share/user/MS4wLjABAAAA-DwFCTwY-oeXt8FRTN5E_BlkcBGnXWBBCp-_BbcDYi0
这是我们要抓取的接口和接口中变化的参数:x-bogus、_signature、msToken三个参数 (还有其他环境必须浏览器ua,浏览器指纹等这里不做更加详细说明)
编写Rpc代码
首先我们需要确定,这三个签名参数是在什么时候生成的,这时候就需要各种调试debug 了,比较麻烦也不演示了我直接说了,是在发送请求的时候直接生成的,那么我们可以直接创建一个xhr请求来试试是否正常
function getSign() { var xhr = new XMLHttpRequest(); xhr.open('get', 'https://www.iesdouyin.com/web/api/v2/aweme/post/?reflow_source=reflow_page&sec_uid=MS4wLjABAAAA-DwFCTwY-oeXt8FRTN5E_BlkcBGnXWBBCp-_BbcDYi0&count=21&max_cursor=0', false); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.setRequestHeader('salute-by', 'douyin'); xhr.send(null); return xhr.responseURL; } getSign();
看到了测试结果是正常的,那么好办了,剩下的直接连接websocket服务api传递参数就行了。
更改后的js代码如下:
function Hlclient(wsURL) { this.wsURL = wsURL; this.handlers = {}; this.socket = {}; if (!wsURL) { throw new Error('wsURL can not be empty!!') } this.connect() } Hlclient.prototype.connect = function () { console.log('begin of connect to wsURL: ' + this.wsURL); var _this = this; try { this.socket["ySocket"] = new WebSocket(this.wsURL); this.socket["ySocket"].onmessage = function (e) { console.log("send func", e.data); _this.handlerRequest(e.data); } } catch (e) { console.log("connection failed,reconnect after 10s"); setTimeout(function () { _this.connect() }, 10000) } this.socket["ySocket"].onclose = function () { console.log("connection failed,reconnect after 10s"); setTimeout(function () { _this.connect() }, 10000) } }; Hlclient.prototype.send = function (msg) { this.socket["ySocket"].send(msg) } Hlclient.prototype.regAction = function (func_name, func) { if (typeof func_name !== 'string') { throw new Error("an func_name must be string"); } if (typeof func !== 'function') { throw new Error("must be function"); } console.log("register func_name: " + func_name); this.handlers[func_name] = func; } Hlclient.prototype.handlerRequest = function (requestJson) { var _this = this; var result=JSON.parse(requestJson); //console.log(result) if (!result['action']) { this.sendResult('','need request param {action}'); return } action=result["action"] var theHandler = this.handlers[action]; if (!theHandler ||theHandler==undefined){ this.sendResult(action,'action not found'); return } try { if (!result["param"]){ theHandler(function (response) { _this.sendResult(action, response); }) }else{ theHandler(function (response) { _this.sendResult(action, response); },result["param"]) } } catch (e) { console.log("error: " + e); _this.sendResult(action+e); } } Hlclient.prototype.sendResult = function (action, e) { let resultMessage = { action, data:e } this.send(JSON.stringify(resultMessage)); } // 只需要关注这里就行了 var service = new Hlclient("wss://api.wslmf.com/websocket/jsrpc/xb/douyin"); // 这里是执行js内方法的,并且返回结果,如果其他业务只需要更改这里面逻辑即可 service.regAction("sign", function (resolve, param) { var xhr = new XMLHttpRequest(); xhr.open('get', param, false); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.setRequestHeader('salute-by', 'douyin'); xhr.send(null); resolve(xhr.responseURL); })
将上面代码直接添加到控制台执行
Api地址及参数说明
接口地址:api.wslmf.com/jsrpc/do
请求方式:POST
请求数据类型:application/json
请求参数示例:
{ "action": "sign", "group": "xb", "name": "douyin", "param": "https://www.iesdouyin.com/web/api/v2/aweme/post/?reflow_source=reflow_page&sec_uid=MS4wLjABAAAA-DwFCTwY-oeXt8FRTN5E_BlkcBGnXWBBCp-_BbcDYi0&count=21&max_cursor=0" }
参数说明:
action: 对应js代码中的 `sign` 参数,必须一致 group和name对应wss地址中的xb和douyin param:表示要传递的参数,多个参数自行传递json或者base64都行,到时候在js代码中解析下就行
测试请求及查看结果
油猴脚本
那为了方便,不必每次都在控制台里面执行这一大段js代码,我将其封装了一个油猴脚本:https://greasyfork.org/zh-CN/scripts/457965-json-rpc-demo
这样当浏览器窗口打开后就会自动执行了
注意事项
当这个服务api公开了后,可能会有各种group和name,请注意这必须是唯一的,但因为websocket仅作为中转服务,我没有做校验,因此自己使用的时候尽可能的起含自己特色的唯一的名字
最后
参考开源项目地址:https://gitee.com/ripperTs/jsrpc
(此项目是后端是Go写的而不是Java,因此跟此Api不兼容,感兴趣的可以自行看看哈!)
评论