forked from cuckoosandbox/cuckoo
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlinux.py
More file actions
130 lines (96 loc) · 4.03 KB
/
Copy pathlinux.py
File metadata and controls
130 lines (96 loc) · 4.03 KB
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
# Copyright (C) 2010-2015 Cuckoo Foundation.
# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org
# See the file 'docs/LICENSE' for copying permission.
import os
import logging
import datetime
import re
import dateutil.parser
from lib.cuckoo.common.abstracts import BehaviorHandler
log = logging.getLogger(__name__)
class FilteredProcessLog(list):
def __init__(self, eventstream, **kwfilters):
self.eventstream = eventstream
self.kwfilters = kwfilters
def __iter__(self):
for event in self.eventstream:
for k, v in self.kwfilters.items():
if event[k] != v:
continue
del event["type"]
yield event
def __nonzero__(self):
return True
class LinuxSystemTap(BehaviorHandler):
"""Parses systemtap generated plaintext logs (see data/strace.stp)."""
key = "processes"
def __init__(self, *args, **kwargs):
super(LinuxSystemTap, self).__init__(*args, **kwargs)
self.processes = []
self.pids_seen = set()
self.forkmap = {}
self.matched = False
self._check_for_probelkm()
def _check_for_probelkm(self):
path_lkm = os.path.join(self.analysis.logs_path, "all.lkm")
if os.path.exists(path_lkm):
lines = open(path_lkm).readlines()
forks = [re.findall("task (\d+)@0x[0-9a-f]+ forked to (\d+)@0x[0-9a-f]+", line) for line in lines]
self.forkmap = dict((j, i) for i, j in reduce(lambda x, y: x+y, forks, []))
# self.results["source"].append("probelkm")
def handles_path(self, path):
if path.endswith(".stap"):
self.matched = True
return True
def parse(self, path):
parser = StapParser(open(path))
for event in parser:
pid = event["pid"]
if pid not in self.pids_seen:
self.pids_seen.add(pid)
ppid = self.forkmap.get(pid, -1)
process = {
"pid": pid,
"ppid": ppid,
"process_name": event["process_name"],
"first_seen": event["time"],
}
# create a process event as we don't have those with linux+systemtap
pevent = dict(process)
pevent["type"] = "process"
yield pevent
process["calls"] = FilteredProcessLog(parser, pid=pid)
self.processes.append(process)
yield event
def run(self):
if not self.matched:
return
self.processes.sort(key=lambda process: process["first_seen"])
return self.processes
class StapParser(object):
"""Handle .stap logs from the Linux analyzer."""
def __init__(self, fd):
self.fd = fd
def __iter__(self):
self.fd.seek(0)
for line in self.fd:
# 'Thu May 7 14:58:43 2015.390178 python@7f798cb95240[2114] close(6) = 0\n'
# datetime is 31 characters
datetimepart, rest = line[:31], line[32:]
# incredibly sophisticated date time handling
dtms = datetime.timedelta(0, 0, int(datetimepart.split(".", 1)[1]))
dt = dateutil.parser.parse(datetimepart.split(".", 1)[0]) + dtms
parts = re.match("^(.+)@([a-f0-9]+)\[(\d+)\] (\w+)\((.*)\) = (\S+){0,1}\s{0,1}(\(\w+\)){0,1}$", rest)
if not parts:
log.warning("Could not parse syscall trace line: %s", line)
continue
pname, ip, pid, fn, arguments, retval, ecode = parts.groups()
argsplit = arguments.split(", ")
arguments = dict(("p%u" % pos, argsplit[pos]) for pos in range(len(argsplit)))
pid = int(pid) if pid.isdigit() else -1
yield {
"time": dt, "process_name": pname, "pid": pid,
"instruction_pointer": ip, "api": fn, "arguments": arguments,
"return_value": retval, "status": ecode,
"type": "apicall", "raw": line,
}