抓包
通過對數據包的分析比對,能夠看到每次請求都會自動生成相應的請求參數,並計算出一個加密後的參數__skcy,服務端根據這些參數信息和請求內容作校驗,校驗經過服務端纔會返回正確的結果。java
找到計算__skcy關鍵函數
通過搜索關鍵字咱們進入到 CandyPreprocessor類的getParametersSignature方法算法
private String getParametersSignature(Builder builder, Context context) throws Exception { Object[] objArr = new Object[]{builder, context}; ChangeQuickRedirect changeQuickRedirect = changeQuickRedirect; String str = "d7fd4e92b3bd07b96007e804b4226165"; if (PatchProxy.isSupport(objArr, this, changeQuickRedirect, false, str, 6917529027641081856L)) { return (String) PatchProxy.accessDispatch(objArr, this, changeQuickRedirect, false, str); } if (builder != null) { Object baseString = baseString(); if (TextUtils.isEmpty(baseString)) { throw new Exception("CandyPreprocessor getParametersSignature normalizedURI is null"); } List arrayList = new ArrayList(); appendList(arrayList, builder, false); if (this.version == CandyVersion.Ver1_0) { arrayList.add(new MyEntry("__sksc", this.candyOriginalMaterial.getScheme())); } if (formURLEncoded() != null) { builder = new StringBuilder("/?"); builder.append(new String(this.candyOriginalMaterial.getPostContent())); appendList(arrayList, Uri.parse(builder.toString()).buildUpon(), true); } builder = getPercentList(arrayList); dictionarySort(builder); builder = getNormalizedParameters(builder); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(this.candyOriginalMaterial.getHttpMethod()); stringBuilder.append(StringUtil.SPACE); stringBuilder.append(baseString); stringBuilder.append(StringUtil.SPACE); stringBuilder.append(builder); builder = stringBuilder.toString(); if (formURLEncoded()) { builder = builder.getBytes(); } else if (this.candyOriginalMaterial.getPostContent() == null) { builder = builder.getBytes(); } else { builder = builder.getBytes(); Builder builder2 = new byte[(builder.length + this.candyOriginalMaterial.getPostContent().length)]; System.arraycopy(builder, 0, builder2, 0, builder.length); System.arraycopy(this.candyOriginalMaterial.getPostContent(), 0, builder2, builder.length, this.candyOriginalMaterial.getPostContent().length); builder = builder2; } return CandyJni.getCandyDataWithKeyForJava(context, builder, "CandyKey"); } throw new Exception("CandyPreprocessor getParametersSignature builder is null"); }
在接下來的跳轉鏈以後,咱們又找到了CandyJni的getCandyDataWithKeyForJava方法:app
public static String getCandyDataWithKeyForJava(Context context, byte[] bArr, String str) { Object[] objArr = new Object[]{context, bArr, str}; ChangeQuickRedirect changeQuickRedirect = changeQuickRedirect; String str2 = "8806cdcfdd305bd7b7224b07a9fb85e3"; if (PatchProxy.isSupport(objArr, null, changeQuickRedirect, true, str2, 6917529027641081856L)) { return (String) PatchProxy.accessDispatch(objArr, null, changeQuickRedirect, true, str2); } if (MTGuard.selfExceptionCheck() && bArr != null) { if (bArr.length != 0) { return getCandyDataWithKey(context, bArr, str); } } return null; }
而後咱們進入函數
public static native String getCandyDataWithKey(Object obj, byte[] bArr, String str);
這是一個本地方法,所以,咱們須要在原生代碼中找到getCandyDataWithKey方法。ui
打開so文件
通過靜態分析 咱們得知是在getCandyDataWithKey是在 libmtguard.so 中,咱們用IDA打開它this
咱們在導出函數列表中能夠看到,只有JNI_Onload,
加密
動態調試還原算法
通過一系列的動態調試,最終還原出具體算法。請求推薦接口spa
成功取到數據。3d