咪咕音乐sign协议分析
环境
app 7.7.0
第一个sign
抓包
image-20211226154036370是个小写的16进制的32位字符,jadx搜索"sign"
30多个结果,不过有挺多是调用其他sdk的,比如com.meizu.*
,com.unionpay.*
,这些都不太需要关注。
看看com.migu.tsg.s.b
com.migu.tsg.j.d
直接调用MD5
,frida hook看看就行了,后面就省略了。
第二个sign
image-20211226155157063可以看到是个大写的16进制的32位字符,搜索了"sign"
,看了几个都不太像。然后看到header还有个字段signVersion
,搜索这个字符串,发现也没结果。
尝试hook系统的java.security.MessageDigest
和javax.crypto.Mac
这两个库的函数,然后发现也没有结果。
再换另一种方法,猜测可能是在so
里面生成的,于是尝试使用frida_hook_libart的hook_art.js
,注释其他的模块,只保留NewStringUTF
,然后启动,发现还是没有。
再换另一种方法,使用Yang大佬的Frida实现okhttp3.Interceptor并打印堆栈
function hook_okhttp3() {
// 1. frida Hook java层的代码必须包裹在Java.perform中,Java.perform会将Hook Java相关API准备就绪。
Java.perform(function () {
// 2. 准备相应类库,用于后续调用,前两个库是Android自带类库,后三个是使用Okhttp网络库的情况下才有的类
var ByteString = Java.use("com.android.okhttp.okio.ByteString");
var Buffer = Java.use("com.android.okhttp.okio.Buffer");
var Interceptor = Java.use("okhttp3.Interceptor");
var ArrayList = Java.use("java.util.ArrayList");
var OkHttpClient = Java.use("okhttp3.OkHttpClient");
// 注册一个Java类
var MyInterceptor = Java.registerClass({
name: "okhttp3.MyInterceptor",
implements: [Interceptor],
methods: {
intercept: function (chain) {
console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
var request = chain.request();
try {
console.log("MyInterceptor.intercept onEnter:", request, "\nrequest headers:\n", request.headers());
var requestBody = request.body();
var contentLength = requestBody ? requestBody.contentLength() : 0;
if (contentLength > 0) {
var BufferObj = Buffer.$new();
requestBody.writeTo(BufferObj);
try {
console.log("\nrequest body String:\n", BufferObj.readString(), "\n");
} catch (error) {
try {
console.log("\nrequest body ByteString:\n", ByteString.of(BufferObj.readByteArray()).hex(), "\n");
} catch (error) {
console.log("error 1:", error);
}
}
}
} catch (error) {
console.log("error 2:", error);
}
var response = chain.proceed(request);
try {
console.log("MyInterceptor.intercept onLeave:", response, "\nresponse headers:\n", response.headers());
var responseBody = response.body();
var contentLength = responseBody ? responseBody.contentLength() : 0;
if (contentLength > 0) {
console.log("\nresponsecontentLength:", contentLength, "responseBody:", responseBody, "\n");
var ContentType = response.headers().get("Content-Type");
console.log("ContentType:", ContentType);
if (ContentType.indexOf("video") == -1) {
if (ContentType.indexOf("application") == 0) {
var source = responseBody.source();
if (ContentType.indexOf("application/zip") != 0) {
try {
console.log("\nresponse.body StringClass\n", source.readUtf8(), "\n");
} catch (error) {
try {
console.log("\nresponse.body ByteString\n", source.readByteString().hex(), "\n");
} catch (error) {
console.log("error 4:", error);
}
}
}
}
}
}
} catch (error) {
console.log("error 3:", error);
}
return response;
}
}
});
OkHttpClient.$init.overload('okhttp3.OkHttpClient$Builder').implementation = function (Builder) {
console.log("OkHttpClient.$init:", this, Java.cast(Builder.interceptors(), ArrayList));
this.$init(Builder);
};
var MyInterceptorObj = MyInterceptor.$new();
var Builder = Java.use("okhttp3.OkHttpClient$Builder");
console.log(Builder);
Builder.build.implementation = function () {
// this.interceptors().clear();
this.interceptors().add(MyInterceptorObj);
var result = this.build();
return result;
};
Builder.addInterceptor.implementation = function (interceptor) {
// this.interceptors().clear();
this.interceptors().add(MyInterceptorObj);
return this;
};
console.log("hook_okhttp3...");
});
}
hook_okhttp3();
image-20211226160722609
终于有结果了,可以看到调用堆栈,其中我们比较关注的是com.migu.bizz_v2.interceptor.BaseInterceptor.intercept
,但是这个函数在jadx
看不到啊。。
找不到该怎么办,这时候应该搜索classLoader
function searchClassLoader(className) {
Java.enumerateClassLoaders({
onMatch: function (loader) {
try {
if (loader.findClass(className)) {
Java.classFactory.loader = loader;
console.log("find:", loader);
}
} catch (error) {
}
},
onComplete: function () {
console.log("finish search");
}
})
}
searchClassLoader("com.migu.bizz_v2.interceptor.BaseInterceptor");
image-20211226164642786
虽然有点多,不过我们还是一个找,最后发现是在base_runtime-master.apk
这个文件里,
最后是调用这两个的其中一个,我们已经可以看到调用了SecuritySignUtils.sign
,但是这个方法又不在这两个apk文件里面。
不过jadx无法查看signStreamBody
方法,我们改用GDA打开
可以看到也是调用了SecuritySignUtils
这个类。
继续搜索这个类
searchClassLoader("com.migu.security.SecuritySignUtils");
image-20211226162514604
打开文件看看,发现是在libraries_feature-master.apk
这个文件
所以最终是调用了libmgsign.so
文件,可以hook验证一下。
function hook_security() {
var util = Java.use("com.migu.security.SecuritySignUtils");
var String = Java.use("java.lang.String");
util.signAppend.implementation = function(j, bArr, j2) {
console.log("signAppend-j:", j);
console.log("signAppend-bArr", String.$new(bArr));
console.log("signAppend-j2:", j2);
var ret = this.signAppend(j, bArr, j2);
return ret;
}
util.signEnd.implementation = function(str){
console.log("str:", str);
var ret = this.signEnd(str);
console.log("ret:", ret);
return ret;
}
}
function main() {
Java.perform(function(){
searchClassLoader("com.migu.security.SecuritySignUtils");
hook_security();
})
}
setTimeout(main, 5000);
image-20211226165139221
可惜的是,libmgsign.so
不在上述三个apk文件里,那么怎么找到它呢?frida中执行下列命令
Process.findModuleByName("libmgsign.so")
image-20211226165217497
那就把这个文件pull
下来,ida打开
所以它最后也是个md5,至于输入是什么,是否经过魔改,hook一下md5的init
,update
,final
就清楚了,之后再分析。
网友评论