前言
使用 xposed 模块修改加解密逻辑。
前文我们提到了某ji的内部中的某段解密逻辑,在那里使用到了 AES 来对网络返回的结果进行解密。
而这篇文章我们主要是来写一写,如何通过 Xposed 模块来修改类似的逻辑。
正文
本文的代码我们使用以下代码进行分析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public final class C1057a { public static String a(String str) throws Exception { byte[] bArr; byte[] bytes = "4afe899e18fa915e939a6676a2c6ce60".getBytes(StandardCharsets.UTF_8); SecretKeySpec secretKeySpec = new SecretKeySpec(bytes, "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); String string = "fdd140e3d1b737a6"; byte[] bytes2 = string.getBytes(StandardCharsets.UTF_8); cipher.init(2, secretKeySpec, new IvParameterSpec(bytes2)); byte[] bArr2 = new byte[str.length() / 2]; int length = str.length() / 2; for (int i8 = 0; i8 < length; i8++) { int i10 = i8 * 2; int i11 = i10 + 1; String strSubstring = str.substring(i10, i11); int i12 = Integer.parseInt(strSubstring, 16); String strSubstring2 = str.substring(i11, i10 + 2); bArr2[i8] = (byte) ((i12 * 16) + Integer.parseInt(strSubstring2, 16)); } byte[] bArrDoFinal = cipher.doFinal(bArr2); Charset charsetForName = Charset.forName("utf-8"); return new String(bArrDoFinal, charsetForName); } }
|
什么,你问我代码哪来的,其实是我在梦中梦到的🥹,绝不是上篇帖子改的🤗。
这里我们以旧版 xposed api 来编写。
如果我们想让任何字符串进入该函数,统一返回相同的字符串,那么我们可以写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public class MainHook implements IXposedHookLoadPackage { static String TARGET_PACKAGE_NAME = "com.a.b"; static String TARGET_CLASS_NAME = "C1057a"; static String TARGET_METHOD_NAME = "a";
@Override public void handleLoadPackage(XC_LoadPackage.LoadPackageParam param) { if (!param.packageName.equals(TARGET_PACKAGE_NAME)) { return; } hook(param); }
private void hook(XC_LoadPackage.LoadPackageParam param) { XposedHelpers.findAndHookMethod( TARGET_CLASS_NAME, param.classLoader, TARGET_METHOD_NAME, String.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) { param.setResult("[{\"identity\":\"003-000-00001\",\"privilege\":{\"totalInServiceDays\":0},\"privilegeStatus\":\"activated\",\"canPay\":false}]".getBytes()); }
@Override protected void afterHookedMethod(MethodHookParam param) { } } ); } }
|
这里的核心就是使用 findAndHookMethod 找到对应的方法,然后通过重写 XC_MethodHook 的 beforeHookedMethod 来修改返回值。
当然,这种方法有一个问题,就是当版本更新的时候,这个类名可能会由于混淆而变更。这样每个版本都得修改代码,非常的麻烦。
那么,有没有另一种方法可以一劳永逸呢?
其实,我们可以换个角度,思考下这个方法的结果是从哪来的,回答 cipher.doFinal ,而且这个方法是内置的方法,是不会被混淆的,那么,我们就可以 hook 这个方法,当然,我们必须得区分 cipher 这个实例是来自 C1057a.a 的,所以这里我们需要通过 key 和 iv 来做判断:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| public class MainHook implements IXposedHookLoadPackage { static String TARGET_PACKAGE_NAME = "com.a.b"; static String TARGET_CLASS_NAME = "C1057a"; static String TARGET_METHOD_NAME = "a";
@Override public void handleLoadPackage(XC_LoadPackage.LoadPackageParam param) { if (!param.packageName.equals(TARGET_PACKAGE_NAME)) { return; } hook(param); }
private static final WeakHashMap<Cipher, Boolean> targetCiphers = new WeakHashMap<>();
void hook(XC_LoadPackage.LoadPackageParam param) { XposedHelpers.findAndHookMethod( Cipher.class, "init", int.class, Key.class, AlgorithmParameterSpec.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) { Key key = (Key) param.args[1]; AlgorithmParameterSpec spec = (AlgorithmParameterSpec) param.args[2];
if (!(key instanceof SecretKeySpec)) { return; } if (!(spec instanceof IvParameterSpec)) { return; } Cipher cipher = (Cipher) param.thisObject;
if (!cipher.getAlgorithm().contains("AES/CBC")) { return; } String keyHex = new String(key.getEncoded(), StandardCharsets.UTF_8); String ivHex = new String(((IvParameterSpec) spec).getIV(), StandardCharsets.UTF_8); if (keyHex.contains("06ec6c2a") && ivHex.contains("6a737b1d")) { targetCiphers.put(cipher, true); } } } ); XposedHelpers.findAndHookMethod( Cipher.class, "doFinal", byte[].class, new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) { Cipher cipher = (Cipher) param.thisObject;
if (!Boolean.TRUE.equals(targetCiphers.get(cipher))) { return; }
byte[] plain = (byte[]) param.getResult(); String text = new String(plain, StandardCharsets.UTF_8); String fake = ""; param.setResult(fake.getBytes(StandardCharsets.UTF_8)); } } ); } }
|
当然我们这个写法是旧版 xposed 的,使用新版 API 的写法可以查看我的另一个帖子:记一次将 xposed 模块迁移到新版 api。