modules.processing.baseline

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

# Source Code for Module modules.processing.baseline

      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 json
      7  import logging
      8  import os.path
      9
     10  from lib.cuckoo.common.abstracts import Processing
     11
     12  log = logging.getLogger(__name__)
     13
     14 -class Baseline(Processing):
     15      """Reduces Baseline results from gathered information."""
     16      order = 2
     17
     18 -    def deep_tuple(self, o, bl=None):
     19          if isinstance(o, (tuple, list)):
     20              r = []
     21              for x in o:
     22                  r.append(self.deep_tuple(x))
     23              return tuple(r)
     24
     25          if isinstance(o, dict):
     26              r = []
     27              for k, v in sorted(o.items()):
     28                  if bl and k in bl:
     29                      continue
     30                  r.append((k, self.deep_tuple(v)))
     31              return tuple(r)
     32
     33          return o
     34
     35 -    def normalize(self, plugin, o):
     36          plugins = {
     37              "pslist": ["num_threads", "num_handles"],
     38          }
     39          return self.deep_tuple(o, plugins.get(plugin))
     40
     41 -    def memory(self, baseline, report):
     42          """Finds the differences between the analysis report and the baseline
     43          report. Puts the differences into the baseline part of the report and
     44          also marks the existing rows with a `class_` attribute."""
     45          results = {}
     46
     47          for plugin in baseline.keys() + report.keys():
     48              results[plugin] = {
     49                  "config": {},
     50                  "data": [],
     51              }
     52
     53          # TODO Support having more keys in one report than the other.
     54          for plugin in set(baseline.keys() + report.keys()):
     55              lr = [self.normalize(plugin, x) for x in report[plugin]["data"]]
     56              lb = [self.normalize(plugin, x) for x in baseline[plugin]["data"]]
     57              sr, sb = set(lr), set(lb)
     58
     59              # Baseline vs Analysis. These events were no longer present
     60              # after the analysis.
     61              for row in sb.difference(sr):
     62                  row = baseline[plugin]["data"][lb.index(row)]
     63                  row["class_"] = "warning"
     64                  results[plugin]["data"].append(row)
     65                  report[plugin]["data"].append(row)
     66
     67              # Analysis vs Baseline. These events were added during
     68              # the analysis.
     69              for row in sr.difference(sb):
     70                  row = report[plugin]["data"][lr.index(row)]
     71                  row["class_"] = "danger"
     72                  results[plugin]["data"].append(row)
     73
     74          return results
     75
     76 -    def store_baseline(self, machine, baseline):
     77          """Store a new baseline report for a particular VM."""
     78          results = {
     79              "memory": self.results.get("memory", {}),
     80          }
     81
     82          with open(baseline, "wb") as report:
     83              json.dump(results, report, indent=4, encoding="latin-1")
     84
     85 -    def run(self):
     86          self.key = "baseline"
     87
     88          machine = self.results.get("info", {}).get("machine", {})
     89          if not machine or not machine.get("name"):
     90              log.warning("Unable to run baseline processing module as we did "
     91                          "not find the name of the Virtual Machine.")
     92              return
     93
     94          machine = machine["name"]
     95          baseline = os.path.join(self.baseline_path, "%s.json" % machine)
     96
     97          # If this task has the baseline category then we're creating a new
     98          # baseline report for a VM (and store it right away).
     99          if self.task["category"] == "baseline":
    100              self.store_baseline(machine, baseline)
    101              return
    102
    103          if not os.path.exists(baseline):
    104              log.info("Could not find a baseline report for machine '%s', "
    105                       "skipping it.", machine)
    106              return
    107
    108          try:
    109              self.baseline = json.load(open(baseline, "rb"))
    110          except Exception as e:
    111              log.warning("Baseline report for machine '%s' seems corrupted, "
    112                          "skipping baseline processing: %s.", machine, e)
    113              return
    114
    115          results = {}
    116
    117          if "memory" in self.results:
    118              results["memory"] = \
    119                  self.memory(self.baseline["memory"], self.results["memory"])
    120
    121          return results
    122