Examples (Hex Rays) | Correcting the types of both parameters and variables - arizvisa/ida-minsc GitHub Wiki

Identify typed functions that point to a structure as one of its parameters

res, err=[], []

# iterate through all typed functions
for ea in db.functions.iterate(typed=True):

    # enumerate all the parameters filtering for ones that have a structure pointing to it
    try:
        items = [(i,ti) for i, ti in enumerate(func.args(ea)) if struc.has(ti)]

    # if this errors out for some reason, bail and collect it in our list
    except Exception:
        print('ERR', hex(ea))
        err.append(ea)
        continue

    # find any structures in the parameters that have "78738" in its name and store the parameter index if so
    if any('78738' in struc.by(ti).name for i, ti in items):
        res.extend((ea, i) for i, ti in items if '78738' in struc.by(ti).name)
        print(hex(ea), func.type(ea))
    continue

General utilities for interacting with tinfo_t pointers.

def ptrcount(ti, count=0):
    '''count the number of times a type may be dereferenced (the number of "*").'''
    if not ti.is_ptr():
        return count
    ti = db.types.dereference(ti)
    return ptrcount(ti, count + 1)

def ptrmake(ti, count=0):
    '''turn the typeinfo into a pointer with the given number of "*".'''
    if count <= 0:
        return ti
    ti = db.types.pointer(ti)
    return ptrmake(ti, count - 1)

Update all collected parameters with the new structure

newstruct = struc.search('*OSEG')
items = res
for ea, i in items:

    # grab the argument type and count the number of times it can be dereferenced
    ti = func.arg(ea, i)
    c = ptrcount(ti)

    # create pointers to "newstruct" using the count we just calculated
    newti = ptrmake(newstruct, c)

    # update the parameter with the new type
    oldti = func.arg(ea, i, newti)
    print("updated {:#x} ({:d}) : {!s} -> {!s}".format(ea, i, oldti, newti))

Iterate through all the decompiled functions and look for any variables matching our wanted type

res, err = [], []

# iterate through all functions that have been decompiled
for ea in db.functions.iterate(decompiled=True):

    # grab their hexrays function object, saving the address if it errors out
    try:
        f = hexrays.function(ea)
    except Exception as E:
        print(hex(ea), 'IGNORED')
        err.append(ea)
        continue

    # grab the type of each variable within the decompiled function
    iterable = (hexrays.variable.type(lv) for lv in hexrays.variables.iterate(f))

    # grab any variables where its type can be resolved to a structure
    items = (struc.by(ti) for ti in iterable if struc.has(ti))

    # if the name of any of the structures have "78738" in it, then save it
    if any('78738' in st.name for st in items):
        res.append(ea)
        print(hex(ea), func.type(ea))
    continue

iterate through our results, find the variable again, and update its type.

newstruc = struc.search('*OSEG')
items, errs = res, []
for ea in items:
    try:
        f = hexrays.function(ea)
    except Exception as E:
        errs.append(ea)
        continue

    # get all of the variables that match our type
    iterable = ((lv,hexrays.variable.type(lv)) for lv in hexrays.variables.iterate(f))
    items = [lv for lv, ti in iterable if struc.has(ti) and '78738' in struc.by(ti).name]
    
    # now that we have them, update their type while ensuring that we don't change
    # the number of dereferences for any pointers.
    for lvar in items:
        ti = hexrays.variable.type(lvar)
        c = ptrcount(ti)
        newti = ptrmake(newstruc, c)
        print(hex(ea), hexrays.variable.type(lvar, newti), newti, hexrays.variable.repr(lvar))
    continue