from filetypes.base import *
import malcat
import datetime
import struct

#https://source.android.com/docs/core/runtime/dex-format


class DexHeader(Struct):

    def parse(self):
        yield String(8, zero_terminated=True, name="Magic")
        yield self.parser.uint32(name="Crc32", comment="adler32 checksum of the rest of the file (everything but magic and this field)")
        yield Bytes(20, name="Signature", comment="SHA-1 signature (hash) of the rest of the file (everything but magic, checksum, and this field)")
        yield self.parser.uint32(name="FileSize")
        hdrsz = yield self.parser.uint32(name="HeaderSize")
        yield self.parser.uint32(name="EndianTag", comment="magic value to tell if the file uses big or little endian")
        yield self.parser.uint32(name="LinkSize", comment="size of the link section, or 0 if this file isn't statically linked")
        yield self.parser.offset(name="LinkOffset", zero_is_invalid=True, comment="link section offset")
        yield self.parser.offset(name="MapOffset", zero_is_invalid=True, comment="offset from the start of the file to the map item.")
        yield self.parser.uint32(name="StringsCount", comment="count of strings in the string identifiers list")
        yield self.parser.offset(name="StringsOffset", zero_is_invalid=True, comment="offset from the start of the file to the string identifiers list,")
        yield self.parser.uint32(name="TypesCount", comment="count of elements in the type identifiers list, at most 65535")
        yield self.parser.offset(name="TypesOffset", zero_is_invalid=True, comment="offset from the start of the file to the type identifiers list")
        yield self.parser.uint32(name="ProtoCount", comment="count of elements in the prototype identifiers list, at most 65535")
        yield self.parser.offset(name="ProtoOffset", zero_is_invalid=True, comment="offset from the start of the file to the prototype identifiers list")
        yield self.parser.uint32(name="FieldsCount", comment="count of elements in the field  identifiers list, at most 65535")
        yield self.parser.offset(name="FieldsOffset", zero_is_invalid=True, comment="offset from the start of the file to the field identifiers list")
        yield self.parser.uint32(name="MethodsCount", comment="count of elements in the method  identifiers list, at most 65535")
        yield self.parser.offset(name="MethodsOffset", zero_is_invalid=True, comment="offset from the start of the file to the method identifiers list")
        yield self.parser.uint32(name="ClassesCount", comment="count of elements in the class identifiers list, at most 65535")
        yield self.parser.offset(name="ClassesOffset", zero_is_invalid=True, comment="offset from the start of the file to the class identifiers list")
        yield self.parser.uint32(name="DataSize", comment="size of data section in bytes")
        yield self.parser.offset(name="DataOffset", zero_is_invalid=True, comment="offset of data section")
        if hdrsz > 0x70:
            yield self.parser.uint32(name="ContainerSize", comment="size of the entire file (including other dex headers and their data)")
            yield self.parser.uint32(name="HeaderOffset", comment="offset from the start of the file to the start of this header")







class DexAnalyzer(FileTypeAnalyzer):
    category = malcat.FileType.PROGRAM
    name = "DEX"
    regexp = r"\x64\x65\x78\x0A\x30..\x00.{24}...\x00[\x70\x78]\x00\x00\x00(?:\x12\x34\x56\x78|\x78\x56\x34\x12)"


    def __init__(self):
        FileTypeAnalyzer.__init__(self)
        self.regions = []
        self.lsb = False


    def parse(self, hint=""):
        self.lsb = self.read(0x28, 4) == b"\x78\x56\x34\x12"
        if self.lsb:
            self.uint16 = UInt16
            self.uint24 = UInt24
            self.uint32 = UInt32
            self.int32 = Int32
            self.uint64 = UInt64
            self.int64 = Int64
            self.offset32 = Offset32
            self.timestamp = Timestamp
            self.offset = Offset32
            self.va = Va32
            self.fmtptr = "<I"
            self.fmtendian = "<"
        else:
            self.uint16 = UInt16BE
            self.uint24 = UInt24BE
            self.uint32 = UInt32BE
            self.int32 = Int32BE
            self.uint64 = UInt64BE
            self.int64 = Int64BE
            self.offset32 = Offset32BE
            self.timestamp = TimestampBE
            self.offset = Offset32BE
            self.va = Va32BE
            self.fmtptr = ">I"
            self.fmtendian = ">"

        hdr = yield DexHeader()
        self.set_eof(min(self.size(), hdr["FileSize"]))

        if hdr["DataSize"]:
            self.add_section("DATA", hdr["DataOffset"], hdr["DataSize"], r=True)

        self.confirm()
