攻防世界app3
- 攻防世界app3
这两天配安卓逆向环境,拿这个题试一下我的环境
附件下下来是一个.ab文件(Android Backup 文件)
.ab
文件通常由 adb backup
命令生成,可以使用android-backup-extractor工具(https://github.com/nelenkov/android-backup-extractor)进行数据提取,但是最新版本的 android-backup-extractor
项目里,下载下来是一个叫 abe
的可执行文件(没有 .jar
后缀),不是以前的 abe.jar
了,遂另外找了一个abe.jar
(https://github.com/nelenkov/android-backup-extractor/releases),且要在java环境下运行,把它们全都放在同一文件夹下,运行java -jar abe.jar unpack app3.ab app3.tar
。
得到tar以后解压,得到base.apk
,Demo.db
,Encryto.db
三个文件,apk扔进jadx
MainActivity: //不会java,所以仔细读了读,对着加了很多注释,
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private SQLiteDatabase a;// SQLite数据库实例(加密)
private a b;// 自定义的数据库辅助类
private Button c;
@Override // android.support.v7.app.AppCompatActivity, android.support.v4.app.FragmentActivity, android.support.v4.app.BaseFragmentActivityGingerbread, android.app.Activity
protected 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写入配置信息
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()初始化数据库并插入数据
a();
}
private void a() {
// 加载SQLCipher库
SQLiteDatabase.loadLibs(this);
// 创建或打开加密数据库"Demo.db"
this.b = new a(this, "Demo.db", null, 1);
// 要插入的数据
ContentValues contentValues = new ContentValues();
contentValues.put("name", "Stranger");
contentValues.put("password", (Integer) 123456);
// 使用自定义类a.a生成加密密钥
com.example.yaphetshan.tencentwelcome.a.a aVar = new com.example.yaphetshan.tencentwelcome.a.a();
String a = aVar.a(contentValues.getAsString("name"), contentValues.getAsString("password"));
// 获取可写数据库,密钥是动态生成的子字符串(前7位)
this.a = this.b.getWritableDatabase(aVar.a(a + aVar.b(a, contentValues.getAsString("password"))).substring(0, 7));
// 插入数据到表"TencentMicrMsg"
this.a.insert("TencentMicrMsg", null, contentValues);
}
@Override // android.view.View.OnClickListener
//当按钮add_data被点击时,跳转到AnotherActivity,并传递两个字符串参数
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);//跳转到AnotherActivity
startActivity(intent);
}
}
}
可以看到MainActivity主要是初始化一个SQLite数据库(使用SQLCipher加密),并向数据库中插入一条数据。
AnotherActivity主要功能是显示一个Toast消息,并没有实际处理从MainActivity
传递过来的数据。
核心部分在这一块
com.example.yaphetshan.tencentwelcome.a.a aVar = new com.example.yaphetshan.tencentwelcome.a.a();
String a = aVar.a(contentValues.getAsString("name"), contentValues.getAsString("password"));
this.a = this.b.getWritableDatabase(aVar.a(a + aVar.b(a, contentValues.getAsString("password"))).substring(0, 7));
this.a.insert("TencentMicrMsg", null, contentValues);
找到com.example.yaphetshan.tencentwelcome.a.a
和com.example.yaphetshan.tencentwelcome.a.b
类
public class a {
private String a = "yaphetshan";
public String a(String str, String str2) {
return str.substring(0, 4) + str2.substring(0, 4);//拼接str和str2的前四个字符
}
public String b(String str, String str2) {
new b();
return b.a(str);//计算str的md5
}
public String a(String str) {
new b();
return b.b(str + this.a);//计算str和yaphetshan拼接以后的SHA-1
}
}
public class b {
public static final String a(String str) {//b.a(str):计算md5值(32位小写哈希)
char[] cArr = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
try {
byte[] bytes = str.getBytes();// 将输入字符串转换为字节数组
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
// 获取MD5消息摘要实例
// 更新要计算的消息
messageDigest.update(bytes);
// 完成哈希计算,返回16字节(128位)的哈希值
byte[] digest = messageDigest.digest();
// 准备字符数组来存储十六进制表示(每个字节转换为2个字符)
char[] cArr2 = new char[digest.length * 2];
int i = 0;
for (byte b : digest) { // 将每个字节转换为两个十六进制字符
int i2 = i + 1;
cArr2[i] = cArr[(b >>> 4) & 15]; // 取高4位并转换为十六进制字符
i = i2 + 1;
cArr2[i2] = cArr[b & 15];//取低4位并转换为十六进制字符
}
// 将字符数组转换为字符串返回(32位小写MD5)
return new String(cArr2);
} catch (Exception e) {
return null;
}
}
public static final String b(String str) {//b.b(str):计算SHA-1(40位小写哈希)
char[] cArr = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
try {
byte[] bytes = str.getBytes();
MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
messageDigest.update(bytes);
byte[] digest = messageDigest.digest();
char[] cArr2 = new char[digest.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;
}
}
}
所以大概逻辑就是Stranger和123456的前4位拼接,即Stra1234
,然后计算它的md5,即44e2e4457d4e252ca5b9fe9d20b3fea5
,然后计算Stra1234拼接44e2e4457d4e252ca5b9fe9d20b3fea5再拼接yaphetshan以后的SHA-1,即ae56f99638285eb0743d8bf76d2b0c80e5cbb096
,最后取前7位,即ae56f99
。
把Encryto.db
扔进DB Browser (SQLCipher)
(有个博客说扔进SQLiteStudio打不开,我试了试,雀食),输入得到的密码ae56f99
。
在浏览数据里,得到VGN0ZntIM2xsMF9Eb19ZMHVfTG92M19UZW5jM250IX0=
,base64解密