广东强网杯 2021 个人决赛findthekey

runwu2204 Lv6

只有一个activity组件

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
50
51
52
53
54
55
56
57
58
package com.ctf.findthekey;

import android.app.AlertDialog;
import android.content.Context;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import androidx.appcompat.app.AppCompatActivity;

/* loaded from: classes.dex */
public class MainActivity extends AppCompatActivity {
public static Context appContext = null;

public native boolean findthekey(Object obj);

public native String stringFromJNI();

static {
System.loadLibrary("native-lib");
}

/* JADX INFO: Access modifiers changed from: protected */
@Override // androidx.appcompat.app.AppCompatActivity, androidx.fragment.app.FragmentActivity, androidx.core.app.ComponentActivity, android.app.Activity
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(C0273R.layout.activity_main);
appContext = getApplicationContext();
Button checkButton = (Button) findViewById(C0273R.C0275id.checkButton);
final EditText inputEditText = (EditText) findViewById(C0273R.C0275id.inputEditText);
checkButton.setOnClickListener(new View.OnClickListener() { // from class: com.ctf.findthekey.MainActivity.1
@Override // android.view.View.OnClickListener
public void onClick(View view) {
String content = inputEditText.getText().toString();
if (MainActivity.this.check(content)) {
new AlertDialog.Builder(this).setTitle("result").setMessage("Congratulations!").show();
inputEditText.setText(BuildConfig.FLAVOR);
return;
}
new AlertDialog.Builder(this).setTitle("result").setMessage("Sorry,try again?").show();
inputEditText.setText(BuildConfig.FLAVOR);
}
});
}

@Override // androidx.appcompat.app.AppCompatActivity, android.app.Activity, android.view.KeyEvent.Callback
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == 4) {
System.exit(0);
}
return super.onKeyDown(keyCode, event);
}

public boolean check(String content) {
return findthekey(content);
}
}

直接调用JNI进行明文校验

发现JNI中的所有函数都不符合对应的findthekey这个名字经过搜索发现是经过了混淆(41条消息) Android SO文件保护加固——混淆篇(一)_android so 混淆_不知世事的博客-CSDN博客

需要看JNI_ONLoad(在loadlibrary时调用,用于注册函数之类的)

以下的byte_5120,byte_510C,byte_5140都在initarray时进行了修改(initarray在启动elf时就执行会先于JNI_OnLoad)

image-20230710153725696

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
int v2; // r0
int v4; // [sp+24h] [bp-1Ch] BYREF
int v5[3]; // [sp+28h] [bp-18h] BYREF

v4 = 0;
sub_15A0(vm, &v4, 65542);
v5[2] = (int)sub_1434;
v5[1] = (int)byte_5120;
v5[0] = (int)byte_510C;
v2 = sub_15D4(v4, byte_5140);
sub_15FE(v4, v2, v5, 1);
return 65542;
}

用脚本重新异或回去得出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def patch(addr,xor,size):
for i in range(size):
idaapi.patch_byte(addr+i,Byte(addr+i)^xor)
patch(0x5004,0x20,4)
patch(0x5010,0x90,0x14)
patch(0x5025,0x54, 0xF)
patch(0x5035,0xF9,5)
patch(0x5040,0x5F,0x18)
patch(0x5060,0x6D,0x19)
patch(0x507A,0xF1,4)
patch(0x5080,0xA7,0x15)
patch(0x50A0,0x78,0x40)
patch(0x50F0,0x86,0x18)
patch(0x5109,0xF4,2)
patch(0x510C,0x74, 0xA)
patch(0x5120,0xFC,0x15)
patch(0x5140, 0x45,0x1F)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
int v2; // r0
int v4; // [sp+24h] [bp-1Ch] BYREF
int v5[3]; // [sp+28h] [bp-18h] BYREF

v4 = 0;
sub_15A0(vm, &v4, 65542);
v5[2] = (int)sub_1434;
v5[1] = (int)byte_5120; // (Ljava/lang/Object;)
v5[0] = (int)byte_510C; // findthekey
v2 = sub_15D4(v4, byte_5140); // 'com/ctf/findthekey/MainActivity'
sub_15FE(v4, v2, v5, 1); //此处应该是将com/ctf/findthekey/MainActivity的findthekey方法注册为sub_1434方法
return 65542;
}

所以直接查看sub_1434函数(此处将)

1
2
3
4
5
6
7
8
9
10
bool __fastcall sub_1434(int a1, int a2, int a3)
{
int v4; // [sp+1Ch] [bp-84h]
char v5[100]; // [sp+30h] [bp-70h] BYREF

v4 = sub_14CC(a1, a3, 0);//将java传入的a3字符串转化为c字符串
memset(v5, 0, sizeof(v5));
sprintf(v5, byte_5109, v4);//将字符串复制给v5
return sub_13B0(v5);
}

又调用了sub_13B0

1
2
3
4
5
6
7
8
9
10
11
bool __fastcall sub_13B0(const char *a1)
{
unsigned __int8 *v1; // r0
int v3; // [sp+8h] [bp-28h]
int v5; // [sp+20h] [bp-10h] BYREF

v5 = 0;
v3 = strlen(a1);
v1 = sub_1214((int)a1, v3, &v5);
return strcmp((_BYTE *)dword_5164, v1) == 0;//将v1字符串与dword_5164进行比较
}

此处的sub_1214使用的是base64算法可以通过其中的一部分代码判断(每次取三字节,生成四字节)

1
2
3
4
5
6
7
8
9
v6[v5] = byte_50A0[*(unsigned __int8 *)(a1 + v4) >> 2];
v6[v5 + 1] = byte_50A0[(16 * (*(_BYTE *)(a1 + v4) & 3)) | (*(unsigned __int8 *)(a1 + v4 + 1) >> 4)];
v6[v5 + 2] = byte_50A0[(4 * (*(_BYTE *)(a1 + v4 + 1) & 0xF)) | (*(unsigned __int8 *)(a1 + v4 + 2) >> 6)];
v6[v5 + 3] = byte_50A0[*(_BYTE *)(a1 + v4 + 2) & 0x3F];
v4 += 3;
v5 += 4;
//此处字典也被initarray的函数修改了
//实际值为byte_50A0="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-+\"
//此处base64表与标准的base64表不同

根据 strcmp((_BYTE *)dword_5164, v1) == 0;可以得出dword_5164为base64后的密文

调查交叉引用,也被initarray的函数修改了

image-20230710154752632

实际值为zMXHz3T0AgLZAxn0AgvRzxL9

换表后得出了flag

image-20230710154852630

flag{thisisthekey}

  • 标题: 广东强网杯 2021 个人决赛findthekey
  • 作者: runwu2204
  • 创建于 : 2023-07-05 11:43:17
  • 更新于 : 2024-04-12 17:25:45
  • 链接: https://runwu2204.github.io/2023/07/05/CTF WP/Re/安卓/广东强网杯 2021 个人决赛findthekey/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
目录
广东强网杯 2021 个人决赛findthekey