⚠️ 本文最后更新于 2025-09-12,文章内容可能过时,请自行甄别。

JS逆向之JSRPC-第0张图片

视频教程:

https://www.bilibili.com/video/BV1GigLzgE9T/

一、启动JSRPC服务端

JS逆向之JSRPC-第1张图片

二、目标网站注入JS

var rpc_client_id, Hlclient = function (wsURL) {
    this.wsURL = wsURL;
    this.handlers = {
        _execjs: function (resolve, param) {
            var res = eval(param)
            if (!res) {
                resolve("没有返回值")
            } else {
                resolve(res)
            }
        }
    };
    this.socket = undefined;
    if (!wsURL) {
        throw new Error('wsURL can not be empty!!')
    }
    this.connect()
}
Hlclient.prototype.connect = function () {
    if (this.wsURL.indexOf("clientId=") === -1 && rpc_client_id) {
        this.wsURL += "&clientId=" + rpc_client_id
    }
    console.log('begin of connect to wsURL: ' + this.wsURL);
    var _this = this;
    try {
        this.socket = new WebSocket(this.wsURL);
        this.socket.onmessage = function (e) {
            _this.handlerRequest(e.data)
        }
    } catch (e) {
        console.log("connection failed,reconnect after 10s");
        setTimeout(function () {
            _this.connect()
        }, 10000)
    }
    this.socket.onclose = function () {
        console.log('rpc已关闭');
        setTimeout(function () {
            _this.connect()
        }, 10000)
    }
    this.socket.addEventListener('open', (event) => {
        console.log("rpc连接成功");
    });
    this.socket.addEventListener('error', (event) => {
        console.error('rpc连接出错,请检查是否打开服务端:', event.error);
    })
};
Hlclient.prototype.send = function (msg) {
    this.socket.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;
    return true
}
Hlclient.prototype.handlerRequest = function (requestJson) {
    var _this = this;
    try {
        var result = JSON.parse(requestJson)
    } catch (error) {
        console.log("请求信息解析错误", requestJson);
        return
    }
    if (result["registerId"]) {
        rpc_client_id = result['registerId']
        return
    }
    if (!result['action'] || !result["message_id"]) {
        console.warn('没有方法或者消息id,不处理');
        return
    }
    var action = result["action"], message_id = result["message_id"]
    var theHandler = this.handlers[action];
    if (!theHandler) {
        this.sendResult(action, message_id, 'action没找到');
        return
    }
    try {
        if (!result["param"]) {
            theHandler(function (response) {
                _this.sendResult(action, message_id, response);
            })
            return
        }
        var param = result["param"]
        try {
            param = JSON.parse(param)
        } catch (e) {
        }
        theHandler(function (response) {
            _this.sendResult(action, message_id, response);
        }, param)
    } catch (e) {
        console.log("error: " + e);
        _this.sendResult(action, message_id, e);
    }
}
Hlclient.prototype.sendResult = function (action, message_id, e) {
    if (typeof e === 'object' && e !== null) {
        try {
            e = JSON.stringify(e)
        } catch (v) {
            console.log(v)//不是json无需操作
        }
    }
    this.send(JSON.stringify({"action": action, "message_id": message_id, "response_data": e}));
}

三、目标网站与JSRPC连接通信

var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=zzz");

四、导出目标函数到window全局

断点定位到目标(encrypt)函数,控制台执行:

window.webFun=encrypt

五、注册函数

1、无参数取值

demo.regAction("yourFunction", function (resolve) {
    //webFun为需要远程调用的函数,需要提前导出到全局window下,方便全局调用
    res=window.webFun();
    resolve(res);
})

2、一个参数

demo.regAction("yourFunction", function (resolve,param) {
    //webFun为需要远程调用的函数,需要提前导出到全局window下,方便全局调用
    res=window.webFun(param);
    resolve(res);
})

3、多个参数

demo.regAction("yourFunction", function (resolve,param) {
    //webFun为需要远程调用的函数,需要提前导出到全局window下,方便全局调用
    res=window.webFun(param["param1"],param["param2"]);
    resolve(res);
})

六、远程调用取值

1、无参数调用

http://127.0.0.1:12080/go?group=zzz&action=yourFunction

2、一个参数调用

http://127.0.0.1:12080/go?group=zzz&action=yourFunction&param=123456

3、多个参数调用

url = "http://127.0.0.1:12080/go"
data = {
    "group": "zzz",#分组
    "action": "yourFunction",#注册事件名称
    "param": json.dumps({"param1":"xxxx","param2":"yyyy"})#远程调用需要传递的参数
}
res=requests.post(url, data=data) 
print(res.text)

七、相关下载

包含详细文档及windows平台JSRPC服务端

本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习使用,请在下载后24小时内删除,严禁商用。若由于商用引起版权纠纷,一切责任均由使用者承担。 【注意:本站发布资源来源于网络搜集,均有较强时效性,请在下载前注意查看文章资源发布或更新时间,距离当前时间太久的资源不建议下载,特别是安卓专区相关资源,会有大概率失效无法使用】