Uses ntfswalk and sleuthkit.
Fetch MFT, find offset, update code near cluster_to_byte_offset
.
Example ntfswalk usage:
ntfswalk32 -mftfile ../mft.raw -out ntfswalk-results -csv -action_include_clusterinfo
class Damage | |
def initialize(start, size) | |
@start = start; @size = size | |
@stop = @start + @size | |
end | |
def overlaps?(start, stop) | |
intersection_start = if start >= @start then start else @start end # max | |
intersection_stop = if stop <= @stop then stop else @stop end # min | |
return intersection_stop >= intersection_start | |
end | |
def self.read(f) | |
r = [] | |
File.open(f, "r") do |f| | |
f.each_line do |l| | |
if l.match(/(0x[A-F0-9]{8}) (0x[A-F0-9]{8}) -/) | |
r.push(Damage.new $1.to_i(16), $2.to_i(16)) | |
end | |
end | |
end | |
r | |
end | |
end | |
class NTFSWalk | |
def self.read(f) | |
File.open(f, "r") do |fh| | |
fh.each_line do |l| | |
if l.match(/^0x/) | |
yield l.split(',') | |
end | |
end | |
end | |
end | |
end | |
NTFS_OFFSET = 718848 * 512 | |
def cluster_to_byte_offset(x) | |
x * 4096 + NTFS_OFFSET | |
end | |
damaged_regions = Damage.read("ddrescue.log") | |
puts damaged_regions.map { |x| x.inspect } | |
NTFSWalk.read('ntfswalk-results') do |mft_entry,seqnum,parent_mft,type,ext,ref,size_data,date,time,macb,data_type,other_info,path_and_filename,clusters| | |
if clusters.match(/(0x[A-Fa-f0-9]+) -> (0x[A-Fa-f0-9]+)/) | |
byte_start = cluster_to_byte_offset($1.to_i(16)) | |
byte_stop = cluster_to_byte_offset($2.to_i(16) + 1) | |
elsif clusters.match(/(0x[A-Fa-f0-9]+)/) | |
byte_start = cluster_to_byte_offset($1.to_i(16)) | |
byte_stop = cluster_to_byte_offset($1.to_i(16) + 1) | |
else | |
next | |
end | |
damaged_regions.each do |d| | |
if d.overlaps? byte_start, byte_stop | |
puts "Damaged file!" | |
puts d.inspect | |
puts "file range=#{byte_start} to #{byte_stop}" | |
puts clusters | |
puts path_and_filename | |
end | |
end | |
end |