ali CTF分析筆記

        拿到樣本通過dex2jar工具將dex轉爲jar包,然後將java代碼複製出來進行修復,修復過程如下,代碼量太大,但是最開始不清楚邏輯所以只能用這種笨辦法了。

public static /* synthetic */ String getClassName(String str) {
   
char[] toCharArray = str.toCharArray();
    for
(int i = 0; i < toCharArray.length; i++) {
        toCharArray[i] = (
char) (toCharArray[i] ^ 116);
   
}
   
return new String(toCharArray);
}

測試3組數據的運行結果:

1.(DDE(DDEA(DDDF(DDEA.(DDEL(DDEA(DDE(DDEG.S(DDDD(DDDB(DDE(DDE(DDEGB(DDDE(DDE(DDEL(DDED(DDEE(DDDB

2.(DDE(DDEA(DDDF(DDEA.(DDEL(DDEA(DDE(DDEG.O(DDEB(DDE(DDEE(DDEC(DDDD

3.(DDE(DDEA(DDDF(DDEA.(DDEL(DDEA(DDE(DDEG.C(DDEL(DDEA(DDDC(DDDC

 

 

 

 

 

 

 

private static /* synthetic */ String access$_T15566(String str) {

    int i = 0;

    byte[] bArr = new byte[17];

    bArr[0] = (byte) 33;

    bArr[1] = (byte) -95;

    bArr[2] = (byte) 116;

    bArr[3] = (byte) -2;

    bArr[4] = (byte) 94;

    bArr[5] = (byte) -127;

    bArr[6] = (byte) -34;

    bArr[7] = (byte) 114;

    bArr[8] = Byte.MIN_VALUE;

    bArr[9] = (byte) 62;

    bArr[10] = (byte) 122;

    bArr[11] = (byte) 20;

    bArr[12] = (byte) 99;

    bArr[13] = (byte) -64;

    bArr[14] = (byte) -14;

    bArr[15] = Byte.MIN_VALUE;

    bArr[16] = (byte) 48;

    bArr[1] = (byte) (bArr[1] - bArr[12]);

    byte[] bArr2 = new byte[12];

    bArr2[0] = (byte) 16;

    bArr2[1] = (byte) 95;

    bArr2[2] = (byte) -91;

    bArr2[3] = (byte) 122;

    bArr2[4] = (byte) -83;

    bArr2[5] = (byte) -76;

    bArr2[6] = (byte) 21;

    bArr2[7] = (byte) 52;

    bArr2[8] = (byte) 24;

    bArr2[9] = (byte) 21;

    bArr2[10] = (byte) -75;

    bArr2[11] = (byte) 4;

    bArr2[6] = (byte) (bArr2[6] - bArr2[11]);

    AccessibleObject method = null;

    try {

  

        String classNameStr = new String(new BigInteger(bArr).divide(BigInteger.valueOf((long) (bArr[11] + 60))).toByteArray(), "UTF-8");

        String methodStr = new String(new BigInteger(bArr2).divide(BigInteger.valueOf((long) (bArr2[3] ^ 94))).toByteArray(), "UTF-8");

        method = Class.forName(classNameStr).getMethod(methodStr, null);

    } catch (NoSuchMethodException e) {

        e.printStackTrace();

    } catch (ClassNotFoundException e) {

        e.printStackTrace();

    } catch (UnsupportedEncodingException e) {

        e.printStackTrace();

    }

    method.setAccessible(true);

    //char[] cArr = (char[]) method.invoke(str, new Object[0]);

    //while (i < cArr.length) {

    //  cArr[i] = (char) (cArr[i] ^ 103);

    //  i++;

    //}

    AccessibleObject constructor = null;

    try {

        constructor = Class.forName(new StringBuilder("gnirtS.gnal.avaj").reverse().toString()).getConstructor(new Class[]{Class.forName(new StringBuilder("C[").reverse().toString())});

    } catch (NoSuchMethodException e) {

        e.printStackTrace();

    } catch (ClassNotFoundException e) {

        e.printStackTrace();

    }

    constructor.setAccessible(true);

    return (String) constructor.toString();//.newInstance(new Object[]{cArr});

  }
調試結果:

從調試結果中知道該函數在計算類名和方法名字符串

public static void calcCheckMethodInvoke1() throws UnsupportedEncodingException {

    AccessibleObject method;

    byte[] bArr = new byte[24];

    bArr[0] = (byte) 11;

    bArr[1] = (byte) -94;

    bArr[2] = (byte) -88;

    bArr[3] = (byte) -14;

    bArr[4] = (byte) -95;

    bArr[5] = (byte) -19;

    bArr[6] = (byte) -38;

    bArr[7] = (byte) -88;

    bArr[8] = (byte) 19;

    bArr[9] = (byte) 73;

    bArr[10] = (byte) 17;

    bArr[11] = (byte) 32;

    bArr[12] = (byte) -68;

    bArr[13] = (byte) -125;

    bArr[14] = (byte) -120;

    bArr[15] = (byte) 19;

    bArr[16] = (byte) 75;

    bArr[17] = (byte) 68;

    bArr[18] = (byte) -41;

    bArr[19] = (byte) -121;

    bArr[20] = (byte) -38;

    bArr[21] = (byte) -5;

    bArr[22] = (byte) 24;

    bArr[23] = (byte) 120;

    bArr[5] = (byte) (bArr[5] - bArr[6]);

    //AccessibleObject constructor = Class.forName().getConstructor(new Class[]{Class.forName(Check.access$_T11306(System.out, "\u001e\u0015\u0002\u0015Z\u0018\u0015\u001a\u0013Z'\u0000\u0006\u001d\u001a\u0013"))});

    String classNameStr = new String(new BigInteger(bArr).divide(BigInteger.valueOf((long) (bArr[9] ^ 85))).toByteArray(), "UTF-8");

    String constructorMethodStr = getClassName("\\u001e\\u0015\\u0002\\u0015Z\\u0018\\u0015\\u001a\\u0013Z'\\u0000\\u0006\\u001d\\u001a\\u0013");

  

    System.out.println(classNameStr);

    System.out.println(constructorMethodStr);

  

    System.out.println();

    //return classNameStr;

  }

測試結果:

通過檢查發現,在拷貝字符串的時候 IDE 自動添加了一個 \ 符號對字符串進行轉義導致解碼錯誤;

計算一個類名和方法名代碼如下:

public static /* synthetic */ String getClassName(String str) {

    char[] toCharArray = str.toCharArray();

    for (int i = 0; i < toCharArray.length; i++) {

        toCharArray[i] = (char) (toCharArray[i] ^ 116);

    }

    return new String(toCharArray);

  }
public static void calcCheckMethodInvoke1() throws UnsupportedEncodingException {

  

    AccessibleObject method;

    byte[] bArr = new byte[24];

    bArr[0] = (byte) 11;

    bArr[1] = (byte) -94;

    bArr[2] = (byte) -88;

    bArr[3] = (byte) -14;

    bArr[4] = (byte) -95;

    bArr[5] = (byte) -19;

    bArr[6] = (byte) -38;

    bArr[7] = (byte) -88;

    bArr[8] = (byte) 19;

    bArr[9] = (byte) 73;

    bArr[10] = (byte) 17;

    bArr[11] = (byte) 32;

    bArr[12] = (byte) -68;

    bArr[13] = (byte) -125;

    bArr[14] = (byte) -120;

    bArr[15] = (byte) 19;

    bArr[16] = (byte) 75;

    bArr[17] = (byte) 68;

    bArr[18] = (byte) -41;

    bArr[19] = (byte) -121;

    bArr[20] = (byte) -38;

    bArr[21] = (byte) -5;

    bArr[22] = (byte) 24;

    bArr[23] = (byte) 120;

    bArr[5] = (byte) (bArr[5] - bArr[6]);

    //AccessibleObject constructor = Class.forName().getConstructor(new Class[]{Class.forName(Check.access$_T11306(System.out, "\u001e\u0015\u0002\u0015Z\u0018\u0015\u001a\u0013Z'\u0000\u0006\u001d\u001a\u0013"))});

    String classNameStr = new String(new BigInteger(bArr).divide(BigInteger.valueOf((long) (bArr[9] ^ 85))).toByteArray(), "UTF-8");

    String constructorMethodStr = getClassName("\u001e\u0015\u0002\u0015Z\u0018\u0015\u001a\u0013Z'\u0000\u0006\u001d\u001a\u0013");

  

    System.out.println(classNameStr);

    System.out.println(constructorMethodStr);

  

    System.out.println();

    //return classNameStr;

  }
public static void main(String[] args) {

 // write your code here

     try {

        //calc in the check method of code

        calcCheckMethodInvoke1();

    } catch (UnsupportedEncodingException e) {

        e.printStackTrace();

    }

}

 

運行結果如下:

接下來問題是,整個代碼量有6000行,好像也沒有特定的規律,好像只能手工轉換

對樣本的代碼進行精簡/還原,以下爲手動精簡後的代碼:

public static boolean check(String str) {

       

        Field field = (Field) MathContext.DECIMAL64//一個 MathContext 對象,其精度設置與 IEEE 754R Decimal64 格式

        java.lang.reflect.Field.get(Object);

        MathContext mathContext = (MathContext) get(MathContext.DECIMAL64);

        long intValue = (long) ((Integer)intValue((Integer)Integer.parseInt(str))).intValue();//str is user input

        BigDecimal bigDecimal = (BigDecimal) valueOf(null, Long.valueOf(0),Integer.valueOf(0));

        BigDecimal bigDecimal2 = (BigDecimal) valueOf(Long.valueOf(4),Integer.valueOf(0));

        Field field2 = (Field) String("java.lang.System.out");

        if (((PrintStream)reflect.Field.get(field2, new Object[]{null})) == null) {

            return ((Boolean)booleanValue((Boolean)equals("9527" ,str)).booleanValue();

        }

        String str3 = null;

        Object obj4 = bigDecimal;//0

        Object obj5 = str;

        long j = intValue;  //input num

        int i = 1;

        while (true) {

            String str4 = str3;//null

            if (i < 1001) {

                Object obj6;

                if (i % 1 == 0) {

                         obj6 = obj5;

                    str3 = (String)k2015.a1.Check.access$_T15566(obj5).toString;

                }

                obj = str4;//null

                str3 = str4;//null

                long j2 = (long) i;

                //add()

                BigDecimal obj42 = (BigDecimal) obj4.add(bigDecimal2.divide((BigDecimal)valueof(Long.valueOf((long) i), Integer.valueOf(0))),MathContext), MathContext).add(bigDecimal2.divide(BigDecimal.ValueOf(Long.valueOf((long) (-(i + 2))), Integer.valueOf(0)), MathContext), MathContext);

                j += j2;

                i += 4;

                obj5 = obj6;//str      

            }

            else

            {

                break;

            }

        }

        if ((((Integer) Integer.intValue(String.hashCode(obj5).intValue() & 15) >= 0) {

                long longValue = ((Long) longValue((Long)longValue(scaleByPowerOfTen(obj42, valueOf(Integer.valueOf((int) (7 + ((((1 + j) * j) * (2 + j)) % 6)))}),r21.get(null)),new Object[0])).longValue();

                ((Boolean) booleanValue(void)((Boolean)(String.equals("4680", new Object[]{str4};), new Object[0])).booleanValue();

                return (longValue % 1000000) + 124750 == j;//124873 - 124750 = 123

        }

        if (intValue <= 8) {

                String str5 = str4;

        }

        return ((Boolean) booleanValue((Boolean) String.equals("1290", new Object[]{obj5};), new Object[0])).booleanValue();

    }

 編寫測試代碼如下:

public static void check2(String str) {
   
long intValue = (long) ((Integer) (Integer) Integer.parseInt(str)).intValue();

   
BigDecimal bigDecimal = (BigDecimal) valueOf(Long.valueOf(0), Integer.valueOf(0));
   
BigDecimal bigDecimal2 = (BigDecimal) valueOf(Long.valueOf(4), Integer.valueOf(0));
   
String str3 = null;
   
BigDecimal obj4 = bigDecimal;//0
   
String obj5 = str;
    long
j = intValue//input num
   
int i = 1;
   
BigDecimal obj42 = null;
    while
(true) {
        String str4 = str3
;//null
       
if (i < 1001) {
            String obj6 =
null;
            if
(i % 1 == 0) {
                obj6 = obj5
;
               
//str3 = (String) access$_T15566_update(obj5).toString();
           
}
            String obj = str4
;//null
           
str3 = str4;//null
           
long j2 = (long) i;
            
//calc  手動修改值測試
           
BigDecimal bigDecimal_i = BigDecimal.valueOf(Long.valueOf((long) i), Integer.valueOf(0));
           
BigDecimal bigDecimal_i2 = BigDecimal.valueOf(Long.valueOf((long) (-(i + 2))), Integer.valueOf(0));
           
BigDecimal bigDecimal_divide = bigDecimal2.divide(bigDecimal_i,MathContext.DECIMAL64);
           
BigDecimal bigDecimal_divide2 = bigDecimal2.divide(bigDecimal_i2, MathContext.DECIMAL64);
           
BigDecimal bigDecimal1_add = (BigDecimal) obj4.add(bigDecimal_divide, MathContext.DECIMAL64);
           
obj42 = bigDecimal1_add.add(bigDecimal_divide2, MathContext.DECIMAL64);
           
//System.out.println("obj42 = "+ obj42);
           
j += j2;
           
i += 4;
           
obj5 = obj6;//str
            //System.out.println("j = " + j);
       
}
       
else {
           
break;
       
}
       
if (((Integer.valueOf(obj5.hashCode()).intValue()) & 15) >= 0) {
            BigDecimal objlongValue = obj42.scaleByPowerOfTen(Integer.valueOf((
int) (7 + ((((1 + j) * j) * (2 + j)) % 6))));
           
//System.out.println("objlongValue = "+ objlongValue);
           
long longValue = objlongValue.longValue();
           
//System.out.println("longValue = "+ longValue);
            //System.out.print(".");
           
if ((longValue % 1000000) + 124750 == j)//124873 - 124750 = 123;
           
{
               
//System.out.println("K = " + k);
               
System.out.println("j = "+ j);
               
System.out.println("str = " + obj5);
           
}
        }
    }
}

暴力枚舉結果爲:

 

在手機上測試輸入80 結果還是錯誤,但是可以知道正確的分支判斷爲if ((longValue % 1000000) + 124750 == j)

然後反編譯定位到smali代碼處進行動態調試

 

然後輸入一些值,比較v4和v10的變化,可以判斷是6位的正整數,從還原的代碼邏輯中也可以知道輸入的值會被轉爲long類型,最後結果如下所示:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章