wsy1qaz2wsx

导航

读取dex文件中的代码数据

java代码先javac转成class文件,然后用d8处理即可获得dex文件.
D8:Android 的 DEX 编译器 / desugar 工具,负责把 Java/Kotlin 编译出来的 .class(以及 Java 8+ 语言特性)转换成 .dex.
R8:Android 的 代码优化 + 压缩 + 混淆 + DEX 编译工具。它可以做 D8 做的编译工作,同时还会进行更激进的优化、shrinking、obfuscation.

若调用d8报错:

是因为d8和jdk/jre版本不匹配.

dex结构可以理解为:
header + index + data,header中包含了dex的基本信息和dex中各种类结构的偏移地址,index中存储了各类数据的地址或查询某类数据的索引(就是查第几个),data就是实际的数据区.数据读取过程可以简单地总结为:在header中找到所在结构的偏移地址,根据需要读取的数据类型获取对应的索引,然后在对应的index中找到索引对应的数据,获取偏移地址,读取最终的实际数据.
dex具体结构可学习:https://bbs.kanxue.com/thread-284995.htm#msg_header_h1_3

实现的dex读取器
import textwrap
import struct
path = "./classes.dex"

with open(path,"rb") as dex:
    dex_file = dex.read()

def read_uleb128(data, offset):
    result = shift = 0
    while True:
        byte = data[offset]
        offset += 1
        result |= (byte & 0x7f) << shift
        if (byte & 0x80) == 0:
            break
        shift += 7
    return result, offset

def getStrByIndex(dex, index):
    stringid_length = 4
    stringId_offset = struct.unpack_from("<I", dex, 60)[0]
    offset = index*stringid_length+stringId_offset
    dexString_offset = struct.unpack_from("<I", dex, offset)[0]
    length, start_offset = read_uleb128(dex, dexString_offset)
    string = dex[start_offset: start_offset+length].decode("utf-8")
    return string
 
def ResolveMethodId(dex):
    methodId_size = struct.unpack_from("<I", dex, 88)[0]
    methodId_offset = struct.unpack_from("<I", dex, 92)[0]
    methodId_length = 8
    for i in range(0,methodId_size):
        start_offset = methodId_offset+methodId_length*i
        nameindex = struct.unpack_from("<I", dex, start_offset+4)[0]
        name = getStrByIndex(dex, nameindex)
        print(name)

def getClassData(dex):
    classDef_num = struct.unpack_from("<I", dex, 96)[0]
    classDef_offset = struct.unpack_from("<I", dex, 100)[0]
    classDef_size = 32
    for i in range(0,classDef_num):
        start_offset = classDef_offset + i * classDef_size
        data_offset = struct.unpack_from("<I", dex, start_offset+24)[0]

        staticField_num,length1= read_uleb128(dex, data_offset)
        instanceField_num,length2 = read_uleb128(dex, length1)
        directMethod_num,length3 = read_uleb128(dex, length2)
        virtualMethod_num,length4 = read_uleb128(dex, length3)

        staticField_offset = length4
        for j in range(0,staticField_num):
            _,length1 = read_uleb128(dex, staticField_offset)
            _,length2 = read_uleb128(dex, length1)
            staticField_offset = length2

        instanceField_offset = staticField_offset
        for k in range(0,instanceField_num):
            _,length1 = read_uleb128(dex, instanceField_offset)
            _,length2 = read_uleb128(dex, length1)
            instanceField_offset = length2

        directMethod_offset = instanceField_offset

        for i in range(0, directMethod_num):
             t1,length1 = read_uleb128(dex,directMethod_offset)
             t2,length2 = read_uleb128(dex,length1)
             code_offset,length3 = read_uleb128(dex,length2)
             
             insns_size = struct.unpack_from("<I", dex, code_offset+12)[0]
             code = dex[code_offset+16: code_offset+16+insns_size*2]
             print(code)
             directMethod_offset = length3          
        virtualMethod_offset = directMethod_offset 

        for i in range(0, virtualMethod_num):   
             t1,length1 = read_uleb128(dex,virtualMethod_offset)
             t2,length2 = read_uleb128(dex,length1)
             code_offset,length3 = read_uleb128(dex,length2)
             
             insns_size = struct.unpack_from("<I", dex, code_offset+12)[0]
             code = dex[code_offset+16: code_offset+16+insns_size*2]
             print(code)
             virtualMethod_offset = length3 


getClassData(dex_file)


注意,从code_item.insns读取到的代码数据是opcode(操作码)的二进制数据,不是直接的smali代码.
opcode以16byte为一个code unit且小端序存储,其中低八位是操作码,其余位则为寄存器编号 / 常量 / 偏移量等操作数.
把opcode转为smali,需要依照instruction format(指令格式):
首先,取一个code unit,查看其低八位,确定其对应的指令.
然后按照instruction format(这个是有规范定义的),确定接下来需要分析多少数据量,如何分析这些数据.

posted on 2026-08-25 16:15  wsyyyyyyy  阅读(4)  评论(0)    收藏  举报