在对安卓手机进行取证时,经常需要备份手机的应用程序数据,备份后得到的数据文件为ab格式。虽然大部分的取证软件都可以对ab文件进行分析,但是,有时候你可能需要解析ab文件的文件系统,然后对应用程序数据进行手动分析。ab文件一般分两种,一种是没有加密,这种文件前面有24字节的文件头,文件头包含none标志,文件头之后就是数据;一种是加密的备份文件,它的文件头就比较复杂了,文件头包含AES-256标志。
Androidbackup extractor是一个开源项目,从sourceforge和github都可以下载最新的源码,它采用java编写,因此运行的时候需要java环境。Android backup extractor可以将ab格式转换为我们熟悉的tar格式,最重要的是它同时支持没有加密和数据加密的adb备份。下面分别介绍一下转换时的命令格式:
对于没有加密的ab文件,命令格式为:java -jar abe.jar unpack 。如果执行成功,则没有任何信息提示;如果出现错误提示,有可能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 [password]。如果执行成功,则没有任何信息提示;如果出现错误信息,有可能ab文件损坏或者密码错误。
Androidbackup extractor除了可以将ab转化为tar,还可以将tar转换为ab。例如,你需要修改一些应用程序数据,但是手机又无法root,因此可以先将手机数据备份为ab文件,将ab备份转换为tar后修改数据,然后将修改后的tar转换为ab备份,最后恢复修改后的ab备份到设备。
题目链接:https://adworld.xctf.org.cn/task/task_list?type=mobile&number=6&grade=0&page=1
下载地址: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,也就是我们需要分析的程序
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 库文件加载进来。name:Stranger
、
password:123456
放入其中。com.example.yaphetshan.tencentwelcome.a.a
类。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!}