首页
论坛
课程
招聘
[原创]第四题 突破重围
2020-11-24 11:28 1555

[原创]第四题 突破重围

2020-11-24 11:28
1555

1.开头


    看到是个android的就来试一试了,发的第一个版本使用360加固的,壳是自己家的,就不说怎么脱了.....................,等下喝茶就不好了,网上搜一搜应该也有方法

2.正文

package com.kanxue.crackme;

import android.app.AlertDialog.Builder;
import android.content.Context;
import android.os.Bundle;
import android.view.View.OnClickListener;
import android.view.View;
import android.widget.EditText;
import androidx.appcompat.app.AppCompatActivity;
import com.stub.StubApp;
import dalvik.system.BaseDexClassLoader;
import dalvik.system.DexClassLoader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MainActivity extends AppCompatActivity {
    public static Context appContext;
    public static DexClassLoader dexClassLoader;

    static {
        StubApp.interface11(0x545);
        MainActivity.appContext = null;
        MainActivity.dexClassLoader = null;
    }

    public boolean check(String content) {
        Class v0_2;
        DexClassLoader v0 = MainActivity.dexClassLoader;
        if(v0 != null) {
            Class clazz = null;
            try {
                v0_2 = v0.loadClass("com.kanxue.crackme.Crack");
            }
            catch(ClassNotFoundException e) {
                e.printStackTrace();
                goto label_12;
            }

            clazz = v0_2;
        label_12:
            if(clazz != null) {
                try {
                    Method[] methods = clazz.getDeclaredMethods();
                    Method v5 = null;
                    int i;
                    for(i = 0; i < methods.length; ++i) {
                        Method method = methods[i];
                        if(method.getName().contains("check")) {
                            v5 = method;
                        }
                    }

                    return ((Boolean)v5.invoke(null, content)).booleanValue();
                }
                catch(IllegalAccessException e) {
                    e.printStackTrace();
                    return 0;
                }
                catch(InvocationTargetException e) {
                }

                e.printStackTrace();
                return 0;
                e.printStackTrace();
            }
        }

        return 0;
    }

    public static Object combineArray(Object array1, Object array2) {
        int array1Length = Array.getLength(array1);
        int newArrayLength = array1Length + Array.getLength(array2);
        Object newArray = Array.newInstance(array1.getClass().getComponentType(), newArrayLength);
        int i;
        for(i = 0; i < newArrayLength; ++i) {
            if(i < array1Length) {
                Array.set(newArray, i, Array.get(array1, i));
            }
            else {
                Array.set(newArray, i, Array.get(array2, i - array1Length));
            }
        }

        return newArray;
    }

    private static boolean copyAssetAndWrite(String fileName) {
        try {
            File cacheDir = MainActivity.appContext.getCacheDir();
            if(!cacheDir.exists()) {
                cacheDir.mkdirs();
            }

            File outFile = new File(cacheDir, fileName);
            if(outFile.exists()) {
                if(outFile.length() > 10L) {
                    return 1;
                }
            }
            else if(!outFile.createNewFile()) {
                return 0;
            }

            InputStream is = MainActivity.appContext.getAssets().open(fileName);
            FileOutputStream fos = new FileOutputStream(outFile);
            byte[] buffer = new byte[0x400];
            while(true) {
                int v7 = is.read(buffer);
                if(v7 == -1) {
                    break;
                }

                fos.write(buffer, 0, v7);
            }

            fos.flush();
            is.close();
            fos.close();
            return 1;
        }
        catch(IOException e) {
            e.printStackTrace();
            return 0;
        }
    }

    public static Object[] getdexElements(BaseDexClassLoader baseDexClassLoader) {
        try {
            BaseDexClassLoader.class.getDeclaredField("pathList").setAccessible(true);
            Object pathlistobj = BaseDexClassLoader.class.getDeclaredField("pathList").get(baseDexClassLoader);
            baseDexClassLoader.loadClass("dalvik.system.DexPathList").getDeclaredField("dexElements").setAccessible(true);
            return (Object[])baseDexClassLoader.loadClass("dalvik.system.DexPathList").getDeclaredField("dexElements").get(pathlistobj);
        }
        catch(NoSuchFieldException e) {
            e.printStackTrace();
            return null;
        }
        catch(IllegalAccessException e) {
            e.printStackTrace();
            return null;
        }
        catch(ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        }
    }

    public void init() {
        MainActivity.copyAssetAndWrite("b.txt");
        MainActivity.testDexClassLoader(MainActivity.appContext, new File(MainActivity.appContext.getCacheDir(), "b.txt").getAbsolutePath());
    }

    @Override  // androidx.appcompat.app.AppCompatActivity
    protected native void onCreate(Bundle arg1) {

        class com.kanxue.crackme.MainActivity.1 implements Runnable {
            @Override
            public void run() {
                try {
                    Thread.currentThread();
                    Thread.sleep(5000L);
                }
                catch(InterruptedException e) {
                    e.printStackTrace();
                }

                System.exit(0);
            }
        }


        class com.kanxue.crackme.MainActivity.2 implements Runnable {
            @Override
            public void run() {
                try {
                    Thread.currentThread();
                    Thread.sleep(5000L);
                }
                catch(InterruptedException e) {
                    e.printStackTrace();
                }

                System.exit(0);
            }
        }


        class com.kanxue.crackme.MainActivity.3 implements View.OnClickListener {
            com.kanxue.crackme.MainActivity.3(EditText arg2, Context arg3) {
            }

            @Override  // android.view.View$OnClickListener
            public void onClick(View view) {
                if(MainActivity.this.check(this.val$inputEditText.getText().toString())) {
                    new AlertDialog.Builder(this.val$tmpcontext).setTitle("result").setMessage("Congratulations! app is exit.....").show();
                    this.val$inputEditText.setText("");
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                Thread.currentThread();
                                Thread.sleep(5000L);
                            }
                            catch(InterruptedException e) {
                                e.printStackTrace();
                            }

                            System.exit(0);
                        }
                    }).start();
                    return;
                }

                new AlertDialog.Builder(this.val$tmpcontext).setTitle("result").setMessage("Sorry,wrong key ,app is exit.....").show();
                this.val$inputEditText.setText("");
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.currentThread();
                            Thread.sleep(5000L);
                        }
                        catch(InterruptedException e) {
                            e.printStackTrace();
                        }

                        System.exit(0);
                    }
                }).start();
            }
        }

    }

    public static boolean testDexClassLoader(Context context, String dexfilepath) {
        Class v0 = MainActivity.class;
        File optfile = context.getDir("opt_dex", 0);
        String libpath = context.getDir("lib_path", 0).getAbsolutePath().replace("app_lib_path", "lib");
        context.getClassLoader();
        if(MainActivity.dexClassLoader == null) {
            MainActivity.dexClassLoader = new DexClassLoader(dexfilepath, optfile.getAbsolutePath(), libpath, v0.getClassLoader());
            Object newarray = MainActivity.combineArray(MainActivity.getdexElements(MainActivity.dexClassLoader), MainActivity.getdexElements(((BaseDexClassLoader)v0.getClassLoader())));
            try {
                BaseDexClassLoader.class.getDeclaredField("pathList").setAccessible(true);
                Object pathlistobj = BaseDexClassLoader.class.getDeclaredField("pathList").get(MainActivity.dexClassLoader);
                MainActivity.dexClassLoader.loadClass("dalvik.system.DexPathList").getDeclaredField("dexElements").setAccessible(true);
                MainActivity.dexClassLoader.loadClass("dalvik.system.DexPathList").getDeclaredField("dexElements").set(pathlistobj, newarray);
            }
            catch(NoSuchFieldException e) {
                e.printStackTrace();
            }
            catch(ClassNotFoundException e) {
                e.printStackTrace();
            }
            catch(IllegalAccessException e) {
                e.printStackTrace();
            }

            return 0;
        }

        return 0;
    }
}

