一道简单的安卓逆向题

Author Avatar
ciaoly 2021年09月06日
  • 在其它设备中阅读本文章

这是第七届职业技能竞赛山东省赛的一道赛题, 价值2分.

题目附件


逆向分析

首先拖入Jadx中看源码, 代码很简单, 也没做混淆. 主要逻辑的代码如下所示:

//.....
byte[] passwordhash = MainActivity.stringToMD5(password.toString());
Toast.makeText(MainActivity.this.getApplicationContext(), "解密flag文件,如果你输入的口令正确,那么你会在解密文件中看到flag的:)", 1).show();
InputStream infile = MainActivity.this.getResources().openRawResource(R.raw.flag);
int data_lenth = 0;
byte[] buffer = new byte[0];
try {
    data_lenth = infile.available();
    buffer = new byte[data_lenth];
    infile.read(buffer);
    infile.close();
} catch (IOException e) {
    e.printStackTrace();
}
for (int i = 0; i < data_lenth; i++) {
    buffer[i] = (byte) (buffer[i] ^ passwordhash[i % 16]);
}
try {
    FileOutputStream outfile = MainActivity.this.openFileOutput("flag.docx", 1);
    outfile.write(buffer);
    outfile.close();
//.....

由于不知道密码, 遂打算设法直接爆破. 通过代码可以看到, flag存储在资源文件flag.docx, 该文件是加密存储的. 加密方法是每16个字节均依次与一个长度为16的byte数组(key)进行异或运算. 因此, 只需要设法找到这个长度为16的key数组, 即可解密该文件.

解密思路是, 找一个正常的docx文件, 根据它的文件结构, 找出docx文件中固定的部分, 将加密文件中相应位置与这部分进行异或运算, 最终得到key. 要注意的是, 这里在寻找固定部分时, 应该确保能够使地址 mod 160..15这个数组填满.

使用HxD打开两个不同的正常的docx文件:

文件1 文件2
image-20210906144553301 image-20210906144503577

可以发现, 在地址为[0, 13] \cup [14, 15]的数据是固定的. 同时, 在地址[0x40, 0x50)之间的值全为零. 根据异或运算的真值表可以得出, 加密文件[0x40, 0x50)处的值即为密码.

0 ^ 0 = 0 
0 ^ 1 = 1 
1 ^ 0 = 1 
1 ^ 1 = 0 

ps: 这里打开的docx文件是用office 2019版默认保存的docx文件, 尝试过使用WPS默认保存的docx文件, 但是发现其结构和题目中的docx文件是不一样的, 如下所示:

WPS的文件 Office的文件 加密的文件
image-20210906145306830 image-20210906145245207 image-20210906145217728

很明显加密文件的结构和Office的文件更相似


在apk中提取出加密文件flag.docx, 编写程序解密该文件.

image-20210906145444561

$flagdoc = [System.IO.File]::ReadAllBytes(".\flag.docx");
$realdoc = [System.IO.File]::ReadAllBytes(".\real.docx");
$key = @();
$output = @();
foreach ($i in 0x40..0x4f) {
    $key += $flagdoc[$i]
}
foreach($i in 0..$flagdoc.Count) {
    $output += ($flagdoc[$i] -bxor $key[$i % 16] );
}
[System.IO.File]::WriteAllBytes("./output.docx", $output);

最后使用Word打开output.docx, 即可得到flag (其实就是key数组:

image-20210906151929762

至于这个hash的源值是什么, 在cmd5.com上查询为付费记录, 其它平台查询均无果. 用hashcat跑了跑, 奈何字典不够大, 也是没能跑出来. 就当是个谜吧.