MASTG-TECH-0023: 审查反编译的 Java 代码

按照 反编译 Java 代码 中的示例,我们假定你已成功反编译并打开了 Android UnCrackable L1 应用,使用的工具是 jadx。jadx 完成反编译后,您可以通过在文件树中选择类来浏览反编译后的类。请注意,许多反编译后的包、类和方法都具有奇怪的单字母名称;这是因为字节码在构建时已使用 ProGuard 进行了“缩小”。这是一种基本的混淆类型,它使字节码更难读取,但对于像这样的相当简单的应用程序,它不会给您带来太多麻烦。但是,当您分析更复杂的应用程序时,它可能会变得非常烦人。

在分析混淆的代码时,在进行过程中注释类名、方法名和其他标识符是一个好习惯。在包sg.vantagepoint.uncrackable1中打开MainActivity类。点击“verify”按钮时,将调用方法verify。此方法将用户输入传递给名为a.a的静态方法,该方法返回一个布尔值。a.a似乎在验证用户输入,因此我们将重构代码以反映这一点。

右键单击类名(a.a中的第一个a),然后从下拉菜单中选择Rename(或按N)。根据您目前对该类的了解,将类名更改为更有意义的名称。例如,您可以将其命名为“Validator”(您可以稍后修改名称)。a.a现在变为Validator.a。按照相同的步骤将静态方法a重命名为check_input

恭喜,您刚刚学习了静态分析的基础知识!静态分析的全部内容在于进行理论分析、注释,并逐步修改有关所分析程序的理论,直到您完全理解或至少足够了解您想要实现的目标为止。

接下来,在check_input方法上按Ctrl+单击(或在 Mac 上按Command+单击)。这将带您进入方法定义。反编译后的方法如下所示:

    public static boolean check_input(String str) {
        byte[] bArrA;
        byte[] bArr = new byte[0];
        try {
            bArrA = sg.vantagepoint.a.a.a(b("8d127684cbc37c17616d806cf50473cc"), Base64.decode("5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc=", 0));
        } catch (Exception e) {
            Log.d("CodeCheck", "AES error:" + e.getMessage());
            bArrA = bArr;
        }
        return str.equals(new String(bArrA));
    }

因此,您有一个 Base64 编码的字符串,该字符串被传递到sg.vantagepoint.a.a 包中的函数 a(再次,一切都称为 a),以及一些看起来非常像十六进制编码的加密密钥(16 个十六进制字节 = 128 位,一种常见的密钥长度)。 这个特定的 a 到底做了什么? Ctrl-单击它以找出答案。

public class a {
    public static byte[] a(byte[] bArr, byte[] bArr2) {
        SecretKeySpec secretKeySpec = new SecretKeySpec(bArr, "AES/ECB/PKCS7Padding");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(2, secretKeySpec);
        return cipher.doFinal(bArr2);
    }
}

现在你到达了某个地方:它只是标准的 AES-ECB。 看起来存储在check_input中的arrby1中的Base64字符串是一个密文。 它使用 128 位 AES 解密,然后与用户输入进行比较。 作为一个额外的任务,尝试解密提取的密文并找到秘密值!

获得解密字符串的更快方法是添加动态分析,如 方法 Hooking 中所述。