壳的反反调试大概是某个线程把它挂起来,然后再把本身libcrack.so的自身创建的反调试线程给挂起来就行了,本来没打算仔细调试的

算法看着很简单

public class Crack {
    public static boolean check(String arg9) {
        byte[] v7_3;
        Method v7;
        int i;
        if(arg9 != null && arg9.length() == 16) {
            Class MyCrackClass = null;
            Field cryptfield = null;
            byte[] result = Crack.crypt(arg9.getBytes());
            Method crackjni = null;
            try {
                MyCrackClass = Crack.class.getClassLoader().loadClass("com.kanxue.crackme.MyCrack");
                cryptfield = MyCrackClass.getDeclaredField("crypt");
                i = 0;
                while(true) {
                label_21:
                    if(i >= MyCrackClass.getDeclaredMethods().length) {
                        goto label_40;
                    }

                    if(MyCrackClass.getDeclaredMethods()[i].getName().equals("crackjni")) {
                        v7 = MyCrackClass.getDeclaredMethods()[i];
                        break;
                    }

                    ++i;
                }
            }
            catch(ClassNotFoundException e) {
                e.printStackTrace();
                goto label_40;
            }
            catch(NoSuchFieldException e) {
                e.printStackTrace();
                goto label_40;
            }

            crackjni = v7;
            ++i;
            goto label_21;
        label_40:
            if(crackjni != null) {
                try {
                    v7_3 = (byte[])crackjni.invoke(null, result);
                }
                catch(IllegalAccessException e) {
                    e.printStackTrace();
                    goto label_58;
                }
                catch(InvocationTargetException e) {
                    e.printStackTrace();
                    goto label_58;
                }

                result = v7_3;
            }

        label_58:
            String finalresult = Base64.encodeToString(Crack.crypt(result), 0);
            if(cryptfield != null && MyCrackClass != null) {
                try {
                    return finalresult.equals(((String)cryptfield.get(null))) ? 1 : 0;
                }
                catch(IllegalAccessException e) {
                    e.printStackTrace();
                    return finalresult.equals("test") ? 1 : 0;
                }
            }

            return finalresult.equals("test") ? 1 : 0;
        }

        return 0;
    }

