一次失败的签名算法逆向过程

某电商App
首先抓包看到请求如下(magisk+edxposed+trustmealready屏蔽ssl验证)

直接jadx打开apk搜索functionId关键字

先定位到了第三个函数

public final String mo15331a(JSONObject jSONObject, String str) { //json对象
        try {
            String b = mo15238b();
            TreeMap treeMap = new TreeMap(new Comparator<String>() {
                /* renamed from: a */
                public int compare(String str, String str2) {
                    return str.compareTo(str2);
                }
            });
            if (jSONObject != null) {
                Iterator keys = jSONObject.keys();
                while (keys.hasNext()) {
                    String str2 = (String) keys.next();
                    if (!TextUtils.isEmpty(jSONObject.optString(str2))) {
                        treeMap.put(str2, jSONObject.optString(str2)); //遍历json对象
                    }
                }
            }
            if (!TextUtils.isEmpty(str)) {
                treeMap.put(JshopConst.JSKEY_JSBODY, str); //加入body
            }
            if (!TextUtils.isEmpty(b)) {
                treeMap.put("functionId", b);
            }
            StringBuilder sb = new StringBuilder();
            for (Entry value : treeMap.entrySet()) {
                sb.append((String) value.getValue()).append("&"); //拼接数据 k=v&
            }
            if (sb.toString().endsWith("&")) { //删除最后一个&
                sb.setLength(sb.length() - 1);
            }
            String c = MantoCryptoUtils.m4776c(C2656c.m2509a() + "7D6D16CC3D2BE89108F9DCFC9A855253", "616E746F"); //获取key C2656c.m2509a() = 2AA64BD44C4381F31D9DA68EFE377874
            MantoLog.m4788d("sign  ", "secretKey --->  " + c); // 02ad4470d1a24880b6d3aca1988694bf
            MantoLog.m4788d("sign  ", "data --->  " + sb); //需要签名的数据
            String a = MantoCryptoUtils.m4772a(sb.toString().getBytes("UTF-8"), c.getBytes("UTF-8")); //签名 HmacSHA256
            MantoLog.m4788d("sign  ", "sign --->  " + a);
            if (!TextUtils.isEmpty(a)) {
                return a.toLowerCase();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

发现大概加密流程是
先把url参数传递进来,然后拼接成k=v&格式,然后使用MantoCryptoUtils.m4776c获取到hash_hmac的key,最后进行hash_hmac sha256加密,

MantoCryptoUtils.m4776c
  public static String getsecretKey(String str, String str2) {
    try{
        byte[] bytes = ("6A642D6D" + str2).getBytes("UTF-8");
        for (int i = 0; i < 16; i++) {
            bytes[i] = (byte) (bytes[i] ^ f3228d[i]);
        }
        String str3 = str + "D4F1E5BBBE321897A0F4BDEC91197EE0";
        SecretKeySpec secretKeySpec = new SecretKeySpec(bytes, f3226b);
        Cipher instance = Cipher.getInstance(f3227c);
        instance.init(2, secretKeySpec);
        return new String(instance.doFinal(xorData(str3.getBytes("UTF-8"))), "UTF-8");
    }catch (Exception e){
        return "";
    }
    }

直接把方法提取出来,写一个脚本获取到完整的key

然后在带入参数进行直接加密测试即可

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import main.util.ReplyCode;
import java.util.TreeMap;
/* renamed from: jd.wjlogin_sdk.util.ReplyCode */
/* compiled from: Proguard */

public class Main {
    private static byte[] f3228d = {ReplyCode.reply0x26, ReplyCode.reply0x38, 11, ReplyCode.reply0x64, -92, -85, 114, -41, -63, 30, ReplyCode.reply0x7b, ReplyCode.reply0x88, ReplyCode.reply0xaa, 102, 10, -32};
    private static String f3226b = "AES";
    private static String f3227c = "AES/ECB/PKCS5Padding";
    public static void main(String[] args) {
        System.out.println("Hello World!");
        System.out.println(getsecretKey("2AA64BD44C4381F31D9DA68EFE3778747D6D16CC3D2BE89108F9DCFC9A855253","616E746F"));
        String c=getsecretKey("2AA64BD44C4381F31D9DA68EFE3778747D6D16CC3D2BE89108F9DCFC9A855253","616E746F");
        String sb="asdsadasd";

        try{
        
            String a = Sign(sb.getBytes("UTF-8"), c.getBytes("UTF-8")); //签名 HmacSHA256
            System.out.println(a);
        }catch (Exception e){

        }

    }

    public static String Sign(byte[] bArr, byte[] bArr2) {
        try {
            SecretKeySpec secretKeySpec = new SecretKeySpec(bArr2, "HmacSHA256");
            Mac instance = Mac.getInstance("HmacSHA256");
            instance.init(secretKeySpec);
            return toHex(instance.doFinal(bArr));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e2) {
            e2.printStackTrace();
        }
        return null;
    }
    private static String toHex(byte[] bArr) {
        StringBuilder sb = new StringBuilder();
        int i = 0;
        while (bArr != null && i < bArr.length) {
            String hexString = Integer.toHexString(bArr[i] & 255);
            if (hexString.length() == 1) {
                sb.append('0');
            }
            sb.append(hexString);
            i++;
        }
        return sb.toString().toUpperCase();
    }
    private static byte[] xorData(byte[] bArr) {
        if (bArr.length % 2 != 0) {
            return null;
        }
        byte[] bArr2 = new byte[(bArr.length / 2)];
        for (int i = 0; i < bArr.length; i += 2) {
            bArr2[i / 2] = (byte) Integer.parseInt(new String(bArr, i, 2), 16);
        }
        return bArr2;
    }
    public static String getsecretKey(String str, String str2) {
    try{
        byte[] bytes = ("6A642D6D" + str2).getBytes("UTF-8");
        for (int i = 0; i < 16; i++) {
            bytes[i] = (byte) (bytes[i] ^ f3228d[i]);
        }
        String str3 = str + "D4F1E5BBBE321897A0F4BDEC91197EE0";
        SecretKeySpec secretKeySpec = new SecretKeySpec(bytes, f3226b);
        Cipher instance = Cipher.getInstance(f3227c);
        instance.init(2, secretKeySpec);
        return new String(instance.doFinal(xorData(str3.getBytes("UTF-8"))), "UTF-8");
    }catch (Exception e){
        return "";
    }


    }
}

最后发现使用这个加密方式的接口已经废弃不再使用,所以试一次失败的逆袭过程,在花点时间找一下新接口的加密算法了,记录一下过程。

标签: 安全WIKI