📄 dumpxip.pl
字号:
my %xip; ( $xip{pvAddr}, $xip{dwLength}, $xip{dwMaxLength}, $xip{usOrder}, $xip{usFlags}, $xip{dwVersion}, $xip{szName}, $xip{dwAlgoFlags}, $xip{dwKeyLen}, $xip{byPublicKey}, )= unpack("VVVvvVA32VVa*", $xipentry); return \%xip;}sub ParseXipChain { my $self= shift; my $xipchain= shift; if (keys %g_xipchaininfo) { printf("!!! found multiple xip-chains - appending\n"); } my $nrxips= unpack("V", $xipchain); for (my $i=0 ; $i<$nrxips ; $i++) { my $xip= ParseXipChainEntry(substr($xipchain, 4+0x290*$i, 0x290)); $self->vadd($xip->{pvAddr}, 0, sprintf("xip block %08lx-%08lx '%s'", $xip->{pvAddr}, $xip->{pvAddr}+$xip->{dwLength}, $xip->{szName})); if (exists $g_xipchaininfo{$xip->{pvAddr}}) { printf("!!! xipchain contains duplicate address: %08lx\n", $xip->{pvAddr}); } $g_xipchaininfo{$xip->{pvAddr}}= $xip; } if (substr($xipchain, 4+0x290*$nrxips) !~ /^\x00+$/) { printf("!!! xip chain padded with non-null\n"); }}sub print { my $self= shift; my $prev; for my $pofs (sort {$a<=>$b} keys %{$self->{items}}) { if ($prev && $pofs>$prev) { printf("%08lx-%08lx L%08lx unknown\n", $prev, $pofs, $pofs-$prev); } elsif ($prev && $pofs<$prev) { printf("%08lx-%08lx L%08lx overlap!!\n", $pofs, $prev, $prev-$pofs); } my $maxlen; for my $item (sort {$a->{len}<=>$b->{len}} @{$self->{items}{$pofs}}) { $maxlen= $item->{len} if (!defined $maxlen || $maxlen < $item->{len}); # ... not printing information from blanks. if ($item->{desc} eq "NUL" || $item->{desc} eq "ONE") { next; } if (exists $item->{vstart}) { printf("%08lx-%08lx | %08lx-%08lx L%08lx %s\n", $item->{pstart}, $item->{pstart}+$item->{len}, $item->{vstart}, $item->{vstart}+$item->{len}, $item->{len}, $item->{desc}); } else { printf("%08lx-%08lx L%08lx %s\n", $item->{pstart}, $item->{pstart}+$item->{len}, $item->{len}, $item->{desc}); } } $prev= $pofs+$maxlen; }}##########################################################################################################################################################package ExeFile;use strict;use Carp;sub new { my ($class, $cputype)= @_; return bless { cputype=>$cputype, }, $class;}sub addo32 { my ($self, $o32)= @_; push @{$self->{o32rom}}, $o32;}sub adde32 { my ($self, $e32)= @_; $self->{e32rom}= $e32;}sub save_data { my ($filename, $data)= @_; my $fh= IO::File->new($filename, "w") or die "$filename: $!\n"; binmode $fh; $fh->print($data); $fh->close();}sub SaveToFile { my ($self, $fn)= @_; my $exedata= $self->reconstruct_binary(); save_data($fn, $exedata);}sub pack_mz_header { return pack("H*", "4d5a90000300000004000000ffff0000"). pack("H*", "b8000000000000004000000000000000"). pack("H*", "00000000000000000000000000000000"). pack("H*", "00000000000000000000000080000000"). pack("H*", "0e1fba0e00b409cd21b8014ccd215468"). pack("H*", "69732070726f6772616d2063616e6e6f"). pack("H*", "742062652072756e20696e20444f5320"). pack("H*", "6d6f64652e0d0d0a2400000000000000");}sub pack_e32exe { my ($e32exe)= @_; my @info= qw(EXP IMP RES EXC SEC FIX DEB IMD MSP TLS CBK RS1 RS2 RS3 RS4 RS5); return pack("a4vvVVVvvvCCVV8v6V4v2V6", $e32exe->{magic}, $e32exe->{cpu}, $e32exe->{objcnt}, $e32exe->{timestamp}, $e32exe->{symtaboff}, $e32exe->{symcount}, $e32exe->{opthdrsize}, $e32exe->{imageflags}, $e32exe->{coffmagic}, $e32exe->{linkmajor}, $e32exe->{linkminor}, $e32exe->{codesize}, $e32exe->{initdsize}, $e32exe->{uninitdsize}, $e32exe->{entryrva}, $e32exe->{codebase}, $e32exe->{database}, $e32exe->{vbase}, $e32exe->{objalign}, $e32exe->{filealign}, $e32exe->{osmajor}, $e32exe->{osminor}, $e32exe->{usermajor}, $e32exe->{userminor}, $e32exe->{subsysmajor}, $e32exe->{subsysminor}, $e32exe->{res1}, $e32exe->{vsize}, $e32exe->{hdrsize}, $e32exe->{filechksum}, $e32exe->{subsys}, $e32exe->{dllflags}, $e32exe->{stackmax}, $e32exe->{stackinit}, $e32exe->{heapmax}, $e32exe->{heapinit}, $e32exe->{res2}, $e32exe->{hdrextra}, ). join("", map { pack("VV", $e32exe->{"${_}_rva"}||0, $e32exe->{"${_}_size"}||0) } @info);}sub pack_o32obj { my ($o32obj)= @_; return pack("a8V8", $o32obj->{name}, $o32obj->{vsize}, $o32obj->{rva}, $o32obj->{psize}, $o32obj->{dataptr}, $o32obj->{realaddr}, $o32obj->{access}, $o32obj->{temp3}, $o32obj->{flags});}sub IMAGE_FILE_RELOCS_STRIPPED { 1 };sub IMAGE_SCN_COMPRESSED { 0x00002000 }sub IMAGE_SCN_CNT_CODE { 0x00000020 }sub IMAGE_SCN_CNT_INITIALIZED_DATA { 0x00000040 }sub IMAGE_SCN_CNT_UNINITIALIZED_DATA { 0x00000080 }sub STD_EXTRA { 16 }sub IMAGE_FILE_MACHINE_ARM { 0x01c0 }sub FindFirstSegment { my ($segtypeflag, @o32rom)= @_; for my $o32ent (@o32rom) { if ($o32ent->{flags} & $segtypeflag) { return $o32ent->{rva}; } } return 0;}sub CalcSegmentSizeSum { my ($segtypeflag, @o32rom)= @_; my $size= 0; for my $o32ent (@o32rom) { # vsize is not entirely correct, I should use the uncompressed size, # but, I don't know that here yet. if ($o32ent->{flags}&$segtypeflag) { $size += $o32ent->{vsize}; } } return $size;}sub round_to_page { my ($val, $page)= @_; if ($val%$page) { return (int($val/$page)+1)*$page; } return $val;}sub round_padding { my ($val, $page)= @_; if ($val%$page) { return $page - ($val%$page); } return 0;}sub convert_e32rom_to_e32exe { my ($cputype, $e32rom, @o32rom)= @_; my %e32exe; $e32exe{magic}= "PE"; $e32exe{cpu}= $cputype; $e32exe{objcnt}= $e32rom->{objcnt}; $e32exe{timestamp}= $e32rom->{timestamp}||0; $e32exe{symtaboff}=0; $e32exe{symcount}=0; $e32exe{opthdrsize}= 0xe0; # fixed. $e32exe{imageflags}= $e32rom->{imageflags} | IMAGE_FILE_RELOCS_STRIPPED; $e32exe{coffmagic}= 0x10b; $e32exe{linkmajor}= 6; $e32exe{linkminor}= 1; $e32exe{codesize}= CalcSegmentSizeSum(IMAGE_SCN_CNT_CODE, @o32rom); $e32exe{initdsize}= CalcSegmentSizeSum(IMAGE_SCN_CNT_INITIALIZED_DATA, @o32rom); $e32exe{uninitdsize}= CalcSegmentSizeSum(IMAGE_SCN_CNT_UNINITIALIZED_DATA, @o32rom); $e32exe{entryrva}= $e32rom->{entryrva}; $e32exe{codebase}= FindFirstSegment(IMAGE_SCN_CNT_CODE, @o32rom); $e32exe{database}= FindFirstSegment(IMAGE_SCN_CNT_INITIALIZED_DATA, @o32rom); $e32exe{vbase}= $e32rom->{vbase}; $e32exe{objalign}= 0x1000; $e32exe{filealign}= 0x200; $e32exe{osmajor}= 4; $e32exe{osminor}= 0; $e32exe{usermajor}= 0; $e32exe{userminor}= 0; $e32exe{subsysmajor}= $e32rom->{subsysmajor}; $e32exe{subsysminor}= $e32rom->{subsysminor}; $e32exe{res1}= 0; # 'Win32 version' according to dumpbin $e32exe{vsize}= $e32rom->{vsize}; $e32exe{hdrsize}= round_to_page(0x80+0xf8+@o32rom*0x28, $e32exe{filealign}); $e32exe{filechksum}= 0; $e32exe{subsys}= $e32rom->{subsys}; $e32exe{dllflags}= 0; $e32exe{stackmax}= $e32rom->{stackmax}; $e32exe{stackinit}=0x1000; # ? $e32exe{heapmax}=0x100000; # ? $e32exe{heapinit}=0x1000; # ? $e32exe{res2}= 0; # 'loader flags' according to dumpbin $e32exe{hdrextra}= STD_EXTRA; # nr of directories $e32exe{EXP_rva}= $e32rom->{EXP_rva}; $e32exe{EXP_size}= $e32rom->{EXP_size}; $e32exe{IMP_rva}= $e32rom->{IMP_rva}; $e32exe{IMP_size}= $e32rom->{IMP_size}; $e32exe{RES_rva}= $e32rom->{RES_rva}; $e32exe{RES_size}= $e32rom->{RES_size}; $e32exe{EXC_rva}= $e32rom->{EXC_rva}; $e32exe{EXC_size}= $e32rom->{EXC_size}; $e32exe{SEC_rva}= $e32rom->{SEC_rva}; $e32exe{SEC_size}= $e32rom->{SEC_size}; # always 0 # relocation info is always missing # $e32exe{FIX_rva}= $e32rom->{FIX_rva}; $e32exe{FIX_size}= $e32rom->{FIX_size}; # $e32exe{DEB_rva}= $e32rom->{DEB_rva}; $e32exe{DEB_size}= $e32rom->{DEB_size}; $e32exe{IMD_rva}= $e32rom->{IMD_rva}; $e32exe{IMD_size}= $e32rom->{IMD_size}; # always 0 $e32exe{MSP_rva}= $e32rom->{MSP_rva}; $e32exe{MSP_size}= $e32rom->{MSP_size}; # always 0 $e32exe{RS4_rva}= $e32rom->{sect14rva}; $e32exe{RS4_size}= $e32rom->{sect14size}; return \%e32exe;}sub convert_o32rom_to_o32obj { my ($o32rom, $e32rom)= @_; my $segtype; if ($e32rom->{RES_rva} == $o32rom->{rva} && $e32rom->{RES_size} == $o32rom->{vsize}) { $segtype= ".rsrc"; } elsif ($e32rom->{EXC_rva} == $o32rom->{rva} && $e32rom->{EXC_size} == $o32rom->{vsize}) { $segtype= ".pdata"; } elsif ($o32rom->{flags}&IMAGE_SCN_CNT_CODE) { $segtype= ".text"; } elsif ($o32rom->{flags}&IMAGE_SCN_CNT_INITIALIZED_DATA) { $segtype= ".data"; } elsif ($o32rom->{flags}&IMAGE_SCN_CNT_UNINITIALIZED_DATA) { $segtype= ".pdata"; } else { $segtype= ".other"; } my %o32obj; # todo: add sequence nrs to identically named sections $o32obj{name} = $segtype; $o32obj{vsize}= $o32rom->{vsize}; $o32obj{rva} = $g_use_wince3_compression ? $o32rom->{rva} : (($o32rom->{realaddr}||$o32rom->{dataptr}) - $e32rom->{vbase}); $o32obj{psize}= $o32rom->{psize}; $o32obj{psize}= length($o32rom->{data}) if (length($o32rom->{data}) > $o32rom->{psize}); $o32obj{dataptr}= 0; # *** set at a later moment $o32obj{realaddr}= 0; # file pointer to relocation table $o32obj{access}= 0; # file pointer to line numbers $o32obj{temp3}= 0; # number of relocations + number of line numbers $o32obj{flags}= $o32rom->{flags} & ~IMAGE_SCN_COMPRESSED; return \%o32obj;}sub convert_rom_to_exe { my ($perom)= @_; my %peexe; $peexe{e32exe}= convert_e32rom_to_e32exe($perom->{cputype}, $perom->{e32rom}, @{$perom->{o32rom}}); my $fileofs= $peexe{e32exe}{hdrsize}; for my $o32ent (@{$perom->{o32rom}}) { my $o32obj= convert_o32rom_to_o32obj($o32ent, $perom->{e32rom}); push @{$peexe{o32obj}}, $o32obj; $o32obj->{dataptr}= $fileofs; $peexe{rvamap}{$o32ent->{rva}}= { rva=>$o32obj->{rva}, size=>$o32obj->{vsize} }; $fileofs += round_to_page($o32obj->{psize}, $peexe{e32exe}{filealign}) } return \%peexe;}sub RvaToFileOfs { my ($rva, @o32obj)= @_; for my $o32ent (@o32obj) { if ($o32ent->{rva}<=$rva && $rva < $o32ent->{rva} + $o32ent->{vsize}) { return $o32ent->{dataptr}+$rva-$o32ent->{rva}; } }}sub strread_dword { my ($pstr, $ofs)= @_; return unpack("V", substr($$pstr, $ofs, 4));}sub strwrite_dword { my ($pstr, $ofs, $dword)= @_; substr($$pstr, $ofs, 4)= pack("V", $dword);}# rvamap maps romrva's to objrva'ssub find_rva_patch { my ($objrva, $rvamap)= @_; #$peexe{rvamap}{$_->{rva}}= { rva=>$o32obj->{rva}, size=>$o32obj->{vsize} }; for my $romrva (keys %$rvamap) { my $info= $rvamap->{$romrva}; if ($romrva <= $objrva && $objrva < $romrva+$info->{size}) { return $objrva-$romrva+$info->{rva}; } } return $objrva;}sub reconstruct_binary { my ($file)= @_; my $peexe= $file->convert_rom_to_exe(); my $mz_data = pack_mz_header(); # $file->{sections}[$i]{data} contains the section data my $e32exe_data = pack_e32exe($peexe->{e32exe}); my @o32exe_data = map { pack_o32obj($_) } @{$peexe->{o32obj}}; my $image= $mz_data; $image .= $e32exe_data; $image .= $_ for (@o32exe_data); # page to filealign $image .= "\x00" x ($peexe->{e32exe}{hdrsize} - length($image)); for my $o32ent (@{$file->{o32rom}}) { $image .= $o32ent->{data}; $image .= "\x00" x round_padding(length($o32ent->{data}), $peexe->{e32exe}{filealign}); } # repair import table. my $impofs= RvaToFileOfs($peexe->{e32exe}{IMP_rva}, @{$peexe->{o32obj}}); while (1) { my $impaddr= strread_dword(\$image, $impofs+0x10); last if ($impaddr==0); my $newimpaddr = find_rva_patch($impaddr, $peexe->{rvamap}); strwrite_dword(\$image, $impofs+0x10, $newimpaddr); $impofs += 0x14; } return $image;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -