拿到樣本通過dex2jar工具將dex轉爲jar包,然後將java代碼複製出來進行修復,修復過程如下,代碼量太大,但是最開始不清楚邏輯所以只能用這種笨辦法了。
public static /* synthetic */ String getClassName(String str) { 測試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) { |
暴力枚舉結果爲:
在手機上測試輸入80 結果還是錯誤,但是可以知道正確的分支判斷爲if ((longValue % 1000000) + 124750 == j)
然後反編譯定位到smali代碼處進行動態調試
然後輸入一些值,比較v4和v10的變化,可以判斷是6位的正整數,從還原的代碼邏輯中也可以知道輸入的值會被轉爲long類型,最後結果如下所示: