介绍
最近测金融app比较多,碰到一个mpaas,简单记录下。
抓包
直接上的apatch,root检测是过了的,frida用的自己改的版本,应该和网上的大差不差。
直接挂不上,attach能注入就没啥问题。
直接抓包会抓不到,用r0cap抓包转发到burp,看起来会清楚点。
发现是本地起了一个代理,所以直接抓是抓不到(当然还有代理检测)。
特征很明显,是用了mpaas框架的,接下来就是处理mpaas框架的加解密问题。
加解密明文转发
直接找了个网上的开源项目,发现可以用,但是响应似乎有点问题。
https://github.com/F6JO/mPaas-frida-hook
关键的代码:
Java.perform(function () {
var JsonSerializerV2 = Java.use('com.alipay.mobile.common.rpc.protocol.json.JsonSerializerV2');
JsonSerializerV2.packet.implementation = function () {
console.log();
console.log("------------------JsonSerializerV2---------------------------------");
var uuidx = uuid();
var OldReqData = utf8ByteToUnicodeStr(this.packet())+ "!!!uuidx:" +uuidx + "!!!";
// console.log(OldReqData)
send({type: 'REQ', data: OldReqData});
var typexx;
var string_to_recv;
recv(function (received_json_object) {
typexx = received_json_object['type'];
string_to_recv = received_json_object['payload'];
}).wait();
if (typexx === 'NEW_REQ') {
console.log(uuidx + ": NewREQ: " + string_to_recv)
console.log("------------------JsonSerializerV2 end---------------------------------");
return stringToByte(string_to_recv + "!!!uuidx:" +uuidx + "!!!");
}
console.log("!!!!!!!!!!!!!!!!!!JsonSerializerV2 NOT NEW_REQ!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1")
// return stringToByte(OldReqData + "[uuidx:" +uuidx + "]");
}
var SignJsonSerializer = Java.use('com.alipay.mobile.common.rpc.protocol.json.SignJsonSerializer');
SignJsonSerializer.packet.implementation = function () {
console.log();
console.log("------------------SignJsonSerializer---------------------------------");
var uuidx = uuid();
var OldReqData = utf8ByteToUnicodeStr(this.packet())+ "!!!uuidx:" +uuidx + "!!!";
send({type: 'REQ', data: OldReqData});
var typexx;
var string_to_recv;
recv(function (received_json_object) {
typexx = received_json_object['type'];
string_to_recv = received_json_object['payload'];
}).wait();
if (typexx === 'NEW_REQ') {
console.log(uuidx + ": NewREQ: " + string_to_recv)
console.log("------------------SignJsonSerializer end---------------------------------");
return stringToByte(string_to_recv + "!!!uuidx:" +uuidx + "!!!");
}
console.log("!!!!!!!!!!!!!!!!!!SignJsonSerializer NOT NEW_REQ!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1")
// return stringToByte(OldReqData + "[uuidx:" +uuidx + "]");
}
var HttpCaller = Java.use('com.alipay.mobile.common.rpc.transport.http.HttpCaller');
HttpCaller.b.overload('com.alipay.mobile.common.transport.http.HttpUrlRequest').implementation = function (a){
var uuidchuanzu = utf8ByteToUnicodeStr(a.getReqData()).match(/!!!uuidx:(.*?)!!!/g);
var uuidchuan = "";
if (uuidchuanzu != null){
uuidchuan = uuidchuanzu[0];
}
var uuidx = uuidchuan.replace("!!!uuidx:","").replace("!!!","");
a.setReqData(stringToByte(utf8ByteToUnicodeStr(a.getReqData()).replace(uuidchuan,"")));
var resp = this.b(a);
// console.log("xiangying: "+utf8ByteToUnicodeStr(resp.getResData()));
var respStr = utf8ByteToUnicodeStr(resp.getResData()) + "!!!uuidx:" + uuidx + "!!!";
send({type: 'RESP', data: respStr});
var typexx;
var string_to_recv;
recv(function (received_json_object) {
typexx = received_json_object['type'];
string_to_recv = received_json_object['payload'];
}).wait();
if (typexx === 'NEW_RESP') {
console.log(uuidx+": NewREP: " + string_to_recv)
resp.setResData(stringToByte(string_to_recv))
return resp
}
}
var RpcInvoker = Java.use('com.alipay.mobile.common.rpc.RpcInvoker');
RpcInvoker.a.overload('java.lang.reflect.Method','java.lang.String','[B','com.alipay.mobile.common.rpc.transport.InnerRpcInvokeContext','com.alipay.mobile.common.rpc.transport.http.HttpCaller').implementation = function (a,b,c,d,e){
// console.log("RpcInvokerRpcInvokerRpcInvoker")
var uuidchuanzu = utf8ByteToUnicodeStr(c).match(/!!!uuidx:(.*?)!!!/g);
if (uuidchuanzu != null){
var uuidchuan = uuidchuanzu[0];
var newc = stringToByte(utf8ByteToUnicodeStr(c).replace(uuidchuan,""))
// console.log(utf8ByteToUnicodeStr(newc))
this.a(a,b,newc,d,e);
}else {
this.a(a,b,c,d,e)
}
// this.a(a,b,c,d,e);
}
}
);
直接用frida或者脱壳机先脱壳看看。
对比后发现,是一个hook方法名的问题。
在这个app中不是b,根据传入参数类型加推测,应该是sendRequset。最后一个RpcInvoker的我这似乎没有调用到,我就没管他。
修改原frida脚本中的这部分内容
不过有点问题,他原项目我跑起来还是会有其他异常,返回包有问题。
我后面改了下他的脚本,移植到自己用的比较多的项目
https://github.com/noobpk/frida-intercept-encrypted-api
用的比较顺手,缺点比较明显,相比起来这个项目请求响应能对应的找到,我用的这个就不行。
修改的模板如下:
var HttpCaller = Java.use('com.alipay.mobile.common.rpc.transport.http.HttpCaller');
HttpCaller["sendRequest"].overload('com.alipay.mobile.common.transport.http.HttpUrlRequest').implementation = function (a) {
a.setReqData(stringToByte(utf8ByteToUnicodeStr(a.getReqData())));
// console.log(a)
var resp = this.sendRequest(a);
var respStr = utf8ByteToUnicodeStr(resp.getResData());
console.log(respStr)
send({ from: "/http", payload: respStr, api_path: "response"});
var data;
var op = recv('input', function (value) {
data = value.payload
console.log(data);
});
op.wait()
resp.setResData(stringToByte(data))
return resp
}
测试再挂起frida进行测试,发现可以了。
参考
https://github.com/F6JO/mPaas-frida-hook
https://github.com/noobpk/frida-intercept-encrypted-api