예제 #1
0
def vtable_overrides(class_vtable,
                     super_vtable,
                     class_vlength=None,
                     super_vlength=None,
                     new=False,
                     methods=False):
    """Get the overrides of a virtual method table.

    A generator that returns the index of each override in the virtual method table. The initial
    empty entries are skipped, so the first virtual method is at index 0.

    Arguments:
        class_vtable: The vtable of the class.
        super_vtable: The vtable of the ancestor to compare against for overrides.

    Options:
        class_vlength: The length of class_vtable. If None, it will be calculated.
        super_vlength: The length of super_vtable. If None, it will be calculated.
        new: If True, include new virtual methods not present in the superclass. Default is False.
        methods: If True, then the generator will produce a tuple containing the index, the
            overridden method in the subclass, and the original method in the superclas, rather
            than just the index. Default is False.
    """
    assert class_vtable
    # Get the vtable lengths.
    if class_vlength is None:
        class_vlength = vtable_length(class_vtable)
    if super_vlength is None:
        super_vlength = vtable_length(super_vtable)
    assert class_vlength >= super_vlength >= 0
    # Skip the first VTABLE_OFFSET entries.
    class_vtable += VTABLE_OFFSET * idau.WORD_SIZE
    super_vtable += VTABLE_OFFSET * idau.WORD_SIZE
    class_vlength -= VTABLE_OFFSET
    super_vlength -= VTABLE_OFFSET
    # How many methods are we iterating over?
    if new:
        nmethods = class_vlength
    else:
        nmethods = super_vlength
    # Iterate through the methods.
    for i in xrange(nmethods):
        # Read the old method.
        super_method = None
        if i < super_vlength:
            super_method = idau.read_word(super_vtable + i * idau.WORD_SIZE)
        # Read the new method. (It's always in range.)
        class_method = idau.read_word(class_vtable + i * idau.WORD_SIZE)
        # If they're different, yield.
        if class_method != super_method:
            if methods:
                yield i, class_method, super_method
            else:
                yield i
예제 #2
0
def vtable_methods(vtable, start=VTABLE_OFFSET, length=None, nmethods=None):
    """Get the methods in a virtual method table.

    A generator that returns each method in the virtual method table. The initial empty entries are
    skipped.

    Arguments:
        vtable: The address of the virtual method table. (This includes the initial empty entries.)

    Options:
        start: The index at which to start returning values. All prior indexes
            are skipped. Default is VTABLE_OFFSET, meaning the initial empty
            entries will be skipped.
        length: The length of the vtable, including the initial empty entries. Specify this value
            to read the entire vtable if the length is already known.
        nmethods: The number of methods to read, excluding the initial empty entries. If None, the
            whole vtable will be read. Default is None.
    """
    assert vtable
    # Get the length of the vtable.
    if nmethods is not None:
        length = nmethods + VTABLE_OFFSET
    elif length is None:
        length = vtable_length(vtable)
    # Read the methods.
    for i in xrange(start, length):
        yield idau.read_word(vtable + i * idau.WORD_SIZE)
 def load(addr, dtyp):
     if not addr:
         return None
     if dtyp == idaapi.dt_qword:
         size = 8
     elif dtyp == idaapi.dt_dword:
         size = 4
     else:
         return None
     return idau.read_word(addr, size)
예제 #4
0
def _get_vtable_metaclass(vtable_addr, metaclass_info):
    """Simulate the getMetaClass method of the vtable and check if it returns an OSMetaClass."""
    getMetaClass = idau.read_word(vtable_addr + _VTABLE_GETMETACLASS * idau.WORD_SIZE)
    def on_RET(reg):
        on_RET.ret = reg['X0']
    on_RET.ret = None
    _emulate_arm64(getMetaClass, getMetaClass + idau.WORD_SIZE * _MAX_GETMETACLASS_INSNS,
            on_RET=on_RET)
    if on_RET.ret in metaclass_info:
        return on_RET.ret
def untag_pointers_in_range(start, end):
    assert kernel.kernelcache_format == kernel.KC_12_MERGED, 'Wrong kernelcache format'
    ea, tp = start, None
    while True:
        ea = tagged_pointer_next(ea, tp, end)
        if ea is None or ea >= end:
            break
        tp = idau.read_word(ea)
        if not is_tagged_pointer(tp):
            _log(1, 'Tagged pointer traversal failed: ea={:x}, tp={:x}'.format(ea, tp))
            break
        untag_pointer(ea, tp)
예제 #6
0
def class_vtable_method(classinfo, index):
    """Get the virtual method for a class by index.

    Arguments:
        classinfo: The class information of the class.
        index: The index of the virtual method, skipping the empty entries (that is, the first
            virtual method is at index 0).
    """
    # Get the vtable for the class.
    methods = classinfo.vtable_methods
    count = classinfo.vtable_nmethods
    if index >= count:
        return None
    return idau.read_word(methods + index * idau.WORD_SIZE)
예제 #7
0
def _process_stub_template_1(stub):
    """A template to match the following stub pattern:

    ADRP X<reg>, #<offset>@PAGE
    LDR  X<reg>, [X<reg>, #<offset>@PAGEOFF]
    BR   X<reg>
    """
    adrp, ldr, br = idau.Instructions(stub, count=3)
    if (adrp.itype == idaapi.ARM_adrp and adrp.Op1.type == idaapi.o_reg
            and adrp.Op2.type == idaapi.o_imm and ldr.itype == idaapi.ARM_ldr
            and ldr.Op1.type == idaapi.o_reg and ldr.Op2.type == idaapi.o_displ
            and ldr.auxpref == 0 and br.itype == idaapi.ARM_br
            and br.Op1.type == idaapi.o_reg
            and adrp.Op1.reg == ldr.Op1.reg == ldr.Op2.reg == br.Op1.reg):
        offset = adrp.Op2.value + ldr.Op2.addr
        target = idau.read_word(offset)
        if target and idau.is_mapped(target):
            return target