首页
社区
课程
招聘
[原创]Dexguard分析&钛备份破解
2014-12-10 17:57 30575

[原创]Dexguard分析&钛备份破解

2014-12-10 17:57
30575
钛备份,貌似是备份方向很火的一个软件(可能类似于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.
如图:
这是一种方法,当然可能搜到的不止一处,这就需要自己去甄别了。
第二种方法:这种方法在我之前的一篇学习笔记里也有讲到,地址:http://bbs.pediy.com/showthread.php?t=195202。里面的第四种方法,所谓的“遗留下的宝藏”。用到了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
Here are attachments:
fs analysis.zip
Cracked by Ericky.haozip01.zip
Cracked by Ericky.haozip02.zip

[培训]《安卓高级研修班(网课)》月薪三万计划,掌 握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

上传的附件:
收藏
点赞1
打赏
分享
最新回复 (14)
雪    币: 296
活跃值: (89)
能力值: ( LV15,RANK:340 )
在线值:
发帖
回帖
粉丝
木桩 8 2014-12-10 20:20
2
0
感谢分享分析过程,有时间也按着LZ的思路拆开看看:)
不过看到这个函数名列表还真是眼前一花,哈哈
雪    币: 370
活跃值: (1181)
能力值: ( LV9,RANK:310 )
在线值:
发帖
回帖
粉丝
ThomasKing 6 2014-12-10 20:48
3
0
多谢楼主分享
雪    币: 1185
活跃值: (458)
能力值: ( LV13,RANK:360 )
在线值:
发帖
回帖
粉丝
Ericky 6 2014-12-10 22:42
4
0
嘿嘿 是啊,希望你试试  然后分享下打包的解决方法呢 (*^__^*)
雪    币: 1185
活跃值: (458)
能力值: ( LV13,RANK:360 )
在线值:
发帖
回帖
粉丝
Ericky 6 2014-12-10 22:43
5
0
你的ELF 也是很感谢~!
雪    币: 1413
活跃值: (401)
能力值: (RANK:270 )
在线值:
发帖
回帖
粉丝
Claud 6 2014-12-11 02:53
6
0
AXML的这种混淆原理和恢复方法,版上已经有两个帖子了:
http://bbs.pediy.com/showthread.php?t=194201
http://bbs.pediy.com/showthread.php?t=194206

“遗留下的宝藏”有点舌尖上“自然的馈赠”的感觉,XDD
雪    币: 1413
活跃值: (401)
能力值: (RANK:270 )
在线值:
发帖
回帖
粉丝
Claud 6 2014-12-11 02:54
7
0
另外,既然你都有了JEB,应该去他们的官方博客看看,JEB有一个脚本可以解密DexGuard的代码加密。就是不知道对最新版的DexGuard是不是还有用,有空你可以再写一篇来介绍,或者自己改改他们的脚本。
雪    币: 1185
活跃值: (458)
能力值: ( LV13,RANK:360 )
在线值:
发帖
回帖
粉丝
Ericky 6 2014-12-11 11:12
8
0
很感谢你的回答,文章从你上一次回答我就已拜读过了,要不就不会有修复的xml文件了~还是很谢谢你
至于“遗留下的宝藏”,只能说是一种思路。实际的过程是我进程序看到它会有类似”License cache Not Found“的提示,进而查找”License“字符串进行定位的,才定位到fs类。“遗留下的宝藏”定位的话,确实是一种思路。说不定对于某些特定的程序能起到奇效。但对于这个程序来说,log出来的内容挺多的,其实是很不好找的,用这种方法的需要很大运气成分。
雪    币: 1185
活跃值: (458)
能力值: ( LV13,RANK:360 )
在线值:
发帖
回帖
粉丝
Ericky 6 2014-12-11 11:19
9
0
有了JEB  当然会去JEB官网看看,至少也要看一下official的tutorials嘛。官网上的JEB确实是有1个脚本,确切的说是2个,1个是在大家都知道的Download下面的Scripts的下载,还有一个隐藏在它的介绍图片里面(虽然很隐蔽,但是细心点就能发现了)。对最新版的DexGuard已经失效,作者已经修改了一些内容,不过认真把脚本读懂还是可以自己融会贯通的写出来的。对真正看懂脚本的人影响不大,作者的修改也只能阻止一些“死搬硬套”的童鞋啦~谢谢解答~很感谢,起步很晚,所以志同道合的人就更难找到了。
雪    币: 188
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
JackJoker 2014-12-18 18:55
10
0
多谢楼主分享。
雪    币: 1194
活跃值: (1309)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
keulraesik 2014-12-20 23:27
11
0
关于hidden脚本 不知可否明示
雪    币: 1185
活跃值: (458)
能力值: ( LV13,RANK:360 )
在线值:
发帖
回帖
粉丝
Ericky 6 2014-12-21 13:02
12
0
在官网介绍的图片里面有
雪    币: 131
活跃值: (153)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
川美 2015-1-26 12:17
13
0
lz最近还在研究这块没?出点文章呗
雪    币: 1185
活跃值: (458)
能力值: ( LV13,RANK:360 )
在线值:
发帖
回帖
粉丝
Ericky 6 2015-1-26 12:54
14
0
没什么好文章出。。学习中
雪    币: 184
活跃值: (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
黑鹰十月 2015-2-15 06:21
15
0
感谢楼主分享,很精彩,希望能够介绍一下图片中所用的工具,包括搜索字符串文本编辑器等这些,方便童鞋照葫芦画瓢,谢谢
游客
登录 | 注册 方可回帖
返回