快速上手
快速上手
所有支持语言列表都在github开放 https://github.com/yint-tech/sekiro-samples 请大家在这里下载样例。
Frida环境
注入如下Frida脚本
var SekiroClient=function(){function e(e){this.handlers={},this.isConnecting=!1,this.sekiroOption=e,e.serverHost=e.serverHost||"sekiro.iinti.cn",e.serverPort=e.serverPort||5612,this.fridaSocketConfig={family:"ipv4",host:e.serverHost,port:e.serverPort},console.log(" welcome to use sekiro framework,\n for more support please visit our website: https://iinti.cn\n"),this.doConnect()}return e.prototype.registerAction=function(e,t){this.handlers[e]=t},e.prototype.reConnect=function(){var e=this;console.log("sekiro try connection after 5s"),setTimeout(function(){return e.doConnect()},5e3)},e.prototype.doConnect=function(){var e=this;this.isConnecting||(this.isConnecting=!0,console.log("sekiro connect to server-> "+this.fridaSocketConfig.host+":"+this.fridaSocketConfig.port),Socket.connect(this.fridaSocketConfig).then(function(t){e.isConnecting=!1,t.setNoDelay(!0),e.conn=t,e.connRead(),e.connWrite({type:16,serialNumber:-1,headers:{SEKIRO_GROUP:e.sekiroOption.sekiroGroup,SEKIRO_CLIENT_ID:e.sekiroOption.clientId}})})["catch"](function(t){e.isConnecting=!1,console.log("sekiro connect failed",t),e.reConnect()}))},e.prototype.connWrite=function(e){var t=this;this.conn.output.write(this.encodeSekiroPacket(e))["catch"](function(e){console.log("sekiro write register cmd failed",e),t.reConnect()})},e.prototype.connRead=function(){var e=this;this.conn.input.read(1024).then(function(t){return t.byteLength<=0?(e.conn.close(),console.log("sekiro server lost!"),void e.reConnect()):(e.onServerData(t),void setImmediate(function(){e.connRead()}))})["catch"](function(t){console.log("sekiro read_loop error",t),e.reConnect()})},e.prototype.onServerData=function(e){var t=this;if(this.readBuffer){if(e){var n=new ArrayBuffer(this.readBuffer.byteLength+e.byteLength),o=new Uint8Array(n);o.set(new Uint8Array(this.readBuffer),0),o.set(new Uint8Array(e),this.readBuffer.byteLength),this.readBuffer=n}}else{if(!e)return;this.readBuffer=e}var r=this.decodeSekiroPacket();r&&(this.handleServerPkg(r),setImmediate(function(){return t.onServerData()}))},e.prototype.encodeSekiroFastJSON=function(e){var t=void 0;e.msg&&(t=this.str2Uint8(e.msg));var n=void 0;e.data&&(n=this.str2Uint8(JSON.stringify(e.data)));var o=8+(t?t.length:0)+4+(n?n.length:0),r=new ArrayBuffer(o),i=new DataView(r);i.setInt32(0,e.status),i.setInt32(4,t?t.length:0);var s=8;return t&&(new Uint8Array(r,8).set(t),s+=t.length),i.setInt32(s,n?n.length:0),s+=4,n&&new Uint8Array(r,s).set(n),r},e.prototype.handleServerPkg=function(e){if(0==e.type)return void this.connWrite(e);if(32!=e.type)return void console.log("unknown server message:"+JSON.stringify(e));var t=this,n=function(n){t.connWrite({type:17,serialNumber:e.serialNumber,headers:{PAYLOAD_CONTENT_TYPE:"CONTENT_TYPE_SEKIRO_FAST_JSON"},data:t.encodeSekiroFastJSON(n)})},o={resolve:function(e){n({status:0,data:e})},reject:function(e){n({status:-1,msg:e})}};if(!e.data)return void o.reject("sekiro system error, no request payload present!!");var r=this.uint8toStr(new Uint8Array(e.data));console.log("sekiro receive request: "+r);var i=JSON.parse(r);if(!i.action)return void o.reject("the param: {action} not presented!!");var s=this.handlers[i.action];if(!s)return void o.reject("sekiro no handler for this action");try{s(i,o.resolve,o.reject)}catch(c){o.reject("sekiro handler error:"+c+JSON.stringify(c))}},e.prototype.decodeSekiroPacket=function(){if(!this.readBuffer)return void 0;var e=new DataView(this.readBuffer),t=e.getInt32(0),n=e.getInt32(4);if(1936026473!=t||1919889457!=n)return console.log("sekiro packet data"),this.conn.close().then(function(){console.log("sekiro close broken pipe")}),void(this.readBuffer=void 0);var o=e.getInt32(8);if(!(this.readBuffer.byteLength<o+12)){for(var r=e.getInt8(12),i=e.getInt32(13),s=e.getInt8(17),c=18,a={},f=0;s>f;f++){var u=e.getInt8(c++),h=this.uint8toStr(new Uint8Array(this.readBuffer.slice(c,u)));c+=u;var l=e.getInt8(c++),d="";l>0&&(d=this.uint8toStr(new Uint8Array(this.readBuffer.slice(c,l))),c+=l),a[h]=d}var p=void 0,y=o+12-c;return y>0&&(p=this.readBuffer.slice(c,c+y)),this.readBuffer.byteLength==o+12?this.readBuffer=void 0:this.readBuffer=this.readBuffer.slice(c),{type:r,serialNumber:i,headers:a,data:p}}},e.prototype.encodeSekiroPacket=function(e){var t=6,n=[];for(var o in e.headers)n.push(this.str2Uint8(o)),n.push(this.str2Uint8(e.headers[o])),t+=2;t+=n.reduce(function(e,t){return e+t.length},0),e.data&&(t+=e.data.byteLength);var r=new ArrayBuffer(t+12),i=new DataView(r);i.setUint32(0,1936026473),i.setUint32(4,1919889457),i.setInt32(8,t),i.setInt8(12,e.type),i.setInt32(13,e.serialNumber),i.setInt8(17,Object.keys(e.headers).length);var s=18;return n.forEach(function(e){i.setInt8(s++,e.length),new Uint8Array(r,s).set(e),s+=e.length}),e.data&&new Uint8Array(r,s).set(new Uint8Array(e.data)),r},e.prototype.uint8toStr=function(e){for(var t,n,o=0,r=Math.min(65536,e.length+1),i=new Uint16Array(r),s=[],c=0,a=function(){var a=o<e.length;if(!a||c>=r-1){var f=i.subarray(0,c),u=[];if(f.forEach(function(e){return u.push(e)}),s.push(String.fromCharCode.apply(null,u)),!a)return{value:s.join("")};e=e.subarray(o),o=0,c=0}var h=e[o++];if(0===(128&h))i[c++]=h;else if(192===(224&h))n=63&e[o++],i[c++]=(31&h)<<6|n;else if(224===(240&h))n=63&e[o++],t=63&e[o++],i[c++]=(31&h)<<12|n<<6|t;else if(240===(248&h)){n=63&e[o++],t=63&e[o++];var l=63&e[o++],d=(7&h)<<18|n<<12|t<<6|l;d>65535&&(d-=65536,i[c++]=d>>>10&1023|55296,d=56320|1023&d),i[c++]=d}};;){var f=a();if("object"==typeof f)return f.value}},e.prototype.str2Uint8=function(e){for(var t=0,n=e.length,o=0,r=Math.max(32,n+(n>>>1)+7),i=new Uint8Array(r>>>3<<3);n>t;){var s=e.charCodeAt(t++);if(s>=55296&&56319>=s){if(n>t){var c=e.charCodeAt(t);56320===(64512&c)&&(++t,s=((1023&s)<<10)+(1023&c)+65536)}if(s>=55296&&56319>=s)continue}if(o+4>i.length){r+=8,r*=1+t/e.length*2,r=r>>>3<<3;var a=new Uint8Array(r);a.set(i),i=a}if(0!==(4294967168&s)){if(0===(4294965248&s))i[o++]=s>>>6&31|192;else if(0===(4294901760&s))i[o++]=s>>>12&15|224,i[o++]=s>>>6&63|128;else{if(0!==(4292870144&s))continue;i[o++]=s>>>18&7|240,i[o++]=s>>>12&63|128,i[o++]=s>>>6&63|128}i[o++]=63&s|128}else i[o++]=s}return i.slice?i.slice(0,o):i.subarray(0,o)},e}();
var client = new SekiroClient({ sekiroGroup: "test_frida", clientId: "test" });
client.registerAction("testAction", function (request, resolve, reject) {
resolve("ok");
});
访问FridaRPC链接:
https://sekiro.iinti.cn/business/invoke?group=test_frida&action=testAction¶m=testparm
更多详情,请参考:sdk
android(Xposed)
api依赖配置
// 仓库
repositories {
maven { url "https://nexus.iinti.cn/repository/maven-public/" }
}
// 依赖
compileOnly 'de.robv.android.xposed:api:82'
implementation('cn.iinti.sekiro3.business:sekiro-business-api:1.5')
服务注册代码
public class XposedMain implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) {
if (loadPackageParam.processName.equals("cn.iinti.sekiroApp")) {// 请注意,一般sekiro只作用于特定的app
new SekiroClient("test_xposed", UUID.randomUUID().toString())
.setupSekiroRequestInitializer((sekiroRequest, handlerRegistry) ->
handlerRegistry.registerSekiroHandler(new ActionHandler() {
@Override
public String action() {
return "testAction";
}
@Override
public void handleRequest(SekiroRequest sekiroRequest, SekiroResponse sekiroResponse) {
sekiroResponse.success("ok");// 接口处理逻辑,我们不做任何处理,直接返回字符串:ok
}
})
).start();
}
}
}
访问XposedRPC链接:
https://sekiro.iinti.cn/business/invoke?group=test_xposed&action=testAction¶m=testparm
更多详情,请参考:sdk
浏览器js环境
打开chrome控制台,输入如下代码:
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};
var client = new SekiroClient("wss://sekiro.iinti.cn:5612/business/register?group=test_web&clientId=" + Math.random());
client.registerAction("testAction", function (request, resolve, reject) {
resolve("ok");
});
访问JsRPC链接:
https://sekiro.iinti.cn/business/invoke?group=test_web&action=testAction¶m=testparm
请注意,如果目标网站是https,且demo无法正确连接,请下载证书并安装到你的系统中
点击这里 pem格式 或者 crt格式下载证书,并跟随系统引导安装根证书
IOS环境
- 请先在这里下载IOS的lib代码
- 如果使用frida进行IOS的RPC,可能不容易持久化,如果希望对IOS的rpc接口进行持久化,那么考虑使用objective-c的sdk
- 可以考虑越狱环境下的oc代码注入,或者使用MonkeyDev进行IOS app重打包完成注入
#import <Foundation/Foundation.h>
#include "Sekiro.h"
void test(NSDictionary *request, SekiroResponse *response) {
[response success:[@"\"ok replay objective-c\"" dataUsingEncoding:NSUTF8StringEncoding]];
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
SekiroClient *client = [[SekiroClient alloc] init:@"test_ios"];
[client registerAction:@"testAction" handler: test];
[client start];
// sekiro启动后,运行在新的线程中,所以这里需要sleep一下,否则直接程序就结束了
[NSThread sleepForTimeInterval:300];
}
return 0;
}
访问GoRPC链接:
https://sekiro.iinti.cn/business/invoke?group=test_ios&action=testAction¶m=testparm
更多详情,请参考:sdk
python语言
- 请先在这里下载python的lib代码
- python不是常见需求
- 请注意这里是将python的功能作为rpc发布给其他人使用,而不是使用python调用别人的服务
import json
from SekiroClient import SekiroClient, SekiroHandler, SekiroResponse
class TestHandler(SekiroHandler):
def handle(self, request: json, response: SekiroResponse):
response.success("ok")
if __name__ == '__main__':
sekiro_client = SekiroClient("test_python")
sekiro_client.register_action("testAction", TestHandler())
sekiro_client.run_sync()
访问PythonRPC链接:
https://sekiro.iinti.cn/business/invoke?group=test_python&action=testAction¶m=testparm
go 语言
- 请先在这里下载go的lib代码
- go不是常见需求
- 请注意这里是将go的功能作为rpc发布给其他人使用,而不是使用go调用别人的服务
package main
import "iinti.cn/sekiro"
type TestSekiroHandler struct {
}
// handler处理器
func (TestSekiroHandler) handleRequest(request map[string]interface{}, response SekiroResponse) {
response.Success("ok")
}
func TestSekiro(t *testing.T) {
client := MakeClientDefault("test_go")
var handler RequestHandler = &TestSekiroHandler{}
client.RegisterHandler("testAction", &handler).Start()
// 请注意,由于内部是go routine,所以这里正常会直接运行结束,所以休眠一下
time.Sleep(2 * time.Minute)
}
访问GoRPC链接:
https://sekiro.iinti.cn/business/invoke?group=test_go&action=testAction¶m=testparm