看雪安全论坛

 

 

 

 


返回   看雪安全论坛 > 移动平台 > 『Android 安全』
  登陆   注册  

发表新主题 回复
优秀帖  
主题工具 显示模式
本站声明:看雪论坛文章版权属于作者,受法律保护。没有作者书面许可不得转载。若作者同意转载,必须以超链接形式标明文章原始出处和作者信息及本声明!
QEver
级别:33 | 在线时长:1260小时 | 升级还需:32小时级别:33 | 在线时长:1260小时 | 升级还需:32小时级别:33 | 在线时长:1260小时 | 升级还需:32小时

中级会员
中级会员

资 料:
注册日期: Jan 2010
帖子: 516 QEver 品行端正
精华: 5
现金: 149 Kx
致谢数: 0
获感谢文章数:23
获会员感谢数:122
1 旧 2017-01-03 15:06:50 默认 已解答: 【原创】一个dex脱壳脚本
QEver 当前离线

标 题: 已解答: 【原创】一个dex脱壳脚本
作 者: QEver
时 间: 2017-01-03,15:06:50
链 接: http://bbs.pediy.com/showthread.php?t=214999

一个ida脚本,配合kill方法,可以实现脱绝大部分运行于dalvik上的dex壳。至于具体用法,自行领悟吧。
代码:
__author__ = 'QEver'

DUMP_FILE_PREFIX = r'd:/'
USER_DEX_FILES_OFFSET = 0x330
LOADED_CLASSES_OFFSET = 0xAC
JAR_NAME_OFFSET = 0x24
SIZE_OF_DEY_HEADER = 0x28
DESC_OFFSET_OF_CLASS_OBJECT = 0x18
METHOD_OFFSET_OF_CLASS_OBJECT = 0x60
SIZE_OF_STRUCT_METHOD = 0x38

import os
import idaapi
import binascii


def read_data(ea, size):
    return idaapi.dbg_read_memory(ea, size)


def read_dword(ea):
    val = int(binascii.hexlify(idaapi.dbg_read_memory(ea, 4)), 16)
    r = (val & 0xff) << 24 | (val & 0xff00) << 8 | (val & 0xff0000) >> 8 | (val & 0xff000000) >> 24
    return r


def read_bool(ea):
    val = int(binascii.hexlify(idaapi.dbg_read_memory(ea, 1)), 16)
    return val


def read_str(ea, max=256):
    c = ''
    while True:
        x = idaapi.dbg_read_memory(ea, 1)
        ea = ea + 1
        max = max - 1
        if x == '\0' or max < 0:
            break
        c += x
    return c


class DvmDex:
    def __init__(self, ea):
        self.ea = ea
        self.pDexFile = read_dword(ea)
        self.baseAddr = read_dword(self.pDexFile + 0x2c)

    def p(self):
        print 'pDexFile = %x' % self.pDexFile
        print 'baseAddr = %x' % self.baseAddr


class ClassObject:
    def __init__(self, ea):
        self.ea = ea
        self.desc_addr = read_dword(ea + DESC_OFFSET_OF_CLASS_OBJECT)

    def get_descriptor(self):
        return read_str(self.desc_addr)


class DexOrJar:
    def __init__(self, ea):
        self.ea = ea
        self.filename = read_dword(ea)
        self.isDex = read_bool(ea + 4)
        self.pRawDexFile = read_dword(ea + 8)
        self.pJarFile = read_dword(ea + 12)

    def get_filename(self):
        if self.isDex == 0:
            return read_str(read_dword(self.pJarFile + JAR_NAME_OFFSET))
        return read_str(self.filename)

    def get_dvmdex(self):
        if self.isDex == 0:
            return read_dword(self.pJarFile + JAR_NAME_OFFSET + 4)
        return read_dword(self.pRawDexFile + 4)

    def p(self):
        print 'filename = %s' % read_str(self.filename)
        print 'isDex = %d' % self.isDex
        print 'pRawDexFile = %x' % self.pRawDexFile
        print 'pJarFile = %x' % self.pJarFile


class HashTable:
    def __init__(self, ea):
        self.ea = ea
        self.tableSize = -1
        self.numEntries = -1
        self.pEntries = None
        self.do_init()

    def do_init(self):
        self.tableSize = read_dword(self.ea)
        self.numEntries = read_dword(self.ea + 4)
        self.pEntries = read_dword(self.ea + 12)

    def get_table_size(self):
        return self.tableSize

    def get_num_entries(self):
        return self.numEntries

    def get_pentries(self):
        return self.pEntries

    def p(self):
        print 'tableSize = %d' % self.tableSize
        print 'numEntries = %d' % self.numEntries
        print 'pEntries = %x' % self.pEntries


