대회때 거의 다 했는데 Log.d로 출력하는거 못 봐서 아쉽게 마무리 못했던 문제이다.

Hooking해서 풀어도 되고 아니면 그냥 AES Decrypt 해도 됐다.

문제 풀이 과정은 간단하다. 블루스택이나 녹스를 사용할때 루팅으로 후킹해서 문제를 풀려면 루팅체크하는 부분을 우회해서 후킹을 해야한다. 출제자 풀이를 보면 finish 후킹했는데 나는 라이브러리 후킹해서 풀었다. finish 후킹할 생각을 못해서 조금 시간 뺏겼다. 그 이후로는 쉬움!

 

PS. 문제 풀면서 느낀게 jadx보단 jeb가 훨씬 좋다 ㅇㅇ.. (유료가 최고임)

 

MainActivity

package com.hspace.pengsu;

import android.os.Bundle;
import android.util.Log;
import android.view.View.OnClickListener;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import b.b.c.h;
import b.b.c.u;
import c.b.a.a.a;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Random;

public class MainActivity extends h implements View.OnClickListener {
    public int o;
    public Random p;
    public TextView q;
    public ProgressBar r;
    public ImageButton[] s;
    public RootCheck t;
    public static final int[] u;
    public static int v;

    public static {
        MainActivity.u = new int[]{0x7F0800B7, 0x7F0800B8, 0x7F0800B9, 0x7F0800BA, 0x7F0800BB, 0x7F0800BC, 0x7F0800BD, 0x7F0800BE};  // id:ib1
        MainActivity.v = 0;
    }

    public MainActivity() {
        this.o = 0;
        this.p = new Random();
    }

    @Override  // android.view.View$OnClickListener
    public void onClick(View arg5) {
        int v5 = this.p.nextInt(10);
        this.o = v5;
        int v1 = MainActivity.v + v5;
        MainActivity.v = v1;
        if(v1 == 100) {
            try {
                a.a();
            }
            catch(Exception v5_1) {
                v5_1.printStackTrace();
            }
        }

        if(this.o != 3 && this.o != 5 && this.o != 7 && this.o != 9 && this.o != 10) {
            TextView v5_2 = this.q;
            StringBuilder v0 = c.a.a.a.a.f("Pengsu\'s Wallet : ");
            v0.append(MainActivity.v);
            v0.append("$");
            v5_2.setText(v0.toString());
            this.r.setProgress(MainActivity.v);
            return;
        }

        this.r.setProgress(MainActivity.v);
        MainActivity.v = 0;
        TextView v5_3 = this.q;
        StringBuilder v0_1 = c.a.a.a.a.f("Pengsu\'s Wallet : ");
        v0_1.append(MainActivity.v);
        v0_1.append("$");
        v5_3.setText(v0_1.toString());
    }

    @Override  // b.b.c.h
    public void onCreate(Bundle arg6) {
        super.onCreate(arg6);
        this.s = new ImageButton[8];
        this.setContentView(0x7F0B001C);  // layout:activity_main
        this.q = (TextView)this.findViewById(0x7F0801A0);  // id:wallet
        this.findViewById(0x7F0801A1);  // id:wallet2
        this.r = (ProgressBar)this.findViewById(0x7F080128);  // id:progress
        ((u)this.o()).e.setTitle("Make Pengsu earn 100$");
        this.q.setText("Pengsu\'s Wallet : 0");
        int v0;
        for(v0 = 0; v0 < 8; ++v0) {
            this.s[v0] = (ImageButton)this.findViewById(MainActivity.u[v0]);
            this.s[v0].setOnClickListener(this);
        }

        RootCheck v6 = new RootCheck();
        this.t = v6;
        if(!v6.rootCheck()) {
            StringBuffer v2 = new StringBuffer();
            try {
                Process v6_2 = Runtime.getRuntime().exec("ps adbd");
                v6_2.waitFor();
                BufferedReader v3 = new BufferedReader(new InputStreamReader(v6_2.getInputStream()));
                while(true) {
                    String v6_3 = v3.readLine();
                    if(v6_3 == null) {
                        break;
                    }

                    v2.append(v6_3 + "\n");
                }
            }
            catch(Exception v6_1) {
                v6_1.printStackTrace();
            }

            if(v2.toString().indexOf("bad") != -1) {
                Toast.makeText(this, "No Rooted or ADB Process Detected", 1).show();
                Log.d("MainActivity", "Detection Not Rooted or ADB!");
                return;
            }
        }

        Toast.makeText(this, "Detection Rooted or ADB Process!", 1).show();
        Log.d("MainActivity", String.valueOf(this.t.rootCheck()));
        Log.d("MainActivity", "Detection Rooted or ADB Process!");
        this.finish();
    }
}

 

a

package c.b.a.a;

import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.os.Build.VERSION;
import android.util.Base64;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.ViewParent;
import b.b.h.x0;
import b.h.j.n;
import c.b.a.a.l.d.b;
import c.b.a.a.l.d.c;
import c.b.a.a.l.d.e;
import c.b.a.a.l.d;
import c.b.a.a.v.g;
import c.b.a.a.v.i;
import com.hspace.pengsu.MainActivity;
import com.hspace.pengsu.RootCheck;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.security.MessageDigest;
import java.util.List;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public final class a {
    public static RootCheck a;

    public static void a() {
        a.a = new RootCheck();
        MainActivity v0 = new MainActivity();
        if(a.a.rootCheck()) {
        label_43:
            Log.d("CipherAlgorithm", String.valueOf(a.a.rootCheck()));
            Log.d("CipherAlgorithm", "Please follow the game rules");
            v0.finish();
        }
        else {
            StringBuffer v3 = new StringBuffer();
            try {
                Process v1_1 = Runtime.getRuntime().exec("ps adbd");
                v1_1.waitFor();
                BufferedReader v4 = new BufferedReader(new InputStreamReader(v1_1.getInputStream()));
                while(true) {
                    String v1_2 = v4.readLine();
                    if(v1_2 == null) {
                        break;
                    }

                    v3.append(v1_2 + "\n");
                }
            }
            catch(Exception v1) {
                v1.printStackTrace();
            }

            if(v3.toString().indexOf("bad") == -1) {
                goto label_43;
            }

            Log.d("CipherAlgorithm", "Detection Not Rooted or ADB!");
        }

        String v1_3 = RootCheck.a();
        "hello android world!".getBytes("UTF-8");
        byte[] v0_1 = "hello android world!".getBytes();
        MessageDigest v5 = MessageDigest.getInstance("MD5");
        v5.update("SOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEER".getBytes());
        byte[] v5_1 = v5.digest();
        MessageDigest v6 = MessageDigest.getInstance("SHA-256");
        v6.update(v1_3.getBytes());
        byte[] v6_1 = v6.digest();
        IvParameterSpec v7 = new IvParameterSpec(v5_1);
        SecretKeySpec v5_2 = new SecretKeySpec(v6_1, "AES");
        Cipher v6_2 = Cipher.getInstance("AES/CBC/PKCS5Padding");
        v6_2.init(1, v5_2, v7);
        byte[] v0_2 = v6_2.doFinal(v0_1);
        if(MainActivity.v == 100) {
            Log.d("CipherAlgorithm", " Decrypt Cipher : " + new String(a.d(v1_3, v1_3, Base64.decode("zem8Qf+nUSVM8gsOgKiEeZ+OPRR9EKu76gEjg2eYf4MdXK9wAXrCeTQ9r1CpWcMu".getBytes("UTF-8"), 0)), "UTF-8"));
        }
        else {
            android.os.Process.killProcess(android.os.Process.myPid());
        }

        a.d("SOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEERSOJUBEER", v1_3, v0_2);
    }

    public static Animator b(d arg6, float arg7, float arg8, float arg9) {
        ObjectAnimator v0 = ObjectAnimator.ofObject(arg6, c.a, b.b, new e[]{new e(arg7, arg8, arg9)});
        if(Build.VERSION.SDK_INT >= 21) {
            e v1 = arg6.getRevealInfo();
            if(v1 != null) {
                Animator v6 = ViewAnimationUtils.createCircularReveal(((View)arg6), ((int)arg7), ((int)arg8), v1.c, arg9);
                AnimatorSet v7 = new AnimatorSet();
                v7.playTogether(new Animator[]{v0, v6});
                return v7;
            }

            throw new IllegalStateException("Caller must set a non-null RevealInfo before calling this.");
        }

        return v0;
    }

    public static c.b.a.a.v.d c(int arg1) {
        return arg1 != 0 && arg1 == 1 ? new c.b.a.a.v.e() : new i();
    }

    public static byte[] d(String arg2, String arg3, byte[] arg4) {
        MessageDigest v0 = MessageDigest.getInstance("MD5");
        v0.update(arg2.getBytes());
        byte[] v2 = v0.digest();
        MessageDigest v0_1 = MessageDigest.getInstance("SHA-256");
        v0_1.update(arg3.getBytes());
        byte[] v3 = v0_1.digest();
        IvParameterSpec v0_2 = new IvParameterSpec(v2);
        SecretKeySpec v2_1 = new SecretKeySpec(v3, "AES");
        Cipher v3_1 = Cipher.getInstance("AES/CBC/PKCS5Padding");
        v3_1.init(2, v2_1, v0_2);
        return v3_1.doFinal(arg4);
    }

    public static float e(float arg0, float arg1, float arg2, float arg3) {
        return (float)Math.hypot(((double)(arg2 - arg0)), ((double)(arg3 - arg1)));
    }

    public static int f(Context arg0, int arg1, int arg2) {
        TypedValue v0 = a.r(arg0, arg1);
        return v0 == null ? arg2 : v0.data;
    }

    public static int g(View arg1, int arg2) {
        return a.t(arg1.getContext(), arg2, arg1.getClass().getCanonicalName());
    }

    public static ColorStateList h(Context arg1, TypedArray arg2, int arg3) {
        if(arg2.hasValue(arg3)) {
            int v0 = arg2.getResourceId(arg3, 0);
            if(v0 != 0) {
                ColorStateList v1 = b.b.d.a.a.a(arg1, v0);
                return v1 == null ? arg2.getColorStateList(arg3) : v1;
            }
        }

        return arg2.getColorStateList(arg3);
    }

    public static ColorStateList i(Context arg2, x0 arg3, int arg4) {
        if(arg3.b.hasValue(arg4)) {
            int v0 = arg3.b.getResourceId(arg4, 0);
            if(v0 != 0) {
                ColorStateList v2 = b.b.d.a.a.a(arg2, v0);
                return v2 == null ? arg3.c(arg4) : v2;
            }
        }

        return arg3.c(arg4);
    }

    public static Drawable j(Context arg1, TypedArray arg2, int arg3) {
        if(arg2.hasValue(arg3)) {
            int v0 = arg2.getResourceId(arg3, 0);
            if(v0 != 0) {
                Drawable v1 = b.b.d.a.a.b(arg1, v0);
                return v1 == null ? arg2.getDrawable(arg3) : v1;
            }
        }

        return arg2.getDrawable(arg3);
    }

    public static boolean k(Context arg1) {
        return arg1.getResources().getConfiguration().fontScale >= 1.3f;
    }

    public static boolean l(Context arg1) {
        return arg1.getResources().getConfiguration().fontScale >= 2f;
    }

    public static boolean m(View arg1) {
        return n.m(arg1) == 1;
    }

    public static int n(int arg1, int arg2, float arg3) {
        return b.h.d.a.a(b.h.d.a.c(arg2, Math.round(((float)Color.alpha(arg2)) * arg3)), arg1);
    }

    public static float o(float arg1, float arg2, float arg3) {
        return arg3 * arg2 + (1f - arg3) * arg1;
    }

    public static PorterDuff.Mode p(int arg1, PorterDuff.Mode arg2) {
        if(arg1 != 3) {
            if(arg1 != 5) {
                if(arg1 != 9) {
                    switch(arg1) {
                        case 14: {
                            break;
                        }
                        case 15: {
                            return PorterDuff.Mode.SCREEN;
                        }
                        case 16: {
                            return PorterDuff.Mode.ADD;
                        }
                        default: {
                            return arg2;
                        }
                    }

                    return PorterDuff.Mode.MULTIPLY;
                }

                return PorterDuff.Mode.SRC_ATOP;
            }

            return PorterDuff.Mode.SRC_IN;
        }

        return PorterDuff.Mode.SRC_OVER;
    }

    public static void q(AnimatorSet arg10, List arg11) {
        int v0 = arg11.size();
        long v2 = 0L;
        int v4;
        for(v4 = 0; v4 < v0; ++v4) {
            Animator v5 = (Animator)arg11.get(v4);
            long v6 = v5.getStartDelay();
            v2 = Math.max(v2, v5.getDuration() + v6);
        }

        ValueAnimator v0_1 = ValueAnimator.ofInt(new int[]{0, 0});
        v0_1.setDuration(v2);
        arg11.add(0, v0_1);
        arg10.playTogether(arg11);
    }

    public static TypedValue r(Context arg2, int arg3) {
        TypedValue v0 = new TypedValue();
        return arg2.getTheme().resolveAttribute(arg3, v0, true) ? v0 : null;
    }

    public static boolean s(Context arg1, int arg2, boolean arg3) {
        TypedValue v1 = a.r(arg1, arg2);
        return v1 != null && v1.type == 18 ? v1.data != 0 : arg3;
    }

    public static int t(Context arg3, int arg4, String arg5) {
        TypedValue v0 = a.r(arg3, arg4);
        if(v0 != null) {
            return v0.data;
        }

        throw new IllegalArgumentException(String.format("%1$s requires a value for the %2$s attribute to be set in your app theme. You can either set the attribute in your theme or update your theme to inherit from Theme.MaterialComponents (or a descendant).", arg5, arg3.getResources().getResourceName(arg4)));
    }

    public static void u(View arg2, float arg3) {
        Drawable v2 = arg2.getBackground();
        if((v2 instanceof g)) {
            g v2_1 = (g)v2;
            c.b.a.a.v.g.b v0 = v2_1.b;
            if(v0.o != arg3) {
                v0.o = arg3;
                v2_1.w();
            }
        }
    }

    public static void v(View arg2, g arg3) {
        if(arg3.b.b != null && (arg3.b.b.a)) {
            ViewParent v2 = arg2.getParent();
            float v0 = 0f;
            while((v2 instanceof View)) {
                v0 += n.k(((View)v2));
                v2 = v2.getParent();
            }

            c.b.a.a.v.g.b v2_1 = arg3.b;
            if(v2_1.n != v0) {
                v2_1.n = v0;
                arg3.w();
            }
        }
    }

    public static PorterDuffColorFilter w(Drawable arg1, ColorStateList arg2, PorterDuff.Mode arg3) {
        return arg2 == null || arg3 == null ? null : new PorterDuffColorFilter(arg2.getColorForState(arg1.getState(), 0), arg3);
    }
}

 

