📄 rdmsflsh.pl
字号:
$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 IMAGE_SCN_TYPE_NOLOAD { 0x00000002 }sub IMAGE_SCN_MEM_DISCARDABLE { 0x02000000 }sub IMAGE_SCN_MEM_EXECUTE { 0x20000000 }sub IMAGE_SCN_MEM_READ { 0x40000000 }sub IMAGE_SCN_MEM_WRITE { 0x80000000 }sub STD_EXTRA { 16 }sub IMAGE_FILE_MACHINE_ARM { 0x01c0 }sub FindFirstSegment { my ($segtypeflag, @o32rom)= @_; for (@o32rom) { if ($_->{flags} & $segtypeflag) { return $_->{rva}; } } return 0;}sub CalcSegmentSizeSum { my ($segtypeflag, @o32rom)= @_; my $size= 0; for (@o32rom) { # vsize is not entirely correct, I should use the uncompressed size, # but, I don't know that here yet. if ($_->{flags}&$segtypeflag) { $size += $_->{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 ($e32rom, @o32rom)= @_; my %e32exe; $e32exe{magic}= "PE"; $e32exe{cpu}= IMAGE_FILE_MACHINE_ARM; # todo: get this from romhdr. $e32exe{objcnt}= $e32rom->{objcnt}; $e32exe{timestamp}= $e32rom->{timestamp}; $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 # ...fixup segment does not look like a real fixup seg. # so we do include the data, but don't do anything with it. #$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 ($e32rom->{FIX_rva} == $o32rom->{rva} && $e32rom->{FIX_size} == $o32rom->{vsize}) { $segtype= ".reloc"; } 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}; if (($o32rom->{flags}&IMAGE_SCN_TYPE_NOLOAD)!=0 && $o32rom->{realaddr}==0) { # most likely fixup $o32obj{rva} = $o32rom->{rva}; } else { $o32obj{rva} = $o32rom->{realaddr} - $e32rom->{vbase}; } $o32obj{psize}= $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->{e32rom}, @{$perom->{o32rom}}); my $fileofs= $peexe{e32exe}{hdrsize}; for (@{$perom->{o32rom}}) { my $o32obj= convert_o32rom_to_o32obj($_, $perom->{e32rom}); push @{$peexe{o32obj}}, $o32obj; $o32obj->{dataptr}= $fileofs; $peexe{rvamap}{$_->{rva}}= { rva=>$o32obj->{rva}, size=>$o32obj->{vsize} }; $fileofs += round_to_page($o32obj->{psize}, $peexe{e32exe}{filealign}) } return \%peexe;}sub RvaToFileOfs { my ($rva, @o32obj)= @_; for (@o32obj) { if ($_->{rva}<=$rva && $rva < $_->{rva} + $_->{vsize}) { return $_->{dataptr}+$rva-$_->{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 ($rva, $rvamap)= @_; #$peexe{rvamap}{$_->{rva}}= { rva=>$o32obj->{rva}, size=>$o32obj->{vsize} }; for (keys %$rvamap) { my $info= $rvamap->{$_}; if ($_ <= $rva && $rva < $_+$info->{size}) { return $rva-$_+$info->{rva}; } } return $rva;}sub reconstruct_binary { my ($file)= @_; my $perom= parse_pe_data($file->{data}); my $peexe= convert_rom_to_exe($perom); 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 $i (0 .. $#{$file->{sections}}) { my $section = $file->{sections}[$i]; my $o32= $peexe->{o32obj}[$i] if ($i<@{$peexe->{o32obj}}); $image .= $section->{data};# if ($o32 && $o32->{name} eq ".reloc") {# printf("reloc %-20s %s %08lx-%08lx-%08lx (%04x): %s\n", # $file->{name},# $section->{name},# $o32->{rva}, $o32->{rva}+$o32->{psize}, $o32->{rva}+$o32->{vsize},# length($section->{data}), unpack("H*", $section->{data}));# } $image .= "\x00" x round_padding(length($section->{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;}# 0000: magic 0xFFFFF6FD# 0004: DWORD dwNextDataTableOffset;# 0008: DWORD dwNextStreamHeaderOffset;# 000c: FS_NAME fsName; : cchName + wFlags# 0010: : wszShortName[4]# 0014:# 0018: DWORD dwStreamSize;# 001c: FS_DATA_RUN dataTable[1];# 0020:# 0024:# 0028:# 002c:# 0030:sub process_sectionentry { my ($dirent, $file)= @_; my %section; my $magic; ( $magic, $section{unk}[0], # 0 always 0 : nextdatatable offset $section{next}, # 1 dirptr to next section entry $section{unk}[1], # 2 always 4 == name flags $section{name}, # 3,4 WCHAR[4] == sectionname $section{size}, # 5 total section size $section{indexblock}, # 6,7 dataptr,size ptr to index block of section data $section{indexsize}, @{$section{unk}}[2..5], # 8-b always 0 ) = unpack("VVVVa8VVVVVVV", $dirent); if ($magic != 0xfffff6fd && $magic != 0xfffffcfd) { croak sprintf("invalid magic %08lx in section entry for %s\n", $magic, $file->{name}); } $section{name} = unicode2string($section{name}); $section{name} =~ s/\x00+$//g; my $sdesc= sprintf("indexblock section %s for %s", $section{name}, $file->{name}); $section{data}= process_indexed_data($rd->ReadData($section{indexblock}, $section{indexsize}, $sdesc), $sdesc); #printf("file %s section %s: %s\n", $file->{name}, $section{name}, $section{data}); return \%section;}# magic: 0xfffffefe or 0xfffff6fe# 0000: magic# 0004: DWORD dwNextDataTableOffset;# 0008: DWORD dwNextStreamHeaderOffset;# 000c: FS_NAME fsName.cchName;# 000e: FS_NAME fsName.wFlags;# 0010: FS_NAME fsName.szShortName;# 0014: FS_NAME fsName.longName;# 0018: DWORD dwStreamSize;# 001c: DWORD dwFileAttributes;# 0020: _FILETIME fileTime;# 0028: DWORD dwReserved;# 002c: FS_DATA_RUN dataTable[1];# 0030:sub process_fileentry { my ($dirent, $desc)= @_; my $magic; my %file; ( $magic, $file{unk}[0], # 0 always 0 $file{firstsection}, # 1 dirptr to first section file $file{namelength}, # 2 WORD filename length : <=4 -> char[4]+ptr = literal filename. $file{nameflags}, # WORD flag: 2= filename ptr is direntry, 0= filenameptr is datablock $file{namehash}, # 3 char[4] $file{filenameptr}, # 4 ptr to filename file ( see flag for type ) $file{size}, # 5 total file length $file{attributes}, # 6 file attributes $file{timestamp}, # 7,8 timestamp $file{unk}[1], # 9 always 0 $file{indexblock}, # a,b dataptr,length to index block of file data $file{indexsize}, ) = unpack("VVVvva4VVVa8VVV", $dirent); $file{timestamp}= cvtime::convert2unixtime($file{timestamp}); if ($magic!=0xfffffefe && $magic!=0xfffff6fe) { croak sprintf("invalid magic: %08lx in fileent\n", $magic); } if ($file{nameflags}&2) { $file{name}= process_nameentry($rd->ReadData($file{filenameptr}, 4*13, "name entry $desc")); } elsif ($file{namelength}<=4) { $file{name}= unicode2string(substr($dirent, 16, 8)); $file{filenameptr}= 0; $file{namehash}= ""; } else { $file{name}= unicode2string($rd->ReadData($file{filenameptr}, $file{namelength}*2, "filenameblock $desc")); } $file{name} =~ s/\x00+$//g; if ($file{firstsection}) { $stats{modules}++; } else { $stats{files}++; } printf("%s: %s\n", $desc, $file{name}) if ($main::verbose); for (my $ofs= $file{firstsection} ; $ofs ; $ofs= $file{sections}[-1]{next}) { $stats{sections}++; push @{$file{sections}}, process_sectionentry($rd->ReadData($ofs, 4*13, sprintf("sectionentry %d for %s", scalar @{$file{sections}}, $file{name})), \%file); } if ($file{indexblock}) { my $fdesc= sprintf("indexblock filedata for %s", $file{name}); $stats{datablocks}++; $file{data}= process_indexed_data($rd->ReadData($file{indexblock}, $file{indexsize}, $fdesc), $fdesc); } else { printf("no index block %08lx %08lx for %s\n", $file{indexblock}, $file{indexsize}, $file{name}); } #printf("file %s: %s\n", $file{name}, $file{data}); return \%file;}sub process_indexed_data { my ($index, $desc)= @_; my $data= ""; for (my $iofs=0 ; $iofs<length($index) ; $iofs+=8) { $stats{datablocks}++; my ($compsize, $fullsize, $dataofs)= unpack("vvV", substr($index, $iofs, 8)); last if ($dataofs==0); my $block= $rd->ReadData($dataofs, $compsize, sprintf("datablock %d for %s", $iofs/8, $desc)); if (!defined $block) { printf("error reading data from %08lx l=%08lx : datablock %d for %s\n", $dataofs, $compsize, $iofs/8, $desc); } elsif ($fullsize==$compsize) { $data .= $block; $stats{uncompressed}++; } elsif ($imgfs_hdr->{compression} eq "XPR") { $stats{compressed}++; my $decomp= XdaDevelopers::CompressUtils::XPR_DecompressDecode($block.("\x00" x 16), $fullsize); if (!defined $decomp) { printf("no decomp !!!: %08lx->%08lx %s\n", $compsize, $fullsize, $desc); $data .= $block; } else { $data .= $decomp; } } elsif ($imgfs_hdr->{compression} eq "LZX") { $stats{compressed}++; my $decomp= XdaDevelopers::CompressUtils::LZX_DecompressDecode($block.("\x00" x 16), $fullsize); if (!defined $decomp) { printf("no decomp !!!: %08lx->%08lx %s\n", $compsize, $fullsize, $desc); $data .= $decomp; } else { $data .= $decomp; } } } return $data;}sub unicode2string { my ($data)= @_; return pack("U*", unpack("v*", $data));}# magic 0xfffffefbsub process_nameentry { my ($nameent)= @_; my ($magic, $name)= unpack("Va*", $nameent); if ($magic!=0xfffffefb) { croak "unexpected: no nameentry magic\n"; } return unicode2string($name);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -