# ---- iso9660recover.pl - Win32 version # Written by bitshiftleft for perlmonks.org # Automate recovery of an entire data cdrom # using Kris Kaspersky's RAW_TOC_READ.exe and ISO9660.dir.exe utility. # Written for personal use and to answer the challenge on page 399 of the # book "CD Cracking Uncovered", ISBN:1-931769-33-8 # BUGS: 1)Some recovered files belong to to parent directory - might cross ref Joliet with iso9660 to verify # 2)Extra character on subdirectory names # ------- ----- use File::Path; my @TOC; my @TOCJoliet; my $NS =0; my %fileexists; open(RAW_TOC,"RAW_TOC_READ.exe \\\\.\\D: 0|") || die "RAW_TOC_READ.exe $!"; @TOC = ; close RAW_TOC; for ($i = 0; $i < 2; ++$i){ shift @TOC }; # trim header info print " ------ TOC ------\n"; print @TOC; foreach $session (@TOC){ last if $session eq "\n"; (undef, undef, $track,undef,$LBA1,$LBA2,$LBA3,$LBA4)=split(" ",$session); $StartLBA = hex($LBA1 .$LBA2 . $LBA3 .$LBA4); chomp $StartLBA; printf "Reading track %02X",hex($track); open(ISODIR,"ISO9660.dir.exe \\\\.\\D: $StartLBA -Joliet|") || die "ISO9660.dir.exe $StartLBA -Joliet \n$!"; my @filenames = ; for ($i = 0; $i < 6; ++$i){$l = shift @filenames; if ($l =~ /NOT/){ $NS = 1;} }; # trim header info push @TOCJoliet, \@filenames; close ISODIR; print " Dirs/Files found: ",scalar(@filenames),":$NS\n"; if($NS){$NS = 0;}; # print @filenames; # last if hex($track) == 3; for debugging this code } print "Retreiving files and directories....\n\n"; # ------- first reconstruct the directory tree --- foreach $index (0 .. $#TOCJoliet){ my @files = @{$TOCJoliet[$index]}; next if $#files == -1; foreach $ii (0 .. $#files){ ($lba1,$size1,$name1 ) = split(" ", $files[$ii]); $name1 = substr ($files[$ii],22); # in case there are spaces in the subdir name chomp $name1; if ($ii == 0){ ($lba2,$size2,$name2 ) = split(" ", $files[$ii+1]); $name2 = substr ($files[$ii+1],22); # in case there are spaces in the subdir name chomp $name2; if ($lba1 == $lba2 && $name1 eq '.' && $name2 eq '..'){$dirtree{$lba1} = 'root/'}; $activedir = $dirtree{$lba1}; if (! -d "$activedir"){mkpath($activedir,0,0777) ;} } next if ($name1 eq '.' or $name1 eq '..'); ($lba2,$size2,$name2 ) = split(" ", $files[$ii+1]); $name2 = substr ($files[$ii+1],22,); # in case there are spaces in the subdir name chomp $name2; if($name2 eq '.') { # ----- we have a subdirectory ($lba3,$size3,$name3 ) = split(" ", $files[$ii+2]); # get parent dir # ---- now remove filename special characters, - needed for wprintf bug ---- $name1 =~ s/(\=|\/|\[|\]|\"|\:|\;|\,|\?|\*|\<|\>|\|)$//g; $dirtree{$lba1} = $dirtree{$lba3} . $name1 . '/'; $activedir = $dirtree{$lba1}; if (! -d "$activedir"){ mkpath("$activedir",0,0777) ;} substr $files[$ii],22,0,$dirtree{$lba3} } else { # ----- we have a file substr $files[$ii],22,0,$activedir; # prepend full path $files[$ii] =~ s/\;.*$//; # trim the filename endings } } push @cddirtree, \@files; # print @files; } @TOCJoliet = (); # memory management - cleanup foreach $index (0 .. $#cddirtree){ # next unless $index > 0x26; my @files = @{$cddirtree[$index]}; foreach $ii (0 .. $#files){ ($lba1,$size1,$name1 ) = split(" ", $files[$ii]); ($lba2,$size2,$name2 ) = split(" ", $files[$ii+1]); next if $name2 eq '|.'; next if ($name1 eq '|.' or $name1 eq '|..'); $f = substr ($files[$ii],22); chomp $f; $size = substr($size1,1); if (! exists($filexists{$lba1})){ # no need to recover same file from previous session ++$filexists{$lba1}; print "Recovering: \"$f\" \n"; # might need line continuations here very for long command lines (xargs for windows?) system("ISO9660.dir.exe \\\\.\\D: \"$f\" $lba1 $size") && die "ISO9660.dir.exe: $!"; } } }