?? dumpxip.pl
字號:
#!perl -w# (C) 2003-2007 Willem Jan Hengeveld <itsme@xs4all.nl># Web: http://www.xs4all.nl/~itsme/# http://wiki.xda-developers.com/## $Id: dumpxip.pl 1766 2008-04-10 11:57:58Z itsme $## G:\archive\software\WINCE420/PUBLIC/COMMON/OAK/INC/pehdr.h# G:\archive\software\WINCE420/PUBLIC/COMMON/OAK/INC/romldr.h### .... i think the problem is that there are 2 xip section both at the same virtual address# ... see for instance decompress data of ceconfig.h# ... it returns the wrong data.use strict;$|=1;use Getopt::Long;use IO::File;use Carp;my $g_fileseek;my $g_doprint= 0;my $g_savedir;my $g_use_wince3_compression;my %seen_extensions;my %g_xipchaininfo;#use XdaDevelopers::CompressUtils;# this requires a patch to Win32::API, which can be found at# http://www.xs4all.nl/~itsme/projects/perl/Win32-API-0.41-wj2.tar.gz#use Win32::API;# CEDecompress is to be used for wince3.x roms# CEDecompressROM is to be used for wince4.x roms## problem is that this call sometimes crashes the app.# ##my $g_decompress= Win32::API->new("CECompress.dll", "CEDecompress", "PNPNNNN", "N", "_cdecl")#my $g_decompress= Win32::API->new("CECompress.dll", "CEDecompressROM", "PNPNNNN", "N", "_cdecl")# or warn "error importing CEDecompress: $!\n";GetOptions( "s=s"=> sub { $g_fileseek= eval($_[1]); }, "d:s"=> \$g_savedir, "3" => \$g_use_wince3_compression,) or die usage();sub usage { return <<__EOF__Usage: dumpxip.pl -o baseoffet [-l length] [-d savedir] [-s fileseek] romfile__EOF__}my $g_filename= shift or die usage();die "$g_filename not found\n" if (!-e $g_filename);my $g_data= ReadFile($g_filename, $g_fileseek);my $rom= ROM->new($g_data);my $mem= MemSpace->new();my $xipblocks= XipBlock::FindXipBlocks($rom);# [0x00000000, 0x10078000], [0x00100000, 0x80000000], [0x00900000, 0x82040000], [0x015c0000, 0x82d00000], [0x01640000, 0x82d80000], [0x01940000, 0x83080000] for my $xipblock ( @$xipblocks ) { $rom->setbase($xipblock->{ofs}, $xipblock->{base}); $mem->setvbase($xipblock->{ofs}, $xipblock->{base}); my $xip= XipBlock->new($rom, $mem, $xipblock->{base}); $xip->ParseXipBlock(); $xip->DumpInfo(); $xip->PrintFileList(); $xipblock->{parsedxip}= $xip;}$mem->pfillblanks($rom, 0, $rom->{size});$mem->print();if ($g_savedir) { my $xipindex= 1; for my $xipblock ( @$xipblocks ) { $rom->setbase($xipblock->{ofs}, $xipblock->{base}); $mem->setvbase($xipblock->{ofs}, $xipblock->{base}); my $xipname= exists $g_xipchaininfo{$xipblock->{base}} ? "xip_".$g_xipchaininfo{$xipblock->{base}}{szName} : sprintf("xip_%02d", $xipindex); $xipblock->{parsedxip}->SaveFiles($g_savedir, $xipname); $xipindex++; }}print "finished\n";exit(0);sub ReadFile { my $fn= shift; my $ofs= shift || 0; my $len= shift || (-s $fn)-$ofs; my $data; my $fh= IO::File->new($fn, "r") or die "$fn: $!"; binmode $fh; $fh->seek($ofs, SEEK_SET); $fh->read($data, $len); $fh->close(); return $data;}##########################################################################################################################################################package XipBlock;use POSIX;use strict;use Carp;use Dumpvalue;sub new { my $class= shift; my $rom= shift; my $mem= shift; my $start= shift; return bless { rom_type=>undef, xipstart=>$start, rom=>$rom, mem=>$mem }, $class;}sub ParseXipBlock { my $self= shift; my $rom= $self->{rom}; my $mem= $self->{mem}; if ($rom->GetDword($self->{xipstart}+0x40) != 0x43454345) { die "ECEC signature not found\n"; } my $romhdrofs= $rom->GetDword($self->{xipstart}+0x44); $mem->vadd($self->{xipstart}+0x40, 8, "ECEC signature + romhdr ptr"); my $romhdr= $self->{romhdr}= $self->ParseRomHdr($rom->GetVData($romhdrofs, 0x54)); $mem->vadd($romhdrofs, 0x54, $romhdr->{desc}); my $modlistofs= $romhdrofs+ 0x54; my $modules= $self->{modules}= $self->ParseModulesList($rom->GetVData($modlistofs, 0x20*$romhdr->{nummods})); $mem->vadd($modlistofs, 0x20*$romhdr->{nummods}, "modules list, %d modules", $romhdr->{nummods}); $_->{filename}= $rom->GetString($_->{lpszFileName}) for (@$modules); my $filesofs= $modlistofs + 0x20*$romhdr->{nummods}; my $files= $self->{files}= $self->ParseFilesList($rom->GetVData($filesofs, 0x1c*$romhdr->{numfiles})); $mem->vadd($filesofs, 0x1c*$romhdr->{numfiles}, "files list, %d files", $romhdr->{numfiles}); $_->{filename}= $rom->GetString($_->{lpszFileName}) for (@$files); if ($romhdr->{ulCopyEntries}) { $self->{copylist}= $self->ParseCopyList($rom->GetVData($romhdr->{ulCopyOffset}, 0x10*$romhdr->{ulCopyEntries})); $mem->vadd($romhdr->{ulCopyOffset}, 0x10*$romhdr->{ulCopyEntries}, "copy list, %d entries", $romhdr->{ulCopyEntries}); } else { $self->{copylist}= []; } $self->AddModuleHeaders($_) for (@{$modules}); $self->ParseExtensions($romhdr->{pExtensions});}sub ParseExtension { my $self= shift; my $data= shift; my @fields= unpack("A24V5", $data); my @names= qw(name type pdata length reserved pNextExt); my @fmt= qw(%s %08lx %08lx %08lx %08lx %08lx); return { desc=>sprintf("extension: %s", join ", ", map { sprintf("%s:$fmt[$_]", $names[$_], $fields[$_]) } (0..$#names)), map { ( $names[$_] => $fields[$_] ) } (0..$#names) };}sub isValidRomOfs { my ($ofs)= @_; return ($ofs>=0x80000000 && $ofs<0xa0000000);}sub ParseExtensions { my ($self, $extptr)= @_; my $first=1; while ($extptr) { last if (!$self->{rom}->IsInRange($extptr)); last if ($seen_extensions{$extptr}); $seen_extensions{$extptr}= 1; my $ext= $self->ParseExtension($self->{rom}->GetVData($extptr, 44)); last if ( ($ext->{pdata}!=0 && !isValidRomOfs($ext->{pdata})) ||($ext->{pNextExt}!=0 && !isValidRomOfs($ext->{pNextExt})) ||$ext->{length}>0x1000000); if (!$first) { $self->{mem}->vadd($extptr, 44, $ext->{desc}); $self->{mem}->vadd($ext->{pdata}, $ext->{length}, "data for extension %s: %s", $ext->{name}, join(",", map { sprintf("%08lx", $_); } unpack("V*", $self->{rom}->GetVData($ext->{pdata}, $ext->{length}))) ) if ($ext->{pdata}); } $first= 0; $extptr= $ext->{pNextExt}; }}sub SaveFiles { my $self= shift; my $savedir= shift; my $xipname= shift; if ($savedir) { mkdir $savedir; } $savedir .= "/$xipname"; if ($savedir) { mkdir $savedir; } die "$savedir does not exist\n" if (!-d $savedir); print "saving files to $savedir\n"; $self->SaveFile($_, $savedir) for (@{$self->{files}}); print "saving modules to $savedir\n"; $self->SaveModule($_, $savedir) for (@{$self->{modules}});}sub DumpInfo { my $self= shift; $self->DumpFilesAreas(); $self->DumpModulesAreas(); $self->{mem}->vfillblanks($self->{rom}, $self->{romhdr}{physfirst}, $self->{romhdr}{physlast}); #$self->{mem}->print();}sub filetimestring { my ($file)= @_; # 100 ns intervals since 1-1-1601 my $win32ftime= $file->{ftTime_high}*(2**32)+$file->{ftTime_low}; my $unixtime= int($win32ftime/10000000.0-11644473600); #return sprintf("%08lX%08lX", $file->{ftTime_high}, $file->{ftTime_low}); return POSIX::strftime("%Y-%m-%d %H:%M:%S", localtime $unixtime);}sub PrintFile { my ($self, $file)= @_; printf("@%08lx %6d %s %s\n", $file->{ulLoadOffset}, exists $file->{nRealFileSize}?$file->{nRealFileSize}:$file->{nFileSize}, filetimestring($file), $file->{filename});}sub PrintFileList { my ($self)= @_; $self->PrintFile($_) for (@{$self->{files}}); $self->PrintFile($_) for (@{$self->{modules}});}sub ParseRomHdr { my $self= shift; my $data= shift; my @fields= unpack("V17v2V3", $data); my @names= qw(dllfirst dlllast physfirst physlast nummods ulRAMStart ulRAMFree ulRAMEnd ulCopyEntries ulCopyOffset ulProfileLen ulProfileOffset numfiles ulKernelFlags ulFSRamPercent ulDrivglobStart ulDrivglobLen usCPUType usMiscFlags pExtensions ulTrackingStart ulTrackingLen); return { desc=>sprintf("romhdr : %s", join ", ", map { sprintf("%s:%08lx", $names[$_], $fields[$_]) } (0..$#names)), map { ( $names[$_] => $fields[$_] ) } (0..$#names) };}sub ParseModulesList { my $self= shift; my $data= shift; my @modules; my $i; for ($i= 0 ; $i<length($data) ; $i+=0x20) { push @modules, ParseModuleEntry(substr($data, $i, 0x20), sprintf("module entry %d", $i/0x20)); } if ($i!=length($data)) { warn "uneven modules list\n"; } return \@modules;}sub ParseModuleEntry { my $data= shift; my $desc= shift; my @fields= unpack("V8", $data); my @names= qw(dwFileAttributes ftTime_low ftTime_high nFileSize lpszFileName ulE32Offset ulO32Offset ulLoadOffset); return { desc=>sprintf("%s : %s", $desc, join ", ", map { sprintf("%s:%08lx", $names[$_], $fields[$_]) } (0..$#names)), map { ( $names[$_] => $fields[$_] ) } (0..$#names) };}sub ParseFilesList { my $self= shift; my $data= shift; my @files; my $i; for ($i= 0 ; $i<length($data) ; $i+=0x1c) { push @files, $self->ParseFilesEntry(substr($data, $i, 0x1c), sprintf("files entry %d", $i/0x1c)); } if ($i!=length($data)) { warn "uneven files list\n"; } return \@files;}sub ParseFilesEntry { my $self= shift; my $data= shift; my $desc= shift; my @fields= unpack("V7", $data); my @names= qw(dwFileAttributes ftTime_low ftTime_high nRealFileSize nCompFileSize lpszFileName ulLoadOffset); return { desc=>sprintf("%s : %s", $desc, join ", ", map { sprintf("%s:%08lx", $names[$_], $fields[$_]) } (0..$#names)), map { ( $names[$_] => $fields[$_] ) } (0..$#names) };}sub ParseCopyList { my $self= shift; my $data= shift; my @list; my $i; for ($i= 0 ; $i<length($data) ; $i+=0x10) { push @list, $self->ParseCopyEntry(substr($data, $i, 0x10), sprintf("copy entry %d", $i/0x10)); } if ($i!=length($data)) { warn "uneven copy list\n"; } return \@list;}sub ParseCopyEntry { my $self= shift; my $data= shift; my $desc= shift; my @fields= unpack("V4", $data); my @names= qw(ulSource ulDest ulCopyLen ulDestLen); return { desc=>sprintf("%s : %s", $desc, join ", ", map { sprintf("%s:%08lx", $names[$_], $fields[$_]) } (0..$#names)), map { ( $names[$_] => $fields[$_] ) } (0..$#names) };}sub AddModuleHeaders { my $self= shift; my $module= shift; my $rom= $self->{rom}; my $mem= $self->{mem}; if (!defined $self->{rom_type}) { $self->{rom_type}= determine_rom_type($rom->GetVData($module->{ulE32Offset}, 0x70)); } if ($self->{rom_type}==5) { $module->{e32}= ParseE32Header_v5($rom->GetVData($module->{ulE32Offset}, 0x6e)); $mem->vadd($module->{ulE32Offset}, 0x6e, "e32 header %s", $module->{filename}); } elsif ($self->{rom_type}==4) { $module->{e32}= ParseE32Header_v4($rom->GetVData($module->{ulE32Offset}, 0x6a)); $mem->vadd($module->{ulE32Offset}, 0x6a, "e32 header %s", $module->{filename}); } else { die "unknown romtype $self->{rom_type}\n"; } for my $objidx (1..$module->{e32}{objcnt}) { push @{$module->{o32}}, ParseO32Header($rom->GetVData($module->{ulO32Offset}+($objidx-1)*0x18, 0x18)); } $mem->vadd($module->{ulO32Offset}, 0x18*$module->{e32}{objcnt}, "o32 headers %s", $module->{filename});}sub determine_rom_type { my @f= unpack("V*", shift); if ($f[8] < $f[5] && $f[26]>0) { return 4; } else { return 5; }}# with extra timestamp field!sub ParseE32Header_v5 { my $data= shift; my @fields= unpack("v2V2v2V5V18v", $data); my @names= qw(objcnt imageflags entryrva vbase subsysmajor subsysminor stackmax vsize sect14rva sect14size timestamp EXP_rva EXP_size IMP_rva IMP_size RES_rva RES_size EXC_rva EXC_size SEC_rva SEC_size FIX_rva FIX_size DEB_rva DEB_size IMD_rva IMD_size MSP_rva MSP_size subsys); return { map { ( $names[$_] => $fields[$_] ) } (0..$#names) };}sub ParseE32Header_v4 { my $data= shift; my @fields= unpack("v2V2v2V4V18v", $data); my @names= qw(objcnt imageflags entryrva vbase subsysmajor subsysminor stackmax vsize sect14rva sect14size EXP_rva EXP_size IMP_rva IMP_size RES_rva RES_size EXC_rva EXC_size SEC_rva SEC_size FIX_rva FIX_size DEB_rva DEB_size IMD_rva IMD_size MSP_rva MSP_size subsys); return { map { ( $names[$_] => $fields[$_] ) } (0..$#names) };}sub ParseO32Header { my $data= shift; my @fields= unpack("V6", $data); my @names= qw(vsize rva psize dataptr realaddr flags); return { map { ( $names[$_] => $fields[$_] ) } (0..$#names) };}sub DumpFilesAreas { my $self= shift; for my $file (@{$self->{files}}) { my $desc= $file->{filename}; $self->{mem}->vadd($file->{ulLoadOffset}, $file->{nCompFileSize}, (($file->{dwFileAttributes}&0x800)?"compressed ":"")."file data %s", $desc); $self->{mem}->vadd($file->{lpszFileName}, length($file->{filename})+1, "file filename %s", $desc); }}sub DumpModulesAreas { my $self= shift; my $mem= $self->{mem}; for my $mod (@{$self->{modules}}) { my $desc= $mod->{filename}; $mem->vadd($mod->{lpszFileName}, length($mod->{filename})+1, "module filename %s", $desc); for my $o32ent (@{$mod->{o32}}) { my $l= $o32ent->{psize}; $l= $o32ent->{vsize} if ($o32ent->{vsize}<$l); $mem->vadd($o32ent->{dataptr}, $l,
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -