邮政app js瑞数5代低能版 ImyafEkG D2ko1bQr sekiro例子 webview调试
这个瑞数五代被写死了,没有用到随机cookie和随机代码和随机变量,我简称弱智版瑞数这个web需要用微信浏览器授权来获取userid,所以不能在谷歌调试
这个瑞数五代被写死了,没有用到随机cookie和随机代码和随机变量,我简称弱智版瑞数
这个web需要用微信浏览器授权来获取userid,所以不能在谷歌调试
这里可以学习到jsvmp的内容,大家可以看下JSVMP js加密
仅供学习侵权联系我删
远程调试
这个app是webview的,在app没法断点调试,但是用的是chrome的X5内核,所以可以映射到pc端的谷歌浏览器调试.
app需要开debugger,
WebView.setWebContentsDebuggingEnabled(true);
方案
- frida hook
- xp模块
hook成功后,adb连上手机
谷歌浏览器打开 chrome://inspect 会看到自己的手机型号和webview的内容
点击对应页面的 pause 就能进行调试,如果一直转圈,要搞个V才行
F12无限debugger
一开始调试,直接就进入了无限debugger,在文本中搜不到debugger
模式也是vm,意思是内存
这个时候就会想到大概率eval
写个脚本hook他
var _eval=eval
eval=function(arg){
console.trace(arg);
return _eval(arg);
}
完事后会发现有两层eval,第一层是乱码,第二层才是代码.
那就注入个代码把debugger去掉,并在第二层注入eval,hook下一层的代码(就套娃)
} else if (56 > 87 - _$G$ && _$G$ < 36) {
if (_$G$ - 64 > -31 && 104 > 69 + _$G$) {
var _$_r = _$vq();
} else if (99 === _$G$ * 3) {
//add
_$w$=_$w$.replace("debugger", "");
_$w$ ="var _eval=eval;eval=function(arg){console.trace(arg); return _eval(arg);}" +_$w$;
//add
_$aj = _$TN[_$Fk[18]](_$pJ, _$w$);
} else if (71 > 102 - _$G$ && 6 - _$G$ > -27) {
return Math.abs(arguments[1]) % 16;
} else {
_$TN = _$hT(221);
}
} else if (_$G$ > 39 && _$G$ - 64 < -20) {
这样就绕过了debugger顺便找到了下一层的代码
实际上debugger的检测是以下两行
} else if (_$Wa === 426) {
var _$AD = _$kg[_$N3[679]](_$f0(_$N3[103]));
} else {
var _$$4 = _$nB(_$I0(_$Xp.join(_$N3[74])));
定位加密
上面的步骤走完后我们已经有了完整的代码,把他eval hook去掉,然后把代码丢到同一个文件,让给他别在vm了,这样我们可以随便调试
这时候刷新下页面,debugger没了,除了乱其它都挺好(乱可以用ast还原下,但是硬怼比较爽)
上一步之前F12的network看堆栈还是在vm的,现在看堆栈已经在代码里面了
…
用正常的逆向手法追踪,一定已经追到类似xmlhttp的一个乱码变量,聪明的朋友会发现他被重写了
用dir看看
找一下作用域
就找到了实际的加密点
function _$63() {
window._$c4 = _$c4;//放到环境变量
_$BN();
console.log('url->'+arguments[1]);//自吐加密前的
var _$M7 = _$c4(arguments[1]);
arguments[1] = _$M7._$O_;
this._$xw = _$M7._$xw;
return _$jC[_$N3[14]](this, arguments);
}
这样搞之后就能在console随便加密了
sekiro
用的免费版,简单易用,目前发现的问题在于有时候断了不会自动重连,自己部署的话有坑,我也忘了啥坑
调用流程
<script type="text/javascript">
alert('hook success');
function guid() {
function S4() {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
}
return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
}
var client = new SekiroClient("wss://sekiro.virjar.com/websocket?group=ws-group-demo&clientId=" + guid());
client.registerAction("encode", function (request, resolve, reject) {
resolve(window._$c4(request['encode_str']));
});
client.registerAction("executeJs", function (request, resolve, reject) {
var code = request['code'];
if (!code) {
reject("need param:{code}");
return;
}
code = "return " + code;
console.log("executeJs: " + code);
try {
var result = new Function(code)();
resolve(result);
} catch (e) {
reject("error: " + e);
}
});
</script>
以下为他开源的部分,我直接复制到源码根目录,不引用了
<script type="text/javascript">
function SekiroClient(wsURL) {
this.wsURL = wsURL;
this.handlers = {};
this.socket = {};
this.base64 = false;
// check
if (!wsURL) {
throw new Error('wsURL can not be empty!!')
}
this.webSocketFactory = this.resolveWebSocketFactory();
this.connect()
}
SekiroClient.prototype.resolveWebSocketFactory = function () {
if (typeof window === 'object') {
var theWebSocket = window.WebSocket ? window.WebSocket : window.MozWebSocket;
return function (wsURL) {
function WindowWebSocketWrapper(wsURL) {
this.mSocket = new theWebSocket(wsURL);
}
WindowWebSocketWrapper.prototype.close = function () {
this.mSocket.close();
};
WindowWebSocketWrapper.prototype.onmessage = function (onMessageFunction) {
this.mSocket.onmessage = onMessageFunction;
};
WindowWebSocketWrapper.prototype.onopen = function (onOpenFunction) {
this.mSocket.onopen = onOpenFunction;
};
WindowWebSocketWrapper.prototype.onclose = function (onCloseFunction) {
this.mSocket.onclose = onCloseFunction;
};
WindowWebSocketWrapper.prototype.send = function (message) {
this.mSocket.send(message);
};
return new WindowWebSocketWrapper(wsURL);
}
}
if (typeof weex === 'object') {
// this is weex env : https://weex.apache.org/zh/docs/modules/websockets.html
try {
console.log("test webSocket for weex");
var ws = weex.requireModule('webSocket');
console.log("find webSocket for weex:" + ws);
return function (wsURL) {
try {
ws.close();
} catch (e) {
}
ws.WebSocket(wsURL, '');
return ws;
}
} catch (e) {
console.log(e);
//ignore
}
}
//TODO support ReactNative
if (typeof WebSocket === 'object') {
return function (wsURL) {
return new theWebSocket(wsURL);
}
}
// weex 和 PC环境的websocket API不完全一致,所以做了抽象兼容
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 _this = this;
// 不check close,让
// if (this.socket && this.socket.readyState === 1) {
// this.socket.close();
// }
try {
this.socket = this.webSocketFactory(this.wsURL);
} catch (e) {
console.log("sekiro: create connection failed,reconnect after 2s");
setTimeout(function () {
_this.connect()
}, 2000)
}
this.socket.onmessage(function (event) {
_this.handleSekiroRequest(event.data)
});
this.socket.onopen(function (event) {
console.log('sekiro: open a sekiro client connection')
});
this.socket.onclose(function (event) {
console.log('sekiro: disconnected ,reconnection after 2s');
setTimeout(function () {
_this.connect()
}, 2000)
});
};
SekiroClient.prototype.handleSekiroRequest = function (requestJson) {
console.log("receive sekiro request: " + requestJson);
var request = JSON.parse(requestJson);
var seq = request['__sekiro_seq__'];
if (!request['action']) {
this.sendFailed(seq, 'need request param {action}');
return
}
var action = request['action'];
if (!this.handlers[action]) {
this.sendFailed(seq, 'no action handler: ' + action + ' defined');
return
}
var theHandler = this.handlers[action];
var _this = this;
try {
theHandler(request, function (response) {
try {
_this.sendSuccess(seq, response)
} catch (e) {
_this.sendFailed(seq, "e:" + e);
}
}, function (errorMessage) {
_this.sendFailed(seq, errorMessage)
})
} catch (e) {
console.log("error: " + e);
_this.sendFailed(seq, ":" + e);
}
};
SekiroClient.prototype.sendSuccess = function (seq, response) {
var responseJson;
if (typeof response == 'string') {
try {
responseJson = JSON.parse(response);
} catch (e) {
responseJson = {};
responseJson['data'] = response;
}
} else if (typeof response == 'object') {
responseJson = response;
} else {
responseJson = {};
responseJson['data'] = response;
}
if (Array.isArray(responseJson)) {
responseJson = {
data: responseJson,
code: 0
}
}
if (responseJson['code']) {
responseJson['code'] = 0;
} else if (responseJson['status']) {
responseJson['status'] = 0;
} else {
responseJson['status'] = 0;
}
responseJson['__sekiro_seq__'] = seq;
var responseText = JSON.stringify(responseJson);
console.log("response :" + responseText);
if (responseText.length < 1024 * 6) {
this.socket.send(responseText);
return;
}
if (this.base64) {
responseText = this.base64Encode(responseText)
}
//大报文要分段传输
var segmentSize = 1024 * 5;
var i = 0, totalFrameIndex = Math.floor(responseText.length / segmentSize) + 1;
for (; i < totalFrameIndex; i++) {
var frameData = JSON.stringify({
__sekiro_frame_total: totalFrameIndex,
__sekiro_index: i,
__sekiro_seq__: seq,
__sekiro_base64: this.base64,
__sekiro_is_frame: true,
__sekiro_content: responseText.substring(i * segmentSize, (i + 1) * segmentSize)
}
);
console.log("frame: " + frameData);
this.socket.send(frameData);
}
};
SekiroClient.prototype.sendFailed = function (seq, errorMessage) {
if (typeof errorMessage != 'string') {
errorMessage = JSON.stringify(errorMessage);
}
var responseJson = {};
responseJson['message'] = errorMessage;
responseJson['status'] = -1;
responseJson['__sekiro_seq__'] = seq;
var responseText = JSON.stringify(responseJson);
console.log("sekiro: response :" + responseText);
this.socket.send(responseText)
};
SekiroClient.prototype.registerAction = function (action, handler) {
if (typeof action !== 'string') {
throw new Error("an action must be string");
}
if (typeof handler !== 'function') {
throw new Error("a handler must be function");
}
console.log("sekiro: register action: " + action);
this.handlers[action] = handler;
return this;
};
SekiroClient.prototype.encodeWithBase64 = function () {
this.base64 = arguments && arguments.length > 0 && arguments[0];
};
SekiroClient.prototype.base64Encode = function (s) {
if (arguments.length !== 1) {
throw "SyntaxError: exactly one argument required";
}
s = String(s);
if (s.length === 0) {
return s;
}
function _get_chars(ch, y) {
if (ch < 0x80) y.push(ch);
else if (ch < 0x800) {
y.push(0xc0 + ((ch >> 6) & 0x1f));
y.push(0x80 + (ch & 0x3f));
} else {
y.push(0xe0 + ((ch >> 12) & 0xf));
y.push(0x80 + ((ch >> 6) & 0x3f));
y.push(0x80 + (ch & 0x3f));
}
}
var _PADCHAR = "=",
_ALPHA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
_VERSION = "1.1";//Mr. Ruan fix to 1.1 to support asian char(utf8)
//s = _encode_utf8(s);
var i,
b10,
y = [],
x = [],
len = s.length;
i = 0;
while (i < len) {
_get_chars(s.charCodeAt(i), y);
while (y.length >= 3) {
var ch1 = y.shift();
var ch2 = y.shift();
var ch3 = y.shift();
b10 = (ch1 << 16) | (ch2 << 8) | ch3;
x.push(_ALPHA.charAt(b10 >> 18));
x.push(_ALPHA.charAt((b10 >> 12) & 0x3F));
x.push(_ALPHA.charAt((b10 >> 6) & 0x3f));
x.push(_ALPHA.charAt(b10 & 0x3f));
}
i++;
}
switch (y.length) {
case 1:
var ch = y.shift();
b10 = ch << 16;
x.push(_ALPHA.charAt(b10 >> 18) + _ALPHA.charAt((b10 >> 12) & 0x3F) + _PADCHAR + _PADCHAR);
break;
case 2:
var ch1 = y.shift();
var ch2 = y.shift();
b10 = (ch1 << 16) | (ch2 << 8);
x.push(_ALPHA.charAt(b10 >> 18) + _ALPHA.charAt((b10 >> 12) & 0x3F) + _ALPHA.charAt((b10 >> 6) & 0x3f) + _PADCHAR);
break;
}
return x.join("");
};
</script>
<script type="text/javascript">
alert('hook success');
function guid() {
function S4() {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
}
return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
}
var client = new SekiroClient("wss://sekiro.virjar.com/websocket?group=ws-group-youzheng&clientId=" + guid());
client.registerAction("encode", function (request, resolve, reject) {
resolve(window._$c4(request['encode_str']));
});
client.registerAction("executeJs", function (request, resolve, reject) {
var code = request['code'];
if (!code) {
reject("need param:{code}");
return;
}
code = "return " + code;
console.log("executeJs: " + code);
try {
var result = new Function(code)();
resolve(result);
} catch (e) {
reject("error: " + e);
}
});
</script>
更多推荐
所有评论(0)