IDA Pro helper script for elf binarys
Benjamin Larsson <[email protected]> Tue, 08 Nov 2005 13:26:10 +0100
| Newsgroups | gmane.comp.video.xine.codec.devel |
|---|---|
| Message-ID | <[email protected]> |
Sometimes when you disassemble elf binarys with the freeware version of IDA pro the software is not able to properly propagate the GOT table (Global offset table) and thus failing to understand the meaning of calls. PIC code can have a placeholder with a hexvalue fffffffc (-4). This confuses IDA pro and fails to properly determine the start and stop of function and fails to do a good autoanalysis. Attached is a script that fills in real addresses in the placeholder so that IDA pro can find the real call functions. External functions don't have real addresses but IDA pro just adds them after the elf address space in the order they are found in the symbol tables, this is emulated in the script. This function might not work correctly depending which tables (sym or dsym) are availible in the binary. The script is run like this: perl gotpropagate.pl -f libwma3.so The output should look like this: [...] Patching offset 00046a40 with current address fcffffff to 73112 Patching offset 00046a78 with current address fcffffff to -7656 [...] And a libwma3.sobak file should be in the local directory with the same size as the original. The code is quite hackish but worked on the file I needed to use it on. MvH Benjamin Larsson
gotpropagate.pl
(text/plain, 5.4 KB)
#!/usr/bin/perl
# Init av variabler
#Argument parser
if (@ARGV){
print "@ARGV\n";
if ($ARGV[0] eq "-f"){
$FILE1 = $ARGV[1];
}
}
else{
print "Usage:\n";
print "./gotpropagate.pl [command] binary\n";
print "-f input datafile\n";
exit;
}
#get extern start address
@rows= `readelf -s libwma3.so | grep -i \"ABS _end\"`;
$externstartaddress = hex(substr $rows[0],8,8);
#print "$externstartaddress|\n";
# get SYMBOL TABLE
@fresource = `objdump -t $FILE1`;
$sym = 0;
@tabaddress = 0;
@tabname = 0;
@tablength = 0;
$tabindex = 1;
#parse out the tables
foreach $rad (@fresource) {
if ($sym){
$type = (substr $rad,17,5);
if ($rad =~ m/text/) {
#print $rad;
$address = (substr $rad,0,8);
#$address =~ m/0*/; #get rid of starting 0's
#$address = $';
$tablelength = (substr $rad,23,8);
$tablelength =~ m/0*/;
$tablelength = $';
$tablen = (substr $rad,32);
chomp($tablen);
$funcname = (substr $rad,45);
chomp($funcname);
#save the list
$tabaddress[$tabindex] = hex($address);
$tabname[$tabindex] = $tablen;
$tablength[$tabindex] = hex($tablelength);
$tabindex++;
$function{$funcname} = $address;
#print "$address $type $tablelength $funcname\n";
}
if ($type eq "*UND*"){
$address = $externstartaddress;
$externstartaddress = $externstartaddress+4;
$funcname = (substr $rad,45);
if ($funcname =~ m/@/){
$funcname = $`;
}
chomp($funcname);
$address = sprintf("%X", "$address");
$function{$funcname} = $address;
#print "$address $type $funcname\n";
}
}
if ($rad =~ m/SYMBOL/) {
$sym = 1;
}
}
# get DYNAMIC SYMBOL TABLE
@fresource = `objdump -T $FILE1`;
$dsym = 0;
@tabaddress = 0;
@tabname = 0;
@tablength = 0;
$tabindex = 1;
#parse out the tables
foreach $rad (@fresource) {
if ($dsym){
$type = (substr $rad,17,5);
if ($rad =~ m/text/) {
#print $rad;
$address = (substr $rad,0,8);
#$address =~ m/0*/; #get rid of starting 0's
#$address = $';
$tablelength = (substr $rad,23,8);
$tablelength =~ m/0*/;
$tablelength = $';
$tablen = (substr $rad,32);
chomp($tablen);
if ($rad =~ m/Base/) {
$funcname = (substr $rad,45);
} else {
$funcname = (substr $rad,32);
}
chomp($funcname);
#save the list
$tabaddress[$tabindex] = hex($address);
$tabname[$tabindex] = $tablen;
$tablength[$tabindex] = hex($tablelength);
$tabindex++;
$function{$funcname} = $address;
#print "$address $type $tablelength $funcname\n";
}
}
if ($rad =~ m/SYMBOL/) {
$dsym = 1;
}
}
# File IO
# get the GOT table from the elf so
open(RESFILE, ">fresource.txt") or die "File doesn't exist\n";
@fresource = `objdump -R $FILE1`;
$ii = 0;
foreach $rad (@fresource)
{
$address = (substr $rad,0,8);
$type = (substr $rad,9,10);
if ($type eq "R_386_PC32")
{
#print STDOUT "$rad";
$fname = (substr $rad,27);
chomp($fname);
#$address =~ m/0*/; #get rid of starting 0's
#$address = $';
#$address =~ tr/a-f/A-F/;
$seekpos[$ii] = $address;
$readdr[$ii] = $function{$fname};
$ii++;
$ofset = hex($function{$fname})- hex($address);
print RESFILE "$address $function{$fname} - $fname $ofset\n";
$functioncall{$address} = hex($function{$fname}) - hex($address)-4;
}
}
close RESFILE;
#Get .data offset
$doffset = 0;
@offsets = `readelf -S $FILE1`;
foreach $rad (@offsets) {
if ($rad=~ m/ \.text/) {
$dataaddress = (substr $rad,41,8);
$dataaddress =~ m/0*/;
$dataaddress = $';
$dataoffset = (substr $rad,50,6);
$dataoffset =~ m/0*/;
$dataoffset = $';
#print "$dataaddress $dataoffset|\n";
$doffset = hex($dataaddress) - hex($dataoffset);
}
}
#Calculate real address
$seekaddress = hex($seekpos[0]) - $doffset;
#print "$seekpos[16] $readdr[16]\n";
open(rf, $FILE1) or die "can't open $FILE1: $!";
binmode rf;
open(wf, ">$FILE1"."bak") or die "open $FILE1 $!";
binmode wf;
#sysseek(rf, $seekaddress, 0) or die "seek:$!";
#seek(BINFILE,hex(c61),0) or die "seek:$!";
#sysread(rf, $BUFFER, 4);
#@fields = unpack("H*",$BUFFER);
$oldpos =0;
foreach $key (sort keys %functioncall) {
if ($functioncall{$key} eq ""){
} else {
$pos = hex($key)-$oldpos; #-1;
sysread(rf, $buf, $pos);
syswrite(wf, $buf, length($buf));
sysread(rf, $BUFFER, 4);
$curvalue = unpack("H*",$BUFFER);
print "Patching offset $key with current address $curvalue to $functioncall{$key}\n";
$newjumpadr = pack("i*","$functioncall{$key}");
syswrite(wf, $newjumpadr, 4);
#@fields = unpack("H*",$newjumpadr);
#print "|$fields[0]|\n";
$oldpos = $oldpos+$pos+4;
}
}
while (sysread(rf, $buf, 1024)){
syswrite(wf, $buf, length($buf));
}
close rf;
close wf;
#$BUFFER = "DEADBEEF";
#$test = unpack("h*",pack("h*",$BUFFER));
#print $test;
print "Done!\n";