forked from hillu/go-yara
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathsimple-yara.go
149 lines (139 loc) · 3.23 KB
/
simple-yara.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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package main
import (
"github.com/VirusTotal/go-yara/v4"
"bytes"
"flag"
"fmt"
"log"
"os"
"path/filepath"
"strconv"
"sync"
)
func printMatches(item string, m []yara.MatchRule, err error) {
if err != nil {
log.Printf("%s: error: %s", item, err)
return
}
if len(m) == 0 {
log.Printf("%s: no matches", item)
return
}
buf := &bytes.Buffer{}
fmt.Fprintf(buf, "%s: [", item)
for i, match := range m {
if i > 0 {
fmt.Fprint(buf, ", ")
}
fmt.Fprintf(buf, "%s:%s", match.Namespace, match.Rule)
}
fmt.Fprint(buf, "]")
log.Print(buf.String())
}
func main() {
var (
rules rules
vars variables
processScan bool
pids []int
threads int
)
flag.BoolVar(&processScan, "processes", false, "scan processes instead of files")
flag.Var(&rules, "rule", "add rules in source form: [namespace:]filename")
flag.Var(&vars, "define", "define variable referenced n ruleset")
flag.IntVar(&threads, "threads", 1, "use specified number of threads")
flag.Parse()
if len(rules) == 0 {
flag.Usage()
log.Fatal("no rules specified")
}
args := flag.Args()
if len(args) == 0 {
flag.Usage()
log.Fatal("no files or processes specified")
}
if processScan {
for _, arg := range args {
if pid, err := strconv.Atoi(arg); err != nil {
log.Fatalf("Could not parse %s ad number", arg)
} else {
pids = append(pids, pid)
}
}
}
c, err := yara.NewCompiler()
if err != nil {
log.Fatalf("Failed to initialize YARA compiler: %s", err)
}
for id, value := range vars {
if err := c.DefineVariable(id, value); err != nil {
log.Fatal("failed to define variable '%s': %s", id, err)
}
}
for _, rule := range rules {
f, err := os.Open(rule.filename)
if err != nil {
log.Fatalf("Could not open rule file %s: %s", rule.filename, err)
}
err = c.AddFile(f, rule.namespace)
f.Close()
if err != nil {
log.Fatalf("Could not parse rule file %s: %s", rule.filename, err)
}
}
r, err := c.GetRules()
if err != nil {
log.Fatalf("Failed to compile rules: %s", err)
}
wg := sync.WaitGroup{}
wg.Add(threads)
if processScan {
c := make(chan int, threads)
for i := 0; i < threads; i++ {
s, _ := yara.NewScanner(r)
go func(c chan int, tid int) {
for pid := range c {
var m yara.MatchRules
log.Printf("<%02d> Scanning process %d...", tid, pid)
err := s.SetCallback(&m).ScanProc(pid)
printMatches(fmt.Sprintf("<pid %d", pid), m, err)
}
wg.Done()
}(c, i)
}
for _, pid := range pids {
c <- pid
}
close(c)
} else {
c := make(chan string, threads)
for i := 0; i < threads; i++ {
s, _ := yara.NewScanner(r)
go func(c chan string, tid int) {
for filename := range c {
var m yara.MatchRules
log.Printf("<%02d> Scanning file %s... ", tid, filename)
err := s.SetCallback(&m).ScanFile(filename)
printMatches(filename, m, err)
}
wg.Done()
}(c, i)
}
for _, path := range args {
if err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
if info.Mode().IsRegular() {
c <- path
} else if info.Mode().IsDir() {
return nil
} else {
log.Printf("Sipping %s", path)
}
return nil
}); err != nil {
log.Printf("walk: %s: %s", path, err)
}
}
close(c)
}
wg.Wait()
}