Dexguard分析&鈦備份破解

鈦備份,貌似是備份方向很火的一個軟件(可能類似於win下的super recovery)。Claud說是加的Dexguard殼,由於本人是初學者,也沒見過什麼世面,更不懂得Dexguard是個什麼東西了,就一股子蠻勁,結果不小心把鈦備份幹掉了,看來功夫不負有心人啊。以下寫出心得和大家分享,互相學習進步。
菜鳥第一次分析,請大牛勿噴,會打擊小菜的積極性的!
一、APKtools反編譯
可能是Dexguard殼子利用了apktools的bug吧,反正我是沒有反編譯成功。AndroidManifest.xml裏所有不在<intent-filter>與</intent-filter>的元素key值都沒有反編譯出來。

如圖所示:


修復後如下:


但是還是無法打包。用apktools還是打包失敗:


既然無法打包,很多方法就行不通了,log的方法也失效了,不過不要緊,反編譯失敗導致無法正常打包,那就用點原始的方法吧。不管那麼多,先分析分析這個程序再說,程序分析透了,至少也算是對自身的一種提高,說幹就幹。(這個問題現在還沒有解決,希望會的大牛告知一下,在下感激不盡。)




二、逆向分析


雖然說打包是沒搞定,但主要是因爲xml文件apktools分析出錯的原因,還好不影響我們親愛的smali文件的反編譯。JEB載入,(這裏要感謝SCZ大神的無私奉獻,雖然說好像保存功能用不了,但是已經非常感謝了)隨便翻了一下,看見一個這個:


我本來準備吐槽作者了,但是往後一翻,我覺得這個也不必怎麼大驚小怪。因爲對於第一次分析APK,發現如下的東西,我開始有點不淡定了。類名和函數的名稱被加密成這樣:



不過不管它多麼花,也要幹掉它!
那就要開始定位關鍵地方,進行破解了。
2.1.關鍵定位
我目前知道的一共有2種方法可以成功定位到關鍵地方。
第一種方法:搜Strings.


這是一種方法,當然可能搜到的不止一處,這就需要自己去甄別了。
第二種方法:這種方法在我之前的一篇學習筆記裏也有講到,裏面的第四種方法,所謂的“遺留下的寶藏”。用到了DDMS 如圖:


OK,真幸運,直接定位到了fs中。Nice。


2.2log分析
既然發現了驗證的類,那就不能放過。發現大部分字符串都被加密過了,我們就從log開始着手吧。找了幾個log如下:



發現瞭解密函數,把它Rename:


解密函數如下:



找到了解密函數,這就好辦了,先把strings解密了再說,我寫了一個python腳本來解密encryptStrings。Python腳本如下:
代碼:

#Author Ericky
import sys
import os
import time
from jeb.api import IScript
from jeb.api import EngineOption
from jeb.api.ui import View
from jeb.api.dex import Dex
from jeb.api.ast import Class, Field, Method, Call, Constant, StaticField, NewArray
encbytes = [69, 21, -111, -111, 14, -30, 5, -3, -10, -6, 9, -6, 6, 9, 60, -36, 
                -45, -4, -1, -4, 4, -5, 83, -68, 1, -3, -6, 2, 68, -71, -4, -4, 6, 42, 25, 14, -30, 
                5, -3, -10, -6, 9, -6, 6, 9, 60, -55, -12, -12, 2, 4, 2, -20, 10, -6, 6, 70, -71, -13, 
                2, 1, 76, -68, 1, -3, -6, 2, 68, -71, -4, -4, 6, 68, -15, -1, -1, 14, -30, 5, -3, -10, 
                -6, 9, -6, 6, 9, 60, -51, -20, -15, 2, 0, 0, -6, 13, 68, -74, -11, 82, -79, -2, -6, 
                83, -87, 20, -12, 2, 4, 67, -66, -14, -12, 11, -3, -4, 12, 54, 14, -30, 5, -3, -10, 
                -6, 9, -6, 6, 9, 60, -51, -20, -15, 2, 0, 0, -6, 13, 68, -88, 13, -4, -1, 75, -84, -2, 
                10, -4, -1, 75, -83, 12, -9, 11, -9, -6, 77, -87, 20, -12, 2, 4, 67, -71, -10, -4, 81, 
                14, -30, 5, -3, -10, -6, 9, -6, 6, 9, 60, -51, -20, -15, 2, 0, 0, -6, 13, 68, -74, -11, 
                82, -84, -2, 10, -4, -1, 75, -87, 16, -14, -8, 88, -71, -13, 12, -15, 10, 57, 14, -30, 
                5, -3, -10, -6, 9, -6, 6, 9, 60, -52, -15, -22, 12, -6, 6, 70, -68, 1, -3, -6, 2, 68, 
                -71, -4, -4, 6, 42, 25, 14, -30, 5, -3, -10, -6, 9, -6, 6, 9, 60, -36, -31, -3, -6, 
                2, 68, -87, 20, -12, 2, 4, 36, 30, -30, 28, 14, -30, 5, -3, -10, -6, 9, -6, 6, 9, 60, 
                -51, -20, -15, 2, 0, 0, -6, 13, 68, -88, 13, -4, -1, 75, -67, -4, 68, -83, 12, -2, -13, 
                12, -15, 10, 2, 0, 67, -67, -4, 1, 1, -21, 1, 13, 68, -80, -8, 16, -14, 81, -18, 1, 
                -5, 0, 17, -80, 8, 69, -74, -12, 0, 82, -87, 20, -12, 2, 4, -6, -12, -6, 88, -69, -18, 
                2, 16, -20, 10, -7, 0, 77, -74, -11, 82, -70, -8, 10, -16, -4, 13, 0, 53, 14, -30, 5, 
                -3, -10, -6, 9, -6, 6, 9, 60, -47, -34, 78, -68, 1, -3, -6, 2, 68, -71, -4, -4, 6, 42, 
                25, 14, -30, 5, -3, -10, -6, 9, -6, 6, 9, 60, -37, -34, -8, 6, -16, 10, -6, 6, 70, -79, 
                -2, 0, 64, -74, 20, -12, 2, 4, 67, -68, 1, -3, -6, 2, 68, -71, -4, -4, 6, 42, 25]


class Mydecypt(IScript):

  def run(self, jeb):
    self.jeb = jeb
    self.dex = self.jeb.getDex()
    self.cstbuilder = Constant.Builder(jeb)

    self.csig = 'fs'
    self.encbytes = encbytes
    self.mname_decrypt = None

    r = jeb.decompileClass(self.csig)
    decrypted_string = self.decrypt(66, 26, 0) #Here enter your encrypt strings
    print '  Decrypted string: %s' % repr(decrypted_string)
  def decrypt(self, length, curChar, pos):
    length = 93 - length
    pos = pos * 2 + 91
    curChar = 378 - curChar
    r = ''
    for i in range(length):
      curChar +=1
      r += chr(pos & 0xFF)
      if i >= len(self.encbytes):
        break
      curEncodedChar = self.encbytes[curChar]
      pos = pos - curEncodedChar -1
    return r   
把字符串解密了,那就事半功倍了。具體的分析就比較簡單了。分析解密後如下:
代碼:

private static final BigInteger 大整數;
    private static final byte[] 加密字符串;
    public static boolean 普通版開關;
    public static boolean 專業版開關;
    public static hG HG類;
    private static final String 字符串常量;
    private static int 常數;
    private static boolean modaco隱藏版本開關;

    static {
        fs.加密字符串 = new byte[]{69, 21, -111, -111, 14, -30, 5, -3, -10, -6, 9, -6, 6, 9, 60, -36, -45, -4, 
                -1, -4, 4, -5, 83, -68, 1, -3, -6, 2, 68, -71, -4, -4, 6, 42, 25, 14, -30, 5, -3, -10, 
                -6, 9, -6, 6, 9, 60, -55, -12, -12, 2, 4, 2, -20, 10, -6, 6, 70, -71, -13, 2, 1, 76, 
                -68, 1, -3, -6, 2, 68, -71, -4, -4, 6, 68, -15, -1, -1, 14, -30, 5, -3, -10, -6, 9, 
                -6, 6, 9, 60, -51, -20, -15, 2, 0, 0, -6, 13, 68, -74, -11, 82, -79, -2, -6, 83, -87, 
                20, -12, 2, 4, 67, -66, -14, -12, 11, -3, -4, 12, 54, 14, -30, 5, -3, -10, -6, 9, -6, 
                6, 9, 60, -51, -20, -15, 2, 0, 0, -6, 13, 68, -88, 13, -4, -1, 75, -84, -2, 10, -4, 
                -1, 75, -83, 12, -9, 11, -9, -6, 77, -87, 20, -12, 2, 4, 67, -71, -10, -4, 81, 14, -30, 
                5, -3, -10, -6, 9, -6, 6, 9, 60, -51, -20, -15, 2, 0, 0, -6, 13, 68, -74, -11, 82, -84, 
                -2, 10, -4, -1, 75, -87, 16, -14, -8, 88, -71, -13, 12, -15, 10, 57, 14, -30, 5, -3, 
                -10, -6, 9, -6, 6, 9, 60, -52, -15, -22, 12, -6, 6, 70, -68, 1, -3, -6, 2, 68, -71, 
                -4, -4, 6, 42, 25, 14, -30, 5, -3, -10, -6, 9, -6, 6, 9, 60, -36, -31, -3, -6, 2, 68, 
                -87, 20, -12, 2, 4, 36, 30, -30, 28, 14, -30, 5, -3, -10, -6, 9, -6, 6, 9, 60, -51, 
                -20, -15, 2, 0, 0, -6, 13, 68, -88, 13, -4, -1, 75, -67, -4, 68, -83, 12, -2, -13, 12, 
                -15, 10, 2, 0, 67, -67, -4, 1, 1, -21, 1, 13, 68, -80, -8, 16, -14, 81, -18, 1, -5, 
                0, 17, -80, 8, 69, -74, -12, 0, 82, -87, 20, -12, 2, 4, -6, -12, -6, 88, -69, -18, 2, 
                16, -20, 10, -7, 0, 77, -74, -11, 82, -70, -8, 10, -16, -4, 13, 0, 53, 14, -30, 5, -3, 
                -10, -6, 9, -6, 6, 9, 60, -47, -34, 78, -68, 1, -3, -6, 2, 68, -71, -4, -4, 6, 42, 25, 
                14, -30, 5, -3, -10, -6, 9, -6, 6, 9, 60, -37, -34, -8, 6, -16, 10, -6, 6, 70, -79, 
                -2, 0, 64, -74, 20, -12, 2, 4, 67, -68, 1, -3, -6, 2, 68, -71, -4, -4, 6, 42, 25};
        fs.常數 = 245;
        boolean v0 = !fs.class.desiredAssertionStatus() ? true : false;
        fs.ʼ = v0;
        fs.字符串常量 = fs.class.getName();
        fs.普通版開關 = false;
        fs.專業版開關 = false;
        fs.HG類 = null;
        fs.modaco隱藏版本開關 = false;
        fs.大整數 = BigInteger.ONE.shiftLeft(16).add(BigInteger.ONE);

值得注意的地方是這個函數:
代碼:

private static void 關鍵函數(Runnable arg3, boolean arg4) {
        if(arg4) {
            fs.ˊ(true);
            fs.專業版開關 = true;
            fs.HG類 = new hG();
        }
        else {
            fs.ˊ(fs.ˊ(MainApplication.ʾ));
            boolean v0 = !fs.modaco隱藏版本開關 || !"95116f196c3b".equals(fs.HG類.get("keyId")) ? false : true;
            fs.普通版開關 = v0;
        }

        arg3.run();//很明顯了吧  
}

分析好的fs類我會打包在附件中。
三、破解


有3個開關,事情就變得很簡單了,改幾個字節就行了。找到類中的開關,打開交叉引用:

找到每一個地方,稍微分析一下,把需要改的置真即可。當然你不怕麻煩的話,可以每一處都置“1”,也是一樣的。
看了吾愛的一篇文章說修改之後,會彈出版本不正確。打開APK中的so,你會看到一個mprotect的函數,根據名字我猜的話應該是so裏面的MD5完整性校驗,但是奇怪的是,由於我更改的是幾個“開關”,貌似dexguard對開關,或者說是聲明函數裏的東西是不檢查的,因此這種方法直接避過了dexguard 6.0的anti-tampering check.不僅省去了逆SO的時間和精力,動態加載也不用去擔心,因爲找到的這塊是風水寶地啊,直接避開了dexguard的檢測,當然也有可能是我直接改的dex文件裏的opcode,可能dexguard對dex的檢測只是依賴與dex自身的SHA-1值和簽名值。
剛纔說了打包不了,怎麼辦呢?我的方法是直接解壓apk,用IDA load dex,然後在IDA中定位到具體的offset,然後用16進制工具直接找到offset直接修改dex的opcode即可。還是很期待有人指點下過dexguard反編譯方法啦,我自己當然也會繼續研究的。
如圖:


四、總結

11.22號開始看豐生強的那本入門書,這個程序3天分析得差不多了,也算是對最近20天自己的一個交代。這個程序真的很有意思,除了表面上的2個版本之外後來還發現有一個隱藏的版本,真的是耐人尋味啊。從中加強了自己的逆向分析,同時也瞭解到了作者的一些驗證思路。本來找到了keygen算法(第一個函數)想分析算法,patch之後做一個keygen出來,但是因爲實力有限吧,最後還是放棄了。因爲JEB不能保存的緣故,這一次fs裏面分析的東西是臨時做的,難免有疏漏,還望各位見諒。
在這裏衷心謝謝非蟲的書,越反覆看覺得越寫得好,雖然有的地方有一些冗長。也感謝論壇上的一些文章,認真讀了,很有收穫。接下來還是要繼續學習吧,不過基礎還是一定要打牢!
總的來說,收穫還是挺大的,學到了很多東西。歡迎大家和我一起交流,一起進步。新手難免沒有紕漏,失敬之處還望各位大俠多多指點。
(*^__^*) 
By Ericky
2014.12.9


發佈了31 篇原創文章 · 獲贊 2 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章