Dexguard分析&钛备份破解

来源:互联网 发布:python 二叉树查找 编辑:程序博客网 时间:2024/04/30 14:25
钛备份,貌似是备份方向很火的一个软件(可能类似于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 Erickyimport sysimport osimport timefrom jeb.api import IScriptfrom jeb.api import EngineOptionfrom jeb.api.ui import Viewfrom jeb.api.dex import Dexfrom jeb.api.ast import Class, Field, Method, Call, Constant, StaticField, NewArrayencbytes = [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


0 0
原创粉丝点击