本教程以某魚App v6.5.10版本為例
第一步:反編譯某魚App
利用dex2jar工具反編譯某魚APK文件,反編譯具體流程可看我的教程《App反編譯工具dex2jar、JD-GUI的使用》。
ps:dex2jar反編譯某魚App過程可能會碰到內存溢出問題,需要把dex2jar的最大內存設置大一點;
第二步:在源碼中找到x-sign生成方法
使用jd-gui工具打開反編譯后的jar包查看源碼;
然后使用jd-gui的搜索功能或者自己利用經驗找x-sign生成方法吧,這一步會比較費時間,某魚App的源碼經過了混淆,不同版本都不同,這里我最終通過“sign”關鍵詞搜索到了,生成方法在mtopsdk.security.InnerSignImpl類下,具體代碼如下:
第三步:Hook
找到生成方法后,我們就可以利用Xposed嘗試進行Hook了。
使用XposedHelpers中的findAndHookMethod方法對簽名方法進行hook,方法名為getMtopApiSign,參數有3個,分別為HashMap、String、String;然后重寫XC_MethodHook中的beforeHookedMethod、afterHookedMethod兩個方法,分別對輸入參數、輸出結果進行打印,具體代碼如下:
Class clazz = hostClassLoader.loadClass("mtopsdk.security.InnerSignImpl");
XposedHelpers.findAndHookMethod(clazz, "getMtopApiSign", HashMap.class, String.class, String.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
XposedBridge.log("某魚x-sign參數0:" + param.args[0].toString());
XposedBridge.log("某魚x-sign參數1:" + param.args[1].toString());
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("某魚x-sign結果:" + param.getResult());
}
});
安裝至手機並開啟當前Xposed模塊進行測試。
第四步:完善遠程調用簽名方法接口相關
在invoke方法中完成遠程調用相關代碼的編寫,利用反射調用簽名方法,接口返回簽名結果x-sign。
第五步:測試
安裝HermesAgent至手機,在Xposed中開啟該模塊,並重啟手機;
在瀏覽器中調用遠程接口測試,效果如下:
HermesAgent相關可看我寫的教程《HermesAgent群控系統使用教程》。
最近代碼如下(最終代碼中我還加了一個x-mini-wua參數的生成):
package com.virjar.hermes.hermesagent.hookagent;
import com.koushikdutta.async.http.Multimap;
import com.virjar.hermes.hermesagent.aidl.InvokeRequest;
import com.virjar.hermes.hermesagent.aidl.InvokeResult;
import com.virjar.hermes.hermesagent.plugin.AgentCallback;
import com.virjar.hermes.hermesagent.plugin.SharedObject;
import com.virjar.hermes.hermesagent.util.CommonUtils;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
/**
* 支持閑魚App 6.5.10版本
*
* @author HuaYunBin
*/
public class XianYuSignAgent implements AgentCallback {
private Object signMethodObject;
private Method signMethod;
private Method wuaMethod;
@Override
public String targetPackageName() {
return "com.taobao.idlefish";
}
@Override
public boolean needHook(XC_LoadPackage.LoadPackageParam loadPackageParam) {
return StringUtils.equalsIgnoreCase(loadPackageParam.processName, "com.taobao.idlefish");
}
@Override
public InvokeResult invoke(InvokeRequest invokeRequest) {
String paramContent = invokeRequest.getParamContent();
Multimap nameValuePairs = CommonUtils.parseUrlEncoded(paramContent);
String deviceId = nameValuePairs.getString("deviceId");
String utdId = nameValuePairs.getString("utdId");
String ttId = nameValuePairs.getString("ttId");
// sid可為空
String sid = nameValuePairs.getString("sid");
// uid可為空
String uid = nameValuePairs.getString("uid");
String appKey = nameValuePairs.getString("appKey");
String t = nameValuePairs.getString("t");
String api = nameValuePairs.getString("api");
String data = nameValuePairs.getString("data");
String v = nameValuePairs.getString("v");
if (deviceId == null || utdId == null || appKey == null || t == null || api == null | data == null || v == null) {
return InvokeResult.failed("請求參數錯誤");
}
String sign = makeSign(deviceId, utdId, ttId, sid, uid, appKey, t, api, data, v);
String wua = makeWua(t, appKey);
if (sign == null) {
return InvokeResult.failed("生成Sign失敗");
} else if (wua == null) {
return InvokeResult.failed("生成Wua失敗");
}
Map<String, Object> resultMap = new HashMap<>(2);
resultMap.put("x-sign", sign);
resultMap.put("x-mini-wua", wua);
return InvokeResult.success(resultMap, SharedObject.context);
}
private String makeWua(String t, String appKey) {
HashMap<String, String> hashMap = new HashMap<>(2);
hashMap.put("pageName", "");
hashMap.put("pageId", "");
try {
return (String) wuaMethod.invoke(signMethodObject, t, appKey, null, hashMap, 8);
} catch (Exception e) {
return null;
}
}
private String makeSign(String deviceId, String utdId, String ttId, String sid, String uid, String appKey, String t, String api, String data, String v) {
HashMap<String, String> hashMap = new HashMap<>(11);
hashMap.put("deviceId", deviceId);
hashMap.put("utdid", utdId);
hashMap.put("ttid", ttId);
hashMap.put("appKey", appKey);
hashMap.put("api", api);
hashMap.put("data", URLDecoder.decode(data));
hashMap.put("x-features", "27");
hashMap.put("v", v);
hashMap.put("sid", sid);
hashMap.put("t", t);
hashMap.put("uid", uid);
XposedBridge.log("生成Sign的Map值為: " + hashMap.toString());
try {
return (String) signMethod.invoke(signMethodObject, hashMap, appKey, null);
} catch (Exception e) {
return null;
}
}
@Override
public void onXposedHotLoad() {
ClassLoader hostClassLoader = SharedObject.loadPackageParam.classLoader;
try {
Class clazz = hostClassLoader.loadClass("mtopsdk.security.InnerSignImpl");
XposedHelpers.findAndHookMethod(clazz, "getMtopApiSign", HashMap.class, String.class, String.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
XposedBridge.log("某魚x-sign參數0:" + param.args[0].toString());
XposedBridge.log("某魚x-sign參數1:" + param.args[1].toString());
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("某魚x-sign結果:" + param.getResult());
signMethodObject = param.thisObject;
signMethod = (Method) param.method;
}
});
XposedHelpers.findAndHookMethod(clazz, "getSecBodyDataEx", String.class, String.class, String.class, HashMap.class, int.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
XposedBridge.log("某寶x-mini-wua參數0:" + param.args[0]);
XposedBridge.log("某寶x-mini-wua參數1:" + param.args[1]);
XposedBridge.log("某寶x-mini-wua參數2:" + param.args[2]);
XposedBridge.log("某寶x-mini-wua參數3:" + param.args[3]);
XposedBridge.log("某寶x-mini-wua參數4:" + param.args[4]);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("某寶x-mini-wua結果:" + param.getResult());
wuaMethod = (Method) param.method;
}
});
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
