Skip to content

dex

AnnotationElement #

This class can parse an annotation_element of a dex file

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a buff object of the annotation_element

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
class AnnotationElement:
    """
    This class can parse an `annotation_element` of a dex file

    :param buff: a string which represents a buff object of the `annotation_element`
    :param cm: a `ClassManager` object
    """

    def __init__(self, buff: BinaryIO, cm: ClassManager) -> None:
        self.CM = cm
        self.offset = buff.tell()

        self.name_idx = readuleb128(cm, buff)
        self.value = EncodedValue(buff, cm)

    def get_name_idx(self) -> int:
        """
        Return the index to the element name, represented as an index into the `string_ids` section

        :returns: the index to the name
        """
        return self.name_idx

    def get_value(self) -> EncodedValue:
        """
        Return the element value ([EncodedValue][androguard.core.dex.EncodedValue])

        :returns: a :`EncodedValue` object
        """
        return self.value

    def show(self):
        bytecode._PrintSubBanner("Annotation Element")
        bytecode._PrintDefault("name_idx=%d\n" % self.name_idx)
        self.value.show()

    def get_obj(self):
        return writeuleb128(self.CM, self.name_idx)

    def get_raw(self):
        return self.get_obj() + self.value.get_raw()

    def get_length(self):
        return len(self.get_obj()) + self.value.get_length()

get_name_idx() #

Return the index to the element name, represented as an index into the string_ids section

Returns:

Type Description
int

the index to the name

Source code in androguard/core/dex/__init__.py
def get_name_idx(self) -> int:
    """
    Return the index to the element name, represented as an index into the `string_ids` section

    :returns: the index to the name
    """
    return self.name_idx

get_value() #

Return the element value (EncodedValue)

Returns:

Type Description
EncodedValue

a :EncodedValue object

Source code in androguard/core/dex/__init__.py
def get_value(self) -> EncodedValue:
    """
    Return the element value ([EncodedValue][androguard.core.dex.EncodedValue])

    :returns: a :`EncodedValue` object
    """
    return self.value

AnnotationItem #

This class can parse an annotation_item of a dex file

Source code in androguard/core/dex/__init__.py
class AnnotationItem:
    """
    This class can parse an `annotation_item` of a dex file
    """

    def __init__(self, buff: BinaryIO, cm:ClassManager) -> None:
        """
        :param buff: a string which represents a Buff object of the `annotation_item`
        :param cm: a `ClassManager` object 
        """
        self.CM = cm

        self.offset = buff.tell()

        self.visibility = get_byte(cm, buff)
        self.annotation = EncodedAnnotation(buff, cm)

    def get_visibility(self) -> int:
        """
        Return the intended visibility of this annotation

        :returns: the visibility of the annotation
        """
        return self.visibility

    def get_annotation(self) -> EncodedAnnotation:
        """
        Return the encoded annotation contents

        :returns: a `EncodedAnnotation` object
        """
        return self.annotation

    def set_off(self, off: int) -> None:
        self.offset = off

    def get_off(self) -> int:
        return self.offset

    def show(self) -> None:
        bytecode._PrintSubBanner("Annotation Item")
        bytecode._PrintDefault("visibility=%d\n" % self.visibility)
        self.annotation.show()

    def get_obj(self) -> list[EncodedAnnotation]:
        return [self.annotation]

    def get_raw(self) -> bytes:
        return (
            self.CM.packer["B"].pack(self.visibility)
            + self.annotation.get_raw()
        )

    def get_length(self) -> int:
        return len(self.get_raw())

__init__(buff, cm) #

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the annotation_item

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
def __init__(self, buff: BinaryIO, cm:ClassManager) -> None:
    """
    :param buff: a string which represents a Buff object of the `annotation_item`
    :param cm: a `ClassManager` object 
    """
    self.CM = cm

    self.offset = buff.tell()

    self.visibility = get_byte(cm, buff)
    self.annotation = EncodedAnnotation(buff, cm)

get_annotation() #

Return the encoded annotation contents

Returns:

Type Description
EncodedAnnotation

a EncodedAnnotation object

Source code in androguard/core/dex/__init__.py
def get_annotation(self) -> EncodedAnnotation:
    """
    Return the encoded annotation contents

    :returns: a `EncodedAnnotation` object
    """
    return self.annotation

get_visibility() #

Return the intended visibility of this annotation

Returns:

Type Description
int

the visibility of the annotation

Source code in androguard/core/dex/__init__.py
def get_visibility(self) -> int:
    """
    Return the intended visibility of this annotation

    :returns: the visibility of the annotation
    """
    return self.visibility

AnnotationOffItem #

This class can parse an annotation_off_item of a dex file

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the annotation_off_item

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
class AnnotationOffItem:
    """
    This class can parse an `annotation_off_item` of a dex file

    :param buff: a string which represents a Buff object of the `annotation_off_item`
    :param cm: a `ClassManager` object
    """

    def __init__(self, buff: BinaryIO, cm: ClassManager) -> None:
        self.CM = cm
        (self.annotation_off,) = cm.packer["I"].unpack(buff.read(4))

    def get_annotation_off(self) -> int:
        return self.annotation_off

    def show(self):
        bytecode._PrintSubBanner("Annotation Off Item")
        bytecode._PrintDefault("annotation_off=0x%x\n" % self.annotation_off)

    def get_obj(self) -> bytes:
        if self.annotation_off != 0:
            self.annotation_off = self.CM.get_obj_by_offset(
                self.annotation_off
            ).get_off()

        return self.CM.packer["I"].pack(self.annotation_off)

    def get_raw(self) -> bytes:
        return self.get_obj()

    def get_length(self) -> int:
        return len(self.get_obj())

    def get_annotation_item(self) -> AnnotationItem:
        return self.CM.get_annotation_item(self.get_annotation_off())

AnnotationSetItem #

This class can parse an annotation_set_item of a dex file

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a buff object of the annotation_set_item

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
class AnnotationSetItem:
    """
    This class can parse an `annotation_set_item` of a dex file

    :param buff: a string which represents a buff object of the `annotation_set_item`
    :param cm: a `ClassManager` object
    """

    def __init__(self, buff: BinaryIO, cm: ClassManager) -> None:
        self.CM = cm
        self.offset = buff.tell()

        (self.size,) = cm.packer["I"].unpack(buff.read(4))
        self.annotation_off_item = [
            AnnotationOffItem(buff, cm) for _ in range(self.size)
        ]

    def get_annotation_off_item(self) -> list[AnnotationOffItem]:
        """
        Return the offset from the start of the file to an annotation

        :returns: a list of `AnnotationOffItem`
        """
        return self.annotation_off_item

    def set_off(self, off: int) -> None:
        self.offset = off

    def get_off(self) -> int:
        return self.offset

    def show(self) -> None:
        bytecode._PrintSubBanner("Annotation Set Item")
        for i in self.annotation_off_item:
            i.show()

    def get_obj(self) -> bytes:
        return self.CM.packer["I"].pack(self.size)

    def get_raw(self) -> bytes:
        return self.get_obj() + b''.join(
            i.get_raw() for i in self.annotation_off_item
        )

    def get_length(self) -> int:
        length = len(self.get_obj())

        for i in self.annotation_off_item:
            length += i.get_length()

        return length

get_annotation_off_item() #

Return the offset from the start of the file to an annotation

Returns:

Type Description
list[AnnotationOffItem]

a list of AnnotationOffItem

Source code in androguard/core/dex/__init__.py
def get_annotation_off_item(self) -> list[AnnotationOffItem]:
    """
    Return the offset from the start of the file to an annotation

    :returns: a list of `AnnotationOffItem`
    """
    return self.annotation_off_item

AnnotationSetRefItem #

This class can parse an annotation_set_ref_item of a dex file

Source code in androguard/core/dex/__init__.py
class AnnotationSetRefItem:
    """
    This class can parse an `annotation_set_ref_item` of a dex file
    """

    def __init__(self, buff: BinaryIO, cm:ClassManager) -> None:
        """
        :param buff: a string which represents a Buff object of the `annotation_set_ref_item`
        :param cm: a `ClassManager` object
        """
        self.CM = cm
        (self.annotations_off,) = cm.packer["I"].unpack(buff.read(4))

    def get_annotations_off(self) -> int:
        """
        Return the offset from the start of the file to the referenced annotation set or
        0 if there are no annotations for this element.

        :returns: the offset
        """
        return self.annotations_off

    def show(self) -> str:
        bytecode._PrintSubBanner("Annotation Set Ref Item")
        bytecode._PrintDefault("annotation_off=0x%x\n" % self.annotations_off)

    def get_obj(self) -> bytes:
        if self.annotations_off != 0:
            self.annotations_off = self.CM.get_obj_by_offset(
                self.annotations_off
            ).get_off()

        return self.CM.packer["I"].pack(self.annotations_off)

    def get_raw(self) -> bytes:
        return self.get_obj()

__init__(buff, cm) #

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the annotation_set_ref_item

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
def __init__(self, buff: BinaryIO, cm:ClassManager) -> None:
    """
    :param buff: a string which represents a Buff object of the `annotation_set_ref_item`
    :param cm: a `ClassManager` object
    """
    self.CM = cm
    (self.annotations_off,) = cm.packer["I"].unpack(buff.read(4))

get_annotations_off() #

Return the offset from the start of the file to the referenced annotation set or 0 if there are no annotations for this element.

Returns:

Type Description
int

the offset

Source code in androguard/core/dex/__init__.py
def get_annotations_off(self) -> int:
    """
    Return the offset from the start of the file to the referenced annotation set or
    0 if there are no annotations for this element.

    :returns: the offset
    """
    return self.annotations_off

AnnotationSetRefList #

This class can parse an annotation_set_ref_list_item of a dex file

Source code in androguard/core/dex/__init__.py
class AnnotationSetRefList:
    """
    This class can parse an `annotation_set_ref_list_item` of a dex file
    """

    def __init__(self, buff: BinaryIO, cm:ClassManager) -> None:
        """
        :param buff: a string which represents a Buff object of the `annotation_set_ref_list_item`
        :param cm: a ClassManager object
        """
        self.offset = buff.tell()

        self.CM = cm
        (self.size,) = cm.packer["I"].unpack(buff.read(4))

        self.list = [AnnotationSetRefItem(buff, cm) for _ in range(self.size)]

    def get_list(self) -> list[AnnotationSetRefItem]:
        """
        Return list of [AnnotationSetRefItem][androguard.core.dex.AnnotationSetRefItem]

        :returns: list of `AnnotationSetRefItem`
        """
        return self.list

    def get_off(self) -> int:
        return self.offset

    def set_off(self, off: int) -> None:
        self.offset = off

    def show(self) -> None:
        bytecode._PrintSubBanner("Annotation Set Ref List Item")
        for i in self.list:
            i.show()

    def get_obj(self) -> list[AnnotationSetRefItem]:
        return [i for i in self.list]

    def get_raw(self) -> bytes:
        return self.CM.packer["I"].pack(self.size) + b''.join(
            i.get_raw() for i in self.list
        )

    def get_length(self) -> int:
        return len(self.get_raw())

__init__(buff, cm) #

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the annotation_set_ref_list_item

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
def __init__(self, buff: BinaryIO, cm:ClassManager) -> None:
    """
    :param buff: a string which represents a Buff object of the `annotation_set_ref_list_item`
    :param cm: a ClassManager object
    """
    self.offset = buff.tell()

    self.CM = cm
    (self.size,) = cm.packer["I"].unpack(buff.read(4))

    self.list = [AnnotationSetRefItem(buff, cm) for _ in range(self.size)]

get_list() #

Return list of AnnotationSetRefItem

Returns:

Type Description
list[AnnotationSetRefItem]

list of AnnotationSetRefItem

Source code in androguard/core/dex/__init__.py
def get_list(self) -> list[AnnotationSetRefItem]:
    """
    Return list of [AnnotationSetRefItem][androguard.core.dex.AnnotationSetRefItem]

    :returns: list of `AnnotationSetRefItem`
    """
    return self.list

AnnotationsDirectoryItem #

This class can parse an annotations_directory_item of a dex file

Source code in androguard/core/dex/__init__.py
class AnnotationsDirectoryItem:
    """
    This class can parse an `annotations_directory_item` of a dex file
    """

    def __init__(self, buff: BinaryIO, cm:ClassManager) -> None:
        """
        :param buff: a string which represents a Buff object of the `annotations_directory_item`
        :param cm: a `ClassManager` object
        """
        self.CM = cm

        self.offset = buff.tell()

        (
            self.class_annotations_off,
            self.annotated_fields_size,
            self.annotated_methods_size,
            self.annotated_parameters_size,
        ) = cm.packer["4I"].unpack(buff.read(16))

        self.field_annotations = [
            FieldAnnotation(buff, cm)
            for i in range(0, self.annotated_fields_size)
        ]

        self.method_annotations = [
            MethodAnnotation(buff, cm)
            for i in range(0, self.annotated_methods_size)
        ]

        self.parameter_annotations = [
            ParameterAnnotation(buff, cm)
            for i in range(0, self.annotated_parameters_size)
        ]

    def get_class_annotations_off(self) -> int:
        """
        Return the offset from the start of the file to the annotations made directly on the class,
        or 0 if the class has no direct annotations

        :returns: the offset
        """
        return self.class_annotations_off

    def get_annotation_set_item(self) -> list[AnnotationSetItem]:
        return self.CM.get_annotation_set_item(self.class_annotations_off)

    def get_annotated_fields_size(self) -> int:
        """
        Return the count of fields annotated by this item

        :returns: the offset
        """
        return self.annotated_fields_size

    def get_annotated_methods_size(self) -> int:
        """
        Return the count of methods annotated by this item

        :returns: the count of methods
        """
        return self.annotated_methods_size

    def get_annotated_parameters_size(self) -> int:
        """
        Return the count of method parameter lists annotated by this item

        :returns: the count of method parameter lists
        """
        return self.annotated_parameters_size

    def get_field_annotations(self) -> list[FieldAnnotation]:
        """
        Return the list of associated [FieldAnnotation][androguard.core.dex.FieldAnnotation]

        :returns: a list of `FieldAnnotation`
        """
        return self.field_annotations

    def get_method_annotations(self) -> list[MethodAnnotation]:
        """
        Return the list of associated [MethodAnnotation][androguard.core.dex.MethodAnnotation]

        :returns: a list of `MethodAnnotation`
        """
        return self.method_annotations

    def get_parameter_annotations(self) -> list[ParameterAnnotation]:
        """
        Return the list of associated method [ParameterAnnotation][androguard.core.dex.ParameterAnnotation]

        :returns: a list of `ParameterAnnotation`
        """
        return self.parameter_annotations

    def set_off(self, off: int) -> None:
        self.offset = off

    def get_off(self) -> int:
        return self.offset

    def show(self) -> None:
        bytecode._PrintSubBanner("Annotations Directory Item")
        bytecode._PrintDefault(
            "class_annotations_off=0x%x annotated_fields_size=%d annotated_methods_size=%d annotated_parameters_size=%d\n"
            % (
                self.class_annotations_off,
                self.annotated_fields_size,
                self.annotated_methods_size,
                self.annotated_parameters_size,
            )
        )

        for i in self.field_annotations:
            i.show()

        for i in self.method_annotations:
            i.show()

        for i in self.parameter_annotations:
            i.show()

    def get_obj(self) -> bytes:
        if self.class_annotations_off != 0:
            self.class_annotations_off = self.CM.get_obj_by_offset(
                self.class_annotations_off
            ).get_off()

        return self.CM.packer["4I"].pack(
            self.class_annotations_off,
            self.annotated_fields_size,
            self.annotated_methods_size,
            self.annotated_parameters_size,
        )

    def get_raw(self) -> bytes:
        return (
            self.get_obj()
            + b''.join(i.get_raw() for i in self.field_annotations)
            + b''.join(i.get_raw() for i in self.method_annotations)
            + b''.join(i.get_raw() for i in self.parameter_annotations)
        )

    def get_length(self) -> int:
        length = len(self.get_obj())
        for i in self.field_annotations:
            length += i.get_length()

        for i in self.method_annotations:
            length += i.get_length()

        for i in self.parameter_annotations:
            length += i.get_length()

        return length

__init__(buff, cm) #

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the annotations_directory_item

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
def __init__(self, buff: BinaryIO, cm:ClassManager) -> None:
    """
    :param buff: a string which represents a Buff object of the `annotations_directory_item`
    :param cm: a `ClassManager` object
    """
    self.CM = cm

    self.offset = buff.tell()

    (
        self.class_annotations_off,
        self.annotated_fields_size,
        self.annotated_methods_size,
        self.annotated_parameters_size,
    ) = cm.packer["4I"].unpack(buff.read(16))

    self.field_annotations = [
        FieldAnnotation(buff, cm)
        for i in range(0, self.annotated_fields_size)
    ]

    self.method_annotations = [
        MethodAnnotation(buff, cm)
        for i in range(0, self.annotated_methods_size)
    ]

    self.parameter_annotations = [
        ParameterAnnotation(buff, cm)
        for i in range(0, self.annotated_parameters_size)
    ]

get_annotated_fields_size() #

Return the count of fields annotated by this item

Returns:

Type Description
int

the offset

Source code in androguard/core/dex/__init__.py
def get_annotated_fields_size(self) -> int:
    """
    Return the count of fields annotated by this item

    :returns: the offset
    """
    return self.annotated_fields_size

get_annotated_methods_size() #

Return the count of methods annotated by this item

Returns:

Type Description
int

the count of methods

Source code in androguard/core/dex/__init__.py
def get_annotated_methods_size(self) -> int:
    """
    Return the count of methods annotated by this item

    :returns: the count of methods
    """
    return self.annotated_methods_size

get_annotated_parameters_size() #

Return the count of method parameter lists annotated by this item

Returns:

Type Description
int

the count of method parameter lists

Source code in androguard/core/dex/__init__.py
def get_annotated_parameters_size(self) -> int:
    """
    Return the count of method parameter lists annotated by this item

    :returns: the count of method parameter lists
    """
    return self.annotated_parameters_size

get_class_annotations_off() #

Return the offset from the start of the file to the annotations made directly on the class, or 0 if the class has no direct annotations

Returns:

Type Description
int

the offset

Source code in androguard/core/dex/__init__.py
def get_class_annotations_off(self) -> int:
    """
    Return the offset from the start of the file to the annotations made directly on the class,
    or 0 if the class has no direct annotations

    :returns: the offset
    """
    return self.class_annotations_off

get_field_annotations() #

Return the list of associated FieldAnnotation

Returns:

Type Description
list[FieldAnnotation]

a list of FieldAnnotation

Source code in androguard/core/dex/__init__.py
def get_field_annotations(self) -> list[FieldAnnotation]:
    """
    Return the list of associated [FieldAnnotation][androguard.core.dex.FieldAnnotation]

    :returns: a list of `FieldAnnotation`
    """
    return self.field_annotations

get_method_annotations() #

Return the list of associated MethodAnnotation

Returns:

Type Description
list[MethodAnnotation]

a list of MethodAnnotation

Source code in androguard/core/dex/__init__.py
def get_method_annotations(self) -> list[MethodAnnotation]:
    """
    Return the list of associated [MethodAnnotation][androguard.core.dex.MethodAnnotation]

    :returns: a list of `MethodAnnotation`
    """
    return self.method_annotations

get_parameter_annotations() #

Return the list of associated method ParameterAnnotation

Returns:

Type Description
list[ParameterAnnotation]

a list of ParameterAnnotation

Source code in androguard/core/dex/__init__.py
def get_parameter_annotations(self) -> list[ParameterAnnotation]:
    """
    Return the list of associated method [ParameterAnnotation][androguard.core.dex.ParameterAnnotation]

    :returns: a list of `ParameterAnnotation`
    """
    return self.parameter_annotations

ClassDataItem #

This class can parse a class_data_item of a dex file

Source code in androguard/core/dex/__init__.py
class ClassDataItem:
    """
    This class can parse a `class_data_item` of a dex file
    """

    def __init__(self, buff: BinaryIO, cm:ClassManager) -> None:
        """
        :param buff: a string which represents a Buff object of the `class_data_item`
        :param cm: a `ClassManager` object
        """
        self.CM = cm

        self.offset = buff.tell()

        self.static_fields_size = readuleb128(cm, buff)
        self.instance_fields_size = readuleb128(cm, buff)
        self.direct_methods_size = readuleb128(cm, buff)
        self.virtual_methods_size = readuleb128(cm, buff)

        self.static_fields = []
        self.instance_fields = []
        self.direct_methods = []
        self.virtual_methods = []

        self._load_elements(
            self.static_fields_size, self.static_fields, EncodedField, buff, cm
        )
        self._load_elements(
            self.instance_fields_size,
            self.instance_fields,
            EncodedField,
            buff,
            cm,
        )
        self._load_elements(
            self.direct_methods_size,
            self.direct_methods,
            EncodedMethod,
            buff,
            cm,
        )
        self._load_elements(
            self.virtual_methods_size,
            self.virtual_methods,
            EncodedMethod,
            buff,
            cm,
        )

    def get_static_fields_size(self) -> int:
        """
        Return the number of static fields defined in this item

        :returns: number of static fields
        """
        return self.static_fields_size

    def get_instance_fields_size(self) -> int:
        """
        Return the number of instance fields defined in this item

        :returns: number of instance fields
        """
        return self.instance_fields_size

    def get_direct_methods_size(self) -> int:
        """
        Return the number of direct methods defined in this item

        :returns: number of direct methods
        """
        return self.direct_methods_size

    def get_virtual_methods_size(self) -> int:
        """
        Return the number of virtual methods defined in this item

        :returns: number of virtual methods
        """
        return self.virtual_methods_size

    def get_static_fields(self) -> list[EncodedField]:
        """
        Return the defined static fields, represented as a sequence of encoded elements

        :returns: a list of `EncodedField` objects
        """
        return self.static_fields

    def get_instance_fields(self) -> list[EncodedField]:
        """
        Return the defined instance fields, represented as a sequence of encoded elements

        :returns: list of `EncodedField` objects
        """
        return self.instance_fields

    def get_direct_methods(self) -> list[EncodedMethod]:
        """
        Return the defined direct (any of static, private, or constructor) methods, represented as a sequence of encoded elements

        :returns: a list of `EncodedMethod` objects
        """
        return self.direct_methods

    def get_virtual_methods(self) -> list[EncodedMethod]:
        """
        Return the defined virtual (none of static, private, or constructor) methods, represented as a sequence of encoded elements

        :returns: a list `EncodedMethod` objects

        """

        return self.virtual_methods

    def get_methods(self) -> list[EncodedMethod]:
        """
        Return direct and virtual methods

        :returns: a list of `EncodedMethod` objects
        """
        return [x for x in self.direct_methods] + [
            x for x in self.virtual_methods
        ]

    def get_fields(self) -> list[EncodedField]:
        """
        Return static and instance fields

        :returns: a list of `EncodedField` objects
        """
        return [x for x in self.static_fields] + [
            x for x in self.instance_fields
        ]

    def set_off(self, off: int):
        self.offset = off

    def set_static_fields(self, value):
        if value is not None:
            values = value.get_values()
            if len(values) <= len(self.static_fields):
                for i in range(0, len(values)):
                    self.static_fields[i].set_init_value(values[i])

    def _load_elements(self, size, l, Type, buff, cm):
        prev = 0
        for i in range(0, size):
            el = Type(buff, cm)
            el.adjust_idx(prev)

            if isinstance(el, EncodedField):
                prev = el.get_field_idx()
            else:
                prev = el.get_method_idx()

            l.append(el)

    def show(self):
        bytecode._PrintSubBanner("Class Data Item")
        bytecode._PrintDefault(
            "static_fields_size=%d instance_fields_size=%d direct_methods_size=%d virtual_methods_size=%d\n"
            % (
                self.static_fields_size,
                self.instance_fields_size,
                self.direct_methods_size,
                self.virtual_methods_size,
            )
        )

        bytecode._PrintSubBanner("Static Fields")
        for i in self.static_fields:
            i.show()

        bytecode._PrintSubBanner("Instance Fields")
        for i in self.instance_fields:
            i.show()

        bytecode._PrintSubBanner("Direct Methods")
        for i in self.direct_methods:
            i.show()

        bytecode._PrintSubBanner("Virtual Methods")
        for i in self.virtual_methods:
            i.show()

    def get_obj(self):
        return (
            [i for i in self.static_fields]
            + [i for i in self.instance_fields]
            + [i for i in self.direct_methods]
            + [i for i in self.virtual_methods]
        )

    def get_raw(self):
        buff = (
            writeuleb128(self.CM, self.static_fields_size)
            + writeuleb128(self.CM, self.instance_fields_size)
            + writeuleb128(self.CM, self.direct_methods_size)
            + writeuleb128(self.CM, self.virtual_methods_size)
            + b''.join(i.get_raw() for i in self.static_fields)
            + b''.join(i.get_raw() for i in self.instance_fields)
            + b''.join(i.get_raw() for i in self.direct_methods)
            + b''.join(i.get_raw() for i in self.virtual_methods)
        )

        return buff

    def get_length(self):
        length = (
            len(writeuleb128(self.CM, self.static_fields_size))
            + len(writeuleb128(self.CM, self.instance_fields_size))
            + len(writeuleb128(self.CM, self.direct_methods_size))
            + len(writeuleb128(self.CM, self.virtual_methods_size))
        )

        for i in self.static_fields:
            length += i.get_size()

        for i in self.instance_fields:
            length += i.get_size()

        for i in self.direct_methods:
            length += i.get_size()

        for i in self.virtual_methods:
            length += i.get_size()

        return length

    def get_off(self):
        return self.offset

__init__(buff, cm) #

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the class_data_item

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
def __init__(self, buff: BinaryIO, cm:ClassManager) -> None:
    """
    :param buff: a string which represents a Buff object of the `class_data_item`
    :param cm: a `ClassManager` object
    """
    self.CM = cm

    self.offset = buff.tell()

    self.static_fields_size = readuleb128(cm, buff)
    self.instance_fields_size = readuleb128(cm, buff)
    self.direct_methods_size = readuleb128(cm, buff)
    self.virtual_methods_size = readuleb128(cm, buff)

    self.static_fields = []
    self.instance_fields = []
    self.direct_methods = []
    self.virtual_methods = []

    self._load_elements(
        self.static_fields_size, self.static_fields, EncodedField, buff, cm
    )
    self._load_elements(
        self.instance_fields_size,
        self.instance_fields,
        EncodedField,
        buff,
        cm,
    )
    self._load_elements(
        self.direct_methods_size,
        self.direct_methods,
        EncodedMethod,
        buff,
        cm,
    )
    self._load_elements(
        self.virtual_methods_size,
        self.virtual_methods,
        EncodedMethod,
        buff,
        cm,
    )

get_direct_methods() #

Return the defined direct (any of static, private, or constructor) methods, represented as a sequence of encoded elements

Returns:

Type Description
list[EncodedMethod]

a list of EncodedMethod objects

Source code in androguard/core/dex/__init__.py
def get_direct_methods(self) -> list[EncodedMethod]:
    """
    Return the defined direct (any of static, private, or constructor) methods, represented as a sequence of encoded elements

    :returns: a list of `EncodedMethod` objects
    """
    return self.direct_methods

get_direct_methods_size() #

Return the number of direct methods defined in this item

Returns:

Type Description
int

number of direct methods

Source code in androguard/core/dex/__init__.py
def get_direct_methods_size(self) -> int:
    """
    Return the number of direct methods defined in this item

    :returns: number of direct methods
    """
    return self.direct_methods_size

get_fields() #

Return static and instance fields

Returns:

Type Description
list[EncodedField]

a list of EncodedField objects

Source code in androguard/core/dex/__init__.py
def get_fields(self) -> list[EncodedField]:
    """
    Return static and instance fields

    :returns: a list of `EncodedField` objects
    """
    return [x for x in self.static_fields] + [
        x for x in self.instance_fields
    ]

get_instance_fields() #

Return the defined instance fields, represented as a sequence of encoded elements

Returns:

Type Description
list[EncodedField]

list of EncodedField objects

Source code in androguard/core/dex/__init__.py
def get_instance_fields(self) -> list[EncodedField]:
    """
    Return the defined instance fields, represented as a sequence of encoded elements

    :returns: list of `EncodedField` objects
    """
    return self.instance_fields

get_instance_fields_size() #

Return the number of instance fields defined in this item

Returns:

Type Description
int

number of instance fields

Source code in androguard/core/dex/__init__.py
def get_instance_fields_size(self) -> int:
    """
    Return the number of instance fields defined in this item

    :returns: number of instance fields
    """
    return self.instance_fields_size

get_methods() #

Return direct and virtual methods

Returns:

Type Description
list[EncodedMethod]

a list of EncodedMethod objects

Source code in androguard/core/dex/__init__.py
def get_methods(self) -> list[EncodedMethod]:
    """
    Return direct and virtual methods

    :returns: a list of `EncodedMethod` objects
    """
    return [x for x in self.direct_methods] + [
        x for x in self.virtual_methods
    ]

get_static_fields() #

Return the defined static fields, represented as a sequence of encoded elements

Returns:

Type Description
list[EncodedField]

a list of EncodedField objects

Source code in androguard/core/dex/__init__.py
def get_static_fields(self) -> list[EncodedField]:
    """
    Return the defined static fields, represented as a sequence of encoded elements

    :returns: a list of `EncodedField` objects
    """
    return self.static_fields

get_static_fields_size() #

Return the number of static fields defined in this item

Returns:

Type Description
int

number of static fields

Source code in androguard/core/dex/__init__.py
def get_static_fields_size(self) -> int:
    """
    Return the number of static fields defined in this item

    :returns: number of static fields
    """
    return self.static_fields_size

get_virtual_methods() #

Return the defined virtual (none of static, private, or constructor) methods, represented as a sequence of encoded elements

Returns:

Type Description
list[EncodedMethod]

a list EncodedMethod objects

Source code in androguard/core/dex/__init__.py
def get_virtual_methods(self) -> list[EncodedMethod]:
    """
    Return the defined virtual (none of static, private, or constructor) methods, represented as a sequence of encoded elements

    :returns: a list `EncodedMethod` objects

    """

    return self.virtual_methods

get_virtual_methods_size() #

Return the number of virtual methods defined in this item

Returns:

Type Description
int

number of virtual methods

Source code in androguard/core/dex/__init__.py
def get_virtual_methods_size(self) -> int:
    """
    Return the number of virtual methods defined in this item

    :returns: number of virtual methods
    """
    return self.virtual_methods_size

ClassDefItem #

This class can parse a class_def_item of a dex file

Source code in androguard/core/dex/__init__.py
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
class ClassDefItem:
    """
    This class can parse a `class_def_item` of a dex file
    """

    def __init__(self, buff: BinaryIO, cm:ClassManager) -> None:
        """
        :param buff: a string which represents a Buff object of the `class_def_item`
        :param cm: a `ClassManager` object
        """
        self.CM = cm
        self.offset = buff.tell()

        (
            self.class_idx,
            self.access_flags,
            self.superclass_idx,
            self.interfaces_off,
            self.source_file_idx,
            self.annotations_off,
            self.class_data_off,
            self.static_values_off,
        ) = cm.packer["8I"].unpack(buff.read(32))

        self.interfaces = []
        self.class_data_item = None
        self.static_values = None
        self.annotations_directory_item = None

        self.name = None
        self.sname = None
        self.access_flags_string = None

        self.reload()

    def reload(self) -> None:
        self.name = self.CM.get_type(self.class_idx)
        self.sname = self.CM.get_type(self.superclass_idx)
        self.interfaces = self.CM.get_type_list(self.interfaces_off)

        if self.class_data_off != 0:
            self.class_data_item = self.CM.get_class_data_item(
                self.class_data_off
            )

        if self.annotations_off != 0:
            self.annotations_directory_item = (
                self.CM.get_annotations_directory_item(self.annotations_off)
            )

        if self.static_values_off != 0:
            self.static_values = self.CM.get_encoded_array_item(
                self.static_values_off
            )

            if self.class_data_item:
                self.class_data_item.set_static_fields(
                    self.static_values.get_value()
                )

    def __str__(self):
        return "{}->{}".format(self.get_superclassname(), self.get_name())

    def __repr__(self):
        return "<dvm.ClassDefItem {}>".format(self.__str__())

    def get_methods(self) -> list[EncodedMethod]:
        """
        Return all [EncodedMethods][androguard.core.dex.EncodedMethod] of this class

        :returns: a list of `EncodedMethod` objects
        """
        if self.class_data_item is not None:
            return self.class_data_item.get_methods()
        return []

    def get_fields(self) -> list[EncodedField]:
        """
        Return all [EncodedFields][androguard.core.dex.EncodedField] of this class

        :returns: a list of `EncodedField` objects
        """
        if self.class_data_item is not None:
            return self.class_data_item.get_fields()
        return []

    def _get_annotation_type_ids(self) -> list[EncodedAnnotation]:
        """
        Get the [EncodedAnnotation][androguard.core.dex.EncodedAnnotation] from this class

        :returns: list of `EncodedAnnotation` objects
        """
        if self.annotations_directory_item is None:
            return []
        annotation_set_item = (
            self.annotations_directory_item.get_annotation_set_item()
        )
        if annotation_set_item is None:
            return []

        annotation_off_item = annotation_set_item.get_annotation_off_item()

        if annotation_off_item is None:
            return []

        return [
            annotation.get_annotation_item().annotation
            for annotation in annotation_off_item
        ]

    def get_annotations(self) -> list[str]:
        """
        Returns the class names of the annotations of this class.

        For example, if the class is marked as `@Deprecated`, this will return
        `['Ljava/lang/Deprecated;']`.

        :returns: list of class names
        """
        return [
            self.CM.get_type(x.get_type_idx())
            for x in self._get_annotation_type_ids()
        ]

    def get_class_idx(self) -> int:
        """
        Return the index into the `type_ids` list for this class

        :returns: the index
        """
        return self.class_idx

    def get_access_flags(self) -> int:
        """
        Return the access flags for the class (`public`, `final`, etc.)

        :returns: the access flags
        """
        return self.access_flags

    def get_superclass_idx(self) -> int:
        """
        Return the index into the `type_ids` list for the superclass

        :returns: the index
        """
        return self.superclass_idx

    def get_interfaces_off(self) -> int:
        """
        Return the offset from the start of the file to the list of interfaces, or 0 if there are none

        :returns: the offset
        """
        return self.interfaces_off

    def get_source_file_idx(self) -> int:
        """
        Return the index into the `string_ids` list for the name of the file containing the original
        source for (at least most of) this class, or the special value `NO_INDEX` to represent a lack of this information

        :returns: the index
        """
        return self.source_file_idx

    def get_annotations_off(self) -> int:
        """
        Return the offset from the start of the file to the annotations structure for this class,
        or 0 if there are no annotations on this class.

        :returns: the offset
        """
        return self.annotations_off

    def get_class_data_off(self) -> int:
        """
        Return the offset from the start of the file to the associated class data for this item,
        or 0 if there is no class data for this class

        :returns: the offset
        """
        return self.class_data_off

    def get_static_values_off(self) -> int:
        """
        Return the offset from the start of the file to the list of initial values for static fields,
        or 0 if there are none (and all static fields are to be initialized with 0 or null)

        :returns: the offset
        """
        return self.static_values_off

    def get_class_data(self) -> ClassDataItem:
        """
        Return the associated class_data_item

        :returns: the associated `ClassDataItem`
        """
        return self.class_data_item

    def get_name(self) -> str:
        """
        Return the name of this class

        :returns: the string name
        """
        return self.name

    def get_superclassname(self) -> str:
        """
        Return the name of the super class

        :returns: the string name
        """
        return self.sname

    def get_interfaces(self) -> list[str]:
        """
        Return the names of the interfaces

        :returns: a list of string names
        """
        return self.interfaces

    def get_access_flags_string(self) -> str:
        """
        Return the access flags string of the class

        :returns: the access flag string
        """
        if self.access_flags_string is None:
            self.access_flags_string = get_access_flags_string(
                self.get_access_flags()
            )

            if self.access_flags_string == "":
                self.access_flags_string = "0x%x" % self.get_access_flags()
        return self.access_flags_string

    def show(self) -> None:
        bytecode._PrintSubBanner("Class Def Item")
        bytecode._PrintDefault(
            "name=%s, sname=%s, interfaces=%s, access_flags=%s\n"
            % (
                self.name,
                self.sname,
                self.interfaces,
                self.get_access_flags_string(),
            )
        )
        bytecode._PrintDefault(
            "class_idx=%d, superclass_idx=%d, interfaces_off=%x, source_file_idx=%d, annotations_off=%x, class_data_off=%x, static_values_off=%x\n"
            % (
                self.class_idx,
                self.superclass_idx,
                self.interfaces_off,
                self.source_file_idx,
                self.annotations_off,
                self.class_data_off,
                self.static_values_off,
            )
        )

        for method in self.get_methods():
            method.show()

    def source(self) -> None:
        """
        Print the source code of the entire class
        """
        self.CM.decompiler_ob.display_all(self)

    def get_source(self) -> str:
        """return the source code of this class

        :returns: the source code string
        """
        return self.CM.decompiler_ob.get_source_class(self)

    def get_source_ext(self) -> list[tuple[str, list]]:
        return self.CM.decompiler_ob.get_source_class_ext(self)

    def get_ast(self):
        return self.CM.decompiler_ob.get_ast_class(self)

    def set_name(self, value):
        self.CM.set_hook_class_name(self, value)

    def get_obj(self):
        if self.interfaces_off != 0:
            self.interfaces_off = self.CM.get_obj_by_offset(
                self.interfaces_off
            ).get_off()

        if self.annotations_off != 0:
            self.annotations_off = self.CM.get_obj_by_offset(
                self.annotations_off
            ).get_off()

        if self.class_data_off != 0:
            self.class_data_off = self.CM.get_obj_by_offset(
                self.class_data_off
            ).get_off()

        if self.static_values_off != 0:
            self.static_values_off = self.CM.get_obj_by_offset(
                self.static_values_off
            ).get_off()

        return self.CM.packer["8I"].pack(
            self.class_idx,
            self.access_flags,
            self.superclass_idx,
            self.interfaces_off,
            self.source_file_idx,
            self.annotations_off,
            self.class_data_off,
            self.static_values_off,
        )

    def get_raw(self):
        return self.get_obj()

    def get_length(self):
        return len(self.get_obj())

__init__(buff, cm) #

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the class_def_item

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
def __init__(self, buff: BinaryIO, cm:ClassManager) -> None:
    """
    :param buff: a string which represents a Buff object of the `class_def_item`
    :param cm: a `ClassManager` object
    """
    self.CM = cm
    self.offset = buff.tell()

    (
        self.class_idx,
        self.access_flags,
        self.superclass_idx,
        self.interfaces_off,
        self.source_file_idx,
        self.annotations_off,
        self.class_data_off,
        self.static_values_off,
    ) = cm.packer["8I"].unpack(buff.read(32))

    self.interfaces = []
    self.class_data_item = None
    self.static_values = None
    self.annotations_directory_item = None

    self.name = None
    self.sname = None
    self.access_flags_string = None

    self.reload()

get_access_flags() #

Return the access flags for the class (public, final, etc.)

Returns:

Type Description
int

the access flags

Source code in androguard/core/dex/__init__.py
def get_access_flags(self) -> int:
    """
    Return the access flags for the class (`public`, `final`, etc.)

    :returns: the access flags
    """
    return self.access_flags

get_access_flags_string() #

Return the access flags string of the class

Returns:

Type Description
str

the access flag string

Source code in androguard/core/dex/__init__.py
def get_access_flags_string(self) -> str:
    """
    Return the access flags string of the class

    :returns: the access flag string
    """
    if self.access_flags_string is None:
        self.access_flags_string = get_access_flags_string(
            self.get_access_flags()
        )

        if self.access_flags_string == "":
            self.access_flags_string = "0x%x" % self.get_access_flags()
    return self.access_flags_string

get_annotations() #

Returns the class names of the annotations of this class.

For example, if the class is marked as @Deprecated, this will return ['Ljava/lang/Deprecated;'].

Returns:

Type Description
list[str]

list of class names

Source code in androguard/core/dex/__init__.py
def get_annotations(self) -> list[str]:
    """
    Returns the class names of the annotations of this class.

    For example, if the class is marked as `@Deprecated`, this will return
    `['Ljava/lang/Deprecated;']`.

    :returns: list of class names
    """
    return [
        self.CM.get_type(x.get_type_idx())
        for x in self._get_annotation_type_ids()
    ]

get_annotations_off() #

Return the offset from the start of the file to the annotations structure for this class, or 0 if there are no annotations on this class.

Returns:

Type Description
int

the offset

Source code in androguard/core/dex/__init__.py
def get_annotations_off(self) -> int:
    """
    Return the offset from the start of the file to the annotations structure for this class,
    or 0 if there are no annotations on this class.

    :returns: the offset
    """
    return self.annotations_off

get_class_data() #

Return the associated class_data_item

Returns:

Type Description
ClassDataItem

the associated ClassDataItem

Source code in androguard/core/dex/__init__.py
def get_class_data(self) -> ClassDataItem:
    """
    Return the associated class_data_item

    :returns: the associated `ClassDataItem`
    """
    return self.class_data_item

get_class_data_off() #

Return the offset from the start of the file to the associated class data for this item, or 0 if there is no class data for this class

Returns:

Type Description
int

the offset

Source code in androguard/core/dex/__init__.py
def get_class_data_off(self) -> int:
    """
    Return the offset from the start of the file to the associated class data for this item,
    or 0 if there is no class data for this class

    :returns: the offset
    """
    return self.class_data_off

get_class_idx() #

Return the index into the type_ids list for this class

Returns:

Type Description
int

the index

Source code in androguard/core/dex/__init__.py
def get_class_idx(self) -> int:
    """
    Return the index into the `type_ids` list for this class

    :returns: the index
    """
    return self.class_idx

get_fields() #

Return all EncodedFields of this class

Returns:

Type Description
list[EncodedField]

a list of EncodedField objects

Source code in androguard/core/dex/__init__.py
def get_fields(self) -> list[EncodedField]:
    """
    Return all [EncodedFields][androguard.core.dex.EncodedField] of this class

    :returns: a list of `EncodedField` objects
    """
    if self.class_data_item is not None:
        return self.class_data_item.get_fields()
    return []

get_interfaces() #

Return the names of the interfaces

Returns:

Type Description
list[str]

a list of string names

Source code in androguard/core/dex/__init__.py
def get_interfaces(self) -> list[str]:
    """
    Return the names of the interfaces

    :returns: a list of string names
    """
    return self.interfaces

get_interfaces_off() #

Return the offset from the start of the file to the list of interfaces, or 0 if there are none

Returns:

Type Description
int

the offset

Source code in androguard/core/dex/__init__.py
def get_interfaces_off(self) -> int:
    """
    Return the offset from the start of the file to the list of interfaces, or 0 if there are none

    :returns: the offset
    """
    return self.interfaces_off

get_methods() #

Return all EncodedMethods of this class

Returns:

Type Description
list[EncodedMethod]

a list of EncodedMethod objects

Source code in androguard/core/dex/__init__.py
def get_methods(self) -> list[EncodedMethod]:
    """
    Return all [EncodedMethods][androguard.core.dex.EncodedMethod] of this class

    :returns: a list of `EncodedMethod` objects
    """
    if self.class_data_item is not None:
        return self.class_data_item.get_methods()
    return []

get_name() #

Return the name of this class

Returns:

Type Description
str

the string name

Source code in androguard/core/dex/__init__.py
def get_name(self) -> str:
    """
    Return the name of this class

    :returns: the string name
    """
    return self.name

get_source() #

return the source code of this class

Returns:

Type Description
str

the source code string

Source code in androguard/core/dex/__init__.py
def get_source(self) -> str:
    """return the source code of this class

    :returns: the source code string
    """
    return self.CM.decompiler_ob.get_source_class(self)

get_source_file_idx() #

Return the index into the string_ids list for the name of the file containing the original source for (at least most of) this class, or the special value NO_INDEX to represent a lack of this information

Returns:

Type Description
int

the index

Source code in androguard/core/dex/__init__.py
def get_source_file_idx(self) -> int:
    """
    Return the index into the `string_ids` list for the name of the file containing the original
    source for (at least most of) this class, or the special value `NO_INDEX` to represent a lack of this information

    :returns: the index
    """
    return self.source_file_idx

get_static_values_off() #

Return the offset from the start of the file to the list of initial values for static fields, or 0 if there are none (and all static fields are to be initialized with 0 or null)

Returns:

Type Description
int

the offset

Source code in androguard/core/dex/__init__.py
def get_static_values_off(self) -> int:
    """
    Return the offset from the start of the file to the list of initial values for static fields,
    or 0 if there are none (and all static fields are to be initialized with 0 or null)

    :returns: the offset
    """
    return self.static_values_off

get_superclass_idx() #

Return the index into the type_ids list for the superclass

Returns:

Type Description
int

the index

Source code in androguard/core/dex/__init__.py
def get_superclass_idx(self) -> int:
    """
    Return the index into the `type_ids` list for the superclass

    :returns: the index
    """
    return self.superclass_idx

get_superclassname() #

Return the name of the super class

Returns:

Type Description
str

the string name

Source code in androguard/core/dex/__init__.py
def get_superclassname(self) -> str:
    """
    Return the name of the super class

    :returns: the string name
    """
    return self.sname

source() #

Print the source code of the entire class

Source code in androguard/core/dex/__init__.py
def source(self) -> None:
    """
    Print the source code of the entire class
    """
    self.CM.decompiler_ob.display_all(self)

ClassHDefItem #

This class can parse a list of class_def_item of a dex file

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the list of class_def_item

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
class ClassHDefItem:
    """
    This class can parse a list of `class_def_item` of a dex file

    :param buff: a string which represents a Buff object of the list of `class_def_item`
    :param cm: a `ClassManager` object
    """

    def __init__(self, size: int, buff: BinaryIO, cm: ClassManager) -> None:
        self.CM = cm

        self.offset = buff.tell()

        self.class_def = []

        for i in range(0, size):
            idx = buff.tell()

            class_def = ClassDefItem(buff, cm)
            self.class_def.append(class_def)

            buff.seek(idx + calcsize("8I"))

    def set_off(self, off: int) -> None:
        self.offset = off

    def get_off(self) -> int:
        return self.offset

    def get_class_idx(self, idx: int) -> ClassDefItem:
        """return the associated `ClassDefItem` from the `class_def` list given an index

        :param idx: the index
        :return: the `ClassDefItem` object , or `None` if not found
        """
        for i in self.class_def:
            if i.get_class_idx() == idx:
                return i
        return None

    def get_method(
        self, name_class: str, name_method: str
    ) -> list[EncodedMethod]:
        """return a list of of `EncodedMethod` objects given a class name and method name

        :param name_class: the name of the class
        :param name_method: the name of the method
        :return: a list of `EncodedMethod` objects
        """
        l = []

        for i in self.class_def:
            if i.get_name() == name_class:
                for j in i.get_methods():
                    if j.get_name() == name_method:
                        l.append(j)
        return l

    def get_names(self) -> list[str]:
        """return a list of class names found in `class_def`

        :return: a list of class names
        """
        return [x.get_name() for x in self.class_def]

    def show(self) -> None:
        for i in self.class_def:
            i.show()

    def get_obj(self) -> list[ClassDefItem]:
        """return a list of `ClassDefItem` objects

        :return: list of `ClassDefItem` objects
        """
        return [i for i in self.class_def]

    def get_raw(self) -> bytes:
        return b''.join(i.get_raw() for i in self.class_def)

    def get_length(self) -> int:
        length = 0
        for i in self.class_def:
            length += i.get_length()
        return length

get_class_idx(idx) #

return the associated ClassDefItem from the class_def list given an index

Parameters:

Name Type Description Default
idx int

the index

required

Returns:

Type Description
ClassDefItem

the ClassDefItem object , or None if not found

Source code in androguard/core/dex/__init__.py
def get_class_idx(self, idx: int) -> ClassDefItem:
    """return the associated `ClassDefItem` from the `class_def` list given an index

    :param idx: the index
    :return: the `ClassDefItem` object , or `None` if not found
    """
    for i in self.class_def:
        if i.get_class_idx() == idx:
            return i
    return None

get_method(name_class, name_method) #

return a list of of EncodedMethod objects given a class name and method name

Parameters:

Name Type Description Default
name_class str

the name of the class

required
name_method str

the name of the method

required

Returns:

Type Description
list[EncodedMethod]

a list of EncodedMethod objects

Source code in androguard/core/dex/__init__.py
def get_method(
    self, name_class: str, name_method: str
) -> list[EncodedMethod]:
    """return a list of of `EncodedMethod` objects given a class name and method name

    :param name_class: the name of the class
    :param name_method: the name of the method
    :return: a list of `EncodedMethod` objects
    """
    l = []

    for i in self.class_def:
        if i.get_name() == name_class:
            for j in i.get_methods():
                if j.get_name() == name_method:
                    l.append(j)
    return l

get_names() #

return a list of class names found in class_def

Returns:

Type Description
list[str]

a list of class names

Source code in androguard/core/dex/__init__.py
def get_names(self) -> list[str]:
    """return a list of class names found in `class_def`

    :return: a list of class names
    """
    return [x.get_name() for x in self.class_def]

get_obj() #

return a list of ClassDefItem objects

Returns:

Type Description
list[ClassDefItem]

list of ClassDefItem objects

Source code in androguard/core/dex/__init__.py
def get_obj(self) -> list[ClassDefItem]:
    """return a list of `ClassDefItem` objects

    :return: list of `ClassDefItem` objects
    """
    return [i for i in self.class_def]

ClassManager #

This class is used to access to all elements (strings, type, proto ...) of the dex format based on their offset or index.

Source code in androguard/core/dex/__init__.py
7801
7802
7803
7804
7805
7806
7807
7808
7809
7810
7811
7812
7813
7814
7815
7816
7817
7818
7819
7820
7821
7822
7823
7824
7825
7826
7827
7828
7829
7830
7831
7832
7833
7834
7835
7836
7837
7838
7839
7840
7841
7842
7843
7844
7845
7846
7847
7848
7849
7850
7851
7852
7853
7854
7855
7856
7857
7858
7859
7860
7861
7862
7863
7864
7865
7866
7867
7868
7869
7870
7871
7872
7873
7874
7875
7876
7877
7878
7879
7880
7881
7882
7883
7884
7885
7886
7887
7888
7889
7890
7891
7892
7893
7894
7895
7896
7897
7898
7899
7900
7901
7902
7903
7904
7905
7906
7907
7908
7909
7910
7911
7912
7913
7914
7915
7916
7917
7918
7919
7920
7921
7922
7923
7924
7925
7926
7927
7928
7929
7930
7931
7932
7933
7934
7935
7936
7937
7938
7939
7940
7941
7942
7943
7944
7945
7946
7947
7948
7949
7950
7951
7952
7953
7954
7955
7956
7957
7958
7959
7960
7961
7962
7963
7964
7965
7966
7967
7968
7969
7970
7971
7972
7973
7974
7975
7976
7977
7978
7979
7980
7981
7982
7983
7984
7985
7986
7987
7988
7989
7990
7991
7992
7993
7994
7995
7996
7997
7998
7999
8000
8001
8002
8003
8004
8005
8006
8007
8008
8009
8010
8011
8012
8013
8014
8015
8016
8017
8018
8019
8020
8021
8022
8023
8024
8025
8026
8027
8028
8029
8030
8031
8032
8033
8034
8035
8036
8037
8038
8039
8040
8041
8042
8043
8044
8045
8046
8047
8048
8049
8050
8051
8052
8053
8054
8055
8056
8057
8058
8059
8060
8061
8062
8063
8064
8065
8066
8067
8068
8069
8070
8071
8072
8073
8074
8075
8076
8077
8078
8079
8080
8081
8082
8083
8084
8085
8086
8087
8088
8089
8090
8091
8092
8093
8094
8095
8096
8097
8098
8099
8100
8101
8102
8103
8104
8105
8106
8107
8108
8109
8110
8111
8112
8113
8114
8115
8116
8117
8118
8119
8120
8121
8122
8123
8124
8125
8126
8127
8128
8129
8130
8131
8132
8133
8134
8135
8136
8137
8138
8139
8140
8141
8142
8143
8144
8145
8146
8147
8148
8149
8150
8151
8152
8153
8154
8155
8156
8157
8158
8159
8160
8161
8162
8163
8164
8165
8166
8167
8168
8169
8170
8171
8172
8173
8174
8175
8176
8177
8178
8179
8180
8181
8182
8183
class ClassManager:
    """
    This class is used to access to all elements (strings, type, proto ...) of the dex format
    based on their offset or index.
    """

    def __init__(self, vm: DEX) -> None:
        """
        :param DEX vm: the VM to create a `ClassManager` for
        """
        self.vm = vm
        self.buff = vm

        self.analysis_dex = None
        self.decompiler_ob = None

        self.__packer = None

        self.__manage_item = {}
        self.__manage_item_off = []

        self.__strings_off = {}
        self.__typelists_off = {}
        self.__classdata_off = {}

        self.__obj_offset = {}
        self.__item_offset = {}

        self.__cached_proto = {}

        self.hook_strings = {}

        if self.vm:
            self.odex_format = self.vm.get_format_type() == "ODEX"
        else:
            self.odex_format = False

    @property
    def packer(self):
        return self.__packer

    @packer.setter
    def packer(self, p):
        self.__packer = p

    def get_ascii_string(self, s: str) -> str:
        # TODO Remove method
        try:
            return s.decode("ascii")
        except UnicodeDecodeError:
            d = ""
            for i in s:
                if i < 128:
                    d += i
                else:
                    d += "%x" % i
            return d

    def get_odex_format(self) -> bool:
        """Returns `True` if the underlying VM is ODEX

        :returns: `True` if vm is ODEX, `False` if not
        """
        return self.odex_format

    def get_obj_by_offset(self, offset: int) -> object:
        """
        Returns a object from as given offset inside the DEX file
        """
        return self.__obj_offset[offset]

    def get_item_by_offset(self, offset: int) -> object:
        return self.__item_offset[offset]

    def get_string_by_offset(self, offset: int) -> object:
        return self.__strings_off[offset]

    def set_decompiler(self, decompiler: DecompilerDAD) -> None:
        self.decompiler_ob = decompiler

    def set_analysis(self, analysis_dex: Analysis) -> None:
        self.analysis_dex = analysis_dex

    def get_analysis(self) -> Analysis:
        return self.analysis_dex

    def add_type_item(
        self, type_item: TypeMapItem, c_item: MapItem, item: object
    ) -> None:
        self.__manage_item[type_item] = item

        self.__obj_offset[c_item.get_off()] = c_item
        self.__item_offset[c_item.get_offset()] = item

        if item is None:
            pass
        elif isinstance(item, list):
            for i in item:
                goff = i.offset
                self.__manage_item_off.append(goff)

                self.__obj_offset[i.get_off()] = i

                if type_item == TypeMapItem.STRING_DATA_ITEM:
                    self.__strings_off[goff] = i
                elif type_item == TypeMapItem.TYPE_LIST:
                    self.__typelists_off[goff] = i
                elif type_item == TypeMapItem.CLASS_DATA_ITEM:
                    self.__classdata_off[goff] = i
        else:
            self.__manage_item_off.append(c_item.get_offset())

    def get_code(self, idx: int) -> Union[DalvikCode, None]:
        try:
            return self.__manage_item[TypeMapItem.CODE_ITEM].get_code(idx)
        except KeyError:
            return None

    def get_class_data_item(self, off: int) -> ClassDataItem:
        i = self.__classdata_off.get(off)
        if i is None:
            logger.warning("unknown class data item @ 0x%x" % off)
        return i

    def get_encoded_array_item(self, off: int) -> EncodedArrayItem:
        for i in self.__manage_item[TypeMapItem.ENCODED_ARRAY_ITEM]:
            if i.get_off() == off:
                return i

    def get_annotations_directory_item(
        self, off: int
    ) -> AnnotationsDirectoryItem:
        for i in self.__manage_item[TypeMapItem.ANNOTATIONS_DIRECTORY_ITEM]:
            if i.get_off() == off:
                return i

    def get_annotation_set_item(self, off: int) -> AnnotationSetItem:
        for i in self.__manage_item[TypeMapItem.ANNOTATION_SET_ITEM]:
            if i.get_off() == off:
                return i

    def get_annotation_off_item(self, off: int) -> AnnotationOffItem:
        for i in self.__manage_item[TypeMapItem.ANNOTATION_OFF_ITEM]:
            if i.get_off() == off:
                return i

    def get_annotation_item(self, off: int) -> AnnotationItem:
        for i in self.__manage_item[TypeMapItem.ANNOTATION_ITEM]:
            if i.get_off() == off:
                return i

    def get_hiddenapi_class_data_item(
        self, off: int
    ) -> HiddenApiClassDataItem:
        for i in self.__manage_item[TypeMapItem.HIDDENAPI_CLASS_DATA_ITEM]:
            if i.get_off() == off:
                return i

    def get_string(self, idx: int) -> str:
        """
        Return a string from the string table at index `idx`

        If string is hooked, the hooked string is returned.

        :param idx: index in the string section

        :returns: string entry
        """
        if idx in self.hook_strings:
            return self.hook_strings[idx]

        return self.get_raw_string(idx)

    def get_raw_string(self, idx: int) -> str:
        """
        Return the (unprocessed) string from the string table at index `idx`.

        :param idx: the index in the string section
        """
        try:
            off = self.__manage_item[TypeMapItem.STRING_ID_ITEM][
                idx
            ].get_string_data_off()
        except IndexError:
            logger.warning("unknown string item @ %d" % idx)
            return "AG:IS: invalid string"

        try:
            return self.__strings_off[off].get()
        except KeyError:
            logger.warning("unknown string item @ 0x%x(%d)" % (off, idx))
            return "AG:IS: invalid string"

    def get_type_list(self, off: int) -> list[str]:
        if off == 0:
            return []

        i = self.__typelists_off[off]
        return [type_.get_string() for type_ in i.get_list()]

    def get_type(self, idx: int) -> str:
        """
        Return the resolved type name based on the index

        This returns the string associated with the type.

        :param int idx:
        :returns: the type name
        """
        _type = self.get_type_ref(idx)
        if _type == -1:
            return "AG:ITI: invalid type"
        return self.get_string(_type)

    def get_type_ref(self, idx: int) -> TypeIdItem:
        """
        Returns the string reference ID for a given type ID.

        This method is similar to [get_type][androguard.core.dex.ClassManager.get_type] but does not resolve
        the string but returns the ID into the string section.

        If the type IDX is not found, -1 is returned.
        """
        return self.__manage_item[TypeMapItem.TYPE_ID_ITEM].get(idx)

    def get_proto(self, idx: int) -> list:
        proto = self.__cached_proto.get(idx)
        if not proto:
            proto = self.__manage_item[TypeMapItem.PROTO_ID_ITEM].get(idx)
            self.__cached_proto[idx] = proto

        return [
            proto.get_parameters_off_value(),
            proto.get_return_type_idx_value(),
        ]

    def get_field(self, idx: int) -> list[str]:
        field = self.get_field_ref(idx)
        # return [field.get_class_name(), field.get_type(), field.get_name()]
        return field.get_list()

    def get_field_ref(self, idx: int) -> FieldIdItem:
        return self.__manage_item[TypeMapItem.FIELD_ID_ITEM].get(idx)

    def get_method(self, idx: int) -> list[str]:
        return self.get_method_ref(idx).get_list()

    def get_method_ref(self, idx: int) -> MethodIdItem:
        return self.__manage_item[TypeMapItem.METHOD_ID_ITEM].get(idx)

    def set_hook_class_name(self, class_def: ClassDefItem, value: str) -> None:
        python_export = True
        _type = self.__manage_item[TypeMapItem.TYPE_ID_ITEM].get(
            class_def.get_class_idx()
        )
        self.set_hook_string(_type, value)

        try:
            self.vm._delete_python_export_class(class_def)
        except AttributeError:
            python_export = False

        class_def.reload()

        # FIXME
        self.__manage_item[TypeMapItem.METHOD_ID_ITEM].reload()

        for i in class_def.get_methods():
            i.reload()

        for i in class_def.get_fields():
            i.reload()

        if python_export:
            self.vm._create_python_export_class(class_def)

    def set_hook_method_name(
        self, encoded_method: EncodedMethod, value: str
    ) -> None:
        python_export = True

        method = self.__manage_item[TypeMapItem.METHOD_ID_ITEM].get(
            encoded_method.get_method_idx()
        )
        self.set_hook_string(method.get_name_idx(), value)

        class_def = self.__manage_item[
            TypeMapItem.CLASS_DEF_ITEM
        ].get_class_idx(method.get_class_idx())
        if class_def is not None:
            try:
                name = bytecode.FormatNameToPython(encoded_method.get_name())
            except AttributeError:
                name += "_" + bytecode.FormatDescriptorToPython(
                    encoded_method.get_descriptor()
                )

            logger.debug("try deleting old name in python...")
            try:
                delattr(class_def.M, name)
                logger.debug("success with regular name")
            except AttributeError:
                logger.debug("WARNING: fail with regular name")
                # python_export = False

                try:
                    name = bytecode.FormatNameToPython(
                        encoded_method.get_name()
                        + '_'
                        + encoded_method.proto.replace(' ', '')
                        .replace('(', '')
                        .replace('[', '')
                        .replace(')', '')
                        .replace('/', '_')
                        .replace(';', '')
                    )
                except AttributeError:
                    name += "_" + bytecode.FormatDescriptorToPython(
                        encoded_method.get_descriptor()
                    )

                try:
                    delattr(class_def.M, name)
                    logger.debug("success with name containing prototype")
                except AttributeError:
                    logger.debug(
                        "WARNING: fail with name containing prototype"
                    )
                    python_export = False

            if python_export:
                name = bytecode.FormatNameToPython(value)
                setattr(class_def.M, name, encoded_method)
                logger.debug("new name in python: created: %s." % name)
            else:
                logger.debug("skipping creating new name in python")

        method.reload()

    def set_hook_field_name(
        self, encoded_field: EncodedField, value: str
    ) -> None:
        python_export = True

        field = self.__manage_item[TypeMapItem.FIELD_ID_ITEM].get(
            encoded_field.get_field_idx()
        )
        self.set_hook_string(field.get_name_idx(), value)

        class_def = self.__manage_item[
            TypeMapItem.CLASS_DEF_ITEM
        ].get_class_idx(field.get_class_idx())
        if class_def is not None:
            try:
                name = bytecode.FormatNameToPython(encoded_field.get_name())
            except AttributeError:
                name += "_" + bytecode.FormatDescriptorToPython(
                    encoded_field.get_descriptor()
                )

            try:
                delattr(class_def.F, name)
            except AttributeError:
                python_export = False

            if python_export:
                name = bytecode.FormatNameToPython(value)
                setattr(class_def.F, name, encoded_field)

        field.reload()

    def set_hook_string(self, idx: int, value: str) -> None:
        self.hook_strings[idx] = value

    def get_next_offset_item(self, idx: int) -> int:
        for i in self.__manage_item_off:
            if i > idx:
                return i
        return idx

    def get_debug_off(self, off: int) -> DebugInfoItem:
        self.buff.seek(off)
        return DebugInfoItem(self.buff, self)

__init__(vm) #

Parameters:

Name Type Description Default
vm DEX

the VM to create a ClassManager for

required
Source code in androguard/core/dex/__init__.py
def __init__(self, vm: DEX) -> None:
    """
    :param DEX vm: the VM to create a `ClassManager` for
    """
    self.vm = vm
    self.buff = vm

    self.analysis_dex = None
    self.decompiler_ob = None

    self.__packer = None

    self.__manage_item = {}
    self.__manage_item_off = []

    self.__strings_off = {}
    self.__typelists_off = {}
    self.__classdata_off = {}

    self.__obj_offset = {}
    self.__item_offset = {}

    self.__cached_proto = {}

    self.hook_strings = {}

    if self.vm:
        self.odex_format = self.vm.get_format_type() == "ODEX"
    else:
        self.odex_format = False

get_obj_by_offset(offset) #

Returns a object from as given offset inside the DEX file

Source code in androguard/core/dex/__init__.py
def get_obj_by_offset(self, offset: int) -> object:
    """
    Returns a object from as given offset inside the DEX file
    """
    return self.__obj_offset[offset]

get_odex_format() #

Returns True if the underlying VM is ODEX

Returns:

Type Description
bool

True if vm is ODEX, False if not

Source code in androguard/core/dex/__init__.py
def get_odex_format(self) -> bool:
    """Returns `True` if the underlying VM is ODEX

    :returns: `True` if vm is ODEX, `False` if not
    """
    return self.odex_format

get_raw_string(idx) #

Return the (unprocessed) string from the string table at index idx.

Parameters:

Name Type Description Default
idx int

the index in the string section

required
Source code in androguard/core/dex/__init__.py
def get_raw_string(self, idx: int) -> str:
    """
    Return the (unprocessed) string from the string table at index `idx`.

    :param idx: the index in the string section
    """
    try:
        off = self.__manage_item[TypeMapItem.STRING_ID_ITEM][
            idx
        ].get_string_data_off()
    except IndexError:
        logger.warning("unknown string item @ %d" % idx)
        return "AG:IS: invalid string"

    try:
        return self.__strings_off[off].get()
    except KeyError:
        logger.warning("unknown string item @ 0x%x(%d)" % (off, idx))
        return "AG:IS: invalid string"

get_string(idx) #

Return a string from the string table at index idx

If string is hooked, the hooked string is returned.

Parameters:

Name Type Description Default
idx int

index in the string section

required

Returns:

Type Description
str

string entry

Source code in androguard/core/dex/__init__.py
def get_string(self, idx: int) -> str:
    """
    Return a string from the string table at index `idx`

    If string is hooked, the hooked string is returned.

    :param idx: index in the string section

    :returns: string entry
    """
    if idx in self.hook_strings:
        return self.hook_strings[idx]

    return self.get_raw_string(idx)

get_type(idx) #

Return the resolved type name based on the index

This returns the string associated with the type.

Parameters:

Name Type Description Default
idx int
required

Returns:

Type Description
str

the type name

Source code in androguard/core/dex/__init__.py
def get_type(self, idx: int) -> str:
    """
    Return the resolved type name based on the index

    This returns the string associated with the type.

    :param int idx:
    :returns: the type name
    """
    _type = self.get_type_ref(idx)
    if _type == -1:
        return "AG:ITI: invalid type"
    return self.get_string(_type)

get_type_ref(idx) #

Returns the string reference ID for a given type ID.

This method is similar to get_type but does not resolve the string but returns the ID into the string section.

If the type IDX is not found, -1 is returned.

Source code in androguard/core/dex/__init__.py
def get_type_ref(self, idx: int) -> TypeIdItem:
    """
    Returns the string reference ID for a given type ID.

    This method is similar to [get_type][androguard.core.dex.ClassManager.get_type] but does not resolve
    the string but returns the ID into the string section.

    If the type IDX is not found, -1 is returned.
    """
    return self.__manage_item[TypeMapItem.TYPE_ID_ITEM].get(idx)

DCode #

This class represents the instructions of a method

Parameters:

Name Type Description Default
class_manager ClassManager

the ClassManager

required
offset int

the offset of the buffer

required
size int

the total size of the buffer

required
buff bytes

a raw buffer where are the instructions

required
Source code in androguard/core/dex/__init__.py
class DCode:
    """
    This class represents the instructions of a method

    :param class_manager: the `ClassManager`
    :param offset: the offset of the buffer
    :param size: the total size of the buffer
    :param buff: a raw buffer where are the instructions
    """

    def __init__(
        self, class_manager: ClassManager, offset: int, size: int, buff: bytes
    ) -> None:
        self.CM = class_manager
        self.insn = buff
        self.offset = offset
        self.size = size

        self.notes = {}
        self.cached_instructions = None

        self.idx = 0

    def get_insn(self) -> bytes:
        """
        Get the insn buffer

        :returns: insn bytes
        """
        return self.insn

    def set_insn(self, insn: bytes) -> None:
        """
        Set a new raw buffer to disassemble

        :param insn: the buffer
        """
        self.insn = insn
        self.size = len(self.insn)

    def seek(self, idx: int) -> None:
        """
        Set the start address of the buffer

        :param idx: the index
        """
        self.idx = idx

    def is_cached_instructions(self) -> bool:
        if self.cached_instructions is not None:
            return True
        return False

    def set_instructions(self, instructions: list[Instruction]) -> None:
        """
        Set the instructions

        :param instructions: the list of instructions
        """
        self.cached_instructions = instructions

    def get_instructions(self) -> Iterator[Instruction]:
        """
        Return an iterator over [Instruction][androguard.core.dex.Instruction]

        :returns: a generator of each `Instruction` (or a cached list of instructions if you have setup instructions)
        """
        # it is possible to a cache for instructions (avoid a new disasm)
        if self.cached_instructions is None:
            ins = LinearSweepAlgorithm.get_instructions(
                self.CM, self.size, self.insn, self.idx
            )
            self.cached_instructions = list(ins)

        for i in self.cached_instructions:
            yield i

    def add_inote(
        self, msg: str, idx: int, off: Union[int, None] = None
    ) -> None:
        """
        Add a message to a specific instruction by using (default) the index of the address if specified

        :param msg: the message
        :param idx: index of the instruction (the position in the list of the instruction)
        :param off: address of the instruction
        """
        if off is not None:
            idx = self.off_to_pos(off)

        if idx not in self.notes:
            self.notes[idx] = []

        self.notes[idx].append(msg)

    def get_instruction(
        self, idx: int, off: Union[int, None] = None
    ) -> Instruction:
        """
        Get a particular instruction by using (default) the index of the address if specified

        :param idx: index of the instruction (the position in the list of the instruction)
        :param off: address of the instruction

        :returns: an `Instruction` object
        """
        if off is not None:
            idx = self.off_to_pos(off)
        if self.cached_instructions is None:
            self.get_instructions()
        return self.cached_instructions[idx]

    def off_to_pos(self, off: int) -> int:
        """
        Get the position of an instruction by using the address

        :param off: address of the instruction

        :returns: the offset
        """
        idx = 0
        nb = 0
        for i in self.get_instructions():
            if idx == off:
                return nb
            nb += 1
            idx += i.get_length()
        return -1

    def get_ins_off(self, off: int) -> Instruction:
        """
        Get a particular instruction by using the address

        :param off: address of the instruction

        :returns: an `Instruction` object
        """
        idx = 0
        for i in self.get_instructions():
            if idx == off:
                return i
            idx += i.get_length()
        return None

    def show(self) -> None:
        """
        Display (with a pretty print) this object
        """
        off = 0
        for n, i in enumerate(self.get_instructions()):
            print(
                "{:8d} (0x{:08x}) {:04x} {:30} {}".format(
                    n,
                    off,
                    i.get_op_value(),
                    i.get_name(),
                    i.get_output(self.idx),
                )
            )
            off += i.get_length()

    def get_raw(self) -> bytearray:
        """
        Return the raw buffer of this object

        :returns: buffer bytearray
        """
        buff = bytearray()
        for i in self.get_instructions():
            buff += i.get_raw()
        return buff

    def get_length(self) -> int:
        """
        Return the length of this object

        :returns: length int
        """
        return len(self.get_raw())

add_inote(msg, idx, off=None) #

Add a message to a specific instruction by using (default) the index of the address if specified

Parameters:

Name Type Description Default
msg str

the message

required
idx int

index of the instruction (the position in the list of the instruction)

required
off Union[int, None]

address of the instruction

None
Source code in androguard/core/dex/__init__.py
def add_inote(
    self, msg: str, idx: int, off: Union[int, None] = None
) -> None:
    """
    Add a message to a specific instruction by using (default) the index of the address if specified

    :param msg: the message
    :param idx: index of the instruction (the position in the list of the instruction)
    :param off: address of the instruction
    """
    if off is not None:
        idx = self.off_to_pos(off)

    if idx not in self.notes:
        self.notes[idx] = []

    self.notes[idx].append(msg)

get_ins_off(off) #

Get a particular instruction by using the address

Parameters:

Name Type Description Default
off int

address of the instruction

required

Returns:

Type Description
Instruction

an Instruction object

Source code in androguard/core/dex/__init__.py
def get_ins_off(self, off: int) -> Instruction:
    """
    Get a particular instruction by using the address

    :param off: address of the instruction

    :returns: an `Instruction` object
    """
    idx = 0
    for i in self.get_instructions():
        if idx == off:
            return i
        idx += i.get_length()
    return None

get_insn() #

Get the insn buffer

Returns:

Type Description
bytes

insn bytes

Source code in androguard/core/dex/__init__.py
def get_insn(self) -> bytes:
    """
    Get the insn buffer

    :returns: insn bytes
    """
    return self.insn

get_instruction(idx, off=None) #

Get a particular instruction by using (default) the index of the address if specified

Parameters:

Name Type Description Default
idx int

index of the instruction (the position in the list of the instruction)

required
off Union[int, None]

address of the instruction

None

Returns:

Type Description
Instruction

an Instruction object

Source code in androguard/core/dex/__init__.py
def get_instruction(
    self, idx: int, off: Union[int, None] = None
) -> Instruction:
    """
    Get a particular instruction by using (default) the index of the address if specified

    :param idx: index of the instruction (the position in the list of the instruction)
    :param off: address of the instruction

    :returns: an `Instruction` object
    """
    if off is not None:
        idx = self.off_to_pos(off)
    if self.cached_instructions is None:
        self.get_instructions()
    return self.cached_instructions[idx]

get_instructions() #

Return an iterator over Instruction

Returns:

Type Description
Iterator[Instruction]

a generator of each Instruction (or a cached list of instructions if you have setup instructions)

Source code in androguard/core/dex/__init__.py
def get_instructions(self) -> Iterator[Instruction]:
    """
    Return an iterator over [Instruction][androguard.core.dex.Instruction]

    :returns: a generator of each `Instruction` (or a cached list of instructions if you have setup instructions)
    """
    # it is possible to a cache for instructions (avoid a new disasm)
    if self.cached_instructions is None:
        ins = LinearSweepAlgorithm.get_instructions(
            self.CM, self.size, self.insn, self.idx
        )
        self.cached_instructions = list(ins)

    for i in self.cached_instructions:
        yield i

get_length() #

Return the length of this object

Returns:

Type Description
int

length int

Source code in androguard/core/dex/__init__.py
def get_length(self) -> int:
    """
    Return the length of this object

    :returns: length int
    """
    return len(self.get_raw())

get_raw() #

Return the raw buffer of this object

Returns:

Type Description
bytearray

buffer bytearray

Source code in androguard/core/dex/__init__.py
def get_raw(self) -> bytearray:
    """
    Return the raw buffer of this object

    :returns: buffer bytearray
    """
    buff = bytearray()
    for i in self.get_instructions():
        buff += i.get_raw()
    return buff

off_to_pos(off) #

Get the position of an instruction by using the address

Parameters:

Name Type Description Default
off int

address of the instruction

required

Returns:

Type Description
int

the offset

Source code in androguard/core/dex/__init__.py
def off_to_pos(self, off: int) -> int:
    """
    Get the position of an instruction by using the address

    :param off: address of the instruction

    :returns: the offset
    """
    idx = 0
    nb = 0
    for i in self.get_instructions():
        if idx == off:
            return nb
        nb += 1
        idx += i.get_length()
    return -1

seek(idx) #

Set the start address of the buffer

Parameters:

Name Type Description Default
idx int

the index

required
Source code in androguard/core/dex/__init__.py
def seek(self, idx: int) -> None:
    """
    Set the start address of the buffer

    :param idx: the index
    """
    self.idx = idx

set_insn(insn) #

Set a new raw buffer to disassemble

Parameters:

Name Type Description Default
insn bytes

the buffer

required
Source code in androguard/core/dex/__init__.py
def set_insn(self, insn: bytes) -> None:
    """
    Set a new raw buffer to disassemble

    :param insn: the buffer
    """
    self.insn = insn
    self.size = len(self.insn)

set_instructions(instructions) #

Set the instructions

Parameters:

Name Type Description Default
instructions list[Instruction]

the list of instructions

required
Source code in androguard/core/dex/__init__.py
def set_instructions(self, instructions: list[Instruction]) -> None:
    """
    Set the instructions

    :param instructions: the list of instructions
    """
    self.cached_instructions = instructions

show() #

Display (with a pretty print) this object

Source code in androguard/core/dex/__init__.py
def show(self) -> None:
    """
    Display (with a pretty print) this object
    """
    off = 0
    for n, i in enumerate(self.get_instructions()):
        print(
            "{:8d} (0x{:08x}) {:04x} {:30} {}".format(
                n,
                off,
                i.get_op_value(),
                i.get_name(),
                i.get_output(self.idx),
            )
        )
        off += i.get_length()

DEX #

This class can parse a classes.dex file of an Android application (APK).

Parameters:

Name Type Description Default
buff

a string which represents the classes.dex file

required
decompiler Union[DecompilerDAD, None]

associate a decompiler object to display the java source code Example: >>> d = DEX( read("classes.dex") )

None
Source code in androguard/core/dex/__init__.py
8307
8308
8309
8310
8311
8312
8313
8314
8315
8316
8317
8318
8319
8320
8321
8322
8323
8324
8325
8326
8327
8328
8329
8330
8331
8332
8333
8334
8335
8336
8337
8338
8339
8340
8341
8342
8343
8344
8345
8346
8347
8348
8349
8350
8351
8352
8353
8354
8355
8356
8357
8358
8359
8360
8361
8362
8363
8364
8365
8366
8367
8368
8369
8370
8371
8372
8373
8374
8375
8376
8377
8378
8379
8380
8381
8382
8383
8384
8385
8386
8387
8388
8389
8390
8391
8392
8393
8394
8395
8396
8397
8398
8399
8400
8401
8402
8403
8404
8405
8406
8407
8408
8409
8410
8411
8412
8413
8414
8415
8416
8417
8418
8419
8420
8421
8422
8423
8424
8425
8426
8427
8428
8429
8430
8431
8432
8433
8434
8435
8436
8437
8438
8439
8440
8441
8442
8443
8444
8445
8446
8447
8448
8449
8450
8451
8452
8453
8454
8455
8456
8457
8458
8459
8460
8461
8462
8463
8464
8465
8466
8467
8468
8469
8470
8471
8472
8473
8474
8475
8476
8477
8478
8479
8480
8481
8482
8483
8484
8485
8486
8487
8488
8489
8490
8491
8492
8493
8494
8495
8496
8497
8498
8499
8500
8501
8502
8503
8504
8505
8506
8507
8508
8509
8510
8511
8512
8513
8514
8515
8516
8517
8518
8519
8520
8521
8522
8523
8524
8525
8526
8527
8528
8529
8530
8531
8532
8533
8534
8535
8536
8537
8538
8539
8540
8541
8542
8543
8544
8545
8546
8547
8548
8549
8550
8551
8552
8553
8554
8555
8556
8557
8558
8559
8560
8561
8562
8563
8564
8565
8566
8567
8568
8569
8570
8571
8572
8573
8574
8575
8576
8577
8578
8579
8580
8581
8582
8583
8584
8585
8586
8587
8588
8589
8590
8591
8592
8593
8594
8595
8596
8597
8598
8599
8600
8601
8602
8603
8604
8605
8606
8607
8608
8609
8610
8611
8612
8613
8614
8615
8616
8617
8618
8619
8620
8621
8622
8623
8624
8625
8626
8627
8628
8629
8630
8631
8632
8633
8634
8635
8636
8637
8638
8639
8640
8641
8642
8643
8644
8645
8646
8647
8648
8649
8650
8651
8652
8653
8654
8655
8656
8657
8658
8659
8660
8661
8662
8663
8664
8665
8666
8667
8668
8669
8670
8671
8672
8673
8674
8675
8676
8677
8678
8679
8680
8681
8682
8683
8684
8685
8686
8687
8688
8689
8690
8691
8692
8693
8694
8695
8696
8697
8698
8699
8700
8701
8702
8703
8704
8705
8706
8707
8708
8709
8710
8711
8712
8713
8714
8715
8716
8717
8718
8719
8720
8721
8722
8723
8724
8725
8726
8727
8728
8729
8730
8731
8732
8733
8734
8735
8736
8737
8738
8739
8740
8741
8742
8743
8744
8745
8746
8747
8748
8749
8750
8751
8752
8753
8754
8755
8756
8757
8758
8759
8760
8761
8762
8763
8764
8765
8766
8767
8768
8769
8770
8771
8772
8773
8774
8775
8776
8777
8778
8779
8780
8781
8782
8783
8784
8785
8786
8787
8788
8789
8790
8791
8792
8793
8794
8795
8796
8797
8798
8799
8800
8801
8802
8803
8804
8805
8806
8807
8808
8809
8810
8811
8812
8813
8814
8815
8816
8817
8818
8819
8820
8821
8822
8823
8824
8825
8826
8827
8828
8829
8830
8831
8832
8833
8834
8835
8836
8837
8838
8839
8840
8841
8842
8843
8844
8845
8846
8847
8848
8849
8850
8851
8852
8853
8854
8855
8856
8857
8858
8859
8860
8861
8862
8863
8864
8865
8866
8867
8868
8869
8870
8871
8872
8873
8874
8875
8876
8877
8878
8879
8880
8881
8882
8883
8884
8885
8886
8887
8888
8889
8890
8891
8892
8893
8894
8895
8896
8897
8898
8899
8900
8901
8902
8903
8904
8905
8906
8907
8908
8909
8910
8911
8912
8913
8914
8915
8916
8917
8918
8919
8920
8921
8922
8923
8924
8925
8926
8927
8928
8929
8930
8931
8932
8933
8934
8935
8936
8937
8938
8939
8940
8941
8942
8943
8944
8945
8946
8947
8948
8949
8950
8951
8952
8953
8954
8955
8956
8957
8958
8959
8960
8961
8962
8963
8964
8965
8966
8967
8968
8969
8970
8971
8972
8973
8974
8975
8976
8977
8978
8979
8980
8981
8982
8983
8984
8985
8986
8987
8988
8989
8990
8991
8992
8993
8994
8995
8996
8997
8998
8999
9000
9001
9002
9003
9004
9005
9006
9007
9008
9009
9010
9011
9012
9013
9014
9015
9016
9017
9018
9019
9020
9021
9022
9023
9024
9025
9026
9027
9028
9029
9030
9031
9032
9033
9034
9035
9036
9037
9038
9039
9040
9041
9042
9043
9044
9045
9046
9047
9048
9049
9050
9051
9052
9053
9054
9055
9056
9057
9058
9059
9060
9061
9062
9063
9064
9065
9066
9067
9068
9069
9070
9071
9072
9073
9074
9075
9076
9077
9078
9079
9080
9081
9082
9083
9084
9085
9086
9087
9088
9089
9090
9091
9092
9093
9094
9095
9096
9097
9098
9099
9100
9101
9102
9103
9104
9105
9106
9107
9108
9109
9110
9111
9112
9113
9114
9115
9116
9117
9118
9119
9120
9121
9122
9123
9124
9125
9126
9127
9128
9129
9130
9131
9132
9133
9134
9135
9136
9137
9138
9139
9140
9141
9142
9143
9144
9145
9146
9147
9148
9149
9150
9151
9152
9153
9154
9155
9156
9157
9158
9159
9160
9161
9162
9163
9164
9165
9166
9167
9168
9169
9170
9171
9172
9173
9174
9175
9176
9177
class DEX:
    """
    This class can parse a classes.dex file of an Android application (APK).

    :param buff: a string which represents the classes.dex file
    :param decompiler: associate a decompiler object to display the java source code

    Example:

        >>> d = DEX( read("classes.dex") )
    """

    def __init__(
        self,
        buff,
        decompiler: Union[DecompilerDAD, None] = None,
        config=None,
        using_api: Union[int, None] = None,
    ) -> None:
        logger.debug("DEX {} {} {}".format(decompiler, config, using_api))

        # to allow to pass apk object ==> we do not need to pass additionally target version
        if isinstance(buff, apk.APK):
            self.api_version = buff.get_target_sdk_version()
            buff = buff.get_dex()  # getting dex from APK file
        elif using_api:
            self.api_version = using_api
        else:
            self.api_version = CONF["DEFAULT_API"]

        self.raw = io.BufferedReader(io.BytesIO(buff))

        self._flush()

        self.CM = ClassManager(self)
        self.CM.set_decompiler(decompiler)

        self._preload(buff)
        self._load(buff)

    def _preload(self, buff):
        pass

    def _load(self, buff) -> None:
        self.header = HeaderItem(0, self.raw, self.CM)

        if self.header.map_off == 0:
            # TODO check if the header specifies items but does not have a map
            logger.warning("no map list! This DEX file is probably empty.")
        else:
            self.map_list = MapList(self.CM, self.header.map_off, self.raw)

            self.classes = self.map_list.get_item_type(
                TypeMapItem.CLASS_DEF_ITEM
            )
            self.methods = self.map_list.get_item_type(
                TypeMapItem.METHOD_ID_ITEM
            )
            self.fields = self.map_list.get_item_type(
                TypeMapItem.FIELD_ID_ITEM
            )
            self.codes = self.map_list.get_item_type(TypeMapItem.CODE_ITEM)
            self.strings = self.map_list.get_item_type(
                TypeMapItem.STRING_DATA_ITEM
            )
            self.debug = self.map_list.get_item_type(
                TypeMapItem.DEBUG_INFO_ITEM
            )
            self.hidden_api = self.map_list.get_item_type(
                TypeMapItem.HIDDENAPI_CLASS_DATA_ITEM
            )

        self._flush()

    def _flush(self) -> None:
        """
        Flush all caches
        Might be used after classes, methods or fields are added.
        """
        self.classes_names = None
        self.__cache_methods = None
        self.__cached_methods_idx = None
        self.__cache_fields = None

        # cache methods and fields as well, otherwise the decompiler is quite slow
        self.__cache_all_methods = None
        self.__cache_all_fields = None

    @property
    def version(self) -> int:
        """
        Returns the version number of the DEX Format
        """
        return self.header.dex_version

    def get_api_version(self) -> int:
        """
        This method returns api version that should be used for loading api
        specific resources.

        :returns: api version string
        """
        return self.api_version

    def get_classes_def_item(self) -> ClassHDefItem:
        """
        This function returns the class def item

        :returns: `ClassHDefItem` object
        """
        return self.classes

    def get_methods_id_item(self) -> MethodHIdItem:
        """
        This function returns the method id item

        :returns: `MethodHIdItem` object
        """
        return self.methods

    def get_fields_id_item(self) -> FieldHIdItem:
        """
        This function returns the field id item

        :returns: `FieldHIdItem` object
        """
        return self.fields

    def get_codes_item(self) -> CodeItem:
        """
        This function returns the code item

        :returns: `CodeItem` object
        """
        return self.codes

    def get_string_data_item(self) -> StringDataItem:
        """
        This function returns the string data item

        :returns: `StringDataItem` object
        """
        return self.strings

    # TODO: this returns DebugInfoItemEmpty, as DebugInfoItem never gets set as a MapItem
    def get_debug_info_item(self) -> DebugInfoItemEmpty:
        """
        This function returns the debug info item
        :returns: `DebugInfoItemEmpty` object
        """
        return self.debug

    def get_header_item(self) -> HeaderItem:
        """
        This function returns the header item

        :returns: `HeaderItem` object
        """
        return self.header

    def get_hidden_api(self) -> HiddenApiClassDataItem:
        """
        This function returns the hidden api item (from Android 10)

        :returns: `HiddenApiClassDataItem` object
        """
        return self.hidden_api

    def get_class_manager(self) -> ClassManager:
        """
        This function returns a ClassManager object which allow you to get
        access to all index references (strings, methods, fields, ....)

        :returns: `ClassManager` object
        """
        return self.CM

    def show(self) -> None:
        """
        Show the all information in the object
        """
        self.map_list.show()

    def save(self) -> bytes:
        """
        Return the dex (with the modifications) into raw format (fix checksums)
        (beta: do not use !)

        :returns: bytes
        """
        l = []
        h = {}
        s = {}
        h_r = {}

        idx = 0
        for i in self.map_list.get_obj():
            length = 0

            if isinstance(i, list):
                for j in i:
                    if isinstance(j, AnnotationsDirectoryItem):
                        if idx % 4 != 0:
                            idx = idx + (4 - (idx % 4))

                    l.append(j)

                    c_length = j.get_length()
                    if isinstance(j, StringDataItem):
                        c_length += 1
                    h[j] = idx + length
                    h_r[idx + length] = j
                    s[idx + length] = c_length

                    length += c_length
                    # logger.debug("SAVE" + str(j) + " @ 0x%x" % (idx+length))

                logger.debug(
                    "SAVE " + str(i[0]) + " @0x{:x} ({:x})".format(idx, length)
                )

            else:
                if isinstance(i, MapList):
                    if idx % 4 != 0:
                        idx = idx + (4 - (idx % 4))

                l.append(i)
                h[i] = idx
                h_r[idx] = i

                length = i.get_length()

                s[idx] = length

                logger.debug(
                    "SAVE " + str(i) + " @0x{:x} ({:x})".format(idx, length)
                )

            idx += length

        self.header.file_size = idx

        for i in l:
            idx = h[i]
            i.set_off(idx)
            if isinstance(i, CodeItem):
                last_idx = idx
                for j in i.get_obj():
                    j.set_off(last_idx)
                    # j.set_debug_info_off(0)
                    last_idx += j.get_size()

        last_idx = 0
        buff = bytearray()
        for i in l:
            idx = h[i]

            if idx != last_idx:
                logger.debug(
                    "Adjust alignment @{:x} with 00 {:x}".format(
                        idx, idx - last_idx
                    )
                )
                buff += bytearray([0] * (idx - last_idx))

            buff += i.get_raw()
            if isinstance(i, StringDataItem):
                buff += b"\x00"
            last_idx = idx + s[idx]

        logger.debug("GLOBAL SIZE %d" % len(buff))

        return self.fix_checksums(buff)

    def fix_checksums(self, buff: bytes) -> bytes:
        """
        Fix a dex format buffer by setting all checksums

        :returns: bytes
        """

        signature = hashlib.sha1(buff[32:]).digest()

        buff = buff[:12] + signature + buff[32:]
        checksum = zlib.adler32(buff[12:])
        buff = buff[:8] + self.CM.packer["I"].pack(checksum) + buff[12:]

        logger.debug("NEW SIGNATURE %s" % repr(signature))
        logger.debug("NEW CHECKSUM %x" % checksum)

        return buff

    def get_cm_field(self, idx: int) -> list[str]:
        """
        Get a specific field by using an index

        :param idx: index of the field
        """
        return self.CM.get_field(idx)

    def get_cm_method(self, idx: int) -> list[str]:
        """
        Get a specific method by using an index

        :param idx: index of the method
        """
        return self.CM.get_method(idx)

    def get_cm_string(self, idx: int) -> str:
        """
        Get a specific string by using an index

        :param idx: index of the string

        :returns: the string
        """
        return self.CM.get_raw_string(idx)

    def get_cm_type(self, idx: int) -> str:
        """
        Get a specific type by using an index

        :param idx: index of the type

        :returns: the string type
        """
        return self.CM.get_type(idx)

    def get_classes_names(self, update: bool = False) -> list[str]:
        """
        Return the names of classes

        :param update: `True` indicates to recompute the list. Maybe needed after using a MyClass.set_name().
        :returns: a list of string names
        """
        if self.classes_names is None or update:
            self.classes_names = [i.get_name() for i in self.get_classes()]
        return self.classes_names

    def get_classes(self) -> list[ClassDefItem]:
        """
        Return all classes

        :returns: a list of `ClassDefItem` objects
        """
        if self.classes:
            return self.classes.class_def
        else:
            # There is a rare case that the DEX has no classes
            return []

    def get_len_classes(self) -> int:
        """
        Return the number of classes

        :returns: int
        """
        return len(self.get_classes())

    def get_class(self, name: str) -> Union[ClassDefItem, None]:
        """
        Return a specific class

        :param name: the name of the class

        :returns: a `ClassDefItem`
        """
        for i in self.get_classes():
            if i.get_name() == name:
                return i
        return None

    def get_field(self, name: str) -> list[FieldIdItem]:
        """get field id item by name

        :param name: the name of the field (a python string regexp)
        :returns: the list of matching `FieldIdItem` objects
        """

        prog = re.compile(name)
        l = []
        for i in self.get_fields():
            if prog.match(i.name):
                l.append(i)
        return l

    def get_fields(self) -> list[FieldIdItem]:
        """
        Return a list of field items

        :returns: a list of `FieldIdItem` objects
        """
        try:
            return self.fields.gets()
        except AttributeError:
            return []

    def get_len_fields(self) -> int:
        """
        Return the number of fields

        :returns: int
        """
        return len(self.get_fields())

    def get_encoded_field(self, name: str) -> list[EncodedField]:
        """
        Return a list all fields which corresponds to the regexp

        :param name: the name of the field (a python string regexp)

        :returns: a list with all `EncodedField` objects
        """
        # TODO could use a generator here
        prog = re.compile(name)
        l = []
        for i in self.get_encoded_fields():
            if prog.match(i.get_name()):
                l.append(i)
        return l

    def get_encoded_fields(self) -> list[EncodedField]:
        """
        Return all field objects

        :returns: a list of `EncodedField` objects
        """
        if self.__cache_all_fields is None:
            self.__cache_all_fields = []
            for i in self.get_classes():
                for j in i.get_fields():
                    self.__cache_all_fields.append(j)
        return self.__cache_all_fields

    def get_len_encoded_fields(self) -> int:
        return len(self.get_encoded_fields())

    def get_field(self, name: str) -> list[FieldIdItem]:
        """get field id item by name

        :param name: the name of the field (a python string regexp)
        :returns: the list of matching `FieldIdItem` objects
        """
        prog = re.compile(name)
        l = []
        for i in self.get_fields():
            if prog.match(i.name):
                l.append(i)
        return l

    def get_method(self, name: str) -> list[MethodIdItem]:
        """get method id item by name

        :param name: the name of the field (a python string regexp)
        :returns: the list of matching `MethodIdItem` objects
        """
        prog = re.compile(name)
        l = []
        for i in self.get_methods():
            if prog.match(i.name):
                l.append(i)
        return l

    def get_methods(self) -> list[MethodIdItem]:
        """
        Return a list of method items

        :returns: a list of `MethodIdItem` objects
        """
        try:
            return self.methods.gets()
        except AttributeError:
            return []

    def get_len_methods(self) -> int:
        """
        Return the number of methods

        :returns: int
        """
        return len(self.get_methods())

    def get_encoded_method(self, name: str) -> list[EncodedMethod]:
        """
        Return a list all encoded methods whose name corresponds to the regexp

        :param name: the name of the method (a python string regexp)

        :returns: a list with all `EncodedMethod` objects
        """
        prog = re.compile(name)
        l = []
        for i in self.get_encoded_methods():
            if prog.match(i.name):
                l.append(i)
        return l

    def get_encoded_methods(self) -> list[EncodedMethod]:
        """
        Return all encoded method objects

        :returns: a list of `EncodedMethod` objects
        """
        if self.__cache_all_methods is None:
            self.__cache_all_methods = []
            for i in self.get_classes():
                for j in i.get_methods():
                    self.__cache_all_methods.append(j)
        return self.__cache_all_methods

    def get_len_encoded_methods(self) -> int:
        """
        Return the number of encoded methods

        :returns: int
        """
        return len(self.get_encoded_methods())

    def get_encoded_method_by_idx(
        self, idx: int
    ) -> Union[EncodedMethod, None]:
        """
        Return a specific encoded method by using an index
        :param idx: the index of the method

        :returns: `None` or an `EncodedMethod` object
        """
        if self.__cached_methods_idx is None:
            self.__cached_methods_idx = {}
            for i in self.get_classes():
                for j in i.get_methods():
                    self.__cached_methods_idx[j.get_method_idx()] = j

        try:
            return self.__cached_methods_idx[idx]
        except KeyError:
            return None

    def get_encoded_method_descriptor(
        self, class_name: str, method_name: str, descriptor: str
    ) -> Union[EncodedMethod, None]:
        """
        Return the specific encoded method given a class name, method name, and descriptor

        :param class_name: the class name of the method
        :param method_name: the name of the method
        :param descriptor: the descriptor of the method

        :returns: `None` or a `EncodedMethod` object
        """
        key = class_name + method_name + descriptor

        if self.__cache_methods is None:
            self.__cache_methods = {}
            for i in self.get_classes():
                for j in i.get_methods():
                    self.__cache_methods[
                        j.get_class_name() + j.get_name() + j.get_descriptor()
                    ] = j

        return self.__cache_methods.get(key)

    def get_encoded_methods_class_method(
        self, class_name: str, method_name: str
    ) -> Union[EncodedMethod, None]:
        """
        Return the specific encoded methods of the class

        :param class_name: the class name of the method
        :param method_name: the name of the method

        :returns: `None` or a `EncodedMethod` object
        """
        for i in self.get_encoded_methods():
            if (
                i.get_name() == method_name
                and i.get_class_name() == class_name
            ):
                return i
        return None

    def get_encoded_methods_class(
        self, class_name: str
    ) -> list[EncodedMethod]:
        """
        Return all encoded methods of a specific class by class name

        :param class_name: the class name

        :returns: a list with `EncodedMethod` objects
        """
        l = []
        for i in self.get_encoded_methods():
            if class_name == i.get_class_name():
                l.append(i)
        return l

    def get_encoded_fields_class(self, class_name: str) -> list[EncodedField]:
        """
        Return all encoded fields of a specific class by class name

        :param class_name: the class name

        :returns: a list with `EncodedField` objects
        """
        l = []
        for i in self.get_encoded_fields():
            if class_name == i.get_class_name():
                l.append(i)
        return l

    def get_encoded_field_descriptor(
        self, class_name: str, field_name: str, descriptor: str
    ) -> EncodedField:
        """
        Return the specific encoded field given a class name, field name, and descriptor

        :param class_name: the class name of the field
        :param field_name: the name of the field
        :param descriptor: the descriptor of the field

        :returns: `None` or a `EncodedField` object
        """

        key = class_name + field_name + descriptor

        if self.__cache_fields is None:
            self.__cache_fields = {}
            for i in self.get_classes():
                for j in i.get_fields():
                    self.__cache_fields[
                        j.get_class_name() + j.get_name() + j.get_descriptor()
                    ] = j

        return self.__cache_fields.get(key)

    def get_strings(self) -> list[str]:
        """
        Return all strings

        The strings will have escaped surrogates, if only a single high or low surrogate is found.
        Complete surrogates are put together into the representing 32bit character.

        :returns: a list with all strings used in the format (types, names ...)
        """
        return (
            [i.get() for i in self.strings] if self.strings is not None else []
        )

    def get_len_strings(self) -> int:
        """
        Return the number of strings

        :returns: int
        """
        return len(self.get_strings())

    def get_regex_strings(
        self, regular_expressions: str
    ) -> Union[list[str], None]:
        """
        Return all target strings matched the regex

        :param regular_expressions: the python regex string

        :returns: a list of strings matching the regex expression
        """
        str_list = []
        if regular_expressions.count is None:
            return None
        for i in self.get_strings():
            if re.match(regular_expressions, i):
                str_list.append(i)
        return str_list

    def get_format_type(self) -> str:
        """
        Return the type

        :returns: a string
        """
        return "DEX"

    def create_python_export(self) -> None:
        """
        Export classes/methods/fields' names in the python namespace
        """
        logger.debug("Exporting Python objects")
        setattr(self, "C", ExportObject())

        for _class in self.get_classes():
            self._create_python_export_class(_class)

    def _delete_python_export_class(self, _class: ClassDefItem) -> None:
        self._create_python_export_class(_class, True)

    def _create_python_export_class(
        self, _class: ClassDefItem, delete: bool = False
    ) -> None:
        if _class is not None:
            ### Class
            name = str(bytecode.FormatClassToPython(_class.get_name()))
            if delete:
                delattr(self.C, name)
                return
            else:
                setattr(self.C, name, _class)
                setattr(_class, "M", ExportObject())
                setattr(_class, "F", ExportObject())

            self._create_python_export_methods(_class, delete)
            self._create_python_export_fields(_class, delete)

    def _create_python_export_methods(
        self, _class: ClassDefItem, delete
    ) -> None:
        m = {}
        for method in _class.get_methods():
            if method.get_name() not in m:
                m[method.get_name()] = []
            m[method.get_name()].append(method)
            setattr(method, "XF", ExportObject())
            setattr(method, "XT", ExportObject())

        for i in m:
            if len(m[i]) == 1:
                j = m[i][0]
                name = str(bytecode.FormatNameToPython(j.get_name()))
                setattr(_class.M, name, j)
            else:
                for j in m[i]:
                    name = (
                        str(bytecode.FormatNameToPython(j.get_name()))
                        + "_"
                        + str(
                            bytecode.FormatDescriptorToPython(
                                j.get_descriptor()
                            )
                        )
                    )
                    setattr(_class.M, name, j)

    def _create_python_export_fields(
        self, _class: ClassDefItem, delete
    ) -> None:
        f = {}
        for field in _class.get_fields():
            if field.get_name() not in f:
                f[field.get_name()] = []
            f[field.get_name()].append(field)
            setattr(field, "XR", ExportObject())
            setattr(field, "XW", ExportObject())

        for i in f:
            if len(f[i]) == 1:
                j = f[i][0]
                name = str(bytecode.FormatNameToPython(j.get_name()))
                setattr(_class.F, name, j)
            else:
                for j in f[i]:
                    name = (
                        str(bytecode.FormatNameToPython(j.get_name()))
                        + "_"
                        + str(
                            bytecode.FormatDescriptorToPython(
                                j.get_descriptor()
                            )
                        )
                    )
                    setattr(_class.F, name, j)

    def set_decompiler(self, decompiler: DecompilerDAD) -> None:
        self.CM.set_decompiler(decompiler)

    def set_analysis(self, analysis_dex: Analysis) -> None:
        self.CM.set_analysis(analysis_dex)

    def disassemble(self, offset: int, size: int) -> Iterator[Instruction]:
        """
        Disassembles a given offset in the DEX file

        :param offset: offset to disassemble in the file (from the beginning of the file)
        :param size:

        :returns: iterator over `Instruction`s at the given offset
        """
        for i in DCode(
            self.CM, offset, size, read_at(self.raw, offset, size)
        ).get_instructions():
            yield i

    def _get_class_hierarchy(self) -> Node:
        """
        Constructs a tree out of all the classes.
        The classes are added to this tree by their superclass.

        :returns: the root `Node` of the tree
        """
        # Contains the class names as well as their running number
        ids = dict()
        present = dict()
        r_ids = dict()
        to_add = dict()
        els = []

        for current_class in self.get_classes():
            s_name = current_class.get_superclassname()[1:-1]
            c_name = current_class.get_name()[1:-1]

            if s_name not in ids:
                ids[s_name] = len(ids) + 1
                r_ids[ids[s_name]] = s_name

            if c_name not in ids:
                ids[c_name] = len(ids) + 1

            els.append([ids[c_name], ids[s_name], c_name])
            present[ids[c_name]] = True

        for i in els:
            if i[1] not in present:
                to_add[i[1]] = r_ids[i[1]]

        for i in to_add:
            els.append([i, 0, to_add[i]])

        treeMap = dict()
        Root = bytecode.Node(0, "Root")
        treeMap[Root.id] = Root
        for element in els:
            nodeId, parentId, title = element
            if not nodeId in treeMap:
                treeMap[nodeId] = bytecode.Node(nodeId, title)
            else:
                treeMap[nodeId].id = nodeId
                treeMap[nodeId].title = title

            if not parentId in treeMap:
                treeMap[parentId] = bytecode.Node(0, '')
            treeMap[parentId].children.append(treeMap[nodeId])

        return Root

    def list_classes_hierarchy(self) -> dict[str, list[dict[str, list]]]:
        """
        Get a tree structure of the classes.
        The parent is always the superclass.

        You can use `pprint.pprint` to print the
        dictionary in a pretty way.

        :returns: a tree in dictionary format where the key is the class name and the value is a list of dictionaries containing a child class name as a key and subsequent child classes as a value list
        """

        def print_map(node, l):
            if node.title not in l:
                l[node.title] = []

            for n in node.children:
                if len(n.children) > 0:
                    w = {n.title: []}
                    l[node.title].append(w)

                    print_map(n, w)
                else:
                    l[node.title].append(n.title)

        l = {}
        print_map(self._get_class_hierarchy(), l)

        return l

version property #

Returns the version number of the DEX Format

create_python_export() #

Export classes/methods/fields' names in the python namespace

Source code in androguard/core/dex/__init__.py
def create_python_export(self) -> None:
    """
    Export classes/methods/fields' names in the python namespace
    """
    logger.debug("Exporting Python objects")
    setattr(self, "C", ExportObject())

    for _class in self.get_classes():
        self._create_python_export_class(_class)

disassemble(offset, size) #

Disassembles a given offset in the DEX file

Parameters:

Name Type Description Default
offset int

offset to disassemble in the file (from the beginning of the file)

required
size int
required

Returns:

Type Description
Iterator[Instruction]

iterator over Instructions at the given offset

Source code in androguard/core/dex/__init__.py
def disassemble(self, offset: int, size: int) -> Iterator[Instruction]:
    """
    Disassembles a given offset in the DEX file

    :param offset: offset to disassemble in the file (from the beginning of the file)
    :param size:

    :returns: iterator over `Instruction`s at the given offset
    """
    for i in DCode(
        self.CM, offset, size, read_at(self.raw, offset, size)
    ).get_instructions():
        yield i

fix_checksums(buff) #

Fix a dex format buffer by setting all checksums

Returns:

Type Description
bytes

bytes

Source code in androguard/core/dex/__init__.py
def fix_checksums(self, buff: bytes) -> bytes:
    """
    Fix a dex format buffer by setting all checksums

    :returns: bytes
    """

    signature = hashlib.sha1(buff[32:]).digest()

    buff = buff[:12] + signature + buff[32:]
    checksum = zlib.adler32(buff[12:])
    buff = buff[:8] + self.CM.packer["I"].pack(checksum) + buff[12:]

    logger.debug("NEW SIGNATURE %s" % repr(signature))
    logger.debug("NEW CHECKSUM %x" % checksum)

    return buff

get_api_version() #

This method returns api version that should be used for loading api specific resources.

Returns:

Type Description
int

api version string

Source code in androguard/core/dex/__init__.py
def get_api_version(self) -> int:
    """
    This method returns api version that should be used for loading api
    specific resources.

    :returns: api version string
    """
    return self.api_version

get_class(name) #

Return a specific class

Parameters:

Name Type Description Default
name str

the name of the class

required

Returns:

Type Description
Union[ClassDefItem, None]

a ClassDefItem

Source code in androguard/core/dex/__init__.py
def get_class(self, name: str) -> Union[ClassDefItem, None]:
    """
    Return a specific class

    :param name: the name of the class

    :returns: a `ClassDefItem`
    """
    for i in self.get_classes():
        if i.get_name() == name:
            return i
    return None

get_class_manager() #

This function returns a ClassManager object which allow you to get access to all index references (strings, methods, fields, ....)

Returns:

Type Description
ClassManager

ClassManager object

Source code in androguard/core/dex/__init__.py
def get_class_manager(self) -> ClassManager:
    """
    This function returns a ClassManager object which allow you to get
    access to all index references (strings, methods, fields, ....)

    :returns: `ClassManager` object
    """
    return self.CM

get_classes() #

Return all classes

Returns:

Type Description
list[ClassDefItem]

a list of ClassDefItem objects

Source code in androguard/core/dex/__init__.py
def get_classes(self) -> list[ClassDefItem]:
    """
    Return all classes

    :returns: a list of `ClassDefItem` objects
    """
    if self.classes:
        return self.classes.class_def
    else:
        # There is a rare case that the DEX has no classes
        return []

get_classes_def_item() #

This function returns the class def item

Returns:

Type Description
ClassHDefItem

ClassHDefItem object

Source code in androguard/core/dex/__init__.py
def get_classes_def_item(self) -> ClassHDefItem:
    """
    This function returns the class def item

    :returns: `ClassHDefItem` object
    """
    return self.classes

get_classes_names(update=False) #

Return the names of classes

Parameters:

Name Type Description Default
update bool

True indicates to recompute the list. Maybe needed after using a MyClass.set_name().

False

Returns:

Type Description
list[str]

a list of string names

Source code in androguard/core/dex/__init__.py
def get_classes_names(self, update: bool = False) -> list[str]:
    """
    Return the names of classes

    :param update: `True` indicates to recompute the list. Maybe needed after using a MyClass.set_name().
    :returns: a list of string names
    """
    if self.classes_names is None or update:
        self.classes_names = [i.get_name() for i in self.get_classes()]
    return self.classes_names

get_cm_field(idx) #

Get a specific field by using an index

Parameters:

Name Type Description Default
idx int

index of the field

required
Source code in androguard/core/dex/__init__.py
def get_cm_field(self, idx: int) -> list[str]:
    """
    Get a specific field by using an index

    :param idx: index of the field
    """
    return self.CM.get_field(idx)

get_cm_method(idx) #

Get a specific method by using an index

Parameters:

Name Type Description Default
idx int

index of the method

required
Source code in androguard/core/dex/__init__.py
def get_cm_method(self, idx: int) -> list[str]:
    """
    Get a specific method by using an index

    :param idx: index of the method
    """
    return self.CM.get_method(idx)

get_cm_string(idx) #

Get a specific string by using an index

Parameters:

Name Type Description Default
idx int

index of the string

required

Returns:

Type Description
str

the string

Source code in androguard/core/dex/__init__.py
def get_cm_string(self, idx: int) -> str:
    """
    Get a specific string by using an index

    :param idx: index of the string

    :returns: the string
    """
    return self.CM.get_raw_string(idx)

get_cm_type(idx) #

Get a specific type by using an index

Parameters:

Name Type Description Default
idx int

index of the type

required

Returns:

Type Description
str

the string type

Source code in androguard/core/dex/__init__.py
def get_cm_type(self, idx: int) -> str:
    """
    Get a specific type by using an index

    :param idx: index of the type

    :returns: the string type
    """
    return self.CM.get_type(idx)

get_codes_item() #

This function returns the code item

Returns:

Type Description
CodeItem

CodeItem object

Source code in androguard/core/dex/__init__.py
def get_codes_item(self) -> CodeItem:
    """
    This function returns the code item

    :returns: `CodeItem` object
    """
    return self.codes

get_debug_info_item() #

This function returns the debug info item

Returns:

Type Description
DebugInfoItemEmpty

DebugInfoItemEmpty object

Source code in androguard/core/dex/__init__.py
def get_debug_info_item(self) -> DebugInfoItemEmpty:
    """
    This function returns the debug info item
    :returns: `DebugInfoItemEmpty` object
    """
    return self.debug

get_encoded_field(name) #

Return a list all fields which corresponds to the regexp

Parameters:

Name Type Description Default
name str

the name of the field (a python string regexp)

required

Returns:

Type Description
list[EncodedField]

a list with all EncodedField objects

Source code in androguard/core/dex/__init__.py
def get_encoded_field(self, name: str) -> list[EncodedField]:
    """
    Return a list all fields which corresponds to the regexp

    :param name: the name of the field (a python string regexp)

    :returns: a list with all `EncodedField` objects
    """
    # TODO could use a generator here
    prog = re.compile(name)
    l = []
    for i in self.get_encoded_fields():
        if prog.match(i.get_name()):
            l.append(i)
    return l

get_encoded_field_descriptor(class_name, field_name, descriptor) #

Return the specific encoded field given a class name, field name, and descriptor

Parameters:

Name Type Description Default
class_name str

the class name of the field

required
field_name str

the name of the field

required
descriptor str

the descriptor of the field

required

Returns:

Type Description
EncodedField

None or a EncodedField object

Source code in androguard/core/dex/__init__.py
def get_encoded_field_descriptor(
    self, class_name: str, field_name: str, descriptor: str
) -> EncodedField:
    """
    Return the specific encoded field given a class name, field name, and descriptor

    :param class_name: the class name of the field
    :param field_name: the name of the field
    :param descriptor: the descriptor of the field

    :returns: `None` or a `EncodedField` object
    """

    key = class_name + field_name + descriptor

    if self.__cache_fields is None:
        self.__cache_fields = {}
        for i in self.get_classes():
            for j in i.get_fields():
                self.__cache_fields[
                    j.get_class_name() + j.get_name() + j.get_descriptor()
                ] = j

    return self.__cache_fields.get(key)

get_encoded_fields() #

Return all field objects

Returns:

Type Description
list[EncodedField]

a list of EncodedField objects

Source code in androguard/core/dex/__init__.py
def get_encoded_fields(self) -> list[EncodedField]:
    """
    Return all field objects

    :returns: a list of `EncodedField` objects
    """
    if self.__cache_all_fields is None:
        self.__cache_all_fields = []
        for i in self.get_classes():
            for j in i.get_fields():
                self.__cache_all_fields.append(j)
    return self.__cache_all_fields

get_encoded_fields_class(class_name) #

Return all encoded fields of a specific class by class name

Parameters:

Name Type Description Default
class_name str

the class name

required

Returns:

Type Description
list[EncodedField]

a list with EncodedField objects

Source code in androguard/core/dex/__init__.py
def get_encoded_fields_class(self, class_name: str) -> list[EncodedField]:
    """
    Return all encoded fields of a specific class by class name

    :param class_name: the class name

    :returns: a list with `EncodedField` objects
    """
    l = []
    for i in self.get_encoded_fields():
        if class_name == i.get_class_name():
            l.append(i)
    return l

get_encoded_method(name) #

Return a list all encoded methods whose name corresponds to the regexp

Parameters:

Name Type Description Default
name str

the name of the method (a python string regexp)

required

Returns:

Type Description
list[EncodedMethod]

a list with all EncodedMethod objects

Source code in androguard/core/dex/__init__.py
def get_encoded_method(self, name: str) -> list[EncodedMethod]:
    """
    Return a list all encoded methods whose name corresponds to the regexp

    :param name: the name of the method (a python string regexp)

    :returns: a list with all `EncodedMethod` objects
    """
    prog = re.compile(name)
    l = []
    for i in self.get_encoded_methods():
        if prog.match(i.name):
            l.append(i)
    return l

get_encoded_method_by_idx(idx) #

Return a specific encoded method by using an index

Parameters:

Name Type Description Default
idx int

the index of the method

required

Returns:

Type Description
Union[EncodedMethod, None]

None or an EncodedMethod object

Source code in androguard/core/dex/__init__.py
def get_encoded_method_by_idx(
    self, idx: int
) -> Union[EncodedMethod, None]:
    """
    Return a specific encoded method by using an index
    :param idx: the index of the method

    :returns: `None` or an `EncodedMethod` object
    """
    if self.__cached_methods_idx is None:
        self.__cached_methods_idx = {}
        for i in self.get_classes():
            for j in i.get_methods():
                self.__cached_methods_idx[j.get_method_idx()] = j

    try:
        return self.__cached_methods_idx[idx]
    except KeyError:
        return None

get_encoded_method_descriptor(class_name, method_name, descriptor) #

Return the specific encoded method given a class name, method name, and descriptor

Parameters:

Name Type Description Default
class_name str

the class name of the method

required
method_name str

the name of the method

required
descriptor str

the descriptor of the method

required

Returns:

Type Description
Union[EncodedMethod, None]

None or a EncodedMethod object

Source code in androguard/core/dex/__init__.py
def get_encoded_method_descriptor(
    self, class_name: str, method_name: str, descriptor: str
) -> Union[EncodedMethod, None]:
    """
    Return the specific encoded method given a class name, method name, and descriptor

    :param class_name: the class name of the method
    :param method_name: the name of the method
    :param descriptor: the descriptor of the method

    :returns: `None` or a `EncodedMethod` object
    """
    key = class_name + method_name + descriptor

    if self.__cache_methods is None:
        self.__cache_methods = {}
        for i in self.get_classes():
            for j in i.get_methods():
                self.__cache_methods[
                    j.get_class_name() + j.get_name() + j.get_descriptor()
                ] = j

    return self.__cache_methods.get(key)

get_encoded_methods() #

Return all encoded method objects

Returns:

Type Description
list[EncodedMethod]

a list of EncodedMethod objects

Source code in androguard/core/dex/__init__.py
def get_encoded_methods(self) -> list[EncodedMethod]:
    """
    Return all encoded method objects

    :returns: a list of `EncodedMethod` objects
    """
    if self.__cache_all_methods is None:
        self.__cache_all_methods = []
        for i in self.get_classes():
            for j in i.get_methods():
                self.__cache_all_methods.append(j)
    return self.__cache_all_methods

get_encoded_methods_class(class_name) #

Return all encoded methods of a specific class by class name

Parameters:

Name Type Description Default
class_name str

the class name

required

Returns:

Type Description
list[EncodedMethod]

a list with EncodedMethod objects

Source code in androguard/core/dex/__init__.py
def get_encoded_methods_class(
    self, class_name: str
) -> list[EncodedMethod]:
    """
    Return all encoded methods of a specific class by class name

    :param class_name: the class name

    :returns: a list with `EncodedMethod` objects
    """
    l = []
    for i in self.get_encoded_methods():
        if class_name == i.get_class_name():
            l.append(i)
    return l

get_encoded_methods_class_method(class_name, method_name) #

Return the specific encoded methods of the class

Parameters:

Name Type Description Default
class_name str

the class name of the method

required
method_name str

the name of the method

required

Returns:

Type Description
Union[EncodedMethod, None]

None or a EncodedMethod object

Source code in androguard/core/dex/__init__.py
def get_encoded_methods_class_method(
    self, class_name: str, method_name: str
) -> Union[EncodedMethod, None]:
    """
    Return the specific encoded methods of the class

    :param class_name: the class name of the method
    :param method_name: the name of the method

    :returns: `None` or a `EncodedMethod` object
    """
    for i in self.get_encoded_methods():
        if (
            i.get_name() == method_name
            and i.get_class_name() == class_name
        ):
            return i
    return None

get_field(name) #

get field id item by name

Parameters:

Name Type Description Default
name str

the name of the field (a python string regexp)

required

Returns:

Type Description
list[FieldIdItem]

the list of matching FieldIdItem objects

Source code in androguard/core/dex/__init__.py
def get_field(self, name: str) -> list[FieldIdItem]:
    """get field id item by name

    :param name: the name of the field (a python string regexp)
    :returns: the list of matching `FieldIdItem` objects
    """
    prog = re.compile(name)
    l = []
    for i in self.get_fields():
        if prog.match(i.name):
            l.append(i)
    return l

get_fields() #

Return a list of field items

Returns:

Type Description
list[FieldIdItem]

a list of FieldIdItem objects

Source code in androguard/core/dex/__init__.py
def get_fields(self) -> list[FieldIdItem]:
    """
    Return a list of field items

    :returns: a list of `FieldIdItem` objects
    """
    try:
        return self.fields.gets()
    except AttributeError:
        return []

get_fields_id_item() #

This function returns the field id item

Returns:

Type Description
FieldHIdItem

FieldHIdItem object

Source code in androguard/core/dex/__init__.py
def get_fields_id_item(self) -> FieldHIdItem:
    """
    This function returns the field id item

    :returns: `FieldHIdItem` object
    """
    return self.fields

get_format_type() #

Return the type

Returns:

Type Description
str

a string

Source code in androguard/core/dex/__init__.py
def get_format_type(self) -> str:
    """
    Return the type

    :returns: a string
    """
    return "DEX"

get_header_item() #

This function returns the header item

Returns:

Type Description
HeaderItem

HeaderItem object

Source code in androguard/core/dex/__init__.py
def get_header_item(self) -> HeaderItem:
    """
    This function returns the header item

    :returns: `HeaderItem` object
    """
    return self.header

get_hidden_api() #

This function returns the hidden api item (from Android 10)

Returns:

Type Description
HiddenApiClassDataItem

HiddenApiClassDataItem object

Source code in androguard/core/dex/__init__.py
def get_hidden_api(self) -> HiddenApiClassDataItem:
    """
    This function returns the hidden api item (from Android 10)

    :returns: `HiddenApiClassDataItem` object
    """
    return self.hidden_api

get_len_classes() #

Return the number of classes

Returns:

Type Description
int

int

Source code in androguard/core/dex/__init__.py
def get_len_classes(self) -> int:
    """
    Return the number of classes

    :returns: int
    """
    return len(self.get_classes())

get_len_encoded_methods() #

Return the number of encoded methods

Returns:

Type Description
int

int

Source code in androguard/core/dex/__init__.py
def get_len_encoded_methods(self) -> int:
    """
    Return the number of encoded methods

    :returns: int
    """
    return len(self.get_encoded_methods())

get_len_fields() #

Return the number of fields

Returns:

Type Description
int

int

Source code in androguard/core/dex/__init__.py
def get_len_fields(self) -> int:
    """
    Return the number of fields

    :returns: int
    """
    return len(self.get_fields())

get_len_methods() #

Return the number of methods

Returns:

Type Description
int

int

Source code in androguard/core/dex/__init__.py
def get_len_methods(self) -> int:
    """
    Return the number of methods

    :returns: int
    """
    return len(self.get_methods())

get_len_strings() #

Return the number of strings

Returns:

Type Description
int

int

Source code in androguard/core/dex/__init__.py
def get_len_strings(self) -> int:
    """
    Return the number of strings

    :returns: int
    """
    return len(self.get_strings())

get_method(name) #

get method id item by name

Parameters:

Name Type Description Default
name str

the name of the field (a python string regexp)

required

Returns:

Type Description
list[MethodIdItem]

the list of matching MethodIdItem objects

Source code in androguard/core/dex/__init__.py
def get_method(self, name: str) -> list[MethodIdItem]:
    """get method id item by name

    :param name: the name of the field (a python string regexp)
    :returns: the list of matching `MethodIdItem` objects
    """
    prog = re.compile(name)
    l = []
    for i in self.get_methods():
        if prog.match(i.name):
            l.append(i)
    return l

get_methods() #

Return a list of method items

Returns:

Type Description
list[MethodIdItem]

a list of MethodIdItem objects

Source code in androguard/core/dex/__init__.py
def get_methods(self) -> list[MethodIdItem]:
    """
    Return a list of method items

    :returns: a list of `MethodIdItem` objects
    """
    try:
        return self.methods.gets()
    except AttributeError:
        return []

get_methods_id_item() #

This function returns the method id item

Returns:

Type Description
MethodHIdItem

MethodHIdItem object

Source code in androguard/core/dex/__init__.py
def get_methods_id_item(self) -> MethodHIdItem:
    """
    This function returns the method id item

    :returns: `MethodHIdItem` object
    """
    return self.methods

get_regex_strings(regular_expressions) #

Return all target strings matched the regex

Parameters:

Name Type Description Default
regular_expressions str

the python regex string

required

Returns:

Type Description
Union[list[str], None]

a list of strings matching the regex expression

Source code in androguard/core/dex/__init__.py
def get_regex_strings(
    self, regular_expressions: str
) -> Union[list[str], None]:
    """
    Return all target strings matched the regex

    :param regular_expressions: the python regex string

    :returns: a list of strings matching the regex expression
    """
    str_list = []
    if regular_expressions.count is None:
        return None
    for i in self.get_strings():
        if re.match(regular_expressions, i):
            str_list.append(i)
    return str_list

get_string_data_item() #

This function returns the string data item

Returns:

Type Description
StringDataItem

StringDataItem object

Source code in androguard/core/dex/__init__.py
def get_string_data_item(self) -> StringDataItem:
    """
    This function returns the string data item

    :returns: `StringDataItem` object
    """
    return self.strings

get_strings() #

Return all strings

The strings will have escaped surrogates, if only a single high or low surrogate is found. Complete surrogates are put together into the representing 32bit character.

Returns:

Type Description
list[str]

a list with all strings used in the format (types, names ...)

Source code in androguard/core/dex/__init__.py
def get_strings(self) -> list[str]:
    """
    Return all strings

    The strings will have escaped surrogates, if only a single high or low surrogate is found.
    Complete surrogates are put together into the representing 32bit character.

    :returns: a list with all strings used in the format (types, names ...)
    """
    return (
        [i.get() for i in self.strings] if self.strings is not None else []
    )

list_classes_hierarchy() #

Get a tree structure of the classes. The parent is always the superclass.

You can use pprint.pprint to print the dictionary in a pretty way.

Returns:

Type Description
dict[str, list[dict[str, list]]]

a tree in dictionary format where the key is the class name and the value is a list of dictionaries containing a child class name as a key and subsequent child classes as a value list

Source code in androguard/core/dex/__init__.py
def list_classes_hierarchy(self) -> dict[str, list[dict[str, list]]]:
    """
    Get a tree structure of the classes.
    The parent is always the superclass.

    You can use `pprint.pprint` to print the
    dictionary in a pretty way.

    :returns: a tree in dictionary format where the key is the class name and the value is a list of dictionaries containing a child class name as a key and subsequent child classes as a value list
    """

    def print_map(node, l):
        if node.title not in l:
            l[node.title] = []

        for n in node.children:
            if len(n.children) > 0:
                w = {n.title: []}
                l[node.title].append(w)

                print_map(n, w)
            else:
                l[node.title].append(n.title)

    l = {}
    print_map(self._get_class_hierarchy(), l)

    return l

save() #

Return the dex (with the modifications) into raw format (fix checksums) (beta: do not use !)

Returns:

Type Description
bytes

bytes

Source code in androguard/core/dex/__init__.py
def save(self) -> bytes:
    """
    Return the dex (with the modifications) into raw format (fix checksums)
    (beta: do not use !)

    :returns: bytes
    """
    l = []
    h = {}
    s = {}
    h_r = {}

    idx = 0
    for i in self.map_list.get_obj():
        length = 0

        if isinstance(i, list):
            for j in i:
                if isinstance(j, AnnotationsDirectoryItem):
                    if idx % 4 != 0:
                        idx = idx + (4 - (idx % 4))

                l.append(j)

                c_length = j.get_length()
                if isinstance(j, StringDataItem):
                    c_length += 1
                h[j] = idx + length
                h_r[idx + length] = j
                s[idx + length] = c_length

                length += c_length
                # logger.debug("SAVE" + str(j) + " @ 0x%x" % (idx+length))

            logger.debug(
                "SAVE " + str(i[0]) + " @0x{:x} ({:x})".format(idx, length)
            )

        else:
            if isinstance(i, MapList):
                if idx % 4 != 0:
                    idx = idx + (4 - (idx % 4))

            l.append(i)
            h[i] = idx
            h_r[idx] = i

            length = i.get_length()

            s[idx] = length

            logger.debug(
                "SAVE " + str(i) + " @0x{:x} ({:x})".format(idx, length)
            )

        idx += length

    self.header.file_size = idx

    for i in l:
        idx = h[i]
        i.set_off(idx)
        if isinstance(i, CodeItem):
            last_idx = idx
            for j in i.get_obj():
                j.set_off(last_idx)
                # j.set_debug_info_off(0)
                last_idx += j.get_size()

    last_idx = 0
    buff = bytearray()
    for i in l:
        idx = h[i]

        if idx != last_idx:
            logger.debug(
                "Adjust alignment @{:x} with 00 {:x}".format(
                    idx, idx - last_idx
                )
            )
            buff += bytearray([0] * (idx - last_idx))

        buff += i.get_raw()
        if isinstance(i, StringDataItem):
            buff += b"\x00"
        last_idx = idx + s[idx]

    logger.debug("GLOBAL SIZE %d" % len(buff))

    return self.fix_checksums(buff)

show() #

Show the all information in the object

Source code in androguard/core/dex/__init__.py
def show(self) -> None:
    """
    Show the all information in the object
    """
    self.map_list.show()

DalvikCode #

This class represents the instructions of a method

Parameters:

Name Type Description Default
buff BinaryIO

a raw buffer where are the instructions

required
cm ClassManager

the ClassManager

required
Source code in androguard/core/dex/__init__.py
class DalvikCode:
    """
    This class represents the instructions of a method

    :param buff: a raw buffer where are the instructions
    :param cm: the `ClassManager`
    """

    def __init__(self, buff: BinaryIO, cm: ClassManager) -> None:
        self.CM = cm
        self.offset = buff.tell()

        (
            self.registers_size,
            self.ins_size,
            self.outs_size,
            self.tries_size,
            self.debug_info_off,
            self.insns_size,
        ) = cm.packer["4H2I"].unpack(buff.read(16))

        ushort = calcsize('H')

        self.code = DCode(
            self.CM,
            buff.tell(),
            self.insns_size,
            buff.read(self.insns_size * ushort),
        )

        if self.insns_size % 2 == 1 and self.tries_size > 0:
            (self.padding,) = cm.packer["H"].unpack(buff.read(2))

        self.tries = []
        self.handlers = None
        if self.tries_size > 0:
            for i in range(0, self.tries_size):
                self.tries.append(TryItem(buff, self.CM))

            self.handlers = EncodedCatchHandlerList(buff, self.CM)

    def get_registers_size(self) -> int:
        """
        Get the number of registers used by this code

        :returns: number of registers
        """
        return self.registers_size

    def get_ins_size(self) -> int:
        """
        Get the number of words of incoming arguments to the method that this code is for

        :returns: number of words
        """
        return self.ins_size

    def get_outs_size(self) -> int:
        """
        Get the number of words of outgoing argument space required by this code for method invocation

        :returns: number of words
        """
        return self.outs_size

    def get_tries_size(self) -> int:
        """
        Get the number of [TryItem][androguard.core.dex.TryItem] for this instance

        :returns: number of `TryItem`
        """
        return self.tries_size

    def get_debug_info_off(self) -> int:
        """
        Get the offset from the start of the file to the debug info (line numbers + local variable info) sequence for this code, or 0 if there simply is no information

        :returns: offset int
        """
        return self.debug_info_off

    def get_insns_size(self) -> int:
        """
        Get the size of the instructions list, in 16-bit code units

        :returns: size int
        """
        return self.insns_size

    def get_handlers(self) -> EncodedCatchHandlerList:
        """
        Get the bytes representing a list of lists of catch types and associated handler addresses.

        :returns: `EncodedCatchHandlerList` object
        """
        return self.handlers

    def get_tries(self) -> list[TryItem]:
        """
        Get the array indicating where in the code exceptions are caught and how to handle them

        :returns: a list of `TryItem` objects
        """
        return self.tries

    def get_debug(self) -> DebugInfoItem:
        """
        Return the associated debug object

        :returns: `DebugInfoItem` object
        """
        return self.CM.get_debug_off(self.debug_info_off)

    def get_bc(self) -> DCode:
        """
        Return the associated code object

        :returns: `DCode` object
        """
        return self.code

    def seek(self, idx: int) -> None:
        self.code.seek(idx)

    def get_length(self) -> int:
        return self.insns_size

    def _begin_show(self) -> None:
        logger.debug("registers_size: %d" % self.registers_size)
        logger.debug("ins_size: %d" % self.ins_size)
        logger.debug("outs_size: %d" % self.outs_size)
        logger.debug("tries_size: %d" % self.tries_size)
        logger.debug("debug_info_off: %d" % self.debug_info_off)
        logger.debug("insns_size: %d" % self.insns_size)

        bytecode._PrintBanner()

    def show(self) -> None:
        self._begin_show()
        self.code.show()
        self._end_show()

    def _end_show(self) -> None:
        bytecode._PrintBanner()

    def get_obj(self) -> tuple[DCode, list[TryItem], EncodedCatchHandlerList]:
        return [self.code, self.tries, self.handlers]

    def get_raw(self) -> bytearray:
        """
        Get the reconstructed code as bytearray

        :returns: code bytearray
        """
        code_raw = self.code.get_raw()
        self.insns_size = (len(code_raw) // 2) + (len(code_raw) % 2)

        buff = bytearray()
        buff += (
            self.CM.packer["4H2I"].pack(
                self.registers_size,
                self.ins_size,
                self.outs_size,
                self.tries_size,
                self.debug_info_off,
                self.insns_size,
            )
            + code_raw
        )

        if self.tries_size > 0:
            if self.insns_size % 2 == 1:
                buff += self.CM.packer["H"].pack(self.padding)

            for i in self.tries:
                buff += i.get_raw()
            buff += self.handlers.get_raw()

        return buff

    def add_inote(self, msg: str, idx: int, off: int = None) -> None:
        """
        Add a message to a specific instruction by using (default) the index of the address if specified

        :param msg: the message
        :param idx: index of the instruction (the position in the list of the instruction)
        :param off: address of the instruction
        """
        if self.code:
            return self.code.add_inote(msg, idx, off)

    def get_instruction(
        self, idx: int, off: Union[int, None] = None
    ) -> Instruction:
        if self.code:
            return self.code.get_instruction(idx, off)

    def get_size(self) -> int:
        return len(self.get_raw())

    def set_off(self, off: int) -> None:
        self.offset = off

    def get_off(self) -> int:
        return self.offset

add_inote(msg, idx, off=None) #

Add a message to a specific instruction by using (default) the index of the address if specified

Parameters:

Name Type Description Default
msg str

the message

required
idx int

index of the instruction (the position in the list of the instruction)

required
off int

address of the instruction

None
Source code in androguard/core/dex/__init__.py
def add_inote(self, msg: str, idx: int, off: int = None) -> None:
    """
    Add a message to a specific instruction by using (default) the index of the address if specified

    :param msg: the message
    :param idx: index of the instruction (the position in the list of the instruction)
    :param off: address of the instruction
    """
    if self.code:
        return self.code.add_inote(msg, idx, off)

get_bc() #

Return the associated code object

Returns:

Type Description
DCode

DCode object

Source code in androguard/core/dex/__init__.py
def get_bc(self) -> DCode:
    """
    Return the associated code object

    :returns: `DCode` object
    """
    return self.code

get_debug() #

Return the associated debug object

Returns:

Type Description
DebugInfoItem

DebugInfoItem object

Source code in androguard/core/dex/__init__.py
def get_debug(self) -> DebugInfoItem:
    """
    Return the associated debug object

    :returns: `DebugInfoItem` object
    """
    return self.CM.get_debug_off(self.debug_info_off)

get_debug_info_off() #

Get the offset from the start of the file to the debug info (line numbers + local variable info) sequence for this code, or 0 if there simply is no information

Returns:

Type Description
int

offset int

Source code in androguard/core/dex/__init__.py
def get_debug_info_off(self) -> int:
    """
    Get the offset from the start of the file to the debug info (line numbers + local variable info) sequence for this code, or 0 if there simply is no information

    :returns: offset int
    """
    return self.debug_info_off

get_handlers() #

Get the bytes representing a list of lists of catch types and associated handler addresses.

Returns:

Type Description
EncodedCatchHandlerList

EncodedCatchHandlerList object

Source code in androguard/core/dex/__init__.py
def get_handlers(self) -> EncodedCatchHandlerList:
    """
    Get the bytes representing a list of lists of catch types and associated handler addresses.

    :returns: `EncodedCatchHandlerList` object
    """
    return self.handlers

get_ins_size() #

Get the number of words of incoming arguments to the method that this code is for

Returns:

Type Description
int

number of words

Source code in androguard/core/dex/__init__.py
def get_ins_size(self) -> int:
    """
    Get the number of words of incoming arguments to the method that this code is for

    :returns: number of words
    """
    return self.ins_size

get_insns_size() #

Get the size of the instructions list, in 16-bit code units

Returns:

Type Description
int

size int

Source code in androguard/core/dex/__init__.py
def get_insns_size(self) -> int:
    """
    Get the size of the instructions list, in 16-bit code units

    :returns: size int
    """
    return self.insns_size

get_outs_size() #

Get the number of words of outgoing argument space required by this code for method invocation

Returns:

Type Description
int

number of words

Source code in androguard/core/dex/__init__.py
def get_outs_size(self) -> int:
    """
    Get the number of words of outgoing argument space required by this code for method invocation

    :returns: number of words
    """
    return self.outs_size

get_raw() #

Get the reconstructed code as bytearray

Returns:

Type Description
bytearray

code bytearray

Source code in androguard/core/dex/__init__.py
def get_raw(self) -> bytearray:
    """
    Get the reconstructed code as bytearray

    :returns: code bytearray
    """
    code_raw = self.code.get_raw()
    self.insns_size = (len(code_raw) // 2) + (len(code_raw) % 2)

    buff = bytearray()
    buff += (
        self.CM.packer["4H2I"].pack(
            self.registers_size,
            self.ins_size,
            self.outs_size,
            self.tries_size,
            self.debug_info_off,
            self.insns_size,
        )
        + code_raw
    )

    if self.tries_size > 0:
        if self.insns_size % 2 == 1:
            buff += self.CM.packer["H"].pack(self.padding)

        for i in self.tries:
            buff += i.get_raw()
        buff += self.handlers.get_raw()

    return buff

get_registers_size() #

Get the number of registers used by this code

Returns:

Type Description
int

number of registers

Source code in androguard/core/dex/__init__.py
def get_registers_size(self) -> int:
    """
    Get the number of registers used by this code

    :returns: number of registers
    """
    return self.registers_size

get_tries() #

Get the array indicating where in the code exceptions are caught and how to handle them

Returns:

Type Description
list[TryItem]

a list of TryItem objects

Source code in androguard/core/dex/__init__.py
def get_tries(self) -> list[TryItem]:
    """
    Get the array indicating where in the code exceptions are caught and how to handle them

    :returns: a list of `TryItem` objects
    """
    return self.tries

get_tries_size() #

Get the number of TryItem for this instance

Returns:

Type Description
int

number of TryItem

Source code in androguard/core/dex/__init__.py
def get_tries_size(self) -> int:
    """
    Get the number of [TryItem][androguard.core.dex.TryItem] for this instance

    :returns: number of `TryItem`
    """
    return self.tries_size

DalvikPacker #

Generic Packer class to unpack bytes based on different endianness

Source code in androguard/core/dex/__init__.py
class DalvikPacker:
    """
    Generic Packer class to unpack bytes based on different endianness
    """

    def __init__(self, endian_tag: int) -> None:
        if endian_tag == 0x78563412:
            logger.error(
                "DEX file with byte swapped endian tag is not supported!"
            )
            raise NotImplementedError("Byte swapped endian tag encountered!")
        elif endian_tag == 0x12345678:
            self.endian_tag = '<'
        else:
            raise ValueError(
                "This is not a DEX file! Wrong endian tag: '0x{:08x}'".format(
                    endian_tag
                )
            )
        self.__structs = {}

    def __getitem__(self, item):
        try:
            return self.__structs[item]
        except KeyError:
            self.__structs[item] = struct.Struct(self.endian_tag + item)
        return self.__structs[item]

    def __getstate__(self):
        return self.endian_tag

    def __setstate__(self, state):
        self.endian_tag = state
        self.__structs = {}

EncodedAnnotation #

This class can parse an encoded_annotation of a dex file

Source code in androguard/core/dex/__init__.py
class EncodedAnnotation:
    """
    This class can parse an `encoded_annotation` of a dex file
    """

    def __init__(self, buff: BinaryIO, cm:ClassManager) -> None:
        """
        :param buff: a string which represents a Buff object of the `encoded_annotation`
        :param cm: a `ClassManager` object
        """
        self.CM = cm
        self.offset = buff.tell()

        self.type_idx = readuleb128(cm, buff)
        self.size = readuleb128(cm, buff)

        self.elements = [AnnotationElement(buff, cm) for _ in range(self.size)]

    def get_type_idx(self):
        """
        Return the type of the annotation. This must be a class (not array or primitive) type

        :returns: the type of the annotation
        """
        return self.type_idx

    def get_size(self):
        """
        Return the number of name-value mappings in this annotation

        :returns: the number of mappings
        """
        return self.size

    def get_elements(self):
        """
        Return the elements of the annotation, represented directly in-line (not as offsets)

        :returns: a list of `AnnotationElement` objects
        """
        return self.elements

    def show(self):
        bytecode._PrintSubBanner("Encoded Annotation")
        bytecode._PrintDefault(
            "type_idx=%d size=%d\n" % (self.type_idx, self.size)
        )

        for i in self.elements:
            i.show()

    def get_obj(self):
        return [i for i in self.elements]

    def get_raw(self):
        return (
            writeuleb128(self.CM, self.type_idx)
            + writeuleb128(self.CM, self.size)
            + b''.join(i.get_raw() for i in self.elements)
        )

    def get_length(self):
        length = len(
            writeuleb128(self.CM, self.type_idx)
            + writeuleb128(self.CM, self.size)
        )

        for i in self.elements:
            length += i.get_length()

        return length

__init__(buff, cm) #

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the encoded_annotation

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
def __init__(self, buff: BinaryIO, cm:ClassManager) -> None:
    """
    :param buff: a string which represents a Buff object of the `encoded_annotation`
    :param cm: a `ClassManager` object
    """
    self.CM = cm
    self.offset = buff.tell()

    self.type_idx = readuleb128(cm, buff)
    self.size = readuleb128(cm, buff)

    self.elements = [AnnotationElement(buff, cm) for _ in range(self.size)]

get_elements() #

Return the elements of the annotation, represented directly in-line (not as offsets)

Returns:

Type Description

a list of AnnotationElement objects

Source code in androguard/core/dex/__init__.py
def get_elements(self):
    """
    Return the elements of the annotation, represented directly in-line (not as offsets)

    :returns: a list of `AnnotationElement` objects
    """
    return self.elements

get_size() #

Return the number of name-value mappings in this annotation

Returns:

Type Description

the number of mappings

Source code in androguard/core/dex/__init__.py
def get_size(self):
    """
    Return the number of name-value mappings in this annotation

    :returns: the number of mappings
    """
    return self.size

get_type_idx() #

Return the type of the annotation. This must be a class (not array or primitive) type

Returns:

Type Description

the type of the annotation

Source code in androguard/core/dex/__init__.py
def get_type_idx(self):
    """
    Return the type of the annotation. This must be a class (not array or primitive) type

    :returns: the type of the annotation
    """
    return self.type_idx

EncodedArray #

This class can parse an encoded_array of a dex file

Source code in androguard/core/dex/__init__.py
class EncodedArray:
    """
    This class can parse an `encoded_array` of a dex file
    """

    def __init__(self, buff: BinaryIO, cm:ClassManager) -> None:
        """
        :param buff: a string which represents a buff object of the `encoded_array`
        :param cm: a ClassManager object
        """
        self.CM = cm
        self.offset = buff.tell()

        self.size = readuleb128(cm, buff)

        self.values = [EncodedValue(buff, cm) for _ in range(self.size)]

    def get_size(self):
        """
        Return the number of elements in the array

        :returns: int
        """
        return self.size

    def get_values(self) -> list[EncodedValue]:
        """
        Return a series of size `encoded_value` byte sequences in the format specified by this section,
        concatenated sequentially

        :returns: a list of `EncodedValue` objects
        """
        return self.values

    def show(self):
        bytecode._PrintSubBanner("Encoded Array")
        bytecode._PrintDefault("size=%d\n" % self.size)

        for i in self.values:
            i.show()

    def get_obj(self):
        return writeuleb128(self.CM, self.size)

    def get_raw(self) -> bytes:
        return self.get_obj() + b''.join(i.get_raw() for i in self.values)

    def get_length(self):
        length = len(self.get_obj())
        for i in self.values:
            length += i.get_length()

        return length

__init__(buff, cm) #

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a buff object of the encoded_array

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
def __init__(self, buff: BinaryIO, cm:ClassManager) -> None:
    """
    :param buff: a string which represents a buff object of the `encoded_array`
    :param cm: a ClassManager object
    """
    self.CM = cm
    self.offset = buff.tell()

    self.size = readuleb128(cm, buff)

    self.values = [EncodedValue(buff, cm) for _ in range(self.size)]

get_size() #

Return the number of elements in the array

Returns:

Type Description

int

Source code in androguard/core/dex/__init__.py
def get_size(self):
    """
    Return the number of elements in the array

    :returns: int
    """
    return self.size

get_values() #

Return a series of size encoded_value byte sequences in the format specified by this section, concatenated sequentially

Returns:

Type Description
list[EncodedValue]

a list of EncodedValue objects

Source code in androguard/core/dex/__init__.py
def get_values(self) -> list[EncodedValue]:
    """
    Return a series of size `encoded_value` byte sequences in the format specified by this section,
    concatenated sequentially

    :returns: a list of `EncodedValue` objects
    """
    return self.values

EncodedArrayItem #

This class can parse an encoded_array_item of a dex file

Source code in androguard/core/dex/__init__.py
class EncodedArrayItem:
    """
    This class can parse an `encoded_array_item` of a dex file
    """

    def __init__(self, buff: BinaryIO, cm: ClassManager) -> None:
        """
        :param buff: a string which represents a Buff object of the `encoded_array_item`
        :param cm: a `ClassManager` object
        """
        self.CM = cm

        self.offset = buff.tell()
        self.value = EncodedArray(buff, cm)

    def get_value(self) -> EncodedArray:
        """
        Return the bytes representing the encoded array value

        :returns: a `EncodedArray` object
        """
        return self.value

    def set_off(self, off: int) -> None:
        self.offset = off

    def show(self) -> None:
        bytecode._PrintSubBanner("Encoded Array Item")
        self.value.show()

    def get_obj(self) -> list[EncodedArray]:
        return [self.value]

    def get_raw(self) -> bytes:
        return self.value.get_raw()

    def get_length(self) -> int:
        return self.value.get_length()

    def get_off(self) -> int:
        return self.offset

__init__(buff, cm) #

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the encoded_array_item

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
def __init__(self, buff: BinaryIO, cm: ClassManager) -> None:
    """
    :param buff: a string which represents a Buff object of the `encoded_array_item`
    :param cm: a `ClassManager` object
    """
    self.CM = cm

    self.offset = buff.tell()
    self.value = EncodedArray(buff, cm)

get_value() #

Return the bytes representing the encoded array value

Returns:

Type Description
EncodedArray

a EncodedArray object

Source code in androguard/core/dex/__init__.py
def get_value(self) -> EncodedArray:
    """
    Return the bytes representing the encoded array value

    :returns: a `EncodedArray` object
    """
    return self.value

EncodedCatchHandler #

This class can parse an encoded_catch_handler of a dex file

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the encoded_catch_handler

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
class EncodedCatchHandler:
    """
    This class can parse an `encoded_catch_handler` of a dex file

    :param buff: a string which represents a Buff object of the `encoded_catch_handler`
    :param cm: a `ClassManager` object
    """

    def __init__(self, buff: BinaryIO, cm: ClassManager) -> None:
        self.CM = cm
        self.offset = buff.tell()

        self.size = readsleb128(cm, buff)

        self.handlers = []

        for i in range(0, abs(self.size)):
            self.handlers.append(EncodedTypeAddrPair(cm, buff))

        if self.size <= 0:
            self.catch_all_addr = readuleb128(cm, buff)

    def get_size(self) -> int:
        """
        Return the number of catch types in this list

        :returns: the number of catch types
        """
        return self.size

    def get_handlers(self) -> list[EncodedTypeAddrPair]:
        """
        Return the stream of `abs(size)` encoded items, one for each caught type, in the order that the types should be tested.

        :returns: a list of `EncodedTypeAddrPair` objects
        """
        return self.handlers

    def get_catch_all_addr(self) -> int:
        """
        Return the bytecode address of the catch-all handler. This element is only present if size is non-positive.

        :returns: the bytecode address
        """
        return self.catch_all_addr

    def get_off(self) -> int:
        return self.offset

    def set_off(self, off: int) -> None:
        self.offset = off

    def show(self) -> None:
        bytecode._PrintSubBanner("Encoded Catch Handler")
        bytecode._PrintDefault("size=%d\n" % self.size)

        for i in self.handlers:
            i.show()

        if self.size <= 0:
            bytecode._PrintDefault("catch_all_addr=%x\n" % self.catch_all_addr)

    def get_raw(self) -> bytearray:
        buff = bytearray()
        buff += writesleb128(self.CM, self.size)
        for i in self.handlers:
            buff += i.get_raw()

        if self.size <= 0:
            buff += writeuleb128(self.CM, self.catch_all_addr)

        return buff

    def get_length(self) -> int:
        length = len(writesleb128(self.CM, self.size))

        for i in self.handlers:
            length += i.get_length()

        if self.size <= 0:
            length += len(writeuleb128(self.CM, self.catch_all_addr))

        return length

get_catch_all_addr() #

Return the bytecode address of the catch-all handler. This element is only present if size is non-positive.

Returns:

Type Description
int

the bytecode address

Source code in androguard/core/dex/__init__.py
def get_catch_all_addr(self) -> int:
    """
    Return the bytecode address of the catch-all handler. This element is only present if size is non-positive.

    :returns: the bytecode address
    """
    return self.catch_all_addr

get_handlers() #

Return the stream of abs(size) encoded items, one for each caught type, in the order that the types should be tested.

Returns:

Type Description
list[EncodedTypeAddrPair]

a list of EncodedTypeAddrPair objects

Source code in androguard/core/dex/__init__.py
def get_handlers(self) -> list[EncodedTypeAddrPair]:
    """
    Return the stream of `abs(size)` encoded items, one for each caught type, in the order that the types should be tested.

    :returns: a list of `EncodedTypeAddrPair` objects
    """
    return self.handlers

get_size() #

Return the number of catch types in this list

Returns:

Type Description
int

the number of catch types

Source code in androguard/core/dex/__init__.py
def get_size(self) -> int:
    """
    Return the number of catch types in this list

    :returns: the number of catch types
    """
    return self.size

EncodedCatchHandlerList #

This class can parse an encoded_catch_handler_list of a dex file

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the encoded_catch_handler_list

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
class EncodedCatchHandlerList:
    """
    This class can parse an `encoded_catch_handler_list` of a dex file

    :param buff: a string which represents a Buff object of the `encoded_catch_handler_list`
    :param cm: a `ClassManager` object
    """

    def __init__(self, buff: BinaryIO, cm: ClassManager) -> None:
        self.CM = cm
        self.offset = buff.tell()

        self.size = readuleb128(cm, buff)
        self.list = [EncodedCatchHandler(buff, cm) for _ in range(self.size)]

    def get_size(self) -> int:
        """
        Return the size of this list, in entries

        :returns: int
        """
        return self.size

    def get_list(self) -> list[EncodedCatchHandler]:
        """
        Return the actual list of handler lists, represented directly (not as offsets), and concatenated sequentially

        :returns: a list of `EncodedCatchHandler` objects
        """
        return self.list

    def show(self) -> None:
        bytecode._PrintSubBanner("Encoded Catch Handler List")
        bytecode._PrintDefault("size=%d\n" % self.size)

        for i in self.list:
            i.show()

    def get_off(self) -> int:
        return self.offset

    def set_off(self, off: int) -> None:
        self.offset = off

    def get_obj(self) -> bytearray:
        return writeuleb128(self.CM, self.size)

    def get_raw(self) -> bytearray:
        buff = bytearray()
        buff += self.get_obj()
        for i in self.list:
            buff += i.get_raw()
        return buff

    def get_length(self) -> int:
        length = len(self.get_obj())

        for i in self.list:
            length += i.get_length()
        return length

get_list() #

Return the actual list of handler lists, represented directly (not as offsets), and concatenated sequentially

Returns:

Type Description
list[EncodedCatchHandler]

a list of EncodedCatchHandler objects

Source code in androguard/core/dex/__init__.py
def get_list(self) -> list[EncodedCatchHandler]:
    """
    Return the actual list of handler lists, represented directly (not as offsets), and concatenated sequentially

    :returns: a list of `EncodedCatchHandler` objects
    """
    return self.list

get_size() #

Return the size of this list, in entries

Returns:

Type Description
int

int

Source code in androguard/core/dex/__init__.py
def get_size(self) -> int:
    """
    Return the size of this list, in entries

    :returns: int
    """
    return self.size

EncodedField #

This class can parse an encoded_field of a dex file

Source code in androguard/core/dex/__init__.py
class EncodedField:
    """
    This class can parse an `encoded_field` of a dex file
    """

    def __init__(self, buff: BinaryIO, cm:ClassManager) -> None:
        """
        :param buff: a string which represents a buff object of the `encoded_field`
        :param cm: a `ClassManager` object
        """
        self.CM = cm
        self.offset = buff.tell()

        self.field_idx_diff = readuleb128(cm, buff)
        self.access_flags = readuleb128(cm, buff)

        self.field_idx = 0

        self.name = None
        self.proto = None
        self.class_name = None

        self.init_value = None
        self.access_flags_string = None
        self.loaded = False

    def load(self) -> None:
        if self.loaded:
            return
        self.reload()
        self.loaded = True

    def reload(self) -> None:
        name = self.CM.get_field(self.field_idx)
        self.class_name = name[0]
        self.name = name[2]
        self.proto = name[1]

    def set_init_value(self, value: EncodedValue) -> None:
        """
        Setup the init value object of the field

        :param value: the init value
        """
        self.init_value = value

    def get_init_value(self) -> EncodedValue:
        """
        Return the init value object of the field

        :returns: an `EncodedValue` object
        """
        return self.init_value

    def adjust_idx(self, val: int) -> None:
        self.field_idx = self.field_idx_diff + val

    def get_field_idx_diff(self) -> int:
        """
        Return the index into the field_ids list for the identity of this field (includes the name and descriptor),
        represented as a difference from the index of previous element in the list

        :returns: the index
        """
        return self.field_idx_diff

    def get_field_idx(self) -> int:
        """
        Return the real index of the method

        :returns: the real index
        """
        return self.field_idx

    def get_access_flags(self) -> int:
        """
        Return the access flags of the field

        :returns: the access flags
        """
        return self.access_flags

    def get_class_name(self) -> str:
        """
        Return the class name of the field

        :returns: the class name
        """
        if not self.loaded:
            self.load()
        return self.class_name

    def get_descriptor(self) -> str:
        """
        Return the descriptor of the field

        The descriptor of a field is the type of the field.

        :returns: the descriptor
        """
        if not self.loaded:
            self.load()
        return self.proto

    def get_name(self) -> str:
        """
        Return the name of the field

        :returns: the name
        """
        if not self.loaded:
            self.load()
        return self.name

    def get_access_flags_string(self) -> str:
        """
        Return the access flags string of the field

        :returns: the access flags
        """
        if self.access_flags_string is None:
            if self.get_access_flags() == 0:
                # No access flags, i.e. Java defaults apply
                self.access_flags_string = ""
                return self.access_flags_string

            # Try to parse the string
            self.access_flags_string = get_access_flags_string(
                self.get_access_flags()
            )

            # Fallback for unknown strings
            if self.access_flags_string == "":
                self.access_flags_string = "0x{:06x}".format(
                    self.get_access_flags()
                )
        return self.access_flags_string

    def set_name(self, value: str) -> None:
        self.CM.set_hook_field_name(self, value)
        self.reload()

    def get_obj(self) -> list:
        return []

    def get_raw(self) -> bytes:
        return writeuleb128(self.CM, self.field_idx_diff) + writeuleb128(
            self.CM, self.access_flags
        )

    def get_size(self) -> bytes:
        return len(self.get_raw())

    def show(self) -> None:
        """
        Display the information (with a pretty print) about the field
        """
        bytecode._PrintSubBanner("Field Information")
        bytecode._PrintDefault(
            "{}->{} {} [access_flags={}]\n".format(
                self.get_class_name(),
                self.get_name(),
                self.get_descriptor(),
                self.get_access_flags_string(),
            )
        )

        init_value = self.get_init_value()
        if init_value is not None:
            bytecode._PrintDefault(
                "\tinit value: %s\n" % str(init_value.get_value())
            )

    def __str__(self):
        return "{}->{} {} [access_flags={}]\n".format(
            self.get_class_name(),
            self.get_name(),
            self.get_descriptor(),
            self.get_access_flags_string(),
        )

__init__(buff, cm) #

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a buff object of the encoded_field

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
def __init__(self, buff: BinaryIO, cm:ClassManager) -> None:
    """
    :param buff: a string which represents a buff object of the `encoded_field`
    :param cm: a `ClassManager` object
    """
    self.CM = cm
    self.offset = buff.tell()

    self.field_idx_diff = readuleb128(cm, buff)
    self.access_flags = readuleb128(cm, buff)

    self.field_idx = 0

    self.name = None
    self.proto = None
    self.class_name = None

    self.init_value = None
    self.access_flags_string = None
    self.loaded = False

get_access_flags() #

Return the access flags of the field

Returns:

Type Description
int

the access flags

Source code in androguard/core/dex/__init__.py
def get_access_flags(self) -> int:
    """
    Return the access flags of the field

    :returns: the access flags
    """
    return self.access_flags

get_access_flags_string() #

Return the access flags string of the field

Returns:

Type Description
str

the access flags

Source code in androguard/core/dex/__init__.py
def get_access_flags_string(self) -> str:
    """
    Return the access flags string of the field

    :returns: the access flags
    """
    if self.access_flags_string is None:
        if self.get_access_flags() == 0:
            # No access flags, i.e. Java defaults apply
            self.access_flags_string = ""
            return self.access_flags_string

        # Try to parse the string
        self.access_flags_string = get_access_flags_string(
            self.get_access_flags()
        )

        # Fallback for unknown strings
        if self.access_flags_string == "":
            self.access_flags_string = "0x{:06x}".format(
                self.get_access_flags()
            )
    return self.access_flags_string

get_class_name() #

Return the class name of the field

Returns:

Type Description
str

the class name

Source code in androguard/core/dex/__init__.py
def get_class_name(self) -> str:
    """
    Return the class name of the field

    :returns: the class name
    """
    if not self.loaded:
        self.load()
    return self.class_name

get_descriptor() #

Return the descriptor of the field

The descriptor of a field is the type of the field.

Returns:

Type Description
str

the descriptor

Source code in androguard/core/dex/__init__.py
def get_descriptor(self) -> str:
    """
    Return the descriptor of the field

    The descriptor of a field is the type of the field.

    :returns: the descriptor
    """
    if not self.loaded:
        self.load()
    return self.proto

get_field_idx() #

Return the real index of the method

Returns:

Type Description
int

the real index

Source code in androguard/core/dex/__init__.py
def get_field_idx(self) -> int:
    """
    Return the real index of the method

    :returns: the real index
    """
    return self.field_idx

get_field_idx_diff() #

Return the index into the field_ids list for the identity of this field (includes the name and descriptor), represented as a difference from the index of previous element in the list

Returns:

Type Description
int

the index

Source code in androguard/core/dex/__init__.py
def get_field_idx_diff(self) -> int:
    """
    Return the index into the field_ids list for the identity of this field (includes the name and descriptor),
    represented as a difference from the index of previous element in the list

    :returns: the index
    """
    return self.field_idx_diff

get_init_value() #

Return the init value object of the field

Returns:

Type Description
EncodedValue

an EncodedValue object

Source code in androguard/core/dex/__init__.py
def get_init_value(self) -> EncodedValue:
    """
    Return the init value object of the field

    :returns: an `EncodedValue` object
    """
    return self.init_value

get_name() #

Return the name of the field

Returns:

Type Description
str

the name

Source code in androguard/core/dex/__init__.py
def get_name(self) -> str:
    """
    Return the name of the field

    :returns: the name
    """
    if not self.loaded:
        self.load()
    return self.name

set_init_value(value) #

Setup the init value object of the field

Parameters:

Name Type Description Default
value EncodedValue

the init value

required
Source code in androguard/core/dex/__init__.py
def set_init_value(self, value: EncodedValue) -> None:
    """
    Setup the init value object of the field

    :param value: the init value
    """
    self.init_value = value

show() #

Display the information (with a pretty print) about the field

Source code in androguard/core/dex/__init__.py
def show(self) -> None:
    """
    Display the information (with a pretty print) about the field
    """
    bytecode._PrintSubBanner("Field Information")
    bytecode._PrintDefault(
        "{}->{} {} [access_flags={}]\n".format(
            self.get_class_name(),
            self.get_name(),
            self.get_descriptor(),
            self.get_access_flags_string(),
        )
    )

    init_value = self.get_init_value()
    if init_value is not None:
        bytecode._PrintDefault(
            "\tinit value: %s\n" % str(init_value.get_value())
        )

EncodedMethod #

This class can parse an encoded_method of a dex file

Source code in androguard/core/dex/__init__.py
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
class EncodedMethod:
    """
    This class can parse an `encoded_method` of a dex file
    """

    def __init__(self, buff: BinaryIO, cm:ClassManager) -> None:
        """
        :param buff: a string which represents a buff object of the `encoded_method`
        :param cm: a `ClassManager` object
        """
        self.CM = cm
        self.offset = buff.tell()

        self.method_idx_diff = readuleb128(
            cm, buff
        )  #: method index diff in the corresponding section
        self.access_flags = readuleb128(
            cm, buff
        )  #: access flags of the method
        self.code_off = readuleb128(cm, buff)  #: offset of the code section

        self.method_idx = 0

        self.name = None
        self.proto = None
        self.class_name = None

        self.code = None

        self.access_flags_string = None

        self.notes = []
        self.loaded = False

    def adjust_idx(self, val: int) -> None:
        self.method_idx = self.method_idx_diff + val

    def get_method_idx(self) -> int:
        """
        Return the real index of the method

        :returns: the real index
        """
        return self.method_idx

    def get_method_idx_diff(self) -> int:
        """
        Return index into the `method_ids` list for the identity of this method (includes the name and descriptor),
        represented as a difference from the index of previous element in the lis

        :returns: the index
        """
        return self.method_idx_diff

    def get_access_flags(self) -> int:
        """
        Return the access flags of the method

        :returns: the access flags
        """
        return self.access_flags

    def get_code_off(self) -> int:
        """
        Return the offset from the start of the file to the code structure for this method,
        or 0 if this method is either abstract or native

        :returns: the offset
        """
        return self.code_off

    def get_address(self) -> int:
        """
        Return the offset from the start of the file to the code structure for this method,
        or 0 if this method is either abstract or native

        :returns: the offset
        """
        return self.code_off + 0x10

    def get_access_flags_string(self) -> str:
        """
        Return the access flags string of the method

        A description of all access flags can be found here:
        https://source.android.com/devices/tech/dalvik/dex-format#access-flags

        :returns: the access flags
        """
        if self.access_flags_string is None:
            self.access_flags_string = get_access_flags_string(
                self.get_access_flags()
            )

            if (
                self.access_flags_string == ""
                and self.get_access_flags() != 0x0
            ):
                self.access_flags_string = "0x%x" % self.get_access_flags()
        return self.access_flags_string

    def load(self) -> None:
        if self.loaded:
            return
        self.reload()
        self.loaded = True

    def reload(self) -> None:
        v = self.CM.get_method(self.method_idx)
        # TODO this can probably be more elegant:
        # get_method returns an array with the already resolved types.
        # But for example to count the number of parameters, we need to split the string now.
        # This is quite tedious and could be avoided if we would return the type IDs
        # instead and resolve them here.
        if v and len(v) >= 3:
            self.class_name = v[0]
            self.name = v[1]
            self.proto = ''.join(i for i in v[2])
        else:
            self.class_name = 'CLASS_NAME_ERROR'
            self.name = 'NAME_ERROR'
            self.proto = 'PROTO_ERROR'

        self.code = self.CM.get_code(self.code_off)

    def get_locals(self) -> int:
        """
        Get the number of local registers used by the method

        This number is equal to the number of registers minus the number of parameters minus 1.

        :returns: number of local registers
        """
        ret = self.proto.split(')')
        params = ret[0][1:].split()

        return self.code.get_registers_size() - len(params) - 1

    def get_information(self) -> dict[str, Union[str, tuple[int, int], list]]:
        """
        Get brief information about the method's register use,
        parameters and return type.

        The resulting dictionary has the form:

            >>> {
            >>>    registers: (start, end),
            >>>    params: [(reg_1, type_1), (reg_2, type_2), ..., (reg_n, type_n)],
            >>>    return: type
            >>> }

        The end register is not the last register used, but the last register
        used not for parameters. Hence, they represent the local registers.
        The start register is always zero.
        The register numbers for the parameters can be found in the tuples
        for each parameter.

        :returns: a dictionary with the basic information about the method
        """
        info = dict()
        if self.code:
            nb = self.code.get_registers_size()
            proto = self.get_descriptor()

            ret = proto.split(')')
            params = ret[0][1:].split()

            info["return"] = get_type(ret[1])

            if params:
                info["registers"] = (0, nb - len(params) - 1)
                j = 0
                info["params"] = []
                for i in range(nb - len(params), nb):
                    info["params"].append((i, get_type(params[j])))
                    j += 1
            else:
                info["registers"] = (0, nb - 1)

        return info

    def each_params_by_register(self, nb: int, proto: str) -> None:
        """
        From the Dalvik Bytecode documentation:

        > The N arguments to a method land in the last N registers
        > of the method's invocation frame, in order.
        > Wide arguments consume two registers.
        > Instance methods are passed a this reference as their first argument.

        This method will print a description of the register usage to stdout.

        :param nb: number of registers
        :param proto: descriptor of method
        """
        bytecode._PrintSubBanner("Params")

        ret = proto.split(')')
        params = ret[0][1:].split()
        if params:
            bytecode._PrintDefault(
                "- local registers: v%d...v%d\n" % (0, nb - len(params) - 1)
            )
            j = 0
            for i in range(nb - len(params), nb):
                bytecode._PrintDefault(
                    "- v%d: %s\n" % (i, get_type(params[j]))
                )
                j += 1
        else:
            bytecode._PrintDefault(
                "local registers: v%d...v%d\n" % (0, nb - 1)
            )

        bytecode._PrintDefault("- return: %s\n" % get_type(ret[1]))
        bytecode._PrintSubBanner()

    def __str__(self):
        return "{}->{}{} [access_flags={}] @ 0x{:x}".format(
            self.get_class_name(),
            self.get_name(),
            self.get_descriptor(),
            self.get_access_flags_string(),
            self.get_code_off(),
        )

    @property
    def full_name(self) -> str:
        """Return class_name + name + descriptor, separated by spaces (no access flags)"""
        return ' '.join([self.class_name, self.name, self.get_descriptor()])

    @property
    def descriptor(self) -> str:
        """Get the descriptor of the method"""
        return self.get_descriptor()

    def get_short_string(self) -> str:
        """
        Return a shorter formatted String which encodes this method.
        The returned name has the form:
        <classname> <methodname> ([arguments ...])<returntype>

        * All Class names are condensed to the actual name (no package).
        * Access flags are not returned.
        * <init> and <clinit> are NOT replaced by the classname!

        This name might not be unique!

        :returns: str
        """

        def _fmt_classname(cls) -> str:
            arr = ""
            # Test for arrays
            while cls.startswith("["):
                arr += "["
                cls = cls[1:]

            # is a object type
            if cls.startswith("L"):
                cls = cls[1:-1]
            # only return last element
            if "/" in cls:
                cls = cls.rsplit("/", 1)[1]
            return arr + cls

        clsname = _fmt_classname(str(self.get_class_name()))

        param, ret = str(self.get_descriptor())[1:].split(")")
        params = map(_fmt_classname, param.split(" "))
        desc = "({}){}".format(''.join(params), _fmt_classname(ret))
        return "{cls} {meth} {desc}".format(
            cls=clsname, meth=self.get_name(), desc=desc
        )

    def show_info(self) -> None:
        """
        Display the basic information about the method
        """
        bytecode._PrintSubBanner("Method Information")
        bytecode._PrintDefault(
            "{}->{}{} [access_flags={}]\n".format(
                self.get_class_name(),
                self.get_name(),
                self.get_descriptor(),
                self.get_access_flags_string(),
            )
        )

    def show(self) -> None:
        """
        Display the information (with a pretty print) about the method
        """
        self.show_info()
        self.show_notes()

        if self.CM.get_analysis():
            self.CM.get_analysis().methods[self].show()
        else:
            if self.code:
                self.each_params_by_register(
                    self.code.get_registers_size(), self.get_descriptor()
                )
                self.code.show()

    def show_notes(self) -> None:
        """
        Display the notes about the method
        """
        if self.notes:
            bytecode._PrintSubBanner("Notes")
            for i in self.notes:
                bytecode._PrintNote(i)
            bytecode._PrintSubBanner()

    def source(self) -> str:
        """
        Return the source code of this method

        :returns: the source code
        """
        self.CM.decompiler_ob.display_source(self)

    def get_source(self) -> str:
        return self.CM.decompiler_ob.get_source_method(self)

    def get_length(self) -> int:
        """
        Return the length of the associated code of the method

        :returns: the length of the source code
        """
        if self.code is not None:
            return self.code.get_length()
        return 0

    def get_code(self) -> Union[DalvikCode, None]:
        """
        Return the code object associated to the method


        :returns: the `DalvikCode` object or None if no Code
        """
        if not self.loaded:
            self.load()
        return self.code

    def is_cached_instructions(self) -> bool:
        if self.code is None:
            return False

        return self.code.get_bc().is_cached_instructions()

    def get_instructions(self) -> Iterator[Instruction]:
        """
        Get the instructions

        :returns: a generator of each `Instruction` (or a cached list of instructions if you have setup instructions)
        """
        if self.get_code() is None:
            return []
        return self.get_code().get_bc().get_instructions()

    def get_instructions_idx(self) -> Iterator[tuple[int, Instruction]]:
        """
        Iterate over all instructions of the method, but also return the current index.
        This is the same as using [get_instructions][androguard.core.dex.EncodedMethod.get_instructions] and adding the instruction length
        to a variable each time.

        :returns: iterator over index and instructions
        """
        if self.get_code() is None:
            return []
        idx = 0
        for ins in self.get_code().get_bc().get_instructions():
            yield idx, ins
            idx += ins.get_length()

    def set_instructions(self, instructions: list[Instruction]) -> None:
        """
        Set the instructions

        :param instructions: the list of `Instructions`
        """
        if self.code is None:
            return []
        return self.code.get_bc().set_instructions(instructions)

    def get_instruction(
        self, idx, off: Union[int, None] = None
    ) -> Iterator[Instruction]:
        """
        Get a particular instruction by using (default) the index of the address if specified

        :param idx: index of the instruction (the position in the list of the instruction)
        :param off: address of the instruction

        :returns: a generator of `Instructions`
        """
        if self.get_code() is not None:
            return self.get_code().get_bc().get_instruction(idx, off)
        return None

    def get_debug(self) -> DebugInfoItem:
        """
        Return the debug object associated to this method

        :returns: `DebugInfoItem` object
        """
        if self.get_code() is None:
            return None
        return self.get_code().get_debug()

    def get_descriptor(self) -> str:
        """
        Return the descriptor of the method
        A method descriptor will have the form `(A A A ...)R`
        Where A are the arguments to the method and R is the return type.
        Basic types will have the short form, i.e. I for integer, V for void
        and class types will be named like a classname, e.g. `Ljava/lang/String;`.

        Typical descriptors will look like this:
        ```
        (I)I   // one integer argument, integer return
        (C)Z   // one char argument, boolean as return
        (Ljava/lang/CharSequence; I)I   // CharSequence and integer as
        argyument, integer as return
        (C)Ljava/lang/String;  // char as argument, String as return.
        ```

        More information about type descriptors are found here:
        https://source.android.com/devices/tech/dalvik/dex-format#typedescriptor

        :returns: the descriptor
        """
        if not self.loaded:
            self.load()
        return self.proto

    def get_class_name(self) -> str:
        """
        Return the class name of the method

        :returns: the class name
        """
        if not self.loaded:
            self.load()
        return self.class_name

    def get_name(self) -> str:
        """
        Return the name of the method

        :returns: the name
        """
        if not self.loaded:
            self.load()
        return self.name

    def get_triple(self) -> tuple[str, str, str]:
        return self.CM.get_method_ref(self.method_idx).get_triple()

    def add_inote(
        self, msg: str, idx: int, off: Union[int, None] = None
    ) -> None:
        """
        Add a message to a specific instruction by using (default) the index of the address if specified

        :param msg: the message
        :param idx: index of the instruction (the position in the list of the instruction)
        :param off: address of the instruction
        """
        if self.code is not None:
            self.code.add_inote(msg, idx, off)

    def add_note(self, msg: str) -> None:
        """
        Add a message to this method

        :param msg: the message
        """
        self.notes.append(msg)

    def set_code_idx(self, idx: int) -> None:
        """
        Set the start address of the buffer to disassemble

        :param idx: the index
        """
        if self.code is not None:
            self.code.seek(idx)

    def set_name(self, value):
        self.CM.set_hook_method_name(self, value)
        self.reload()

    def get_raw(self):
        if self.code is not None:
            self.code_off = self.code.get_off()

        return (
            writeuleb128(self.CM, self.method_idx_diff)
            + writeuleb128(self.CM, self.access_flags)
            + writeuleb128(self.CM, self.code_off)
        )

    def get_size(self):
        return len(self.get_raw())

descriptor property #

Get the descriptor of the method

full_name property #

Return class_name + name + descriptor, separated by spaces (no access flags)

__init__(buff, cm) #

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a buff object of the encoded_method

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
def __init__(self, buff: BinaryIO, cm:ClassManager) -> None:
    """
    :param buff: a string which represents a buff object of the `encoded_method`
    :param cm: a `ClassManager` object
    """
    self.CM = cm
    self.offset = buff.tell()

    self.method_idx_diff = readuleb128(
        cm, buff
    )  #: method index diff in the corresponding section
    self.access_flags = readuleb128(
        cm, buff
    )  #: access flags of the method
    self.code_off = readuleb128(cm, buff)  #: offset of the code section

    self.method_idx = 0

    self.name = None
    self.proto = None
    self.class_name = None

    self.code = None

    self.access_flags_string = None

    self.notes = []
    self.loaded = False

add_inote(msg, idx, off=None) #

Add a message to a specific instruction by using (default) the index of the address if specified

Parameters:

Name Type Description Default
msg str

the message

required
idx int

index of the instruction (the position in the list of the instruction)

required
off Union[int, None]

address of the instruction

None
Source code in androguard/core/dex/__init__.py
def add_inote(
    self, msg: str, idx: int, off: Union[int, None] = None
) -> None:
    """
    Add a message to a specific instruction by using (default) the index of the address if specified

    :param msg: the message
    :param idx: index of the instruction (the position in the list of the instruction)
    :param off: address of the instruction
    """
    if self.code is not None:
        self.code.add_inote(msg, idx, off)

add_note(msg) #

Add a message to this method

Parameters:

Name Type Description Default
msg str

the message

required
Source code in androguard/core/dex/__init__.py
def add_note(self, msg: str) -> None:
    """
    Add a message to this method

    :param msg: the message
    """
    self.notes.append(msg)

each_params_by_register(nb, proto) #

From the Dalvik Bytecode documentation:

The N arguments to a method land in the last N registers of the method's invocation frame, in order. Wide arguments consume two registers. Instance methods are passed a this reference as their first argument.

This method will print a description of the register usage to stdout.

Parameters:

Name Type Description Default
nb int

number of registers

required
proto str

descriptor of method

required
Source code in androguard/core/dex/__init__.py
def each_params_by_register(self, nb: int, proto: str) -> None:
    """
    From the Dalvik Bytecode documentation:

    > The N arguments to a method land in the last N registers
    > of the method's invocation frame, in order.
    > Wide arguments consume two registers.
    > Instance methods are passed a this reference as their first argument.

    This method will print a description of the register usage to stdout.

    :param nb: number of registers
    :param proto: descriptor of method
    """
    bytecode._PrintSubBanner("Params")

    ret = proto.split(')')
    params = ret[0][1:].split()
    if params:
        bytecode._PrintDefault(
            "- local registers: v%d...v%d\n" % (0, nb - len(params) - 1)
        )
        j = 0
        for i in range(nb - len(params), nb):
            bytecode._PrintDefault(
                "- v%d: %s\n" % (i, get_type(params[j]))
            )
            j += 1
    else:
        bytecode._PrintDefault(
            "local registers: v%d...v%d\n" % (0, nb - 1)
        )

    bytecode._PrintDefault("- return: %s\n" % get_type(ret[1]))
    bytecode._PrintSubBanner()

get_access_flags() #

Return the access flags of the method

Returns:

Type Description
int

the access flags

Source code in androguard/core/dex/__init__.py
def get_access_flags(self) -> int:
    """
    Return the access flags of the method

    :returns: the access flags
    """
    return self.access_flags

get_access_flags_string() #

Return the access flags string of the method

A description of all access flags can be found here: https://source.android.com/devices/tech/dalvik/dex-format#access-flags

Returns:

Type Description
str

the access flags

Source code in androguard/core/dex/__init__.py
def get_access_flags_string(self) -> str:
    """
    Return the access flags string of the method

    A description of all access flags can be found here:
    https://source.android.com/devices/tech/dalvik/dex-format#access-flags

    :returns: the access flags
    """
    if self.access_flags_string is None:
        self.access_flags_string = get_access_flags_string(
            self.get_access_flags()
        )

        if (
            self.access_flags_string == ""
            and self.get_access_flags() != 0x0
        ):
            self.access_flags_string = "0x%x" % self.get_access_flags()
    return self.access_flags_string

get_address() #

Return the offset from the start of the file to the code structure for this method, or 0 if this method is either abstract or native

Returns:

Type Description
int

the offset

Source code in androguard/core/dex/__init__.py
def get_address(self) -> int:
    """
    Return the offset from the start of the file to the code structure for this method,
    or 0 if this method is either abstract or native

    :returns: the offset
    """
    return self.code_off + 0x10

get_class_name() #

Return the class name of the method

Returns:

Type Description
str

the class name

Source code in androguard/core/dex/__init__.py
def get_class_name(self) -> str:
    """
    Return the class name of the method

    :returns: the class name
    """
    if not self.loaded:
        self.load()
    return self.class_name

get_code() #

Return the code object associated to the method

Returns:

Type Description
Union[DalvikCode, None]

the DalvikCode object or None if no Code

Source code in androguard/core/dex/__init__.py
def get_code(self) -> Union[DalvikCode, None]:
    """
    Return the code object associated to the method


    :returns: the `DalvikCode` object or None if no Code
    """
    if not self.loaded:
        self.load()
    return self.code

get_code_off() #

Return the offset from the start of the file to the code structure for this method, or 0 if this method is either abstract or native

Returns:

Type Description
int

the offset

Source code in androguard/core/dex/__init__.py
def get_code_off(self) -> int:
    """
    Return the offset from the start of the file to the code structure for this method,
    or 0 if this method is either abstract or native

    :returns: the offset
    """
    return self.code_off

get_debug() #

Return the debug object associated to this method

Returns:

Type Description
DebugInfoItem

DebugInfoItem object

Source code in androguard/core/dex/__init__.py
def get_debug(self) -> DebugInfoItem:
    """
    Return the debug object associated to this method

    :returns: `DebugInfoItem` object
    """
    if self.get_code() is None:
        return None
    return self.get_code().get_debug()

get_descriptor() #

Return the descriptor of the method A method descriptor will have the form (A A A ...)R Where A are the arguments to the method and R is the return type. Basic types will have the short form, i.e. I for integer, V for void and class types will be named like a classname, e.g. Ljava/lang/String;.

Typical descriptors will look like this:

(I)I   // one integer argument, integer return
(C)Z   // one char argument, boolean as return
(Ljava/lang/CharSequence; I)I   // CharSequence and integer as
argyument, integer as return
(C)Ljava/lang/String;  // char as argument, String as return.

More information about type descriptors are found here: https://source.android.com/devices/tech/dalvik/dex-format#typedescriptor

Returns:

Type Description
str

the descriptor

Source code in androguard/core/dex/__init__.py
def get_descriptor(self) -> str:
    """
    Return the descriptor of the method
    A method descriptor will have the form `(A A A ...)R`
    Where A are the arguments to the method and R is the return type.
    Basic types will have the short form, i.e. I for integer, V for void
    and class types will be named like a classname, e.g. `Ljava/lang/String;`.

    Typical descriptors will look like this:
    ```
    (I)I   // one integer argument, integer return
    (C)Z   // one char argument, boolean as return
    (Ljava/lang/CharSequence; I)I   // CharSequence and integer as
    argyument, integer as return
    (C)Ljava/lang/String;  // char as argument, String as return.
    ```

    More information about type descriptors are found here:
    https://source.android.com/devices/tech/dalvik/dex-format#typedescriptor

    :returns: the descriptor
    """
    if not self.loaded:
        self.load()
    return self.proto

get_information() #

Get brief information about the method's register use, parameters and return type.

The resulting dictionary has the form:

>>> {
>>>    registers: (start, end),
>>>    params: [(reg_1, type_1), (reg_2, type_2), ..., (reg_n, type_n)],
>>>    return: type
>>> }

The end register is not the last register used, but the last register used not for parameters. Hence, they represent the local registers. The start register is always zero. The register numbers for the parameters can be found in the tuples for each parameter.

Returns:

Type Description
dict[str, Union[str, tuple[int, int], list]]

a dictionary with the basic information about the method

Source code in androguard/core/dex/__init__.py
def get_information(self) -> dict[str, Union[str, tuple[int, int], list]]:
    """
    Get brief information about the method's register use,
    parameters and return type.

    The resulting dictionary has the form:

        >>> {
        >>>    registers: (start, end),
        >>>    params: [(reg_1, type_1), (reg_2, type_2), ..., (reg_n, type_n)],
        >>>    return: type
        >>> }

    The end register is not the last register used, but the last register
    used not for parameters. Hence, they represent the local registers.
    The start register is always zero.
    The register numbers for the parameters can be found in the tuples
    for each parameter.

    :returns: a dictionary with the basic information about the method
    """
    info = dict()
    if self.code:
        nb = self.code.get_registers_size()
        proto = self.get_descriptor()

        ret = proto.split(')')
        params = ret[0][1:].split()

        info["return"] = get_type(ret[1])

        if params:
            info["registers"] = (0, nb - len(params) - 1)
            j = 0
            info["params"] = []
            for i in range(nb - len(params), nb):
                info["params"].append((i, get_type(params[j])))
                j += 1
        else:
            info["registers"] = (0, nb - 1)

    return info

get_instruction(idx, off=None) #

Get a particular instruction by using (default) the index of the address if specified

Parameters:

Name Type Description Default
idx

index of the instruction (the position in the list of the instruction)

required
off Union[int, None]

address of the instruction

None

Returns:

Type Description
Iterator[Instruction]

a generator of Instructions

Source code in androguard/core/dex/__init__.py
def get_instruction(
    self, idx, off: Union[int, None] = None
) -> Iterator[Instruction]:
    """
    Get a particular instruction by using (default) the index of the address if specified

    :param idx: index of the instruction (the position in the list of the instruction)
    :param off: address of the instruction

    :returns: a generator of `Instructions`
    """
    if self.get_code() is not None:
        return self.get_code().get_bc().get_instruction(idx, off)
    return None

get_instructions() #

Get the instructions

Returns:

Type Description
Iterator[Instruction]

a generator of each Instruction (or a cached list of instructions if you have setup instructions)

Source code in androguard/core/dex/__init__.py
def get_instructions(self) -> Iterator[Instruction]:
    """
    Get the instructions

    :returns: a generator of each `Instruction` (or a cached list of instructions if you have setup instructions)
    """
    if self.get_code() is None:
        return []
    return self.get_code().get_bc().get_instructions()

get_instructions_idx() #

Iterate over all instructions of the method, but also return the current index. This is the same as using get_instructions and adding the instruction length to a variable each time.

Returns:

Type Description
Iterator[tuple[int, Instruction]]

iterator over index and instructions

Source code in androguard/core/dex/__init__.py
def get_instructions_idx(self) -> Iterator[tuple[int, Instruction]]:
    """
    Iterate over all instructions of the method, but also return the current index.
    This is the same as using [get_instructions][androguard.core.dex.EncodedMethod.get_instructions] and adding the instruction length
    to a variable each time.

    :returns: iterator over index and instructions
    """
    if self.get_code() is None:
        return []
    idx = 0
    for ins in self.get_code().get_bc().get_instructions():
        yield idx, ins
        idx += ins.get_length()

get_length() #

Return the length of the associated code of the method

Returns:

Type Description
int

the length of the source code

Source code in androguard/core/dex/__init__.py
def get_length(self) -> int:
    """
    Return the length of the associated code of the method

    :returns: the length of the source code
    """
    if self.code is not None:
        return self.code.get_length()
    return 0

get_locals() #

Get the number of local registers used by the method

This number is equal to the number of registers minus the number of parameters minus 1.

Returns:

Type Description
int

number of local registers

Source code in androguard/core/dex/__init__.py
def get_locals(self) -> int:
    """
    Get the number of local registers used by the method

    This number is equal to the number of registers minus the number of parameters minus 1.

    :returns: number of local registers
    """
    ret = self.proto.split(')')
    params = ret[0][1:].split()

    return self.code.get_registers_size() - len(params) - 1

get_method_idx() #

Return the real index of the method

Returns:

Type Description
int

the real index

Source code in androguard/core/dex/__init__.py
def get_method_idx(self) -> int:
    """
    Return the real index of the method

    :returns: the real index
    """
    return self.method_idx

get_method_idx_diff() #

Return index into the method_ids list for the identity of this method (includes the name and descriptor), represented as a difference from the index of previous element in the lis

Returns:

Type Description
int

the index

Source code in androguard/core/dex/__init__.py
def get_method_idx_diff(self) -> int:
    """
    Return index into the `method_ids` list for the identity of this method (includes the name and descriptor),
    represented as a difference from the index of previous element in the lis

    :returns: the index
    """
    return self.method_idx_diff

get_name() #

Return the name of the method

Returns:

Type Description
str

the name

Source code in androguard/core/dex/__init__.py
def get_name(self) -> str:
    """
    Return the name of the method

    :returns: the name
    """
    if not self.loaded:
        self.load()
    return self.name

get_short_string() #

Return a shorter formatted String which encodes this method. The returned name has the form: ([arguments ...])

  • All Class names are condensed to the actual name (no package).
  • Access flags are not returned.
  • and are NOT replaced by the classname!

This name might not be unique!

Returns:

Type Description
str

str

Source code in androguard/core/dex/__init__.py
def get_short_string(self) -> str:
    """
    Return a shorter formatted String which encodes this method.
    The returned name has the form:
    <classname> <methodname> ([arguments ...])<returntype>

    * All Class names are condensed to the actual name (no package).
    * Access flags are not returned.
    * <init> and <clinit> are NOT replaced by the classname!

    This name might not be unique!

    :returns: str
    """

    def _fmt_classname(cls) -> str:
        arr = ""
        # Test for arrays
        while cls.startswith("["):
            arr += "["
            cls = cls[1:]

        # is a object type
        if cls.startswith("L"):
            cls = cls[1:-1]
        # only return last element
        if "/" in cls:
            cls = cls.rsplit("/", 1)[1]
        return arr + cls

    clsname = _fmt_classname(str(self.get_class_name()))

    param, ret = str(self.get_descriptor())[1:].split(")")
    params = map(_fmt_classname, param.split(" "))
    desc = "({}){}".format(''.join(params), _fmt_classname(ret))
    return "{cls} {meth} {desc}".format(
        cls=clsname, meth=self.get_name(), desc=desc
    )

set_code_idx(idx) #

Set the start address of the buffer to disassemble

Parameters:

Name Type Description Default
idx int

the index

required
Source code in androguard/core/dex/__init__.py
def set_code_idx(self, idx: int) -> None:
    """
    Set the start address of the buffer to disassemble

    :param idx: the index
    """
    if self.code is not None:
        self.code.seek(idx)

set_instructions(instructions) #

Set the instructions

Parameters:

Name Type Description Default
instructions list[Instruction]

the list of Instructions

required
Source code in androguard/core/dex/__init__.py
def set_instructions(self, instructions: list[Instruction]) -> None:
    """
    Set the instructions

    :param instructions: the list of `Instructions`
    """
    if self.code is None:
        return []
    return self.code.get_bc().set_instructions(instructions)

show() #

Display the information (with a pretty print) about the method

Source code in androguard/core/dex/__init__.py
def show(self) -> None:
    """
    Display the information (with a pretty print) about the method
    """
    self.show_info()
    self.show_notes()

    if self.CM.get_analysis():
        self.CM.get_analysis().methods[self].show()
    else:
        if self.code:
            self.each_params_by_register(
                self.code.get_registers_size(), self.get_descriptor()
            )
            self.code.show()

show_info() #

Display the basic information about the method

Source code in androguard/core/dex/__init__.py
def show_info(self) -> None:
    """
    Display the basic information about the method
    """
    bytecode._PrintSubBanner("Method Information")
    bytecode._PrintDefault(
        "{}->{}{} [access_flags={}]\n".format(
            self.get_class_name(),
            self.get_name(),
            self.get_descriptor(),
            self.get_access_flags_string(),
        )
    )

show_notes() #

Display the notes about the method

Source code in androguard/core/dex/__init__.py
def show_notes(self) -> None:
    """
    Display the notes about the method
    """
    if self.notes:
        bytecode._PrintSubBanner("Notes")
        for i in self.notes:
            bytecode._PrintNote(i)
        bytecode._PrintSubBanner()

source() #

Return the source code of this method

Returns:

Type Description
str

the source code

Source code in androguard/core/dex/__init__.py
def source(self) -> str:
    """
    Return the source code of this method

    :returns: the source code
    """
    self.CM.decompiler_ob.display_source(self)

EncodedTypeAddrPair #

This class can parse an encoded_type_addr_pair of a dex file

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the encoded_type_addr_pair

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
class EncodedTypeAddrPair:
    """
    This class can parse an `encoded_type_addr_pair` of a dex file

    :param buff: a string which represents a Buff object of the `encoded_type_addr_pair`
    :param cm: a `ClassManager` object
    """

    def __init__(self, cm: ClassManager, buff: BinaryIO) -> None:
        self.CM = cm
        self.type_idx = readuleb128(cm, buff)
        self.addr = readuleb128(cm, buff)

    def get_type_idx(self) -> int:
        """
        Return the index into the `type_ids` list for the type of the exception to catch

        :returns: the index
        """
        return self.type_idx

    def get_addr(self) -> int:
        """
        Return the bytecode address of the associated exception handler

        :returns: the bytecode address
        """
        return self.addr

    def get_obj(self) -> list:
        return []

    def show(self) -> None:
        bytecode._PrintSubBanner("Encoded Type Addr Pair")
        bytecode._PrintDefault(
            "type_idx=%d addr=%x\n" % (self.type_idx, self.addr)
        )

    def get_raw(self) -> bytearray:
        return writeuleb128(self.CM, self.type_idx) + writeuleb128(
            self.CM, self.addr
        )

    def get_length(self) -> int:
        return len(self.get_raw())

get_addr() #

Return the bytecode address of the associated exception handler

Returns:

Type Description
int

the bytecode address

Source code in androguard/core/dex/__init__.py
def get_addr(self) -> int:
    """
    Return the bytecode address of the associated exception handler

    :returns: the bytecode address
    """
    return self.addr

get_type_idx() #

Return the index into the type_ids list for the type of the exception to catch

Returns:

Type Description
int

the index

Source code in androguard/core/dex/__init__.py
def get_type_idx(self) -> int:
    """
    Return the index into the `type_ids` list for the type of the exception to catch

    :returns: the index
    """
    return self.type_idx

EncodedValue #

This class can parse an encoded_value of a dex file

Source code in androguard/core/dex/__init__.py
class EncodedValue:
    """
    This class can parse an `encoded_value` of a dex file
    """
    def __init__(self, buff: BinaryIO, cm:ClassManager) -> None:
        """
        :param buff: a string which represents a Buff object of the `encoded_value`
        :param cm: a `ClassManager` object
        """
        self.CM = cm

        self.val = get_byte(cm, buff)
        self.value_arg = self.val >> 5
        self.value_type = self.val & 0x1F

        self.raw_value = None
        self.value = ""

        #  TODO: parse floats/doubles correctly
        if VALUE_SHORT <= self.value_type < VALUE_STRING:
            self.value, self.raw_value = self._getintvalue(
                buff.read(self.value_arg + 1)
            )
        elif self.value_type == VALUE_STRING:
            id, self.raw_value = self._getintvalue(
                buff.read(self.value_arg + 1)
            )
            self.value = cm.get_raw_string(id)
        elif self.value_type == VALUE_TYPE:
            id, self.raw_value = self._getintvalue(
                buff.read(self.value_arg + 1)
            )
            self.value = cm.get_type(id)
        elif self.value_type == VALUE_FIELD:
            id, self.raw_value = self._getintvalue(
                buff.read(self.value_arg + 1)
            )
            self.value = cm.get_field(id)
        elif self.value_type == VALUE_METHOD:
            id, self.raw_value = self._getintvalue(
                buff.read(self.value_arg + 1)
            )
            self.value = cm.get_method(id)
        elif self.value_type == VALUE_ENUM:
            id, self.raw_value = self._getintvalue(
                buff.read(self.value_arg + 1)
            )
            self.value = cm.get_field(id)
        elif self.value_type == VALUE_ARRAY:
            self.value = EncodedArray(buff, cm)
        elif self.value_type == VALUE_ANNOTATION:
            self.value = EncodedAnnotation(buff, cm)
        elif self.value_type == VALUE_BYTE:
            self.value = get_byte(cm, buff)
        elif self.value_type == VALUE_NULL:
            self.value = None
        elif self.value_type == VALUE_BOOLEAN:
            if self.value_arg:
                self.value = True
            else:
                self.value = False
        else:
            logger.warning("Unknown value 0x%x" % self.value_type)

    def get_value(self):
        """
        Return the bytes representing the value, variable in length and interpreted differently for different `value_type` bytes,
        though always little-endian

        :returns: an object representing the value
        """
        return self.value

    def get_value_type(self):
        return self.value_type

    def get_value_arg(self):
        return self.value_arg

    def _getintvalue(self, buf):
        ret = 0
        shift = 0
        for b in buf:
            ret |= b << shift
            shift += 8

        return ret, buf

    def show(self):
        bytecode._PrintSubBanner("Encoded Value")
        bytecode._PrintDefault(
            "val=%x value_arg=%x value_type=%x\n"
            % (self.val, self.value_arg, self.value_type)
        )

    def get_obj(self):
        if not isinstance(self.value, str):
            return [self.value]
        return []

    def get_raw(self):
        if self.raw_value is None:
            return self.CM.packer["B"].pack(
                self.val
            ) + bytecode.object_to_bytes(self.value)
        else:
            return self.CM.packer["B"].pack(
                self.val
            ) + bytecode.object_to_bytes(self.raw_value)

    def get_length(self):
        return len(self.get_raw())

__init__(buff, cm) #

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the encoded_value

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
def __init__(self, buff: BinaryIO, cm:ClassManager) -> None:
    """
    :param buff: a string which represents a Buff object of the `encoded_value`
    :param cm: a `ClassManager` object
    """
    self.CM = cm

    self.val = get_byte(cm, buff)
    self.value_arg = self.val >> 5
    self.value_type = self.val & 0x1F

    self.raw_value = None
    self.value = ""

    #  TODO: parse floats/doubles correctly
    if VALUE_SHORT <= self.value_type < VALUE_STRING:
        self.value, self.raw_value = self._getintvalue(
            buff.read(self.value_arg + 1)
        )
    elif self.value_type == VALUE_STRING:
        id, self.raw_value = self._getintvalue(
            buff.read(self.value_arg + 1)
        )
        self.value = cm.get_raw_string(id)
    elif self.value_type == VALUE_TYPE:
        id, self.raw_value = self._getintvalue(
            buff.read(self.value_arg + 1)
        )
        self.value = cm.get_type(id)
    elif self.value_type == VALUE_FIELD:
        id, self.raw_value = self._getintvalue(
            buff.read(self.value_arg + 1)
        )
        self.value = cm.get_field(id)
    elif self.value_type == VALUE_METHOD:
        id, self.raw_value = self._getintvalue(
            buff.read(self.value_arg + 1)
        )
        self.value = cm.get_method(id)
    elif self.value_type == VALUE_ENUM:
        id, self.raw_value = self._getintvalue(
            buff.read(self.value_arg + 1)
        )
        self.value = cm.get_field(id)
    elif self.value_type == VALUE_ARRAY:
        self.value = EncodedArray(buff, cm)
    elif self.value_type == VALUE_ANNOTATION:
        self.value = EncodedAnnotation(buff, cm)
    elif self.value_type == VALUE_BYTE:
        self.value = get_byte(cm, buff)
    elif self.value_type == VALUE_NULL:
        self.value = None
    elif self.value_type == VALUE_BOOLEAN:
        if self.value_arg:
            self.value = True
        else:
            self.value = False
    else:
        logger.warning("Unknown value 0x%x" % self.value_type)

get_value() #

Return the bytes representing the value, variable in length and interpreted differently for different value_type bytes, though always little-endian

Returns:

Type Description

an object representing the value

Source code in androguard/core/dex/__init__.py
def get_value(self):
    """
    Return the bytes representing the value, variable in length and interpreted differently for different `value_type` bytes,
    though always little-endian

    :returns: an object representing the value
    """
    return self.value

ExportObject #

Wrapper object for ipython exports

Source code in androguard/core/dex/__init__.py
class ExportObject:
    """
    Wrapper object for ipython exports
    """

    pass

FieldAnnotation #

This class can parse a field_annotation of a dex file

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a buff object of the field_annotation

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
class FieldAnnotation:
    """
    This class can parse a `field_annotation` of a dex file

    :param buff: a string which represents a buff object of the `field_annotation`
    :param cm: a ClassManager object
    """

    def __init__(self, buff: BinaryIO, cm: ClassManager) -> None:
        self.offset = buff.tell()

        self.CM = cm
        self.field_idx, self.annotations_off = cm.packer["2I"].unpack(
            buff.read(8)
        )

    def get_field_idx(self) -> int:
        """
        Return the index into the `field_ids` list for the identity of the field being annotated

        :returns: the index
        """
        return self.field_idx

    def get_annotations_off(self) -> int:
        """
        Return the offset from the start of the file to the list of annotations for the field

        :returns: the offset
        """
        return self.annotations_off

    def set_off(self, off: int) -> None:
        self.offset = off

    def get_off(self) -> int:
        return self.offset

    def show(self) -> None:
        bytecode._PrintSubBanner("Field Annotation")
        bytecode._PrintDefault(
            "field_idx=0x%x annotations_off=0x%x\n"
            % (self.field_idx, self.annotations_off)
        )

    def get_obj(self) -> bytes:
        if self.annotations_off != 0:
            self.annotations_off = self.CM.get_obj_by_offset(
                self.annotations_off
            ).get_off()

        return self.CM.packer["2I"].pack(self.field_idx, self.annotations_off)

    def get_raw(self) -> bytes:
        return self.get_obj()

    def get_length(self) -> int:
        return len(self.get_raw())

get_annotations_off() #

Return the offset from the start of the file to the list of annotations for the field

Returns:

Type Description
int

the offset

Source code in androguard/core/dex/__init__.py
def get_annotations_off(self) -> int:
    """
    Return the offset from the start of the file to the list of annotations for the field

    :returns: the offset
    """
    return self.annotations_off

get_field_idx() #

Return the index into the field_ids list for the identity of the field being annotated

Returns:

Type Description
int

the index

Source code in androguard/core/dex/__init__.py
def get_field_idx(self) -> int:
    """
    Return the index into the `field_ids` list for the identity of the field being annotated

    :returns: the index
    """
    return self.field_idx

FieldHIdItem #

This class can parse a list of field_id_item of a dex file

Source code in androguard/core/dex/__init__.py
class FieldHIdItem:
    """
    This class can parse a list of `field_id_item` of a dex file
    """

    def __init__(self, size:int, buff: BinaryIO, cm:ClassManager) -> None:
        """
        :param buff: a string which represents a buff object of the list of `field_id_item`
        :param cm: a `ClassManager` object
        """
        self.offset = buff.tell()

        self.field_id_items = [FieldIdItem(buff, cm) for i in range(0, size)]

    def set_off(self, off: int) -> None:
        self.offset = off

    def get_off(self) -> int:
        return self.offset

    def gets(self) -> list[FieldIdItem]:
        return self.field_id_items

    def get(self, idx: int) -> Union[FieldIdItem, FieldIdItemInvalid]:
        try:
            return self.field_id_items[idx]
        except IndexError:
            return FieldIdItemInvalid()

    def show(self) -> None:
        nb = 0
        for i in self.field_id_items:
            print(nb, end=' ')
            i.show()
            nb = nb + 1

    def get_obj(self) -> list[FieldIdItem]:
        return [i for i in self.field_id_items]

    def get_raw(self) -> bytes:
        return b''.join(i.get_raw() for i in self.field_id_items)

    def get_length(self) -> int:
        length = 0
        for i in self.field_id_items:
            length += i.get_length()
        return length

__init__(size, buff, cm) #

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a buff object of the list of field_id_item

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
def __init__(self, size:int, buff: BinaryIO, cm:ClassManager) -> None:
    """
    :param buff: a string which represents a buff object of the list of `field_id_item`
    :param cm: a `ClassManager` object
    """
    self.offset = buff.tell()

    self.field_id_items = [FieldIdItem(buff, cm) for i in range(0, size)]

FieldIdItem #

This class can parse a field_id_item of a dex file

Source code in androguard/core/dex/__init__.py
class FieldIdItem:
    """
    This class can parse a `field_id_item` of a dex file
    """

    def __init__(self, buff: BinaryIO, cm: ClassManager) -> None:
        """"
        :param buff: a string which represents a Buff object of the `field_id_item`
        :param cm: a `ClassManager` object
        """
        self.CM = cm
        self.offset = buff.tell()

        self.class_idx, self.type_idx, self.name_idx = cm.packer["2HI"].unpack(
            buff.read(8)
        )

        self.reload()

    def reload(self) -> None:
        self.class_idx_value = self.CM.get_type(self.class_idx)
        self.type_idx_value = self.CM.get_type(self.type_idx)
        self.name_idx_value = self.CM.get_string(self.name_idx)

    def get_class_idx(self) -> int:
        """
        Return the index into the `type_ids` list for the definer of this field

        :returns: the index
        """
        return self.class_idx

    def get_type_idx(self) -> int:
        """
        Return the index into the `type_ids` list for the type of this field

        :returns: the index
        """
        return self.type_idx

    def get_name_idx(self) -> int:
        """
        Return the index into the `string_ids` list for the name of this field

        :returns: the index
        """
        return self.name_idx

    def get_class_name(self) -> str:
        """
        Return the class name of the field

        :returns: the class name
        """
        if self.class_idx_value is None:
            self.class_idx_value = self.CM.get_type(self.class_idx)
        return self.class_idx_value

    def get_type(self) -> str:
        """
        Return the type of the field

        :returns: the type
        """
        if self.type_idx_value is None:
            self.type_idx_value = self.CM.get_type(self.type_idx)
        return self.type_idx_value

    def get_descriptor(self) -> str:
        """
        Return the descriptor of the field

        :returns: the desciptor
        """
        if self.type_idx_value is None:
            self.type_idx_value = self.CM.get_type(self.type_idx)
        return self.type_idx_value

    def get_name(self) -> str:
        """
        Return the name of the field

        :returns: the name
        """
        if self.name_idx_value is None:
            self.name_idx_value = self.CM.get_string(self.name_idx)
        return self.name_idx_value

    def get_list(self) -> list[str]:
        return [self.get_class_name(), self.get_type(), self.get_name()]

    def show(self) -> None:
        bytecode._PrintSubBanner("Field Id Item")
        bytecode._PrintDefault(
            "class_idx=%d type_idx=%d name_idx=%d\n"
            % (self.class_idx, self.type_idx, self.name_idx)
        )
        bytecode._PrintDefault(
            "class_idx_value=%s type_idx_value=%s name_idx_value=%s\n"
            % (self.class_idx_value, self.type_idx_value, self.name_idx_value)
        )

    def get_obj(self) -> bytes:
        return self.CM.packer["2HI"].pack(
            self.class_idx, self.type_idx, self.name_idx
        )

    def get_raw(self) -> bytes:
        return self.get_obj()

    def get_length(self) -> int:
        return len(self.get_obj())

__init__(buff, cm) #

"

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the field_id_item

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
def __init__(self, buff: BinaryIO, cm: ClassManager) -> None:
    """"
    :param buff: a string which represents a Buff object of the `field_id_item`
    :param cm: a `ClassManager` object
    """
    self.CM = cm
    self.offset = buff.tell()

    self.class_idx, self.type_idx, self.name_idx = cm.packer["2HI"].unpack(
        buff.read(8)
    )

    self.reload()

get_class_idx() #

Return the index into the type_ids list for the definer of this field

Returns:

Type Description
int

the index

Source code in androguard/core/dex/__init__.py
def get_class_idx(self) -> int:
    """
    Return the index into the `type_ids` list for the definer of this field

    :returns: the index
    """
    return self.class_idx

get_class_name() #

Return the class name of the field

Returns:

Type Description
str

the class name

Source code in androguard/core/dex/__init__.py
def get_class_name(self) -> str:
    """
    Return the class name of the field

    :returns: the class name
    """
    if self.class_idx_value is None:
        self.class_idx_value = self.CM.get_type(self.class_idx)
    return self.class_idx_value

get_descriptor() #

Return the descriptor of the field

Returns:

Type Description
str

the desciptor

Source code in androguard/core/dex/__init__.py
def get_descriptor(self) -> str:
    """
    Return the descriptor of the field

    :returns: the desciptor
    """
    if self.type_idx_value is None:
        self.type_idx_value = self.CM.get_type(self.type_idx)
    return self.type_idx_value

get_name() #

Return the name of the field

Returns:

Type Description
str

the name

Source code in androguard/core/dex/__init__.py
def get_name(self) -> str:
    """
    Return the name of the field

    :returns: the name
    """
    if self.name_idx_value is None:
        self.name_idx_value = self.CM.get_string(self.name_idx)
    return self.name_idx_value

get_name_idx() #

Return the index into the string_ids list for the name of this field

Returns:

Type Description
int

the index

Source code in androguard/core/dex/__init__.py
def get_name_idx(self) -> int:
    """
    Return the index into the `string_ids` list for the name of this field

    :returns: the index
    """
    return self.name_idx

get_type() #

Return the type of the field

Returns:

Type Description
str

the type

Source code in androguard/core/dex/__init__.py
def get_type(self) -> str:
    """
    Return the type of the field

    :returns: the type
    """
    if self.type_idx_value is None:
        self.type_idx_value = self.CM.get_type(self.type_idx)
    return self.type_idx_value

get_type_idx() #

Return the index into the type_ids list for the type of this field

Returns:

Type Description
int

the index

Source code in androguard/core/dex/__init__.py
def get_type_idx(self) -> int:
    """
    Return the index into the `type_ids` list for the type of this field

    :returns: the index
    """
    return self.type_idx

FillArrayData #

This class can parse a FillArrayData instruction

Parameters:

Name Type Description Default
buff BinaryIO

a Buff object which represents a buffer where the instruction is stored

required
Source code in androguard/core/dex/__init__.py
class FillArrayData:
    """
    This class can parse a `FillArrayData` instruction

    :param buff: a Buff object which represents a buffer where the instruction is stored
    """

    # FIXME: why is this not a subclass of Instruction?
    def __init__(self, cm: ClassManager, buff: BinaryIO) -> None:
        self.OP = 0x0
        self.notes = []
        self.CM = cm

        self.format_general_size = calcsize("2HI")
        self.ident, self.element_width, self.size = cm.packer["2HI"].unpack(
            buff[0:8]
        )

        buf_len = self.size * self.element_width
        if buf_len % 2:
            buf_len += 1

        self.data = buff[
            self.format_general_size : self.format_general_size + buf_len
        ]

    def add_note(self, msg: str) -> None:
        """
        Add a note to this instruction

        :param msg: the message
        """
        self.notes.append(msg)

    def get_notes(self) -> list[str]:
        """
        Get all notes from this instruction

        :returns: a list of string notes
        """
        return self.notes

    def get_op_value(self) -> int:
        """
        Get the value of the opcode

        :returns: the value
        """
        return self.ident

    def get_data(self) -> bytes:
        """
        Return the data of this instruction (the payload)

        :returns: the instruction payload bytes
        """
        return self.data

    def get_output(self, idx: int = -1) -> str:
        """
        Return an additional output of the instruction

        :returns: additional output of the instruction
        """
        buff = ""

        data = self.get_data()

        buff += repr(data) + " | "
        for i in range(0, len(data)):
            buff += "\\x{:02x}".format(data[i])

        return buff

    def get_operands(self, idx: int=-1) -> tuple[Operand, str]:
        # FIXME: not sure of binascii is the right choice here,
        # but before it was repr(), which lead to weird outputs of bytearrays
        if isinstance(self.get_data(), bytearray):
            return [
                (
                    Operand.RAW,
                    binascii.hexlify(self.get_data()).decode('ascii'),
                )
            ]
        else:
            return [(Operand.RAW, repr(self.get_data()))]

    def get_formatted_operands(self) -> None:
        return None

    def get_name(self) -> str:
        """
        Return the name of the instruction

        :returns: name string
        """
        return "fill-array-data-payload"

    def show_buff(self, pos: int) -> str:
        """
        Return the display of the instruction

        :returns: display string
        """
        buff = self.get_name() + " "

        for i in range(0, len(self.data)):
            buff += "\\x%02x" % self.data[i]
        return buff

    def show(self, pos: int) -> None:
        """
        Print the instruction

        :param pos: the position of the instruction
        """
        print(self.show_buff(pos), end=' ')

    def get_length(self) -> int:
        """
        Return the length of the instruction

        :returns: the length
        """
        return ((self.size * self.element_width + 1) // 2 + 4) * 2

    def get_raw(self) -> bytes:
        return (
            self.CM.packer["2HI"].pack(
                self.ident, self.element_width, self.size
            )
            + self.data
        )

    def get_hex(self) -> str:
        """
        Returns a HEX String, separated by spaces every byte
        """
        s = binascii.hexlify(self.get_raw()).decode("ascii")
        return " ".join(s[i : i + 2] for i in range(0, len(s), 2))

    def disasm(self) -> str:
        # FIXME:
        return self.show_buff(None)

add_note(msg) #

Add a note to this instruction

Parameters:

Name Type Description Default
msg str

the message

required
Source code in androguard/core/dex/__init__.py
def add_note(self, msg: str) -> None:
    """
    Add a note to this instruction

    :param msg: the message
    """
    self.notes.append(msg)

get_data() #

Return the data of this instruction (the payload)

Returns:

Type Description
bytes

the instruction payload bytes

Source code in androguard/core/dex/__init__.py
def get_data(self) -> bytes:
    """
    Return the data of this instruction (the payload)

    :returns: the instruction payload bytes
    """
    return self.data

get_hex() #

Returns a HEX String, separated by spaces every byte

Source code in androguard/core/dex/__init__.py
def get_hex(self) -> str:
    """
    Returns a HEX String, separated by spaces every byte
    """
    s = binascii.hexlify(self.get_raw()).decode("ascii")
    return " ".join(s[i : i + 2] for i in range(0, len(s), 2))

get_length() #

Return the length of the instruction

Returns:

Type Description
int

the length

Source code in androguard/core/dex/__init__.py
def get_length(self) -> int:
    """
    Return the length of the instruction

    :returns: the length
    """
    return ((self.size * self.element_width + 1) // 2 + 4) * 2

get_name() #

Return the name of the instruction

Returns:

Type Description
str

name string

Source code in androguard/core/dex/__init__.py
def get_name(self) -> str:
    """
    Return the name of the instruction

    :returns: name string
    """
    return "fill-array-data-payload"

get_notes() #

Get all notes from this instruction

Returns:

Type Description
list[str]

a list of string notes

Source code in androguard/core/dex/__init__.py
def get_notes(self) -> list[str]:
    """
    Get all notes from this instruction

    :returns: a list of string notes
    """
    return self.notes

get_op_value() #

Get the value of the opcode

Returns:

Type Description
int

the value

Source code in androguard/core/dex/__init__.py
def get_op_value(self) -> int:
    """
    Get the value of the opcode

    :returns: the value
    """
    return self.ident

get_output(idx=-1) #

Return an additional output of the instruction

Returns:

Type Description
str

additional output of the instruction

Source code in androguard/core/dex/__init__.py
def get_output(self, idx: int = -1) -> str:
    """
    Return an additional output of the instruction

    :returns: additional output of the instruction
    """
    buff = ""

    data = self.get_data()

    buff += repr(data) + " | "
    for i in range(0, len(data)):
        buff += "\\x{:02x}".format(data[i])

    return buff

show(pos) #

Print the instruction

Parameters:

Name Type Description Default
pos int

the position of the instruction

required
Source code in androguard/core/dex/__init__.py
def show(self, pos: int) -> None:
    """
    Print the instruction

    :param pos: the position of the instruction
    """
    print(self.show_buff(pos), end=' ')

show_buff(pos) #

Return the display of the instruction

Returns:

Type Description
str

display string

Source code in androguard/core/dex/__init__.py
def show_buff(self, pos: int) -> str:
    """
    Return the display of the instruction

    :returns: display string
    """
    buff = self.get_name() + " "

    for i in range(0, len(self.data)):
        buff += "\\x%02x" % self.data[i]
    return buff

HeaderItem #

This class can parse an header_item of a dex file. Several checks are performed to detect if this is not an header_item. Also the Adler32 checksum of the file is calculated in order to detect file corruption.

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the header_item

required
cm ClassManager

a ClassManager object

required

Raises:

Type Description
ValueError

if DEX file header is incorrect

Source code in androguard/core/dex/__init__.py
class HeaderItem:
    """
    This class can parse an `header_item` of a dex file.
    Several checks are performed to detect if this is not an `header_item`.
    Also the Adler32 checksum of the file is calculated in order to detect file
    corruption.

    :raises ValueError: if DEX file header is incorrect
    :param buff: a string which represents a Buff object of the `header_item`
    :param cm: a `ClassManager` object
    """

    def __init__(self, size, buff: BinaryIO, cm: ClassManager) -> None:
        logger.debug("HeaderItem")

        self.CM = cm

        self.offset = buff.tell()

        if self.offset != 0:
            logger.warning(
                "Unusual DEX file, does not have the header at offset 0"
            )

        if buff.raw.getbuffer().nbytes < self.get_length():
            raise ValueError("Not a DEX file, Header too small.")

        (self.endian_tag,) = unpack('<I', read_at(buff, 40, 4))
        cm.packer = DalvikPacker(self.endian_tag)

        # Q is actually wrong, but we do not change it here and unpack our own
        # stuff...
        (
            self.magic,
            self.checksum,
            self.signature,
            self.file_size,
            self.header_size,
            endian_tag,
            self.link_size,
            self.link_off,
            self.map_off,
            self.string_ids_size,
            self.string_ids_off,
            self.type_ids_size,
            self.type_ids_off,
            self.proto_ids_size,
            self.proto_ids_off,
            self.field_ids_size,
            self.field_ids_off,
            self.method_ids_size,
            self.method_ids_off,
            self.class_defs_size,
            self.class_defs_off,
            self.data_size,
            self.data_off,
        ) = cm.packer['8sI20s20I'].unpack(buff.read(112))

        # possible dex or dey:
        if (
            self.magic[:2] != b'de'
            or self.magic[2] not in [0x78, 0x79]
            or self.magic[3] != 0x0A
            or self.magic[7] != 0x00
        ):
            raise ValueError(
                "This is not a DEX file! Wrong magic: {}".format(
                    repr(self.magic)
                )
            )

        try:
            self.dex_version = int(self.magic[4:7].decode('ascii'), 10)
        except (UnicodeDecodeError, ValueError):
            logger.warning(
                "Wrong DEX version: {}, trying to parse anyways".format(
                    repr(self.magic)
                )
            )
            self.dex_version = 35  # assume a common version...

        if zlib.adler32(read_at(buff, self.offset + 12)) != self.checksum:
            raise ValueError("Wrong Adler32 checksum for DEX file!")

        if self.file_size != buff.raw.getbuffer().nbytes:
            # Maybe raise an error here too...
            logger.warning(
                "DEX file size is different to the buffer. Trying to parse anyways."
            )

        if self.header_size != 0x70:
            raise ValueError(
                "This is not a DEX file! Wrong header size: '{}'".format(
                    self.header_size
                )
            )

        if self.type_ids_size > 65535:
            raise ValueError(
                "DEX file contains too many ({}) TYPE_IDs to be valid!".format(
                    self.type_ids_size
                )
            )

        if self.proto_ids_size > 65535:
            raise ValueError(
                "DEX file contains too many ({}) PROTO_IDs to be valid!".format(
                    self.proto_ids_size
                )
            )

        if self.data_size % 4 != 0:
            logger.warning(
                "data_size is not a multiple of sizeof(uint32_t), but try to parse anyways."
            )

        self.map_off_obj = None
        self.string_off_obj = None
        self.type_off_obj = None
        self.proto_off_obj = None
        self.field_off_obj = None
        self.method_off_obj = None
        self.class_off_obj = None
        self.data_off_obj = None

    def get_obj(self) -> bytes:
        if self.map_off_obj is None:
            self.map_off_obj = self.CM.get_item_by_offset(self.map_off)

        if self.string_off_obj is None:
            self.string_off_obj = self.CM.get_item_by_offset(
                self.string_ids_off
            )

        if self.type_off_obj is None:
            self.type_off_obj = self.CM.get_item_by_offset(self.type_ids_off)

        if self.proto_off_obj is None:
            self.proto_off_obj = self.CM.get_item_by_offset(self.proto_ids_off)

        if self.field_off_obj is None:
            self.field_off_obj = self.CM.get_item_by_offset(self.field_ids_off)

        if self.method_off_obj is None:
            self.method_off_obj = self.CM.get_item_by_offset(
                self.method_ids_off
            )

        if self.class_off_obj is None:
            self.class_off_obj = self.CM.get_item_by_offset(
                self.class_defs_off
            )

        if self.data_off_obj is None:
            self.data_off_obj = self.CM.get_item_by_offset(self.data_off)

        # FIXME: has no object map_off_obj!
        self.map_off = self.map_off_obj.get_off()

        self.string_ids_size = len(self.string_off_obj)
        self.string_ids_off = self.string_off_obj[0].get_off()

        self.type_ids_size = len(self.type_off_obj.type)
        self.type_ids_off = self.type_off_obj.get_off()

        self.proto_ids_size = len(self.proto_off_obj.proto)
        self.proto_ids_off = self.proto_off_obj.get_off()

        self.field_ids_size = len(self.field_off_obj.elem)
        self.field_ids_off = self.field_off_obj.get_off()

        self.method_ids_size = len(self.method_off_obj.methods)
        self.method_ids_off = self.method_off_obj.get_off()

        self.class_defs_size = len(self.class_off_obj.class_def)
        self.class_defs_off = self.class_off_obj.get_off()

        # FIXME: data_off_obj has no map_item!!!
        self.data_size = len(self.data_off_obj.map_item)
        self.data_off = self.data_off_obj.get_off()

        return (
            pack("<Q", self.magic)
            + pack("<I", self.checksum)
            + pack("<20s", self.signature)
            + pack("<I", self.file_size)
            + pack("<I", self.header_size)
            + pack("<I", self.endian_tag)
            + pack("<I", self.link_size)
            + pack("<I", self.link_off)
            + pack("<I", self.map_off)
            + pack("<I", self.string_ids_size)
            + pack("<I", self.string_ids_off)
            + pack("<I", self.type_ids_size)
            + pack("<I", self.type_ids_off)
            + pack("<I", self.proto_ids_size)
            + pack("<I", self.proto_ids_off)
            + pack("<I", self.field_ids_size)
            + pack("<I", self.field_ids_off)
            + pack("<I", self.method_ids_size)
            + pack("<I", self.method_ids_off)
            + pack("<I", self.class_defs_size)
            + pack("<I", self.class_defs_off)
            + pack("<I", self.data_size)
            + pack("<I", self.data_off)
        )

    def get_raw(self) -> bytes:
        return self.get_obj()

    def get_length(self) -> int:
        return 112

    def show(self) -> None:
        bytecode._PrintSubBanner("Header Item")
        bytecode._PrintDefault(
            "magic=%s, checksum=%s, signature=%s\n"
            % (
                self.magic,
                self.checksum,
                binascii.hexlify(self.signature).decode("ASCII"),
            )
        )
        bytecode._PrintDefault(
            "file_size=%x, header_size=%x, endian_tag=%x\n"
            % (self.file_size, self.header_size, self.endian_tag)
        )
        bytecode._PrintDefault(
            "link_size=%x, link_off=%x\n" % (self.link_size, self.link_off)
        )
        bytecode._PrintDefault("map_off=%x\n" % self.map_off)
        bytecode._PrintDefault(
            "string_ids_size=%x, string_ids_off=%x\n"
            % (self.string_ids_size, self.string_ids_off)
        )
        bytecode._PrintDefault(
            "type_ids_size=%x, type_ids_off=%x\n"
            % (self.type_ids_size, self.type_ids_off)
        )
        bytecode._PrintDefault(
            "proto_ids_size=%x, proto_ids_off=%x\n"
            % (self.proto_ids_size, self.proto_ids_off)
        )
        bytecode._PrintDefault(
            "field_ids_size=%x, field_ids_off=%x\n"
            % (self.field_ids_size, self.field_ids_off)
        )
        bytecode._PrintDefault(
            "method_ids_size=%x, method_ids_off=%x\n"
            % (self.method_ids_size, self.method_ids_off)
        )
        bytecode._PrintDefault(
            "class_defs_size=%x, class_defs_off=%x\n"
            % (self.class_defs_size, self.class_defs_off)
        )
        bytecode._PrintDefault(
            "data_size=%x, data_off=%x\n" % (self.data_size, self.data_off)
        )

    def __repr__(self):
        return self.__str__()

    def __str__(self):
        return (
            "Header Item magic={}, checksum={}, signature={} file_size={:X}, header_size={:X}, endian_tag={:X},"
            "link_size={:X}, link_off={:X}, map_off={:X}, string_ids_size={:X}, string_ids_off={:X},  "
            "type_ids_size={:X}, type_ids_off={:X}, proto_ids_size={:X}, proto_ids_off={:X}, "
            "field_ids_size={:X}, field_ids_off={:X}, method_ids_size={:X}, method_ids_off={:X}, "
            "class_defs_size={:X}, class_defs_off={:X}, data_size={:X}, data_off={:X}".format(
                self.magic,
                self.checksum,
                binascii.hexlify(self.signature).decode("ASCII"),
                self.file_size,
                self.header_size,
                self.endian_tag,
                self.link_size,
                self.link_off,
                self.map_off,
                self.string_ids_size,
                self.string_ids_off,
                self.type_ids_size,
                self.type_ids_off,
                self.proto_ids_size,
                self.proto_ids_off,
                self.field_ids_size,
                self.field_ids_off,
                self.method_ids_size,
                self.method_ids_off,
                self.class_defs_size,
                self.class_defs_off,
                self.data_size,
                self.data_off,
            )
        )

    def set_off(self, off: int) -> None:
        self.offset = off

    def get_off(self) -> int:
        return self.offset

HiddenApiClassDataItem #

This class can parse an hiddenapi_class_data_item of a dex file (from Android 10 dex version 039)

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the hiddenapi_class_data_item

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
class HiddenApiClassDataItem:
    """
    This class can parse an `hiddenapi_class_data_item` of a dex file (from Android 10 dex version 039)

    :param buff: a string which represents a Buff object of the `hiddenapi_class_data_item`
    :param cm: a `ClassManager` object
    """

    class RestrictionApiFlag(IntEnum):
        WHITELIST = 0
        GREYLIST = 1
        BLACKLIST = 2
        GREYLIST_MAX_O = 3
        GREYLIST_MAX_P = 4
        GREYLIST_MAX_Q = 5
        GREYLIST_MAX_R = 6

    class DomapiApiFlag(IntEnum):
        NONE = 0
        CORE_PLATFORM_API = 1
        TEST_API = 2

    def __init__(self, buff: BinaryIO, cm: ClassManager) -> None:
        self.CM = cm

        self.offset = buff.tell()

        (self.section_size,) = cm.packer["I"].unpack(buff.read(4))

        # Find the end of the offsets array (first non-zero offset entry is the start of `flags`)
        offsets_size = 0
        i = 0
        while buff.tell() - self.offset < self.section_size:
            if offsets_size != 0 and i >= offsets_size:
                break
            (offset,) = cm.packer["I"].unpack(buff.read(4))
            if offset != 0 and offsets_size == 0:
                offsets_size = (offset - 4) // 4
            i += 1

        self.flags = []
        for i in range(offsets_size):
            flag = readuleb128(cm, buff)
            self.flags.append(
                (
                    self.RestrictionApiFlag(flag & 0b111),
                    self.DomapiApiFlag(flag >> 3),
                )
            )

    def get_section_size(self):
        """
        Return the total size of this section

        :returns: the total size
        """
        return self.section_size

    def get_flags(self, idx) -> tuple[RestrictionApiFlag, DomapiApiFlag]:
        """
        Return a tuple of the flags per class

        :param idx: The index to return the flags of (index of the class)

        :returns: tuple of `RestrictionApiFlag`, `DomapiApiFlag`
        """
        return self.flags[idx]

    def set_off(self, off: int):
        self.offset = off

    def get_off(self):
        return self.offset

    def show(self):
        bytecode._PrintSubBanner("HiddenApi Class Data Item")
        bytecode._PrintDefault("section_size=0x%x\n" % (self.section_size,))

        for i, (rf, df) in enumerate(self.flags):
            bytecode._PrintDefault("[%u] %s, %s\n" % (i, rf, df))

    def get_obj(self):
        base = 4 + len(self.flags)
        raw_offsets = b''
        raw_flags = b''
        for rf, df in self.flags:
            raw_offsets += self.CM.packer["I"].pack(base + len(raw_flags))
            raw_flags += writeuleb128(self.CM, (df.value << 3) | rf.value)

        return (
            self.CM.packer["I"].pack(self.section_size)
            + raw_offsets
            + raw_flags
        )

    def get_raw(self):
        return self.get_obj()

    def get_length(self):
        return self.section_size

get_flags(idx) #

Return a tuple of the flags per class

Parameters:

Name Type Description Default
idx

The index to return the flags of (index of the class)

required

Returns:

Type Description
tuple[RestrictionApiFlag, DomapiApiFlag]

tuple of RestrictionApiFlag, DomapiApiFlag

Source code in androguard/core/dex/__init__.py
def get_flags(self, idx) -> tuple[RestrictionApiFlag, DomapiApiFlag]:
    """
    Return a tuple of the flags per class

    :param idx: The index to return the flags of (index of the class)

    :returns: tuple of `RestrictionApiFlag`, `DomapiApiFlag`
    """
    return self.flags[idx]

get_section_size() #

Return the total size of this section

Returns:

Type Description

the total size

Source code in androguard/core/dex/__init__.py
def get_section_size(self):
    """
    Return the total size of this section

    :returns: the total size
    """
    return self.section_size

Instruction #

This class represents a Dalvik instruction

It can both handle normal instructions as well as optimized instructions.

WARNING: There is not much documentation about the optimized opcodes! Hence, it relies on reverese engineered specification!

More information about the instruction format can be found in the official documentation: https://source.android.com/devices/tech/dalvik/instruction-formats.html

WARNING: Values stored in the instructions are already interpreted at this stage.

The Dalvik VM has a eight opcodes to create constant integer values. There are four variants for 32bit values and four for 64bit. If floating point numbers are required, you have to use the conversion opcodes like int-to-float, int-to-double or the variants using long.

Androguard will always show the values as they are used in the opcode and also extend signs and shift values! As an example: The opcode const/high16 can be used to create constant values where the lower 16 bits are all zero. In this case, androguard will process bytecode 15 00 CD AB as beeing const/high16 v0, 0xABCD0000. For the sign-extension, nothing is really done here, as it only affects the bit represenation in the virtual machine. As androguard parses the values and uses python types internally, we are not bound to specific size.

Source code in androguard/core/dex/__init__.py
class Instruction:
    """
    This class represents a Dalvik instruction

    It can both handle normal instructions as well as optimized instructions.

    WARNING: There is not much documentation about the optimized opcodes! Hence, it relies on reverese engineered specification!

    More information about the instruction format can be found in the official documentation:
    https://source.android.com/devices/tech/dalvik/instruction-formats.html

    WARNING: Values stored in the instructions are already interpreted at this stage.

    The Dalvik VM has a eight opcodes to create constant integer values.
    There are four variants for 32bit values and four for 64bit.
    If floating point numbers are required, you have to use the conversion opcodes
    like `int-to-float`, `int-to-double` or the variants using `long`.

    Androguard will always show the values as they are used in the opcode and also extend signs
    and shift values!
    As an example: The opcode `const/high16` can be used to create constant values
    where the lower 16 bits are all zero.
    In this case, androguard will process bytecode `15 00 CD AB` as beeing
    `const/high16 v0, 0xABCD0000`.
    For the sign-extension, nothing is really done here, as it only affects the bit represenation
    in the virtual machine. As androguard parses the values and uses python types internally,
    we are not bound to specific size.
    """

    length = 0
    OP = 0

    def get_kind(self) -> int:
        """
        Return the 'kind' argument of the instruction

        This is the type of the argument, i.e. in which kind of table you have
        to look up the argument in the `ClassManager`

        :returns: the kind
        """
        if self.OP >= 0xF2FF:
            return DALVIK_OPCODES_OPTIMIZED[self.OP][1][1]
        return DALVIK_OPCODES_FORMAT[self.OP][1][1]

    def get_name(self) -> str:
        """
        Return the mnemonic of the instruction

        :returns: the mnemonic
        """
        if self.OP >= 0xF2FF:
            return DALVIK_OPCODES_OPTIMIZED[self.OP][1][0]
        return DALVIK_OPCODES_FORMAT[self.OP][1][0]

    def get_op_value(self) -> int:
        """
        Return the numerical value of the opcode

        :returns: the numerical opcode
        """
        return self.OP

    def get_literals(self) -> list:
        """
        Not Implemented

        Return the associated literals

        :returns: list of int
        """
        return []

    def show(self, idx: int) -> None:
        """
        Print the instruction

        No Line ending is printed.
        """
        print(self.get_name() + " " + self.get_output(idx), end=' ')

    def show_buff(self, idx: int) -> str:
        """
        Return the display of the instruction

        :returns: the display of the instruction
        """
        return self.get_output(idx)

    def get_translated_kind(self) -> str:
        """
        Return the translated value of the 'kind' argument

        :returns: the translated value
        """
        return get_kind(self.cm, self.get_kind(), self.get_ref_kind())

    def get_output(self, idx: int = -1) -> str:
        """
        Not Implemented

        Return an additional output of the instruction

        :returns: the additional output as a string
        """
        return ""

    def get_operands(self, idx:int=-1) -> list[tuple[Operand, object]]:
        """
        Not Implemented

        Return all operands

        This will return a list of tuples, containing the Enum [Operand][androguard.core.dex.dex_types.Operand]
        at the first position and the objects afterwards.

        :returns: List[Tuple(Operand, object, ...)]
        """
        return []

    def get_length(self) -> int:
        """
        Return the length of the instruction in bytes

        :returns: the length
        """
        return self.length

    def get_raw(self):
        """
        Return the object in a raw format

        :returns: the raw format
        """
        raise Exception("not implemented")

    def get_ref_kind(self):
        """
        Return the value of the 'kind' argument

        :returns: value
        """
        raise Exception("not implemented")

    def get_hex(self) -> str:
        """
        Returns a HEX String, separated by spaces every byte

        The hex string contains the raw bytes of the instruction,
        including the opcode and all arguments.

        :returns: the hex string
        """
        s = binascii.hexlify(self.get_raw()).decode('ascii')
        return " ".join(s[i : i + 2] for i in range(0, len(s), 2))

    def __str__(self):
        return "{} {}".format(self.get_name(), self.get_output())

    # FIXME Better name
    def disasm(self) -> str:
        """Some small line for disassembly view"""
        s = binascii.hexlify(self.get_raw()).decode('ascii')
        byteview = " ".join(s[i : i + 4] for i in range(0, len(s), 4))
        return '{:24s}  {:24s} {}'.format(
            byteview, self.get_name(), self.get_output()
        )

disasm() #

Some small line for disassembly view

Source code in androguard/core/dex/__init__.py
def disasm(self) -> str:
    """Some small line for disassembly view"""
    s = binascii.hexlify(self.get_raw()).decode('ascii')
    byteview = " ".join(s[i : i + 4] for i in range(0, len(s), 4))
    return '{:24s}  {:24s} {}'.format(
        byteview, self.get_name(), self.get_output()
    )

get_hex() #

Returns a HEX String, separated by spaces every byte

The hex string contains the raw bytes of the instruction, including the opcode and all arguments.

Returns:

Type Description
str

the hex string

Source code in androguard/core/dex/__init__.py
def get_hex(self) -> str:
    """
    Returns a HEX String, separated by spaces every byte

    The hex string contains the raw bytes of the instruction,
    including the opcode and all arguments.

    :returns: the hex string
    """
    s = binascii.hexlify(self.get_raw()).decode('ascii')
    return " ".join(s[i : i + 2] for i in range(0, len(s), 2))

get_kind() #

Return the 'kind' argument of the instruction

This is the type of the argument, i.e. in which kind of table you have to look up the argument in the ClassManager

Returns:

Type Description
int

the kind

Source code in androguard/core/dex/__init__.py
def get_kind(self) -> int:
    """
    Return the 'kind' argument of the instruction

    This is the type of the argument, i.e. in which kind of table you have
    to look up the argument in the `ClassManager`

    :returns: the kind
    """
    if self.OP >= 0xF2FF:
        return DALVIK_OPCODES_OPTIMIZED[self.OP][1][1]
    return DALVIK_OPCODES_FORMAT[self.OP][1][1]

get_length() #

Return the length of the instruction in bytes

Returns:

Type Description
int

the length

Source code in androguard/core/dex/__init__.py
def get_length(self) -> int:
    """
    Return the length of the instruction in bytes

    :returns: the length
    """
    return self.length

get_literals() #

Not Implemented

Return the associated literals

Returns:

Type Description
list

list of int

Source code in androguard/core/dex/__init__.py
def get_literals(self) -> list:
    """
    Not Implemented

    Return the associated literals

    :returns: list of int
    """
    return []

get_name() #

Return the mnemonic of the instruction

Returns:

Type Description
str

the mnemonic

Source code in androguard/core/dex/__init__.py
def get_name(self) -> str:
    """
    Return the mnemonic of the instruction

    :returns: the mnemonic
    """
    if self.OP >= 0xF2FF:
        return DALVIK_OPCODES_OPTIMIZED[self.OP][1][0]
    return DALVIK_OPCODES_FORMAT[self.OP][1][0]

get_op_value() #

Return the numerical value of the opcode

Returns:

Type Description
int

the numerical opcode

Source code in androguard/core/dex/__init__.py
def get_op_value(self) -> int:
    """
    Return the numerical value of the opcode

    :returns: the numerical opcode
    """
    return self.OP

get_operands(idx=-1) #

Not Implemented

Return all operands

This will return a list of tuples, containing the Enum Operand at the first position and the objects afterwards.

Returns:

Type Description
list[tuple[Operand, object]]

List[Tuple(Operand, object, ...)]

Source code in androguard/core/dex/__init__.py
def get_operands(self, idx:int=-1) -> list[tuple[Operand, object]]:
    """
    Not Implemented

    Return all operands

    This will return a list of tuples, containing the Enum [Operand][androguard.core.dex.dex_types.Operand]
    at the first position and the objects afterwards.

    :returns: List[Tuple(Operand, object, ...)]
    """
    return []

get_output(idx=-1) #

Not Implemented

Return an additional output of the instruction

Returns:

Type Description
str

the additional output as a string

Source code in androguard/core/dex/__init__.py
def get_output(self, idx: int = -1) -> str:
    """
    Not Implemented

    Return an additional output of the instruction

    :returns: the additional output as a string
    """
    return ""

get_raw() #

Return the object in a raw format

Returns:

Type Description

the raw format

Source code in androguard/core/dex/__init__.py
def get_raw(self):
    """
    Return the object in a raw format

    :returns: the raw format
    """
    raise Exception("not implemented")

get_ref_kind() #

Return the value of the 'kind' argument

Returns:

Type Description

value

Source code in androguard/core/dex/__init__.py
def get_ref_kind(self):
    """
    Return the value of the 'kind' argument

    :returns: value
    """
    raise Exception("not implemented")

get_translated_kind() #

Return the translated value of the 'kind' argument

Returns:

Type Description
str

the translated value

Source code in androguard/core/dex/__init__.py
def get_translated_kind(self) -> str:
    """
    Return the translated value of the 'kind' argument

    :returns: the translated value
    """
    return get_kind(self.cm, self.get_kind(), self.get_ref_kind())

show(idx) #

Print the instruction

No Line ending is printed.

Source code in androguard/core/dex/__init__.py
def show(self, idx: int) -> None:
    """
    Print the instruction

    No Line ending is printed.
    """
    print(self.get_name() + " " + self.get_output(idx), end=' ')

show_buff(idx) #

Return the display of the instruction

Returns:

Type Description
str

the display of the instruction

Source code in androguard/core/dex/__init__.py
def show_buff(self, idx: int) -> str:
    """
    Return the display of the instruction

    :returns: the display of the instruction
    """
    return self.get_output(idx)

Instruction00x #

Bases: Instruction

A class for unused instructions, has zero length and raises an error on initialization

Source code in androguard/core/dex/__init__.py
class Instruction00x(Instruction):
    """A class for unused instructions, has zero length and raises an error on initialization"""

    length = 0

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        raise InvalidInstruction(
            "Instruction with opcode '0x{:02x}' is unused! This looks like invalid bytecode.".format(
                buff[0]
            )
        )

Instruction10t #

Bases: Instruction

This class represents all instructions which have the 10t format

Source code in androguard/core/dex/__init__.py
class Instruction10t(Instruction):
    """
    This class represents all instructions which have the 10t format
    """

    length = 2

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        self.OP, self.AA = cm.packer["Bb"].unpack(buff[: self.length])

    def get_output(self, idx: int = -1) -> str:
        # Offset is given in 16bit units
        return "{:+02x}h".format(self.AA)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        return [(Operand.OFFSET, self.AA)]

    def get_ref_off(self) -> int:
        return self.AA

    def get_raw(self) -> bytes:
        return self.cm.packer["Bb"].pack(self.OP, self.AA)

Instruction10x #

Bases: Instruction

This class represents all instructions which have the 10x format

Source code in androguard/core/dex/__init__.py
class Instruction10x(Instruction):
    """
    This class represents all instructions which have the 10x format
    """

    length = 2

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        self.OP, padding = cm.packer["BB"].unpack(buff[: self.length])
        if padding != 0:
            raise InvalidInstruction(
                'High byte of opcode with format 10x must be zero!'
            )

    def get_raw(self) -> bytes:
        return self.cm.packer["H"].pack(self.OP)

Instruction11n #

Bases: Instruction

This class represents all instructions which have the 11n format

Source code in androguard/core/dex/__init__.py
class Instruction11n(Instruction):
    """
    This class represents all instructions which have the 11n format
    """

    length = 2

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        self.OP, i8 = cm.packer["Bb"].unpack(buff[: self.length])
        self.A = i8 & 0xF
        # Sign extension not required
        self.B = i8 >> 4

    def get_output(self, idx: int = -1) -> str:
        return "v{}, {}".format(self.A, self.B)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        return [(Operand.REGISTER, self.A), (Operand.LITERAL, self.B)]

    def get_literals(self) -> list[int]:
        return [self.B]

    def get_raw(self) -> bytes:
        return self.cm.packer["h"].pack(
            (self.B << 12) | (self.A << 8) | self.OP
        )

Instruction11x #

Bases: Instruction

This class represents all instructions which have the 11x format

Source code in androguard/core/dex/__init__.py
class Instruction11x(Instruction):
    """
    This class represents all instructions which have the 11x format
    """

    length = 2

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        self.OP, self.AA = cm.packer["BB"].unpack(buff[: self.length])

    def get_output(self, idx: int = -1) -> str:
        return "v{}".format(self.AA)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        return [(Operand.REGISTER, self.AA)]

    def get_raw(self) -> bytes:
        return self.cm.packer["H"].pack((self.AA << 8) | self.OP)

Instruction12x #

Bases: Instruction

This class represents all instructions which have the 12x format

Source code in androguard/core/dex/__init__.py
class Instruction12x(Instruction):
    """
    This class represents all instructions which have the 12x format
    """

    length = 2

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        (i16,) = cm.packer["h"].unpack(buff[: self.length])
        self.OP = i16 & 0xFF
        self.A = (i16 >> 8) & 0xF
        self.B = (i16 >> 12) & 0xF

    def get_output(self, idx: int = -1) -> str:
        return "v{}, v{}".format(self.A, self.B)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        return [(Operand.REGISTER, self.A), (Operand.REGISTER, self.B)]

    def get_raw(self) -> bytes:
        return self.cm.packer["H"].pack(
            (self.B << 12) | (self.A << 8) | self.OP
        )

Instruction20bc #

Bases: Instruction

This class represents all instructions which have the 20bc format

Source code in androguard/core/dex/__init__.py
class Instruction20bc(Instruction):
    """
    This class represents all instructions which have the 20bc format
    """

    length = 4

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        self.OP, self.AA, self.BBBB = cm.packer["BBH"].unpack(
            buff[: self.length]
        )

    def get_output(self, idx: int = -1) -> str:
        return "{}, {}".format(self.AA, self.BBBB)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        return [(Operand.LITERAL, self.AA), (Operand.LITERAL, self.BBBB)]

    def get_raw(self) -> bytes:
        return self.cm.packer["2H"].pack((self.AA << 8) | self.OP, self.BBBB)

Instruction20t #

Bases: Instruction

This class represents all instructions which have the 20t format

Source code in androguard/core/dex/__init__.py
class Instruction20t(Instruction):
    """
    This class represents all instructions which have the 20t format
    """

    length = 4

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        self.OP, padding, self.AAAA = cm.packer["BBh"].unpack(
            buff[: self.length]
        )
        if padding != 0:
            raise InvalidInstruction(
                'High byte of opcode with format 20t must be zero!'
            )

    def get_output(self, idx: int = -1) -> str:
        # Offset is in 16bit units
        return "{:+04x}h".format(self.AAAA)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        return [(Operand.OFFSET, self.AAAA)]

    def get_ref_off(self) -> int:
        return self.AAAA

    def get_raw(self) -> bytes:
        return self.cm.packer["Hh"].pack(self.OP, self.AAAA)

Instruction21c #

Bases: Instruction

This class represents all instructions which have the 21c format

Source code in androguard/core/dex/__init__.py
class Instruction21c(Instruction):
    """
    This class represents all instructions which have the 21c format
    """

    length = 4

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm
        self.OP, self.AA, self.BBBB = cm.packer["BBH"].unpack(
            buff[: self.length]
        )

    def get_output(self, idx: int = -1) -> str:
        kind = get_kind(self.cm, self.get_kind(), self.BBBB)
        if self.get_kind() == Kind.STRING:
            kind = '"{}"'.format(kind)
        return "v{}, {}".format(self.AA, kind)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int, int]]:
        kind = get_kind(self.cm, self.get_kind(), self.BBBB)
        return [
            (Operand.REGISTER, self.AA),
            (self.get_kind() + Operand.KIND, self.BBBB, kind),
        ]

    def get_ref_kind(self) -> int:
        return self.BBBB

    def get_string(self) -> str:
        return get_kind(self.cm, self.get_kind(), self.BBBB)

    def get_raw_string(self) -> str:
        return get_kind(self.cm, Kind.RAW_STRING, self.BBBB)

    def get_raw(self) -> bytes:
        return self.cm.packer["2H"].pack((self.AA << 8) | self.OP, self.BBBB)

Instruction21h #

Bases: Instruction

This class represents all instructions which have the 21h format

Source code in androguard/core/dex/__init__.py
class Instruction21h(Instruction):
    """
    This class represents all instructions which have the 21h format
    """

    length = 4

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        self.OP, self.AA, self.__BBBB = cm.packer["BBh"].unpack(
            buff[: self.length]
        )

        if self.OP == 0x15:
            # OP 0x15: int16_t -> int32_t
            self.BBBB = self.__BBBB << 16
        elif self.OP == 0x19:
            # OP 0x19: int16_t -> int64_t
            self.BBBB = self.__BBBB << 48
        else:
            # Unknown opcode?
            self.BBBB = self.__BBBB

    def get_output(self, idx: int = -1) -> str:
        return "v{}, {}".format(self.AA, self.BBBB)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        return [(Operand.REGISTER, self.AA), (Operand.LITERAL, self.BBBB)]

    def get_literals(self) -> list[int]:
        return [self.BBBB]

    def get_raw(self) -> bytes:
        return self.cm.packer["Hh"].pack((self.AA << 8) | self.OP, self.__BBBB)

Instruction21s #

Bases: Instruction

This class represents all instructions which have the 21s format

Source code in androguard/core/dex/__init__.py
class Instruction21s(Instruction):
    """
    This class represents all instructions which have the 21s format
    """

    length = 4

    def __init__(self, cm: ClassManager, buff: bytes) -> bytes:
        super().__init__()
        self.cm = cm

        # BBBB is a signed int (16bit)
        self.OP, self.AA, self.BBBB = self.cm.packer["BBh"].unpack(
            buff[: self.length]
        )

    def get_output(self, idx: int = -1) -> str:
        return "v{}, {}".format(self.AA, self.BBBB)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        return [(Operand.REGISTER, self.AA), (Operand.LITERAL, self.BBBB)]

    def get_literals(self) -> list[int]:
        return [self.BBBB]

    def get_raw(self) -> bytes:
        return self.cm.packer["BBh"].pack(self.OP, self.AA, self.BBBB)

Instruction21t #

Bases: Instruction

This class represents all instructions which have the 21t format

Source code in androguard/core/dex/__init__.py
class Instruction21t(Instruction):
    """
    This class represents all instructions which have the 21t format
    """

    length = 4

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        self.OP, self.AA, self.BBBB = cm.packer["BBh"].unpack(
            buff[: self.length]
        )

    def get_output(self, idx: int = -1) -> str:
        return "v{}, {:+04x}h".format(self.AA, self.BBBB)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        return [(Operand.REGISTER, self.AA), (Operand.OFFSET, self.BBBB)]

    def get_ref_off(self) -> int:
        return self.BBBB

    def get_raw(self) -> bytes:
        return self.cm.packer["Hh"].pack((self.AA << 8) | self.OP, self.BBBB)

Instruction22b #

Bases: Instruction

This class represents all instructions which have the 22b format

Source code in androguard/core/dex/__init__.py
class Instruction22b(Instruction):
    """
    This class represents all instructions which have the 22b format
    """

    length = 4

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        self.OP, self.AA, self.BB, self.CC = cm.packer["BBBb"].unpack(
            buff[: self.length]
        )

    def get_output(self, idx: int = -1) -> str:
        return "v{}, v{}, {}".format(self.AA, self.BB, self.CC)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        return [
            (Operand.REGISTER, self.AA),
            (Operand.REGISTER, self.BB),
            (Operand.LITERAL, self.CC),
        ]

    def get_literals(self) -> list[int]:
        return [self.CC]

    def get_raw(self) -> bytes:
        return self.cm.packer["Hh"].pack(
            (self.AA << 8) | self.OP, (self.CC << 8) | self.BB
        )

Instruction22c #

Bases: Instruction

This class represents all instructions which have the 22c format

Source code in androguard/core/dex/__init__.py
class Instruction22c(Instruction):
    """
    This class represents all instructions which have the 22c format
    """

    length = 4

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        i16, self.CCCC = cm.packer["2H"].unpack(buff[: self.length])
        self.OP = i16 & 0xFF
        self.A = (i16 >> 8) & 0xF
        self.B = (i16 >> 12) & 0xF

    def get_output(self, idx: int = -1):
        kind = get_kind(self.cm, self.get_kind(), self.CCCC)
        return "v{}, v{}, {}".format(self.A, self.B, kind)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        kind = get_kind(self.cm, self.get_kind(), self.CCCC)
        return [
            (Operand.REGISTER, self.A),
            (Operand.REGISTER, self.B),
            (self.get_kind() + Operand.KIND, self.CCCC, kind),
        ]

    def get_ref_kind(self) -> int:
        return self.CCCC

    def get_raw(self) -> int:
        return self.cm.packer["2H"].pack(
            (self.B << 12) | (self.A << 8) | self.OP, self.CCCC
        )

Instruction22cs #

Bases: Instruction

This class represents all instructions which have the 22cs format

Source code in androguard/core/dex/__init__.py
class Instruction22cs(Instruction):
    """
    This class represents all instructions which have the 22cs format
    """

    length = 4

    def __init__(self, cm: ClassManager, buff: bytes) -> str:
        super().__init__()
        self.cm = cm

        i16, self.CCCC = cm.packer["2H"].unpack(buff[: self.length])
        self.OP = i16 & 0xFF
        self.A = (i16 >> 8) & 0xF
        self.B = (i16 >> 12) & 0xF

    def get_output(self, idx: int = -1) -> str:
        kind = get_kind(self.cm, self.get_kind(), self.CCCC)
        return "v{}, v{}, {}".format(self.A, self.B, kind)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        kind = get_kind(self.cm, self.get_kind(), self.CCCC)
        return [
            (Operand.REGISTER, self.A),
            (Operand.REGISTER, self.B),
            (self.get_kind() + Operand.KIND, self.CCCC, kind),
        ]

    def get_ref_kind(self) -> int:
        return self.CCCC

    def get_raw(self) -> bytes:
        return self.cm.packer["2H"].pack(
            (self.B << 12) | (self.A << 8) | self.OP, self.CCCC
        )

Instruction22s #

Bases: Instruction

This class represents all instructions which have the 22s format

Source code in androguard/core/dex/__init__.py
class Instruction22s(Instruction):
    """
    This class represents all instructions which have the 22s format
    """

    length = 4

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        i16, self.CCCC = cm.packer["Hh"].unpack(buff[: self.length])
        self.OP = i16 & 0xFF
        self.A = (i16 >> 8) & 0xF
        self.B = (i16 >> 12) & 0xF

    def get_output(self, idx: int = -1) -> str:
        return "v{}, v{}, {}".format(self.A, self.B, self.CCCC)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        return [
            (Operand.REGISTER, self.A),
            (Operand.REGISTER, self.B),
            (Operand.LITERAL, self.CCCC),
        ]

    def get_literals(self) -> list[int]:
        return [self.CCCC]

    def get_raw(self) -> bytes:
        return self.cm.packer["Hh"].pack(
            (self.B << 12) | (self.A << 8) | self.OP, self.CCCC
        )

Instruction22t #

Bases: Instruction

This class represents all instructions which have the 22t format

Source code in androguard/core/dex/__init__.py
class Instruction22t(Instruction):
    """
    This class represents all instructions which have the 22t format
    """

    length = 4

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        i16, self.CCCC = cm.packer["Hh"].unpack(buff[: self.length])
        self.OP = i16 & 0xFF
        self.A = (i16 >> 8) & 0xF
        self.B = (i16 >> 12) & 0xF

    def get_output(self, idx: int = -1) -> str:
        return "v{}, v{}, {:+04x}h".format(self.A, self.B, self.CCCC)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        return [
            (Operand.REGISTER, self.A),
            (Operand.REGISTER, self.B),
            (Operand.OFFSET, self.CCCC),
        ]

    def get_ref_off(self) -> int:
        return self.CCCC

    def get_raw(self) -> bytes:
        return self.cm.packer["Hh"].pack(
            (self.B << 12) | (self.A << 8) | self.OP, self.CCCC
        )

Instruction22x #

Bases: Instruction

This class represents all instructions which have the 22x format

Source code in androguard/core/dex/__init__.py
class Instruction22x(Instruction):
    """
    This class represents all instructions which have the 22x format
    """

    length = 4

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        self.OP, self.AA, self.BBBB = cm.packer["BBH"].unpack(
            buff[: self.length]
        )

    def get_output(self, idx: int = -1) -> str:
        return "v{}, v{}".format(self.AA, self.BBBB)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        return [(Operand.REGISTER, self.AA), (Operand.REGISTER, self.BBBB)]

    def get_raw(self) -> bytes:
        return self.cm.packer["2H"].pack((self.AA << 8) | self.OP, self.BBBB)

Instruction23x #

Bases: Instruction

This class represents all instructions which have the 23x format

Source code in androguard/core/dex/__init__.py
class Instruction23x(Instruction):
    """
    This class represents all instructions which have the 23x format
    """

    length = 4

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        self.OP, self.AA, self.BB, self.CC = cm.packer["BBBB"].unpack(
            buff[: self.length]
        )

    def get_output(self, idx: int = -1) -> str:
        return "v{}, v{}, v{}".format(self.AA, self.BB, self.CC)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        return [
            (Operand.REGISTER, self.AA),
            (Operand.REGISTER, self.BB),
            (Operand.REGISTER, self.CC),
        ]

    def get_raw(self) -> bytes:
        return self.cm.packer["2H"].pack(
            (self.AA << 8) | self.OP, (self.CC << 8) | self.BB
        )

Instruction30t #

Bases: Instruction

This class represents all instructions which have the 30t format

Source code in androguard/core/dex/__init__.py
class Instruction30t(Instruction):
    """
    This class represents all instructions which have the 30t format
    """

    length = 6

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        self.OP, padding, self.AAAAAAAA = cm.packer["BBi"].unpack(
            buff[: self.length]
        )
        if padding != 0:
            raise InvalidInstruction(
                'High byte of opcode with format 30t must be zero!'
            )

    def get_output(self, idx: int = -1) -> str:
        return "{:+08x}h".format(self.AAAAAAAA)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        return [(Operand.OFFSET, self.AAAAAAAA)]

    def get_ref_off(self) -> int:
        return self.AAAAAAAA

    def get_raw(self) -> bytes:
        return self.cm.packer["Hi"].pack(self.OP, self.AAAAAAAA)

Instruction31c #

Bases: Instruction

This class represents all instructions which have the 31c format

Source code in androguard/core/dex/__init__.py
class Instruction31c(Instruction):
    """
    This class represents all instructions which have the 31c format
    """

    length = 6

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm
        self.OP, self.AA, self.BBBBBBBB = cm.packer["BBi"].unpack(
            buff[: self.length]
        )

    def get_output(self, idx: int = -1) -> str:
        kind = get_kind(self.cm, self.get_kind(), self.BBBBBBBB)
        return "v{}, {}".format(self.AA, kind)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        kind = get_kind(self.cm, self.get_kind(), self.BBBBBBBB)
        return [
            (Operand.REGISTER, self.AA),
            (self.get_kind() + Operand.KIND, self.BBBBBBBB, kind),
        ]

    def get_ref_kind(self) -> int:
        return self.BBBBBBBB

    def get_string(self) -> str:
        """
        Return the string associated to the 'kind' argument

        :returns: string
        """
        return get_kind(self.cm, self.get_kind(), self.BBBBBBBB)

    def get_raw_string(self) -> str:
        return get_kind(self.cm, Kind.RAW_STRING, self.BBBBBBBB)

    def get_raw(self) -> bytes:
        return self.cm.packer["HI"].pack(
            (self.AA << 8) | self.OP, self.BBBBBBBB
        )

get_string() #

Return the string associated to the 'kind' argument

Returns:

Type Description
str

string

Source code in androguard/core/dex/__init__.py
def get_string(self) -> str:
    """
    Return the string associated to the 'kind' argument

    :returns: string
    """
    return get_kind(self.cm, self.get_kind(), self.BBBBBBBB)

Instruction31i #

Bases: Instruction

This class represents all instructions which have the 31i format

Source code in androguard/core/dex/__init__.py
class Instruction31i(Instruction):
    """
    This class represents all instructions which have the 31i format
    """

    length = 6

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        self.OP, self.AA, self.BBBBBBBB = cm.packer["BBi"].unpack(
            buff[: self.length]
        )

        # 0x14 // const vAA, #+BBBBBBBB: arbitrary 32-bit constant
        # 0x17 // const-wide/32 vAA, #+BBBBBBBB: signed int (32 bits)

    def get_output(self, idx: int = -1) -> str:
        # FIXME: on const-wide/32: it is actually a register pair vAA:vAA+1!
        return "v{}, {}".format(self.AA, self.BBBBBBBB)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        return [(Operand.REGISTER, self.AA), (Operand.LITERAL, self.BBBBBBBB)]

    def get_literals(self) -> list[int]:
        return [self.BBBBBBBB]

    def get_raw(self) -> bytes:
        return self.cm.packer["BBi"].pack(self.OP, self.AA, self.BBBBBBBB)

Instruction31t #

Bases: Instruction

This class represents all instructions which have the 31t format

Source code in androguard/core/dex/__init__.py
class Instruction31t(Instruction):
    """
    This class represents all instructions which have the 31t format
    """

    length = 6

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        self.OP, self.AA, self.BBBBBBBB = cm.packer["BBi"].unpack(
            buff[: self.length]
        )

    def get_output(self, idx: int = -1) -> str:
        return "v{}, {:+08x}h".format(self.AA, self.BBBBBBBB)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        return [(Operand.REGISTER, self.AA), (Operand.OFFSET, self.BBBBBBBB)]

    def get_ref_off(self) -> int:
        return self.BBBBBBBB

    def get_raw(self) -> bytes:
        return self.cm.packer["Hi"].pack(
            (self.AA << 8) | self.OP, self.BBBBBBBB
        )

Instruction32x #

Bases: Instruction

This class represents all instructions which have the 32x format

Source code in androguard/core/dex/__init__.py
class Instruction32x(Instruction):
    """
    This class represents all instructions which have the 32x format
    """

    length = 6

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        self.OP, padding, self.AAAA, self.BBBB = cm.packer["BBHH"].unpack(
            buff[: self.length]
        )
        if padding != 0:
            raise InvalidInstruction(
                'High byte of opcode with format 32x must be zero!'
            )

    def get_output(self, idx: int = -1) -> str:
        return "v{}, v{}".format(self.AAAA, self.BBBB)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        return [(Operand.REGISTER, self.AAAA), (Operand.REGISTER, self.BBBB)]

    def get_raw(self) -> bytes:
        return self.cm.packer["3H"].pack(self.OP, self.AAAA, self.BBBB)

Instruction35c #

Bases: Instruction

This class represents all instructions which have the 35c format

Source code in androguard/core/dex/__init__.py
class Instruction35c(Instruction):
    """
    This class represents all instructions which have the 35c format
    """

    length = 6

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        i16a, self.BBBB, i16b = cm.packer["3H"].unpack(buff[: self.length])
        self.OP = i16a & 0xFF
        self.G = (i16a >> 8) & 0xF
        self.A = (i16a >> 12) & 0xF

        self.C = i16b & 0xF
        self.D = (i16b >> 4) & 0xF
        self.E = (i16b >> 8) & 0xF
        self.F = (i16b >> 12) & 0xF

    def get_output(self, idx: int = -1) -> str:
        kind = get_kind(self.cm, self.get_kind(), self.BBBB)

        if self.A == 0:
            return "%s" % kind
        elif self.A == 1:
            return "v%d, %s" % (self.C, kind)
        elif self.A == 2:
            return "v%d, v%d, %s" % (self.C, self.D, kind)
        elif self.A == 3:
            return "v%d, v%d, v%d, %s" % (self.C, self.D, self.E, kind)
        elif self.A == 4:
            return "v%d, v%d, v%d, v%d, %s" % (
                self.C,
                self.D,
                self.E,
                self.F,
                kind,
            )
        elif self.A == 5:
            return "v%d, v%d, v%d, v%d, v%d, %s" % (
                self.C,
                self.D,
                self.E,
                self.F,
                self.G,
                kind,
            )

        return ''

    def get_operands(self, idx: int = -1) -> list[tuple]:
        l = []
        kind = get_kind(self.cm, self.get_kind(), self.BBBB)

        if self.A == 0:
            l.append((self.get_kind() + Operand.KIND, self.BBBB, kind))
        elif self.A == 1:
            l.extend(
                [
                    (Operand.REGISTER, self.C),
                    (self.get_kind() + Operand.KIND, self.BBBB, kind),
                ]
            )
        elif self.A == 2:
            l.extend(
                [
                    (Operand.REGISTER, self.C),
                    (Operand.REGISTER, self.D),
                    (self.get_kind() + Operand.KIND, self.BBBB, kind),
                ]
            )
        elif self.A == 3:
            l.extend(
                [
                    (Operand.REGISTER, self.C),
                    (Operand.REGISTER, self.D),
                    (Operand.REGISTER, self.E),
                    (self.get_kind() + Operand.KIND, self.BBBB, kind),
                ]
            )
        elif self.A == 4:
            l.extend(
                [
                    (Operand.REGISTER, self.C),
                    (Operand.REGISTER, self.D),
                    (Operand.REGISTER, self.E),
                    (Operand.REGISTER, self.F),
                    (self.get_kind() + Operand.KIND, self.BBBB, kind),
                ]
            )
        elif self.A == 5:
            l.extend(
                [
                    (Operand.REGISTER, self.C),
                    (Operand.REGISTER, self.D),
                    (Operand.REGISTER, self.E),
                    (Operand.REGISTER, self.F),
                    (Operand.REGISTER, self.G),
                    (self.get_kind() + Operand.KIND, self.BBBB, kind),
                ]
            )

        return l

    def get_ref_kind(self) -> int:
        return self.BBBB

    def get_raw(self) -> bytes:
        return self.cm.packer["3H"].pack(
            (self.A << 12) | (self.G << 8) | self.OP,
            self.BBBB,
            (self.F << 12) | (self.E << 8) | (self.D << 4) | self.C,
        )

Instruction35mi #

Bases: Instruction

This class represents all instructions which have the 35mi format

Source code in androguard/core/dex/__init__.py
class Instruction35mi(Instruction):
    """
    This class represents all instructions which have the 35mi format
    """

    length = 6

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        i16a, self.BBBB, i16b = cm.packer["3H"].unpack(buff[: self.length])
        self.OP = i16a & 0xFF
        self.G = (i16a >> 8) & 0xF
        self.A = (i16a >> 12) & 0xF
        self.C = i16b & 0xF
        self.D = (i16b >> 4) & 0xF
        self.E = (i16b >> 8) & 0xF
        self.F = (i16b >> 12) & 0xF

    def get_output(self, idx: int = -1) -> str:
        kind = get_kind(self.cm, self.get_kind(), self.BBBB)

        if self.A == 1:
            return "v%d, %s" % (self.C, kind)
        elif self.A == 2:
            return "v%d, v%d, %s" % (self.C, self.D, kind)
        elif self.A == 3:
            return "v%d, v%d, v%d, %s" % (self.C, self.D, self.E, kind)
        elif self.A == 4:
            return "v%d, v%d, v%d, v%d, %s" % (
                self.C,
                self.D,
                self.E,
                self.F,
                kind,
            )
        elif self.A == 5:
            return "v%d, v%d, v%d, v%d, v%d, %s" % (
                self.C,
                self.D,
                self.E,
                self.F,
                self.G,
                kind,
            )

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        l = []
        kind = get_kind(self.cm, self.get_kind(), self.BBBB)

        if self.A == 1:
            l.extend(
                [
                    (Operand.REGISTER, self.C),
                    (self.get_kind() + Operand.KIND, self.BBBB, kind),
                ]
            )
        elif self.A == 2:
            l.extend(
                [
                    (Operand.REGISTER, self.C),
                    (Operand.REGISTER, self.D),
                    (self.get_kind() + Operand.KIND, self.BBBB, kind),
                ]
            )
        elif self.A == 3:
            l.extend(
                [
                    (Operand.REGISTER, self.C),
                    (Operand.REGISTER, self.D),
                    (Operand.REGISTER, self.E),
                    (self.get_kind() + Operand.KIND, self.BBBB, kind),
                ]
            )
        elif self.A == 4:
            l.extend(
                [
                    (Operand.REGISTER, self.C),
                    (Operand.REGISTER, self.D),
                    (Operand.REGISTER, self.E),
                    (Operand.REGISTER, self.F),
                    (self.get_kind() + Operand.KIND, self.BBBB, kind),
                ]
            )
        elif self.A == 5:
            l.extend(
                [
                    (Operand.REGISTER, self.C),
                    (Operand.REGISTER, self.D),
                    (Operand.REGISTER, self.E),
                    (Operand.REGISTER, self.F),
                    (Operand.REGISTER, self.G),
                    (self.get_kind() + Operand.KIND, self.BBBB, kind),
                ]
            )

        return l

    def get_ref_kind(self) -> int:
        return self.BBBB

    def get_raw(self) -> bytes:
        return self.cm.packer["3H"].pack(
            (self.A << 12) | (self.G << 8) | self.OP,
            self.BBBB,
            (self.F << 12) | (self.E << 8) | (self.D << 4) | self.C,
        )

Instruction35ms #

Bases: Instruction

This class represents all instructions which have the 35ms format

Source code in androguard/core/dex/__init__.py
class Instruction35ms(Instruction):
    """
    This class represents all instructions which have the 35ms format
    """

    length = 6

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        i16a, self.BBBB, i16b = cm.packer["3H"].unpack(buff[: self.length])
        self.OP = i16a & 0xFF
        self.G = (i16a >> 8) & 0xF
        self.A = (i16a >> 12) & 0xF
        self.C = i16b & 0xF
        self.D = (i16b >> 4) & 0xF
        self.E = (i16b >> 8) & 0xF
        self.F = (i16b >> 12) & 0xF

    def get_output(self, idx: int = -1) -> str:
        kind = get_kind(self.cm, self.get_kind(), self.BBBB)

        if self.A == 1:
            return "v%d, %s" % (self.C, kind)
        elif self.A == 2:
            return "v%d, v%d, %s" % (self.C, self.D, kind)
        elif self.A == 3:
            return "v%d, v%d, v%d, %s" % (self.C, self.D, self.E, kind)
        elif self.A == 4:
            return "v%d, v%d, v%d, v%d, %s" % (
                self.C,
                self.D,
                self.E,
                self.F,
                kind,
            )
        elif self.A == 5:
            return "v%d, v%d, v%d, v%d, v%d, %s" % (
                self.C,
                self.D,
                self.E,
                self.F,
                self.G,
                kind,
            )

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        l = []
        kind = get_kind(self.cm, self.get_kind(), self.BBBB)

        if self.A == 1:
            l.extend(
                [
                    (Operand.REGISTER, self.C),
                    (self.get_kind() + Operand.KIND, self.BBBB, kind),
                ]
            )
        elif self.A == 2:
            l.extend(
                [
                    (Operand.REGISTER, self.C),
                    (Operand.REGISTER, self.D),
                    (self.get_kind() + Operand.KIND, self.BBBB, kind),
                ]
            )
        elif self.A == 3:
            l.extend(
                [
                    (Operand.REGISTER, self.C),
                    (Operand.REGISTER, self.D),
                    (Operand.REGISTER, self.E),
                    (self.get_kind() + Operand.KIND, self.BBBB, kind),
                ]
            )
        elif self.A == 4:
            l.extend(
                [
                    (Operand.REGISTER, self.C),
                    (Operand.REGISTER, self.D),
                    (Operand.REGISTER, self.E),
                    (Operand.REGISTER, self.F),
                    (self.get_kind() + Operand.KIND, self.BBBB, kind),
                ]
            )
        elif self.A == 5:
            l.extend(
                [
                    (Operand.REGISTER, self.C),
                    (Operand.REGISTER, self.D),
                    (Operand.REGISTER, self.E),
                    (Operand.REGISTER, self.F),
                    (Operand.REGISTER, self.G),
                    (self.get_kind() + Operand.KIND, self.BBBB, kind),
                ]
            )

        return l

    def get_ref_kind(self) -> int:
        return self.BBBB

    def get_raw(self) -> bytes:
        return self.cm.packer["3H"].pack(
            (self.A << 12) | (self.G << 8) | self.OP,
            self.BBBB,
            (self.F << 12) | (self.E << 8) | (self.D << 4) | self.C,
        )

Instruction3rc #

Bases: Instruction

This class represents all instructions which have the 3rc format

Source code in androguard/core/dex/__init__.py
class Instruction3rc(Instruction):
    """
    This class represents all instructions which have the 3rc format
    """

    length = 6

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        self.OP, self.AA, self.BBBB, self.CCCC = cm.packer["BBHH"].unpack(
            buff[: self.length]
        )

        self.NNNN = self.CCCC + self.AA - 1

    def get_output(self, idx: int = -1) -> str:
        kind = get_kind(self.cm, self.get_kind(), self.BBBB)

        if self.CCCC == self.NNNN:
            return "v{}, {}".format(self.CCCC, kind)
        else:
            return "v{} ... v{}, {}".format(self.CCCC, self.NNNN, kind)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        kind = get_kind(self.cm, self.get_kind(), self.BBBB)

        return [
            (Operand.REGISTER, i) for i in range(self.CCCC, self.NNNN + 1)
        ] + [(self.get_kind() + Operand.KIND, self.BBBB, kind)]

    def get_ref_kind(self) -> int:
        return self.BBBB

    def get_raw(self) -> bytes:
        return self.cm.packer["3H"].pack(
            (self.AA << 8) | self.OP, self.BBBB, self.CCCC
        )

Instruction3rmi #

Bases: Instruction

This class represents all instructions which have the 3rmi format

Note, this instruction is similar to 3rc but holds an inline

Source code in androguard/core/dex/__init__.py
class Instruction3rmi(Instruction):
    """
    This class represents all instructions which have the 3rmi format

    Note, this instruction is similar to 3rc but holds an inline
    """

    length = 6

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        self.OP, self.AA, self.BBBB, self.CCCC = cm.packer["BBHH"].unpack(
            buff[: self.length]
        )

        self.NNNN = self.CCCC + self.AA - 1

    def get_output(self, idx: int = -1) -> str:
        kind = get_kind(self.cm, self.get_kind(), self.BBBB)

        if self.CCCC == self.NNNN:
            return "v{}, {}".format(self.CCCC, kind)
        else:
            return "v{} ... v{}, {}".format(self.CCCC, self.NNNN, kind)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        kind = get_kind(self.cm, self.get_kind(), self.BBBB)

        if self.CCCC == self.NNNN:
            return [
                (Operand.REGISTER, self.CCCC),
                (self.get_kind() + Operand.KIND, self.BBBB, kind),
            ]
        else:
            l = []
            for i in range(self.CCCC, self.NNNN):
                l.append((Operand.REGISTER, i))

            l.append((self.get_kind() + Operand.KIND, self.BBBB, kind))
            return l

    def get_ref_kind(self) -> int:
        return self.BBBB

    def get_raw(self) -> bytes:
        return self.cm.packer["3H"].pack(
            (self.AA << 8) | self.OP, self.BBBB, self.CCCC
        )

Instruction3rms #

Bases: Instruction

This class represents all instructions which have the 3rms format

Note, this instruction is similar to 3rc but holds a vtaboff

Source code in androguard/core/dex/__init__.py
class Instruction3rms(Instruction):
    """
    This class represents all instructions which have the 3rms format

    Note, this instruction is similar to 3rc but holds a vtaboff
    """

    length = 6

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        self.OP, self.AA, self.BBBB, self.CCCC = cm.packer["BBHH"].unpack(
            buff[: self.length]
        )

        self.NNNN = self.CCCC + self.AA - 1

    def get_output(self, idx: int = -1) -> str:
        kind = get_kind(self.cm, self.get_kind(), self.BBBB)

        if self.CCCC == self.NNNN:
            return "v{}, {}".format(self.CCCC, kind)
        else:
            return "v{} ... v{}, {}".format(self.CCCC, self.NNNN, kind)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        kind = get_kind(self.cm, self.get_kind(), self.BBBB)

        if self.CCCC == self.NNNN:
            return [
                (Operand.REGISTER, self.CCCC),
                (self.get_kind() + Operand.KIND, self.BBBB, kind),
            ]
        else:
            l = []
            for i in range(self.CCCC, self.NNNN):
                l.append((Operand.REGISTER, i))

            l.append((self.get_kind() + Operand.KIND, self.BBBB, kind))
            return l

    def get_ref_kind(self) -> int:
        return self.BBBB

    def get_raw(self) -> bytes:
        return self.cm.packer["3H"].pack(
            (self.AA << 8) | self.OP, self.BBBB, self.CCCC
        )

Instruction40sc #

Bases: Instruction

This class represents all instructions which have the 40sc format

This instruction is only used in ODEX

Source code in androguard/core/dex/__init__.py
class Instruction40sc(Instruction):
    """
    This class represents all instructions which have the 40sc format

    This instruction is only used in ODEX
    """

    length = 8

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        self.OP, self.BBBBBBBB, self.AAAA = cm.packer["HIH"].unpack(
            buff[: self.length]
        )

    def get_output(self, idx: int = -1) -> str:
        kind = get_kind(self.cm, self.get_kind(), self.BBBBBBBB)
        return "{}, {}".format(self.AAAA, kind)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        kind = get_kind(self.cm, self.get_kind(), self.BBBBBBBB)
        return [
            (Operand.LITERAL, self.AAAA),
            (self.get_kind() + Operand.KIND, self.BBBBBBBB, kind),
        ]

    def get_ref_kind(self) -> int:
        return self.BBBBBBBB

    def get_raw(self) -> bytes:
        return self.cm.packer["HIH"].pack(self.OP, self.BBBBBBBB, self.AAAA)

Instruction41c #

Bases: Instruction

This class represents all instructions which have the 41c format

This instruction is only used in ODEX

Source code in androguard/core/dex/__init__.py
class Instruction41c(Instruction):
    """
    This class represents all instructions which have the 41c format

    This instruction is only used in ODEX
    """

    length = 8

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        self.OP, self.BBBBBBBB, self.AAAA = cm.packer["HIH"].unpack(
            buff[: self.length]
        )

    def get_output(self, idx: int = -1) -> str:
        kind = get_kind(self.cm, self.get_kind(), self.BBBBBBBB)
        return "v{}, {}".format(self.AAAA, kind)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        kind = get_kind(self.cm, self.get_kind(), self.BBBBBBBB)
        return [
            (Operand.REGISTER, self.AAAA),
            (self.get_kind() + Operand.KIND, self.BBBBBBBB, kind),
        ]

    def get_ref_kind(self) -> int:
        return self.BBBBBBBB

    def get_raw(self) -> bytes:
        return self.cm.packer["HIH"].pack(self.OP, self.BBBBBBBB, self.AAAA)

Instruction51l #

Bases: Instruction

This class represents all instructions which have the 51l format

Source code in androguard/core/dex/__init__.py
class Instruction51l(Instruction):
    """
    This class represents all instructions which have the 51l format
    """

    length = 10

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        # arbitrary double-width (64-bit) constant
        self.OP, self.AA, self.BBBBBBBBBBBBBBBB = cm.packer["BBq"].unpack(
            buff[: self.length]
        )

    def get_output(self, idx: int = -1) -> str:
        return "v{}, {}".format(self.AA, self.BBBBBBBBBBBBBBBB)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        return [
            (Operand.REGISTER, self.AA),
            (Operand.LITERAL, self.BBBBBBBBBBBBBBBB),
        ]

    def get_literals(self) -> list[int]:
        return [self.BBBBBBBBBBBBBBBB]

    def get_raw(self) -> bytes:
        return self.cm.packer["BBq"].pack(
            self.OP, self.AA, self.BBBBBBBBBBBBBBBB
        )

Instruction52c #

Bases: Instruction

This class represents all instructions which have the 52c format

This instruction is only used in ODEX

Source code in androguard/core/dex/__init__.py
class Instruction52c(Instruction):
    """
    This class represents all instructions which have the 52c format

    This instruction is only used in ODEX
    """

    length = 10

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        # FIXME: Not in the documentation!
        # Using 16bit for opcode, but its ODEX, so...
        self.OP, self.CCCCCCCC, self.AAAA, self.BBBB = cm.packer[
            "HI2H"
        ].unpack(buff[: self.length])

    def get_output(self, idx: int = -1) -> str:
        kind = get_kind(self.cm, self.get_kind(), self.CCCCCCCC)
        return "v{}, v{}, {}".format(self.AAAA, self.BBBB, kind)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        kind = get_kind(self.cm, self.get_kind(), self.CCCCCCCC)
        return [
            (Operand.LITERAL, self.AAAA),
            (Operand.LITERAL, self.BBBB),
            (self.get_kind() + Operand.KIND, self.CCCCCCCC, kind),
        ]

    def get_ref_kind(self) -> int:
        return self.CCCCCCCC

    def get_raw(self) -> bytes:
        return self.cm.packer["HI2H"].pack(
            self.OP, self.CCCCCCCC, self.AAAA, self.BBBB
        )

Instruction5rc #

Bases: Instruction

This class represents all instructions which have the 5rc format

This instruction is only used in ODEX

Source code in androguard/core/dex/__init__.py
class Instruction5rc(Instruction):
    """
    This class represents all instructions which have the 5rc format

    This instruction is only used in ODEX
    """

    length = 10

    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        super().__init__()
        self.cm = cm

        self.OP, self.BBBBBBBB, self.AAAA, self.CCCC = cm.packer[
            "HI2H"
        ].unpack(buff[: self.length])

        self.NNNN = self.CCCC + self.AAAA - 1

    def get_output(self, idx: int = -1) -> str:
        kind = get_kind(self.cm, self.get_kind(), self.BBBBBBBB)

        if self.CCCC == self.NNNN:
            return "v{}, {}".format(self.CCCC, kind)
        else:
            return "v{} ... v{}, {}".format(self.CCCC, self.NNNN, kind)

    def get_operands(self, idx: int = -1) -> list[tuple[Operand, int]]:
        kind = get_kind(self.cm, self.get_kind(), self.BBBBBBBB)

        if self.CCCC == self.NNNN:
            return [
                (Operand.REGISTER, self.CCCC),
                (self.get_kind() + Operand.KIND, self.BBBBBBBB, kind),
            ]
        else:
            l = []
            for i in range(self.CCCC, self.NNNN):
                l.append((Operand.REGISTER, i))

            l.append((self.get_kind() + Operand.KIND, self.BBBBBBBB, kind))
            return l

    def get_ref_kind(self) -> int:
        return self.BBBBBBBB

    def get_raw(self) -> bytes:
        return self.cm.packer["HI2H"].pack(
            self.OP, self.BBBBBBBB, self.AAAA, self.CCCC
        )

LinearSweepAlgorithm #

This class is used to disassemble a method. The algorithm used by this class is linear sweep.

Source code in androguard/core/dex/__init__.py
class LinearSweepAlgorithm:
    """
    This class is used to disassemble a method. The algorithm used by this class is linear sweep.
    """

    @staticmethod
    def get_instructions(
        cm: ClassManager, size: int, insn: bytearray, idx: int
    ) -> Iterator[Instruction]:
        """
        Yields all instructions for the given bytecode sequence.
        If unknown/corrupt/unused instructions are encountered,
        the loop will stop and an error is written to the logger.

        That means that the bytecode read might be corrupt
        or was crafted in this way, to break parsers.

        :param cm: a `ClassManager` object
        :param size: the total size of the buffer in 16-bit units
        :param insn: a raw buffer where are the instructions
        :param idx: a start address in the buffer
        :raises InvalidInstruction: if an instruction is invalid
        :returns: iterator over `Instruction`s
        """
        is_odex = cm.get_odex_format()

        max_idx = size * calcsize('H')
        if max_idx > len(insn):
            logger.warning(
                "Declared size of instructions is larger than the bytecode!"
            )
            max_idx = len(insn)

        # Get instructions
        # TODO sometimes there are padding bytes after the last instruction, to ensure 16bit alignment.
        while idx < max_idx:
            # Get one 16bit unit
            # TODO: possible optimization; instead of reading the first 16 bits twice,
            #       just push this into the Instruction's constructor
            (op_value,) = cm.packer['H'].unpack(insn[idx : idx + 2])

            try:
                if op_value > 0xFF and (op_value & 0xFF) in (0x00, 0xFF):
                    # FIXME: in theory, it could happen that this is a normal opcode? I.e. a 0xff opcode with AA being non zero
                    if op_value in DALVIK_OPCODES_PAYLOAD:
                        # payload instructions, i.e. for arrays or switch
                        obj = get_instruction_payload(op_value, cm, insn[idx:])
                    elif is_odex and (op_value in DALVIK_OPCODES_OPTIMIZED):
                        # optimized instructions, only of ODEX file
                        obj = get_optimized_instruction(
                            cm, op_value, insn[idx:]
                        )
                    else:
                        raise InvalidInstruction(
                            "Unknown Instruction '0x{:04x}'".format(op_value)
                        )
                else:
                    obj = get_instruction(cm, op_value & 0xFF, insn[idx:])
            except InvalidInstruction as e:
                raise InvalidInstruction(
                    "Invalid instruction encountered! Stop parsing bytecode at idx %s. Message: %s",
                    idx,
                    e,
                )
            # emit instruction
            yield obj
            idx += obj.get_length()

get_instructions(cm, size, insn, idx) staticmethod #

Yields all instructions for the given bytecode sequence. If unknown/corrupt/unused instructions are encountered, the loop will stop and an error is written to the logger.

That means that the bytecode read might be corrupt or was crafted in this way, to break parsers.

Parameters:

Name Type Description Default
cm ClassManager

a ClassManager object

required
size int

the total size of the buffer in 16-bit units

required
insn bytearray

a raw buffer where are the instructions

required
idx int

a start address in the buffer

required

Returns:

Type Description
Iterator[Instruction]

iterator over Instructions

Raises:

Type Description
InvalidInstruction

if an instruction is invalid

Source code in androguard/core/dex/__init__.py
@staticmethod
def get_instructions(
    cm: ClassManager, size: int, insn: bytearray, idx: int
) -> Iterator[Instruction]:
    """
    Yields all instructions for the given bytecode sequence.
    If unknown/corrupt/unused instructions are encountered,
    the loop will stop and an error is written to the logger.

    That means that the bytecode read might be corrupt
    or was crafted in this way, to break parsers.

    :param cm: a `ClassManager` object
    :param size: the total size of the buffer in 16-bit units
    :param insn: a raw buffer where are the instructions
    :param idx: a start address in the buffer
    :raises InvalidInstruction: if an instruction is invalid
    :returns: iterator over `Instruction`s
    """
    is_odex = cm.get_odex_format()

    max_idx = size * calcsize('H')
    if max_idx > len(insn):
        logger.warning(
            "Declared size of instructions is larger than the bytecode!"
        )
        max_idx = len(insn)

    # Get instructions
    # TODO sometimes there are padding bytes after the last instruction, to ensure 16bit alignment.
    while idx < max_idx:
        # Get one 16bit unit
        # TODO: possible optimization; instead of reading the first 16 bits twice,
        #       just push this into the Instruction's constructor
        (op_value,) = cm.packer['H'].unpack(insn[idx : idx + 2])

        try:
            if op_value > 0xFF and (op_value & 0xFF) in (0x00, 0xFF):
                # FIXME: in theory, it could happen that this is a normal opcode? I.e. a 0xff opcode with AA being non zero
                if op_value in DALVIK_OPCODES_PAYLOAD:
                    # payload instructions, i.e. for arrays or switch
                    obj = get_instruction_payload(op_value, cm, insn[idx:])
                elif is_odex and (op_value in DALVIK_OPCODES_OPTIMIZED):
                    # optimized instructions, only of ODEX file
                    obj = get_optimized_instruction(
                        cm, op_value, insn[idx:]
                    )
                else:
                    raise InvalidInstruction(
                        "Unknown Instruction '0x{:04x}'".format(op_value)
                    )
            else:
                obj = get_instruction(cm, op_value & 0xFF, insn[idx:])
        except InvalidInstruction as e:
            raise InvalidInstruction(
                "Invalid instruction encountered! Stop parsing bytecode at idx %s. Message: %s",
                idx,
                e,
            )
        # emit instruction
        yield obj
        idx += obj.get_length()

MapItem #

Source code in androguard/core/dex/__init__.py
class MapItem:
    def __init__(self, buff: bytes, cm: ClassManager) -> None:
        """
        Implementation of a map_item, which occours in a map_list

        https://source.android.com/devices/tech/dalvik/dex-format#map-item
        """
        self.CM = cm
        self.buff = buff

        self.off = buff.tell()

        self.type = TypeMapItem(cm.packer["H"].unpack(buff.read(2))[0])
        self.unused, self.size, self.offset = cm.packer["H2I"].unpack(
            buff.read(10)
        )

        self.item = None

    def get_off(self) -> int:
        """Gets the offset of the map item itself inside the DEX file"""
        return self.off

    def get_offset(self) -> int:
        """Gets the offset of the item of the map item"""
        return self.offset

    def get_type(self) -> TypeMapItem:
        return self.type

    def get_size(self) -> int:
        """
        Returns the number of items found at the location indicated by
        [get_offset][androguard.core.dex.MapItem.get_offset].

        :returns: number of items
        """
        return self.size

    def parse(self) -> None:
        """parse this map_item by parsing its potential [TypeMapItem][androguard.core.dex.dex_types.TypeMapItem] type and cast it appropriately."""
        logger.debug("Starting parsing map_item '{}'".format(self.type.name))
        started_at = time.time()

        # Not all items are aligned in the same way. Most are aligned by four bytes,
        # but there are a few which are not!
        # Hence, we need to check the alignment for each item.

        buff = self.buff
        cm = self.CM

        if TypeMapItem.STRING_ID_ITEM == self.type:
            # Byte aligned
            buff.seek(self.offset)
            self.item = [StringIdItem(buff, cm) for _ in range(self.size)]

        elif TypeMapItem.CODE_ITEM == self.type:
            # 4-byte aligned
            buff.seek(self.offset + (self.offset % 4))
            self.item = CodeItem(self.size, buff, cm)

        elif TypeMapItem.TYPE_ID_ITEM == self.type:
            # 4-byte aligned
            buff.seek(self.offset + (self.offset % 4))
            self.item = TypeHIdItem(self.size, buff, cm)

        elif TypeMapItem.PROTO_ID_ITEM == self.type:
            # 4-byte aligned
            buff.seek(self.offset + (self.offset % 4))
            self.item = ProtoHIdItem(self.size, buff, cm)

        elif TypeMapItem.FIELD_ID_ITEM == self.type:
            # 4-byte aligned
            buff.seek(self.offset + (self.offset % 4))
            self.item = FieldHIdItem(self.size, buff, cm)

        elif TypeMapItem.METHOD_ID_ITEM == self.type:
            # 4-byte aligned
            buff.seek(self.offset + (self.offset % 4))
            self.item = MethodHIdItem(self.size, buff, cm)

        elif TypeMapItem.CLASS_DEF_ITEM == self.type:
            # 4-byte aligned
            buff.seek(self.offset + (self.offset % 4))
            self.item = ClassHDefItem(self.size, buff, cm)

        elif TypeMapItem.HEADER_ITEM == self.type:
            # FIXME probably not necessary to parse again here...
            # 4-byte aligned
            buff.seek(self.offset + (self.offset % 4))
            self.item = HeaderItem(self.size, buff, cm)

        elif TypeMapItem.ANNOTATION_ITEM == self.type:
            # Byte aligned
            buff.seek(self.offset)
            self.item = [AnnotationItem(buff, cm) for _ in range(self.size)]

        elif TypeMapItem.ANNOTATION_SET_ITEM == self.type:
            # 4-byte aligned
            buff.seek(self.offset + (self.offset % 4))
            self.item = [AnnotationSetItem(buff, cm) for _ in range(self.size)]

        elif TypeMapItem.ANNOTATIONS_DIRECTORY_ITEM == self.type:
            # 4-byte aligned
            buff.seek(self.offset + (self.offset % 4))
            self.item = [
                AnnotationsDirectoryItem(buff, cm) for _ in range(self.size)
            ]

        elif TypeMapItem.HIDDENAPI_CLASS_DATA_ITEM == self.type:
            # Byte aligned
            buff.seek(self.offset)
            self.item = HiddenApiClassDataItem(buff, cm)

        elif TypeMapItem.ANNOTATION_SET_REF_LIST == self.type:
            # 4-byte aligned
            buff.seek(self.offset + (self.offset % 4))
            self.item = [
                AnnotationSetRefList(buff, cm) for _ in range(self.size)
            ]

        elif TypeMapItem.TYPE_LIST == self.type:
            # 4-byte aligned
            buff.seek(self.offset + (self.offset % 4))
            self.item = [TypeList(buff, cm) for _ in range(self.size)]

        elif TypeMapItem.STRING_DATA_ITEM == self.type:
            # Byte aligned
            buff.seek(self.offset)
            self.item = [StringDataItem(buff, cm) for _ in range(self.size)]

        elif TypeMapItem.DEBUG_INFO_ITEM == self.type:
            # Byte aligned
            buff.seek(self.offset)
            self.item = DebugInfoItemEmpty(buff, cm)

        elif TypeMapItem.ENCODED_ARRAY_ITEM == self.type:
            # Byte aligned
            buff.seek(self.offset)
            self.item = [EncodedArrayItem(buff, cm) for _ in range(self.size)]

        elif TypeMapItem.CLASS_DATA_ITEM == self.type:
            # Byte aligned
            buff.seek(self.offset)
            self.item = [ClassDataItem(buff, cm) for _ in range(self.size)]

        elif TypeMapItem.MAP_LIST == self.type:
            # 4-byte aligned
            buff.seek(self.offset + (self.offset % 4))
            pass  # It's me I think !!! No need to parse again

        else:
            logger.warning(
                "Map item with id '{type}' offset: 0x{off:x} ({off}) "
                "size: {size} is unknown. "
                "Is this a newer DEX format?".format(
                    type=self.type, off=buff.tell(), size=self.size
                )
            )

        diff = time.time() - started_at
        minutes, seconds = diff // 60, diff % 60
        logger.debug(
            "End of parsing map_item '{}'. Required time {:.0f}:{:07.4f}".format(
                self.type.name, minutes, seconds
            )
        )

    def show(self) -> None:
        bytecode._Print("\tMAP_TYPE_ITEM", self.type.name)

        if self.item is not None:
            if isinstance(self.item, list):
                for i in self.item:
                    i.show()
            else:
                self.item.show()

    def get_obj(self) -> object:
        """
        Return the associated item itself.
        Might return `None`, if [parse][androguard.core.dex.MapItem.parse] was not called yet.

        This method is the same as `item`.

        :returns: item object
        """
        return self.item

    # alias
    get_item = get_obj

    def get_raw(self) -> bytes:
        # FIXME why is it necessary to get the offset here agin? We have this
        # stored?!
        if isinstance(self.item, list):
            self.offset = self.item[0].get_off()
        else:
            self.offset = self.item.get_off()

        return self.CM.packer["2H2I"].pack(
            self.type, self.unused, self.size, self.offset
        )

    def get_length(self) -> int:
        return calcsize("HHII")

    def set_item(self, item: object) -> None:
        self.item = item

__init__(buff, cm) #

Implementation of a map_item, which occours in a map_list

https://source.android.com/devices/tech/dalvik/dex-format#map-item

Source code in androguard/core/dex/__init__.py
def __init__(self, buff: bytes, cm: ClassManager) -> None:
    """
    Implementation of a map_item, which occours in a map_list

    https://source.android.com/devices/tech/dalvik/dex-format#map-item
    """
    self.CM = cm
    self.buff = buff

    self.off = buff.tell()

    self.type = TypeMapItem(cm.packer["H"].unpack(buff.read(2))[0])
    self.unused, self.size, self.offset = cm.packer["H2I"].unpack(
        buff.read(10)
    )

    self.item = None

get_obj() #

Return the associated item itself. Might return None, if parse was not called yet.

This method is the same as item.

Returns:

Type Description
object

item object

Source code in androguard/core/dex/__init__.py
def get_obj(self) -> object:
    """
    Return the associated item itself.
    Might return `None`, if [parse][androguard.core.dex.MapItem.parse] was not called yet.

    This method is the same as `item`.

    :returns: item object
    """
    return self.item

get_off() #

Gets the offset of the map item itself inside the DEX file

Source code in androguard/core/dex/__init__.py
def get_off(self) -> int:
    """Gets the offset of the map item itself inside the DEX file"""
    return self.off

get_offset() #

Gets the offset of the item of the map item

Source code in androguard/core/dex/__init__.py
def get_offset(self) -> int:
    """Gets the offset of the item of the map item"""
    return self.offset

get_size() #

Returns the number of items found at the location indicated by get_offset.

Returns:

Type Description
int

number of items

Source code in androguard/core/dex/__init__.py
def get_size(self) -> int:
    """
    Returns the number of items found at the location indicated by
    [get_offset][androguard.core.dex.MapItem.get_offset].

    :returns: number of items
    """
    return self.size

parse() #

parse this map_item by parsing its potential TypeMapItem type and cast it appropriately.

Source code in androguard/core/dex/__init__.py
def parse(self) -> None:
    """parse this map_item by parsing its potential [TypeMapItem][androguard.core.dex.dex_types.TypeMapItem] type and cast it appropriately."""
    logger.debug("Starting parsing map_item '{}'".format(self.type.name))
    started_at = time.time()

    # Not all items are aligned in the same way. Most are aligned by four bytes,
    # but there are a few which are not!
    # Hence, we need to check the alignment for each item.

    buff = self.buff
    cm = self.CM

    if TypeMapItem.STRING_ID_ITEM == self.type:
        # Byte aligned
        buff.seek(self.offset)
        self.item = [StringIdItem(buff, cm) for _ in range(self.size)]

    elif TypeMapItem.CODE_ITEM == self.type:
        # 4-byte aligned
        buff.seek(self.offset + (self.offset % 4))
        self.item = CodeItem(self.size, buff, cm)

    elif TypeMapItem.TYPE_ID_ITEM == self.type:
        # 4-byte aligned
        buff.seek(self.offset + (self.offset % 4))
        self.item = TypeHIdItem(self.size, buff, cm)

    elif TypeMapItem.PROTO_ID_ITEM == self.type:
        # 4-byte aligned
        buff.seek(self.offset + (self.offset % 4))
        self.item = ProtoHIdItem(self.size, buff, cm)

    elif TypeMapItem.FIELD_ID_ITEM == self.type:
        # 4-byte aligned
        buff.seek(self.offset + (self.offset % 4))
        self.item = FieldHIdItem(self.size, buff, cm)

    elif TypeMapItem.METHOD_ID_ITEM == self.type:
        # 4-byte aligned
        buff.seek(self.offset + (self.offset % 4))
        self.item = MethodHIdItem(self.size, buff, cm)

    elif TypeMapItem.CLASS_DEF_ITEM == self.type:
        # 4-byte aligned
        buff.seek(self.offset + (self.offset % 4))
        self.item = ClassHDefItem(self.size, buff, cm)

    elif TypeMapItem.HEADER_ITEM == self.type:
        # FIXME probably not necessary to parse again here...
        # 4-byte aligned
        buff.seek(self.offset + (self.offset % 4))
        self.item = HeaderItem(self.size, buff, cm)

    elif TypeMapItem.ANNOTATION_ITEM == self.type:
        # Byte aligned
        buff.seek(self.offset)
        self.item = [AnnotationItem(buff, cm) for _ in range(self.size)]

    elif TypeMapItem.ANNOTATION_SET_ITEM == self.type:
        # 4-byte aligned
        buff.seek(self.offset + (self.offset % 4))
        self.item = [AnnotationSetItem(buff, cm) for _ in range(self.size)]

    elif TypeMapItem.ANNOTATIONS_DIRECTORY_ITEM == self.type:
        # 4-byte aligned
        buff.seek(self.offset + (self.offset % 4))
        self.item = [
            AnnotationsDirectoryItem(buff, cm) for _ in range(self.size)
        ]

    elif TypeMapItem.HIDDENAPI_CLASS_DATA_ITEM == self.type:
        # Byte aligned
        buff.seek(self.offset)
        self.item = HiddenApiClassDataItem(buff, cm)

    elif TypeMapItem.ANNOTATION_SET_REF_LIST == self.type:
        # 4-byte aligned
        buff.seek(self.offset + (self.offset % 4))
        self.item = [
            AnnotationSetRefList(buff, cm) for _ in range(self.size)
        ]

    elif TypeMapItem.TYPE_LIST == self.type:
        # 4-byte aligned
        buff.seek(self.offset + (self.offset % 4))
        self.item = [TypeList(buff, cm) for _ in range(self.size)]

    elif TypeMapItem.STRING_DATA_ITEM == self.type:
        # Byte aligned
        buff.seek(self.offset)
        self.item = [StringDataItem(buff, cm) for _ in range(self.size)]

    elif TypeMapItem.DEBUG_INFO_ITEM == self.type:
        # Byte aligned
        buff.seek(self.offset)
        self.item = DebugInfoItemEmpty(buff, cm)

    elif TypeMapItem.ENCODED_ARRAY_ITEM == self.type:
        # Byte aligned
        buff.seek(self.offset)
        self.item = [EncodedArrayItem(buff, cm) for _ in range(self.size)]

    elif TypeMapItem.CLASS_DATA_ITEM == self.type:
        # Byte aligned
        buff.seek(self.offset)
        self.item = [ClassDataItem(buff, cm) for _ in range(self.size)]

    elif TypeMapItem.MAP_LIST == self.type:
        # 4-byte aligned
        buff.seek(self.offset + (self.offset % 4))
        pass  # It's me I think !!! No need to parse again

    else:
        logger.warning(
            "Map item with id '{type}' offset: 0x{off:x} ({off}) "
            "size: {size} is unknown. "
            "Is this a newer DEX format?".format(
                type=self.type, off=buff.tell(), size=self.size
            )
        )

    diff = time.time() - started_at
    minutes, seconds = diff // 60, diff % 60
    logger.debug(
        "End of parsing map_item '{}'. Required time {:.0f}:{:07.4f}".format(
            self.type.name, minutes, seconds
        )
    )

MapList #

This class can parse the "map_list" of the dex format

https://source.android.com/devices/tech/dalvik/dex-format#map-list

Source code in androguard/core/dex/__init__.py
class MapList:
    """
    This class can parse the "map_list" of the dex format

    https://source.android.com/devices/tech/dalvik/dex-format#map-list
    """

    def __init__(self, cm: ClassManager, off: int, buff: BinaryIO) -> None:
        self.CM = cm

        buff.seek(off)

        self.offset = off

        (self.size,) = cm.packer["I"].unpack(buff.read(4))

        self.map_item = []
        for _ in range(0, self.size):
            idx = buff.tell()

            mi = MapItem(buff, self.CM)
            self.map_item.append(mi)

            buff.seek(idx + mi.get_length())

        load_order = TypeMapItem.determine_load_order()
        ordered = sorted(
            self.map_item, key=lambda mi: load_order[mi.get_type()]
        )

        for mi in ordered:
            mi.parse()

            c_item = mi.get_item()
            if c_item is None:
                mi.set_item(self)
                c_item = mi.get_item()

            self.CM.add_type_item(mi.get_type(), mi, c_item)

    def get_off(self) -> int:
        return self.offset

    def set_off(self, off: int) -> None:
        self.offset = off

    def get_item_type(self, ttype: TypeMapItem) -> object:
        """
        Get a particular item type

        :param ttype: a `TypeMapItem` enum which represents the desired type

        :returns: `None` or the item object
        """
        for i in self.map_item:
            if i.get_type() == ttype:
                return i.get_item()
        return None

    def show(self) -> None:
        """
        Print with a pretty display the MapList object
        """
        bytecode._Print("MAP_LIST SIZE", self.size)
        for i in self.map_item:
            if i.item != self:
                # FIXME this does not work for CodeItems!
                # as we do not have the method analysis here...
                i.show()

    def get_obj(self) -> list[object]:
        return [x.get_obj() for x in self.map_item]

    def get_raw(self) -> bytes:
        return self.CM.packer["I"].pack(self.size) + b''.join(
            x.get_raw() for x in self.map_item
        )

    def get_class_manager(self) -> ClassManager:
        return self.CM

    def get_length(self) -> int:
        return len(self.get_raw())

get_item_type(ttype) #

Get a particular item type

Parameters:

Name Type Description Default
ttype TypeMapItem

a TypeMapItem enum which represents the desired type

required

Returns:

Type Description
object

None or the item object

Source code in androguard/core/dex/__init__.py
def get_item_type(self, ttype: TypeMapItem) -> object:
    """
    Get a particular item type

    :param ttype: a `TypeMapItem` enum which represents the desired type

    :returns: `None` or the item object
    """
    for i in self.map_item:
        if i.get_type() == ttype:
            return i.get_item()
    return None

show() #

Print with a pretty display the MapList object

Source code in androguard/core/dex/__init__.py
def show(self) -> None:
    """
    Print with a pretty display the MapList object
    """
    bytecode._Print("MAP_LIST SIZE", self.size)
    for i in self.map_item:
        if i.item != self:
            # FIXME this does not work for CodeItems!
            # as we do not have the method analysis here...
            i.show()

MethodAnnotation #

This class can parse a method_annotation of a dex file

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a buff object of the method_annotation

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
class MethodAnnotation:
    """
    This class can parse a `method_annotation` of a dex file

    :param buff: a string which represents a buff object of the `method_annotation`
    :param cm: a `ClassManager` object
    """

    def __init__(self, buff: BinaryIO, cm: ClassManager) -> None:
        self.offset = buff.tell()

        self.CM = cm
        self.method_idx, self.annotations_off = cm.packer["2I"].unpack(
            buff.read(8)
        )

    def get_method_idx(self) -> int:
        """
        Return the index into the method_ids list for the identity of the method being annotated

        :returns: the index
        """
        return self.method_idx

    def get_annotations_off(self) -> int:
        """
        Return the offset from the start of the file to the list of annotations for the method

        :returns: the offset
        """
        return self.annotations_off

    def set_off(self, off: int) -> None:
        self.offset = off

    def get_off(self) -> int:
        return self.offset

    def show(self) -> None:
        bytecode._PrintSubBanner("Method Annotation")
        bytecode._PrintDefault(
            "method_idx=0x%x annotations_off=0x%x\n"
            % (self.method_idx, self.annotations_off)
        )

    def get_obj(self) -> bytes:
        if self.annotations_off != 0:
            self.annotations_off = self.CM.get_obj_by_offset(
                self.annotations_off
            ).get_off()

        return self.CM.packer["2I"].pack(self.method_idx, self.annotations_off)

    def get_raw(self) -> bytes:
        return self.get_obj()

    def get_length(self) -> int:
        return len(self.get_raw())

get_annotations_off() #

Return the offset from the start of the file to the list of annotations for the method

Returns:

Type Description
int

the offset

Source code in androguard/core/dex/__init__.py
def get_annotations_off(self) -> int:
    """
    Return the offset from the start of the file to the list of annotations for the method

    :returns: the offset
    """
    return self.annotations_off

get_method_idx() #

Return the index into the method_ids list for the identity of the method being annotated

Returns:

Type Description
int

the index

Source code in androguard/core/dex/__init__.py
def get_method_idx(self) -> int:
    """
    Return the index into the method_ids list for the identity of the method being annotated

    :returns: the index
    """
    return self.method_idx

MethodHIdItem #

This class can parse a list of method_id_item of a dex file

Source code in androguard/core/dex/__init__.py
class MethodHIdItem:
    """
    This class can parse a list of `method_id_item` of a dex file
    """


    def __init__(self, size:int, buff: BinaryIO, cm:ClassManager) -> None:
        """
        :param buff: a string which represents a Buff object of the list of `method_id_item`
        :param cm: a `ClassManager` object
        """
        self.CM = cm

        self.offset = buff.tell()

        self.method_id_items = [MethodIdItem(buff, cm) for i in range(0, size)]

    def set_off(self, off: int):
        self.offset = off

    def get_off(self) -> int:
        return self.offset

    def gets(self) -> list[MethodIdItem]:
        return self.method_id_items

    def get(self, idx) -> Union[MethodIdItem, MethodIdItemInvalid]:
        try:
            return self.method_id_items[idx]
        except IndexError:
            return MethodIdItemInvalid()

    def reload(self) -> None:
        for i in self.method_id_items:
            i.reload()

    def show(self) -> None:
        print("METHOD_ID_ITEM")
        nb = 0
        for i in self.method_id_items:
            print(nb, end=' ')
            i.show()
            nb = nb + 1

    def get_obj(self) -> list[MethodIdItem]:
        return [i for i in self.method_id_items]

    def get_raw(self) -> bytes:
        return b''.join(i.get_raw() for i in self.method_id_items)

    def get_length(self) -> int:
        length = 0
        for i in self.method_id_items:
            length += i.get_length()
        return length

__init__(size, buff, cm) #

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the list of method_id_item

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
def __init__(self, size:int, buff: BinaryIO, cm:ClassManager) -> None:
    """
    :param buff: a string which represents a Buff object of the list of `method_id_item`
    :param cm: a `ClassManager` object
    """
    self.CM = cm

    self.offset = buff.tell()

    self.method_id_items = [MethodIdItem(buff, cm) for i in range(0, size)]

MethodIdItem #

This class can parse a method_id_item of a dex file

Source code in androguard/core/dex/__init__.py
class MethodIdItem:
    """
    This class can parse a `method_id_item` of a dex file
    """

    def __init__(self, buff: BinaryIO, cm:ClassManager) -> None:
        """
        :param buff: a string which represents a Buff object of the `method_id_item`
        :param cm: a `ClassManager` object
        """
        self.CM = cm
        self.offset = buff.tell()

        self.class_idx, self.proto_idx, self.name_idx = cm.packer[
            "2HI"
        ].unpack(buff.read(8))

        self.reload()

    def reload(self) -> None:
        self.class_idx_value = self.CM.get_type(self.class_idx)
        self.proto_idx_value = self.CM.get_proto(self.proto_idx)
        self.name_idx_value = self.CM.get_string(self.name_idx)

    def get_class_idx(self) -> int:
        """
        Return the index into the type_ids list for the definer of this method

        :returns: the index
        """
        return self.class_idx

    def get_proto_idx(self) -> int:
        """
        Return the index into the `proto_ids` list for the prototype of this method

        :returns: the index
        """
        return self.proto_idx

    def get_name_idx(self) -> int:
        """
        Return the index into the `string_ids` list for the name of this method

        :returns: the index
        """
        return self.name_idx

    def get_class_name(self) -> str:
        """
        Return the class name of the method

        :returns: the class name
        """
        if self.class_idx_value is None:
            self.class_idx_value = self.CM.get_type(self.class_idx)

        return self.class_idx_value

    def get_proto(self) -> str:
        """
        Return the prototype of the method

        :returns: the prototype
        """
        if self.proto_idx_value is None:
            self.proto_idx_value = self.CM.get_proto(self.proto_idx)

        return self.proto_idx_value

    def get_descriptor(self) -> str:
        """
        Return the descriptor

        :returns: the descriptor
        """
        proto = self.get_proto()
        return proto[0] + proto[1]

    def get_real_descriptor(self) -> str:
        """
        Return the real descriptor (i.e. without extra spaces)

        :returns: the real descriptor, without extra spaces
        """
        proto = self.get_proto()
        return proto[0].replace(' ', '') + proto[1]

    def get_name(self) -> str:
        """
        Return the name of the method

        :returns: the name of the of method
        """
        if self.name_idx_value is None:
            self.name_idx_value = self.CM.get_string(self.name_idx)
        return self.name_idx_value

    def get_list(self) -> list[str]:
        return [self.get_class_name(), self.get_name(), self.get_proto()]

    def get_triple(self) -> tuple[str, str, str]:
        return (
            self.get_class_name()[1:-1],
            self.get_name(),
            self.get_real_descriptor(),
        )

    def show(self) -> None:
        bytecode._PrintSubBanner("Method Id Item")
        bytecode._PrintDefault(
            "class_idx=%d proto_idx=%d name_idx=%d\n"
            % (self.class_idx, self.proto_idx, self.name_idx)
        )
        bytecode._PrintDefault(
            "class_idx_value=%s proto_idx_value=%s name_idx_value=%s\n"
            % (self.class_idx_value, self.proto_idx_value, self.name_idx_value)
        )

    def get_obj(self) -> bytes:
        return self.CM.packer["2HI"].pack(
            self.class_idx, self.proto_idx, self.name_idx
        )

    def get_raw(self) -> bytes:
        return self.get_obj()

    def get_length(self) -> int:
        return len(self.get_obj())

__init__(buff, cm) #

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the method_id_item

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
def __init__(self, buff: BinaryIO, cm:ClassManager) -> None:
    """
    :param buff: a string which represents a Buff object of the `method_id_item`
    :param cm: a `ClassManager` object
    """
    self.CM = cm
    self.offset = buff.tell()

    self.class_idx, self.proto_idx, self.name_idx = cm.packer[
        "2HI"
    ].unpack(buff.read(8))

    self.reload()

get_class_idx() #

Return the index into the type_ids list for the definer of this method

Returns:

Type Description
int

the index

Source code in androguard/core/dex/__init__.py
def get_class_idx(self) -> int:
    """
    Return the index into the type_ids list for the definer of this method

    :returns: the index
    """
    return self.class_idx

get_class_name() #

Return the class name of the method

Returns:

Type Description
str

the class name

Source code in androguard/core/dex/__init__.py
def get_class_name(self) -> str:
    """
    Return the class name of the method

    :returns: the class name
    """
    if self.class_idx_value is None:
        self.class_idx_value = self.CM.get_type(self.class_idx)

    return self.class_idx_value

get_descriptor() #

Return the descriptor

Returns:

Type Description
str

the descriptor

Source code in androguard/core/dex/__init__.py
def get_descriptor(self) -> str:
    """
    Return the descriptor

    :returns: the descriptor
    """
    proto = self.get_proto()
    return proto[0] + proto[1]

get_name() #

Return the name of the method

Returns:

Type Description
str

the name of the of method

Source code in androguard/core/dex/__init__.py
def get_name(self) -> str:
    """
    Return the name of the method

    :returns: the name of the of method
    """
    if self.name_idx_value is None:
        self.name_idx_value = self.CM.get_string(self.name_idx)
    return self.name_idx_value

get_name_idx() #

Return the index into the string_ids list for the name of this method

Returns:

Type Description
int

the index

Source code in androguard/core/dex/__init__.py
def get_name_idx(self) -> int:
    """
    Return the index into the `string_ids` list for the name of this method

    :returns: the index
    """
    return self.name_idx

get_proto() #

Return the prototype of the method

Returns:

Type Description
str

the prototype

Source code in androguard/core/dex/__init__.py
def get_proto(self) -> str:
    """
    Return the prototype of the method

    :returns: the prototype
    """
    if self.proto_idx_value is None:
        self.proto_idx_value = self.CM.get_proto(self.proto_idx)

    return self.proto_idx_value

get_proto_idx() #

Return the index into the proto_ids list for the prototype of this method

Returns:

Type Description
int

the index

Source code in androguard/core/dex/__init__.py
def get_proto_idx(self) -> int:
    """
    Return the index into the `proto_ids` list for the prototype of this method

    :returns: the index
    """
    return self.proto_idx

get_real_descriptor() #

Return the real descriptor (i.e. without extra spaces)

Returns:

Type Description
str

the real descriptor, without extra spaces

Source code in androguard/core/dex/__init__.py
def get_real_descriptor(self) -> str:
    """
    Return the real descriptor (i.e. without extra spaces)

    :returns: the real descriptor, without extra spaces
    """
    proto = self.get_proto()
    return proto[0].replace(' ', '') + proto[1]

ODEX #

Bases: DEX

This class can parse an odex file

Parameters:

Name Type Description Default
buff

byteswhich represents the odex file

required
decompiler Union[DecompilerDAD, None]

associate a decompiler object to display the java source code Example: >>> ODEX( read("classes.odex") )

None
Source code in androguard/core/dex/__init__.py
class ODEX(DEX):
    """
    This class can parse an odex file

    :param buff: byteswhich represents the odex file
    :param decompiler: associate a decompiler object to display the java source code

    Example:

        >>> ODEX( read("classes.odex") )
    """

    def _preload(self, buff: BinaryIO):
        self.orig_buff = buff
        self.magic = buff[:8]
        if self.magic in (
            ODEX_FILE_MAGIC_35,
            ODEX_FILE_MAGIC_36,
            ODEX_FILE_MAGIC_37,
        ):
            self.odex_header = OdexHeaderItem(self)

            self.seek(self.odex_header.deps_offset)
            self.dependencies = OdexDependencies(self)

            self.padding = buff[
                self.odex_header.deps_offset + self.odex_header.deps_length :
            ]

            self.seek(self.odex_header.dex_offset)
            self.set_buff(self.read(self.odex_header.dex_length))
            self.seek(0)

    def save(self) -> bytes:
        """
        Do not use !
        """
        dex_raw = super().save()
        return (
            self.magic
            + self.odex_header.get_raw()
            + dex_raw
            + self.dependencies.get_raw()
            + self.padding
        )

    def get_buff(self) -> bytes:
        return (
            self.magic
            + self.odex_header.get_raw()
            + super().get_buff()
            + self.dependencies.get_raw()
            + self.padding
        )

    def get_dependencies(self) -> OdexDependencies:
        """
        Return the odex dependencies object

        :returns: an `OdexDependencies` object
        """
        return self.dependencies

    def get_format_type(self) -> str:
        """
        Return the type

        :returns: a string
        """
        return "ODEX"

get_dependencies() #

Return the odex dependencies object

Returns:

Type Description
OdexDependencies

an OdexDependencies object

Source code in androguard/core/dex/__init__.py
def get_dependencies(self) -> OdexDependencies:
    """
    Return the odex dependencies object

    :returns: an `OdexDependencies` object
    """
    return self.dependencies

get_format_type() #

Return the type

Returns:

Type Description
str

a string

Source code in androguard/core/dex/__init__.py
def get_format_type(self) -> str:
    """
    Return the type

    :returns: a string
    """
    return "ODEX"

save() #

Do not use !

Source code in androguard/core/dex/__init__.py
def save(self) -> bytes:
    """
    Do not use !
    """
    dex_raw = super().save()
    return (
        self.magic
        + self.odex_header.get_raw()
        + dex_raw
        + self.dependencies.get_raw()
        + self.padding
    )

OdexDependencies #

This class can parse the odex dependencies

Parameters:

Name Type Description Default
buff BinaryIO

a Buff object string which represents the odex dependencies

required
Source code in androguard/core/dex/__init__.py
class OdexDependencies:
    """
    This class can parse the odex dependencies

    :param buff: a Buff object string which represents the odex dependencies
    """

    def __init__(self, buff: BinaryIO) -> None:
        self.modification_time = unpack("=I", buff.read(4))[0]
        self.crc = unpack("=I", buff.read(4))[0]
        self.dalvik_build = unpack("=I", buff.read(4))[0]
        self.dependency_count = unpack("=I", buff.read(4))[0]
        self.dependencies = []
        self.dependency_checksums = []

        for i in range(0, self.dependency_count):
            string_length = unpack("=I", buff.read(4))[0]
            name_dependency = buff.read(string_length)
            self.dependencies.append(name_dependency)
            self.dependency_checksums.append(buff.read(20))

    def get_dependencies(self) -> list[str]:
        """
        Return the list of dependencies

        :returns: a list of strings
        """
        return self.dependencies

    def get_raw(self) -> bytes:
        dependencies = b""

        for idx, value in enumerate(self.dependencies):
            dependencies += (
                pack("=I", len(value))
                + pack("=%ds" % len(value), value)
                + pack("=20s", self.dependency_checksums[idx])
            )

        return (
            pack("=I", self.modification_time)
            + pack("=I", self.crc)
            + pack("=I", self.dalvik_build)
            + pack("=I", self.dependency_count)
            + dependencies
        )

get_dependencies() #

Return the list of dependencies

Returns:

Type Description
list[str]

a list of strings

Source code in androguard/core/dex/__init__.py
def get_dependencies(self) -> list[str]:
    """
    Return the list of dependencies

    :returns: a list of strings
    """
    return self.dependencies

OdexHeaderItem #

This class can parse the odex header

Parameters:

Name Type Description Default
buff BinaryIO

a Buff object string which represents the odex dependencies

required
Source code in androguard/core/dex/__init__.py
class OdexHeaderItem:
    """
    This class can parse the odex header

    :param buff: a Buff object string which represents the odex dependencies
    """

    def __init__(self, buff: BinaryIO) -> None:
        buff.seek(8)

        self.dex_offset = unpack("=I", buff.read(4))[0]
        self.dex_length = unpack("=I", buff.read(4))[0]
        self.deps_offset = unpack("=I", buff.read(4))[0]
        self.deps_length = unpack("=I", buff.read(4))[0]
        self.aux_offset = unpack("=I", buff.read(4))[0]
        self.aux_length = unpack("=I", buff.read(4))[0]
        self.flags = unpack("=I", buff.read(4))[0]
        self.padding = unpack("=I", buff.read(4))[0]

    def show(self) -> None:
        print(
            "dex_offset:{:x} dex_length:{:x} deps_offset:{:x} deps_length:{:x} aux_offset:{:x} aux_length:{:x} flags:{:x}".format(
                self.dex_offset,
                self.dex_length,
                self.deps_offset,
                self.deps_length,
                self.aux_offset,
                self.aux_length,
                self.flags,
            )
        )

    def get_raw(self) -> bytes:
        return (
            pack("=I", self.dex_offset)
            + pack("=I", self.dex_length)
            + pack("=I", self.deps_offset)
            + pack("=I", self.deps_length)
            + pack("=I", self.aux_offset)
            + pack("=I", self.aux_length)
            + pack("=I", self.flags)
            + pack("=I", self.padding)
        )

PackedSwitch #

This class can parse a PackedSwitch instruction

Parameters:

Name Type Description Default
buff bytes

a Buff object which represents a buffer where the instruction is stored

required
Source code in androguard/core/dex/__init__.py
class PackedSwitch:
    """
    This class can parse a `PackedSwitch` instruction

    :param buff: a Buff object which represents a buffer where the instruction is stored
    """

    # FIXME: why is this not a subclass of Instruction?
    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        self.OP = 0x0
        self.notes = []
        self.CM = cm

        self.format_general_size = calcsize("2HI")

        self.ident, self.size, self.first_key = cm.packer["2Hi"].unpack(
            buff[0:8]
        )

        self.targets = []

        idx = self.format_general_size

        max_size = self.size
        if (max_size * 4) > len(buff):
            max_size = len(buff) - idx - 8

        for i in range(0, max_size):
            self.targets.append(cm.packer["l"].unpack(buff[idx : idx + 4])[0])
            idx += 4

    def add_note(self, msg: str) -> None:
        """
        Add a note to this instruction

        :param msg: the message
        """
        self.notes.append(msg)

    def get_notes(self) -> list[str]:
        """
        Get all notes from this instruction

        :returns: a list of note strings
        """
        return self.notes

    def get_op_value(self) -> int:
        """
        Get the value of the opcode

        :returns: opcode value
        """
        return self.ident

    def get_keys(self) -> list[int]:
        """
        Return the keys of the instruction

        :returns: a list of long (integer)
        """
        return [(self.first_key + i) for i in range(0, len(self.targets))]

    def get_values(self) -> list[int]:
        return self.get_keys()

    def get_targets(self) -> list[int]:
        """
        Return the targets (address) of the instruction

        :returns: a list of long (integer)
        """
        return self.targets

    def get_output(self, idx: int = -1) -> str:
        """
        Return an additional output of the instruction

        :returns: additional output string
        """
        return " ".join(
            "%x" % (self.first_key + i) for i in range(0, len(self.targets))
        )

    def get_operands(self, idx: int = -1) -> list:
        """
        Return an additional output of the instruction

        :returns: list
        """
        return []

    def get_formatted_operands(self) -> None:
        return None

    def get_name(self) -> str:
        """
        Return the name of the instruction

        :returns: name string
        """
        return "packed-switch-payload"

    def show_buff(self, pos: int) -> str:
        """
        Return the display of the instruction

        :returns: display string
        """
        buff = self.get_name() + " "
        buff += "%x:" % self.first_key

        for i in self.targets:
            buff += " %x" % i

        return buff

    def show(self, pos: int) -> None:
        """
        Print the instruction
        """
        print(self.show_buff(pos), end=' ')

    def get_length(self) -> int:
        return self.format_general_size + (self.size * calcsize('<L'))

    def get_raw(self) -> bytes:
        return self.CM.packer["2Hi"].pack(
            self.ident, self.size, self.first_key
        ) + b''.join(self.CM.packer["l"].pack(i) for i in self.targets)

    def get_hex(self) -> bytes:
        """
        Returns a HEX String, separated by spaces every byte
        """
        s = binascii.hexlify(self.get_raw()).decode('ascii')
        return " ".join(s[i : i + 2] for i in range(0, len(s), 2))

    def disasm(self) -> str:
        # FIXME:
        return self.show_buff(None)

add_note(msg) #

Add a note to this instruction

Parameters:

Name Type Description Default
msg str

the message

required
Source code in androguard/core/dex/__init__.py
def add_note(self, msg: str) -> None:
    """
    Add a note to this instruction

    :param msg: the message
    """
    self.notes.append(msg)

get_hex() #

Returns a HEX String, separated by spaces every byte

Source code in androguard/core/dex/__init__.py
def get_hex(self) -> bytes:
    """
    Returns a HEX String, separated by spaces every byte
    """
    s = binascii.hexlify(self.get_raw()).decode('ascii')
    return " ".join(s[i : i + 2] for i in range(0, len(s), 2))

get_keys() #

Return the keys of the instruction

Returns:

Type Description
list[int]

a list of long (integer)

Source code in androguard/core/dex/__init__.py
def get_keys(self) -> list[int]:
    """
    Return the keys of the instruction

    :returns: a list of long (integer)
    """
    return [(self.first_key + i) for i in range(0, len(self.targets))]

get_name() #

Return the name of the instruction

Returns:

Type Description
str

name string

Source code in androguard/core/dex/__init__.py
def get_name(self) -> str:
    """
    Return the name of the instruction

    :returns: name string
    """
    return "packed-switch-payload"

get_notes() #

Get all notes from this instruction

Returns:

Type Description
list[str]

a list of note strings

Source code in androguard/core/dex/__init__.py
def get_notes(self) -> list[str]:
    """
    Get all notes from this instruction

    :returns: a list of note strings
    """
    return self.notes

get_op_value() #

Get the value of the opcode

Returns:

Type Description
int

opcode value

Source code in androguard/core/dex/__init__.py
def get_op_value(self) -> int:
    """
    Get the value of the opcode

    :returns: opcode value
    """
    return self.ident

get_operands(idx=-1) #

Return an additional output of the instruction

Returns:

Type Description
list

list

Source code in androguard/core/dex/__init__.py
def get_operands(self, idx: int = -1) -> list:
    """
    Return an additional output of the instruction

    :returns: list
    """
    return []

get_output(idx=-1) #

Return an additional output of the instruction

Returns:

Type Description
str

additional output string

Source code in androguard/core/dex/__init__.py
def get_output(self, idx: int = -1) -> str:
    """
    Return an additional output of the instruction

    :returns: additional output string
    """
    return " ".join(
        "%x" % (self.first_key + i) for i in range(0, len(self.targets))
    )

get_targets() #

Return the targets (address) of the instruction

Returns:

Type Description
list[int]

a list of long (integer)

Source code in androguard/core/dex/__init__.py
def get_targets(self) -> list[int]:
    """
    Return the targets (address) of the instruction

    :returns: a list of long (integer)
    """
    return self.targets

show(pos) #

Print the instruction

Source code in androguard/core/dex/__init__.py
def show(self, pos: int) -> None:
    """
    Print the instruction
    """
    print(self.show_buff(pos), end=' ')

show_buff(pos) #

Return the display of the instruction

Returns:

Type Description
str

display string

Source code in androguard/core/dex/__init__.py
def show_buff(self, pos: int) -> str:
    """
    Return the display of the instruction

    :returns: display string
    """
    buff = self.get_name() + " "
    buff += "%x:" % self.first_key

    for i in self.targets:
        buff += " %x" % i

    return buff

ParameterAnnotation #

This class can parse a parameter_annotation of a dex file

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a buff object of the parameter_annotation

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
class ParameterAnnotation:
    """
    This class can parse a `parameter_annotation` of a dex file

    :param buff: a string which represents a buff object of the `parameter_annotation`
    :param cm: a `ClassManager` object
    """

    def __init__(self, buff: BinaryIO, cm: ClassManager) -> None:
        self.offset = buff.tell()

        self.CM = cm
        self.method_idx, self.annotations_off = cm.packer["2I"].unpack(
            buff.read(8)
        )

    def get_method_idx(self) -> int:
        """
        Return the index into the `method_ids` list for the identity of the method whose parameters are being annotated

        :returns: the index
        """
        return self.method_idx

    def get_annotations_off(self) -> int:
        """
        Return the offset from the start of the file to the list of annotations for the method parameters

        :returns: the offset
        """
        return self.annotations_off

    def set_off(self, off: int) -> None:
        self.offset = off

    def get_off(self) -> int:
        return self.offset

    def show(self) -> None:
        bytecode._PrintSubBanner("Parameter Annotation")
        bytecode._PrintDefault(
            "method_idx=0x%x annotations_off=0x%x\n"
            % (self.method_idx, self.annotations_off)
        )

    def get_obj(self) -> bytes:
        if self.annotations_off != 0:
            self.annotations_off = self.CM.get_obj_by_offset(
                self.annotations_off
            ).get_off()

        return self.CM.packer["2I"].pack(self.method_idx, self.annotations_off)

    def get_raw(self) -> bytes:
        return self.get_obj()

    def get_length(self) -> int:
        return len(self.get_raw())

get_annotations_off() #

Return the offset from the start of the file to the list of annotations for the method parameters

Returns:

Type Description
int

the offset

Source code in androguard/core/dex/__init__.py
def get_annotations_off(self) -> int:
    """
    Return the offset from the start of the file to the list of annotations for the method parameters

    :returns: the offset
    """
    return self.annotations_off

get_method_idx() #

Return the index into the method_ids list for the identity of the method whose parameters are being annotated

Returns:

Type Description
int

the index

Source code in androguard/core/dex/__init__.py
def get_method_idx(self) -> int:
    """
    Return the index into the `method_ids` list for the identity of the method whose parameters are being annotated

    :returns: the index
    """
    return self.method_idx

ProtoHIdItem #

This class can parse a list of proto_id_item of a dex file

Source code in androguard/core/dex/__init__.py
class ProtoHIdItem:
    """
    This class can parse a list of `proto_id_item` of a dex file
    """

    def __init__(self, size:int, buff: BinaryIO, cm:ClassManager) -> None:
        """
        :param buff: a string which represents a Buff object of the list of `proto_id_item`
        :param cm: a `ClassManager` object
        """
        self.CM = cm

        self.offset = buff.tell()

        self.proto = [ProtoIdItem(buff, cm) for i in range(0, size)]

    def set_off(self, off: int) -> None:
        self.offset = off

    def get_off(self) -> int:
        return self.offset

    def get(self, idx: int) -> ProtoIdItem:
        try:
            return self.proto[idx]
        except IndexError:
            return ProtoIdItemInvalid()

    def show(self) -> None:
        bytecode._PrintSubBanner("Proto List Item")
        for i in self.proto:
            i.show()

    def get_obj(self) -> list[ProtoIdItem]:
        return [i for i in self.proto]

    def get_raw(self) -> bytes:
        return b''.join(i.get_raw() for i in self.proto)

    def get_length(self) -> int:
        length = 0
        for i in self.proto:
            length += i.get_length()
        return length

__init__(size, buff, cm) #

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the list of proto_id_item

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
def __init__(self, size:int, buff: BinaryIO, cm:ClassManager) -> None:
    """
    :param buff: a string which represents a Buff object of the list of `proto_id_item`
    :param cm: a `ClassManager` object
    """
    self.CM = cm

    self.offset = buff.tell()

    self.proto = [ProtoIdItem(buff, cm) for i in range(0, size)]

ProtoIdItem #

This class can parse a proto_id_item of a dex file

Source code in androguard/core/dex/__init__.py
class ProtoIdItem:
    """
    This class can parse a `proto_id_item` of a dex file
    """

    def __init__(self, buff: BinaryIO, cm: ClassManager):
        """
        :param buff: a string which represents a Buff object of the `proto_id_item`
        :param cm: a `ClassManager` object
        """
        self.CM = cm
        self.offset = buff.tell()

        self.shorty_idx, self.return_type_idx, self.parameters_off = cm.packer[
            "3I"
        ].unpack(buff.read(12))

        self.shorty_idx_value = self.CM.get_string(self.shorty_idx)
        self.return_type_idx_value = self.CM.get_type(self.return_type_idx)
        self.parameters_off_value = None

    def get_shorty_idx(self) -> int:
        """
        Return the index into the `string_ids` list for the short-form descriptor string of this prototype

        :returns: the index
        """
        return self.shorty_idx

    def get_return_type_idx(self) -> int:
        """
        Return the index into the `type_ids` list for the return type of this prototype

        :returns: the index
        """
        return self.return_type_idx

    def get_parameters_off(self) -> int:
        """
        Return the offset from the start of the file to the list of parameter types for this prototype, or 0 if this prototype has no parameters

        :returns: the offset
        """
        return self.parameters_off

    def get_shorty_idx_value(self) -> str:
        """
        Return the string associated to the `shorty_idx`

        :returns: string
        """
        if self.shorty_idx_value is None:
            self.shorty_idx_value = self.CM.get_string(self.shorty_idx)
        return self.shorty_idx_value

    def get_return_type_idx_value(self) -> str:
        """
        Return the string associated to the `return_type_idx`

        :returns: string
        """
        if self.return_type_idx_value is None:
            self.return_type_idx_value = self.CM.get_type(self.return_type_idx)
        return self.return_type_idx_value

    def get_parameters_off_value(self) -> str:
        """
        Return the string associated to the `parameters_off`

        :returns: string
        """
        if self.parameters_off_value is None:
            params = self.CM.get_type_list(self.parameters_off)
            self.parameters_off_value = '(' + ' '.join(params) + ')'
        return self.parameters_off_value

    def show(self) -> None:
        bytecode._PrintSubBanner("Proto Item")
        bytecode._PrintDefault(
            "shorty_idx=%d return_type_idx=%d parameters_off=%d\n"
            % (self.shorty_idx, self.return_type_idx, self.parameters_off)
        )
        bytecode._PrintDefault(
            "shorty_idx_value=%s return_type_idx_value=%s parameters_off_value=%s\n"
            % (
                self.shorty_idx_value,
                self.return_type_idx_value,
                self.parameters_off_value,
            )
        )

    def get_obj(self) -> bytes:
        if self.parameters_off != 0:
            self.parameters_off = self.CM.get_obj_by_offset(
                self.parameters_off
            ).get_off()

        return self.CM.packer["3I"].pack(
            self.shorty_idx, self.return_type_idx, self.parameters_off
        )

    def get_raw(self) -> bytes:
        return self.get_obj()

    def get_length(self) -> int:
        return len(self.get_obj())

__init__(buff, cm) #

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the proto_id_item

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
def __init__(self, buff: BinaryIO, cm: ClassManager):
    """
    :param buff: a string which represents a Buff object of the `proto_id_item`
    :param cm: a `ClassManager` object
    """
    self.CM = cm
    self.offset = buff.tell()

    self.shorty_idx, self.return_type_idx, self.parameters_off = cm.packer[
        "3I"
    ].unpack(buff.read(12))

    self.shorty_idx_value = self.CM.get_string(self.shorty_idx)
    self.return_type_idx_value = self.CM.get_type(self.return_type_idx)
    self.parameters_off_value = None

get_parameters_off() #

Return the offset from the start of the file to the list of parameter types for this prototype, or 0 if this prototype has no parameters

Returns:

Type Description
int

the offset

Source code in androguard/core/dex/__init__.py
def get_parameters_off(self) -> int:
    """
    Return the offset from the start of the file to the list of parameter types for this prototype, or 0 if this prototype has no parameters

    :returns: the offset
    """
    return self.parameters_off

get_parameters_off_value() #

Return the string associated to the parameters_off

Returns:

Type Description
str

string

Source code in androguard/core/dex/__init__.py
def get_parameters_off_value(self) -> str:
    """
    Return the string associated to the `parameters_off`

    :returns: string
    """
    if self.parameters_off_value is None:
        params = self.CM.get_type_list(self.parameters_off)
        self.parameters_off_value = '(' + ' '.join(params) + ')'
    return self.parameters_off_value

get_return_type_idx() #

Return the index into the type_ids list for the return type of this prototype

Returns:

Type Description
int

the index

Source code in androguard/core/dex/__init__.py
def get_return_type_idx(self) -> int:
    """
    Return the index into the `type_ids` list for the return type of this prototype

    :returns: the index
    """
    return self.return_type_idx

get_return_type_idx_value() #

Return the string associated to the return_type_idx

Returns:

Type Description
str

string

Source code in androguard/core/dex/__init__.py
def get_return_type_idx_value(self) -> str:
    """
    Return the string associated to the `return_type_idx`

    :returns: string
    """
    if self.return_type_idx_value is None:
        self.return_type_idx_value = self.CM.get_type(self.return_type_idx)
    return self.return_type_idx_value

get_shorty_idx() #

Return the index into the string_ids list for the short-form descriptor string of this prototype

Returns:

Type Description
int

the index

Source code in androguard/core/dex/__init__.py
def get_shorty_idx(self) -> int:
    """
    Return the index into the `string_ids` list for the short-form descriptor string of this prototype

    :returns: the index
    """
    return self.shorty_idx

get_shorty_idx_value() #

Return the string associated to the shorty_idx

Returns:

Type Description
str

string

Source code in androguard/core/dex/__init__.py
def get_shorty_idx_value(self) -> str:
    """
    Return the string associated to the `shorty_idx`

    :returns: string
    """
    if self.shorty_idx_value is None:
        self.shorty_idx_value = self.CM.get_string(self.shorty_idx)
    return self.shorty_idx_value

SparseSwitch #

This class can parse a SparseSwitch instruction

Parameters:

Name Type Description Default
buff bytes

a Buff object which represents a buffer where the instruction is stored

required
Source code in androguard/core/dex/__init__.py
class SparseSwitch:
    """
    This class can parse a SparseSwitch instruction

    :param buff: a Buff object which represents a buffer where the instruction is stored
    """

    # FIXME: why is this not a subclass of Instruction?
    def __init__(self, cm: ClassManager, buff: bytes) -> None:
        self.OP = 0x0
        self.notes = []
        self.CM = cm

        self.format_general_size = calcsize("2H")
        self.ident, self.size = cm.packer["2H"].unpack(buff[0:4])

        self.keys = []
        self.targets = []

        idx = self.format_general_size
        for i in range(0, self.size):
            self.keys.append(cm.packer["l"].unpack(buff[idx : idx + 4])[0])
            idx += 4

        for i in range(0, self.size):
            self.targets.append(cm.packer["l"].unpack(buff[idx : idx + 4])[0])
            idx += 4

    def add_note(self, msg: str) -> None:
        """
        Add a note to this instruction

        :param msg: the message
        """
        self.notes.append(msg)

    def get_notes(self) -> list[str]:
        """
        Get all notes from this instruction

        :returns: a list of note strings
        """
        return self.notes

    def get_op_value(self) -> int:
        """
        Get the value of the opcode

        :returns: the value
        """
        return self.ident

    def get_keys(self) -> list[int]:
        """
        Return the keys of the instruction

        :returns: a list of long (integer)
        """
        return self.keys

    def get_values(self) -> list[int]:
        return self.get_keys()

    def get_targets(self) -> list[int]:
        """
        Return the targets (address) of the instruction

        :returns: a list of long (integer)
        """
        return self.targets

    def get_output(self, idx: int = -1) -> str:
        """
        Return an additional output of the instruction

        :returns: additional output string
        """
        return " ".join("%x" % i for i in self.keys)

    def get_operands(self, idx: int = -1) -> str:
        """
        Return an additional output of the instruction

        :returns: additional output string
        """
        return []

    def get_formatted_operands(self) -> None:
        return None

    def get_name(self) -> str:
        """
        Return the name of the instruction

        :returns: name string
        """
        return "sparse-switch-payload"

    def show_buff(self, pos: int) -> str:
        """
        Return the display of the instruction

        :returns: display string
        """
        buff = self.get_name() + " "
        for i in range(0, len(self.keys)):
            buff += "{:x}:{:x} ".format(self.keys[i], self.targets[i])

        return buff

    def show(self, pos) -> None:
        """
        Print the instruction
        """
        print(self.show_buff(pos), end=' ')

    def get_length(self) -> int:
        return self.format_general_size + (self.size * calcsize('<L')) * 2

    def get_raw(self) -> bytes:
        return (
            self.CM.packer["2H"].pack(self.ident, self.size)
            + b''.join(self.CM.packer["l"].pack(i) for i in self.keys)
            + b''.join(self.CM.packer["l"].pack(i) for i in self.targets)
        )

    def get_hex(self) -> str:
        """
        Returns a HEX String, separated by spaces every byte

        :returns: hex string
        """
        s = binascii.hexlify(self.get_raw()).decode('ascii')
        return " ".join(s[i : i + 2] for i in range(0, len(s), 2))

    def disasm(self) -> str:
        # FIXME:
        return self.show_buff(None)

add_note(msg) #

Add a note to this instruction

Parameters:

Name Type Description Default
msg str

the message

required
Source code in androguard/core/dex/__init__.py
def add_note(self, msg: str) -> None:
    """
    Add a note to this instruction

    :param msg: the message
    """
    self.notes.append(msg)

get_hex() #

Returns a HEX String, separated by spaces every byte

Returns:

Type Description
str

hex string

Source code in androguard/core/dex/__init__.py
def get_hex(self) -> str:
    """
    Returns a HEX String, separated by spaces every byte

    :returns: hex string
    """
    s = binascii.hexlify(self.get_raw()).decode('ascii')
    return " ".join(s[i : i + 2] for i in range(0, len(s), 2))

get_keys() #

Return the keys of the instruction

Returns:

Type Description
list[int]

a list of long (integer)

Source code in androguard/core/dex/__init__.py
def get_keys(self) -> list[int]:
    """
    Return the keys of the instruction

    :returns: a list of long (integer)
    """
    return self.keys

get_name() #

Return the name of the instruction

Returns:

Type Description
str

name string

Source code in androguard/core/dex/__init__.py
def get_name(self) -> str:
    """
    Return the name of the instruction

    :returns: name string
    """
    return "sparse-switch-payload"

get_notes() #

Get all notes from this instruction

Returns:

Type Description
list[str]

a list of note strings

Source code in androguard/core/dex/__init__.py
def get_notes(self) -> list[str]:
    """
    Get all notes from this instruction

    :returns: a list of note strings
    """
    return self.notes

get_op_value() #

Get the value of the opcode

Returns:

Type Description
int

the value

Source code in androguard/core/dex/__init__.py
def get_op_value(self) -> int:
    """
    Get the value of the opcode

    :returns: the value
    """
    return self.ident

get_operands(idx=-1) #

Return an additional output of the instruction

Returns:

Type Description
str

additional output string

Source code in androguard/core/dex/__init__.py
def get_operands(self, idx: int = -1) -> str:
    """
    Return an additional output of the instruction

    :returns: additional output string
    """
    return []

get_output(idx=-1) #

Return an additional output of the instruction

Returns:

Type Description
str

additional output string

Source code in androguard/core/dex/__init__.py
def get_output(self, idx: int = -1) -> str:
    """
    Return an additional output of the instruction

    :returns: additional output string
    """
    return " ".join("%x" % i for i in self.keys)

get_targets() #

Return the targets (address) of the instruction

Returns:

Type Description
list[int]

a list of long (integer)

Source code in androguard/core/dex/__init__.py
def get_targets(self) -> list[int]:
    """
    Return the targets (address) of the instruction

    :returns: a list of long (integer)
    """
    return self.targets

show(pos) #

Print the instruction

Source code in androguard/core/dex/__init__.py
def show(self, pos) -> None:
    """
    Print the instruction
    """
    print(self.show_buff(pos), end=' ')

show_buff(pos) #

Return the display of the instruction

Returns:

Type Description
str

display string

Source code in androguard/core/dex/__init__.py
def show_buff(self, pos: int) -> str:
    """
    Return the display of the instruction

    :returns: display string
    """
    buff = self.get_name() + " "
    for i in range(0, len(self.keys)):
        buff += "{:x}:{:x} ".format(self.keys[i], self.targets[i])

    return buff

StringDataItem #

This class can parse a string_data_item of a dex file

Strings in Dalvik files might not be representable in python! This is due to the fact, that you can store any UTF-16 character inside a Dalvik file, but this string might not be decodeable in python as it can contain invalid surrogate-pairs.

To circumvent this issue, this class has different methods how to access the string. There are also some fallbacks implemented to make a "invalid" string printable in python. Dalvik uses MUTF-8 as encoding for the strings. This encoding has the advantage to allow for null terminated strings in UTF-8 encoding, as the null character maps to something else. Therefore you can use get_data to retrieve the actual data of the string and can handle encoding yourself. If you want a representation of the string, which should be printable in python you ca use get which escapes invalid characters.

Source code in androguard/core/dex/__init__.py
class StringDataItem:
    """
    This class can parse a `string_data_item` of a dex file

    Strings in Dalvik files might not be representable in python!
    This is due to the fact, that you can store any UTF-16 character inside
    a Dalvik file, but this string might not be decodeable in python as it can
    contain invalid surrogate-pairs.

    To circumvent this issue, this class has different methods how to access the
    string. There are also some fallbacks implemented to make a "invalid" string
    printable in python.
    Dalvik uses MUTF-8 as encoding for the strings. This encoding has the
    advantage to allow for null terminated strings in UTF-8 encoding, as the
    null character maps to something else.
    Therefore you can use [get_data][androguard.core.dex.StringDataItem.get_data] to retrieve the actual data of the
    string and can handle encoding yourself.
    If you want a representation of the string, which should be printable in
    python you ca use [get][androguard.core.dex.StringDataItem.get] which escapes invalid characters.
    """

    def __init__(self, buff: BinaryIO, cm: ClassManager) -> None:
        """
        :param buff: a string which represents a Buff object of the `string_data_item`
        :param cm: a `ClassManager` object
        """
        self.CM = cm

        self.offset = buff.tell()

        # Content of string_data_item
        self.utf16_size = readuleb128(cm, buff)
        self.data = read_null_terminated_string(buff)

    def get_utf16_size(self) -> int:
        """
        Return the size of this string, in UTF-16 code units

        :returns: the size of the string
        """
        return self.utf16_size

    def get_data(self) -> str:
        """
        Return a series of MUTF-8 code units (a.k.a. octets, a.k.a. bytes) followed by a byte of value 0

        :returns: string
        """
        return self.data + b"\x00"

    def set_off(self, off: int) -> None:
        self.offset = off

    def get_off(self) -> int:
        return self.offset

    def get(self) -> str:
        """
        Returns a str object

        :returns: string
        """
        try:
            return mutf8.decode(self.data)
        except UnicodeDecodeError:
            logger.error("Impossible to decode {}".format(self.data))
            return "ANDROGUARD[INVALID_STRING] {}".format(self.data)

    def show(self) -> None:
        bytecode._PrintSubBanner("String Data Item")
        bytecode._PrintDefault(
            "utf16_size=%d data=%s\n" % (self.utf16_size, repr(self.get()))
        )

    def get_obj(self) -> list:
        return []

    def get_raw(self) -> bytes:
        """
        Returns the raw string including the ULEB128 coded length
        and null byte string terminator

        :returns: bytes
        """
        return writeuleb128(self.CM, self.utf16_size) + self.data + b"\x00"

    def get_length(self) -> int:
        """
        Get the length of the raw string including the ULEB128 coded
        length and the null byte terminator

        :return: int
        """
        return len(writeuleb128(self.CM, self.utf16_size)) + len(self.data) + 1

__init__(buff, cm) #

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the string_data_item

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
def __init__(self, buff: BinaryIO, cm: ClassManager) -> None:
    """
    :param buff: a string which represents a Buff object of the `string_data_item`
    :param cm: a `ClassManager` object
    """
    self.CM = cm

    self.offset = buff.tell()

    # Content of string_data_item
    self.utf16_size = readuleb128(cm, buff)
    self.data = read_null_terminated_string(buff)

get() #

Returns a str object

Returns:

Type Description
str

string

Source code in androguard/core/dex/__init__.py
def get(self) -> str:
    """
    Returns a str object

    :returns: string
    """
    try:
        return mutf8.decode(self.data)
    except UnicodeDecodeError:
        logger.error("Impossible to decode {}".format(self.data))
        return "ANDROGUARD[INVALID_STRING] {}".format(self.data)

get_data() #

Return a series of MUTF-8 code units (a.k.a. octets, a.k.a. bytes) followed by a byte of value 0

Returns:

Type Description
str

string

Source code in androguard/core/dex/__init__.py
def get_data(self) -> str:
    """
    Return a series of MUTF-8 code units (a.k.a. octets, a.k.a. bytes) followed by a byte of value 0

    :returns: string
    """
    return self.data + b"\x00"

get_length() #

Get the length of the raw string including the ULEB128 coded length and the null byte terminator

Returns:

Type Description
int

int

Source code in androguard/core/dex/__init__.py
def get_length(self) -> int:
    """
    Get the length of the raw string including the ULEB128 coded
    length and the null byte terminator

    :return: int
    """
    return len(writeuleb128(self.CM, self.utf16_size)) + len(self.data) + 1

get_raw() #

Returns the raw string including the ULEB128 coded length and null byte string terminator

Returns:

Type Description
bytes

bytes

Source code in androguard/core/dex/__init__.py
def get_raw(self) -> bytes:
    """
    Returns the raw string including the ULEB128 coded length
    and null byte string terminator

    :returns: bytes
    """
    return writeuleb128(self.CM, self.utf16_size) + self.data + b"\x00"

get_utf16_size() #

Return the size of this string, in UTF-16 code units

Returns:

Type Description
int

the size of the string

Source code in androguard/core/dex/__init__.py
def get_utf16_size(self) -> int:
    """
    Return the size of this string, in UTF-16 code units

    :returns: the size of the string
    """
    return self.utf16_size

StringIdItem #

This class can parse a string_id_item of a dex file

Source code in androguard/core/dex/__init__.py
class StringIdItem:
    """
    This class can parse a `string_id_item` of a dex file
    """

    def __init__(self, buff: BinaryIO, cm: ClassManager):
        """
        :param buff: a string which represents a Buff object of the str`ing_id_item
        :param cm: a `ClassManager` object
        """
        self.CM = cm
        self.offset = buff.tell()

        (self.string_data_off,) = cm.packer["I"].unpack(buff.read(4))

    def get_string_data_off(self) -> int:
        """
        Return the offset from the start of the file to the string data for this item

        :returns: the offset
        """
        return self.string_data_off

    def set_off(self, off: int) -> None:
        self.offset = off

    def get_off(self) -> int:
        return self.offset

    def show(self) -> None:
        bytecode._PrintSubBanner("String Id Item")
        bytecode._PrintDefault("string_data_off=%x\n" % self.string_data_off)

    def get_obj(self) -> bytes:
        if self.string_data_off != 0:
            self.string_data_off = self.CM.get_string_by_offset(
                self.string_data_off
            ).get_off()

        return self.CM.packer["I"].pack(self.string_data_off)

    def get_raw(self) -> bytes:
        return self.get_obj()

    def get_length(self) -> int:
        return len(self.get_obj())

__init__(buff, cm) #

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the str`ing_id_item

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
def __init__(self, buff: BinaryIO, cm: ClassManager):
    """
    :param buff: a string which represents a Buff object of the str`ing_id_item
    :param cm: a `ClassManager` object
    """
    self.CM = cm
    self.offset = buff.tell()

    (self.string_data_off,) = cm.packer["I"].unpack(buff.read(4))

get_string_data_off() #

Return the offset from the start of the file to the string data for this item

Returns:

Type Description
int

the offset

Source code in androguard/core/dex/__init__.py
def get_string_data_off(self) -> int:
    """
    Return the offset from the start of the file to the string data for this item

    :returns: the offset
    """
    return self.string_data_off

TryItem #

This class represents the try_item format

Parameters:

Name Type Description Default
buff BinaryIO

a raw buffer where are the try_item format

required
cm ClassManager

the ClassManager

required
Source code in androguard/core/dex/__init__.py
class TryItem:
    """
    This class represents the `try_item` format

    :param buff: a raw buffer where are the `try_item` format
    :param cm: the `ClassManager`
    """

    def __init__(self, buff: BinaryIO, cm: ClassManager) -> None:
        self.offset = buff.tell()

        self.CM = cm

        self.start_addr, self.insn_count, self.handler_off = cm.packer[
            "I2H"
        ].unpack(buff.read(8))

    def set_off(self, off: int) -> None:
        self.offset = off

    def get_off(self) -> int:
        return self.offset

    def get_start_addr(self) -> int:
        """
        Get the start address of the block of code covered by this entry. The address is a count of 16-bit code units to the start of the first covered instruction.

        :returns: address int
        """
        return self.start_addr

    def get_insn_count(self) -> int:
        """
        Get the number of 16-bit code units covered by this entry

        :returns: int
        """
        return self.insn_count

    def get_handler_off(self) -> int:
        """
        Get the offset in bytes from the start of the associated `EncodedCatchHandlerList` to the `EncodedCatchHandler` for this entry.

        :returns: int
        """
        return self.handler_off

    def get_raw(self) -> bytes:
        return self.CM.packer["I2H"].pack(
            self.start_addr, self.insn_count, self.handler_off
        )

    def get_length(self) -> int:
        return len(self.get_raw())

get_handler_off() #

Get the offset in bytes from the start of the associated EncodedCatchHandlerList to the EncodedCatchHandler for this entry.

Returns:

Type Description
int

int

Source code in androguard/core/dex/__init__.py
def get_handler_off(self) -> int:
    """
    Get the offset in bytes from the start of the associated `EncodedCatchHandlerList` to the `EncodedCatchHandler` for this entry.

    :returns: int
    """
    return self.handler_off

get_insn_count() #

Get the number of 16-bit code units covered by this entry

Returns:

Type Description
int

int

Source code in androguard/core/dex/__init__.py
def get_insn_count(self) -> int:
    """
    Get the number of 16-bit code units covered by this entry

    :returns: int
    """
    return self.insn_count

get_start_addr() #

Get the start address of the block of code covered by this entry. The address is a count of 16-bit code units to the start of the first covered instruction.

Returns:

Type Description
int

address int

Source code in androguard/core/dex/__init__.py
def get_start_addr(self) -> int:
    """
    Get the start address of the block of code covered by this entry. The address is a count of 16-bit code units to the start of the first covered instruction.

    :returns: address int
    """
    return self.start_addr

TypeHIdItem #

This class can parse a list of type_id_item of a dex file

Source code in androguard/core/dex/__init__.py
class TypeHIdItem:
    """
    This class can parse a list of `type_id_item` of a dex file
    """

    def __init__(self, size: int, buff: BinaryIO, cm: ClassManager) -> None:
        """
        :param buff: a string which represents a Buff object of the list of `type_id_item`
        :param cm: a `ClassManager` object
        """
        self.CM = cm

        self.offset = buff.tell()

        self.type = [TypeIdItem(buff, cm) for i in range(0, size)]

    def get_type(self) -> list[TypeIdItem]:
        """
        Return the list of `type_id_item`

        :returns: a list of `TypeIdItem` objects
        """
        return self.type

    def get(self, idx: int) -> int:
        try:
            return self.type[idx].get_descriptor_idx()
        except IndexError:
            return -1

    def set_off(self, off: int) -> None:
        self.offset = off

    def get_off(self) -> int:
        return self.offset

    def show(self) -> None:
        bytecode._PrintSubBanner("Type List Item")
        for i in self.type:
            i.show()

    def get_obj(self) -> list[TypeIdItem]:
        return [i for i in self.type]

    def get_raw(self) -> bytes:
        return b''.join(i.get_raw() for i in self.type)

    def get_length(self) -> int:
        length = 0
        for i in self.type:
            length += i.get_length()
        return length

__init__(size, buff, cm) #

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the list of type_id_item

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
def __init__(self, size: int, buff: BinaryIO, cm: ClassManager) -> None:
    """
    :param buff: a string which represents a Buff object of the list of `type_id_item`
    :param cm: a `ClassManager` object
    """
    self.CM = cm

    self.offset = buff.tell()

    self.type = [TypeIdItem(buff, cm) for i in range(0, size)]

get_type() #

Return the list of type_id_item

Returns:

Type Description
list[TypeIdItem]

a list of TypeIdItem objects

Source code in androguard/core/dex/__init__.py
def get_type(self) -> list[TypeIdItem]:
    """
    Return the list of `type_id_item`

    :returns: a list of `TypeIdItem` objects
    """
    return self.type

TypeIdItem #

This class can parse a type_id_item of a dex file

Source code in androguard/core/dex/__init__.py
class TypeIdItem:
    """
    This class can parse a `type_id_item` of a dex file
    """

    def __init__(self, buff: BinaryIO, cm: ClassManager):
        """
        :param buff: a string which represents a Buff object of the `type_id_item`
        :param cm: a `ClassManager` object
        """
        self.CM = cm
        self.offset = buff.tell()

        (self.descriptor_idx,) = cm.packer["I"].unpack(buff.read(4))
        self.descriptor_idx_value = self.CM.get_string(self.descriptor_idx)

    def get_descriptor_idx(self) -> int:
        """
        Return the index into the string_ids list for the descriptor string of this type

        :returns: int
        """
        return self.descriptor_idx

    def get_descriptor_idx_value(self) -> str:
        """
        Return the string associated to the descriptor

        :returns: string
        """
        return self.descriptor_idx_value

    def show(self) -> None:
        bytecode._PrintSubBanner("Type Id Item")
        bytecode._PrintDefault(
            "descriptor_idx=%d descriptor_idx_value=%s\n"
            % (self.descriptor_idx, self.descriptor_idx_value)
        )

    def get_obj(self) -> bytes:
        return self.CM.packer["I"].pack(self.descriptor_idx)

    def get_raw(self) -> bytes:
        return self.get_obj()

    def get_length(self) -> int:
        return len(self.get_obj())

__init__(buff, cm) #

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the type_id_item

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
def __init__(self, buff: BinaryIO, cm: ClassManager):
    """
    :param buff: a string which represents a Buff object of the `type_id_item`
    :param cm: a `ClassManager` object
    """
    self.CM = cm
    self.offset = buff.tell()

    (self.descriptor_idx,) = cm.packer["I"].unpack(buff.read(4))
    self.descriptor_idx_value = self.CM.get_string(self.descriptor_idx)

get_descriptor_idx() #

Return the index into the string_ids list for the descriptor string of this type

Returns:

Type Description
int

int

Source code in androguard/core/dex/__init__.py
def get_descriptor_idx(self) -> int:
    """
    Return the index into the string_ids list for the descriptor string of this type

    :returns: int
    """
    return self.descriptor_idx

get_descriptor_idx_value() #

Return the string associated to the descriptor

Returns:

Type Description
str

string

Source code in androguard/core/dex/__init__.py
def get_descriptor_idx_value(self) -> str:
    """
    Return the string associated to the descriptor

    :returns: string
    """
    return self.descriptor_idx_value

TypeItem #

This class can parse a type_item of a dex file

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a buff object of the type_item

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
class TypeItem:
    """
    This class can parse a `type_item` of a dex file

    :param buff: a string which represents a buff object of the `type_item`
    :param cm: a `ClassManager` object
    """

    def __init__(self, buff: BinaryIO, cm: ClassManager) -> None:
        self.CM = cm
        (self.type_idx,) = cm.packer["H"].unpack(buff.read(2))

    def get_type_idx(self):
        """
        Return the index into the `type_ids` list

        :returns: the index
        """
        return self.type_idx

    def get_string(self):
        """
        Return the type string

        :returns: the type string
        """
        return self.CM.get_type(self.type_idx)

    def show(self):
        bytecode._PrintSubBanner("Type Item")
        bytecode._PrintDefault("type_idx=%d\n" % self.type_idx)

    def get_obj(self):
        return self.CM.packer["H"].pack(self.type_idx)

    def get_raw(self):
        return self.get_obj()

    def get_length(self):
        return len(self.get_obj())

get_string() #

Return the type string

Returns:

Type Description

the type string

Source code in androguard/core/dex/__init__.py
def get_string(self):
    """
    Return the type string

    :returns: the type string
    """
    return self.CM.get_type(self.type_idx)

get_type_idx() #

Return the index into the type_ids list

Returns:

Type Description

the index

Source code in androguard/core/dex/__init__.py
def get_type_idx(self):
    """
    Return the index into the `type_ids` list

    :returns: the index
    """
    return self.type_idx

TypeList #

This class can parse a type_list of a dex file

Parameters:

Name Type Description Default
buff BinaryIO

a string which represents a Buff object of the type_list

required
cm ClassManager

a ClassManager object

required
Source code in androguard/core/dex/__init__.py
class TypeList:
    """
    This class can parse a `type_list` of a dex file

    :param buff: a string which represents a Buff object of the `type_list`
    :param cm: a `ClassManager` object
    """

    def __init__(self, buff: BinaryIO, cm: ClassManager) -> None:
        self.CM = cm
        self.offset = buff.tell()
        (self.size,) = cm.packer["I"].unpack(buff.read(4))

        self.list = [TypeItem(buff, cm) for _ in range(self.size)]

        self.pad = b""
        if self.size % 2 != 0:
            self.pad = buff.read(2)

        self.len_pad = len(self.pad)

    def get_pad(self):
        """
        Return the alignment string

        :returns: the alignment string
        """
        return self.pad

    def get_type_list_off(self):
        """
        Return the offset of the item

        :returns: the offset
        """
        return self.offset

    def get_string(self):
        """
        Return the concatenation of all strings

        :returns: concatenated strings
        """
        return ' '.join(i.get_string() for i in self.list)

    def get_size(self):
        """
        Return the size of the list, in entries

        :returns: the size of the list
        """
        return self.size

    def get_list(self):
        """
        Return the list of [TypeItem][androguard.core.dex.TypeItem]

        :returns: a list of `TypeItem` objects
        """
        return self.list

    def set_off(self, off: int):
        self.offset = off

    def get_off(self):
        return self.offset + self.len_pad

    def show(self):
        bytecode._PrintSubBanner("Type List")
        bytecode._PrintDefault("size=%d\n" % self.size)

        for i in self.list:
            i.show()

    def get_obj(self):
        return self.pad + self.CM.packer["I"].pack(self.size)

    def get_raw(self):
        return self.get_obj() + b''.join(i.get_raw() for i in self.list)

    def get_length(self):
        length = len(self.get_obj())

        for i in self.list:
            length += i.get_length()

        return length

get_list() #

Return the list of TypeItem

Returns:

Type Description

a list of TypeItem objects

Source code in androguard/core/dex/__init__.py
def get_list(self):
    """
    Return the list of [TypeItem][androguard.core.dex.TypeItem]

    :returns: a list of `TypeItem` objects
    """
    return self.list

get_pad() #

Return the alignment string

Returns:

Type Description

the alignment string

Source code in androguard/core/dex/__init__.py
def get_pad(self):
    """
    Return the alignment string

    :returns: the alignment string
    """
    return self.pad

get_size() #

Return the size of the list, in entries

Returns:

Type Description

the size of the list

Source code in androguard/core/dex/__init__.py
def get_size(self):
    """
    Return the size of the list, in entries

    :returns: the size of the list
    """
    return self.size

get_string() #

Return the concatenation of all strings

Returns:

Type Description

concatenated strings

Source code in androguard/core/dex/__init__.py
def get_string(self):
    """
    Return the concatenation of all strings

    :returns: concatenated strings
    """
    return ' '.join(i.get_string() for i in self.list)

get_type_list_off() #

Return the offset of the item

Returns:

Type Description

the offset

Source code in androguard/core/dex/__init__.py
def get_type_list_off(self):
    """
    Return the offset of the item

    :returns: the offset
    """
    return self.offset

clean_name_instruction(instruction) #

USED IN ELSIM

Source code in androguard/core/dex/__init__.py
def clean_name_instruction(instruction: Instruction) -> str:
    """USED IN ELSIM"""
    op_value = instruction.get_op_value()

    # goto range
    if 0x28 <= op_value <= 0x2A:
        return "goto"

    return instruction.get_name()

determineException(vm, m) #

Returns try-catch handler inside the method.

Parameters:

Name Type Description Default
vm DEX

a DEX object

required
m EncodedMethod

EncodedMethod object

required

Returns:

Type Description
list[list]

a list

Source code in androguard/core/dex/__init__.py
def determineException(vm: DEX, m: EncodedMethod) -> list[list]:
    """
    Returns try-catch handler inside the method.

    :param vm: a `DEX` object
    :param m: `EncodedMethod` object
    :return: a list
    """
    # no exceptions !
    if m.get_code().get_tries_size() <= 0:
        return []

    h_off = {}

    handler_catch_list = m.get_code().get_handlers()

    for try_item in m.get_code().get_tries():
        offset_handler = (
            try_item.get_handler_off() + handler_catch_list.get_off()
        )
        if offset_handler in h_off:
            h_off[offset_handler].append([try_item])
        else:
            h_off[offset_handler] = []
            h_off[offset_handler].append([try_item])

    # print m.get_name(), "\t HANDLER_CATCH_LIST SIZE", handler_catch_list.size, handler_catch_list.get_offset()
    for handler_catch in handler_catch_list.get_list():
        if handler_catch.get_off() not in h_off:
            continue

        for i in h_off[handler_catch.get_off()]:
            i.append(handler_catch)

    exceptions = []
    # print m.get_name(), h_off
    for i in h_off:
        for value in h_off[i]:
            try_value = value[0]

            # start,end
            z = [
                try_value.get_start_addr() * 2,
                (try_value.get_start_addr() * 2)
                + (try_value.get_insn_count() * 2)
                - 1,
            ]

            handler_catch = value[1]

            # exceptions
            for handler in handler_catch.get_handlers():
                z.append(
                    [
                        vm.get_cm_type(handler.get_type_idx()),
                        handler.get_addr() * 2,
                    ]
                )

            if handler_catch.get_size() <= 0:
                z.append(
                    [
                        "Ljava/lang/Throwable;",
                        handler_catch.get_catch_all_addr() * 2,
                    ]
                )

            exceptions.append(z)

    # print m.get_name(), exceptions
    return exceptions

determineNext(i, cur_idx, m) #

Determine the next offsets inside the bytecode of an EncodedMethod. The offsets are calculated in number of bytes from the start of the method. Note, that offsets inside the bytecode are denoted in 16bit units but this method returns actual bytes!

Offsets inside the opcode are counted from the beginning of the opcode.

The returned type is a list, as branching opcodes will have multiple paths. if and switch opcodes will return more than one item in the list, while throw, return and goto opcodes will always return a list with length one.

An offset of -1 indicates that the method is exited, for example by throw or return.

If the entered opcode is not branching or jumping, an empty list is returned.

Parameters:

Name Type Description Default
i Instruction

the current Instruction

required
cur_idx int

Index of the instruction

required
m EncodedMethod

the current method

required

Returns:

Type Description
list
Source code in androguard/core/dex/__init__.py
def determineNext(i: Instruction, cur_idx: int, m: EncodedMethod) -> list:
    """
    Determine the next offsets inside the bytecode of an [EncodedMethod][androguard.core.dex.EncodedMethod].
    The offsets are calculated in number of bytes from the start of the method.
    Note, that offsets inside the bytecode are denoted in 16bit units but this method returns actual bytes!

    Offsets inside the opcode are counted from the beginning of the opcode.

    The returned type is a list, as branching opcodes will have multiple paths.
    `if` and `switch` opcodes will return more than one item in the list, while
    `throw`, `return` and `goto` opcodes will always return a list with length one.

    An offset of -1 indicates that the method is exited, for example by `throw` or `return`.

    If the entered opcode is not branching or jumping, an empty list is returned.

    :param i: the current Instruction
    :param cur_idx: Index of the instruction
    :param m: the current method
    :return:
    """
    op_value = i.get_op_value()

    if (op_value == 0x27) or (0x0E <= op_value <= 0x11):
        # throw + return*
        return [-1]
    elif 0x28 <= op_value <= 0x2A:
        # all kind of 'goto'
        off = i.get_ref_off() * 2
        return [off + cur_idx]
    elif 0x32 <= op_value <= 0x3D:
        # all kind of 'if'
        off = i.get_ref_off() * 2
        return [cur_idx + i.get_length(), off + cur_idx]
    elif op_value in (0x2B, 0x2C):
        # packed/sparse switch
        # Code flow will continue after the switch command
        x = [cur_idx + i.get_length()]

        # The payload must be read at the offset position
        code = m.get_code().get_bc()
        off = i.get_ref_off() * 2

        # See DEX bytecode documentation:
        # "the instructions must be located on even-numbered bytecode offsets (that is, 4-byte aligned).
        # In order to meet this requirement, dex generation tools must
        # emit an extra nop instruction as a spacer if such an instruction would otherwise be unaligned."
        remaining = (off + cur_idx) % 4
        padding = 0 if remaining == 0 else (4 - remaining)
        if padding != 0:
            logger.warning(
                "Switch payload not aligned, assume stuff and add {} bytes...".format(
                    padding
                )
            )
        data = code.get_ins_off(off + cur_idx + padding)

        # TODO: some malware points to invalid code
        # Does Android ignores the nop and searches for the switch payload?
        # So we make sure that this is a switch payload
        if data and (
            isinstance(data, PackedSwitch) or isinstance(data, SparseSwitch)
        ):
            for target in data.get_targets():
                x.append(target * 2 + cur_idx)
        else:
            logger.warning(
                "Could not determine payload of switch command at offset {} inside {}! "
                "Possibly broken bytecode?".format(cur_idx, m)
            )

        return x
    return []

get_access_flags_string(value) #

Transform an access flag field to the corresponding string

Parameters:

Name Type Description Default
value int

the value of the access flags

required

Returns:

Type Description
str

the transformed string

Source code in androguard/core/dex/__init__.py
def get_access_flags_string(value: int) -> str:
    """
    Transform an access flag field to the corresponding string

    :param value: the value of the access flags

    :returns: the transformed string
    """
    flags = []
    for k, v in ACCESS_FLAGS.items():
        if (k & value) == k:
            flags.append(v)

    return " ".join(flags)

get_bytecodes_method(dex_object, analysis_object, method) #

return a string representation of method and its code. Wraps get_bytecodes_methodx

Parameters:

Name Type Description Default
dex_object

unused

required
analysis_object Analysis

the Analysis object containing the class

required
method EncodedMethod

the EncodedMethod to get

required
Source code in androguard/core/dex/__init__.py
def get_bytecodes_method(
    dex_object, analysis_object: Analysis, method: EncodedMethod
) -> str:
    """return a string representation of method and its code. Wraps [get_bytecodes_methodx][androguard.core.dex.get_bytecodes_methodx]

    :param dex_object: unused
    :param analysis_object: the `Analysis` object containing the class
    :param method: the `EncodedMethod` to get
    """
    mx = analysis_object.get_method(method)
    return get_bytecodes_methodx(method, mx)

get_bytecodes_methodx(method, mx) #

return a string representation of a method and its code

Parameters:

Name Type Description Default
method EncodedMethod

the associatedEncodedMethod to get

required
mx MethodAnalysis

the associated MethodAnalysis to get

required

Returns:

Type Description
str

the string representation

Source code in androguard/core/dex/__init__.py
def get_bytecodes_methodx(method: EncodedMethod, mx: MethodAnalysis) -> str:
    """return a string representation of a method and its code

    :param method: the associated`EncodedMethod` to get
    :param mx: the associated `MethodAnalysis` to get
    :returns: the string representation
    """
    basic_blocks = mx.basic_blocks.gets()
    i_buffer = ""

    idx = 0
    nb = 0

    i_buffer += "# {}->{}{} [access_flags={}]\n#\n".format(
        method.get_class_name(),
        method.get_name(),
        method.get_descriptor(),
        method.get_access_flags_string(),
    )
    if method.code is not None:
        i_buffer += get_params_info(
            method.code.get_registers_size(), method.get_descriptor()
        )

        for i in basic_blocks:
            bb_buffer = ""
            ins_buffer = ""

            bb_buffer += "%s : " % i.name

            # TODO using the generator object as a list again is not ideal...
            instructions = list(i.get_instructions())
            for ins in instructions:
                ins_buffer += "\t%-8d(%08x) " % (nb, idx)
                ins_buffer += "{:<20} {}".format(
                    ins.get_name(), ins.get_output(idx)
                )

                op_value = ins.get_op_value()
                if ins == instructions[-1] and i.childs != []:
                    # packed/sparse-switch
                    if (op_value == 0x2B or op_value == 0x2C) and len(
                        i.childs
                    ) > 1:
                        values = i.get_special_ins(idx).get_values()
                        bb_buffer += "[ D:%s " % i.childs[0][2].name
                        bb_buffer += (
                            ' '.join(
                                "%d:%s" % (values[j], i.childs[j + 1][2].name)
                                for j in range(0, len(i.childs) - 1)
                            )
                            + " ]"
                        )
                    else:
                        # if len(i.childs) == 2:
                        #    i_buffer += "%s[ %s%s " % (branch_false_color, i.childs[0][2].name, branch_true_color))
                        #    print_fct(' '.join("%s" % c[2].name for c in i.childs[1:]) + " ]%s" % normal_color)
                        # else:
                        bb_buffer += (
                            "[ "
                            + ' '.join("%s" % c[2].name for c in i.childs)
                            + " ]"
                        )

                idx += ins.get_length()
                nb += 1

                ins_buffer += "\n"

            if i.get_exception_analysis() is not None:
                ins_buffer += "\t%s\n" % (i.exception_analysis.show_buff())

            i_buffer += bb_buffer + "\n" + ins_buffer + "\n"

    return i_buffer

get_instruction(cm, op_value, buff) #

Return the Instruction for the given opcode

Parameters:

Name Type Description Default
cm ClassManager

ClassManager to propagate to Instruction

required
op_value int

integer value of the instruction

required
buff bytearray

Bytecode starting with the instruction

required

Returns:

Type Description
Instruction

the parsed Instruction

Raises:

Type Description
InvalidInstruction

if instruction is invalid

Source code in androguard/core/dex/__init__.py
def get_instruction(
    cm: ClassManager, op_value: int, buff: bytearray
) -> Instruction:
    """
    Return the [Instruction][androguard.core.dex.Instruction] for the given opcode

    :param cm: `ClassManager` to propagate to `Instruction`
    :param op_value: integer value of the instruction
    :param buff: Bytecode starting with the `instruction`
    :raises InvalidInstruction: if instruction is invalid
    :returns: the parsed `Instruction`
    """
    try:
        return DALVIK_OPCODES_FORMAT[op_value][0](cm, buff)
    except struct.error:
        # FIXME: there are other possible errors too...
        raise InvalidInstruction(
            "Invalid Instruction for '0x{:02x}': {}".format(
                op_value, repr(buff)
            )
        )

get_kind(cm, kind, value) #

Return the value of the 'kind' argument

Parameters:

Name Type Description Default
cm ClassManager

a ClassManager object

required
kind int

the type of the 'kind' argument

required
value int

the value of the 'kind' argument

required

Returns:

Type Description
str

string

Source code in androguard/core/dex/__init__.py
def get_kind(cm: ClassManager, kind: int, value: int) -> str:
    """
    Return the value of the 'kind' argument

    :param cm: a ClassManager object
    :param kind: the type of the 'kind' argument
    :param value: the value of the 'kind' argument

    :returns: string
    """
    if kind == Kind.METH:
        method = cm.get_method_ref(value)
        class_name = method.get_class_name()
        name = method.get_name()
        descriptor = method.get_descriptor()

        return "{}->{}{}".format(class_name, name, descriptor)

    elif kind == Kind.STRING:
        return cm.get_string(value)

    # TODO: unused?
    elif kind == Kind.RAW_STRING:
        return cm.get_string(value)

    elif kind == Kind.FIELD:
        class_name, proto, field_name = cm.get_field(value)
        return "{}->{} {}".format(class_name, field_name, proto)

    elif kind == Kind.TYPE:
        return cm.get_type(value)

    elif kind == Kind.VTABLE_OFFSET:
        return "vtable[0x%x]" % value

    elif kind == Kind.FIELD_OFFSET:
        return "field[0x%x]" % value

    elif kind == Kind.INLINE_METHOD:
        buff = "inline[0x%x]" % value

        # FIXME: depends of the android version ...
        if len(INLINE_METHODS) > value:
            elem = INLINE_METHODS[value]
            buff += " {}->{}{}".format(elem[0], elem[1], elem[2])

        return buff

    return None

get_optimized_instruction(cm, op_value, buff) #

Return the Instruction for the given optimized opcode

Parameters:

Name Type Description Default
cm ClassManager

ClassManager to propagate to Instruction

required
op_value int

integer value of the instruction

required
buff bytearray

Bytecode starting with the instruction

required

Returns:

Type Description
Instruction

the parsed Instruction

Raises:

Type Description
InvalidInstruction

if instruction is invalid

Source code in androguard/core/dex/__init__.py
def get_optimized_instruction(
    cm: ClassManager, op_value: int, buff: bytearray
) -> Instruction:
    """Return the [Instruction][androguard.core.dex.Instruction] for the given optimized opcode

    :param cm: `ClassManager` to propagate to `Instruction`
    :param op_value: integer value of the instruction
    :param buff: Bytecode starting with the `instruction`
    :raises InvalidInstruction: if instruction is invalid
    :returns: the parsed `Instruction`
    """
    try:
        return DALVIK_OPCODES_OPTIMIZED[op_value][0](cm, buff)
    except struct.error:
        # FIXME: there are other possible errors too...
        raise InvalidInstruction(
            "Invalid Instruction for '0x{:04x}': {}".format(
                op_value, repr(buff)
            )
        )

get_params_info(nb, proto) #

return a string of parameter info given a function prototype (proto)

Parameters:

Name Type Description Default
nb int

the number of parameters

required
proto str

the function prototype with parameters

required

Returns:

Type Description
str

a string representation of the parameter info

Source code in androguard/core/dex/__init__.py
def get_params_info(nb: int, proto: str) -> str:
    """return a string of parameter info given a function prototype (proto)

    :param nb: the number of parameters
    :param proto: the function prototype with parameters
    :returns: a string representation of the parameter info
    """
    i_buffer = "# Parameters:\n"

    ret = proto.split(')')
    params = ret[0][1:].split()
    if params:
        i_buffer += "# - local registers: v%d...v%d\n" % (
            0,
            nb - len(params) - 1,
        )
        j = 0
        for i in range(nb - len(params), nb):
            i_buffer += "# - v%d:%s\n" % (i, get_type(params[j]))
            j += 1
    else:
        i_buffer += "# local registers: v%d...v%d\n" % (0, nb - 1)

    i_buffer += "#\n# - return:%s\n\n" % get_type(ret[1])

    return i_buffer

get_type(atype, size=None) #

Retrieve the type of a descriptor (e.g : I)

Returns:

Type Description
str

the descriptor string

Source code in androguard/core/dex/__init__.py
def get_type(atype: str, size: Union[int, None] = None) -> str:
    """
    Retrieve the type of a descriptor (e.g : I)
    :returns: the descriptor string
    """
    if atype.startswith('java.lang'):
        atype = atype.replace('java.lang.', '')
    res = TYPE_DESCRIPTOR.get(atype.lstrip('java.lang'))
    if res is None:
        if atype[0] == 'L':
            res = atype[1:-1].replace('/', '.')
        elif atype[0] == '[':
            if size is None:
                res = '%s[]' % get_type(atype[1:])
            else:
                res = '{}[{}]'.format(get_type(atype[1:]), size)
        else:
            res = atype
    return res

read_null_terminated_string(f) #

Read a null terminated string from a file-like object.

Parameters:

Name Type Description Default
f IO

file-like object

required

Returns:

Type Description
bytearray

the bytes of the string read

Source code in androguard/core/dex/__init__.py
def read_null_terminated_string(f: IO) -> bytearray:
    """
    Read a null terminated string from a file-like object.
    :param f: file-like object

    :returns: the bytes of the string read
    """
    x = []
    while True:
        z = f.read(128)
        if 0 in z:
            s = z.split(b'\x00', 1)
            x.append(s[0])
            idx = f.tell()
            f.seek(idx - len(s[1]))
            break
        else:
            x.append(z)
    return b''.join(x)

readsleb128(cm, buff) #

Read a signed LEB128 at the current position of the buffer.

Parameters:

Name Type Description Default
buff BinaryIO

a file like object

required

Returns:

Type Description
int

decoded sLEB128

Source code in androguard/core/dex/__init__.py
def readsleb128(cm: ClassManager, buff: BinaryIO) -> int:
    """
    Read a signed LEB128 at the current position of the buffer.

    :param buff: a file like object
    :return: decoded sLEB128
    """
    result = 0
    shift = 0

    for x in range(0, 5):
        cur = get_byte(cm, buff)
        result |= (cur & 0x7F) << shift
        shift += 7

        if not cur & 0x80:
            bit_left = max(32 - shift, 0)
            result = result << bit_left
            if result > 0x7FFFFFFF:
                result = (0x7FFFFFFF & result) - 0x80000000
            result = result >> bit_left
            break

    return result

readuleb128(cm, buff) #

Read an unsigned LEB128 at the current position of the buffer

Parameters:

Name Type Description Default
buff BinaryIO

a file like object

required

Returns:

Type Description
int

decoded unsigned LEB128

Source code in androguard/core/dex/__init__.py
def readuleb128(cm: ClassManager, buff: BinaryIO) -> int:
    """
    Read an unsigned LEB128 at the current position of the buffer

    :param buff: a file like object
    :returns: decoded unsigned LEB128
    """
    result = get_byte(cm, buff)
    if result > 0x7F:
        cur = get_byte(cm, buff)
        result = (result & 0x7F) | ((cur & 0x7F) << 7)
        if cur > 0x7F:
            cur = get_byte(cm, buff)
            result |= (cur & 0x7F) << 14
            if cur > 0x7F:
                cur = get_byte(cm, buff)
                result |= (cur & 0x7F) << 21
                if cur > 0x7F:
                    cur = get_byte(cm, buff)
                    if cur > 0x0F:
                        logger.warning("possible error while decoding number")
                    result |= cur << 28

    return result

readuleb128p1(cm, buff) #

Read an unsigned LEB128p1 at the current position of the buffer. This format is the same as uLEB128 but has the ability to store the value -1.

Parameters:

Name Type Description Default
buff BinaryIO

a file like object

required

Returns:

Type Description
int

decoded uLEB128p1

Source code in androguard/core/dex/__init__.py
def readuleb128p1(cm: ClassManager, buff: BinaryIO) -> int:
    """
    Read an unsigned LEB128p1 at the current position of the buffer.
    This format is the same as uLEB128 but has the ability to store the value -1.

    :param buff: a file like object
    :return: decoded uLEB128p1
    """
    return readuleb128(cm, buff) - 1

static_operand_instruction(instruction) #

USED IN ELSIM

Source code in androguard/core/dex/__init__.py
def static_operand_instruction(instruction: Instruction) -> str:
    """USED IN ELSIM"""
    buff = ""

    if isinstance(instruction, Instruction):
        # get instructions without registers
        for val in instruction.get_literals():
            buff += "%s" % val

    op_value = instruction.get_op_value()
    if op_value == 0x1A or op_value == 0x1B:
        buff += instruction.get_string()

    return buff

writesleb128(cm, value) #

Convert an integer value to the corresponding signed LEB128

Parameters:

Name Type Description Default
value int

integer value

required

Returns:

Type Description
bytearray

bytes

Source code in androguard/core/dex/__init__.py
def writesleb128(cm: ClassManager, value: int) -> bytearray:
    """
    Convert an integer value to the corresponding signed LEB128

    :param value: integer value
    :return: bytes
    """
    remaining = value >> 7
    hasMore = True
    buff = bytearray()

    if (value & (-sys.maxsize - 1)) == 0:
        end = 0
    else:
        end = -1

    while hasMore:
        hasMore = (remaining != end) or ((remaining & 1) != ((value >> 6) & 1))
        tmp = 0
        if hasMore:
            tmp = 0x80

        buff += cm.packer["B"].pack((value & 0x7F) | tmp)
        value = remaining
        remaining >>= 7

    return buff

writeuleb128(cm, value) #

Convert an integer value to the corresponding unsigned LEB128.

Raises a value error, if the given value is negative.

Parameters:

Name Type Description Default
value int

non-negative integer

required

Returns:

Type Description
bytearray

bytes

Raises:

Type Description
ValueError

if given value is negative

Source code in androguard/core/dex/__init__.py
def writeuleb128(cm: ClassManager, value: int) -> bytearray:
    """
    Convert an integer value to the corresponding unsigned LEB128.

    Raises a value error, if the given value is negative.

    :raises ValueError: if given value is negative
    :param value: non-negative integer
    :returns: bytes
    """
    if value < 0:
        raise ValueError("value must be non-negative!")

    remaining = value >> 7

    buff = bytearray()
    while remaining > 0:
        buff += cm.packer["B"].pack(((value & 0x7F) | 0x80))

        value = remaining
        remaining >>= 7

    buff += cm.packer["B"].pack(value & 0x7F)
    return buff