Le script python n'est pas très long, je vous le paste donc ici :

'''
objdump  --no-show-raw-insn -d -M intel > log
idagraph log rules
dot -Tsvg -Ln20 -LC2 -omain.svg *.dot
'''
 
import sys
import re 
 
def decorate(line): 
    color = ""
    font = ""
    for display_rule in display_rules :
      if display_rule[0].match(line) : color += " "+display_rule[1]
    for font_rule in font_rules :
      if font_rule[0].match(line) : font += " "+font_rule[1]
    return "<TR><TD "+color+">"+(font and ("<FONT %s >"%font) or "" )+line.replace("<","").replace(">","")+(font and "</FONT>" or "" )+"</TD></TR>"
 
rules = {"functions":[],"graphparam":[],"table_param":[],"font_rule":[],"display_rule":[],"label_font":[],"label_display":[]}
nodes = {}
labels = {}
currnode = 0
funregex = re.compile("(?P<address>[0-9a-f]+)[\t ]+<(?P<funname>[^>]+)>:")
jumpregex = re.compile(" (?P<address>[0-9a-f]+):[\t ]+(?P<jmptype>j[^ ]+)[\t ]+(?P<destadd>[0-9a-f]*)([\t ]+<(?P<destid>[^>]+)>)?")
disasregex = re.compile(" ?(?P<address>[0-9a-f]+):?[\t ]+(?P<disasm>.*)")
 
parseit = False
if len(sys.argv) < 2 :
  print "pyda.py objdumplog [rules]"
  sys.exit(0)
 
log = file(sys.argv[1], "rb")
print "parsing rules ..."
if len(sys.argv) > 2 :
  frules = file(sys.argv[2],"r")
  raw_rules = frules.readlines()
  for raw_rule in raw_rules :
    print [rule.strip() for rule in raw_rule.strip().split("\t",1)]
    type, rule = [rule.strip() for rule in raw_rule.strip().split("\t",1)]
    if not type in rules :
      raise Exception("invalid rule : %s"%raw_rule)
    else :
      rules[type].append(rule)
print "parsing rules : OK"
display_rules = []
print "parsing display rules ..."
for raw_display_rule in rules["display_rule"] :
  regex , display_rule = [rule.strip() for rule in raw_display_rule.split("\t",1)]
  try :
    display_rules.append((re.compile(regex), display_rule))
  except :
    raise Exception("invalid color rule : %s"%raw_display_rule)
print "parsing display rules : OK"
 
font_rules = []
print "parsing font rules ..."
for raw_font_rule in rules["font_rule"] :
  regex , font_rule = [rule.strip() for rule in raw_font_rule.split("\t",1)]
  try :
    font_rules.append((re.compile(regex), font_rule))
  except :
    raise Exception("invalid color rule : %s"%raw_font_rule)
print "parsing font rules : OK"
 
print "parsing log ..."
while (True):
  d = log.readline()
  if not d :
    break
  disas = disasregex.match(d)
  if not disas :
    continue
  f = funregex.match(d)
  if f :
    if not rules["functions"] :
      yn = None
      while not (yn in ["Y","N"]):
        print "include %s:%s in graph ? (y|n)"%(f.group("address"),f.group("funname"))
        yn = sys.stdin.readline().strip().upper()
      if yn == "Y" : parseit = True
      elif yn == "N" : parseit = False
    else : parseit = f.group("funname") in rules["functions"]
    print "parse %s:%s :"%(f.group("address"),f.group("funname")),f.group("funname") in rules["functions"]
    if parseit :
      currnode = f.group("address")
      nodes[currnode] = (f.group("funname"), [], [], {}, {})
      labels[f.group("address")] = "fun_"+f.group("funname").replace("<","").replace("<","").replace(" ","_")
    continue
  if not parseit :
    continue
  j = jumpregex.match(d)
  if j :
    nodes[currnode][3][j.group("address")] = (j.group("jmptype"),j.group("destadd"))
    nodes[currnode][4][(j.group("destadd"))] = None
    if j.group("destid") :
      labels[j.group("destadd")] = "loc_"+j.group("destid").replace("<","").replace("<","").replace(" ","_")
  nodes[currnode][1].append(disas.group("disasm"))
  nodes[currnode][2].append(disas.group("address"))
 
print "parsing log : OK"
 
for fun in nodes :
  filename = (nodes[fun][0] and nodes[fun][0] or fun) +".dot"
  print "generating %s ..."%filename
  try :
    fdot = file(filename, "w")
    fdot.write("digraph G {\n")
    for i in rules["graphparam"] :
      fdot.write(i+"\n")
    name, lines, addresses, jmps, destinations = nodes[fun]
    currname = "_"+fun
    blocks = {currname:[]}
    relations = []
    for i in xrange(len(lines)) :
      lines[i] = decorate(lines[i])
 
    i = 0
    while i < len(addresses) :
      if addresses[i] in jmps :
        blocks[currname].append(lines[i])
        jmptype, destaddr = jmps[addresses[i]]
        if i+1 < len(addresses) : nextname = "_"+addresses[i+1]
        else : nextname = None
        destname = "_"+destaddr
        relations.append((currname, destname, (jmptype == "jmp") and "blue" or "green", (jmptype == "jmp") and "s" or "se"))
        if nextname and jmptype != "jmp" : relations.append((currname, nextname, "red", "sw"))
        currname = nextname
        if currname : 
          blocks[currname] = [lines[i+1]]
          i+=1
      elif addresses[i] in destinations :
        if  i != 0 and not addresses[i-1] in jmps :
          relations.append((currname, "_"+addresses[i],"blue", "s"))
        currname = "_"+addresses[i]
        blocks[currname] = [lines[i]]
      else :
        blocks[currname].append(lines[i])
      i+=1
    for relation in relations :
      fdot.write(relation[0]+" -> "+relation[1]+" [color=%s, tailport=%s];\n"%(relation[2],relation[3]))
    for block in blocks :
      fdot.write(block+" [label=<<TABLE %s>%s</TABLE>>];\n"%(rules["table_param"] and rules["table_param"][0] or "", decorate(labels.get(block[1:],"loc_"+block[1:]).replace("<","").replace(">","")) + "".join(blocks[block])))
    fdot.write("}\n")
    fdot.close()
    print "generating %s : OK"%filename
  except :
    print "generating %s : FAIL"%filename

le script prend en paramètre la sortie de objdump ainsi qu'un fichier de règle optionnel (mais pas vraiment, la sortie sans ce fichier est dégueulasse)

Le fichier de règle est très simple et pour les différentes options qui sont utilisables, je vous conseille de vous référer au manuel graphviz, Grâce à cet aide ainsi qu'au fichier de règle d'exemple suivant (utilisé pour produire l'image plus bas) vous ne devriez pas avoir de mal à faire votre propre rendu. (atention les séparateurs doivent être des tabulations)

functions	main
graphparam	graph [splines=true];
graphparam	edge [color=blue, arrowsize=2];
graphparam	node [color=lightblue, style=filled, shape=box, fontname="Verdana"];
table_param	ALIGN="LEFT" BGCOLOR="lightblue" BORDER="0" CELLBORDER="0"
display_rule	call.*		BGCOLOR="blue" 
display_rule	jmp		BGCOLOR="yellow"
display_rule	j[^m]		BGCOLOR="yellow"
display_rule	.*		ALIGN="LEFT"
font_rule	j[^m]		COLOR="red"
font_rule	loc_		COLOR="darkblue" FACE="Georgia" POINT-SIZE="20"
font_rule	fun_		COLOR="darkblue" FACE="Georgia" POINT-SIZE="20"

Un exemple un peu plus complexe (le crackme en question) pour vous montrer ce qu'est capable de produire pyda (un peu prétentieux comme nom mais j'assume complètement) et graphviz.

Attention opera chie dans la colle avec ce svg, préférez firefox ...).

pyda 2

Bien sur ca n'atteint pas le niveau de IDA mais ca permet de dépanner les pauvres barbus sans le sous ;)