]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/bootstrap/server/src/unpack
update
[l4.git] / l4 / pkg / bootstrap / server / src / unpack
1 #! /usr/bin/perl -W
2 #
3 # by Adam Lackorzynski
4 #
5 # Simple attack at unpacking a bootstrap-image again. A smarter way would
6 # probably be if we'd add some clear marks in the image when generating
7 # it...
8 #
9 # Todo: prettification
10
11 use strict;
12
13 my @phdrs;
14 my $filename = shift;
15 die "Need to give filename!" unless defined $filename;
16
17 system("arm-linux-objcopy -j .data -O binary $filename unpack.data");
18 die "objcopy failed" if $?;
19
20 # make it easy, just hold the file parts in memory
21 my $unpackdata;
22 my $allfile;
23 open(A, "unpack.data") || die "Cannot open: $!";
24 {
25   local undef $/;
26   $unpackdata = <A>;
27 }
28 close A;
29
30 open(A, $filename) || die "Cannot open: $!";
31 {
32   local undef $/;
33   $allfile = <A>;
34 }
35 close A;
36
37 sub find_offset($)
38 {
39   my $vaddr = shift;
40   die "find_offset: EINVAL" unless defined $vaddr;
41
42   foreach my $p (@phdrs) {
43     if ($vaddr > @$p{vaddr} && @$p{vaddr} + @$p{memsize} >= $vaddr) {
44       return $vaddr - @$p{vaddr} + @$p{fileoff};
45     }
46   }
47   die "find_phdr unsuccessful";
48 }
49
50 sub get_string($)
51 {
52   unpack("Z*", substr($allfile, find_offset(shift)));
53 }
54
55 sub get_blob($$)
56 {
57   my $vaddr = shift;
58   my $len   = shift;
59   substr($allfile, find_offset($vaddr), $len);
60 }
61
62 # parse $filename PHDRs
63 {
64   my $o = `objdump -p $filename`;
65
66   foreach (split / LOAD /, $o) {
67     if (/off\s+0x([a-fA-F0-9]+)\s+vaddr\s+0x([a-fA-F0-9]+)\s+paddr\s+0x[a-fA-F0-9]+\s+align\s+\d\*\*\d+\s*.\s+filesz\s+0x([a-fA-F0-9]+)\s+memsz\s+0x([a-fA-F0-9]+)/m) {
68       print "PHDR: off=$1 vaddr=$2 fsz=$3 msz=$4\n";
69       push @phdrs, { fileoff => hex($1), vaddr => hex($2), filesize => hex($3), memsize => hex($4) };
70     }
71   }
72 }
73
74 my $filesize = -s "$filename";
75
76 my $offset = 0;
77 my %entries;
78 my $previous;
79 my $delta = 4;
80 my $modinfo_size = 24;
81 while ($offset < length($unpackdata) - 12 * 4) {
82   my ($start0, $size0, $sizeun0, $name0, $md5comp0, $md5uncomp0,
83       $start1, $size1, $sizeun1, $name1, $md5comp1, $md5uncomp1,
84       $start2, $size2, $sizeun2, $name2, $md5comp2, $md5uncomp2)
85    = unpack("LLLLLLLLLLLLLLLLLL", substr($unpackdata, $offset));
86
87   if ((!defined $previous || $previous + $modinfo_size == $offset)
88       && ($start0 > 0x5000)
89       && ($start1 > 0x5000)
90       && ($start2 > 0x5000)
91       && (($start0 & 0xfff) == 0)
92       && (($start1 & 0xfff) == 0)
93       && (($start2 & 0xfff) == 0)
94       && ($size0 < $filesize)
95       && ($size1 < $filesize)
96       && ($size2 < $filesize)
97       && ($sizeun0 < (80 << 20))
98       && ($sizeun1 < (80 << 20))
99       && ($sizeun2 < (80 << 20))) {
100
101     #printf "%x %x %x\n", $start0, $start1, $start2;
102     printf "Found module info at offset %d/0x%x\n", $offset, $offset;
103
104     $entries{$offset}{addr}                          = $start0;
105     $entries{$offset}{size}                          = $size0;
106     $entries{$offset}{usize}                         = $sizeun0;
107     $entries{$offset}{name}                          = $name0;
108     $entries{$offset}{md5comp}                       = $md5comp0;
109     $entries{$offset}{md5uncomp}                     = $md5uncomp0;
110     $entries{$offset + 1 * $modinfo_size}{addr}      = $start1;
111     $entries{$offset + 1 * $modinfo_size}{size}      = $size1;
112     $entries{$offset + 1 * $modinfo_size}{usize}     = $sizeun1;
113     $entries{$offset + 1 * $modinfo_size}{name}      = $name1;
114     $entries{$offset + 1 * $modinfo_size}{md5comp}   = $md5comp1;
115     $entries{$offset + 1 * $modinfo_size}{md5uncomp} = $md5uncomp1;
116     $entries{$offset + 2 * $modinfo_size}{addr}      = $start2;
117     $entries{$offset + 2 * $modinfo_size}{size}      = $size2;
118     $entries{$offset + 2 * $modinfo_size}{usize}     = $sizeun2;
119     $entries{$offset + 2 * $modinfo_size}{name}      = $name2;
120     $entries{$offset + 2 * $modinfo_size}{md5comp}   = $md5comp2;
121     $entries{$offset + 2 * $modinfo_size}{md5uncomp} = $md5uncomp2;
122
123     $previous = $offset;
124     $delta = $modinfo_size;
125   } else {
126     $delta = 4;
127   }
128   $offset += $delta;
129
130   print "Scanning at offset $offset\n" if $offset % 1000 == 0;
131 }
132
133 my $dir = "unpack.dir";
134 mkdir $dir;
135
136 open(MODLIST, ">$dir/modules.list")
137   || die "Cannot open $dir/unpack.modules.list: $!";
138 print MODLIST "entry unpacked\n";
139 print MODLIST "modaddr 0x01200000\n";
140
141 my $nr = 1;
142 open(M, ">md5sums") || die "Cannot create checksum file: $!";
143 foreach my $e (sort { $a <=> $b } keys %entries)
144 {
145   my $name = get_string($entries{$e}{name});
146   my $fname = "$dir/$name";
147   open(A, ">$fname") || die "Cannot create file $fname: $!";
148   print A get_blob($entries{$e}{addr}, $entries{$e}{size});
149   close A;
150
151   print M get_string($entries{$e}{md5uncomp})."  $fname\n";
152
153
154   system("file $fname");
155
156   # missing: cmdlines
157   if ($nr == 1) {
158     print MODLIST "kernel $name\n";
159   } elsif ($nr == 2) {
160     print MODLIST "sigma0 $name\n";
161   } elsif ($nr == 3) {
162     print MODLIST "roottask $name\n";
163   } else {
164     print MODLIST "module $name\n";
165   }
166
167
168   $nr++;
169 }
170 close M;
171 close MODLIST;
172
173 unlink "unpack.data";
174
175 system("md5sum -c md5sums");