CTF-rootme 题解之APK - Anti-debug

LINK:https://www.root-me.org/en/Challenges/Cracking/APK-Anti-debug

Reference:https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Character.html#digit(char,int)

Mobsf下载地址:https://github.com/MobSF/Mobile-Security-Framework-MobSF

使用Mobsf等apk反编译工具将目标程序反编译,得到如下java代码:关键代码已经标注。也可以使用d2j-dex2jar ch16.apk转换成jar文件再使用jd-gui打开。

还可以使用unzip -l ch16.apk解压后。

Validate.java

/*
 * Decompiled with CFR 0_132.
 * 
 * Could not load the following classes:
 *  android.content.Context
 *  android.util.Log
 */
package com.fortiguard.challenge.hashdays2012.challengeapp;

import android.content.Context;
import android.util.Log;
import java.lang.reflect.Array;
import java.security.MessageDigest;
import java.util.Arrays;

public class Validate {
    private static final String[] answers;
    private static byte[][] bh;
    private static boolean computed;
    private static final String[] hashes;
    public static String[] hexArray;
    private Context context;

    static {
  //需要破解的Hash值 hashes = new String[]{"622a751d6d12b46ad74049cf50f2578b871ca9e9447a98b06c21a44604cab0b4", "301c4cd0097640bdbfe766b55924c0d5c5cc28b9f2bdab510e4eb7c442ca0c66", "d09e1fe7c97238c68e4be7b3cd64230c638dde1d08c656a1c9eaae30e49c4caf", "4813494d137e1631bba301d5acab6e7bb7aa74ce1185d456565ef51d737677b2"}; answers = new String[]{"Congrats from the FortiGuard team :)", "Nice try, but that would be too easy", "Ha! Ha! FortiGuard grin ;)", "Are you implying we are n00bs?", "Come on, this is a DEFCON conference!"}; hexArray = new String[]{"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF", "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF", "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF"}; bh = (byte[][])Array.newInstance(Byte.TYPE, 4, 32); computed = false; } public Validate(Context context) { this.context = context; } /* * Enabled aggressive block sorting * Enabled unnecessary exception pruning * Enabled aggressive exception aggregation */ public static String checkSecret(String object) { byte[] arrby; block5 : { try { MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); messageDigest.reset(); arrby = messageDigest.digest(object.getBytes()); if (!computed) { Validate.convert2bytes(); } break block5; } catch (Exception exception) { Log.w((String)"Hashdays", (String)("checkSecret: " + exception.toString())); } return answers[4]; } int n = 0; while (n < hashes.length) { if (Arrays.equals(arrby, bh[n])) { return answers[n]; } ++n; } return answers[4]; }  //转换函数 public static void convert2bytes() { for (int i = 0; i < hashes.length; ++i) { Validate.bh[i] = Validate.hexStringToByteArray(hashes[i]); } computed = true; }  //Hex转Byte函数 public static byte[] hexStringToByteArray(String string2) { int n = string2.length() - 1; byte[] arrby = new byte[n / 2 + 1]; for (int i = 0; i < n; i += 2) { arrby[i / 2] = (byte)((Character.digit(string2.charAt(i), 16) << 4) + Character.digit(string2.charAt(i + 1), 16)); } return arrby; } public static boolean isEmulator() { return true; } }

 Character.digit(string2.charAt(i), 16)表示取字符串string2第i-1位字符的16进制的值

参考java官方文档得到如下信息:

  • digit

    public static int digit​(int codePoint,
                            int radix)
    Returns the numeric value of the specified character (Unicode code point) in the specified radix.

    If the radix is not in the range MIN_RADIXradixMAX_RADIX or if the character is not a valid digit in the specified radix, -1 is returned. A character is a valid digit if at least one of the following is true:

    • The method isDigit(codePoint) is true of the character and the Unicode decimal digit value of the character (or its single-character decomposition) is less than the specified radix. In this case the decimal digit value is returned.
    • The character is one of the uppercase Latin letters 'A' through 'Z' and its code is less than radix + 'A' - 10. In this case, codePoint - 'A' + 10 is returned.
    • The character is one of the lowercase Latin letters 'a' through 'z' and its code is less than radix + 'a' - 10. In this case, codePoint - 'a' + 10 is returned.
    • The character is one of the fullwidth uppercase Latin letters A ('\uFF21') through Z ('\uFF3A') and its code is less than radix + '\uFF21' - 10. In this case, codePoint - '\uFF21' + 10 is returned.
    • The character is one of the fullwidth lowercase Latin letters a ('\uFF41') through z ('\uFF5A') and its code is less than radix + '\uFF41'- 10. In this case, codePoint - '\uFF41' + 10 is returned.
    Parameters:
    codePoint - the character (Unicode code point) to be converted.
    radix - the radix.
    Returns:
    the numeric value represented by the character in the specified radix.
    Since:
    1.5
    See Also:
    forDigit(int, int), isDigit(int)

答案及参考:
The AES key is AnakinSkywalker.
To get the message ”Nice try, but that would be too easy”, use AnakinSkywalker as password.
To get the message ”Ha! Ha! FortiGuard grin ;)”, use Fortiguard as password.
To get the message ”Are you implying we are n00bs?”, use root as password.
References
[010] 010 Editor. http://www.sweetscape.com/010editor/.
[apk] APKTool. code.google.com/p/android-apktool.
[Des] Anthony Desnos. Androguard. http://code.google.com/p/androguard.
[DEXa] .dex Dalvik Executable Format. http://source.android.com/tech/dalvik/dex-format.html.
[Dexb] Dex2jar. http://code.google.com/p/dex2jar/.
[has12] Hashdays 2012, November 2012. https://www.hashdays.ch/.
[Lar] Jon Larimer. DEX Template. https://github.com/jlarimer/android-stuff/blob/master/
DEXTemplate.bt.

posted @ 2019-03-17 18:01  heycomputer  阅读(1322)  评论(0编辑  收藏  举报