【愚公系列】2021年12月 攻防世界-简单题-MOBILE-004(app3)

举报
愚公搬代码 发表于 2021/12/11 00:01:13 2021/12/11
【摘要】 前言 1.ab文件在对安卓手机进行取证时,经常需要备份手机的应用程序数据,备份后得到的数据文件为ab格式。虽然大部分的取证软件都可以对ab文件进行分析,但是,有时候你可能需要解析ab文件的文件系统,然后对应用程序数据进行手动分析。ab文件一般分两种,一种是没有加密,这种文件前面有24字节的文件头,文件头包含none标志,文件头之后就是数据;一种是加密的备份文件,它的文件头就比较复杂了,文件...

前言

1.ab文件

在对安卓手机进行取证时,经常需要备份手机的应用程序数据,备份后得到的数据文件为ab格式。虽然大部分的取证软件都可以对ab文件进行分析,但是,有时候你可能需要解析ab文件的文件系统,然后对应用程序数据进行手动分析。ab文件一般分两种,一种是没有加密,这种文件前面有24字节的文件头,文件头包含none标志,文件头之后就是数据;一种是加密的备份文件,它的文件头就比较复杂了,文件头包含AES-256标志。

2.Android backup extractor

Androidbackup extractor是一个开源项目,从sourceforge和github都可以下载最新的源码,它采用java编写,因此运行的时候需要java环境。Android backup extractor可以将ab格式转换为我们熟悉的tar格式,最重要的是它同时支持没有加密和数据加密的adb备份。下面分别介绍一下转换时的命令格式:

对于没有加密的ab文件,命令格式为:java -jar abe.jar unpack <backup.ab> <backup.tar>。如果执行成功,则没有任何信息提示;如果出现错误提示,有可能ab文件损坏,需要重新制作备份。

对于加密的ab文件,转换就比较麻烦,需要安装Java Cryptography Extension,可以从java官网下载文件local_policy.jar和US_export_policy.jar,复制到当前系统的java相应目录下,具体细节大家可以参考Android backup extractor的readme.txt文件。对于加密ab备份的转换,具体命令格式为:java -jar abe.jar unpack <backup.ab> <backup.tar> [password]。如果执行成功,则没有任何信息提示;如果出现错误信息,有可能ab文件损坏或者密码错误。

Androidbackup extractor除了可以将ab转化为tar,还可以将tar转换为ab。例如,你需要修改一些应用程序数据,但是手机又无法root,因此可以先将手机数据备份为ab文件,将ab备份转换为tar后修改数据,然后将修改后的tar转换为ab备份,最后恢复修改后的ab备份到设备。

一、app3

题目链接:https://adworld.xctf.org.cn/task/task_list?type=mobile&number=6&grade=0&page=1

二、答题步骤

1.Android backup extractor

下载地址:https://github.com/nelenkov/android-backup-extractor

编译安卓文件

mvn clean package

会生成target文件夹
在这里插入图片描述

还原ab安卓备份文件

java -jar abe.jar unpack app3.ab app3.tar

在这里插入图片描述
接下来解压app3.tar,一番搜寻后,发现了base.apk,也就是我们需要分析的程序
在这里插入图片描述

2.jadx反编译apk文件

package com.example.yaphetshan.tencentwelcome;

import android.content.ContentValues;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import com.example.yaphetshan.tencentwelcome.a.a;
import net.sqlcipher.database.SQLiteDatabase;

/* loaded from: classes.dex */
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private SQLiteDatabase a;
    private a b;
    private Button c;

    /* JADX INFO: Access modifiers changed from: protected */
    @Override // android.support.v7.app.AppCompatActivity, android.support.v4.app.FragmentActivity, android.support.v4.app.BaseFragmentActivityGingerbread, android.app.Activity
    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(R.layout.activity_main);
        this.c = (Button) findViewById(R.id.add_data);
        this.c.setOnClickListener(this);
        SharedPreferences.Editor edit = getSharedPreferences("test", 0).edit();
        edit.putString("Is_Encroty", "1");
        edit.putString("Encryto", "SqlCipher");
        edit.putString("ver_sion", "3_4_0");
        edit.apply();
        a();
    }

    private void a() {
        SQLiteDatabase.loadLibs(this);
        this.b = new a(this, "Demo.db", null, 1);
        ContentValues contentValues = new ContentValues();
        contentValues.put("name", "Stranger");//用户名
        contentValues.put("password", (Integer) 123456);//密码
        a aVar = new a();
        String a = aVar.a(contentValues.getAsString("name"), contentValues.getAsString("password"));//Stra1234 函数1在下面
        this.a = this.b.getWritableDatabase(aVar.a(a + aVar.b(a, contentValues.getAsString("password"))).substring(0, 7));//函数2在下面
        this.a.insert("TencentMicrMsg", null, contentValues);
    }

    @Override // android.view.View.OnClickListener
    public void onClick(View view) {
        if (view == this.c) {
            Intent intent = new Intent();
            intent.putExtra("name", "name");
            intent.putExtra("password", "pass");
            intent.setClass(this, AnotherActivity.class);
            startActivity(intent);
        }
    }
}

