2020网鼎杯玄武组部分writeup

上周参加了网鼎杯玄武组比赛,现在把两题apk的解题过程分享出来,水平太菜,大佬路过勿喷。

题目名称:java

题目类型:Reverse

下载题目 java.zip, 解压发现一个文件java.apk

jadx-gui打开java.apk

分析MainActivity

    c p;

    /* access modifiers changed from: protected */
    public void onCreate(Bundle bundle) {
        ...
        this.n.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                MainActivity mainActivity;
                String str;
                MainActivity.this.o = MainActivity.this.m.getText().toString();
                MainActivity.this.p = new c();
                if (MainActivity.this.o == null) {
                    mainActivity = MainActivity.this;
                    str = "Need Input";
                } else if (MainActivity.this.p.a(MainActivity.this.o)) {
                    mainActivity = MainActivity.this;
                    str = "Congratulations";
                } else {
                    mainActivity = MainActivity.this;
                    str = "Wrong Flag";
                }
                Toast.makeText(mainActivity, str, 1).show();
            }
        });
    }

关键点在于下面几行代码

MainActivity.this.o = MainActivity.this.m.getText().toString();

...

} else if (MainActivity.this.p.a(MainActivity.this.o)) {
                    mainActivity = MainActivity.this;
                    str = "Congratulations";

用户输入的字符串应该就是flag,调用MainActivity.this.p.a校验flag,如果校验成功就输出Congratulations

而p是class c的实例,我们去看看class c

分析class c

class c的代码如下

public class c {
    public static String a = "aes_check_key!@#";
    public static String b = "VsBDJCvuhD65/+sL+Hlf587nWuIa2MPcqZaq7GMVWI0Vx8l9R42PXWbhCRftoFB3";
    int[] c = {214, 144, 233, 254, 204, 225, 61, 183, 22, 182, 43, a.j.AppCompatTheme_textColorAlertDialogListItem, 20, 194, 40, 251, 44, 5, 43, a.j.AppCompatTheme_textColorAlertDialogListItem, 154, a.j.AppCompatTheme_windowMinWidthMinor, 42, 190, 4, 195, 43, a.j.AppCompatTheme_textColorAlertDialogListItem, 170, 68, 19, 38, 73, 134, 43, a.j.AppCompatTheme_textColorAlertDialogListItem, 153, 156, 66, 80, 244, 145, 80, a.j.AppCompatTheme_textColorAlertDialogListItem, 239, 152, 122, 98, 50, 214};
    d d;

    public boolean a(String str) {
        byte[] bArr = new byte[0];
        byte[] a2 = e.a(str.getBytes(), a.getBytes());
        this.d = new d();
        this.d.a(a2, 22, this.c);
        return new String(b.a(a2)).equals(b);
    }
}

这里是破解的关键,我们来梳理一下流程
第一步 aes加密
byte[] a2 = e.a(str.getBytes(), a.getBytes());

第二步 异或运算
this.d.a(a2, 22, this.c);

第三步 base64编码
new String(b.a(a2))

第四步 比较结果
new String(b.a(a2)).equals(b);
比较第三步的结果与b是否一致,而b为”VsBDJCvuhD65/+sL+Hlf587nWuIa2MPcqZaq7GMVWI0Vx8l9R42PXWbhCRftoFB3”

到这里,解题思路就很清晰了,逆向整个算法
第一步
把b通过base64解编码,结果赋值给x

第二步
把x经过异或运算,结果赋值给y

第三步
把y经过aes解密,结果赋值给z,z则为我们要的flag

实现脚本如下:

import base64
from Crypto.Cipher import AES

b = "VsBDJCvuhD65/+sL+Hlf587nWuIa2MPcqZaq7GMVWI0Vx8l9R42PXWbhCRftoFB3"

c = [214, 144, 233, 254, 204, 225, 61, 183, 22, 182, 43, 103, 20, 194, 40, 251, 44, 5, 43, 103, 154, 118, 42, 190, 4,
     195, 43, 103, 170, 68, 19, 38, 73, 134, 43, 103, 153, 156, 66, 80, 244, 145, 80, 103, 239, 152, 122, 98, 50, 214]

x = base64.b64decode(b)

y = []
for i in range(len(x)):
    y.append(x[i] ^ 22 ^ c[i])
y = bytes(y)

aeskey = 'aes_check_key!@#'
cipher = AES.new(aeskey, AES.MODE_ECB)
z = cipher.decrypt(y)

print(z)

执行上述脚本,发现解密后的数据不对,再回去看看apk代码,发现在App类中,有一行代码

c.a = c.a.replace("e", "o");

而c.a就是我们看到的aes密钥

public class c {
    public static String a = "aes_check_key!@#";

那只要把上述python脚本中,把aeskey = ‘aes_check_key!@#’替换为aeskey = ‘aes_check_key!@#’.replace(‘e’, ‘o’).encode()即可解题成功

题目名称:vulcrack

题目类型:misc

下载 vulcrack.zip,解压发现vulcrack.apk

用jadx-gui打开apk,发现assets中有libjiagu.so,是用360加固了

先脱壳

手机端准备工作

frida-server传入手机

通过adb install vulcrack.apk安装apk

启动frida-server并打开vulcrack app

pc端准备工作

下载脱壳工具,https://github.com/hluwa/FRIDA-DEXDump

进入FRIDA-DEXDump执行python main.py

即可在FRIDA-DEXDump目录下看到dump出来的dex文件

用jadx-gui打开dex文件

主要的逻辑如下

public class Flag {
    public static String keyFirst = "Zm1jan85NztBN0c0NjJIOzJGLzc8STk0OTZFSDE=";
    public static String keySecond = "QTpISTlFNEkxRTY8fQ==";

    public static String calcFlagFirstStep() {
        return comm(Base64.decodeToString(keyFirst), 8);
    }

    public static String calcFlagSecondStep() {
        return comm(Base64.decodeToString(keySecond), 4);
    }

    public static String comm(String str, int num) {
        byte[] cmdbyte = str.getBytes();
        for (byte i = 0; i < cmdbyte.length; i = (byte) (i + 1)) {
            cmdbyte[i] = (byte) (cmdbyte[i] - (i % num));
        }
        try {
            return new String(cmdbyte, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return "";
        }
    }
}

编写python解密代码vulcrack.py

import base64

keyFirst = "Zm1jan85NztBN0c0NjJIOzJGLzc8STk0OTZFSDE="
keySecond = "QTpISTlFNEkxRTY8fQ=="

def comm(key, num):
    ns = []
    for i in range(len(key)):
        ns.append(key[i] - (i % num))
    print(bytes(ns))

comm(base64.b64decode(keyFirst), 8)
comm(base64.b64decode(keySecond), 4)

执行python vulcrack.py即可获取flag

Table of Contents