Examples | Generate Breakpoints for all of the Functions that you have visited - arizvisa/ida-minsc GitHub Wiki

(Dumb) windbg breakpoint generator for all the functions you've touched

masmformat = lambda item: "@{:s}".format(item.name) if isinstance(item, register_t) else "@rsp+8+{:#x}".format(item.offset)
for ea, tags in db.select('__typeinfo__'):
    if not func.within(ea): continue

    sizes = [ ti.get_size() for ti in func.type.args(ea) ]
    locs = func.type.args.registers(ea) + func.type.args.locations(ea)

    params = [ "({:s}) & {:#x}".format(masmformat(item), pow(2, 8 * size) - 1) for item, size in zip(locs, sizes)]
    formats = [ "%0{:d}x".format(2 * size) for size in sizes ]
    bpstr = ".printf \"{:s} -> {:s}({:s})\\n\"{:s}; gc".format(tags['__typeinfo__'], func.name(ea), ', '.join(formats), ", {:s}".format(', '.join(params)) if params else '')
    db.tag(ea, 'func.entry.breakpoint', bpstr)

    result = func.type.result(ea)
    loc = func.type.result.location(ea)
    bpstr = ".printf \"{:s} -> returned{:s}\\n\"{:s};gc".format(tags['__typeinfo__'], ' %p' if loc else '', ",@{:s}".format(loc.name) if isinstance(loc, register_t) else '')
    for ea in func.bottom(ea):
        db.tag(ea, 'func.exit.breakpoint', bpstr)
    continue

Then to actually generate them so you can load them with $>< or something similar.

for f, tags in db.selectcontents(Or=['func.entry.breakpoint', 'func.exit.breakpoint']):
    for ea, tags in func.select(f, Or=['func.entry.breakpoint', 'func.exit.breakpoint']):
        for k, v in tags.items():
            print("bp {:s}+{:#x} \"{:s}\"".format(db.module(), db.offset(ea), custom.windbg.escape(v, 1)))

Really terrible code to generate windbg breakpoints that list input and output for entries and exits of a list of functions

stackreg = '@rsp'
def getargs(ea):
    for name, ti, store in zip(func.args.names(ea), func.args(ea), func.args.storage(ea)):
        yield name, ti, store
    return

def resolvestr(ti):
    if not ti.is_ptr():
        return
    ti = ti.get_pointed_object()
    if ti.is_char():
        return "%ma"
    elif ti.get_type_name() == 'wchar_t':
        return "%mu"
    return

def expandargs(ea):
    table = {
        1: 'by({:s})' + "&{:#x}".format(pow(2,8*1)-1),
        2: 'wo({:s})' + "&{:#x}".format(pow(2,8*2)-1),
        4: 'dwo({:s})' + "&{:#x}".format(pow(2,8*4)-1),
        8: 'qwo({:s})' + "&{:#x}".format(pow(2,8*8)-1),
    }
    for name, ti, store in getargs(ea):
        fmt = table[store.size].format
        store = store + 4 if isinstance(store, location_t) else store
        loc = fmt("@{:s}+{:x}".format(stackreg, store.offset)) if isinstance(store, location_t) else "@{:s}".format(store.name)
        if resolvestr(ti):
            yield name, "%x->"+resolvestr(ti), [loc, loc]
        elif ti.is_ptr():
            yield name, "%x->%x", [loc, 'poi({:s})'.format(loc)]
        else:
            yield name, '%x', [loc]
        continue
    return

def preserveargs(ea):
    for i, (name, ti, store) in enumerate(getargs(ea)):
        if not ti.is_ptr(): continue
        store = store + 4 if isinstance(store, location_t) else store
        loc = "@{:s}+{:x}".format(stackreg, store.offset) if isinstance(store, location_t) else "@{:s}".format(store.name)
        yield ".if ($vvalid(poi({:s}),1)) {{r@$t{:d}=poi({:s})}}".format(loc, i, loc)
    return

def dumpargs(ea):
    for i, (name, ti, store) in enumerate(getargs(ea)): 
        if not ti.is_ptr(): continue
        ti = ti.get_pointed_object()
        p1 = ".printf\"    {:s} : {:s} = %p -> {:s}\\n\",{:s},{:s}".format(func.name(ea), name, resolvestr(ti) or '%x', "@$t{:d}".format(i), "poi(@$t{:d})".format(i))
        p2 = ".printf\"    {:s} : {:s} = %p\\n\",{:s}".format(func.name(ea), name, "@$t{:d}".format(i))
        yield ".if ($vvalid(@$t{:d},1)) {{ {:s} }} .else {{ {:s} }}".format(i, p1, p2)
    return

def prototype(ea):
    items = [("{:s}={:s}".format(name, fmt), locs) for name, fmt, locs in expandargs(ea)]
    formats, locations = zip(*items) if items else ([], [])
    params = "{:s}({:s})".format(func.name(ea), ', '.join(formats) if formats else '')
    return ".printf\"{:s}\\n\"{:s}".format(params, ",{:s}".format(','.join(itertools.chain(*locations))) if locations else '')

for ea, res in db.select('export.func', 'synopsis'):
    n, _ = res['export.func']
    if n.upper() != 'JSVDA' or not func.name(ea).startswith('jsvda::'):
        continue
    commands = []
    commands.append("?poi(@{:s})".format(stackreg))
    commands.append(prototype(ea))
    commands.extend(preserveargs(ea))
    commands.append('.push /q /r')
    commands.append('gc')
    print("bu {:s}+{:x} \"{:s}\"".format(db.config.module(), db.offset(ea), application.windbg.escape(';'.join(commands), 1)))
    ec = []
    ec.append(".printf\"{:s} -> %x\\n\",@{:s}".format(func.name(ea), func.result.storage(ea).name))
    ec.append(".pop /q /r")
    ec.extend(dumpargs(ea))
    ec.append("gc")
    [print("bu {:s}+{:x} \"{:s}\"".format(db.config.module(), db.offset(ea), application.windbg.escape(';'.join(ec), 1))) for ea in func.bottom(ea)]