📄 rdmsflsh.pl
字号:
$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's
sub 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 0xfffffefb
sub 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 + -