modules.processing.platform.linux

Package modules :: Package processing :: Package platform :: Module linux |
[hide private]
[frames] | no frames]

# Source Code for Module modules.processing.platform.linux

      1  # Copyright (C) 2010-2013 Claudio Guarnieri.
      2  # Copyright (C) 2014-2016 Cuckoo Foundation.
      3  # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org
      4  # See the file 'docs/LICENSE' for copying permission.
      5
      6  import os
      7  import logging
      8  import datetime
      9  import re
     10
     11  import dateutil.parser
     12
     13  from lib.cuckoo.common.abstracts import BehaviorHandler
     14
     15  log = logging.getLogger(__name__)
     16
     17 -class FilteredProcessLog(list):
     18 -    def __init__(self, eventstream, **kwfilters):
     19          self.eventstream = eventstream
     20          self.kwfilters = kwfilters
     21
     22 -    def __iter__(self):
     23          for event in self.eventstream:
     24              for k, v in self.kwfilters.items():
     25                  if event[k] != v:
     26                      continue
     27
     28                  del event["type"]
     29                  yield event
     30
     31 -    def __nonzero__(self):
     32          return True
     33
     34 -class LinuxSystemTap(BehaviorHandler):
     35      """Parses systemtap generated plaintext logs (see data/strace.stp)."""
     36
     37      key = "processes"
     38
     39 -    def __init__(self, *args, **kwargs):
     40          super(LinuxSystemTap, self).__init__(*args, **kwargs)
     41
     42          self.processes = []
     43          self.pids_seen = set()
     44          self.forkmap = {}
     45          self.matched = False
     46
     47          self._check_for_probelkm()
     48
     49 -    def _check_for_probelkm(self):
     50          path_lkm = os.path.join(self.analysis.logs_path, "all.lkm")
     51          if os.path.exists(path_lkm):
     52              lines = open(path_lkm).readlines()
     53
     54              forks = [re.findall("task (\d+)@0x[0-9a-f]+ forked to (\d+)@0x[0-9a-f]+", line) for line in lines]
     55              self.forkmap = dict((j, i) for i, j in reduce(lambda x, y: x+y, forks, []))
     56
     57              # self.results["source"].append("probelkm")
     58
     59 -    def handles_path(self, path):
     60          if path.endswith(".stap"):
     61              self.matched = True
     62              return True
     63
     64 -    def parse(self, path):
     65          parser = StapParser(open(path))
     66
     67          for event in parser:
     68              pid = event["pid"]
     69              if pid not in self.pids_seen:
     70                  self.pids_seen.add(pid)
     71                  ppid = self.forkmap.get(pid, -1)
     72
     73                  process = {
     74                      "pid": pid,
     75                      "ppid": ppid,
     76                      "process_name": event["process_name"],
     77                      "first_seen": event["time"],
     78                  }
     79
     80                  # create a process event as we don't have those with linux+systemtap
     81                  pevent = dict(process)
     82                  pevent["type"] = "process"
     83                  yield pevent
     84
     85                  process["calls"] = FilteredProcessLog(parser, pid=pid)
     86                  self.processes.append(process)
     87
     88              yield event
     89
     90 -    def run(self):
     91          if not self.matched:
     92              return
     93
     94          self.processes.sort(key=lambda process: process["first_seen"])
     95          return self.processes
     96
     97 -class StapParser(object):
     98      """Handle .stap logs from the Linux analyzer."""
     99
    100 -    def __init__(self, fd):
    101          self.fd = fd
    102
    103 -    def __iter__(self):
    104          self.fd.seek(0)
    105
    106          for line in self.fd:
    107              # 'Thu May  7 14:58:43 2015.390178 python@7f798cb95240[2114] close(6) = 0\n'
    108              # datetime is 31 characters
    109              datetimepart, rest = line[:31], line[32:]
    110
    111              # incredibly sophisticated date time handling
    112              dtms = datetime.timedelta(0, 0, int(datetimepart.split(".", 1)[1]))
    113              dt = dateutil.parser.parse(datetimepart.split(".", 1)[0]) + dtms
    114
    115              parts = re.match("^(.+)@([a-f0-9]+)\[(\d+)\] (\w+)\((.*)\) = (\S+){0,1}\s{0,1}(\(\w+\)){0,1}$", rest)
    116              if not parts:
    117                  log.warning("Could not parse syscall trace line: %s", line)
    118                  continue
    119
    120              pname, ip, pid, fn, arguments, retval, ecode = parts.groups()
    121              argsplit = arguments.split(", ")
    122              arguments = dict(("p%u" % pos, argsplit[pos]) for pos in range(len(argsplit)))
    123
    124              pid = int(pid) if pid.isdigit() else -1
    125
    126              yield {
    127                  "time": dt, "process_name": pname, "pid": pid,
    128                  "instruction_pointer": ip, "api": fn, "arguments": arguments,
    129                  "return_value": retval, "status": ecode,
    130                  "type": "apicall", "raw": line,
    131              }
    132