函数1

public String a(String str, String str2) {
    String substring = str.substring(0, 4);
    return substring + str2.substring(0, 4);
}

执行结果:Stra1234

  • 第一行SQLiteDatabase.loadLibs(((Context)this));将所需要的 sqlitecipher 库文件加载进来。
  • 第二行实例化一个 sqlitehelper 类。
  • 第三、四、五行实例化了一个 ContentValues 类 并 将 键 值 对 name:Stranger
    password:123456放入其中。
  • 第六行实例化了一个com.example.yaphetshan.tencentwelcome.a.a类。
  • 第七行获取了 v2 变量的值。
  • 第八行调用了getWritableDatabase函数,传进去的字符串参数即是数据库解密的密钥。

现在目标已经很明确了,就是获取数据库解密密钥(猜一下 flag 就藏在加密的 sqlite 数
据库中),而该密钥由com.example.yaphetshan.tencentwelcome.a.a里面的方法生成,而
这个类又调用了 b.java 里面的方法,如图所示:
在这里插入图片描述
函数2

package com.example.yaphetshan.tencentwelcome.a;

import java.security.MessageDigest;

/* compiled from: SHA1Manager.java */
/* loaded from: classes.dex */
public class b {
    public static final String a(String str) {
        char[] cArr = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        try {
            byte[] bytes = str.getBytes();
            MessageDigest instance = MessageDigest.getInstance("MD5");
            instance.update(bytes);
            byte[] digest = instance.digest();
            int length = digest.length;
            char[] cArr2 = new char[length * 2];
            int i = 0;
            for (byte b : digest) {
                int i2 = i + 1;
                cArr2[i] = cArr[(b >>> 4) & 15];
                i = i2 + 1;
                cArr2[i2] = cArr[b & 15];
            }
            return new String(cArr2);
        } catch (Exception e) {
            return null;
        }
    }

    public static final String b(String str) {
        char[] cArr = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        try {
            byte[] bytes = str.getBytes();
            MessageDigest instance = MessageDigest.getInstance("SHA-1");
            instance.update(bytes);
            byte[] digest = instance.digest();
            int length = digest.length;
            char[] cArr2 = new char[length * 2];
            int i = 0;
            for (byte b : digest) {
                int i2 = i + 1;
                cArr2[i] = cArr[(b >>> 4) & 15];
                i = i2 + 1;
                cArr2[i2] = cArr[b & 15];
            }
            return new String(cArr2);
        } catch (Exception e) {
            return null;
        }
    }
}

在这里插入图片描述
执行:

import java.security.MessageDigest;

class SHA1Manager {

    public static final String m24a(String str) {
        char[] cArr = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        try {
            byte[] bytes = str.getBytes();
            MessageDigest instance = MessageDigest.getInstance("MD5");
            instance.update(bytes);
            // 这里的r4是自己添加的,为了程序正常运行
            int r4 = instance.getDigestLength();
            char[] cArr2 = new char[(r4 * 2)];
            int i = 0;
            for (byte b : instance.digest()) {
                int i2 = i + 1;
                cArr2[i] = cArr[(b >>> 4) & 15];
                i = i2 + 1;
                cArr2[i2] = cArr[b & 15];
            }
            return new String(cArr2);
        } catch (Exception e) {
            return null;
        }
    }

    /* renamed from: b */
    public static final String m25b(String str) {
        char[] cArr = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        try {
            byte[] bytes = str.getBytes();
            MessageDigest instance = MessageDigest.getInstance("SHA-1");
            instance.update(bytes);
            // 这里的r4是自己添加的,为了程序正常运行
            int r4 = instance.getDigestLength();
            char[] cArr2 = new char[(r4 * 2)];
            int i = 0;
            for (byte b : instance.digest()) {
                int i2 = i + 1;
                cArr2[i] = cArr[(b >>> 4) & 15];
                i = i2 + 1;
                cArr2[i2] = cArr[b & 15];
            }
            return new String(cArr2);
        } catch (Exception e) {
            return null;
        }
    }
    public static void main(String[] args){
        String s = SHA1Manager.m25b("Stra1234" + SHA1Manager.m24a("Stra1234") + "yaphetshan").substring(0, 7);
        System.out.println(s);
    }

}
this.f32a = this.f33b.getWritableDatabase(aVar.mo6316a(a + aVar.mo6318b(a, contentValues.getAsString("password"))).substring(0, 7));
    也就是 ⬇
this.f32a = this.f33b.getWritableDatabase("ae56f99");

得到:ae56f99

用ae56f99登录数据库找到:VGN0ZntIM2xsMF9Eb19ZMHVfTG92M19UZW5jM250IX0=
在这里插入图片描述
base64进行解密得到本题最终的flag:Tctf{H3ll0_Do_Y0u_Lov3_Tenc3nt!}
在这里插入图片描述


总结

  • Android backup extractor
  • jadx
  • base64
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。