RootCheck

package com.hspace.pengsu;

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

    public static native String a() {
    }

    public native boolean rootCheck() {
    }
}

 

Java_com_hspace_pengsu_RootCheck_rootCheck

__int64 __fastcall Java_com_hspace_pengsu_RootCheck_rootCheck()
{
  unsigned int v0; // ebx

  if ( !access("/sbin/su", 0)
    || !access("/system/su", 0)
    || !access("/system/sbin/su", 0)
    || !access("/system/xbin/su", 0)
    || !access("/data/data/com.example.demoapp.su", 0)
    || !access("/system/app/Superuser.apk", 0)
    || !access("/system/bin/su", 0)
    || !access("/system/bin/.ext/.su", 0)
    || !access("/system/usr/we-need-root/su-backup", 0)
    || (v0 = 0, !access("/system/xbin/mu", 0)) )
  {
    __android_log_print(6LL, "C++", "There is a suspected rooting file.");
    LOBYTE(v0) = 1;
  }
  return v0;
}

 

 

Java_com_hspace_pengsu_RootCheck_a

__int64 __fastcall Java_com_hspace_pengsu_RootCheck_a(__int64 a1)
{
  char *v1; // rbp
  unsigned __int8 v2; // bl
  unsigned __int64 v3; // rdx
  char *v4; // rsi
  char *v5; // rsi
  char *v6; // rsi
  __int64 v7; // rax
  __int64 v8; // rcx
  unsigned __int64 v9; // rdx
  __int64 v10; // rax
  __int64 v11; // rcx
  unsigned __int8 v12; // bl
  char *v13; // r12
  unsigned int v14; // ebp
  __int64 v15; // r14
  __int64 v16; // rax
  int v17; // ebx
  int v18; // ebp
  int v19; // eax
  int v20; // er8
  int v21; // er9
  int v22; // ebx
  __int64 v23; // rbp
  int v24; // eax
  int v25; // er9
  __int64 v26; // rbx
  unsigned __int8 v28; // [rsp+8h] [rbp-A0h] BYREF
  char v29; // [rsp+9h] [rbp-9Fh] BYREF
  unsigned int v30; // [rsp+10h] [rbp-98h]
  void *v31; // [rsp+18h] [rbp-90h]
  __int128 v32; // [rsp+20h] [rbp-88h] BYREF
  void *v33; // [rsp+30h] [rbp-78h]
  __int128 v34; // [rsp+40h] [rbp-68h] BYREF
  void *v35; // [rsp+50h] [rbp-58h]
  __int128 v36; // [rsp+60h] [rbp-48h] BYREF
  void *ptr; // [rsp+70h] [rbp-38h]
  unsigned __int64 v38; // [rsp+78h] [rbp-30h]

  v38 = __readfsqword(0x28u);
  ptr = (void *)operator new(0x20uLL);
  v36 = xmmword_40750;
  strcpy((char *)ptr, "\b!0ASD%/!7!'19-az13FZ9(=(-\"!");
  v35 = (void *)operator new(0x20uLL);
  v34 = xmmword_40720;
  strcpy((char *)v35, "\b$003Z#/AZOQ()*7-az13FZ9(*-\"!");
  v33 = (void *)operator new(0x20uLL);
  v32 = xmmword_40670;
  strcpy((char *)v33, "\b!0c7)%/!7!'16-0=% %-(=(-\"!");
  v1 = (char *)&v32 + 1;
  v2 = 33;
  v3 = 0LL;
  while ( (v2 & 1) == 0 )
  {
    v4 = (char *)&v32 + 1;
    if ( v3 >= v2 >> 1 )
      goto LABEL_12;
LABEL_8:
    v4[v3] ^= 0x44u;
    v5 = (char *)&v36 + 1;
    if ( (v36 & 1) != 0 )
      v5 = (char *)ptr;
    v5[v3] ^= 0x44u;
    v6 = (char *)&v34 + 1;
    if ( (v34 & 1) != 0 )
      v6 = (char *)v35;
    v6[v3++] ^= 0x44u;
    v2 = v32;
  }
  if ( *((_QWORD *)&v32 + 1) > v3 )
  {
    v4 = (char *)v33;
    goto LABEL_8;
  }
LABEL_12:
  v7 = std::__put_character_sequence<char,std::char_traits<char>>(
         &std::cout,
         "standard time starting",
         22LL,
         (char *)&v34 + 1);
  if ( (v32 & 1) != 0 )
  {
    v1 = (char *)v33;
    v9 = *((_QWORD *)&v32 + 1);
  }
  else
  {
    v9 = (unsigned __int64)(unsigned __int8)v32 >> 1;
  }
  v10 = std::__put_character_sequence<char,std::char_traits<char>>(v7, v1, v9, v8);
  std::__put_character_sequence<char,std::char_traits<char>>(v10, "\n", 1LL, v11);
  std::string::basic_string(&v28, &v32);
  v12 = v28;
  v13 = (char *)v31;
  if ( (v28 & 1) != 0 )
    v14 = v30;
  else
    v14 = v28 >> 1;
  v15 = (*(__int64 (__fastcall **)(__int64, _QWORD))(*(_QWORD *)a1 + 1408LL))(a1, v14);
  if ( (v12 & 1) == 0 )
    v13 = &v29;
  (*(void (__fastcall **)(__int64, __int64, _QWORD, _QWORD, char *))(*(_QWORD *)a1 + 1664LL))(a1, v15, 0LL, v14, v13);
  v16 = (*(__int64 (__fastcall **)(__int64, const char *))(*(_QWORD *)a1 + 48LL))(a1, "java/nio/charset/Charset");
  v17 = v16;
  v18 = (*(__int64 (__fastcall **)(__int64, __int64, const char *, const char *))(*(_QWORD *)a1 + 904LL))(
          a1,
          v16,
          "forName",
          "(Ljava/lang/String;)Ljava/nio/charset/Charset;");
  v19 = (*(__int64 (__fastcall **)(__int64, const char *))(*(_QWORD *)a1 + 1336LL))(a1, "UTF-8");
  v22 = _JNIEnv::CallStaticObjectMethod(a1, v17, v18, v19, v20, v21);
  v23 = (*(__int64 (__fastcall **)(__int64, const char *))(*(_QWORD *)a1 + 48LL))(a1, "java/lang/String");
  v24 = (*(__int64 (__fastcall **)(__int64, __int64, const char *, const char *))(*(_QWORD *)a1 + 264LL))(
          a1,
          v23,
          "<init>",
          "([BLjava/nio/charset/Charset;)V");
  v26 = _JNIEnv::NewObject(a1, v23, v24, v15, v22, v25);
  if ( (v28 & 1) != 0 )
  {
    operator delete(v31);
    if ( (v32 & 1) != 0 )
      goto LABEL_27;
LABEL_22:
    if ( (v34 & 1) == 0 )
      goto LABEL_23;
LABEL_28:
    operator delete(v35);
    if ( (v36 & 1) != 0 )
LABEL_24:
      operator delete(ptr);
  }
  else
  {
    if ( (v32 & 1) == 0 )
      goto LABEL_22;
LABEL_27:
    operator delete(v33);
    if ( (v34 & 1) != 0 )
      goto LABEL_28;
LABEL_23:
    if ( (v36 & 1) != 0 )
      goto LABEL_24;
  }
  return v26;
}

 

