# this script converts typical windbg prompt single-step output # to IDC colors/comments # # inspired from: # "MindshaRE: Hit Tracing in WinDbg" - Cody Pierce # here http://dvlabs.tippingpoint.com/blog/2008/07/17/mindshare-hit-tracing-in-windbg # # expects your windbg prompt to look like: # # 0:000> p # eax=28cad4fd ebx=7ffde000 ecx=0012ff7c edx=7c90e4f4 esi=0117f55c edi=7c911440 # eip=00429186 esp=0012ffc4 ebp=0012fff0 iopl=0 nv up ei pl nz na pe nc # cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 # image00400000+0x29186: # 00429186 6a60 push 60h use warnings; use strict; use FileHandle; # if the script encounters a comment-table address more than once, # it will append comments each time... this variable here limits # how many append will occur my $comment_limit = 8; # color of visited places # my $color = "0xC0C0C0"; # this tracks how many times each eip was encountered my %eip_visits; # returns an array of 5 strings: # [0]: eax=00000001 ebx=00255b78 ecx=0000003b edx=00000001 esi=00000000 edi=00000000 # [1]: eip=75c6ea5f esp=0157fec4 ebp=0157ff24 iopl=0 nv up ei pl zr na pe nc # [2]: cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 # [3]: jscript!DllCanUnloadNow+0x75fe: # [4]: 75c6ea5f 8bec mov ebp,esp sub GetNextStep() { my $state = 0; my @step = (); while() { next if(m/^\*\*\* /); if($state == 0) { if(m/^eax=/) { $step[0]=$_; $state = 1 } } elsif($state == 1) { if(m/^eip=/) { $step[1]=$_; $state = 2; } else { print "//error 1->2\n"; $state = 0; } } elsif($state == 2) { if(m/cs=[0-9A-Fa-f]+ /) { $step[2]=$_; $state = 3; } else { print "//error 2->3\n"; $state=0; } } elsif($state == 3) { if(m/^.*!.*:$/ || m/^.*\+.*:$/) { $step[3]=$_; $state = 4; } else { print "//error 3->4\n"; $state = 0; } } elsif($state == 4) { s/dword ptr //g; s/word ptr //g; s/byte ptr //g; # lines can be as small as: # 4000591a c3 ret if(m/^([0-9A-Fa-f]+) [0-9A-Fa-f]+ +[^ ]+/) { $step[4]=$_; $state=5; last; } else { print "//error 4->0\n"; $state = 0; } $state = 0; } } if($state==5) { return @step; } else { return (); } } sub GetExtra($) { my $ar = $_[0]; my $line = $ar->[4]; $line =~ s/dword ptr //g; $line =~ s/word ptr //g; $line =~ s/byte ptr //g; # eg: 6d9db535 83ea01 sub edx,1 # # eip bytes s opc s opr comment return $1 if($line =~ m/^[0-9A-Fa-f]+ [0-9A-Fa-f]+ +[^ ]+ +[^ ]+ *(.*)$/); return ''; } sub GetEip($) { my $ar = $_[0]; my $line = $ar->[4]; if($line =~ m/^([0-9A-Fa-f]+)/) { return $1; } else { return ''; } } sub GetOpcode($) { my $ar = $_[0]; my $line = $ar->[4]; if($line =~ m/^[0-9A-Fa-f]+ [0-9A-Fa-f]+ +([^ ]+)/) { return $1 } else { return ''; } } print "#include \n"; print "static main() {\n"; print "auto temp;\n"; # we stay one ahead, in case we need to look ahead (to find destination of ret, # for example) my @step0 = GetNextStep(); my @step1 = GetNextStep(); die("insufficient log data") if(!@step0 || !@step1); my $queue_full=1; while(1) { my $eip = GetEip(\@step0); die("wtf") unless($eip); my $xtra = GetExtra(\@step0); my $opcode = GetOpcode(\@step0); if(!exists($eip_visits{$eip})) { $eip_visits{$eip}=0; } if($eip_visits{$eip} <= $comment_limit) { print "SetColor(0x$eip,CIC_ITEM,$color);\n"; my $new_comment = ''; # if windbg has some extra info at the end of the current # line of disassembly, let's try to make some use of it if($xtra) { # for branches, just comment on the branch status if($xtra =~ m/(\[br=\d\])/) { $new_comment = $1; } elsif($xtra =~ m/[0-9a-fA-F]{8}=(.*)$/) { # if some value is being assigned, try to # make a string from it my $t = pack("H8", $1); my @chars = unpack("CCCC", $t); my $str; for(my $i=3; $i>=0; --$i) { if($chars[$i]>=ord(' ') && $chars[$i]<=ord('~')) { if($chars[$i]==ord('"')) { $str.="\\\""; } else { $str.=chr($chars[$i]); } } else { $str.='.'; } } $new_comment = $xtra." \\\"$str\\\""; # also remove selector stuff # before: ds:0023:0106c13c=007ffffa "...." # after: [0106c13c]=007ffffa "...." $new_comment =~ s/ds:....:(........)/[$1]/; } } # otherwise, under some conditions, we may try to add some # inf outselves else { if($opcode =~ m/^ret/) { if(@step1) { my $ret_destination = GetEip(\@step1); $new_comment = "return to: $ret_destination"; } else { $new_comment = "unknown return"; } } } # if any comments were made, produce the code if($new_comment) { # prepend pass number to comment $new_comment = $eip_visits{$eip}.": ".$new_comment; print "temp=CommentEx(0x$eip,0);\n"; print "temp=form(\"\%s\\n%s\",temp,\"$new_comment\");\n"; print "MakeComm(0x$eip,temp);\n"; } $eip_visits{$eip}++; } @step0 = @step1; @step1 = GetNextStep(); last unless(@step0); } print "}\n";