美图秀秀 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 数据解密和反序列化