    public static byte[] crypt(byte[] arg13) {
        if(arg13 != null) {
            int x = 0;
            int y = 0;
            byte[] b_key = "kaokaonio".getBytes();
            byte[] key = new byte[0x100];
            int i;
            for(i = 0; i < 0x100; ++i) {
                key[i] = (byte)i;
            }

            int index1 = 0;
            int index2 = 0;
            if(b_key != null && b_key.length != 0) {
                int i;
                for(i = 0; i < 0x100; ++i) {
                    index2 = (b_key[index1] & 0xFF) + (key[i] & 0xFF) + index2 & 0xFF;
                    byte tmp = key[i];
                    key[i] = key[index2];
                    key[index2] = tmp;
                    index1 = (index1 + 1) % b_key.length;
                }

                byte[] result = new byte[arg13.length];
                int i;
                for(i = 0; i < arg13.length; ++i) {
                    x = x + 1 & 0xFF;
                    y = (key[x] & 0xFF) + y & 0xFF;
                    byte v9_1 = key[x];
                    key[x] = key[y];
                    key[y] = v9_1;
                    result[i] = (byte)(arg13[i] ^ key[(key[x] & 0xFF) + (key[y] & 0xFF) & 0xFF]);
                }

                return result;
            }

            return null;
        }

        return null;
    }
}
int __fastcall Java_com_kanxue_crackme_MyCrack_crackjni(_JNIEnv *env, int a2_NULL, int a3_input)
{
  char v3; // r0
  char v4; // r2
  int v6; // [sp+40h] [bp-410h]
  unsigned __int8 v7; // [sp+57h] [bp-3F9h]
  char *k; // [sp+60h] [bp-3F0h]
  int v9; // [sp+68h] [bp-3E8h]
  int v10; // [sp+6Ch] [bp-3E4h]
  int v11; // [sp+70h] [bp-3E0h]
  int v12; // [sp+74h] [bp-3DCh]
  int v13; // [sp+7Ch] [bp-3D4h]
  int v14; // [sp+80h] [bp-3D0h]
  int v15; // [sp+84h] [bp-3CCh]
  int v16; // [sp+88h] [bp-3C8h]
  unsigned __int8 v17; // [sp+9Bh] [bp-3B5h]
  char *j; // [sp+A4h] [bp-3ACh]
  int result; // [sp+ACh] [bp-3A4h]
  int v20; // [sp+B4h] [bp-39Ch]
  const void *v21; // [sp+B8h] [bp-398h]
  void *input_serial; // [sp+BCh] [bp-394h]
  unsigned __int8 v23; // [sp+CBh] [bp-385h]
  char *i; // [sp+D4h] [bp-37Ch]
  int v25; // [sp+E4h] [bp-36Ch]
  int v26; // [sp+E4h] [bp-36Ch]
  int v27; // [sp+E4h] [bp-36Ch]
  int v30; // [sp+124h] [bp-32Ch]
  unsigned __int8 *v31; // [sp+128h] [bp-328h]
  int v32; // [sp+12Ch] [bp-324h]
  char v33; // [sp+133h] [bp-31Dh]
  char v34; // [sp+136h] [bp-31Ah]
  int v35; // [sp+138h] [bp-318h]
  int v36; // [sp+13Ch] [bp-314h]
  int v37; // [sp+140h] [bp-310h]
  char s[512]; // [sp+144h] [bp-30Ch]
  char v39[256]; // [sp+344h] [bp-10Ch]

  v37 = -587273509;
  v36 = -75511142;
  v35 = 1258011390;
  for ( i = (char *)&v35; i != s; ++i )
  {
    v23 = (((unsigned __int8)(~*i ^ 0xB1) >> 6) | (4 * (~*i ^ 0xB1))) ^ 0x4A;
    *i = (v23 >> 6) | (4 * v23);
  }
  No_USE();
  v25 = openat((void *)0xFFFFFF9C, byte_1F0F5, 0, 0);
  if ( v25 >= 1 )
  {
    while ( (int)sub_B168(v25, s, 0x200u) >= 1 )
    {
      if ( strstr(s, aPdRw6) )
        LOBYTE(dword_0) = 99;
      if ( sscanf(s, byte_1F120, &v31, &v30, &v33, &v32, v39) == 5
        && v33 == 114
        && v34 == 112
        && !v32
        && strlen(v39)
        && v39[0] != 91
        && (unsigned int)(v30 - (_DWORD)v31) > 0xF4240
        && !CmpStr(v39, aE)
        && sub_B228(v31)
        && sub_B0D2(v31, v30, (unsigned __int8 *)&v35, 0xBu) == 1 )
      {
        LOBYTE(dword_0) = 99;
        break;
      }
    }
  }
  close_0(v25);
  v21 = (const void *)GetByteArrayElements(env, a3_input, 0);
  v20 = GetArrayLength(env, a3_input);          // 16
  input_serial = (void *)operator new[](v20);
  memset(input_serial, 0, v20);
  qmemcpy(input_serial, v21, v20);
  result = operator new[](v20);
  AES_ECB((int)input_serial, (int)byte_1F1E0, result);
  ReleaseByteArrayElements(env, a3_input, (int)v21, 0);
  for ( j = (char *)&v35; j != s; ++j )
  {
    v17 = (((unsigned __int8)(~*j ^ 0xB1) >> 6) | (4 * (~*j ^ 0xB1))) ^ 0x4A;
    *j = (v17 >> 6) | (4 * v17);
  }
  No_USE();
  v26 = openat((void *)0xFFFFFF9C, byte_1F0F5, 0, 0);
  if ( v26 >= 1 )
  {
    while ( (int)sub_B168(v26, s, 0x200u) >= 1 )
    {
      if ( strstr(s, aPdRw6) )
        LOBYTE(dword_0) = 99;
      if ( sscanf(s, byte_1F120, &v31, &v30, &v33, &v32, v39) == 5
        && v33 == 'r'
        && v34 == 'p'
        && !v32
        && strlen(v39)
        && v39[0] != '['
        && (unsigned int)(v30 - (_DWORD)v31) > 0xF4240
        && !CmpStr(v39, aE)
        && sub_B228(v31)
        && sub_B0D2(v31, v30, (unsigned __int8 *)&v35, 0xBu) == 1 )
      {
        LOBYTE(dword_0) = 99;
        break;
      }
    }
  }
  close_0(v26);
  if ( Count )
  {
    if ( dword_403D8 )
    {
      v12 = dword_403D8 + 0x16D3A6;
      v3 = *(_BYTE *)(dword_403D8 + 0x16D3A6);
      v4 = Count++;
      *(_BYTE *)(dword_403D8 + 0x16D3A6) = v3 + v4;
      *(_BYTE *)(v12 + 1) = 61;
      v11 = FincClass(env, (int)byte_1F200);
      v10 = GetField(env, v11, (int)a0S, (int)byte_1F230);
      v9 = NewStringUTF(env, (int)byte_1F270);
      SetStaticObjectField(env, v11, v10, v9);
    }
    ++Count;
  }
  else
  {
    if ( dword_403D8 )
    {
      v16 = dword_403D8 + 0x16D3A6;
      *(_BYTE *)(dword_403D8 + 0x16D3A6) = 0xD3;
      *(_BYTE *)(v16 + 1) = '=';
      v15 = FincClass(env, (int)byte_1F200);
      v14 = GetField(env, v15, (int)a0S, (int)byte_1F230);
      v13 = NewStringUTF(env, (int)byte_1F250);
      SetStaticObjectField(env, v15, v14, v13);
    }
    ++Count;
  }
  for ( k = (char *)&v35; k != s; ++k )
  {
    v7 = (((unsigned __int8)(~*k ^ 0xB1) >> 6) | (4 * (~*k ^ 0xB1))) ^ 0x4A;
    *k = (v7 >> 6) | (4 * v7);
  }
  No_USE();
  v27 = openat((void *)0xFFFFFF9C, byte_1F0F5, 0, 0);
  if ( v27 >= 1 )
  {
    while ( (int)sub_B168(v27, s, 0x200u) >= 1 )
    {
      if ( strstr(s, aPdRw6) )
        LOBYTE(dword_0) = 99;
      if ( sscanf(s, byte_1F120, &v31, &v30, &v33, &v32, v39) == 5
        && v33 == 114
        && v34 == 112
        && !v32
        && strlen(v39)
        && v39[0] != 91
        && (unsigned int)(v30 - (_DWORD)v31) > 0xF4240
        && !CmpStr(v39, aE)
        && sub_B228(v31)
        && sub_B0D2(v31, v30, (unsigned __int8 *)&v35, 0xBu) == 1 )
      {
        LOBYTE(dword_0) = 99;
        break;
      }
    }
  }
  close_0(v27);
  v6 = NewByteArray(env, v20);
  SetByteArrayRegion(env, v6, 0, v20, result);
  return v6;
}

