GFSJ0371-【android-app-100】
apk逆向
下载附件之后改apk后缀 jadx打开
package com.example.ctf2;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
/* JADX INFO: loaded from: classes.dex */
public class MainActivity extends Activity {
Button a;
EditText b;
TextView c;
int d = 123;
String e = "Code";
static {
System.loadLibrary("adnjni");
}
public native int IsCorrect(String str);
@Override // android.app.Activity
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_main);
this.a = (Button) findViewById(R.id.Btn);
this.b = (EditText) findViewById(R.id.edit_message);
this.c = (TextView) findViewById(R.id.text_id);
this.e = Build.SERIAL;
this.d = 114366;
this.a.setOnClickListener(new a(this));
}
public native int processObjectArrayFromNative(String str);
}
能看到注册了两个nat 我们再看看其他函数 这里面都是数据
package com.example.ctf2;
/* JADX INFO: This class is generated by JADX */
public final class R {
public static final class dimen {
public static final int activity_horizontal_margin = 0x7f040000;
public static final int activity_vertical_margin = 0x7f040001;
}
public static final class drawable {
public static final int ic_launcher = 0x7f020000;
}
public static final class id {
public static final int edit_message = 0x7f080000;
public static final int Btn = 0x7f080001;
public static final int text_id = 0x7f080002;
public static final int action_settings = 0x7f080003;
}
public static final class layout {
public static final int activity_main = 0x7f030000;
}
public static final class menu {
public static final int main = 0x7f070000;
}
public static final class string {
public static final int app_name = 0x7f050000;
public static final int hello_world = 0x7f050001;
public static final int action_settings = 0x7f050002;
}
public static final class style {
public static final int AppBaseTheme = 0x7f060000;
public static final int AppTheme = 0x7f060001;
}
}
再看看 a
package com.example.ctf2;
import android.util.Log;
import android.view.View;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/* JADX INFO: loaded from: classes.dex */
class a implements View.OnClickListener {
final /* synthetic */ MainActivity a;
a(MainActivity mainActivity) {
this.a = mainActivity;
}
@Override // android.view.View.OnClickListener
public void onClick(View view) {
new String(" ");
String string = this.a.b.getText().toString();
Log.v("EditText", this.a.b.getText().toString());
new String("");
int iProcessObjectArrayFromNative = this.a.processObjectArrayFromNative(string);
int iIsCorrect = this.a.IsCorrect(string);
String str = String.valueOf(this.a.d + iProcessObjectArrayFromNative) + " ";
try {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
messageDigest.update(str.getBytes());
byte[] bArrDigest = messageDigest.digest();
StringBuffer stringBuffer = new StringBuffer();
for (byte b : bArrDigest) {
stringBuffer.append(Integer.toString((b & 255) + 256, 16).substring(1));
}
if (iIsCorrect == 1 && this.a.e != "unknown") {
this.a.c.setText("Sharif_CTF(" + stringBuffer.toString() + ")");
}
if (iIsCorrect == 1 && this.a.e == "unknown") {
this.a.c.setText("Just keep Trying :-)");
}
if (iIsCorrect == 0) {
this.a.c.setText("Just keep Trying :-)");
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
}
能看出来flag格式 捋一捋java层干嘛了
初始化 > 然后读取用户输入 > 用户输入传入两个nat层函数 > 然后计算md5 > 出flag
初始化
this.e = Build.SERIAL;
this.d = 114366;
this.a.setOnClickListener(new a(this));
读取
String string = this.a.b.getText().toString();
传入
int nativeValue = this.a.processObjectArrayFromNative(string);
int isCorrect = this.a.IsCorrect(string);
计算 注意要加空格
String str = String.valueOf(this.a.d + nativeValue) + " ";
flag
this.a.c.setText("Sharif_CTF(" + stringBuffer.toString() + ")");
IsCorrect函数
int __fastcall Java_com_example_ctf2_MainActivity_IsCorrect(int a1, int a2, int a3)
{
int v4; // r6
int v5; // r0
int v6; // r1
char *v9; // [sp+14h] [bp-38h]
int v10; // [sp+1Ch] [bp-30h]
int v11; // [sp+20h] [bp-2Ch]
char v12[40]; // [sp+24h] [bp-28h] BYREF
v9 = (char *)(*(int (__fastcall **)(int, int, _DWORD))(*(_DWORD *)a1 + 676))(a1, a3, 0);
strcpy(v12, "ef57f3fe3cf603c03890ee588878c0ec");
v4 = 0;
v12[33] = 53;
v10 = j_strcmp(v9, v12);
v5 = 1701458332;
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
v6 = v5;
v5 = 809244963;
if ( v6 <= 1701458331 )
break;
v5 = -333293478;
if ( v10 )
v5 = -158041539;
}
if ( v6 <= 809244962 )
break;
(*(void (__fastcall **)(int, int, char *))(*(_DWORD *)a1 + 680))(a1, a3, v9);
v11 = v4;
v5 = -326599761;
}
if ( v6 != -158041539 )
{
v4 = 1;
v5 = -158041539;
if ( v6 != -333293478 )
break;
}
}
return v11;
}
进去直接給验证码 processObjectArrayFromNative函数給了一段 然后后面逐字节会給出来 与上面函数一致的验证码
int __fastcall Java_com_example_ctf2_MainActivity_processObjectArrayFromNative(int a1, int a2, int a3)
{
int v3; // r0
int v4; // r0
char v5; // r4
char v6; // r1
int v7; // r0
char v8; // r1
int v10; // [sp+0h] [bp-58h] BYREF
int v11; // [sp+4h] [bp-54h]
int v12; // [sp+8h] [bp-50h]
const char *v13; // [sp+Ch] [bp-4Ch]
const char *v14; // [sp+10h] [bp-48h]
int v15; // [sp+14h] [bp-44h]
int v16; // [sp+18h] [bp-40h]
int v17; // [sp+1Ch] [bp-3Ch]
int v18; // [sp+20h] [bp-38h]
int v19; // [sp+24h] [bp-34h]
int *v20; // [sp+2Ch] [bp-2Ch]
int *v21; // [sp+30h] [bp-28h]
int *v22; // [sp+34h] [bp-24h]
int *v23; // [sp+38h] [bp-20h]
int *v24; // [sp+3Ch] [bp-1Ch]
char v25; // [sp+40h] [bp-18h]
int v26; // [sp+44h] [bp-14h]
v16 = a3;
v15 = a1;
v3 = -1661035768;
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
while ( v3 <= -1303766071 )
v3 = 2063008300;
if ( v3 > 441419317 )
break;
v3 = 1800572839;
if ( !v25 )
v3 = 441419318;
}
if ( v3 > 867851767 )
break;
v3 = 1405326207;
}
if ( v3 <= 1405326206 )
break;
if ( v3 == 1405326207 )
{
*v24 = j_lrand48();
(*(void (__fastcall **)(int, int, int))(*(_DWORD *)*v20 + 680))(*v20, *v21, *v23);
v26 = *v22;
v3 = 867851768;
}
else if ( v3 == 1800572839 )
{
*v22 = 92060626;
v3 = 441419318;
}
else
{
v20 = &v10 - 2;
v21 = &v10 - 4;
v22 = &v10 - 6;
v23 = &v10 - 8;
v24 = &v10 - 10;
*v20 = v15;
*v21 = v16;
v17 = 0;
*v22 = 0;
v4 = (*(int (__fastcall **)(int, int, _DWORD))(*(_DWORD *)*v20 + 676))(*v20, *v21, 0);
*v23 = v4;
v14 = (const char *)*v23;
v13 = (const char *)(&v10 - 10);
v18 = 101;
qmemcpy(&v10 - 10, "ef57f3fe3cf603c03890", 20);
v19 = 53;
v12 = 55;
v11 = 99;
v5 = v18;
*((_BYTE *)&v10 - 20) = v18;
*((_BYTE *)&v10 - 19) = v5;
*((_BYTE *)&v10 - 18) = v19;
*((_BYTE *)&v10 - 17) = 56;
*((_BYTE *)&v10 - 16) = 56;
*((_BYTE *)&v10 - 15) = 56;
*((_BYTE *)&v10 - 14) = v12;
*((_BYTE *)&v10 - 13) = 56;
v6 = v11;
*((_BYTE *)&v10 - 12) = v11;
*((_BYTE *)&v10 - 11) = 48;
*((_BYTE *)&v10 - 10) = v18;
*((_BYTE *)&v10 - 9) = v6;
*((_BYTE *)&v10 - 8) = v17;
*((_BYTE *)&v10 - 7) = v19;
v7 = j_strcmp(v14, v13);
v8 = 1;
if ( v7 )
v8 = v17;
v25 = v8;
v3 = -18897425;
}
}
return v26;
}
那么我们直接打开apk 输入这个验证码 就能出flag 但是我输入进去显示错误呢 有无大佬讲解一波
那我么就逆一下他的逻辑吧 能看到 processObjectArrayFromNative函数返回了 return v26; 同时v26 = *v22; 然后
*v22 = 92060626; 所以 processObjectArrayFromNative就会返回 92060626;
那么回到java层的计算
String str = String.valueOf(this.a.d + nativeValue) + " ";
也就是
114366 + 92060626 = 92174992
再加一个空格
92174992
也就是
MD5("92174992 ")
exp
import hashlib
native_value = 92060626
d = 114366
s = str(native_value + d) + " "
print(hashlib.md5(s.encode()).hexdigest())
flag
Sharif_CTF(833489ef285e6fa80690099efc5d9c9d)
评论