# you will want to change this:

#functions_of_interest=["KERNEL32.dll!CreateFileW", "KERNEL32.dll!WriteFile", "KERNEL32.dll!ReadFile", "KERNEL32.dll!MapViewOfFile"]
#functions_of_interest=["KERNEL32.dll!CreateFileW", "KERNEL32.dll!WriteFile", "KERNEL32.dll!ReadFile"]
#functions_of_interest=["WS2_32.dll!__imp_recvfrom","WS2_32.dll!__imp_sendto"]
functions_of_interest=["msvcrt.dll!rand", "msvcrt.dll!srand"]
GV_FNAME="c:\\tmp\\1.gv"

# (partially) copypasted from https://reverseengineering.stackexchange.com/questions/13627/ida-python-list-all-imported-functions
import idaapi
import networkx

def imp_cb(ea, name, ord):
    global names
    if name:
        names.append([name,ea])
    #print "imp_cb() name=", name
    return True

nimps = idaapi.get_import_module_qty()

def process_func1 (ea):
    funcs=set()
    t=get_first_cref_to(ea)
    while t!=BADADDR:
        funcs.add(idaapi.get_func_name(t))
        t=get_next_cref_to(ea, t)
    return list(funcs)

G=networkx.DiGraph()

print "** imports:"
# process imports
for i in xrange(0, nimps):
    global names
    name = idaapi.get_import_module_name(i)
    if not name:
        continue

    print "*** name", name
    names=[]
    idaapi.enum_import_names(i, imp_cb)
    for n in names:
        call_from=process_func1 (n[1])
        for c in call_from:
            print c, "->", name+".dll!"+n[0]
            G.add_edge(c,name+".dll!"+n[0])

# process all functions
def process_func2 (ea):
    funcs=set()
    t=get_first_cref_to(ea)
    while t!=BADADDR:
        funcs.add(idaapi.get_func_name(t))
        t=get_next_cref_to(ea, t)
    return list(funcs)

print "** functions:"
for ea in Segments():
    for funcea in Functions(SegStart(ea), SegEnd(ea)):
        call_from=process_func2(funcea)
        for c in call_from:
            if c==None:
                continue
            print c, "->", idaapi.get_func_name(funcea)
            #G.add_edge("\""+c+"\"", "\""+idaapi.get_func_name(funcea)+"\"")
            #print c
            #print idaapi.get_func_name(funcea)
            G.add_edge(c, idaapi.get_func_name(funcea))

def get_all_pairs_from_path(p):
    for i in range(len(p)-1):
        yield (p[i], p[i+1])

print "** paths:"
pairs=set()
# enumerate all paths:
for func in functions_of_interest:
    # source: A source, in a directed graph, is a vertex with no incoming edges (in-degree equals 0).
    # in-degree: The number of incoming edges in a directed graph; see degree.
    # ( https://en.wikipedia.org/wiki/Glossary_of_graph_theory_terms )
    for src in G.nodes():
        if G.in_degree(src)==0:
            for path in list(networkx.all_simple_paths(G, src, func)):
                print " -> ".join(path)
                for pair in get_all_pairs_from_path(path):
                    pairs.add(pair)

f=open(GV_FNAME, "w")

f.write ("digraph tst {\n")
f.write ("rankdir=\"LR\"\n");
for pair in pairs:
    f.write ("\""+pair[0]+"\" -> \""+pair[1]+"\";\n")
f.write ("}\n")
f.close()