class Method:
    def __init__(self, ea):
        self.ea = ea

    def get_name(self):
        addr = self.ea + 0x10
        return read_str(read_dword(addr))

    def get_insns(self):
        addr = self.ea + 0x20
        return read_dword(addr)

    def get_address(self):
        return self.ea


def get_gdvm_address():
    return idaapi.get_debug_name_ea("gDvm")


def dump_all_dex(prefix=DUMP_FILE_PREFIX):
    gdvm = get_gdvm_address()
    print '[*] gDvm = 0x%x' % gdvm
    user_dex_files = read_dword(gdvm + USER_DEX_FILES_OFFSET)
    print '[*] gDvm.user_dex_files = 0x%x' % user_dex_files

    ht = HashTable(user_dex_files)

    max_size = ht.get_table_size()
    size = ht.get_num_entries()
    p = ht.get_pentries()
    print '[*] Found %s items in Dex Table' % size
    for i in range(max_size):
        x = read_dword(p)

        p += 8
        if x == 0:
            continue
        doj = DexOrJar(x)
        print '[*] Dex in Address 0x%x, isDex = %d' % (x, doj.isDex)
        addr = doj.get_dvmdex()
        name = doj.get_filename()
        print '[*] found file : %s , dvmdex = 0x%x' % (name, addr)

        dd = DvmDex(addr)
        addr = dd.baseAddr
        base = addr - SIZE_OF_DEY_HEADER
        size = read_dword(addr + 0x20) + SIZE_OF_DEY_HEADER
        flag = read_str(base, 3)
        if flag != 'dey':
            base = addr
            size = size = read_dword(addr + 0x20)

        print '[*] found odex file = 0x%x <%s>, size = 0x%x' % (base, read_str(base, 7).replace('\n', '.'), size)

        name = os.path.basename(name)
        path = os.path.join(prefix, name)

        print '[*] Write to %s' % path
        data = read_data(base, size)

        f = open(path, 'wb')
        f.write(data)
        f.close()
        print '[*] Finish Write'


def find_class(name):
    gDvm = get_gdvm_address()
    loaded_classes = read_dword(gDvm + LOADED_CLASSES_OFFSET)

    ht = HashTable(loaded_classes)
    max_size = ht.get_table_size()
    size = ht.get_num_entries()
    p = ht.get_pentries() + 4
    print 'Finding for %d items, may take a long time...' % max_size
    for i in range(max_size):
        x = read_dword(p)
        p = p + 8
        if x == 0:
            continue
        c = ClassObject(x)
        s = c.get_descriptor()
        if s == name:
            print '[*] Found Class <%s> : 0x%x' % (name, x)
            return x
        if s.find(name) != -1:
            print '[*] Found Class <%s> : 0x%x' % (s, x)


def list_method(class_addr):
    x = ClassObject(class_addr)
    print '[*] List All Method of %s' % x.get_descriptor()
    m = class_addr + METHOD_OFFSET_OF_CLASS_OBJECT
    directMethodCount = read_dword(m)
    directMethodTable = read_dword(m + 4)
    virtualMethodCount = read_dword(m + 8)
    virtualMethodTable = read_dword(m + 12)

    for i in range(directMethodCount):
        method = Method(directMethodTable)
        directMethodTable = directMethodTable + SIZE_OF_STRUCT_METHOD
        print method.get_name(), hex(method.get_address())

    for i in range(virtualMethodCount):
        method = Method(virtualMethodTable)
        virtualMethodTable = virtualMethodTable + SIZE_OF_STRUCT_METHOD
        print method.get_name()


def list_all_class():
    gDvm = get_gdvm_address()
    loaded_classes = read_dword(gDvm + LOADED_CLASSES_OFFSET)

    ht = HashTable(loaded_classes)
    max_size = ht.get_table_size()
    size = ht.get_num_entries()
    p = ht.get_pentries() + 4
    for i in range(max_size):
        x = read_dword(p)
        p = p + 8
        if x == 0:
            continue
        c = ClassObject(x)
        print c.get_descriptor()

if __name__ == '__main__':
    #list_all_class()
    #find_class('alibaba')
    #list_method(class_addr) 
    dump_all_dex('d:/')
