📄 dumpxip.pl
字号:
"v%07lx r%07lx %smodule data %s", $o32ent->{rva}, $o32ent->{realaddr}, ($o32ent->{flags}&0x2000)?"compressed ":"", $desc) if ($o32ent->{dataptr}); } }}sub GetUniqueFilename { my ($dir, $filename)= @_; my $fn= "$dir/$filename"; my $i= 1; while (-e $fn) { $fn= sprintf("%s/%s-%d", $dir, $filename, $i++); } return $fn;}sub GetUncompressedData { my ($rom, $ofs, $size, $fullsize, $compressed)= @_; return "" if ($size==0); my $data= $rom->GetVData($ofs, $size); if ($compressed) { if ($g_use_wince3_compression && $size==$fullsize) { # BUG in wince3 ... often compress flag is set, while data is not compressed. return $data; } #printf("decompress %08lx:%08lx %08lx -> %08lx : %s\n", $ofs, $size, length($data), $fullsize, unpack("H*", $data)); # .. append some extra data, so the (buggy) dll can read beyond the end of its input buffer.require XdaDevelopers::CompressUtils; my $decomp= $g_use_wince3_compression ? XdaDevelopers::CompressUtils::rom3uncompress($data.("\x00" x 16), $fullsize) : XdaDevelopers::CompressUtils::rom4uncompress($data.("\x00" x 16), $fullsize); if (!defined $decomp) { #printf(".. error\n"); return undef; } #printf(".. ok\n"); return $decomp; } return $data;}sub IMAGE_SCN_COMPRESSED { 0x2000; }sub FILE_ATTRIBUTE_COMPRESSED{ 0x0800; }sub SaveFile { my $self= shift; my $rom= $self->{rom}; my $file= shift; my $savedir= shift; my $data= GetUncompressedData($rom, $file->{ulLoadOffset}, $file->{nCompFileSize}, $file->{nRealFileSize}, $file->{dwFileAttributes}&FILE_ATTRIBUTE_COMPRESSED); if (!defined $data) { printf("ERROR decompressing file (%d -> %d) '%s'\n", $file->{nCompFileSize}, $file->{nRealFileSize}, $file->{filename}); return; } my $filename= GetUniqueFilename($savedir, $file->{filename}); my $fh= IO::File->new($filename, "w+") or die "$filename: $!\n"; binmode $fh; $fh->print($data); $fh->close();}sub SaveModule { my ($self, $module, $savedir)= @_; my $exe= ExeFile->new($self->{romhdr}{usCPUType}); for my $o32ent (@{$module->{o32}}) { my $size= $o32ent->{vsize}; $size= $o32ent->{psize} if ($size>$o32ent->{psize}); $o32ent->{data}= GetUncompressedData($rom, $o32ent->{dataptr}, $size, $o32ent->{vsize}, $o32ent->{flags} & IMAGE_SCN_COMPRESSED); if (!defined $o32ent->{data}) { printf("ERROR decompressing section %08lx-%08lx (%d -> %d) of '%s'\n", $o32ent->{dataptr}, $o32ent->{dataptr}+$size, $size, $o32ent->{vsize}, $module->{filename}); return; } $exe->addo32($o32ent); } $exe->adde32($module->{e32}); my $filename= GetUniqueFilename($savedir, $module->{filename}); $exe->SaveToFile($filename);}# ... these are class methods / static functions# finds the rom header, which points back to the specified start offset.sub FindRomHdr { my ($rom, $firstofs)= @_;# if ($have_xiputils) {# return XdaDevelopers::XipUtils::findromhdr($rom->{data}, $firstofs)# } my $hdrptr= $rom->GetPDword($firstofs+0x44); #printf("searching for header at ptr=%08lx from ofs=%08lx\n", $hdrptr, $firstofs+0x48); # search for romheader, starting directly after 'ECEC', until end of rom. for(my $hdrofs=$firstofs+0x48 ; $hdrofs < $rom->{size}-0x54 ; $hdrofs+=4) { my $firstptr= $rom->GetPDword($hdrofs+8); if ($hdrptr-$firstptr==$hdrofs-$firstofs) { #printf("found romheader at ptr:f=%08lx, h=%08lx | ofs:f=%08lx, h=%08lx\n", # $firstptr, $hdrptr, $firstofs, $hdrofs); return $hdrofs; } } return -1;}# finds the rom header, which points back to the specified start offset.# this is optimized by looking for the cpuidsub FindRomHdrByCpu { my $rom= shift; my $firstofs= shift; my $cpuid= pack("V",shift); my $hdrptr= $rom->GetPDword($firstofs+0x44); #printf("searching for cpuid in header at ptr=%08lx from ofs=%08lx\n", $hdrptr, $firstofs+0x48); # search for romheader, starting directly after 'ECEC', until end of rom. # ( 0x48 = ofs directly ofter romhdr-ptr, 0x44 is ofs of cpuid in romhdr ) my $ofs=$rom->find($cpuid, $firstofs+0x48+0x44); # 0x10 is size of rest of romhdr of cpuid. while ($ofs!=-1 && $ofs < $rom->{size}-0x10) { my $hdrofs= $ofs-0x44; my $firstptr= $rom->GetPDword($hdrofs+8); #print unpack("H*", $rom->GetPData($hdrofs, 0x50)), "\n"; #printf(" cpuid at %08lx ptr:f=%08lx, h=%08lx | ofs:f=%08lx, h=%08lx\n", # $ofs, $firstptr, $hdrptr, $firstofs, $hdrofs); if ($hdrptr-$firstptr==$hdrofs-$firstofs) { #printf("found romheader at ptr:f=%08lx, h=%08lx | ofs:f=%08lx, h=%08lx\n", # $firstptr, $hdrptr, $firstofs, $hdrofs); return $hdrofs; } $ofs=$rom->find($cpuid, $ofs+4); } return -1;}sub FindXipBlocks { my $rom= shift; my $cpuid; my @xiplist; my $ofs= 0; while ($ofs < $rom->{size}) { my $ececofs= $rom->find("ECEC", $ofs); last if ($ececofs==-1); my $firstofs= $ececofs-0x40; my $hdrptr= $rom->GetPDword($firstofs+0x44); my $hdrofs= $cpuid? FindRomHdrByCpu($rom, $firstofs, $cpuid) : FindRomHdr($rom, $firstofs); if ($hdrofs==-1) { $ofs= $ececofs+4; } else { my $firstptr= $rom->GetPDword($hdrofs+8); my $lastptr= $rom->GetPDword($hdrofs+12); $cpuid= $rom->GetPDword($hdrofs+68); my $lastofs= $lastptr-$hdrptr+$hdrofs; push @xiplist, { ofs=>$firstofs, len=>$lastptr-$firstptr, base=>$firstptr }; $ofs= $lastofs+0x40; } } #printf("found %d xip blocks\n", scalar @xiplist); return \@xiplist;}##########################################################################################################################################################package ROM;use strict;use Carp;sub new { my $class= shift; my $data= shift; my $base= shift; return bless { data=>$data, size=>length($data) }, $class;}sub setbase { my ($self, $dataofs, $base)= @_; $self->{base}= $base- $dataofs;}sub IsInRange { my ($self, $ofs)= @_; return $ofs-$self->{base}>=0 && $ofs-$self->{base}<$self->{size};}sub find { my ($self, $str, $ofs)= @_; return index($self->{data}, $str, $ofs);}sub GetDword { my ($self, $ofs)= @_; return unpack("V", $self->GetVData($ofs, 4));}# get data by virtual offsetsub GetVData { my ($self, $ofs, $len)= @_; if ($ofs-$self->{base}<0 || $ofs-$self->{base}+$len > length($self->{data})) { croak sprintf("%08lx l=%08lx beyond size : base=%08lx l=%08lx\n", $ofs, $len, $self->{base}, length($self->{data})); } return substr($self->{data}, $ofs-$self->{base}, $len)}# get data by physical offsetsub GetPData { my ($self, $ofs, $len)= @_; return substr($self->{data}, $ofs, $len)}# get dword by physical offsetsub GetPDword { my ($self, $ofs)= @_; return unpack("V", $self->GetPData($ofs, 4));}sub GetString { my ($self, $ofs)= @_; if ($ofs==0) { return "((null))"; } my $nulpos= $self->{base}+index($self->{data}, "\x00", $ofs-$self->{base}); return $self->GetVData($ofs, $nulpos-$ofs);}##########################################################################################################################################################package MemSpace;use strict;use Carp;sub new { return bless {}, shift;}sub setvbase { my ($self, $physical, $virtual)= @_; $self->{base}= $virtual - $physical; # virtualaddr = physical + base}# add region by virtual address.sub vadd { my ($self, $vstart, $len, $fmt, @args)= @_; if ($vstart==0) { carp "vadd: v=NULL\n"; return; } my $paddr= $vstart-$self->{base}; push @{$self->{items}{$paddr}}, { pstart=>$paddr, vstart=>$vstart, len=>$len, desc=>sprintf($fmt, @args) };}# fill blanks in virtual region.sub vfillblanks { my ($self, $rom, $first, $last)= @_; my $vprev; for my $pofs (sort {$a<=>$b} keys %{$self->{items}}) { my $vofs= $pofs+$self->{base}; next if ($vofs<$first); last if ($vofs>$last); #printf("adding unknown first=%08lx last=%08lx vofs=%08lx vprev=%08lx pofs=%08lx\n", $first, $last, $vofs, $vprev, $pofs); $self->vadd_unknown($rom, $first, $vofs-$first) if (!$vprev && $vofs>$first); $self->vadd_unknown($rom, $vprev, $vofs-$vprev) if ($vprev && $vofs>$vprev); my $maxlen; for my $item (sort {$a->{len}<=>$b->{len}} @{$self->{items}{$pofs}}) { $maxlen= $item->{len} if (!defined $maxlen || $maxlen < $item->{len}); } $vprev= $vofs+$maxlen; } #printf("adding last unknown first=%08lx last=%08lx vprev=%08lx\n", $first, $last, $vprev); $self->vadd_unknown($rom, $vprev, $last-$vprev) if ($vprev && $last > $vprev);}sub vadd_unknown { my ($self, $rom, $start, $len)= @_; my $data= $rom->GetVData($start, $len); my $desc; if ($data =~ /^\x00+$/) { $desc= "NUL"; } elsif ($data =~ /^\xff+$/) { $desc= "ONE"; } elsif ($data =~ /^...\xea\x00+$/) { my $target=unpack("V", $data); $desc= sprintf("kernel entry point : branch to %08lx", $start+4*($target&0xffffff)+8); } else { if (length($data)>64) { $desc= "unknown-large: ".unpack("H*", substr($data, 0, 64)); } else { $desc= "unknown: ".unpack("H*", $data); } } #printf("... unknown %08lx-%08lx L%08lx\n", $start, $start+$len, $len); $self->vadd($start, $len, $desc);}# functions dealing with physical offsets.sub padd { my ($self, $pstart, $len, $fmt, @args)= @_; push @{$self->{items}{$pstart}}, { pstart=>$pstart, len=>$len, desc=>sprintf($fmt, @args) };}# fill blanks in physical region.sub pfillblanks { my ($self, $rom, $first, $last)= @_; my $pprev; for my $pofs (sort {$a<=>$b} keys %{$self->{items}}) { next if ($pofs<$first); last if ($pofs>$last); $self->padd_unknown($rom, $first, $pofs-$first) if (!$pprev && $pofs>$first); $self->padd_unknown($rom, $pprev, $pofs-$pprev) if ($pprev && $pofs>$pprev); my $maxlen; for my $item (sort {$a->{len}<=>$b->{len}} @{$self->{items}{$pofs}}) { $maxlen= $item->{len} if (!defined $maxlen || $maxlen < $item->{len}); } $pprev= $pofs+$maxlen; } $self->padd_unknown($rom, $pprev, $last-$pprev) if ($pprev && $last > $pprev);}# add unknown region by physical addresssub padd_unknown { my ($self, $rom, $start, $len)= @_; my $data= $rom->GetPData($start, $len); my $desc; if ($data =~ /^(\x00*)(\xff*)$/) { my $l_nul= length($1); my $l_one= length($2); #printf("adding NULONE section: %08lx l %08lx\n", $start, $len); ### $self->padd($start, $l_nul, "NUL") if ($l_nul); $self->padd($start+$l_nul, $l_one, "ONE") if ($l_one); } else { my $bofs= 0; pos($data)= $bofs; if ($data =~ /\G\x00+/) { if (length($&)>16) { $self->padd($start+$bofs, length($&), "NUL"); $bofs += length($&); } } pos($data)= $bofs; if ($data =~ /\G\xff+/) { if (length($&)>16) { #printf("adding ONE section: %08lx l %08lx : %08lx l %08lx\n", $start, $len, $start+$bofs, length($&)); ### $self->padd($start+$bofs, length($&), "ONE"); $bofs += length($&); } } my $eofs= length($data); if ($eofs < 0x1000) {# !!! this regex takes a very long time for large data.# .. and the remainder unknown is not calculated correctly pos($data)= $eofs; if ($data =~ /\xff+\G/) { if (length($&)>16) { $eofs -= length($&); if ($eofs>$bofs) { $self->padd($start+$eofs, length($&), "ONE"); } } } pos($data)= $eofs; if ($data =~ /\x00+\G/) { if (length($&)>16) { $eofs -= length($&); if ($eofs>$bofs) { $self->padd($start+$eofs, length($&), "NUL"); } } } } #printf("punknown: start=%08lx len=%08lx eofs=%08lx bofs=%08lx\n", $start, $len, $eofs, $bofs);# removed this restriction: $len-$bofs==0x2000 && if (substr($data, $bofs+0x48, 4) eq "RSA1") { $desc= "xip-chain"; $self->ParseXipChain(substr($data, $bofs, $eofs-$bofs)); } elsif ($eofs-$bofs>64) { $desc= "unknown-large: ".unpack("H*", substr($data, $bofs, 64)); } else { $desc= "unknown: ".unpack("H*", substr($data, $bofs, $eofs-$bofs)); } $self->padd($start+$bofs, $eofs-$bofs, $desc) if ($eofs>$bofs); }}sub ParseXipChainEntry { my $xipentry= shift;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -