forked from Velocidex/velociraptor
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added mscfb (OLE) accessor and Jumplist artifact (Velocidex#3573)
Parses the Automatic Destinations files.
- Loading branch information
Showing
12 changed files
with
1,353 additions
and
56 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,269 @@ | ||
package mscfb | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"os" | ||
"runtime/debug" | ||
"time" | ||
|
||
"github.com/Velocidex/go-mscfb/parser" | ||
"github.com/Velocidex/ordereddict" | ||
"www.velocidex.com/golang/velociraptor/accessors" | ||
"www.velocidex.com/golang/velociraptor/json" | ||
"www.velocidex.com/golang/vfilter" | ||
) | ||
|
||
type MscfbFileInfo struct { | ||
entry *parser.DirectoryEntry | ||
_full_path *accessors.OSPath | ||
} | ||
|
||
func (self *MscfbFileInfo) Name() string { | ||
return self.entry.Name | ||
} | ||
|
||
func (self *MscfbFileInfo) UniqueName() string { | ||
return self._full_path.String() | ||
} | ||
|
||
func (self *MscfbFileInfo) IsDir() bool { | ||
return self.entry.IsDir | ||
} | ||
|
||
func (self *MscfbFileInfo) Data() *ordereddict.Dict { | ||
return ordereddict.NewDict() | ||
} | ||
|
||
func (self *MscfbFileInfo) FullPath() string { | ||
return self._full_path.String() | ||
} | ||
|
||
func (self *MscfbFileInfo) OSPath() *accessors.OSPath { | ||
return self._full_path | ||
} | ||
|
||
// Not supported | ||
func (self *MscfbFileInfo) IsLink() bool { | ||
return false | ||
} | ||
|
||
func (self *MscfbFileInfo) GetLink() (*accessors.OSPath, error) { | ||
return nil, errors.New("Not implemented") | ||
} | ||
|
||
func (self *MscfbFileInfo) Mtime() time.Time { | ||
return self.entry.Mtime | ||
} | ||
|
||
func (self *MscfbFileInfo) ModTime() time.Time { | ||
return self.entry.Mtime | ||
} | ||
|
||
func (self *MscfbFileInfo) Atime() time.Time { | ||
return time.Time{} | ||
} | ||
|
||
func (self *MscfbFileInfo) Ctime() time.Time { | ||
return self.entry.Ctime | ||
} | ||
|
||
func (self *MscfbFileInfo) Btime() time.Time { | ||
return self.entry.Ctime | ||
} | ||
|
||
func (self *MscfbFileInfo) Size() int64 { | ||
return int64(self.entry.Size) | ||
} | ||
|
||
func (self *MscfbFileInfo) Mode() os.FileMode { | ||
var result os.FileMode = 0755 | ||
if self.IsDir() { | ||
result |= os.ModeDir | ||
} | ||
return result | ||
} | ||
|
||
type MscfbFileSystemAccessor struct { | ||
scope vfilter.Scope | ||
|
||
// The delegate accessor we use to open the underlying volume. | ||
accessor string | ||
device *accessors.OSPath | ||
|
||
root *accessors.OSPath | ||
} | ||
|
||
func NewMscfbFileSystemAccessor( | ||
scope vfilter.Scope, | ||
root_path *accessors.OSPath, | ||
device *accessors.OSPath, accessor string) *MscfbFileSystemAccessor { | ||
return &MscfbFileSystemAccessor{ | ||
scope: scope, | ||
accessor: accessor, | ||
device: device, | ||
root: root_path, | ||
} | ||
} | ||
|
||
func (self MscfbFileSystemAccessor) New(scope vfilter.Scope) ( | ||
accessors.FileSystemAccessor, error) { | ||
// Create a new cache in the scope. | ||
return &MscfbFileSystemAccessor{ | ||
scope: scope, | ||
device: self.device, | ||
accessor: self.accessor, | ||
root: self.root, | ||
}, nil | ||
} | ||
|
||
func (self MscfbFileSystemAccessor) ParsePath(path string) ( | ||
*accessors.OSPath, error) { | ||
return accessors.NewLinuxOSPath(path) | ||
} | ||
|
||
func (self *MscfbFileSystemAccessor) ReadDir(path string) ( | ||
res []accessors.FileInfo, err error) { | ||
// Normalize the path | ||
fullpath, err := self.ParsePath(path) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return self.ReadDirWithOSPath(fullpath) | ||
} | ||
|
||
func (self *MscfbFileSystemAccessor) ReadDirWithOSPath( | ||
fullpath *accessors.OSPath) (res []accessors.FileInfo, err error) { | ||
defer func() { | ||
r := recover() | ||
if r != nil { | ||
fmt.Printf("PANIC %v\n", r) | ||
debug.PrintStack() | ||
err, _ = r.(error) | ||
} | ||
}() | ||
|
||
result := []accessors.FileInfo{} | ||
if len(fullpath.Components) > 0 { | ||
return nil, errors.New("Not found error") | ||
} | ||
|
||
ole_ctx, err := GetMscfbContext( | ||
self.scope, self.device, fullpath, self.accessor) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// List the directory. | ||
for _, info := range ole_ctx.Directories { | ||
result = append(result, &MscfbFileInfo{ | ||
entry: &info, | ||
_full_path: fullpath.Append(info.Name), | ||
}) | ||
} | ||
return result, nil | ||
} | ||
|
||
func (self *MscfbFileSystemAccessor) Open( | ||
path string) (res accessors.ReadSeekCloser, err error) { | ||
|
||
full_path, err := self.ParsePath(path) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return self.OpenWithOSPath(full_path) | ||
} | ||
|
||
func (self *MscfbFileSystemAccessor) OpenWithOSPath( | ||
fullpath *accessors.OSPath) (res accessors.ReadSeekCloser, err error) { | ||
|
||
defer func() { | ||
r := recover() | ||
if r != nil { | ||
fmt.Printf("PANIC %v\n", r) | ||
debug.PrintStack() | ||
err, _ = r.(error) | ||
} | ||
}() | ||
|
||
if len(fullpath.Components) != 1 { | ||
return nil, errors.New("Not found error") | ||
} | ||
|
||
ole_ctx, err := GetMscfbContext( | ||
self.scope, self.device, fullpath, self.accessor) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// Open the device path from the root. | ||
stream, dir, err := ole_ctx.Open(fullpath.Components[0]) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return &readAdapter{ | ||
info: &MscfbFileInfo{ | ||
entry: dir, | ||
_full_path: fullpath, | ||
}, | ||
reader: stream, | ||
}, nil | ||
} | ||
|
||
func (self *MscfbFileSystemAccessor) Lstat( | ||
path string) (res accessors.FileInfo, err error) { | ||
|
||
fullpath, err := self.ParsePath(path) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return self.LstatWithOSPath(fullpath) | ||
} | ||
|
||
func (self *MscfbFileSystemAccessor) LstatWithOSPath( | ||
fullpath *accessors.OSPath) (res accessors.FileInfo, err error) { | ||
defer func() { | ||
r := recover() | ||
if r != nil { | ||
fmt.Printf("PANIC %v\n", r) | ||
debug.PrintStack() | ||
err, _ = r.(error) | ||
} | ||
}() | ||
|
||
ole_ctx, err := GetMscfbContext( | ||
self.scope, self.device, fullpath, self.accessor) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var dir *parser.DirectoryEntry | ||
if len(fullpath.Components) > 1 { | ||
return nil, errors.New("Not found error") | ||
} | ||
|
||
if len(fullpath.Components) == 0 { | ||
// Root directory | ||
dir, err = ole_ctx.GetDirentry(0) | ||
} else { | ||
|
||
dir, err = ole_ctx.Stat(fullpath.Components[0]) | ||
} | ||
|
||
return &MscfbFileInfo{ | ||
entry: dir, | ||
_full_path: fullpath, | ||
}, err | ||
} | ||
|
||
func init() { | ||
accessors.Register("mscfb", &MscfbFileSystemAccessor{}, | ||
`Parse a MSCFB file as an archive. | ||
`) | ||
|
||
json.RegisterCustomEncoder(&MscfbFileInfo{}, accessors.MarshalGlobFileInfo) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package mscfb | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"runtime/debug" | ||
"sync" | ||
|
||
"www.velocidex.com/golang/velociraptor/accessors" | ||
) | ||
|
||
type readAdapter struct { | ||
sync.Mutex | ||
|
||
info accessors.FileInfo | ||
pos int64 | ||
reader io.ReaderAt | ||
} | ||
|
||
func (self *readAdapter) Read(buf []byte) (res int, err error) { | ||
self.Lock() | ||
defer self.Unlock() | ||
|
||
defer func() { | ||
r := recover() | ||
if r != nil { | ||
fmt.Printf("PANIC %v\n", r) | ||
debug.PrintStack() | ||
err, _ = r.(error) | ||
} | ||
}() | ||
|
||
res, err = self.reader.ReadAt(buf, self.pos) | ||
|
||
// If ReadAt is unable to read anything it means an EOF. | ||
if res == 0 { | ||
// The NTFS cache may be flushed during this read and in this | ||
// case the file handle will be closed on us during the | ||
// read. This usually shows up as an EOF read with 0 length. | ||
// See Issue | ||
// https://github.com/Velocidex/velociraptor/issues/2153 | ||
|
||
// We catch this issue by issuing one more read just to make | ||
// sure. Usually we are wrapping a ReadAtter here and we do | ||
// not expect to see a EOF anyway. In the case of NTFS the | ||
// extra read will re-open the underlying device file with a | ||
// new NTFS context (reparsing the $MFT and purging all the | ||
// caches) so the next read will succeed. | ||
res, err = self.reader.ReadAt(buf, self.pos) | ||
if res == 0 { | ||
// Still EOF - give up | ||
return res, io.EOF | ||
} | ||
} | ||
|
||
self.pos += int64(res) | ||
|
||
return res, err | ||
} | ||
|
||
func (self *readAdapter) ReadAt(buf []byte, offset int64) (int, error) { | ||
self.Lock() | ||
defer self.Unlock() | ||
self.pos = offset | ||
|
||
return self.reader.ReadAt(buf, offset) | ||
} | ||
|
||
func (self *readAdapter) Close() error { | ||
return nil | ||
} | ||
|
||
func (self *readAdapter) Seek(offset int64, whence int) (int64, error) { | ||
self.Lock() | ||
defer self.Unlock() | ||
|
||
self.pos = offset | ||
return self.pos, nil | ||
} |
Oops, something went wrong.