2013年10月20日 星期日

Disassemble u-boot.bin

This script not only disassemble u-boot.bin, but also regenerate a elf that could be used for GDB.

./disassemble.pl <offset> <binary_file>
./disassemble.pl 0xc0000000 u-boot.bin

GPL:disassemble.pl - CHDK Wiki
http://chdk.wikia.com/wiki/GPL:disassemble.pl#
#!/usr/bin/perl
 
# disassemble alien binary blobs
# look for "ldr .., [pc + #nn]" etc. 
# and add strings and values it refers to
#
# (c) 2008 chr
# GPL V3+
#
# v0.2.1:
# * create labels for branch targets
# v0.2:
# * catch unaligned strings
# * note on strings
# * check for integer overflow
 
# use Data::Dumper;
# $Data::Dumper::Sortkeys = 1;
 
# Added to support execution of disassembler.pl
# when not in the same folder as binary file to
# be disassembled.
use Cwd;
$firmware_basepath = getcwd;
 
# adjust these for your needs (note final slash):
#$path = "$ENV{'HOME'}/gcc-4.1-arm/bin/";
$path = "";
 
# note on "strings": default is a minimum length of 4 chars.
# So if u are hunting for e.g. "FI2" add -n3
# However, it gives a lot of false positive.
$strdump = "strings -t x";
$objdump = "${path}arm-elf-objdump";
$objcopy = "${path}arm-elf-objcopy";
 
if (@ARGV != 2) {
	die("Usage: $0 0x ");
}
 
$offset  = $ARGV[0];
$binfile = $ARGV[1];
$firmware_file_path = "$firmware_basepath/$ARGV[1]";
 
# check if we wrap over
die "error stat($firmware_file_path): $!" unless ($flen = (stat($firmware_file_path))[7]);
 
if ( hex($offset) + $flen - 1 > 0xffffffff) {
	die "offset + filesize - 1 > 0xffffffff. We can't wrap around!\n\ngame over"
}
 
#####
print "string dump\n";
my %strings;
open(IN, "$strdump \"$firmware_file_path\" |") or die "cannot start $strdump \"$firmware_file_path\": $!";
open(OUT,">$firmware_file_path.strings") or die "cannot write to $firmware_file_path.strings: $!";
while () {
	/^ *([[:xdigit:]]*) (.*)/;
	my $addr     = hex($1) + hex($offset);
	my $addr_str = sprintf("%08x", $addr);
	$strings{$addr_str} = $2;
 
	print OUT "$addr_str $2\n"; 
 
	# align string address so unaligned strings appears in disassemble
	$addr_str = sprintf("%08x", $addr & ~0x3);
	my $offs = $addr & 0x3;
	$strings{$addr_str} = '.' x $offs . $2;
 
}
close IN;
close OUT;
 
#$strings{'ff810164'} = "TEST test";
#$strings{'ff810420'} = "add test";
#print Dumper(\%strings);
#exit;
 
#####
print "create elf file\n";
 
`$objcopy --change-addresses=$offset -I binary -O elf32-littlearm -B arm \"$firmware_file_path\" \"$firmware_file_path.elf\"`;
`$objcopy --set-section-flags .data=code,load,alloc,content \"$firmware_file_path.elf\"`;
 
#####
print "label scan\n";
my %labels;
open(IN, "$objdump -d \"$firmware_file_path.elf\" |")
      or die "cannot start $objdump \"$firmware_file_path\": $!";
open(OUT,">$firmware_file_path.labels") or die "cannot write to $firmware_file_path.labels: $!";
 
while () {
        if (my ($addr, $dest) = $_ =~ /^ *([[:xdigit:]]+):[ \t]+[[:xdigit:]]+[ \t]+[Bb][[:alpha:]]*[ \t]+([[:xdigit:]]+)/) {
                if ($labels{$dest} lt 1) {
                        print OUT "$dest ($addr)\n";
                }
                $labels{$dest} += 1;
                print "\r0x$addr  ";
        }
}
close IN;
close OUT;
 
#####
print "\ndisassemble and string lookup\n";
 
open(IN, "$objdump -d \"$firmware_file_path.elf\" |")
      or die "cannot start $objdump \"$firmware_file_path\": $!";
open(OUT,">$firmware_file_path.dis") or die "cannot write to $firmware_file_path.dis: $!";
open(BIN, "<$firmware_file_path") or die "cannot read $firmware_file_path";
 
binmode BIN;
 
while () {
	if ($_ eq "	...\n") { print OUT $_; next;}
 
	my ($addr, $line) = $_ =~ /^ *([[:xdigit:]]*):(.*)/ or next;
 
	# ff810b98:	e51f2060 	ldr	r2, [pc, #-96]	; ff810b40 <_binary_dump_bin_start xb40="">
	# ff815dd4:	e28f10dc 	add	r1, pc, #220	; 0xdc
	if (
		($line =~ /^(.*\tldr.*\[pc, #([-\d]+).*; )/) ||
		($line =~ /^(.*\tadd.*pc, #([-\d]+).*; )/)
	) {
		$line = $1;
		my $off = hex($addr) - hex($offset) + $2 + 8;
		my $point = sprintf("%08x", hex($addr) + $2 + 8);
		my $value = &get_word($off);
		$line .= "$point: ($value) ";
		if (my $str = $strings{$point}) {
			# add pointed string
			$line .= qq| *"$str"|;
		}
		elsif (my $str = $strings{$value}) {
			# pointer to pointer ...
			$line .= qq| **"$str"|;
		}
	} 
	# ff815e1c:	e24f0090 	sub	r0, pc, #144	; 0x90
	elsif ($line =~ /^(.*\tsub.*pc, #([-\d]+).*; )/) {
		$line = $1;
		my $off = hex($addr) - hex($offset) - $2 + 8;
		my $point = sprintf("%08x", hex($addr) - $2 + 8);
		my $value = &get_word($off);
		$line .= "$point: ($value) ";
		if (my $str = $strings{$point}) {
			$line .= qq| *"$str"|;
		}
		elsif (my $str = $strings{$value}) {
			$line .= qq| **"$str"|;
		}
	}
        # ff81015c:       3afffffc        bcc     ff810154 <_binary__blah ...="">
        elsif ($line =~ /^([ \t]*[[:xdigit:]]+[ \t]+[Bb][[:alpha:]]*[ \t]+)([[:xdigit:]]+)/) {
                $line = "$1loc_$2"
        }
        # insert label
        if ($labels{$addr} gt 1) {
                print OUT "loc_$addr: ; $labels{$addr} refs\n";
        } elsif ($labels{$addr} gt 0) {
                print OUT "loc_$addr:\n";
        }
	# add string comment
	if (my $str = $strings{$addr}) {
		print OUT qq|"$str":\n|;
	}
	print OUT "$addr: $line\n"; 
	print "\r0x$addr  ";
}
close IN;
close OUT;
 
#####
print "\njob complete!\n";
 
sub get_word {
	my $off = shift;
	my $ret;
 
	seek(BIN, $off, 0);
	my $c = read(BIN, $ret, 4);# or die "off: $off $! ($ret)";
	return ($c > 0 ? sprintf("%08x", unpack("I", $ret)) : '???');
}


With the following changes:
diff --git a/disassemble.pl b/disassemble.pl
index fea0761..1a85518 100644
--- a/disassemble.pl
+++ b/disassemble.pl
@@ -27,12 +27,16 @@ $firmware_basepath = getcwd;
 #$path = "$ENV{'HOME'}/gcc-4.1-arm/bin/";
 $path = "";
  
+#$cross = "arm-elf-";
+$cross = "mips64-octeon-linux-gnu-";
 # note on "strings": default is a minimum length of 4 chars.
 # So if u are hunting for e.g. "FI2" add -n3
 # However, it gives a lot of false positive.
 $strdump = "strings -t x";
-$objdump = "${path}arm-elf-objdump";
-$objcopy = "${path}arm-elf-objcopy";
+$objdump = "${path}${cross}objdump";
+$objcopy = "${path}${cross}objcopy";
+#$objcopy_param = " -I binary -O elf32-littlearm -B arm ";
+$objcopy_param = "-I binary -O elf32-ntradbigmips -B mips:octeon2 ";
  
 if (@ARGV != 2) {
        die("Usage: $0 0x ");
@@ -79,7 +83,7 @@ close OUT;
 #####
 print "create elf file\n";
  
-`$objcopy --change-addresses=$offset -I binary -O elf32-littlearm -B arm \"$firmware_file_path\" \"$firmware_file_path.elf\"`;
+`$objcopy --change-addresses=$offset ${objcopy_param} \"$firmware_file_path\" \"$firmware_file_path.elf\"`;
 `$objcopy --set-section-flags .data=code,load,alloc,content \"$firmware_file_path.elf\"`;
  
 #####





Linux下如何反汇编arm raw binary文件 - ZhengKarl的专栏 - 博客频道 - CSDN.NET
http://blog.csdn.net/zhengkarl/article/details/5663042


GPL Disassembling - CHDK Wiki
http://chdk.wikia.com/wiki/GPL_Disassembling

linux下的arm反汇编-CPU与编译器-ChinaUnix.net
http://bbs.chinaunix.net/thread-1948607-1-1.html

The following works:
mips64-octeon-linux-gnu-objdump  u-boot.bin -b binary -D -m mips:octeon2 -M reg-names=n32,reg-names=octeon2 -EB | head

u-boot.bin:     file format binary


Disassembly of section .data:

0000000000000000 <.data>:
       0:    1000013f     b    0x500
       4:    00000000     nop
       8:    424f4f54     c0    0x4f4f54


Emulating Digicam with QEMU - page 4 - General Discussion and Assistance - CHDK Forum
http://chdk.setepontos.com/index.php/topic,1918.msg20065.html#msg20065
Emulating Digicam with QEMU - page 5 - General Discussion and Assistance - CHDK Forum
http://chdk.setepontos.com/index.php?topic=1918.msg28546#msg28546
disassemble_with_stubs_funcs-v1.0.zip 
http://chdk.setepontos.com/index.php?action=dlattach;topic=1918.0;attach=2786


沒有留言: