#!/usr/bin/perl -w # # Created: Tue May 21 23:40:38 GMT 2002 # Updated: Wed May 22 16:30:39 CEST 2002 # # Copyright (C) 2002 # # TODO: - gérer le niveau de profondeur des fonctions # my $objdump = "/usr/bin/objdump -D"; my $binary = $ARGV[0]; my @disass; my %tab_function = (); my %tab_call = (); my $function = ""; my @not_this_fct = qw( _init _start Letext __do_global_dtors_aux fini_dummy frame_dummy init_dummy __stat __do_global_ctors_aux _fini _IO_stdin_used __data_start __EH_FRAME_BEGIN__ __CTOR_LIST__ __CTOR_END__ __DTOR_LIST__ _GLOBAL_OFFSET_TABLE_ _DYNAMIC __DTOR_END__ ); my %tmp_not_this_fct = (); my $tmp_fct = ""; my %fct_listed = (); my $i; my $grec; printf "drawgraph.pl - draw a pseudo-graph of functions\n"; printf "\n"; printf "--------------------------------------------\n\n"; if ( !defined($binary) ) { print "Usage: ./drawgraph.pl \n"; exit( -1 ); } print "[+] ELF binary : " . $binary . "\n"; open( OBJDUMP, "$objdump $binary |" ) || die "[-] Can't exec program: $!\n"; @disass = ; close( OBJDUMP ); foreach $tmp_fct ( @not_this_fct ) { $tmp_not_this_fct{$tmp_fct} = 1; } ### Récupération de la liste des fonctions ### for ( $i = 0; $i < @disass; $i++ ) { if ( $disass[$i] =~ /<\w+>:/ ) { my ( $address, $name_function ); ( $address, $name_function ) = split( " ", $disass[$i] ); $function = split_balise( $name_function ); unless ( $tmp_not_this_fct{$function} ) { $tab_function{$function} = $address; } } } ### Affichage du nombre de fonctions ### $i = 0; while ( ($function, $one) = each (%tab_function) ) { $i = $i + 1; } print "[*] $i functions\n\n"; ### Traitement de la fonction main ### %tab_call = list_call( "main", $tab_function{"main"} ); $fct_listed{"main"} = 1; print "+ main\n"; delete( $tab_function{"main"} ); $grec = 1; while ( ($call, $one) = each (%tab_call) ) { print " + $call\n"; recursive( $call, $grec ); } ### Affichage des fonctions appelées nulle part ailleurs ### $grec = 1; if ( %tab_function ) { my $address; print "\n\n"; print "[*] Other functions\n\n"; while ( ($function,$address) = each (%tab_function) ) { print "+ $function\n"; recursive( $function, $grec ); } } ####################################################################### sub recursive { my $call = $_[0]; my $rec = $_[1]; my $new_call = ""; my %new_tab_call = (); my $i; if ( $tab_function{$call} ) { $rec = $rec + 1; delete( $tab_function{$call} ); %new_tab_call = list_call( $call, $tab_function{$call} ); $fct_listed{$call} = 1; while ( ($new_call, $one) = each (%new_tab_call) ) { print " " x $rec; print "+ $new_call\n"; unless ( $fct_listed{$new_call} ) { recursive( $new_call, $rec ); } } } } ####################################################################### sub split_balise { my $balise = $_[0]; my ( $first, $two, $third, $four ) = ""; ( $first, $two ) = split( "<", $balise ); ( $third, $four ) = split( ">", $two ); return( $third ); } ####################################################################### sub list_call { my $function = $_[0]; my $address = $_[1]; my $call = ""; my %tab_call = (); for ( $i = 0; $i < @disass; $i++ ) { if ( $disass[$i] =~ /\<$function\>:/ ) { for ( $j = $i; $j < @disass; $j++ ) { if ( $disass[$j] =~ "call" ) { ### To fix() - Dirty code ### if ( $disass[$j] =~ /eax/ ) { next; } if ( $disass[$j] =~ /ebx/ ) { next; } if ( $disass[$j] =~ /ecx/ ) { next; } if ( $disass[$j] =~ /edx/ ) { next; } if ( $disass[$j] =~ /edi/ ) { next; } if ( $disass[$j] =~ /esi/ ) { next; } $call = split_balise( $disass[$j] ); if ( $call =~ /_init\+/ ) { next; } if ( $call =~ /_end\+/ ) { next; } unless ( $tab_call{$call} ) { $tab_call{$call} = 1; } } if ( $disass[$j] =~ /^\n/ ) { last; } } } } return( %tab_call ); } exit( 0 );