大概流程就是 serial -> crypt函数 -> 进入so AES 一下 -> crypt函数 ->  base64编一下 -> 与so动过手脚的 MyCrack.crypt 比较


crypt函数很简单,仔细观察就是一个异或操作


然后就写脚本解了,然后解了半天,发现结果始终不对


还是太菜了,还是仔细调一下吧,发现

    if ( dword_403D8 )
    {
      v16 = dword_403D8 + 0x16D3A6;
      *(_BYTE *)(dword_403D8 + 0x16D3A6) = 0xD3;
      *(_BYTE *)(v16 + 1) = '=';
      v15 = FincClass(env, (int)byte_1F200);

这个地方在做某些神秘的事

把那个神秘的b.txt从内存dump出来

    public static byte[] crypt(byte[] arg13) {
        if(arg13 != null) {
            int x = 0;
            int y = 0;
            byte[] b_key = "keepGoing".getBytes();
            byte[] key = new byte[0x100];
            int i;
            for(i = 0; i < 0x100; ++i) {
                key[i] = (byte)i;
            }

            int index1 = 0;
            int index2 = 0;
            if(b_key != null && b_key.length != 0) {
                int i;
                for(i = 0; i < 0x100; ++i) {
                    index2 = (b_key[index1] & 0xFF) + (key[i] & 0xFF) + index2 & 0xFF;
                    byte tmp = key[i];
                    key[i] = key[index2];
                    key[index2] = tmp;
                    index1 = (index1 + 1) % b_key.length;
                }

                byte[] result = new byte[arg13.length];
                int i;
                for(i = 0; i < arg13.length; ++i) {
                    x = x + 1 & 0xFF;
                    y = (key[x] & 0xFF) + y & 0xFF;
                    byte v9_1 = key[x];
                    key[x] = key[y];
                    key[y] = v9_1;
                    result[i] = (byte)(arg13[i] ^ key[(key[x] & 0xFF) + (key[y] & 0xFF) & 0xFF]);
                }

                return result;
            }

            return null;
        }

        return null;
    }

发现这个算法变了,所以最终流程是这样的

大概流程就是 serial -> crypt函数 -> 进入so AES 一下 ->变了的 crypt函数 ->  base64编一下 -> 与so动过手脚的 MyCrack.crypt 比较

from Crypto.Cipher import AES
def decrypt2(a):
   
    key=[
-65,
108,
-11,
-98,
-83,
-57,
110,
51,
88,
7,
-10,
91,
109,
-57,
-117,
95]
    for i in range(16):
        a[i]=(a[i]^key[i]) & 0xFF
    return ''.join(map(chr,a))
def decrypt1(a):
   
    key=[101,
-107,
-29,
125,
14,
114,
-104,
-38,
93,
-126,
42,
46,
124,
17,
40,
40]
    for i in range(16):
        a[i]=(a[i]^key[i]) & 0xFF
    return ''.join(map(chr,a))    

import base64 as B

key="kaokaonikaokaoni"
cryptor = AES.new(key, AES.MODE_ECB)
result="l+x7fKd2FBaaEY4NV4309A=="
t=B.b64decode(result)
t=map(ord,t)
t=decrypt2(t)
t=cryptor.decrypt(t)
t=map(ord,t)
t=decrypt1(t)
print t

#flag{thisiskey!}



看雪侠者千人榜,看看你上榜了吗?

最后于 2020-11-24 11:42 被大帅锅编辑 ,原因:
收藏
点赞0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回