Exploit code

// com.hspace.pengsu

setTimeout(function(){
	setImmediate(function(){
		Interceptor.attach(Module.findExportByName("libnative-lib.so","Java_com_hspace_pengsu_RootCheck_rootCheck"),{
		    onEnter: function(args){
		        console.log('[*] rooting');
		    },
		    onLeave: function(ret){
		    	console.log(ret);
		    	return 0x0;
		    }
		});

		Java.perform(function(){
			var log = Java.use('android.util.Log');
			log.d.overload('java.lang.String','java.lang.String').implementation = function(a,b){
				console.log('[*]FLAG : ' + a.toString() + ", " + b.toString());
				return this.d(a,b);
			}
		});


		Java.perform(function(){
		    console.warn("[*] 1");
		    var s = Java.use('com.hspace.pengsu.MainActivity');
		    s.v.value = 100;
		    console.log(s.v.value);
		});

		Java.perform(function(){
			var d = Java.use('com.hspace.pengsu.RootCheck');
			d.rootCheck.implementation = function(){
				var retv = this.rootCheck();
				console.log(retv);
				return false;
			}
		});
	});
}, 1000);

 

펭수 귀엽다.

끝!

FLAG : hspace{Vu!lner0able_9an13d0ro6id_1a3p3p1}

 

 

+ Recent posts