其实脚本的思想,在2014年阿里安全竞赛解题报告里面,我就已经说的很清楚了。近期简单整理了代码,看到很多人还在纠结dex脱壳问题,就当作新年礼物,给大家分享一下吧。(我认为方法比某qian的xxxhunter靠谱多了~~~~~~~
本人早已经不做破解相关工作。不过在之前帮朋友的时候,发现现在的壳已经有针对我之前提到过的"kill -19"的防御措施,深感欣慰(=。=)~不过这条思路是无法防御的,变通一下方式,就能达到同样的目的。
总之~方法是死的,人是活的。没有牛逼的工具,只有牛逼的人~

最后~本Demo只是用于演示破解思路,本人不负责维护,也不会解释任何使用相关的问题!*转载请注明来自看雪论坛@PEdiy.com
回复时引用此帖 返回顶端
共 19 位会员
感谢 QEver 发表的文章:
AqCxBoM (2017-01-05), bengou (2017-01-04), cqccqc (2017-01-03), dagangwood (2017-01-05), gtict (2017-01-03), keulraesik (2017-01-03), MaYil (2017-01-03), netwind (2017-01-03), qqtianqi (2017-01-04), rfkj (2017-01-07), skyun (2017-01-05), toToC (2017-01-07), weslyw (2017-01-16), 影子不寂寞 (2017-01-13), 星际侠盗 (2017-01-14), 独自行走路上 (2017-01-05), 雪衫 (2017-01-03), 非虫 (2017-01-07), 黑夜破解 (2017-01-11)
最佳答案 - 作者: QEver
引用:
最初由 SANCDAYE发布 查看帖子
我是运行后,ida附加dump的,壳的话说官网加的免费版
总结一下吧。
1. ida脚本必须在原始的dex加载之后运行。一般需要配合kill“干掉”反调试。
2. 里面都是硬编码的数字,我用的是android-4.4.4_r2的系统。其他系统可能需要调整
3. 这份脚本是帮别人写的,脱了目标apk成功就没测试别的。然后随手删掉部分敏感内容后直接发出来了。
4. 其实就是一个原理,想方设法找到dvmdex
5. 脚本是手工的时候常用操作总结,用起来十分方便。而“靠谱”指的是dvmdex
6. 目前dump_all_dex是基于gDvm.userDexFiles脱的,这点可能被anti,但代价比较大,一般免费壳很少会处理。如果处理了,利用find_class。。。()
7. 脚本(手工静态)脱壳一般只适用于内存中存在完整dex的情况。如果是动态恢复的dex,建议换其他方法。(当然,脚本也可以动态下断点,动态dump,前提是你愿意写代码,并且完全搞定了反调试)。
8. 理论上来讲,壳是没有任何意义的,尤其是对于Android这种复杂的环境,只是打时间差和信息差而已。所以任何工具都不可能通用,但只要肯花时间分析清楚壳的信息,就能做到心中无壳~
gugubupt
级别:6 | 在线时长:73小时 | 升级还需:4小时级别:6 | 在线时长:73小时 | 升级还需:4小时级别:6 | 在线时长:73小时 | 升级还需:4小时

gugubupt 的头像

初级会员
初级会员

资 料:
注册日期: Mar 2013
帖子: 41 gugubupt 品行端正
精华: 0
现金: 57 Kx
致谢数: 2
获感谢文章数:2
获会员感谢数:3
2 旧 2017-01-03, 15:36:51 默认
gugubupt 当前离线

前排mark 大神
回复时引用此帖 返回顶端
wangzehua
级别:13 | 在线时长:243小时 | 升级还需:9小时级别:13 | 在线时长:243小时 | 升级还需:9小时级别:13 | 在线时长:243小时 | 升级还需:9小时级别:13 | 在线时长:243小时 | 升级还需:9小时

wangzehua 的头像

初级会员
初级会员

资 料:
注册日期: Oct 2010
帖子: 37 wangzehua 品行端正
精华: 0
现金: 100 Kx
致谢数: 0
获感谢文章数:0
获会员感谢数:0
3 旧 2017-01-03, 15:47:42 默认
wangzehua 当前离线

Q神牛逼!
回复时引用此帖 返回顶端
Zkeleven
级别:9 | 在线时长:138小时 | 升级还需:2小时级别:9 | 在线时长:138小时 | 升级还需:2小时级别:9 | 在线时长:138小时 | 升级还需:2小时

初级会员
初级会员

资 料:
注册日期: Dec 2015
帖子: 61 Zkeleven 品行端正
精华: 0
现金: 37 Kx
致谢数: 1
获感谢文章数:1
获会员感谢数:1
4 旧 2017-01-03, 15:51:49 默认
Zkeleven 当前离线

大神转做什么啦?
回复时引用此帖 返回顶端
qqsunqiang
级别:15 | 在线时长:292小时 | 升级还需:28小时级别:15 | 在线时长:292小时 | 升级还需:28小时级别:15 | 在线时长:292小时 | 升级还需:28小时级别:15 | 在线时长:292小时 | 升级还需:28小时级别:15 | 在线时长:292小时 | 升级还需:28小时级别:15 | 在线时长:292小时 | 升级还需:28小时

qqsunqiang 的头像

初级会员
初级会员

资 料:
注册日期: Dec 2013
帖子: 174 qqsunqiang 品行端正
精华: 0
现金: 80 Kx
致谢数: 1
获感谢文章数:1
获会员感谢数:2
5 旧 2017-01-03, 16:20:34 默认
qqsunqiang 当前离线

前排mark 大神
回复时引用此帖 返回顶端
tangsilian
级别:6 | 在线时长:73小时 | 升级还需:4小时级别:6 | 在线时长:73小时 | 升级还需:4小时级别:6 | 在线时长:73小时 | 升级还需:4小时

tangsilian 的头像

初级会员
初级会员

资 料:
注册日期: May 2016
帖子: 7 tangsilian 品行端正
精华: 0
现金: 10 Kx
致谢数: 3
获感谢文章数:0
获会员感谢数:0
6 旧 2017-01-03, 16:52:45 默认
tangsilian 当前离线

膜一波 大神
回复时引用此帖 返回顶端
xWeiwei
级别:15 | 在线时长:295小时 | 升级还需:25小时级别:15 | 在线时长:295小时 | 升级还需:25小时级别:15 | 在线时长:295小时 | 升级还需:25小时级别:15 | 在线时长:295小时 | 升级还需:25小时级别:15 | 在线时长:295小时 | 升级还需:25小时级别:15 | 在线时长:295小时 | 升级还需:25小时

xWeiwei 的头像

初级会员
初级会员

资 料:
注册日期: Aug 2014
帖子: 27 xWeiwei 品行端正
精华: 0
现金: 34 Kx
致谢数: 9
获感谢文章数:1
获会员感谢数:4
7 旧 2017-01-03, 16:56:31 默认
xWeiwei 当前离线

参观留名
回复时引用此帖 返回顶端
netwind
级别:30 | 在线时长:1061小时 | 升级还需:24小时级别:30 | 在线时长:1061小时 | 升级还需:24小时级别:30 | 在线时长:1061小时 | 升级还需:24小时级别:30 | 在线时长:1061小时 | 升级还需:24小时级别:30 | 在线时长:1061小时 | 升级还需:24小时级别:30 | 在线时长:1061小时 | 升级还需:24小时

『CrackMe◇ReverseMe』版主
『CrackMe◇ReverseMe』版主

资 料:
注册日期: May 2006
帖子: 514 netwind 品行端正
精华: 9
现金: 1115 Kx
致谢数: 17
获感谢文章数:4
获会员感谢数:8
8 旧 2017-01-03, 18:04:55 默认
netwind 当前离线

高手出招
回复时引用此帖 返回顶端
zylyy
级别:17 | 在线时长:375小时 | 升级还需:21小时级别:17 | 在线时长:375小时 | 升级还需:21小时

zylyy 的头像

初级会员
初级会员

资 料:
注册日期: Apr 2012
帖子: 187 zylyy 品行端正
精华: 0
现金: 100 Kx
致谢数: 7
获感谢文章数:0
获会员感谢数:0
9 旧 2017-01-03, 18:53:01 默认
zylyy 当前离线

恩,不错的小脚本
回复时引用此帖 返回顶端
Loopher
级别:4 | 在线时长:33小时 | 升级还需:12小时

初级会员
初级会员

资 料:
注册日期: Jul 2016
帖子: 58 Loopher 品行端正
精华: 0
现金: 5 Kx
致谢数: 0
获感谢文章数:1
获会员感谢数:1
10 旧 2017-01-03, 22:48:04 默认
Loopher 当前离线

牛逼的人,哈哈
回复时引用此帖 返回顶端
金奔腾
级别:5 | 在线时长:45小时 | 升级还需:15小时级别:5 | 在线时长:45小时 | 升级还需:15小时

初级会员
初级会员

资 料:
注册日期: Jan 2014
帖子: 19 金奔腾 品行端正
精华: 0
现金: 37 Kx
致谢数: 3
获感谢文章数:0
获会员感谢数:0
11 旧 2017-01-04, 08:32:51 默认
金奔腾 当前离线

感谢分享哦
回复时引用此帖 返回顶端
yaojunhap
级别:8 | 在线时长:111小时 | 升级还需:6小时级别:8 | 在线时长:111小时 | 升级还需:6小时

初级会员
初级会员

资 料:
注册日期: Feb 2013
帖子: 43 yaojunhap 品行端正
精华: 0
现金: 41 Kx
致谢数: 2
获感谢文章数:1
获会员感谢数:1
12 旧 2017-01-04, 09:47:57 默认
yaojunhap 当前离线

看不出比DEX Hunter靠谱在何处,可以简单解释一下吗。Dex Hunter在虚拟机里面改写代码,起码不用担心反调试反篡改等手段。并可以改造为自己枚举来强迫遍历所有类都实例化了。至于防止fread和fopen等注入更是简单。Dex Hunter主要缺点就是要编译个虚拟机,我想这个难度对做脱壳的同学不算啥吧。对学习脱壳的同学来说Dex Hunter算是打开了一扇大门。当然对做加固的同学来说就是个坑了。
回复时引用此帖 返回顶端
zzcc
级别:28 | 在线时长:936小时 | 升级还需:21小时级别:28 | 在线时长:936小时 | 升级还需:21小时级别:28 | 在线时长:936小时 | 升级还需:21小时级别:28 | 在线时长:936小时 | 升级还需:21小时

初级会员
初级会员

资 料:
注册日期: Jan 2007
帖子: 342 zzcc 品行端正
精华: 0
现金: 572 Kx
致谢数: 8
获感谢文章数:0
获会员感谢数:0
13 旧 2017-01-04, 12:29:14 默认
zzcc 当前离线

都太高端!
回复时引用此帖 返回顶端
QEver
级别:33 | 在线时长:1260小时 | 升级还需:32小时级别:33 | 在线时长:1260小时 | 升级还需:32小时级别:33 | 在线时长:1260小时 | 升级还需:32小时

中级会员
中级会员

资 料:
注册日期: Jan 2010
帖子: 516 QEver 品行端正
精华: 5
现金: 149 Kx
致谢数: 0
获感谢文章数:23
获会员感谢数:122
14 旧 2017-01-05, 10:49:34 默认
QEver 当前离线

引用:
最初由 yaojunhap发布 查看帖子
看不出比DEX Hunter靠谱在何处,可以简单解释一下吗。Dex Hunter在虚拟机里面改写代码,起码不用担心反调试反篡改等手段。并可以改造为自己枚举来强迫遍历所有类都实例化了。至于防止fread和fopen等注入更是简单。Dex Hunter主要缺点就是要编译个虚拟机,我想这个难度对做脱壳的同...
你要搞清楚两种方案的区别,然后考虑怎么做防御,才有可能看出哪里靠谱来。
例如,dexhunter公布出来了,加固程序简单更新一下,就能使其无效。而这份脚本里的方法,你可以想想如何才能防御。
回复时引用此帖 返回顶端
安东尼大木
级别:4 | 在线时长:32小时 | 升级还需:13小时

初级会员
初级会员

资 料:
注册日期: Aug 2016
帖子: 8 安东尼大木 品行端正
精华: 0
现金: 21 Kx
致谢数: 1
获感谢文章数:2
获会员感谢数:9
15 旧 2017-01-05, 11:46:11 默认
安东尼大木 当前离线

对于那些执行函数前恢复insns,完成后擦除insns的某些加固似乎没用呢?xxxhunter至少解决了这个问题
回复时引用此帖 返回顶端
发表新主题 回复

添加到书签

主题工具
显示模式

发帖规则
不可以发表主题
不可以回复帖子
不可以上传附件
不可以编辑自己的帖子
论坛论坛启用 vB 代码
论坛启用 表情图标

相似的主题
主题 主题作者 论坛 回复 最后发表
【原创】21题 谖草 『CrackMe&ReverseMe』 0 2016-12-12 16:40:49
【原创】Crackme20题 谖草 『CrackMe&ReverseMe』 0 2016-12-11 20:43:30
【原创】CTF第6题 shmily云 『CrackMe&ReverseMe』 0 2016-11-12 19:37:44


所有时间均为北京时间, 现在的时间是 02:03:43.


  ©2000-2016 看雪学院(PEdiy.com) |关于我们 | 京ICP备10040895号-17 | 知道创宇提供带宽资源 | 微信公众帐号:ikanxue