美图秀秀 sig参数分析
转载一篇好的博客,原始链接 https://mp.weixin.qq.com/s/5kUDmlPvIOw-6mdzywvyFA
推荐一波,这是博主的网站:https://www.qinless.com/ 有兴趣看看,多学习学习。
今天我们要研究的app是美图秀秀,版本号:v9080,下载链接:https://www.wandoujia.com/apps/37577/history_v9080
同系列文章推荐下:
1.聚美app之 _sign参数分析
2.大润发优鲜app之paramsMD5参数分析
3.美图秀秀 sig参数分析
4.贝壳app Authorization参数分析
5.豆瓣app sig参数分析
6.半次元app之data参数分析
转载请注明出处:
https://blog.csdn.net/weixin_38819889/article/details/122307928?spm=1001.2014.3001.5501
美图秀秀请求接口中有一个sig参数加密
1.来我们先抓个包:
2.java 层分析
「直接全局搜索 sig 关键词即可」
最终是定位到了这个函数 com.meitu.secret.SigEntity.generatorSig
调用 SigEntity.nativeGeneratorSig 执行加密逻辑。
该 native 函数在 librelease_sig.so 文件里
3.so 分析
「librelease_sig so 文件都是静态注册的函数,也没啥对抗分析,打开即可分析」
打开 so 可以看到符号都没混淆,逻辑还是比较清晰的。先来看看 ValidateKey::getValidateResult 函数逻辑。
进来这里调用了 JavaHelper::getAndroidAPKKeyHash 函数,看起来像是校验 apk 签名。
点进来逻辑很清晰一眼望去,确实是获取签名。下面再来看 GeneratorSIG sig 生成函数。
刚开始掉用了一个 GetSecretKey 函数,获取 key,接着是拼接一些不明的字符串,最后调用了 MD5_Calculate 计算函数。着重分析下这个。
md5 init update final 函数一应俱全,应该是标准的。
点进 init 函数,这些常量确实是标准的
4.frida hook
hook java 函数
var SigEntity = Java.use("com.meitu.secret.SigEntity"); SigEntity.generatorSig.overload('java.lang.String', '[Ljava.lang.String;', 'java.lang.String', 'java.lang.Object').implementation = function (a, b, c, d) {printLog('SigEntity.generatorSig.a: ', a);printLog('SigEntity.generatorSig.b: ', b);printLog('SigEntity.generatorSig.c: ', c);printLog('SigEntity.generatorSig.d: ', d);var res = this.generatorSig(a, b, c, d);printLog('SigEntity.generatorSig.res: ', res.sig.value);return res; }hook so 函数
「里面的一部分 hook 逻辑,在后面使用 unidbg 跑 so 时会用的」
frida hook 命令跑起来,把结果保存到文件中,generatorSig 函数入参, 参数比较简单,也就是请求的一些参数。
so md5 update 函数
hook 结果 md5 update 函数一共调用了三次。这对 md5 算法有了解的小伙伴就会看的出来,只有第一次是真正的数据,后面两次全是填充的数据
「Tips: 不了解的可以看看之前分享的密码学文章:https://www.qinless.com/1246」
最终结果:
就是这个 390b028d37b588d2b4380c4aa215be72, 我们来加密下看看是否相同。
最终加密结果相同。
「下面分享下怎么使用 unidbg 跑起来」
5.unidbg
老规矩,先搭架子
package com.xiayu.meituxiuxiu;import com.github.unidbg.AndroidEmulator; import com.github.unidbg.Emulator; import com.github.unidbg.Module; import com.github.unidbg.debugger.BreakPointCallback; import com.github.unidbg.debugger.Debugger; import com.github.unidbg.debugger.DebuggerType; import com.github.unidbg.linux.android.AndroidEmulatorBuilder; import com.github.unidbg.linux.android.AndroidResolver; import com.github.unidbg.linux.android.dvm.*; import com.github.unidbg.linux.android.dvm.array.ArrayObject; import com.github.unidbg.linux.android.dvm.array.ByteArray; import com.github.unidbg.memory.Memory; import unicorn.ArmConst;import java.io.File; import java.io.IOException; import java.security.MessageDigest;public class GetSig_v9080Test extends AbstractJni {private final AndroidEmulator emulator;private final Module module;private final VM vm;public String apkPath = "/Volumes/T7/android/android-file/meituxiuxiu-9.0.8.0.apk";public String soPath2 = "unidbg-android/src/test/resources/test_so/meituxiuxiu/librelease_sig-9.0.8.0.so";GetSig_v9080Test() {emulator = AndroidEmulatorBuilder.for32Bit().build();final Memory memory = emulator.getMemory();memory.setLibraryResolver(new AndroidResolver(23));vm = emulator.createDalvikVM(new File(apkPath));vm.setVerbose(true);vm.setJni(this);DalvikModule dm2 = vm.loadLibrary(new File(soPath2), true);dm2.callJNI_OnLoad(emulator);module = dm2.getModule();}public static void main(String[] args) {GetSig_v9080Test getSig = new GetSig_v9080Test();getSig.destroy();}private void destroy() {try {emulator.close();} catch (IOException e) {e.printStackTrace();}} }
又是熟悉的 bug,这里依赖了 libgnustl_shared.so 我们给他加上。
跑起来,发现啥都没有输出,这没啥事,只要没报错就是好事。下面直接 call 函数
「注意这里的 byte[][] 类型,千万不要直接 vm.resolveClass("[[B") 这样在后面取值会报错,需要使用 ArrayObject + ByteArray 构建(龙哥指点------->ps:龙哥也是一位大佬)」
报错,正常补环境
又报错,但是看不出来啥问题,日志全开看看。
发现这里是调用 GetSuperClass JNI 函数报错的。不知道啥问题点进源码看看 DalvikVM.java:150
这里调用了 dvmClass.getSuperclass 函数,返回空,才报错的。跟进去看看
这个函数返回 superClass 字段,该字段的值来源于初始化的时候。在哪里初始化的呢。这个跟一下源码就可以了,我这里就不再继续分析了。是在 vm.resolveClass 的时候
这里可以传递多个参数,正常都是传递一个,如果有两个第二个参数就是 superClass
咱们加上试试
跑起来,成功了,没有报 superClass 错误了,但是又出现其他的了,不慌点进源码一探究竟
发现这里是个未实现的 JNI 函数,这里为了简单,就直接返回需要的值就行了。使用 jnitrace 看看返回值是啥
这里是个 0 直接返回
上面正常补环境即可
这里需要注意下,android base64 跟 java base64 还是有点区别的(龙哥的精讲课程里也说到过),这里为了不出问题,就直接复制了 android base64 的代码,大家自行复制就行。
环境补完,但是出奇的是结果尽然为空就很奇怪。不慌继续分析
「复制最后一次 NewStringUTF 的地址,ida 里跳过去」
是在这里操作的,x 查看该函数的交叉引用。
跟到了这里 LABEL_8 代码块,很明显是在 ValidateKey::getValidateResult 函数之后的 if 判断里调用的,在分析该函数逻辑。
这里有多地方会返回 -1 那就应该是该函数出了问题
「Tips: 这里应该是单步调试或者 hook 排除,博主就不去一步步分析了,大家可以自行尝试(具体啥原因也是没分析出来,直接使用 patch 大法搞定它)」
还记得前面的 frida hook 吗,里面就有 hook while 循环里 v11 的值,来看一下
这里循环了三次,最后一次结果为 0,刚好前面的 if 判断不成立就可以继续了
这里直接使用 unidbg hook 强制修改函数返回值为 0,最后也是成功运行出了结果。
6.最后end:
嗯,这篇文章好长啊,转载了我半天时间,后来qinless大哥给了一个固定url 的demo,前前后后分析了半天请求url参数差别,最后还是给还原成Python,测试 详情,评论和搜索接口都能用。
可以看到计算出来的结果 美图秀秀sig: 9667703fa8bc772b436ad0b451de9a6d 和抓包拿到的一模一样。
核心代码 就不公布了毕竟对人家不太友善,有兴趣的朋友可以一起交流学习(扣扣: 519545433)
总结
以上是生活随笔为你收集整理的美图秀秀 sig参数分析的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 贝壳app Authorization参
- 下一篇: 大众点评app 数据解密和反序列化