首页
社区
课程
招聘
[原创]KCTF2020秋季赛 第四题 突破重围 writeup
发表于: 2020-11-23 23:42 4220

[原创]KCTF2020秋季赛 第四题 突破重围 writeup

2020-11-23 23:42
4220

图片描述

com.kanxue.crackme.Crack.check

com.kanxue.crackme.Crack.crypt

图片描述
找到cryptcontent的值为 "l+x7fKd2FBaaEY4NV4309A==\n"

图片描述
crypt中的mkey有改变 "kaokaonio" -> "keepGoing"

图片描述
S盒
图片描述

AES扩展密钥算法

图片描述

1、"l+x7fKd2FBaaEY4NV4309A==" -> bytes -> base64 -> crypto (mKey=keepGoing)

2、AES解密
图片描述
3、解密字符串
crypto (mKey=kaokaonio)
图片描述

图片描述

System.loadLibrary("crack");
 
init();  -> DexClassLoader /assets/b.txt
 
check() 反射执行 com.kanxue.crackme.Crack.check()
System.loadLibrary("crack");
 
init();  -> DexClassLoader /assets/b.txt
 
check() 反射执行 com.kanxue.crackme.Crack.check()
public class MyCrack {
    public static String crypt = "otVvmpP4ZI58pqB26OTaYw==";
 
    public static native byte[] crackjni(byte[] bArr);
}
public class MyCrack {
    public static String crypt = "otVvmpP4ZI58pqB26OTaYw==";
 
    public static native byte[] crackjni(byte[] bArr);
}
public static boolean check(String content) {
        if (content == null || content.length() != 16) {
            return false;
        }
        Class MyCrackClass = null;
        Field cryptfield = null;
        byte[] result = crypt(content.getBytes());
        Method crackjni = null;
        try {
            MyCrackClass = Crack.class.getClassLoader().loadClass("com.kanxue.crackme.MyCrack");
            cryptfield = MyCrackClass.getDeclaredField("crypt");
            Method[] methods = MyCrackClass.getDeclaredMethods();
            for (int i = 0; i < methods.length; i++) {
                if (methods[i].getName().equals("crackjni")) {
                    crackjni = methods[i];
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e2) {
            e2.printStackTrace();
        }
        if (crackjni != null) {
            try {
                result = (byte[]) crackjni.invoke(null, new Object[]{result});
            } catch (IllegalAccessException e3) {
                e3.printStackTrace();
            } catch (InvocationTargetException e4) {
                e4.printStackTrace();
            }
        }
        String finalresult = Base64.encodeToString(crypt(result), 0);
        String cryptcontent = "test";
        if (!(cryptfield == null || MyCrackClass == null)) {
            try {
                cryptcontent = (String) cryptfield.get(null);
            } catch (IllegalAccessException e5) {
                e5.printStackTrace();
            }
        }
        if (finalresult.equals(cryptcontent)) {
            return true;
        }
        return false;
    }
public static boolean check(String content) {
        if (content == null || content.length() != 16) {
            return false;
        }
        Class MyCrackClass = null;
        Field cryptfield = null;
        byte[] result = crypt(content.getBytes());
        Method crackjni = null;
        try {
            MyCrackClass = Crack.class.getClassLoader().loadClass("com.kanxue.crackme.MyCrack");
            cryptfield = MyCrackClass.getDeclaredField("crypt");
            Method[] methods = MyCrackClass.getDeclaredMethods();
            for (int i = 0; i < methods.length; i++) {
                if (methods[i].getName().equals("crackjni")) {
                    crackjni = methods[i];
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e2) {
            e2.printStackTrace();
        }
        if (crackjni != null) {
            try {
                result = (byte[]) crackjni.invoke(null, new Object[]{result});
            } catch (IllegalAccessException e3) {
                e3.printStackTrace();
            } catch (InvocationTargetException e4) {
                e4.printStackTrace();
            }
        }
        String finalresult = Base64.encodeToString(crypt(result), 0);
        String cryptcontent = "test";
        if (!(cryptfield == null || MyCrackClass == null)) {
            try {
                cryptcontent = (String) cryptfield.get(null);
            } catch (IllegalAccessException e5) {
                e5.printStackTrace();
            }
        }
        if (finalresult.equals(cryptcontent)) {
            return true;
        }
        return false;
    }
public static byte[] crypt(byte[] b_data) {
        String mKkey = "kaokaonio";
        if (b_data == null) {
            return null;
        }
        int x = 0;
        int y = 0;
        byte[] b_key = mKkey.getBytes();
        byte[] key = new byte[256];
        for (int i = 0; i < 256; i++) {
            key[i] = (byte) i;
        }
        int index1 = 0;
        int index2 = 0;
        if (b_key == null || b_key.length == 0) {
            return null;
        }
        for (int i2 = 0; i2 < 256; i2++) {
            index2 = ((b_key[index1] & 255) + (key[i2] & 255) + index2) & 255;
            byte tmp = key[i2];
            key[i2] = key[index2];
            key[index2] = tmp;
            index1 = (index1 + 1) % b_key.length;
        }
        byte[] result = new byte[b_data.length];
        for (int i3 = 0; i3 < b_data.length; i3++) {
            x = (x + 1) & 255;
            y = ((key[x] & 255) + y) & 255;
            byte tmp2 = key[x];
            key[x] = key[y];
            key[y] = tmp2;
            result[i3] = (byte) (b_data[i3] ^ key[((key[x] & 255) + (key[y] & 255)) & 255]);
        }
        return result;
    }
public static byte[] crypt(byte[] b_data) {
        String mKkey = "kaokaonio";
        if (b_data == null) {
            return null;
        }
        int x = 0;
        int y = 0;
        byte[] b_key = mKkey.getBytes();
        byte[] key = new byte[256];
        for (int i = 0; i < 256; i++) {
            key[i] = (byte) i;
        }
        int index1 = 0;
        int index2 = 0;
        if (b_key == null || b_key.length == 0) {
            return null;
        }
        for (int i2 = 0; i2 < 256; i2++) {
            index2 = ((b_key[index1] & 255) + (key[i2] & 255) + index2) & 255;
            byte tmp = key[i2];
            key[i2] = key[index2];
            key[index2] = tmp;
            index1 = (index1 + 1) % b_key.length;
        }
        byte[] result = new byte[b_data.length];
        for (int i3 = 0; i3 < b_data.length; i3++) {
            x = (x + 1) & 255;
            y = ((key[x] & 255) + y) & 255;
            byte tmp2 = key[x];
            key[x] = key[y];
            key[y] = tmp2;
            result[i3] = (byte) (b_data[i3] ^ key[((key[x] & 255) + (key[y] & 255)) & 255]);
        }
        return result;
    }
 
1. input 长度16
 
2. byte[] result = crypt(input) crypt方法中的 mkey=kaokaonio
 
3. crackjni_reslut = libcarack.so->crackjni(reslut) 对 reslut 进行加密
 
4. reslut = crypt(crackjni_reslut) crypt方法中的 mkey=keepGoing
 
5. base64(reslut) 与 cryptcontent = "l+x7fKd2FBaaEY4NV4309A==\n" 进行比较
1. input 长度16
 
2. byte[] result = crypt(input) crypt方法中的 mkey=kaokaonio
 
3. crackjni_reslut = libcarack.so->crackjni(reslut) 对 reslut 进行加密
 
4. reslut = crypt(crackjni_reslut) crypt方法中的 mkey=keepGoing
 
5. base64(reslut) 与 cryptcontent = "l+x7fKd2FBaaEY4NV4309A==\n" 进行比较
int __fastcall Java_com_kanxue_crackme_MyCrack_crackjni(_JNIEnv *a1, int a2, int a3)
{
  v25 = sub_CF79ECBC((void *)0xFFFFFF9C, "/proc/self/maps", 0, 0); // frida anti
  if ( v25 >= 1 )
  {
    while ( sub_CF7A2168(v25, &s, 0x200) >= 1 )
    {
      if ( strstr(&s, "frida") )
        MEMORY[0] = 0x63;
      if ( sscanf(&s, "%x-%lx %4s %lx %*s %*s %s", &v31, &v30, &v33, &v32, &v39) == 5
        && v33 == 0x72
        && v34 == 0x70
        && !v32
        && strlen(&v39)
        && v39 != 0x5B
        && (unsigned int)(v30 - v31) > 0xF4240
        && !sub_CF7A22C0(&v39, ".oat")
        && sub_CF7A2228(v31) == 1
        && sub_CF7A20D2(v31, 0, v30, v30 >> 0x1F) == 1 )
      {
        MEMORY[0] = 0x63;
        break;
      }
    }
  }
    ......
 
  sub_CF79ED60(v5, "kaokaonikaokaoni", v6); // AES加密
 
    ......
 
  if ( dword_CF7D73E4 )
  {
    if ( dword_CF7D73D8 )
    {
      v12 = dword_CF7D73D8 + 0x16D3A6;
      v13 = *(_BYTE *)(dword_CF7D73D8 + 0x16D3A6);
      v14 = dword_CF7D73E4++;
      *(_BYTE *)(dword_CF7D73D8 + 0x16D3A6) = v13 + v14;
      *(_BYTE *)(v12 + 1) = 0x3D;
      v15 = sub_CF7A38C2(v29, "com/kanxue/crackme/MyCrack");
      v16 = sub_CF7A38EC(v29, v15, "crypt", "Ljava/lang/String;");
      v17 = sub_CF7A3934(v29, "ZmxhZ3RyeWFnYWluP30=");
      sub_CF7A3960(v29, v15, v16, v17);
    }
    ++dword_CF7D73E4;
  }
  else
  {
    if ( dword_CF7D73D8 )
    {
      v8 = dword_CF7D73D8 + 0x16D3A6;
      *(_BYTE *)(dword_CF7D73D8 + 0x16D3A6) = 0xD3u;              // "kaokaonio" -> "keepGoing"
      *(_BYTE *)(v8 + 1) = 0x3D;
      v9 = sub_CF7A38C2(v29, "com/kanxue/crackme/MyCrack");
      v10 = sub_CF7A38EC(v29, v9, "crypt", "Ljava/lang/String;");                                    
      v11 = sub_CF7A3934(v29, "l+x7fKd2FBaaEY4NV4309A==\n"); // "otVvmpP4ZI58pqB26OTaYw==" -> "l+x7fKd2FBaaEY4NV4309A=="   
      sub_CF7A3960(v29, v9, v10, v11);
    }
    ++dword_CF7D73E4;
  }
 
}

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2020-11-24 07:56 被neilwu编辑 ,原因:
收藏
免费 5
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//