玩转 JS 逆向:RPC 加持,Python爬虫效率飙升

大家好,我是小敢!

一些复杂的网站针对参数是层层加密,如果选择硬刚,去扣代码、补环境,耗时耗力的同时,不一定能获取完整的加密逻辑

在 JS 逆向中,我们可以通过 RPC 通信,直接调用浏览器的方法生成加密参数,这样可以省去扣代码的时间

本篇文章将介绍 Sekiro RPC 进行 JS 逆向的完整流程


目标网站:

aHR0cHM6Ly93d3cueGluZ3R1LmNuL3N1cC9jcmVhdG9yL2hvdA==

具体操作步骤如下:

1、Sekiro RPC

Sekiro 是一个多语言的、分布式网络拓扑无关的服务发布平台

它能基于长连接和代码注入 API 服务暴露的框架,可用于逆向(包含 JS 逆向和 App 逆向)

官网:

https://sekiro.iinti.cn/sekiro-doc/

2、分析网站

打开目标网站,发现接口 /h/api/gateway/handler_get 中的查询参数 sign 是加密的

在 Sources - Page 面板下,通过关键字 sign: 全局查询

发现加密参数生成的具体逻辑如下:

PS:通过方法 generatePayload 生成 sign,其中 c、l 为参数

文件位置:

https://*/obj/goofy/star/idou_fe/assets/vendor-a1b40867.js

然后,在方法 generatePayload 方法内添加条件断点

这样,通过多次 Debugger 分析,可以得出参数的生成规则(即:参数固定值、参数生成逻辑)

//条件监听  
//条件:c.service_name==='author.AdStarAuthorService'  

这样,在调试模式下,我们可以在浏览器控制台进行测试了

如下,直接调用方法可以拿到加密后的参数

3、加密文件重写 Overrides

在本地新建一个文件夹,Sources - Overrides 关联该本地目录

PS:开启 Overrides 并授予权限

在 Sources - Page 面板下,选择 vendor-a1b40867.js 文件右键,选择 Save for overrides 将文件保存到 Overrides 中

4、Sekiro 定义

修改 Overrides 中 vendor-a1b40867.js 文件

定义 SekiroClient 方法对象并实例化,注册一个方法进行监听处理

SekiroClient 源码如下:

https://raw.githubusercontent.com/yint-tech/sekiro-samples/main/demo-web/sekiroWeb.js

通过关键字 generatePayload 找到对应方法,回车换行,输入如下逻辑

PS:修改源码后,需要重新开启、关闭 Overrides 开关一次( Enable Local Overrides )

...
function SekiroClient(e){if(this.wsURL=e,this.handlers={},this.socket={},!e)throw new Error("wsURL can not be empty!!");this.webSocketFactory=this.resolveWebSocketFactory(),this.connect()}SekiroClient.prototype.resolveWebSocketFactory=function(){if("object"==typeof window){var e=window.WebSocket?window.WebSocket:window.MozWebSocket;return function(o){function t(o){this.mSocket=new e(o)}return t.prototype.close=function(){this.mSocket.close()},t.prototype.onmessage=function(e){this.mSocket.onmessage=e},t.prototype.onopen=function(e){this.mSocket.onopen=e},t.prototype.onclose=function(e){this.mSocket.onclose=e},t.prototype.send=function(e){this.mSocket.send(e)},new t(o)}}if("object"==typeof weex)try{console.log("test webSocket for weex");var o=weex.requireModule("webSocket");return console.log("find webSocket for weex:"+o),function(e){try{o.close()}catch(e){}return o.WebSocket(e,""),o}}catch(e){console.log(e)}if("object"==typeof WebSocket)return function(o){return new e(o)};throw new Error("the js environment do not support websocket")},SekiroClient.prototype.connect=function(){console.log("sekiro: begin of connect to wsURL: "+this.wsURL);var e=this;try{this.socket=this.webSocketFactory(this.wsURL)}catch(o){return console.log("sekiro: create connection failed,reconnect after 2s:"+o),void setTimeout(function(){e.connect()},2e3)}this.socket.onmessage(function(o){e.handleSekiroRequest(o.data)}),this.socket.onopen(function(e){console.log("sekiro: open a sekiro client connection")}),this.socket.onclose(function(o){console.log("sekiro: disconnected ,reconnection after 2s"),setTimeout(function(){e.connect()},2e3)})},SekiroClient.prototype.handleSekiroRequest=function(e){console.log("receive sekiro request: "+e);var o=JSON.parse(e),t=o.__sekiro_seq__;if(o.action){var n=o.action;if(this.handlers[n]){var s=this.handlers[n],i=this;try{s(o,function(e){try{i.sendSuccess(t,e)}catch(e){i.sendFailed(t,"e:"+e)}},function(e){i.sendFailed(t,e)})}catch(e){console.log("error: "+e),i.sendFailed(t,":"+e)}}else this.sendFailed(t,"no action handler: "+n+" defined")}else this.sendFailed(t,"need request param {action}")},SekiroClient.prototype.sendSuccess=function(e,o){var t;if("string"==typeof o)try{t=JSON.parse(o)}catch(e){(t={}).data=o}else"object"==typeof o?t=o:(t={}).data=o;(Array.isArray(t)||"string"==typeof t)&&(t={data:t,code:0}),t.code?t.code=0:(t.status,t.status=0),t.__sekiro_seq__=e;var n=JSON.stringify(t);console.log("response :"+n),this.socket.send(n)},SekiroClient.prototype.sendFailed=function(e,o){"string"!=typeof o&&(o=JSON.stringify(o));var t={};t.message=o,t.status=-1,t.__sekiro_seq__=e;var n=JSON.stringify(t);console.log("sekiro: response :"+n),this.socket.send(n)},SekiroClient.prototype.registerAction=function(e,o){if("string"!=typeof e)throw new Error("an action must be string");if("function"!=typeof o)throw new Error("a handler must be function");return console.log("sekiro: register action: "+e),this.handlers[e]=o,this};

