首页
社区
课程
招聘
[原创]DASCTF-2024暑期赛-Reverse-BabyAndroid-WP
发表于: 2024-7-21 14:50 7637

[原创]DASCTF-2024暑期赛-Reverse-BabyAndroid-WP

2024-7-21 14:50
7637

题型:安卓-Hook-Native分析
DAS46-BabyAndroid.zip

题目不支持模拟器运行,只能真机
附件里面除了APK,还有一段抓包后的响应体
出题人说是加密后的数据
所以我们的目标就是解密这段数据了
看看数据形式

有两个==
我们可以推测里面可能至少会用到base64编码
嗯,基本不可能只考base64

但具体是什么加密,我们目前不得而知
故,用上 算法助手
算法助手作用域勾选+算法助手开关
同时勾选算法分析4个开关
image.png
打开目标软件
让我们设置图形解锁
无所谓,这个不是关键点

进入软件后就会发现软件功能就是做笔记的
我们尝试下做个笔记
image.png
然后打开算法助手
image.png
非常nice
分析出了加密的算法AES/ECB/PKCS5Padding
而下面的SHA-256,不用管,没有人拿这个当加密算法的,解密不出来的
我们点进去看看
image.png
加密密钥都已经被Hook出来了
DQ0NDQ0NDQ0NDQ0NDQ0NDQ==
而加密的内容从1变成49
这中间应该还有一些操作
不可能就这么梭出来的
我们拿密钥和密文去在线网站上解密
image.png
解密出来的明显不是最后的flag
我们可以验证下
49.000000和密钥进行加密
看看结果是不是FXb5k9BUw5T1EkGuNStrRw==
嗯,结果确实是
那至少我们解出来了一层加密

接下来我们就要开始看dex了
不过我们不直接看
我们先看看算法助手里面的调用堆栈
看看是哪个函数调用了刚刚的加密

还是刚刚的图片
我们看到其中有一行是

那我们先看看加密函数吧
MT查看Dex
image.png
我们发现了上面这个
但这明显和刚刚不一样啊,一个0一个o
又找不到带o的
这里面肯定是有蹊跷的
我们先点进去看看

加密是这个加密类型
但明显key不对劲
这里显示的key是DASCTF

那这时候
我们就需要考虑是不是这东西从其他地方加载了dex(例如PYCC2024的challengemobile

其实
我们查看APK的时候可以发现
在assets目录下有个sex.jpg
但它又不是图片
image.png
大概这个就存储了dex数据
我们用算法助手看看是不是这样
image.png
重启,保存一个笔记
然后发现确实是读入了sex.jpg
image.png
我们点进去看调用堆栈
发现这两个比较特殊
image.png
我们再用MT找到先相关的函数

看看如上代码
loadData函数 getAssest 获取文件
然后调用rc4解密函数和一个key来解密
最终返回所解密的内容
那我们直接Hook loadData函数
来看看
但这里我们要换成SimpleHookR 或者用Frida
因为最新版算法助手自动把数据转换成编码字节集了
我们用SimpleHookR记录这个函数的参返
image.png
我们把返回值复制下来
用python脚本把其转换化成dex文件

用MT打开试试
image.png
发现了我们之前在找的Encrypto

现在我们去看看另一个红框里的东西

我们可以发现
就是doInBackground函数调用了loadData
并且还使用了classLoader去加载我们刚刚得到得到的类
然后我们发现cipher就是加密后的数据
它是由我们输入的文本经sendInit处理,然后再被刚刚加载的类加密得来的
我们跳转去看看sendInit
image.png
原来就在刚刚的NoteActivity里面
这里 native
说明我们要去分析/lib里面的so文件了
当然,我们可以先Hook一下,验证一下
image.png
参数1
返回49.000000
没问题,就是他

我们用ida64打开so
我们直接找带sendInit
image.png

我刚看到这个伪代码的时候确实是崩溃的
因为我伪代码分析能力太弱了
压根看不懂
丢给chatgpt都没救

但看到都有2个解了
就一个一个点进去看
encrypt(v18);
这个其实满显眼的函数时

直觉告诉我,就是这个了
丢给chatgpt
分析是什么离散啥啥的,简称DCT
又问有没有逆向的
chatgpt给出了IDCT的python脚本

运行脚本就会得到flag

TwMkYUkg4bYsY0hL99ggYWnVjWyXQrWAdNmToB0eBXbS6wBzL6ktorjNWI9VOroTU4HgIUYyzGLpcHzd1zNGT+bFZZI7IoxJwpcgXfdwW1LSmiNSP+PuSUsqAzNclF1nJ07b4tYyLWg0zTypbzWsLhOIM+6uci3RFZLREUCALafi01M8mS+KMNxX1Pyn8mSP+KKKjQ5S5fasHRSn+L9qBFws0mWavpfI0QEiMgarxv0iGhYU8cfgonWyL70RvoXET5VUDP1vfYWIBLzzzaAqLC0OiMtUK3TTATSU7yijdgXm18OKMcGIke/NZIM6Sr5fL3t6psDOOkw2C/5uYrJVPn+D6U9KTL64bgREppDqMOvhvbhtuf/S3ASW/+rhtPMtoaD8FxDg0wWSLZA53fQfNA==
TwMkYUkg4bYsY0hL99ggYWnVjWyXQrWAdNmToB0eBXbS6wBzL6ktorjNWI9VOroTU4HgIUYyzGLpcHzd1zNGT+bFZZI7IoxJwpcgXfdwW1LSmiNSP+PuSUsqAzNclF1nJ07b4tYyLWg0zTypbzWsLhOIM+6uci3RFZLREUCALafi01M8mS+KMNxX1Pyn8mSP+KKKjQ5S5fasHRSn+L9qBFws0mWavpfI0QEiMgarxv0iGhYU8cfgonWyL70RvoXET5VUDP1vfYWIBLzzzaAqLC0OiMtUK3TTATSU7yijdgXm18OKMcGIke/NZIM6Sr5fL3t6psDOOkw2C/5uYrJVPn+D6U9KTL64bgREppDqMOvhvbhtuf/S3ASW/+rhtPMtoaD8FxDg0wWSLZA53fQfNA==
at site.qifen.note.ui.Encrypto.encrypt(Encrypto.java:37)
at site.qifen.note.ui.Encrypto.encrypt(Encrypto.java:37)
package site.qifen.note.ui;
 
import android.util.Base64;
import java.security.MessageDigest;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
 
public class Encrypt0 {
    private static final String KEY = "DSACTF";
    private static final String TAG = "Encrypto";
 
    public static String encrypt(String data) throws Exception {
        MessageDigest sha = MessageDigest.getInstance("SHA-1");
        byte[] keyBytes = sha.digest(KEY.getBytes("UTF-8"));
        byte[] keyBytes16 = new byte[16];
        System.arraycopy(keyBytes, 0, keyBytes16, 0, 16);
        SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes16, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(1, secretKeySpec);
        byte[] encryptedBytes = cipher.doFinal(data.getBytes("UTF-8"));
        return Base64.encodeToString(encryptedBytes, 2);
    }
}
package site.qifen.note.ui;
 
import android.util.Base64;
import java.security.MessageDigest;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
 
public class Encrypt0 {
    private static final String KEY = "DSACTF";
    private static final String TAG = "Encrypto";
 
    public static String encrypt(String data) throws Exception {
        MessageDigest sha = MessageDigest.getInstance("SHA-1");
        byte[] keyBytes = sha.digest(KEY.getBytes("UTF-8"));
        byte[] keyBytes16 = new byte[16];
        System.arraycopy(keyBytes, 0, keyBytes16, 0, 16);
        SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes16, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(1, secretKeySpec);
        byte[] encryptedBytes = cipher.doFinal(data.getBytes("UTF-8"));
        return Base64.encodeToString(encryptedBytes, 2);
    }
}
public byte[] loadData(String str) {
    try {
        InputStream open = getAssets().open(str);
        byte[] encryptedData = new byte[open.available()];
        open.read(encryptedData);
        open.close();
        byte[] key = "DASCTF".getBytes();
        return rc4Decrypt(key, encryptedData);
    } catch (IOException e) {
        Log.e("错误", "加载数据时发生错误", e);
        return null;
    }
}
 
private byte[] rc4Decrypt(byte[] key, byte[] data) {
    int[] S = new int[256];
    for (int i = 0; i < 256; i++) {
        S[i] = i;
    }
    int j = 0;
    for (int i2 = 0; i2 < 256; i2++) {
        j = ((S[i2] + j) + (key[i2 % key.length] & 255)) % 256;
        int temp = S[i2];
        S[i2] = S[j];
        S[j] = temp;
    }
    int i3 = data.length;
    byte[] result = new byte[i3];
    int i4 = 0;
    int j2 = 0;
    for (int k = 0; k < data.length; k++) {
        i4 = (i4 + 1) % 256;
        j2 = (S[i4] + j2) % 256;
        int temp2 = S[i4];
        S[i4] = S[j2];
        S[j2] = temp2;
        int t = (S[i4] + S[j2]) % 256;
        result[k] = (byte) (data[k] ^ S[t]);
    }
    return result;
}
public byte[] loadData(String str) {
    try {
        InputStream open = getAssets().open(str);
        byte[] encryptedData = new byte[open.available()];
        open.read(encryptedData);
        open.close();
        byte[] key = "DASCTF".getBytes();
        return rc4Decrypt(key, encryptedData);
    } catch (IOException e) {
        Log.e("错误", "加载数据时发生错误", e);
        return null;
    }
}
 
private byte[] rc4Decrypt(byte[] key, byte[] data) {
    int[] S = new int[256];
    for (int i = 0; i < 256; i++) {
        S[i] = i;
    }
    int j = 0;
    for (int i2 = 0; i2 < 256; i2++) {
        j = ((S[i2] + j) + (key[i2 % key.length] & 255)) % 256;
        int temp = S[i2];
        S[i2] = S[j];
        S[j] = temp;
    }
    int i3 = data.length;
    byte[] result = new byte[i3];
    int i4 = 0;
    int j2 = 0;
    for (int k = 0; k < data.length; k++) {
        i4 = (i4 + 1) % 256;
        j2 = (S[i4] + j2) % 256;
        int temp2 = S[i4];
        S[i4] = S[j2];
        S[j2] = temp2;
        int t = (S[i4] + S[j2]) % 256;
        result[k] = (byte) (data[k] ^ S[t]);
    }
    return result;
}
def to_unsigned_bytes(byte_list):
    return bytes([(b + 256) % 256 for b in byte_list])
 
your_byte_list = [数据]
converted_bytes = to_unsigned_bytes(your_byte_list)
 
with open('dump.dex', 'wb') as file:
    file.write(converted_bytes)
 
print("Data written to dump.dex")
def to_unsigned_bytes(byte_list):
    return bytes([(b + 256) % 256 for b in byte_list])
 
your_byte_list = [数据]
converted_bytes = to_unsigned_bytes(your_byte_list)
 
with open('dump.dex', 'wb') as file:
    file.write(converted_bytes)
 
print("Data written to dump.dex")
package site.qifen.note.ui;
 
import android.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
 
public class Encrypto {
    private static final String KEY = "DSACTF";
    private static final String TAG = "Encrypto";
 
    private static byte[] customHash(String input) {
        byte[] keyBytes = new byte[16];
        int[] temp = new int[16];
        for (int i = 0; i < input.length(); i++) {
            int charVal = input.charAt(i);
            for (int j = 0; j < 16; j++) {
                temp[j] = ((temp[j] * 31) + charVal) % 251;
            }
        }
        for (int i2 = 0; i2 < 16; i2++) {
            keyBytes[i2] = (byte) (temp[i2] % 256);
        }
        return keyBytes;
    }
 
    public static String encrypt(String data) throws Exception {
        byte[] keyBytes = customHash(KEY);
        SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(1, secretKeySpec);
        byte[] encryptedBytes = cipher.doFinal(data.getBytes("UTF-8"));
        return Base64.encodeToString(encryptedBytes, 2);
    }
}
package site.qifen.note.ui;
 
import android.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
 
public class Encrypto {
    private static final String KEY = "DSACTF";
    private static final String TAG = "Encrypto";
 
    private static byte[] customHash(String input) {
        byte[] keyBytes = new byte[16];
        int[] temp = new int[16];
        for (int i = 0; i < input.length(); i++) {
            int charVal = input.charAt(i);
            for (int j = 0; j < 16; j++) {
                temp[j] = ((temp[j] * 31) + charVal) % 251;
            }
        }
        for (int i2 = 0; i2 < 16; i2++) {
            keyBytes[i2] = (byte) (temp[i2] % 256);
        }
        return keyBytes;
    }
 
    public static String encrypt(String data) throws Exception {
        byte[] keyBytes = customHash(KEY);
        SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(1, secretKeySpec);
        byte[] encryptedBytes = cipher.doFinal(data.getBytes("UTF-8"));
        return Base64.encodeToString(encryptedBytes, 2);
    }
}
package site.qifen.note.ui;
 
import android.os.AsyncTask;
import android.os.Build;
import android.util.Log;
import dalvik.system.InMemoryDexClassLoader;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.Date;
import site.qifen.note.model.Note;
import site.qifen.note.model.sendRequest;
import site.qifen.note.util.NoteUtil;
 
class NoteActivity$EncryptAndSendTask extends AsyncTask<String, Void, String> {
    final NoteActivity this$0;
 
    private NoteActivity$EncryptAndSendTask(NoteActivity noteActivity) {
        this.this$0 = noteActivity;
    }
 
    @Override
    public String doInBackground(String... params) {
        String contentText = params[0];
        try {
            byte[] dexData = this.this$0.loadData("Sex.jpg");
            ByteBuffer dexBuffer = ByteBuffer.wrap(dexData);
            InMemoryDexClassLoader classLoader = null;
            if (Build.VERSION.SDK_INT >= 26) {
                classLoader = new InMemoryDexClassLoader(dexBuffer, this.this$0.getClassLoader());
            }
            Class<?> checkerClass = classLoader.loadClass("site.qifen.note.ui.Encrypto");
            Method checkMethod = checkerClass.getMethod("encrypt", String.class);
            this.this$0.contentText_back = contentText;
            String cipher = (String) checkMethod.invoke(checkerClass.getDeclaredConstructor(new Class[0]).newInstance(new Object[0]), this.this$0.sendInit(contentText));
            String response = sendRequest.sendPost("http://yuanshen.com/", "data=" + cipher);
            Log.d("JNITest", "Server Response: " + response);
            return cipher;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
 
    @Override
    public void onPostExecute(String cipher) {
        if (cipher != null) {
            String titleText = this.this$0.noteWriteTitleEdit.getText().toString();
            String tagText = this.this$0.noteWriteTagEdit.getText().toString();
            String date = new SimpleDateFormat("yyyy-MM-dd HH:mm").format(new Date());
            if (NoteActivity.access$100(this.this$0) == null) {
                NoteActivity.access$200(this.this$0).insertNote(new Note(tagText, titleText, this.this$0.contentText_back, date, false));
                NoteUtil.toast("保存成功");
                this.this$0.finish();
                return;
            }
            NoteActivity.access$100(this.this$0).setTitle(titleText);
            NoteActivity.access$100(this.this$0).setContent(this.this$0.contentText_back);
            NoteActivity.access$100(this.this$0).setDate(date);
            NoteActivity.access$100(this.this$0).setTag(this.this$0.contentText_back);
            NoteActivity.access$200(this.this$0).updateNote(NoteActivity.access$100(this.this$0));
            NoteUtil.toast("修改成功");
            this.this$0.finish();
            return;
        }
        NoteUtil.toast("加密失败");
    }
}
package site.qifen.note.ui;
 
import android.os.AsyncTask;
import android.os.Build;
import android.util.Log;
import dalvik.system.InMemoryDexClassLoader;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.Date;
import site.qifen.note.model.Note;
import site.qifen.note.model.sendRequest;
import site.qifen.note.util.NoteUtil;
 
class NoteActivity$EncryptAndSendTask extends AsyncTask<String, Void, String> {
    final NoteActivity this$0;
 
    private NoteActivity$EncryptAndSendTask(NoteActivity noteActivity) {

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 6
支持
分享
最新回复 (5)
雪    币: 29182
活跃值: (63621)
能力值: (RANK:135 )
在线值:
发帖
回帖
粉丝
2

感谢分享!

附件论坛本地存档一份。

上传的附件:
2024-7-21 16:38
0
雪    币: 954
活跃值: (135)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
Editor 感谢分享!附件论坛本地存档一份。
谢谢,想着有链接就没上传了
2024-7-21 16:58
0
雪    币: 1601
活跃值: (1335)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
4
太強啦
2024-7-21 17:38
0
雪    币: 1457
活跃值: (2058)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
5
出题人路过,唯一一个分析的和我预想的一样的
2024-7-22 14:05
2
雪    币: 904
活跃值: (100)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
Shangwendada 出题人路过,唯一一个分析的和我预想的一样的
tql
2024-7-22 14:50
0
游客
登录 | 注册 方可回帖
返回
//