• 软件脱壳


    什么是 dex 文件

    他是Android系统的可执行文件,包含应用程序的全部操作指令以及运行时数据。

    由于dalvik是一种针对嵌入式设备而特殊设计的java虚拟机,所以dex文件与标准的class文件在结构设计上有着本质的区别

    当java程序编译成class后,还需要使用dx工具将所有的class文件整合到一个dex文件,目的是其中各个类能够共享数据,在一定程度上降低了冗余,同时也是文件结构更加经凑,实验表明,dex文件是传统jar文件大小的50%左右

    可以看见:
    dex将原来class每个文件都有的共有信息合成一体,这样减少了class的冗余

    数据结构

    类型 含义
    u1 unit8_t,1字节无符号数
    u2 unit16_t,2字节无符号数
    u4 unit32_t,4字节无符号数
    u8 unit64_t,8字节无符号数
    sleb128 有符号LEB128,可变长度1~5
    uleb128 无符号LEB128,
    uleb128p1 无符号LEB128值加1,

    dex文件结构

    首先从宏观上来说 dex 的文件结构很简单,实际上是由多个不同结构的数据体以首尾相接的方式拼接而成。如下图:

    数据名称 解释
    header dex文件头部,记录整个dex文件的相关属性
    string_ids 字符串数据索引,记录了每个字符串在数据区的偏移量
    type_ids 类似数据索引,记录了每个类型的字符串索引
    proto_ids 原型数据索引,记录了方法声明的字符串,返回类型字符串,参数列表
    field_ids 字段数据索引,记录了所属类,类型以及方法名
    method_ids 类方法索引,记录方法所属类名,方法声明以及方法名等信息
    class_defs 类定义数据索引,记录指定类各类信息,包括接口,超类,类数据偏移量
    data 数据区,保存了各个类的真是数据
    link_data 连接数据区

    header

    简单记录了dex文件的一些基本信息,以及大致的数据分布。长度固定为0x70,其中每一项信息所占用的内存空间也是固定的,好处是虚拟机在处理dex时不用考虑dex文件的多样性

    字段名称 偏移值 长度 说明
    magic 0x0 8 魔术字段,值为"dex 035"
    checksum 0x8 4 校验码
    signature 0xc 20 sha-1签名
    file_size 0x20 4 dex文件总长度
    header_size 0x24 4 文件头长度,009版本=0x5c,035版本=0x70
    endian_tag 0x28 4 标示字节顺序的常量
    link_size 0x2c 4 链接段的大小,如果为0就是静态链接
    link_off 0x30 4 链接段的开始位置
    map_off 0x34 4 map数据基址
    string_ids_size 0x38 4 字符串列表中字符串个数
    string_ids_off 0x3c 4 字符串列表基址
    type_ids_size 0x40 4 类列表里的类型个数
    type_ids_off 0x44 4 类列表基址
    proto_ids_size 0x48 4 原型列表里面的原型个数
    proto_ids_off 0x4c 4 原型列表基址
    field_ids_size 0x50 4 字段个数
    field_ids_off 0x54 4 字段列表基址
    method_ids_size 0x58 4 方法个数
    method_ids_off 0x5c 4 方法列表基址
    class_defs_size 0x60 4 类定义标中类的个数
    class_defs_off 0x64 4 类定义列表基址
    data_size 0x68 4 数据段的大小,必须4k对齐
    data_off 0x6c 4 数据段基址

    magic

    标识一个有效的dex文件,他的固定值为:64 65 78 0a 30 33 35 00,转换为字符串为dex.035.
    在电子取证中也称“文件签名”

    checksum

    他是整个头部的校验和。它被用来校验头部是否损坏

    signature

    二次打包时的签名

    file_size

    记录包括dexHeader在内的整个dex文件大小,用来计算偏移和方便定位某区段(section),他也有诸如唯一的标识dex,因为他是dex文件中计算sha-1区段的一个组成部分

    header_size

    存放整个DexHeadeer结构体的长度,它也可用来计算下一个区段在文件中的起始位置,目前值为0x70


    脱壳原理

    什么是软件脱壳?

    软件脱壳,顾名思义,就是对软件加壳的逆操作,把软件上存在的壳去掉

    加固是如何运行起来的?

    1. -->APP启动
    2. -->壳dex先加载起来
    3. -->壳负责把源dex文件读出来
    4. -->壳把源dex文件解密
    5. -->把解密后的dex加载进内存 源dex运行起来

    原理:

    源dex文件最终会加载进内存
    Hook加载Dex的函数,把Dex从内存中dump出来
    Hook DexFile::OpenMemory()
    DexFile::OpenMemory(const uint8_t* base,
    size_t size,
    const std::string& location,
    uint32_t location_checksum,
    MemMap* mem_map,//nullptr
    const OatDexFile* oat_dex_file,
    std::string* error_msg)


    脱壳方案

    方案一:Xposed + Fdex2

    方案二:Frida 脱壳

    1、启动手机内的 frida-server 并进行端口转发。27043 27042

    2、导出 Android 的 /system/lib/libart.so 到本地。然后使用 IDA 查看 OpenMemory 对应的签名函数名。我这里对应的是 _ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_

    import frida
    import sys
    
    package = 'com.iCitySuzhou.suzhou001'
    
    def on_message(message, data):
        if message['type'] == 'send':
            print(f"[*] {message['payload']}")
        else:
            print(message)
    
    # OpenMenory 在 libart.so 中,art 虚拟机(安卓5),davlink 虚拟机(安卓4)
    # Hook OpenMemory 的导出方法
    # 用 IDA 打开 libart.so ,查看 OpenMemory 的到处方法名
    # OpenMemory 的第一个参数是 dex 文件在内存中的其实位置
    # 根据 dex 文件格式,从其实位置开始第32个字节是该 dex 文件的大小
    # 知道 dex 起始位置和整个文件大小,只需要把这段内存 dump 出来即可
    # 使用于 安卓6 7 8 9
    
    src = """
    var openMemory_address = Module.findExportByName("libart.so", "_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_")
    
    Interceptor.attach(openMemory_address, {
        onEnter: function(args){
        
            // dex 文件的起始位置
            var dex_begin_address = args[1]
            
            //dex 文件的前 8 个字节是 magic 字段
            // 打印 magic (会显示“dex 035”)三个字符,可以验证是否为 dex 文件
            console.log("magic:" + Memory.readUtf8String(dex_begin_address))
            
            // 把地址转换成整形,再加32
            //因为 dex 文件的第32个字节处存放的是 dex 文件的大小
            var address = parseInt(dex_begin_address, 16) + 0x20
            
            // 把 address 地址指向的内存值读出来,该值就是 dex 的文件大小
            // ptr(address)转换的原因是 frida 只接受 NativePointer 类型指针
            var dex_size = Memory.readInt(ptr(address))
            console.log("dex_size:" + dex_size)
            
            //frida 写入文件,把内存中的数据写到本地
            var timestamp = new Date().getTime();
            var file = new File("/data/data/%s/" + timestamp + ".dex", "wb")
            
            // Memory.readByteArray(begin, length)
            // 把内存里的数据读出来,从 begin 开始读,取 length 长度
            file.write(Memory.readByteArray(dex_begin_address, dex_size))
            file.flush()
            file.close()
            
            send("dex begin address: "+parseInt(dex_begin_address,16))
            send("dex file size:" +dex_size)
        },
        onLeave: function (retval) {
            if (retval.toInt32() > 0){
            }
        } 
    });
    """%(package)
    
    print(f"dex 导出目录为: /data/data/{package}")
    device = frida.get_remote_device()
    pid = device.spawn(package)
    session = device.attach(pid)
    script  =session.create_script(src)
    script.on("message", on_message)
    script.load()
    device.resume(pid)
    sys.stdin.read()
    

    输出:

    D:Pythonpython.exe E:/wx_h5/frida_dev.py
    dex 导出目录为: /data/data/com.iCitySuzhou.suzhou001
    magic:dex
    035
    dex_size:5993048
    [*] dex begin address: 3760596376
    [*] dex file size:5993048
    magic:dex
    035
    dex_size:292
    [*] dex begin address: 4111687680
    [*] dex file size:292
    magic:dex
    035
    dex_size:292
    [*] dex begin address: 4098458380
    [*] dex file size:292
    magic:dex
    035
    dex_size:5542488
    [*] dex begin address: 3761046936
    [*] dex file size:5542488
    magic:dex
    035
    dex_size:143416
    [*] dex begin address: 3729728852
    [*] dex file size:143416
    magic:dex
    035
    dex_size:5432740
    [*] dex begin address: 3697659272
    [*] dex file size:5432740
    magic:dex
    035
    dex_size:74656
    [*] dex begin address: 3723183372
    [*] dex file size:74656
    magic:dex
    035
    dex_size:358828
    [*] dex begin address: 3536693200
    [*] dex file size:358828
    magic:dex
    035
    dex_size:358828
    [*] dex begin address: 3536693200
    [*] dex file size:358828
    
    

    到手机上看,脱壳成功

    然后使用 adb 命令 pull 到本地,用 jadx 打开

    需要将手机里的目录加上权限

    chmod -R 777 目标文件夹
    
  • 相关阅读:
    WEB新手之sql注入
    WEB新手之do u know caidao?
    C#发送邮件三种方法,Localhost,SMTP,SSL-SMTP
    利用SMTP发送Mail详解
    DevExpress GridControl List绑定方式下新增行的方法
    技术收藏书签
    Oracle CONNECT BY 用法
    在 Oracle Database 11g 第 2 版中查询层次结构数据的快速入门
    Jquery选择器(转载)
    MVC 验证
  • 原文地址:https://www.cnblogs.com/kai-/p/13662201.html
Copyright © 2020-2023  润新知