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 但是我输入进去显示错误呢 有无大佬讲解一波

image

那我么就逆一下他的逻辑吧 能看到 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)