//实例化一个客户端连接对象
//group:业务类型  
//clientId:设备id  
var client = new SekiroClient("wss://sekiro.iinti.cn:5612/business/register?group=test_web&clientId=" + Math.random());  
  
//注册  
 client.registerAction("xingtu", function (request, resolve, reject) {  
     // var enc_data = request['data']  
     // var res = enc_data;  
     // resolve(v()(res));  
     let c={  
         "hot_list_id": "0",  
         "tag": "61e541324fe6649d1b8a2ee3",  
         "service_name": "author.AdStarAuthorService",  
         "service_method": "GetHotListData"  
     };  
  
     let l={  
         "strict": true,  
         "serializing": true,  
         "rule": {  
             "include": [  
                 "hot_list_id",  
                 "tag",  
                 "download",  
                 "image_download",  
                 "province",  
                 "city",  
                 "rlid"  
             ]  
         }  
     };  
resolve(generatePayload(c,l));  
 });  
...

重新访问下面地址,查看控制台,发现 Sekiro 已经准备完毕

5、Python 调用

通过 Websocket 调用,借助浏览器调用 generatePayload() 方法,获取加密后的值 sign

最后,组成完整的 URL 获取数据

import requests  
  
# Websocket通讯,获取sign(Sekiro)  
def get_signature():  
    data = {"group": "test_web",  
            "action": "xingtu"  
            }  
    resp = requests.get("http://sekiro.iinti.cn:5612/business/invoke", params=data).json()  
    return resp['sign']  
  
# 获取数据  
def get_data(sign):  
    url = f"https://*host/h/api/gateway/handler_get/?hot_list_id=0&tag=*tag&service_name=author.AdStarAuthorService&service_method=GetHotListData&sign_strict=1&sign={sign}"  
  
    payload = {}  
    headers = {  
        'authority': '*host',  
        'agw-js-conv': 'str',  
        'pragma': 'no-cache',  
        'x-login-source': '1',  
        'x-star-service-method': 'GetHotListData',  
        'x-star-service-name': 'author.AdStarAuthorService',  
        'Cookie': 'cookie',  
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36'  
    }  
    response = requests.request("GET", url, headers=headers, data=payload)  
  
    print(response.text)  
  
if __name__ == '__main__':  
    sign = get_signature()  
    print("sign:",sign)  
  
    get_data(sign)

6、补充一下

除了 Overrides 覆盖文件外,还可以使用油猴脚本或浏览器插件进行脚本注入,完成 Sekiro 的初始化及事件注册

相比传统的 JS 逆向,利用 Sekiro 直接调用方法获取加密参数更加方便快捷然后;但是它有一个缺点,即:需要通过浏览器打开目标网站

感兴趣的小伙伴,赠送全套Python学习资料,包含面试题、简历资料等具体看下方。

一、Python所有方向的学习路线

Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照下面的知识点去找对应的学习资源,保证自己学得较为全面。

img
img

二、Python必备开发工具

工具都帮大家整理好了,安装就可直接上手!img

三、最新Python学习笔记

当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。

img

四、Python视频合集

观看全面零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。

img

五、实战案例

纸上得来终觉浅,要学会跟着视频一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

img

六、面试宝典

在这里插入图片描述

在这里插入图片描述

简历模板在这里插入图片描述

若有侵权,请联系删除

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值