Skip to content

Commit a60063a

Browse files
committed
Moved AMCache formatter to configuration log2timeline#444
1 parent 9d784fd commit a60063a

File tree

10 files changed

+145
-86
lines changed

10 files changed

+145
-86
lines changed

data/formatters.yaml

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Event formatters.
2+
3+
type: 'conditional'
4+
data_type: 'windows:registry:amcache'
5+
message:
6+
- 'path: {full_path}'
7+
- 'sha1: {sha1}'
8+
- 'productname: {productname}'
9+
- 'companyname: {companyname}'
10+
- 'fileversion: {fileversion}'
11+
- 'languagecode: {languagecode}'
12+
- 'filesize: {filesize}'
13+
- 'filedescription: {filedescription}'
14+
- 'linkerts: {linkerts}'
15+
- 'lastmodifiedts: {lastmodifiedts}'
16+
- 'createdts: {createdts}'
17+
- 'programid: {programid}'
18+
short_message:
19+
- 'path: {full_path}'
20+
short_source: 'AMCACHE'
21+
source: 'Amcache Registry Entry'
22+
---
23+
type: 'conditional'
24+
data_type: 'windows:registry:amcache:programs'
25+
message:
26+
- 'name: {name}'
27+
- 'version: {version}'
28+
- 'publisher: {publisher}'
29+
- 'languagecode: {languagecode}'
30+
- 'entrytype: {entrytype}'
31+
- 'uninstallkey: {uninstallkey}'
32+
- 'filepaths: {filepaths}'
33+
- 'productcode: {productcode}'
34+
- 'packagecode: {packagecode}'
35+
- 'msiproductcode: {msiproductcode}'
36+
- 'msipackagecode: {msipackagecode}'
37+
- 'files: {files}'
38+
short_message:
39+
- 'name: {name}'
40+
short_source: 'AMCACHEPROGRAM'
41+
source: 'Amcache Programs Registry Entry'

plaso/cli/extraction_tool.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ def _ReadParserPresetsFromFile(self):
238238
self._presets_manager.ReadFromFile(self._presets_file)
239239
except errors.MalformedPresetError as exception:
240240
raise errors.BadConfigOption(
241-
'Unable to read presets from file with error: {0!s}'.format(
241+
'Unable to read parser presets from file with error: {0!s}'.format(
242242
exception))
243243

244244
def _SetExtractionParsersAndPlugins(self, configuration, session):

plaso/cli/psort_tool.py

+26
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
from plaso.engine import engine
3030
from plaso.engine import knowledge_base
3131
from plaso.filters import event_filter
32+
from plaso.formatters import manager as formatters_manager
3233
from plaso.lib import errors
3334
from plaso.lib import loggers
3435
from plaso.lib import timelib
@@ -61,6 +62,8 @@ class PsortTool(
6162
'Application to read, filter and process output from a plaso storage '
6263
'file.')
6364

65+
_FORMATTERS_FILE_NAME = 'formatters.yaml'
66+
6467
def __init__(self, input_reader=None, output_writer=None):
6568
"""Initializes the CLI tool object.
6669
@@ -79,6 +82,7 @@ def __init__(self, input_reader=None, output_writer=None):
7982
self._deduplicate_events = True
8083
self._event_filter_expression = None
8184
self._event_filter = None
85+
self._formatters_file = None
8286
self._knowledge_base = knowledge_base.KnowledgeBase()
8387
self._number_of_analysis_reports = 0
8488
self._preferred_language = 'en-US'
@@ -284,6 +288,26 @@ def _PrintAnalysisReportsDetails(self, storage_reader):
284288

285289
table_view.Write(self._output_writer)
286290

291+
def _ReadEventFormattersFromFile(self):
292+
"""Reads the event formatters the formatters.yaml file.
293+
294+
Raises:
295+
BadConfigOption: if the event formatters file cannot be read.
296+
"""
297+
self._formatters_file = os.path.join(
298+
self._data_location, self._FORMATTERS_FILE_NAME)
299+
if not os.path.isfile(self._formatters_file):
300+
raise errors.BadConfigOption(
301+
'No such event formatters file: {0:s}.'.format(self._formatters_file))
302+
303+
try:
304+
formatters_manager.FormattersManager.ReadFormattersFromFile(
305+
self._formatters_file)
306+
except KeyError as exception:
307+
raise errors.BadConfigOption(
308+
'Unable to read event formatters from file with error: {0!s}'.format(
309+
exception))
310+
287311
def AddProcessingOptions(self, argument_group):
288312
"""Adds processing options to the argument group
289313
@@ -457,6 +481,8 @@ def ParseOptions(self, options):
457481
helpers_manager.ArgumentHelperManager.ParseOptions(
458482
options, self, names=['data_location'])
459483

484+
self._ReadEventFormattersFromFile()
485+
460486
self._ParseLogFileOptions(options)
461487

462488
self._ParseProcessingOptions(options)

plaso/cli/psteal_tool.py

+25
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from plaso.engine import engine
2424
from plaso.engine import knowledge_base
2525
from plaso.engine import single_process as single_process_engine
26+
from plaso.formatters import manager as formatters_manager
2627
from plaso.lib import errors
2728
from plaso.lib import loggers
2829
from plaso.multi_processing import psort
@@ -83,6 +84,8 @@ class PstealTool(
8384
'And that is how you build a timeline using psteal...',
8485
'']))
8586

87+
_FORMATTERS_FILE_NAME = 'formatters.yaml'
88+
8689
_SOURCE_TYPES_TO_PREPROCESS = frozenset([
8790
dfvfs_definitions.SOURCE_TYPE_DIRECTORY,
8891
dfvfs_definitions.SOURCE_TYPE_STORAGE_MEDIA_DEVICE,
@@ -103,6 +106,7 @@ def __init__(self, input_reader=None, output_writer=None):
103106
self._command_line_arguments = None
104107
self._deduplicate_events = True
105108
self._enable_sigsegv_handler = False
109+
self._formatters_file = None
106110
self._knowledge_base = knowledge_base.KnowledgeBase()
107111
self._number_of_analysis_reports = 0
108112
self._number_of_extraction_workers = 0
@@ -173,6 +177,26 @@ def _PrintAnalysisReportsDetails(
173177

174178
table_view.Write(self._output_writer)
175179

180+
def _ReadEventFormattersFromFile(self):
181+
"""Reads the event formatters the formatters.yaml file.
182+
183+
Raises:
184+
BadConfigOption: if the event formatters file cannot be read.
185+
"""
186+
self._formatters_file = os.path.join(
187+
self._data_location, self._FORMATTERS_FILE_NAME)
188+
if not os.path.isfile(self._formatters_file):
189+
raise errors.BadConfigOption(
190+
'No such event formatters file: {0:s}.'.format(self._formatters_file))
191+
192+
try:
193+
formatters_manager.FormattersManager.ReadFormattersFromFile(
194+
self._formatters_file)
195+
except KeyError as exception:
196+
raise errors.BadConfigOption(
197+
'Unable to read event formatters from file with error: {0!s}'.format(
198+
exception))
199+
176200
def AnalyzeEvents(self):
177201
"""Analyzes events from a plaso storage file and generate a report.
178202
@@ -452,6 +476,7 @@ def ParseOptions(self, options):
452476
options, self, names=['data_location'])
453477

454478
self._ReadParserPresetsFromFile()
479+
self._ReadEventFormattersFromFile()
455480

456481
# The output modules options are dependent on the preferred language
457482
# and preferred time zone options.

plaso/formatters/__init__.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# -*- coding: utf-8 -*-
22
"""This file contains an import statement for each formatter."""
33

4-
from plaso.formatters import amcache
54
from plaso.formatters import android_app_usage
65
from plaso.formatters import android_calls
76
from plaso.formatters import android_sms

plaso/formatters/amcache.py

-61
This file was deleted.

plaso/formatters/manager.py

+32-8
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from plaso.formatters import default
77
from plaso.formatters import logger
88
from plaso.lib import definitions
9+
from plaso.formatters import yaml_formatters_file
910

1011

1112
class FormattersManager(object):
@@ -15,6 +16,9 @@ class FormattersManager(object):
1516
_formatter_objects = {}
1617
_unformatted_attributes = {}
1718

19+
# Work-around to prevent the tests re-reading the formatters file.
20+
_file_was_read = False
21+
1822
@classmethod
1923
def DeregisterFormatter(cls, formatter_class):
2024
"""Deregisters a formatter class.
@@ -29,9 +33,8 @@ def DeregisterFormatter(cls, formatter_class):
2933
"""
3034
formatter_data_type = formatter_class.DATA_TYPE.lower()
3135
if formatter_data_type not in cls._formatter_classes:
32-
raise KeyError(
33-
'Formatter class not set for data type: {0:s}.'.format(
34-
formatter_class.DATA_TYPE))
36+
raise KeyError('Formatter class not set for data type: {0:s}.'.format(
37+
formatter_class.DATA_TYPE))
3538

3639
del cls._formatter_classes[formatter_data_type]
3740

@@ -57,8 +60,8 @@ def GetFormatterObject(cls, data_type):
5760
formatter_object = formatter_class()
5861

5962
if not formatter_object:
60-
logger.warning(
61-
'Using default formatter for data type: {0:s}'.format(data_type))
63+
logger.warning('Using default formatter for data type: {0:s}'.format(
64+
data_type))
6265
formatter_object = default.DefaultFormatter()
6366

6467
cls._formatter_objects[data_type] = formatter_object
@@ -124,6 +127,28 @@ def GetUnformattedAttributes(cls, event_data):
124127

125128
return unformatted_attributes
126129

130+
@classmethod
131+
def ReadFormattersFromFile(cls, path):
132+
"""Reads formatters from a file.
133+
134+
Args:
135+
path (str): path of file that contains the formatters configuration.
136+
137+
Raises:
138+
KeyError: if formatter class is already set for the corresponding
139+
data type.
140+
"""
141+
if not cls._file_was_read:
142+
formatters_file = yaml_formatters_file.YAMLFormattersFile()
143+
for formatter in formatters_file.ReadFromFile(path):
144+
# TODO: refactor RegisterFormatter to only use formatter objects.
145+
cls.RegisterFormatter(formatter)
146+
147+
data_type = formatter.DATA_TYPE.lower()
148+
cls._formatter_objects[data_type] = formatter
149+
150+
cls._file_was_read = True
151+
127152
@classmethod
128153
def RegisterFormatter(cls, formatter_class):
129154
"""Registers a formatter class.
@@ -139,9 +164,8 @@ def RegisterFormatter(cls, formatter_class):
139164
"""
140165
formatter_data_type = formatter_class.DATA_TYPE.lower()
141166
if formatter_data_type in cls._formatter_classes:
142-
raise KeyError((
143-
'Formatter class already set for data type: {0:s}.').format(
144-
formatter_class.DATA_TYPE))
167+
raise KeyError('Formatter class already set for data type: {0:s}.'.format(
168+
formatter_class.DATA_TYPE))
145169

146170
cls._formatter_classes[formatter_data_type] = formatter_class
147171

tests/formatters/yaml_formatters_file.py

+8-6
Original file line numberDiff line numberDiff line change
@@ -88,22 +88,24 @@ def testReadFormatterDefinition(self):
8888

8989
def testReadFromFileObject(self):
9090
"""Tests the _ReadFromFileObject function."""
91-
test_path = self._GetTestFilePath(['formatters', 'format_test.yaml'])
92-
self._SkipIfPathNotExists(test_path)
91+
test_file_path = self._GetTestFilePath(['formatters', 'format_test.yaml'])
92+
self._SkipIfPathNotExists(test_file_path)
9393

9494
test_formatters_file = yaml_formatters_file.YAMLFormattersFile()
95-
with io.open(test_path, 'r', encoding='utf-8') as file_object:
95+
96+
with io.open(test_file_path, 'r', encoding='utf-8') as file_object:
9697
formatters = list(test_formatters_file._ReadFromFileObject(file_object))
9798

9899
self.assertEqual(len(formatters), 1)
99100

100101
def testReadFromFile(self):
101102
"""Tests the ReadFromFile function."""
102-
test_path = self._GetTestFilePath(['formatters', 'format_test.yaml'])
103-
self._SkipIfPathNotExists(test_path)
103+
test_file_path = self._GetTestFilePath(['formatters', 'format_test.yaml'])
104+
self._SkipIfPathNotExists(test_file_path)
104105

105106
test_formatters_file = yaml_formatters_file.YAMLFormattersFile()
106-
formatters = test_formatters_file.ReadFromFile(test_path)
107+
108+
formatters = test_formatters_file.ReadFromFile(test_file_path)
107109

108110
self.assertEqual(len(formatters), 1)
109111

tests/parsers/amcache.py

+6-9
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,17 @@ def testParse(self):
3535
'is-f4510.tmp\\idafree50.tmp')
3636
self.assertEqual(event_data.full_path, expected_full_path)
3737

38-
expected_sha1 = '82274eef0911a948f91425f5e5b0e730517fe75e'
39-
self.assertEqual(event_data.sha1, expected_sha1)
38+
self.assertEqual(
39+
event_data.sha1, '82274eef0911a948f91425f5e5b0e730517fe75e')
4040

4141
event = events[1148]
4242

4343
event_data = self._GetEventDataOfEvent(storage_writer, event)
44+
self.assertEqual(event_data.name, 'FileInsight - File analysis tool')
45+
self.assertEqual(event_data.publisher, 'McAfee Inc.')
4446

45-
expected_program_name = 'FileInsight - File analysis tool'
46-
self.assertEqual(event_data.name, expected_program_name)
47-
48-
expected_publisher = 'McAfee Inc.'
49-
self.assertEqual(event_data.publisher, expected_publisher)
50-
51-
# TODO: add test for message string
47+
expected_message = 'name: FileInsight - File analysis tool'
48+
self._TestGetMessageStrings(event_data, expected_message, expected_message)
5249

5350
def testParseWithSystem(self):
5451
"""Tests the Parse function with a SYSTEM Registry file."""

0 commit comments

Comments
 (0)