JS-RPC实战区块链交易信息获取
在上一篇文章中用老实的js逆向获取了这个区块链网站中的x-apikey加密参数,总体来说还算简单,但是扣代码,补函数,改调用还是很烦的,现在我们用JS-RPC来简化这个复杂的步骤
这是JS-RPC的Github链接
自行下载合适的可执行文件并打开,你会看到如下窗口
看到这个窗口就证明你以及准备好了服务环境,现在要开始对网页注入代码链接上这个服务端了
找到加密函数的位置(上一篇文章中以及说过)然后手动在控制台调用一下这个函数,ok成功获取数据,但是我们在实际获取的时候是不可能让页面停留在断点处的,所以我们尝试将这个函数提升为全局函数
window.abc=h.A.getApiKey
但当我们尝试调用abc函数获取x-apikey参数的时候会发现报错了
不要慌张,此时开始从调用堆栈中一步一步找
在控制台中输入第二个函数的调用代码,可以看到控制台正常输出这个结果
开始尝试将这个函数改为全局函数
window.vv=v
尝试调用这个函数
成功运行,此时就不再需要断点了,将说有断点删除,开始向控制台中输入链接之前开启的JS-RPC服务端的代码(在该项目的Github里面有,考虑到网络问题将这些代码附上)
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 nx = new Hlclient("ws://127.0.0.1:12080/ws?group=nx");
nx.regAction("vv", function (resolve,param) {
var res = vv(JSON.parse(param.replace(/'/g, '"')));
console.log(res)
resolve(res);
})
看到这个返回就代表以及成功了
现在就可以直接获取加密参数了,有了这个工具就相当于开启了一个web服务可以让我们通过访问本机的web端来获取网页中js代码的执行结果(想要了解更多的话可以访问项目的Github地址查看)
其实就是向本机的12080端口发送get请求,在url中带上group组名,action注册的函数名,param传参就可以了
import requests,json
page = {"offset": str(1),"limit": "1"}
#offset是开始的条位置,limit是一次返回的数据数量限制
params = {
"group": "nx",
"action": "vv",
"param" : str(page)
}
print(params)
response = requests.get("http://127.0.0.1:12080/go", params=params)
headers_=json.loads(response.json()["data"])["headers"]#获取返回的headers
response = requests.get("https://www.oklink.com/api/explorer/v1/btc/transactionsNoRestrict",params=page,headers=headers_,)
print(response.json())
运行这段代码就会得到想要的结果啦
和普通的扣代码比起来这个方法似乎没有多大差别,都挺繁琐的,但是当遇到目标环境的加密很复杂,还有复杂的对象操作的时候,这个方法就可以算得上so easy了,方法多种多样关键的是要有灵活的头脑去处理,方法选择不存在绝对最优解,只有基于当前条件的相对高效路径
下一篇将会讲解通过WebSocket 来实现这个JSRPC