mft function rewrite

master
兔子 3 years ago
parent db9e96e4ed
commit 426a959d0d
Signed by: b612
GPG Key ID: 481225A74DEB62A1

@ -108,7 +108,7 @@ func main() {
if v.Format == "NTFS" && v.Driver == `C:\` { if v.Format == "NTFS" && v.Driver == `C:\` {
starlog.Infoln("开始获取NTFS USN日志磁盘", v.Driver) starlog.Infoln("开始获取NTFS USN日志磁盘", v.Driver)
fileLists, err := wincmd.ListUsnFileFn(v.Driver, func(name string, typed uint8) bool { fileLists, err := wincmd.ListUsnFileFn(v.Driver, func(name string, typed bool) bool {
return true return true
if ok, _ := regexp.MatchString(`\.exe$`, name); ok { if ok, _ := regexp.MatchString(`\.exe$`, name); ok {
return true return true

@ -1,9 +1,7 @@
package wincmd package mft
import ( import (
"b612.me/win32api"
"b612.me/wincmd/ntfs/binutil" "b612.me/wincmd/ntfs/binutil"
"b612.me/wincmd/ntfs/mft"
"b612.me/wincmd/ntfs/utf16" "b612.me/wincmd/ntfs/utf16"
"encoding/binary" "encoding/binary"
"errors" "errors"
@ -11,6 +9,7 @@ import (
"os" "os"
"reflect" "reflect"
"runtime" "runtime"
"strings"
"time" "time"
"unsafe" "unsafe"
) )
@ -24,11 +23,16 @@ type MFTFile struct {
IsDir bool IsDir bool
Node uint64 Node uint64
} }
type FileEntry struct {
Name string
Parent uint64
}
func GetFileListsByMftFn(driver string, fn func(string, bool) bool) ([]MFTFile, error) { func GetFileListsByMftFn(driver string, fn func(string, bool) bool) ([]MFTFile, error) {
var result []MFTFile var result []MFTFile
fileMap := make(map[win32api.DWORDLONG]FileEntry) extendMftRecord := make(map[uint64][]Attribute)
f, size, err := mft.GetMFTFile(driver) fileMap := make(map[uint64]FileEntry)
f, size, err := GetMFTFile(driver)
if err != nil { if err != nil {
return []MFTFile{}, err return []MFTFile{}, err
} }
@ -59,20 +63,41 @@ func GetFileListsByMftFn(driver string, fn func(string, bool) bool) ([]MFTFile,
} }
alreadyGot += int64(got) alreadyGot += int64(got)
for j := int64(0); j < 1024*maxRecordSize; j += 1024 { for j := int64(0); j < 1024*maxRecordSize; j += 1024 {
record, err := mft.ParseRecord(buf[j : j+1024]) record, err := ParseRecord(buf[j : j+1024])
if err != nil { if err != nil {
continue continue
} }
if record.Flags&mft.RecordFlagInUse == 1 && record.Flags&mft.RecordFlagIsIndex == 0 { if record.BaseRecordReference.ToUint64() != 0 {
val := extendMftRecord[record.BaseRecordReference.ToUint64()]
for _, v := range record.Attributes {
if v.Type == AttributeTypeData && v.ActualSize != 0 {
val = append(val, v)
}
}
if len(val) != 0 {
extendMftRecord[record.BaseRecordReference.ToUint64()] = val
}
}
if record.Flags&RecordFlagInUse == 1 && record.Flags&RecordFlagIsIndex == 0 {
var file MFTFile var file MFTFile
file.IsDir = record.Flags&mft.RecordFlagIsDirectory != 0 file.IsDir = record.Flags&RecordFlagIsDirectory != 0
file.Node = record.FileReference.ToUint64() file.Node = record.FileReference.ToUint64()
parent := uint64(0) parent := uint64(0)
for _, v := range record.Attributes { for _, v := range record.Attributes {
if v.Type == mft.AttributeTypeFileName { if v.Type == AttributeTypeData {
file.Size = v.ActualSize
file.Aszie = v.AllocatedSize
}
if v.Type == AttributeTypeStandardInformation {
if len(v.Data) >= 48 {
r := binutil.NewLittleEndianReader(v.Data)
file.ModTime = ConvertFileTime(r.Uint64(0x08))
}
}
if v.Type == AttributeTypeFileName {
name := utf16.DecodeString(v.Data[66:], binary.LittleEndian) name := utf16.DecodeString(v.Data[66:], binary.LittleEndian)
if len(file.Name) < len(name) && len(name) > 0 { if len(file.Name) < len(name) && len(name) > 0 {
if len(name) > 2 && name[len(name)-2] == '~' { if len(file.Name) > 0 && !strings.Contains(file.Name, "~") {
continue continue
} }
file.Name = name file.Name = name
@ -81,28 +106,17 @@ func GetFileListsByMftFn(driver string, fn func(string, bool) bool) ([]MFTFile,
parent = binutil.NewLittleEndianReader(v.Data[:8]).Uint64(0) parent = binutil.NewLittleEndianReader(v.Data[:8]).Uint64(0)
} }
} }
if v.Type == mft.AttributeTypeData {
file.Size = v.ActualSize
file.Aszie = v.AllocatedSize
}
if v.Type == mft.AttributeTypeStandardInformation {
if len(v.Data) < 48 {
continue
}
r := binutil.NewLittleEndianReader(v.Data)
file.ModTime = mft.ConvertFileTime(r.Uint64(0x08))
}
} }
if file.Name != "" { if file.Name != "" {
canAdd := fn(file.Name, file.IsDir) canAdd := fn(file.Name, file.IsDir)
if canAdd { if canAdd {
result = append(result, file) result = append(result, file)
} }
if canAdd || file.IsDir { if canAdd || file.IsDir {
fileMap[win32api.DWORDLONG(file.Node)] = FileEntry{ fileMap[uint64(file.Node)] = FileEntry{
Name: file.Name, Name: file.Name,
Parent: win32api.DWORDLONG(parent), Parent: uint64(parent),
Type: 0,
} }
} }
} }
@ -112,7 +126,18 @@ func GetFileListsByMftFn(driver string, fn func(string, bool) bool) ([]MFTFile,
(*reflect.SliceHeader)(unsafe.Pointer(&result)).Cap = len(result) (*reflect.SliceHeader)(unsafe.Pointer(&result)).Cap = len(result)
for k, v := range result { for k, v := range result {
result[k].Path = GetFullUsnPath(driver, fileMap, win32api.DWORDLONG(v.Node)) if attrs, ok := extendMftRecord[v.Node]; ok {
if v.Aszie == 0 {
for _, v := range attrs {
if v.Type == AttributeTypeData && v.ActualSize != 0 {
result[k].Size = v.ActualSize
result[k].Aszie = v.AllocatedSize
}
}
}
delete(extendMftRecord, v.Node)
}
result[k].Path = GetFullUsnPath(driver, fileMap, uint64(v.Node))
} }
fileMap = nil fileMap = nil
runtime.GC() runtime.GC()
@ -125,7 +150,8 @@ func GetFileListsByMft(driver string) ([]MFTFile, error) {
func GetFileListsFromMftFileFn(filepath string, fn func(string, bool) bool) ([]MFTFile, error) { func GetFileListsFromMftFileFn(filepath string, fn func(string, bool) bool) ([]MFTFile, error) {
var result []MFTFile var result []MFTFile
fileMap := make(map[win32api.DWORDLONG]FileEntry) extendMftRecord := make(map[uint64][]Attribute)
fileMap := make(map[uint64]FileEntry)
f, err := os.Open(filepath) f, err := os.Open(filepath)
if err != nil { if err != nil {
return []MFTFile{}, err return []MFTFile{}, err
@ -162,20 +188,41 @@ func GetFileListsFromMftFileFn(filepath string, fn func(string, bool) bool) ([]M
} }
alreadyGot += int64(got) alreadyGot += int64(got)
for j := int64(0); j < 1024*maxRecordSize; j += 1024 { for j := int64(0); j < 1024*maxRecordSize; j += 1024 {
record, err := mft.ParseRecord(buf[j : j+1024]) record, err := ParseRecord(buf[j : j+1024])
if err != nil { if err != nil {
continue continue
} }
if record.Flags&mft.RecordFlagInUse == 1 && record.Flags&mft.RecordFlagIsIndex == 0 { if record.BaseRecordReference.ToUint64() != 0 {
val := extendMftRecord[record.BaseRecordReference.ToUint64()]
for _, v := range record.Attributes {
if v.Type == AttributeTypeData && v.ActualSize != 0 {
val = append(val, v)
}
}
if len(val) != 0 {
extendMftRecord[record.BaseRecordReference.ToUint64()] = val
}
}
if record.Flags&RecordFlagInUse == 1 && record.Flags&RecordFlagIsIndex == 0 {
var file MFTFile var file MFTFile
file.IsDir = record.Flags&mft.RecordFlagIsDirectory != 0 file.IsDir = record.Flags&RecordFlagIsDirectory != 0
file.Node = record.FileReference.ToUint64() file.Node = record.FileReference.ToUint64()
parent := uint64(0) parent := uint64(0)
for _, v := range record.Attributes { for _, v := range record.Attributes {
if v.Type == mft.AttributeTypeFileName { if v.Type == AttributeTypeData {
file.Size = v.ActualSize
file.Aszie = v.AllocatedSize
}
if v.Type == AttributeTypeStandardInformation {
if len(v.Data) >= 48 {
r := binutil.NewLittleEndianReader(v.Data)
file.ModTime = ConvertFileTime(r.Uint64(0x08))
}
}
if v.Type == AttributeTypeFileName {
name := utf16.DecodeString(v.Data[66:], binary.LittleEndian) name := utf16.DecodeString(v.Data[66:], binary.LittleEndian)
if len(file.Name) < len(name) && len(name) > 0 { if len(file.Name) < len(name) && len(name) > 0 {
if len(name) > 2 && name[len(name)-2] == '~' { if len(file.Name) > 0 && !strings.Contains(file.Name, "~") {
continue continue
} }
file.Name = name file.Name = name
@ -184,17 +231,6 @@ func GetFileListsFromMftFileFn(filepath string, fn func(string, bool) bool) ([]M
parent = binutil.NewLittleEndianReader(v.Data[:8]).Uint64(0) parent = binutil.NewLittleEndianReader(v.Data[:8]).Uint64(0)
} }
} }
if v.Type == mft.AttributeTypeData {
file.Size = v.ActualSize
file.Aszie = v.AllocatedSize
}
if v.Type == mft.AttributeTypeStandardInformation {
if len(v.Data) < 48 {
continue
}
r := binutil.NewLittleEndianReader(v.Data)
file.ModTime = mft.ConvertFileTime(r.Uint64(0x08))
}
} }
if file.Name != "" { if file.Name != "" {
canAdd := fn(file.Name, file.IsDir) canAdd := fn(file.Name, file.IsDir)
@ -202,10 +238,9 @@ func GetFileListsFromMftFileFn(filepath string, fn func(string, bool) bool) ([]M
result = append(result, file) result = append(result, file)
} }
if canAdd || file.IsDir { if canAdd || file.IsDir {
fileMap[win32api.DWORDLONG(file.Node)] = FileEntry{ fileMap[uint64(file.Node)] = FileEntry{
Name: file.Name, Name: file.Name,
Parent: win32api.DWORDLONG(parent), Parent: uint64(parent),
Type: 0,
} }
} }
} }
@ -215,7 +250,18 @@ func GetFileListsFromMftFileFn(filepath string, fn func(string, bool) bool) ([]M
(*reflect.SliceHeader)(unsafe.Pointer(&result)).Cap = len(result) (*reflect.SliceHeader)(unsafe.Pointer(&result)).Cap = len(result)
for k, v := range result { for k, v := range result {
result[k].Path = GetFullUsnPath(" ", fileMap, win32api.DWORDLONG(v.Node)) if attrs, ok := extendMftRecord[v.Node]; ok {
if v.Aszie == 0 {
for _, v := range attrs {
if v.Type == AttributeTypeData && v.ActualSize != 0 {
result[k].Size = v.ActualSize
result[k].Aszie = v.AllocatedSize
}
}
}
delete(extendMftRecord, v.Node)
}
result[k].Path = GetFullUsnPath(" ", fileMap, uint64(v.Node))
} }
fileMap = nil fileMap = nil
runtime.GC() runtime.GC()
@ -225,3 +271,21 @@ func GetFileListsFromMftFileFn(filepath string, fn func(string, bool) bool) ([]M
func GetFileListsFromMftFile(filepath string) ([]MFTFile, error) { func GetFileListsFromMftFile(filepath string) ([]MFTFile, error) {
return GetFileListsFromMftFileFn(filepath, func(string, bool) bool { return true }) return GetFileListsFromMftFileFn(filepath, func(string, bool) bool { return true })
} }
func GetFullUsnPath(diskName string, fileMap map[uint64]FileEntry, id uint64) (name string) {
for id != 0 {
fe := fileMap[id]
if id == fe.Parent {
name = "\\" + name
break
}
if name == "" {
name = fe.Name
} else {
name = fe.Name + "\\" + name
}
id = fe.Parent
}
name = diskName[:len(diskName)-1] + name
return
}

@ -5,7 +5,6 @@ import (
"b612.me/wincmd/ntfs/fragment" "b612.me/wincmd/ntfs/fragment"
"bytes" "bytes"
"fmt" "fmt"
"github.com/t9t/gomft/mft"
"io" "io"
"os" "os"
"runtime" "runtime"
@ -13,7 +12,6 @@ import (
const supportedOemId = "NTFS " const supportedOemId = "NTFS "
const isWin = runtime.GOOS == "windows" const isWin = runtime.GOOS == "windows"
func GetMFTFileBytes(volume string) ([]byte, error) { func GetMFTFileBytes(volume string) ([]byte, error) {
@ -85,12 +83,12 @@ func GetMFTFile(volume string) (io.Reader, int64, error) {
return nil, 0, fmt.Errorf("Unable to read $MFT record: %v\n", err) return nil, 0, fmt.Errorf("Unable to read $MFT record: %v\n", err)
} }
record, err := mft.ParseRecord(mftData) record, err := ParseRecord(mftData)
if err != nil { if err != nil {
return nil, 0, fmt.Errorf("Unable to parse $MFT record: %v\n", err) return nil, 0, fmt.Errorf("Unable to parse $MFT record: %v\n", err)
} }
dataAttributes := record.FindAttributes(mft.AttributeTypeData) dataAttributes := record.FindAttributes(AttributeTypeData)
if len(dataAttributes) == 0 { if len(dataAttributes) == 0 {
return nil, 0, fmt.Errorf("No $DATA attribute found in $MFT record\n") return nil, 0, fmt.Errorf("No $DATA attribute found in $MFT record\n")
} }

@ -1,4 +1,4 @@
package wincmd package usn
import ( import (
"b612.me/win32api" "b612.me/win32api"

@ -1,4 +1,4 @@
package wincmd package usn
import ( import (
"fmt" "fmt"

@ -1,4 +1,4 @@
package wincmd package usn
import ( import (
"b612.me/stario" "b612.me/stario"
Loading…
Cancel
Save