This change to dls allows the option '-n' which numbers blocks as they come out.
It allows utilities that filter the blocks to spit out block numbers without having to run dcalc on (sometimes) thousands of block numbers. I'm also including the perl script bgrep3 which uses the output of the -n option to find blocks that are probable candidates for indirect inodes -- It only works for partitions < 64GB, but is easily modifiable for larger partitions (to a point). and the script idtest which tries to sort out double and triple indirect inodes.
--- sleuthkit-2.03.orig/src/fstools/dls_lib.c +++ sleuthkit-2.03/src/fstools/dls_lib.c @@ -29,6 +29,7 @@ */ #include "libfstools.h" +int blog=1; @@ -90,6 +91,14 @@ { if (verbose) fprintf(stderr, "write block %" PRIuDADDR "\n", addr); + if(blog){ + int blen=fs->block_size + sizeof(blen) + sizeof(addr); + if( fwrite(&blen,sizeof(blen),1,stdout) != 1 || + fwrite(&addr,sizeof(addr),1,stdout) != 1){ + error("dls_lib: error writing data to stdout: %m"); + return WALK_STOP ; + } + }; if (fwrite(buf, fs->block_size, 1, stdout) != 1) error("write stdout: %m"); --- sleuthkit-2.03.orig/src/fstools/dls.c +++ sleuthkit-2.03/src/fstools/dls.c @@ -1,7 +1,7 @@ /* ** The Sleuth Kit ** -** $Date: 2006/10/01 18:09:50 $ +** $Date: 2005/09/02 19:53:27 $ ** ** Brian Carrier [EMAIL PROTECTED] ** Copyright (c) 2003-2005 Brian Carrier. All rights reserved @@ -29,6 +29,8 @@ */ #include "libfstools.h" +extern int blog; + /* atoblock - convert string to block number */ @@ -66,6 +68,8 @@ fprintf(stderr, "\t-s: print slack space only (other flags are ignored\n"); fprintf(stderr, "\t-v: verbose to stderr\n"); + fprintf(stderr, "\t-n: Number the block (binary)\n"); + fprintf(stderr, "\t-V: print version\n"); fprintf(stderr, "\t-f fstype: File system type\n"); fprintf(stderr, "Supported file system types:\n"); @@ -100,7 +104,7 @@ progname = argv[0]; setlocale(LC_ALL, ""); - while ((ch = getopt(argc, argv, "bef:i:lo:svV")) > 0) { + while ((ch = getopt(argc, argv, "bef:i:lo:snvV")) > 0) { switch (ch) { case '?': default: @@ -128,6 +132,10 @@ case 's': lclflags |= DLS_SLACK; break; + case 'n': + blog=1; + break; + case 'v': verbose++; break;
#!/usr/bin/perl # reads in blocks presuming my changes to dls that prepend # a length and block number (in binary) to every block. # this allows a very fast printing of raw block numbers of interest. # by default, look for possible indirect inode blocks: # This pattern looks for indirect inode blocks in a 'small' partition # (less then 64GiB). # if you have a partition > 64Gib, then you will have to allow # the high order byte to be 0...(floor(size/64GiB) # # This also presumes the file to be non-sparse, so a block number # of zero should be end of data, and the rest of the block should # be zeroes. # also checks for replicated 'block numbers' as an indication that # this really isn't an indirect block; $pattern= '^(?:(?!\0\0\0\0)...\0)+(?:\0\0\0\0)*$'; $quiet=0; $verbose=0; if ($ARGV[0] =~ '-q'){ shift @ARGV;; printf "quiet...\n"; $quiet=1; }elsif ($ARGV[0] =~ '-v'){ shift @ARGV;; printf "quiet...\n"; $verbose=1; }; if( $ARGV[0] ){ $pattern=$argv[0]; } $intlen=4; $blocksize=4096; $blockcount=0; printf "pattern=($pattern)\n" if $verbose; shift ; $lastbad=''; $rc=0; $hit=0; print ""; $|=1; sub nextblock{ my($gotten1,$thissize,$lendata,$metasize,$gotten2,$bnumstr,@bnums); # print "nextblock\n"; $gotten1=read(STDIN,$lendata,$intlen); unless( $gotten1){ return(0)}; $thissize= (unpack("i",$lendata))[0]; # printf "thissize=%d intlen=%d\n",$thissize,$intlen; $metasize=$thissize%32; # printf "metasize= %d\n", $metasize; # printf "reading more: %d\n", $metasize-$intlen; $gotten2=read(STDIN,$bnumstr,$metasize-$intlen); return(0) unless $gotten1; @bnums=unpack("I*",$bnumstr); # presumes little-endian word ordering if(defined($bnums[1])){ $blockno=$bnums[1] * 4294967296 + $bnums[0] ;}; $rn = read(STDIN,$block,$thissize-$metasize); # print "rn=$rn\n"; return $rn; } while ( $gotten=nextblock() ){ printf "got%d\n",$gotten if $verbose; if($lastbad){ print STDERR $lastbad unless $quiet; $lastbad='';}; # print( ".") unless $quiet; if ($gotten != $blocksize ) { $lastbad= sprintf "bad read len (%d) for block %d\n",$gotten,$blockno; } if( @match=($block =~ /$pattern/s ) ) { my (%used, @blocks); %used=(); @blocks=unpack("V*",$block); $bad=0; printf( "(%s)",join(")(",@blocks)) if $verbose; foreach $b (@blocks){ # printf "(%s)",$b; if($b && ! defined($used{$b}) ){ $used{$b}=1; }elsif($b){ printf ("BadHit at block %d -- %d\n",$blockno,$blockcount) unless $quiet; $bad=1; last; }else{ last }; } if(!$bad){ printf "Hit at block %d -- %d ",$blockno,$blockcount unless $quiet; # printf "<%s> <%s>\n",$match[0],$match[1] unless $quiet; printf "(%s)\n",join(") (",@match ) unless $quiet; $hit=1; }; }; $blockcount++; }; print "\n" unless $quiet; if($hit){ printf "Had hit returning $rc\n"; exit $rc; }else{ printf "Had no hit\n"; exit 1 };
#!/usr/bin/perl $dev="/dev/hda8"; $list="/tmp/idl"; $bsize=4096; open IDL,"<$list" or die "couldn't open $list"; open DEV,$dev or die "couldn't open $dev"; # read the list of indirct candidates while(<IDL>){ chomp; $inlist{$_}=1; }; # checks a block to see if it is a complete double indirect # it is a complet double if every block it points to is unallocated and indirect sub isind{ my ($blockno)[EMAIL PROTECTED]; my ($n)= 0; seek DEV,$blockno*$bsize,0 or die "seek failed for block $$blockno"; read( DEV,$block,$bsize) or die "read failed for block $$blockno"; @inums= unpack("l*",$block); $bad=0; foreach $p (@inums){ if($p){ if(! exists $inlist{$p}){ return(0); }; }else{ $partial{$blockno}=1; return($n+0); }; $n++; }; return($n+0) }; # mark all the double indirects foreach $bnum ( keys %inlist ){ if($count=isind($bnum)){ $double{$bnum}=$count; }; }; # checks a double indrect to see if it is actually a complete triple sub isind2{ my($bnum)[EMAIL PROTECTED]; my($n)=0; seek DEV,$bnum*$bsize,0 or die "seek failed for block $$blockno"; read( DEV,$block,$bsize) or die "read failed for block $$blockno"; @inums= unpack("l*",$block); $bad=0; foreach $p (@inums){ if($p){ if(! exists $double{$p}){ return 0 ; }; }else{ return($n+0); }; $n++; }; return($n+0); }; if(1){ # check each doubles to see if they are actually triples foreach $bnum ( keys %double ){ if($count=isind2($bnum)){ $triple{$bnum}=$count; }; }; } open TRIPLES,">Triples" or die "could not create Triples ($@)\n"; # for each triple memer, delete the doubles and singles # from the appropriae list, then print the triple block number foreach $bnum (keys %triple){ printf TRIPLES "%d\t%d\n",$triple{$bnum},$bnum; seek DEV,$bnum*$bsize,0 or die "seek failed for block $$blockno"; read( DEV,$block,$bsize) or die "read failed for block $$blockno"; @inums= unpack("l*",$block); $bad=0; delete $double{$bnum}; foreach $p (@inums){ if($p){ delete $double{$p}; delete $inlist{$p}; seek DEV,$dbnum*$bsize,0 or die "seek failed for block $$blockno"; read( DEV,$dblock,$bsize) or die "read failed for block $$blockno"; @dnums= unpack("l*",$block); foreach $ind (@dnums){ delete $inlist{$ind} } }else{ $last; }; }; }; close TRIPLES; open DOUBLES ,">Doubles" or die "could not create Doubles ($@)\n"; foreach $bnum (keys %double){ printf DOUBLES "%d %d\n",$double{$bnum},$bnum; delete $inlist{$bnum}; seek DEV,$bnum*$bsize,0 or die "seek failed for block $$blockno"; read( DEV,$block,$bsize); @inums= unpack("l*",$block); $bad=0; foreach $p (@inums){ if($p){ delete $inlist{$p}; }else{ $last; }; }; }; close SDOUBLES; open SINGLES ,">Singles" or die "could not create Doubles ($@)\n"; # Print remaining indirect block numbers, but only print # COMPLETE indirects, as partial indirects point to files too small # for our liking. foreach $bnum (keys %inlist){ if( ! exists( $partial{$bnum} )){ printf SINGLES "%d\n",$bnum; }; }