柏鹭杯 2021寻找丢失的碎片

runwu2204 Lv6

直接拖进jadx,无法正常输出反编译结果

解压后再进行压缩为apk,就可以进行反编译了

只有一个activity组件

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" android:compileSdkVersion="29" android:compileSdkVersionCodename="10" package="com.example.c2" platformBuildVersionCode="29" platformBuildVersionName="10">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29"/>
<uses-feature android:name="android.hardware.sensor.accelerometer" android:required="true"/>
<application android:theme="@style/AppTheme" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:allowBackup="true" android:supportsRtl="true" android:fullBackupContent="false" android:roundIcon="@mipmap/ic_launcher_round" android:appComponentFactory="androidx.core.app.CoreComponentFactory">
<activity android:name="com.example.p004c2.MainActivity" android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>

主函数有点长第一步

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private final boolean loadSo() {
File file = new File(getFilesDir(), "libcore.so");
if (file.exists() && file.isFile()) {
try {
System.load(file.getAbsolutePath());
return true;
} catch (UnsatisfiedLinkError unused) {
Log.i("HINT: ", getString(C0269R.string.no_init));
return false;
}
}
Log.i("HINT: ", getString(C0269R.string.noengine));
return false;
}


直接访问资源文件查看提示

1
2
3
<string name="info">APK的某个库文件被分片隐藏了起来,找到并组合成完整文件,根据提示,获取FLAG</string>
<string name="no_init">模块未完成初始化</string>
<string name="noengine">缺失某个库文件,请将组合起来的代码文件放到指定位置</string>

碎片真**难找,但都可以通过binwalk工具找出来

第一个碎片

1
binwalk -e misc3/res/mipmap-xxxhdpi-v4/ic_launcher2.png

image-20230715174542325

第二个碎片

1
misc3/res/raw/msg.raw

直接打开就行

image-20230715174705528

第三个碎片

1
binwalk -e misc3/META-INF/kotlin-elf.kotlin_module

image-20230715175105122

第四个碎片

1
binwalk -e misc3.apk #隐藏在apk安装包里

image-20230715175113714

最终,融合召唤libcore.so

主要函数如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
int __fastcall Java_com_example_c2_MainActivity_funcB(JNIEnv *a1, int a2)
{
void *v4; // r6
jmethodID v5; // r6
void *v6; // r6
const char *v7; // r8
size_t v8; // r0
int v9; // r9
jstring (*NewStringUTF)(JNIEnv *, const char *); // r2
const char *v11; // r1
jclass v13; // r6
jmethodID v14; // r8
jbyteArray v15; // r6

v4 = (void *)((int (__fastcall *)(JNIEnv *))(*a1)->GetObjectClass)(a1);
if ( sub_946(a1)
&& (v5 = (*a1)->GetMethodID(a1, v4, "funcS", "()Ljava/lang/String;"), sub_946(a1))
&& (v6 = (void *)sub_968(a1, a2, v5), sub_946(a1))
&& (v7 = (*a1)->GetStringUTFChars(a1, v6, 0), sub_946(a1))
&& (v8 = _strlen_chk("8470096DE680B2D1D00A44ADA1ACE568", 0x21u),
v9 = memcmp(v7, "8470096DE680B2D1D00A44ADA1ACE568", v8),
(*a1)->ReleaseStringUTFChars(a1, v6, v7),
!v9) )
{
v13 = (*a1)->GetObjectClass(a1, a2);
if ( sub_946(a1) )
{
v14 = (*a1)->GetMethodID(a1, v13, "funcC", "([B)V");
if ( sub_946(a1) )
{
v15 = (*a1)->NewByteArray(a1, 32);
if ( sub_946(a1) )
{
(*a1)->SetByteArrayRegion(a1, v15, 0, 32, "dGhpcyBpcyBub3QgYSBmbGFn77yB77yB77yB");
sub_9A0(a1, a2, v14, v15);
sub_946(a1);
}
}
}
NewStringUTF = (*a1)->NewStringUTF;
v11 = (const char *)&unk_2346;
}
else
{
NewStringUTF = (*a1)->NewStringUTF;
v11 = (const char *)&unk_2330;
}
return (int)NewStringUTF(a1, v11);
}

主要逻辑如下

graph TB;
funcB--->|2.校验对应的hash值|funcS--->|1.传入apk的hash值|funcB-->|"3.校验成功则传入字符串的前三十位"|funcC-->|4.传入字符串的大写md5值|D0
D0-->D2
D0-->D1
D1-->|key|D3
D2-->|iv|D3
D3-->|5.AES/CBC/PKCS7Padding解密|D4

subgraph java层
    funcS
    funcC
subgraph JNI层
    funcB
end
        subgraph decryptMsg方法
            direction TB
            D0[md5字符串]
            D1[前16个字符串]
            D2[剩余的字符串]
            D3[assets中msg文件]
             D4[解密后的文件]
        end
    end

解密exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
from Crypto.Util.number import*
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
tmp=tmp=str.upper(__import__("hashlib").md5("dGhpcyBpcyBub3QgYSBmbGFn77yB77yB77yB"[:32].encode()).hexdigest())
password=tmp[0:16].encode()
iv=tmp[16:].encode()
with open(r'./assets/msg','rb') as e:
with open(r'./assets/dec',"wb+")as d:
enc=e.read()
cipher=AES.new(password,AES.MODE_CBC,iv)
dec=cipher.decrypt(enc)
dec=unpad(dec,AES.block_size)
d.write(dec)

解密后发现是个图片

image-20230715191259253

继续用binwalk分离,发现没有隐藏文件

尝试使用zsteg,获取到了提示PixelJihad (sekao.net)

image-20230715191730467

上传后,得到了flag

image-20230715191754833

  • 标题: 柏鹭杯 2021寻找丢失的碎片
  • 作者: runwu2204
  • 创建于 : 2023-07-15 17:40:00
  • 更新于 : 2023-09-07 16:33:17
  • 链接: https://runwu2204.github.io/2023/07/15/CTF WP/Re/安卓/柏鹭杯 2021寻找丢失的碎片/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
目录
柏鹭杯 2021寻找丢失的碎片