diff --git a/internal/etw/processors/fs_windows.go b/internal/etw/processors/fs_windows.go index 40e0ad6f4..c8e0c798d 100644 --- a/internal/etw/processors/fs_windows.go +++ b/internal/etw/processors/fs_windows.go @@ -49,8 +49,6 @@ var ( type fsProcessor struct { // files stores the file metadata indexed by file object files map[uint64]*FileInfo - // mmaps stores memory-mapped files by pid and file object - mmaps map[uint32]map[uint64]*MmapInfo hsnap handle.Snapshotter psnap ps.Snapshotter @@ -75,13 +73,6 @@ type FileInfo struct { Type fs.FileType } -// MmapInfo stores information of the memory-mapped file. -type MmapInfo struct { - File string - BaseAddr uint64 - Size uint64 -} - func newFsProcessor( hsnap handle.Snapshotter, psnap ps.Snapshotter, @@ -91,7 +82,6 @@ func newFsProcessor( ) Processor { f := &fsProcessor{ files: make(map[uint64]*FileInfo), - mmaps: make(map[uint32]map[uint64]*MmapInfo), irps: make(map[uint64]*kevent.Kevent), hsnap: hsnap, psnap: psnap, @@ -139,35 +129,25 @@ func (f *fsProcessor) processEvent(e *kevent.Kevent) (*kevent.Kevent, error) { f.files[fileObject] = &FileInfo{Name: filepath, Type: fs.GetFileType(filepath, 0)} } case ktypes.MapFileRundown: - // if the memory-mapped view refers to the image/data file - // we store it in internal state for each process. The state - // is consulted later when we process unmap events - sec := e.Kparams.MustGetUint32(kparams.FileViewSectionType) - isMapped := sec != va.SectionPagefile && sec != va.SectionPhysical - if !isMapped { - return e, nil - } fileKey := e.Kparams.MustGetUint64(kparams.FileKey) - viewBase := e.Kparams.MustGetUint64(kparams.FileViewBase) - viewSize := e.Kparams.MustGetUint64(kparams.FileViewSize) - f.initMmap(e.PID) fileinfo := f.files[fileKey] + if fileinfo != nil { totalMapRundownFiles.Add(1) - f.mmaps[e.PID][fileKey] = &MmapInfo{File: fileinfo.Name, BaseAddr: viewBase, Size: viewSize} + e.AppendParam(kparams.FilePath, kparams.Path, fileinfo.Name) } else { - process, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION, false, e.PID) - if err != nil { - return e, nil + // if the view of section is backed by the data/image file + // try to get the mapped file name and append it to params + sec := e.Kparams.MustGetUint32(kparams.FileViewSectionType) + isMapped := sec != va.SectionPagefile && sec != va.SectionPhysical + if isMapped { + totalMapRundownFiles.Add(1) + addr := e.Kparams.MustGetUint64(kparams.FileViewBase) + (e.Kparams.MustGetUint64(kparams.FileOffset)) + e.AppendParam(kparams.FilePath, kparams.Path, f.getMappedFile(e.PID, addr)) } - defer windows.Close(process) - totalMapRundownFiles.Add(1) - addr := e.Kparams.MustGetUint64(kparams.FileViewBase) + (e.Kparams.MustGetUint64(kparams.FileOffset)) - name := f.devMapper.Convert(sys.GetMappedFile(process, uintptr(addr))) - f.mmaps[e.PID][fileKey] = &MmapInfo{File: name, BaseAddr: viewBase, Size: viewSize} } - e.AppendParam(kparams.FilePath, kparams.Path, f.mmaps[e.PID][fileKey].File) - return e, f.psnap.AddFileMapping(e) + + return e, f.psnap.AddMmap(e) case ktypes.CreateFile: // we defer the processing of the CreateFile event until we get // the matching FileOpEnd event. This event contains the operation @@ -255,24 +235,22 @@ func (f *fsProcessor) processEvent(e *kevent.Kevent) (*kevent.Kevent, error) { fileObject := e.Kparams.MustGetUint64(kparams.FileObject) delete(f.files, fileObject) case ktypes.UnmapViewFile: - _ = f.psnap.RemoveFileMapping(e.PID, e.Kparams.TryGetAddress(kparams.FileViewBase)) - fileKey := e.Kparams.MustGetUint64(kparams.FileKey) - if _, ok := f.mmaps[e.PID]; !ok { - return e, nil - } - mmapinfo := f.mmaps[e.PID][fileKey] - if mmapinfo != nil { - e.AppendParam(kparams.FilePath, kparams.Path, mmapinfo.File) + ok, proc := f.psnap.Find(e.PID) + addr := e.Kparams.TryGetAddress(kparams.FileViewBase) + if ok { + mmap := proc.FindMmap(addr) + if mmap != nil { + e.AppendParam(kparams.FilePath, kparams.Path, mmap.File) + } } + totalMapRundownFiles.Add(-1) - delete(f.mmaps[e.PID], fileKey) - if len(f.mmaps[e.PID]) == 0 { - // process terminated, all files unmapped - f.removeMmap(e.PID) - } + + return e, f.psnap.RemoveMmap(e.PID, addr) default: var fileObject uint64 fileKey := e.Kparams.MustGetUint64(kparams.FileKey) + if !e.IsMapViewFile() { fileObject = e.Kparams.MustGetUint64(kparams.FileObject) } @@ -286,28 +264,18 @@ func (f *fsProcessor) processEvent(e *kevent.Kevent) (*kevent.Kevent, error) { if fileinfo == nil && e.IsMapViewFile() { sec := e.Kparams.MustGetUint32(kparams.FileViewSectionType) isMapped := sec != va.SectionPagefile && sec != va.SectionPhysical - if !isMapped { - return e, nil + if isMapped { + totalMapRundownFiles.Add(1) + addr := e.Kparams.MustGetUint64(kparams.FileViewBase) + (e.Kparams.MustGetUint64(kparams.FileOffset)) + e.AppendParam(kparams.FilePath, kparams.Path, f.getMappedFile(e.PID, addr)) } - process, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION, false, e.PID) - if err != nil { - return e, nil - } - defer windows.Close(process) - viewBase := e.Kparams.MustGetUint64(kparams.FileViewBase) - viewSize := e.Kparams.MustGetUint64(kparams.FileViewSize) - addr := e.Kparams.MustGetUint64(kparams.FileViewBase) + (e.Kparams.MustGetUint64(kparams.FileOffset)) - name := f.devMapper.Convert(sys.GetMappedFile(process, uintptr(addr))) - f.initMmap(e.PID) - f.mmaps[e.PID][fileKey] = &MmapInfo{File: name, BaseAddr: viewBase, Size: viewSize} - e.AppendParam(kparams.FilePath, kparams.Path, name) - return e, f.psnap.AddFileMapping(e) } // ignore object misses that are produced by CloseFile if fileinfo == nil && !e.IsCloseFile() { fileObjectMisses.Add(1) } + if e.IsDeleteFile() { delete(f.files, fileObject) } @@ -317,14 +285,16 @@ func (f *fsProcessor) processEvent(e *kevent.Kevent) (*kevent.Kevent, error) { } return e, nil } + if fileinfo != nil { if fileinfo.Type != fs.Unknown { e.AppendEnum(kparams.FileType, uint32(fileinfo.Type), fs.FileTypes) } e.AppendParam(kparams.FilePath, kparams.Path, fileinfo.Name) } + if e.IsMapViewFile() { - return e, f.psnap.AddFileMapping(e) + return e, f.psnap.AddMmap(e) } } return e, nil @@ -352,15 +322,13 @@ func (f *fsProcessor) findFile(fileKey, fileObject uint64) *FileInfo { return nil } -func (f *fsProcessor) initMmap(pid uint32) { - m := f.mmaps[pid] - if m == nil { - f.mmaps[pid] = make(map[uint64]*MmapInfo) +func (f *fsProcessor) getMappedFile(pid uint32, addr uint64) string { + process, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION, false, pid) + if err != nil { + return "" } -} - -func (f *fsProcessor) removeMmap(pid uint32) { - delete(f.mmaps, pid) + defer windows.Close(process) + return f.devMapper.Convert(sys.GetMappedFile(process, uintptr(addr))) } func (f *fsProcessor) purge() { diff --git a/internal/etw/processors/fs_windows_test.go b/internal/etw/processors/fs_windows_test.go index 260012601..d08756ca0 100644 --- a/internal/etw/processors/fs_windows_test.go +++ b/internal/etw/processors/fs_windows_test.go @@ -27,6 +27,7 @@ import ( "github.com/rabbitstack/fibratus/pkg/kevent/kparams" "github.com/rabbitstack/fibratus/pkg/kevent/ktypes" "github.com/rabbitstack/fibratus/pkg/ps" + pstypes "github.com/rabbitstack/fibratus/pkg/ps/types" "github.com/rabbitstack/fibratus/pkg/util/va" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -89,12 +90,11 @@ func TestFsProcessor(t *testing.T) { }, func(e *kevent.Kevent, t *testing.T, hsnap *handle.SnapshotterMock, p Processor) { fsProcessor := p.(*fsProcessor) - assert.Contains(t, fsProcessor.mmaps, uint32(10233)) - mapinfo := fsProcessor.mmaps[10233][124567380264] - require.NotNil(t, mapinfo) - assert.Equal(t, "C:\\Windows\\System32\\kernel32.dll", mapinfo.File) - assert.Equal(t, uint64(3098), mapinfo.Size) - assert.Equal(t, uint64(0xffff23433), mapinfo.BaseAddr) + + assert.Equal(t, "C:\\Windows\\System32\\kernel32.dll", e.GetParamAsString(kparams.FilePath)) + + psnap := fsProcessor.psnap.(*ps.SnapshotterMock) + psnap.AssertNumberOfCalls(t, "AddMmap", 1) }, }, { @@ -201,19 +201,16 @@ func TestFsProcessor(t *testing.T) { kparams.FileViewSectionType: {Name: kparams.FileViewSectionType, Type: kparams.Enum, Value: uint32(va.SectionImage), Enum: kevent.ViewSectionTypes}, }, }, - func(p Processor) { - fsProcessor := p.(*fsProcessor) - fsProcessor.mmaps[10233] = make(map[uint64]*MmapInfo) - fsProcessor.mmaps[10233][124567380264] = &MmapInfo{File: "C:\\Windows\\System32\\kernel32.dll"} - }, + nil, func() *handle.SnapshotterMock { hsnap := new(handle.SnapshotterMock) return hsnap }, func(e *kevent.Kevent, t *testing.T, hsnap *handle.SnapshotterMock, p Processor) { fsProcessor := p.(*fsProcessor) - assert.True(t, e.Kparams.Contains(kparams.FilePath)) - assert.Nil(t, fsProcessor.mmaps[3098][124567380264]) + + psnap := fsProcessor.psnap.(*ps.SnapshotterMock) + psnap.AssertNumberOfCalls(t, "RemoveMmap", 1) }, }, { @@ -298,8 +295,13 @@ func TestFsProcessor(t *testing.T) { t.Run(tt.name, func(t *testing.T) { hsnap := tt.hsnap() psnap := new(ps.SnapshotterMock) - psnap.On("AddFileMapping", mock.Anything).Return(nil) - psnap.On("RemoveFileMapping", mock.Anything, mock.Anything).Return(nil) + psnap.On("AddMmap", mock.Anything).Return(nil) + psnap.On("RemoveMmap", mock.Anything, mock.Anything).Return(nil) + psnap.On("Find", mock.Anything).Return(true, &pstypes.PS{ + Mmaps: []pstypes.Mmap{ + {File: "C:\\Windows\\System32\\kernel32.dll", BaseAddress: va.Address(0xffff23433), Size: 3098}, + }, + }) p := newFsProcessor(hsnap, psnap, fs.NewDevMapper(), fs.NewDevPathResolver(), &config.Config{}) if tt.setupProcessor != nil { tt.setupProcessor(p) diff --git a/internal/etw/source_test.go b/internal/etw/source_test.go index d2143a88f..db58db85a 100644 --- a/internal/etw/source_test.go +++ b/internal/etw/source_test.go @@ -68,8 +68,8 @@ func TestEventSourceStartTraces(t *testing.T) { psnap.On("Write", mock.Anything).Return(nil) psnap.On("AddThread", mock.Anything).Return(nil) psnap.On("AddModule", mock.Anything).Return(nil) - psnap.On("AddFileMapping", mock.Anything).Return(nil) - psnap.On("RemoveFileMapping", mock.Anything, mock.Anything).Return(nil) + psnap.On("AddMmap", mock.Anything).Return(nil) + psnap.On("RemoveMmap", mock.Anything, mock.Anything).Return(nil) psnap.On("RemoveThread", mock.Anything, mock.Anything).Return(nil) psnap.On("RemoveModule", mock.Anything, mock.Anything).Return(nil) psnap.On("FindModule", mock.Anything).Return(false, nil) @@ -153,8 +153,8 @@ func TestEventSourceEnableFlagsDynamically(t *testing.T) { psnap.On("Write", mock.Anything).Return(nil) psnap.On("AddThread", mock.Anything).Return(nil) psnap.On("AddModule", mock.Anything).Return(nil) - psnap.On("AddFileMapping", mock.Anything).Return(nil) - psnap.On("RemoveFileMapping", mock.Anything, mock.Anything).Return(nil) + psnap.On("AddMmap", mock.Anything).Return(nil) + psnap.On("RemoveMmap", mock.Anything, mock.Anything).Return(nil) psnap.On("RemoveThread", mock.Anything, mock.Anything).Return(nil) psnap.On("RemoveModule", mock.Anything, mock.Anything).Return(nil) psnap.On("FindModule", mock.Anything).Return(false, nil) @@ -236,8 +236,8 @@ func TestEventSourceEnableFlagsDynamicallyWithYaraEnabled(t *testing.T) { psnap.On("Write", mock.Anything).Return(nil) psnap.On("AddThread", mock.Anything).Return(nil) psnap.On("AddModule", mock.Anything).Return(nil) - psnap.On("AddFileMapping", mock.Anything).Return(nil) - psnap.On("RemoveFileMapping", mock.Anything, mock.Anything).Return(nil) + psnap.On("AddMmap", mock.Anything).Return(nil) + psnap.On("RemoveMmap", mock.Anything, mock.Anything).Return(nil) psnap.On("RemoveThread", mock.Anything, mock.Anything).Return(nil) psnap.On("RemoveModule", mock.Anything, mock.Anything).Return(nil) psnap.On("FindModule", mock.Anything).Return(false, nil) @@ -311,8 +311,8 @@ func TestEventSourceRundownEvents(t *testing.T) { psnap.On("Write", mock.Anything).Return(nil) psnap.On("AddThread", mock.Anything).Return(nil) psnap.On("AddModule", mock.Anything).Return(nil) - psnap.On("AddFileMapping", mock.Anything).Return(nil) - psnap.On("RemoveFileMapping", mock.Anything, mock.Anything).Return(nil) + psnap.On("AddMmap", mock.Anything).Return(nil) + psnap.On("RemoveMmap", mock.Anything, mock.Anything).Return(nil) psnap.On("RemoveThread", mock.Anything, mock.Anything).Return(nil) psnap.On("RemoveModule", mock.Anything, mock.Anything).Return(nil) psnap.On("FindModule", mock.Anything).Return(false, nil) @@ -721,11 +721,11 @@ func TestEventSourceAllEvents(t *testing.T) { psnap.On("Write", mock.Anything).Return(nil) psnap.On("AddThread", mock.Anything).Return(nil) psnap.On("AddModule", mock.Anything).Return(nil) - psnap.On("AddFileMapping", mock.Anything).Return(nil) + psnap.On("AddMmap", mock.Anything).Return(nil) psnap.On("RemoveThread", mock.Anything, mock.Anything).Return(nil) psnap.On("RemoveModule", mock.Anything, mock.Anything).Return(nil) psnap.On("FindModule", mock.Anything).Return(false, nil) - psnap.On("RemoveFileMapping", mock.Anything, mock.Anything).Return(nil) + psnap.On("RemoveMmap", mock.Anything, mock.Anything).Return(nil) psnap.On("FindAndPut", mock.Anything).Return(&pstypes.PS{}) psnap.On("Find", mock.Anything).Return(true, &pstypes.PS{}) psnap.On("Remove", mock.Anything).Return(nil) @@ -814,22 +814,22 @@ type NoopPsSnapshotter struct{} var fakeProc = &pstypes.PS{PID: 111111, Name: "fake.exe"} -func (s *NoopPsSnapshotter) Write(kevt *kevent.Kevent) error { return nil } -func (s *NoopPsSnapshotter) Remove(kevt *kevent.Kevent) error { return nil } -func (s *NoopPsSnapshotter) Find(pid uint32) (bool, *pstypes.PS) { return true, fakeProc } -func (s *NoopPsSnapshotter) FindAndPut(pid uint32) *pstypes.PS { return fakeProc } -func (s *NoopPsSnapshotter) Put(ps *pstypes.PS) {} -func (s *NoopPsSnapshotter) Size() uint32 { return 1 } -func (s *NoopPsSnapshotter) Close() error { return nil } -func (s *NoopPsSnapshotter) GetSnapshot() []*pstypes.PS { return nil } -func (s *NoopPsSnapshotter) AddThread(kevt *kevent.Kevent) error { return nil } -func (s *NoopPsSnapshotter) AddModule(kevt *kevent.Kevent) error { return nil } -func (s *NoopPsSnapshotter) FindModule(addr va.Address) (bool, *pstypes.Module) { return false, nil } -func (s *NoopPsSnapshotter) RemoveThread(pid uint32, tid uint32) error { return nil } -func (s *NoopPsSnapshotter) RemoveModule(pid uint32, mod string) error { return nil } -func (s *NoopPsSnapshotter) WriteFromKcap(kevt *kevent.Kevent) error { return nil } -func (s *NoopPsSnapshotter) AddFileMapping(kevt *kevent.Kevent) error { return nil } -func (s *NoopPsSnapshotter) RemoveFileMapping(pid uint32, address va.Address) error { return nil } +func (s *NoopPsSnapshotter) Write(kevt *kevent.Kevent) error { return nil } +func (s *NoopPsSnapshotter) Remove(kevt *kevent.Kevent) error { return nil } +func (s *NoopPsSnapshotter) Find(pid uint32) (bool, *pstypes.PS) { return true, fakeProc } +func (s *NoopPsSnapshotter) FindAndPut(pid uint32) *pstypes.PS { return fakeProc } +func (s *NoopPsSnapshotter) Put(ps *pstypes.PS) {} +func (s *NoopPsSnapshotter) Size() uint32 { return 1 } +func (s *NoopPsSnapshotter) Close() error { return nil } +func (s *NoopPsSnapshotter) GetSnapshot() []*pstypes.PS { return nil } +func (s *NoopPsSnapshotter) AddThread(kevt *kevent.Kevent) error { return nil } +func (s *NoopPsSnapshotter) AddModule(kevt *kevent.Kevent) error { return nil } +func (s *NoopPsSnapshotter) FindModule(addr va.Address) (bool, *pstypes.Module) { return false, nil } +func (s *NoopPsSnapshotter) RemoveThread(pid uint32, tid uint32) error { return nil } +func (s *NoopPsSnapshotter) RemoveModule(pid uint32, mod string) error { return nil } +func (s *NoopPsSnapshotter) WriteFromKcap(kevt *kevent.Kevent) error { return nil } +func (s *NoopPsSnapshotter) AddMmap(kevt *kevent.Kevent) error { return nil } +func (s *NoopPsSnapshotter) RemoveMmap(pid uint32, address va.Address) error { return nil } func TestCallstackEnrichment(t *testing.T) { hsnap := new(handle.SnapshotterMock) diff --git a/pkg/ps/snapshotter.go b/pkg/ps/snapshotter.go index 8ebbe1af3..8135489a3 100644 --- a/pkg/ps/snapshotter.go +++ b/pkg/ps/snapshotter.go @@ -40,10 +40,10 @@ type Snapshotter interface { RemoveThread(pid uint32, tid uint32) error // RemoveModule removes the module the given process. RemoveModule(pid uint32, mod string) error - // AddFileMapping adds a new data memory-mapped file to this process state. - AddFileMapping(*kevent.Kevent) error - // RemoveFileMapping removes memory-mapped file at the given base address. - RemoveFileMapping(pid uint32, address va.Address) error + // AddMmap adds a new memory mapping (data memory-mapped file, image, or pagefile) to this process state. + AddMmap(*kevent.Kevent) error + // RemoveMmap removes memory mapping at the given base address. + RemoveMmap(pid uint32, address va.Address) error // WriteFromKcap appends a new process state to the snapshotter from the captured kernel event. WriteFromKcap(kevt *kevent.Kevent) error // Remove deletes process's state from the snapshotter. diff --git a/pkg/ps/snapshotter_mock.go b/pkg/ps/snapshotter_mock.go index b54fcc24c..4e36d44c6 100644 --- a/pkg/ps/snapshotter_mock.go +++ b/pkg/ps/snapshotter_mock.go @@ -106,13 +106,13 @@ func (s *SnapshotterMock) RemoveModule(pid uint32, mod string) error { func (s *SnapshotterMock) WriteFromKcap(kevt *kevent.Kevent) error { return nil } // AddFileMapping method -func (s *SnapshotterMock) AddFileMapping(kevt *kevent.Kevent) error { +func (s *SnapshotterMock) AddMmap(kevt *kevent.Kevent) error { args := s.Called(kevt) return args.Error(0) } // RemoveFileMapping method -func (s *SnapshotterMock) RemoveFileMapping(pid uint32, address va.Address) error { +func (s *SnapshotterMock) RemoveMmap(pid uint32, address va.Address) error { args := s.Called(pid, address) return args.Error(0) } diff --git a/pkg/ps/snapshotter_windows.go b/pkg/ps/snapshotter_windows.go index b6edf62f9..a6d6f9fdf 100644 --- a/pkg/ps/snapshotter_windows.go +++ b/pkg/ps/snapshotter_windows.go @@ -25,7 +25,6 @@ import ( "golang.org/x/sys/windows" "path/filepath" "strconv" - "strings" "sync" "time" @@ -266,7 +265,7 @@ func (s *snapshotter) FindModule(addr va.Address) (bool, *pstypes.Module) { return false, nil } -func (s *snapshotter) AddFileMapping(e *kevent.Kevent) error { +func (s *snapshotter) AddMmap(e *kevent.Kevent) error { s.mu.Lock() defer s.mu.Unlock() proc, ok := s.procs[e.PID] @@ -274,24 +273,21 @@ func (s *snapshotter) AddFileMapping(e *kevent.Kevent) error { return nil } - filename := e.GetParamAsString(kparams.FilePath) - ext := strings.ToLower(filepath.Ext(filename)) - // skip redundant or unneeded memory-mapped files - if ext == ".dll" || ext == ".exe" || ext == ".mui" { - return nil - } mmapCount.Add(1) + mmap := pstypes.Mmap{} - mmap.File = filename + mmap.File = e.GetParamAsString(kparams.FilePath) mmap.BaseAddress = e.Kparams.TryGetAddress(kparams.FileViewBase) mmap.Size, _ = e.Kparams.GetUint64(kparams.FileViewSize) + mmap.Protection, _ = e.Kparams.GetUint32(kparams.MemProtect) + mmap.Type = e.GetParamAsString(kparams.FileViewSectionType) - proc.MapFile(mmap) + proc.AddMmap(mmap) return nil } -func (s *snapshotter) RemoveFileMapping(pid uint32, addr va.Address) error { +func (s *snapshotter) RemoveMmap(pid uint32, addr va.Address) error { s.mu.Lock() defer s.mu.Unlock() proc, ok := s.procs[pid] @@ -299,7 +295,7 @@ func (s *snapshotter) RemoveFileMapping(pid uint32, addr va.Address) error { return nil } mmapCount.Add(-1) - proc.UnmapFile(addr) + proc.RemoveMmap(addr) return nil } diff --git a/pkg/ps/types/types_windows.go b/pkg/ps/types/types_windows.go index 85c35f3fb..619e58ba5 100644 --- a/pkg/ps/types/types_windows.go +++ b/pkg/ps/types/types_windows.go @@ -67,8 +67,8 @@ type PS struct { Threads map[uint32]Thread `json:"-"` // Modules contains all the modules loaded by the process. Modules []Module `json:"modules"` - // FileMappings contains all memory-mapped data files. - FileMappings []Mmap + // Mmaps contains all memory mappings. + Mmaps []Mmap // Handles represents the collection of handles allocated by the process. Handles htypes.Handles `json:"handles"` // PE stores the PE (Portable Executable) metadata. @@ -333,28 +333,36 @@ func (m Module) String() string { // IsExecutable determines if the loaded module is an executable. func (m Module) IsExecutable() bool { return strings.ToLower(filepath.Ext(m.Name)) == ".exe" } -// Mmap stores information of the memory-mapped file. +// Mmap stores information related to the memory mapping. type Mmap struct { - File string + // BaseAddress represents the address where the view of section is mapped. BaseAddress va.Address - Size uint64 + // Size indicates the size of the mapped view of section. + Size uint64 + // Protection is the bitmask with view protection rights. + Protection uint32 + // Type represents the type of the view of section (e.g. IMAGE, DATA, PAGEFILE) + Type string + // File if the view is backed by the file object, this field indicates + // the file path of the mapped image/data file. + File string } // New produces a new process state. func New(pid, ppid uint32, name, cmndline, exe string, sid *windows.SID, sessionID uint32) *PS { ps := &PS{ - PID: pid, - Ppid: ppid, - Name: name, - Cmdline: cmndline, - Exe: exe, - Args: cmdline.Split(cmndline), - SID: sid.String(), - SessionID: sessionID, - Threads: make(map[uint32]Thread), - Modules: make([]Module, 0), - Handles: make([]htypes.Handle, 0), - FileMappings: make([]Mmap, 0), + PID: pid, + Ppid: ppid, + Name: name, + Cmdline: cmndline, + Exe: exe, + Args: cmdline.Split(cmndline), + SID: sid.String(), + SessionID: sessionID, + Threads: make(map[uint32]Thread), + Modules: make([]Module, 0), + Handles: make([]htypes.Handle, 0), + Mmaps: make([]Mmap, 0), } ps.Username, ps.Domain, _, _ = sid.LookupAccount("") return ps @@ -363,12 +371,12 @@ func New(pid, ppid uint32, name, cmndline, exe string, sid *windows.SID, session // NewFromKcap reconstructs the state of the process from the capture file. func NewFromKcap(buf []byte, sec section.Section) (*PS, error) { ps := PS{ - Args: make([]string, 0), - Envs: make(map[string]string), - Handles: make([]htypes.Handle, 0), - Modules: make([]Module, 0), - Threads: make(map[uint32]Thread), - FileMappings: make([]Mmap, 0), + Args: make([]string, 0), + Envs: make(map[string]string), + Handles: make([]htypes.Handle, 0), + Modules: make([]Module, 0), + Threads: make(map[uint32]Thread), + Mmaps: make([]Mmap, 0), } if err := ps.Unmarshal(buf, sec); err != nil { return nil, err @@ -445,28 +453,27 @@ func (ps *PS) FindModuleByVa(addr va.Address) *Module { return nil } -// MapFile adds a new data-mapped file this process state. -func (ps *PS) MapFile(mmap Mmap) { - ps.FileMappings = append(ps.FileMappings, mmap) +// AddMmap adds a new memory mapping for this process state. +func (ps *PS) AddMmap(mmap Mmap) { + ps.Mmaps = append(ps.Mmaps, mmap) } -// UnmapFile removes a specified data-mapped file from this process state. -func (ps *PS) UnmapFile(addr va.Address) { - for i, mmap := range ps.FileMappings { +// RemoveMmap removes the memory mapping at the specified address. +func (ps *PS) RemoveMmap(addr va.Address) { + for i, mmap := range ps.Mmaps { if mmap.BaseAddress == addr { - ps.FileMappings = append(ps.FileMappings[:i], ps.FileMappings[i+1:]...) + ps.Mmaps = append(ps.Mmaps[:i], ps.Mmaps[i+1:]...) break } } } -// FindMappingByVa finds the memory-mapped file -// by probing the range of the given virtual address. -func (ps *PS) FindMappingByVa(addr va.Address) string { - for _, mmap := range ps.FileMappings { - if addr >= mmap.BaseAddress && addr <= mmap.BaseAddress.Inc(mmap.Size) { - return mmap.File +// FindMmap returns the memory mapping by the given address. +func (ps *PS) FindMmap(addr va.Address) *Mmap { + for _, mmap := range ps.Mmaps { + if mmap.BaseAddress == addr { + return &mmap } } - return "unbacked" + return nil } diff --git a/pkg/symbolize/symbolizer.go b/pkg/symbolize/symbolizer.go index c0bdf0c95..c0f830ecf 100644 --- a/pkg/symbolize/symbolizer.go +++ b/pkg/symbolize/symbolizer.go @@ -396,9 +396,6 @@ func (s *Symbolizer) produceFrame(addr va.Address, e *kevent.Kevent, fast, looku if mod != nil { frame.Module = mod.Name } - if frame.Module == "unbacked" || frame.Module == "" { - frame.Module = e.PS.FindMappingByVa(addr) - } if lookupExport { frame.Symbol = s.resolveSymbolFromExportDirectory(addr, mod) } @@ -493,9 +490,6 @@ func (s *Symbolizer) produceFrame(addr va.Address, e *kevent.Kevent, fast, looku if frame.Module == "" { mod := s.r.GetModuleName(proc.handle, addr) - if mod == "?" && e.PS != nil { - mod = e.PS.FindMappingByVa(addr) - } frame.Module = mod if frame.Module == "?" { frame.Module = "unbacked"