前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【愚公系列】2023年05月 攻防世界-MOBILE(app3)

【愚公系列】2023年05月 攻防世界-MOBILE(app3)

作者头像
愚公搬代码
发布2023-05-24 10:09:37
3190
发布2023-05-24 10:09:37
举报
文章被收录于专栏:历史专栏历史专栏

前言

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备份到设备。

3.相关工具

下面介绍两个反编译工具

  • jadx是一个用于反编译Android APK文件的开源工具,静态反编译,查找索引功能强大
  • jeb和IDA很像,属于动态调试,可以看java汇编也可以生成伪代码,还可以动态attach到目标调试

对于so文件的逆向工具选择

  • IDA逆向工具是一款反汇编器,被广泛应用于软件逆向工程领域,能够反汇编各种不同平台的二进制程序代码,并还原成可读的汇编代码。

Objection是一款移动设备运行时漏洞利用工具,该工具由Frida驱动,可以帮助研究人员访问移动端应用程序,并在无需越狱或root操作的情况下对移动端应用程序的安全进行评估检查。

安装命令

代码语言:javascript
复制
pip3 install objection 

frida是一款便携的、自由的、支持全平台的hook框架,可以通过编写JavaScript、Python代码来和frida_server端进行交互

frida的安装可以参考:https://www.jianshu.com/p/60cfd3f6afde

一、app3

1.题目

在这里插入图片描述
在这里插入图片描述

2.答题

2.1 Android backup extractor

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

编译安卓文件

代码语言:javascript
复制
mvn clean package

会生成target文件夹

在这里插入图片描述
在这里插入图片描述

还原ab安卓备份文件

代码语言:javascript
复制
java -jar abe.jar unpack app3.ab app3.tar
在这里插入图片描述
在这里插入图片描述

接下来解压app3.tar,一番搜寻后,发现了base.apk,也就是我们需要分析的程序

在这里插入图片描述
在这里插入图片描述

2.21 jadx反编译apk文件

代码语言:javascript
复制
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

代码语言:javascript
复制
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:Strangerpassword:123456放入其中。
  • 第六行实例化了一个com.example.yaphetshan.tencentwelcome.a.a类。
  • 第七行获取了 v2 变量的值。
  • 第八行调用了getWritableDatabase函数,传进去的字符串参数即是数据库解密的密钥。

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

在这里插入图片描述
在这里插入图片描述

函数2

代码语言:javascript
复制
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;
        }
    }
}
在这里插入图片描述
在这里插入图片描述

执行:

代码语言:javascript
复制
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);
    }

}
代码语言:javascript
复制
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
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-05-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 1.ab文件
  • 2.Android backup extractor
  • 3.相关工具
  • 一、app3
    • 1.题目
      • 2.答题
        • 2.1 Android backup extractor
        • 2.21 jadx反编译apk文件
    • 总结
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档