本教程以某鱼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(); } } }