-
Notifications
You must be signed in to change notification settings - Fork 12
/
processScanner.go
125 lines (105 loc) · 2.73 KB
/
processScanner.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package yapscan
import (
"io/ioutil"
"os"
"github.com/hillu/go-yara/v4"
"github.com/sirupsen/logrus"
"github.com/fkie-cad/yapscan/procIO"
"github.com/targodan/go-errors"
)
type MemoryScanner interface {
ScanMem(buf []byte) (results []yara.MatchRule, err error)
}
type ProcessScanner struct {
proc procIO.Process
filter MemorySegmentFilter
scanner MemoryScanner
}
func NewProcessScanner(proc procIO.Process, filter MemorySegmentFilter, scanner MemoryScanner) *ProcessScanner {
return &ProcessScanner{
proc: proc,
filter: filter,
scanner: scanner,
}
}
var ErrSkipped = errors.New("skipped")
type MemoryScanProgress struct {
Process procIO.Process
MemorySegment *procIO.MemorySegmentInfo
Dump []byte
Matches []yara.MatchRule
Error error
}
func (s *ProcessScanner) Scan() (<-chan *MemoryScanProgress, error) {
segments, err := s.proc.MemorySegments()
if err != nil {
logrus.WithFields(logrus.Fields{
"process": s.proc,
logrus.ErrorKey: err,
}).Error("Could not retrieve memory segments for process.")
return nil, err
}
progress := make(chan *MemoryScanProgress)
go func() {
defer close(progress)
for _, segment := range segments {
if len(segment.SubSegments) == 0 {
// Only scan leaf segments
matches, data, err := s.scanSegment(segment)
progress <- &MemoryScanProgress{
Process: s.proc,
MemorySegment: segment,
Dump: data,
Matches: matches,
Error: err,
}
if errors.Is(err, os.ErrPermission) {
return
}
}
for _, subSegment := range segment.SubSegments {
matches, data, err := s.scanSegment(subSegment)
progress <- &MemoryScanProgress{
Process: s.proc,
MemorySegment: subSegment,
Dump: data,
Matches: matches,
Error: err,
}
if errors.Is(err, os.ErrPermission) {
return
}
}
}
}()
return progress, nil
}
func (s *ProcessScanner) scanSegment(seg *procIO.MemorySegmentInfo) ([]yara.MatchRule, []byte, error) {
match := s.filter.Filter(seg)
if !match.Result {
logrus.WithFields(logrus.Fields{
"segment": seg,
"reason": match.Reason,
}).Debug("Memory segment skipped.")
return nil, nil, ErrSkipped
}
logrus.WithFields(logrus.Fields{
"segment": seg,
}).Info("Scanning memory segment.")
rdr, err := procIO.NewMemoryReader(s.proc, seg)
if err != nil {
return nil, nil, err
}
defer rdr.Close()
data, err := ioutil.ReadAll(rdr)
if err != nil {
logrus.WithFields(logrus.Fields{
"process": s.proc,
"segment": seg,
logrus.ErrorKey: err,
}).Error("Could not read memory of process.")
return nil, nil, err
}
matches, err := s.scanner.ScanMem(data)
return matches, data, err
}