LEFT | RIGHT |
1 # -*- coding: utf-8 -*- | 1 # -*- coding: utf-8 -*- |
2 """Parser for Windows Scheduled Task job files.""" | 2 """Parser for Windows Scheduled Task job files.""" |
3 | 3 |
4 from __future__ import unicode_literals | 4 from __future__ import unicode_literals |
5 | |
6 import os | |
7 | 5 |
8 from dfdatetime import definitions as dfdatetime_definitions | 6 from dfdatetime import definitions as dfdatetime_definitions |
9 from dfdatetime import systemtime as dfdatetime_systemtime | 7 from dfdatetime import systemtime as dfdatetime_systemtime |
10 from dfdatetime import time_elements as dfdatetime_time_elements | 8 from dfdatetime import time_elements as dfdatetime_time_elements |
11 | |
12 from dtfabric.runtime import fabric as dtfabric_fabric | |
13 | 9 |
14 from plaso.containers import events | 10 from plaso.containers import events |
15 from plaso.containers import time_events | 11 from plaso.containers import time_events |
16 from plaso.lib import errors | 12 from plaso.lib import errors |
17 from plaso.lib import definitions | 13 from plaso.lib import definitions |
18 from plaso.parsers import data_formats | 14 from plaso.parsers import dtfabric_parser |
19 from plaso.parsers import manager | 15 from plaso.parsers import manager |
20 | 16 |
21 | 17 |
22 class WinJobEventData(events.EventData): | 18 class WinJobEventData(events.EventData): |
23 """Windows Scheduled Task event data. | 19 """Windows Scheduled Task event data. |
24 | 20 |
25 Attributes: | 21 Attributes: |
26 application (str): path to job executable. | 22 application (str): path to job executable. |
27 description (str): description of the scheduled task. | 23 description (str): description of the scheduled task. |
28 parameters (str): application command line parameters. | 24 parameters (str): application command line parameters. |
29 trigger_type (int): trigger type. | 25 trigger_type (int): trigger type. |
30 username (str): username that scheduled the task. | 26 username (str): username that scheduled the task. |
31 working_directory (str): working directory of the scheduled task. | 27 working_directory (str): working directory of the scheduled task. |
32 """ | 28 """ |
33 | 29 |
34 DATA_TYPE = 'windows:tasks:job' | 30 DATA_TYPE = 'windows:tasks:job' |
35 | 31 |
36 def __init__(self): | 32 def __init__(self): |
37 """Initializes event data.""" | 33 """Initializes event data.""" |
38 super(WinJobEventData, self).__init__(data_type=self.DATA_TYPE) | 34 super(WinJobEventData, self).__init__(data_type=self.DATA_TYPE) |
39 self.application = None | 35 self.application = None |
40 self.comment = None | 36 self.comment = None |
41 self.parameters = None | 37 self.parameters = None |
42 self.trigger_type = None | 38 self.trigger_type = None |
43 self.username = None | 39 self.username = None |
44 self.working_directory = None | 40 self.working_directory = None |
45 | 41 |
46 | 42 |
47 class WinJobParser(data_formats.DataFormatParser): | 43 class WinJobParser(dtfabric_parser.DtFabricBaseParser): |
48 """Parse Windows Scheduled Task files for job events.""" | 44 """Parse Windows Scheduled Task files for job events.""" |
49 | 45 |
50 NAME = 'winjob' | 46 NAME = 'winjob' |
51 DESCRIPTION = 'Parser for Windows Scheduled Task job (or At-job) files.' | 47 DESCRIPTION = 'Parser for Windows Scheduled Task job (or At-job) files.' |
52 | 48 |
53 _DATA_TYPE_FABRIC_DEFINITION_FILE = os.path.join( | 49 _DEFINITION_FILE = 'winjob.yaml' |
54 os.path.dirname(__file__), 'winjob.yaml') | |
55 | |
56 with open(_DATA_TYPE_FABRIC_DEFINITION_FILE, 'rb') as file_object: | |
57 _DATA_TYPE_FABRIC_DEFINITION = file_object.read() | |
58 | |
59 _DATA_TYPE_FABRIC = dtfabric_fabric.DataTypeFabric( | |
60 yaml_definition=_DATA_TYPE_FABRIC_DEFINITION) | |
61 | |
62 _FIXED_LENGTH_DATA_SECTION = _DATA_TYPE_FABRIC.CreateDataTypeMap( | |
63 'job_fixed_length_data_section') | |
64 | |
65 _FIXED_LENGTH_DATA_SECTION_SIZE = _FIXED_LENGTH_DATA_SECTION.GetByteSize() | |
66 | |
67 _VARIABLE_LENGTH_DATA_SECTION = _DATA_TYPE_FABRIC.CreateDataTypeMap( | |
68 'job_variable_length_data_section') | |
69 | 50 |
70 _EMPTY_SYSTEM_TIME_TUPLE = (0, 0, 0, 0, 0, 0, 0, 0) | 51 _EMPTY_SYSTEM_TIME_TUPLE = (0, 0, 0, 0, 0, 0, 0, 0) |
71 | 52 |
72 _PRODUCT_VERSIONS = { | 53 _PRODUCT_VERSIONS = { |
73 0x0400: 'Windows NT 4.0', | 54 0x0400: 'Windows NT 4.0', |
74 0x0500: 'Windows 2000', | 55 0x0500: 'Windows 2000', |
75 0x0501: 'Windows XP', | 56 0x0501: 'Windows XP', |
76 0x0600: 'Windows Vista', | 57 0x0600: 'Windows Vista', |
77 0x0601: 'Windows 7', | 58 0x0601: 'Windows 7', |
78 0x0602: 'Windows 8', | 59 0x0602: 'Windows 8', |
79 0x0603: 'Windows 8.1', | 60 0x0603: 'Windows 8.1', |
80 0x0a00: 'Windows 10', | 61 0x0a00: 'Windows 10', |
81 } | 62 } |
82 | 63 |
83 def _ParseEventData(self, variable_length_section): | 64 def _ParseEventData(self, variable_length_section): |
84 """Parses the event data form a variable-length data section. | 65 """Parses the event data form a variable-length data section. |
85 | 66 |
86 Args: | 67 Args: |
87 variable_length_section (job_fixed_length_data_section): a variable-length | 68 variable_length_section (job_fixed_length_data_section): a variable-length |
88 data section. | 69 data section. |
89 | 70 |
90 Returns: | 71 Returns: |
91 WinJobEventData: event data of the job file. | 72 WinJobEventData: event data of the job file. |
92 """ | 73 """ |
93 event_data = WinJobEventData() | 74 event_data = WinJobEventData() |
94 event_data.application = ( | 75 event_data.application = ( |
95 variable_length_section.application_name.string.rstrip('\x00')) | 76 variable_length_section.application_name.rstrip('\x00')) |
96 event_data.comment = variable_length_section.comment.string.rstrip('\x00') | 77 event_data.comment = variable_length_section.comment.rstrip('\x00') |
97 event_data.parameters = ( | 78 event_data.parameters = ( |
98 variable_length_section.parameters.string.rstrip('\x00')) | 79 variable_length_section.parameters.rstrip('\x00')) |
99 event_data.username = variable_length_section.author.string.rstrip('\x00') | 80 event_data.username = variable_length_section.author.rstrip('\x00') |
100 event_data.working_directory = ( | 81 event_data.working_directory = ( |
101 variable_length_section.working_directory.string.rstrip('\x00')) | 82 variable_length_section.working_directory.rstrip('\x00')) |
102 | 83 |
103 return event_data | 84 return event_data |
104 | 85 |
105 def _ParseLastRunTime(self, parser_mediator, fixed_length_section): | 86 def _ParseLastRunTime(self, parser_mediator, fixed_length_section): |
106 """Parses the last run time from a fixed-length data section. | 87 """Parses the last run time from a fixed-length data section. |
107 | 88 |
108 Args: | 89 Args: |
109 parser_mediator (ParserMediator): mediates interactions between parsers | 90 parser_mediator (ParserMediator): mediates interactions between parsers |
110 and other components, such as storage and dfvfs. | 91 and other components, such as storage and dfvfs. |
111 fixed_length_section (job_fixed_length_data_section): a fixed-length | 92 fixed_length_section (job_fixed_length_data_section): a fixed-length |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
198 """Parses a Windows job file-like object. | 179 """Parses a Windows job file-like object. |
199 | 180 |
200 Args: | 181 Args: |
201 parser_mediator (ParserMediator): mediates interactions between parsers | 182 parser_mediator (ParserMediator): mediates interactions between parsers |
202 and other components, such as storage and dfvfs. | 183 and other components, such as storage and dfvfs. |
203 file_object (dfvfs.FileIO): a file-like object. | 184 file_object (dfvfs.FileIO): a file-like object. |
204 | 185 |
205 Raises: | 186 Raises: |
206 UnableToParseFile: when the file cannot be parsed. | 187 UnableToParseFile: when the file cannot be parsed. |
207 """ | 188 """ |
208 file_offset = 0 | 189 fixed_section_data_map = self._GetDataTypeMap( |
| 190 'job_fixed_length_data_section') |
209 | 191 |
210 try: | 192 try: |
211 fixed_length_section = self._ReadStructure( | 193 fixed_length_section, file_offset = self._ReadStructureFromFileObject( |
212 file_object, file_offset, self._FIXED_LENGTH_DATA_SECTION_SIZE, | 194 file_object, 0, fixed_section_data_map) |
213 self._FIXED_LENGTH_DATA_SECTION, 'fixed-length data section') | |
214 except (ValueError, errors.ParseError) as exception: | 195 except (ValueError, errors.ParseError) as exception: |
215 raise errors.UnableToParseFile( | 196 raise errors.UnableToParseFile( |
216 'Unable to parse fixed-length data section with error: {0!s}'.format( | 197 'Unable to parse fixed-length data section with error: {0!s}'.format( |
217 exception)) | 198 exception)) |
218 | 199 |
219 if not fixed_length_section.product_version in self._PRODUCT_VERSIONS: | 200 if not fixed_length_section.product_version in self._PRODUCT_VERSIONS: |
220 raise errors.UnableToParseFile( | 201 raise errors.UnableToParseFile( |
221 'Unsupported product version in: 0x{0:04x}'.format( | 202 'Unsupported product version in: 0x{0:04x}'.format( |
222 fixed_length_section.product_version)) | 203 fixed_length_section.product_version)) |
223 | 204 |
224 if not fixed_length_section.format_version == 1: | 205 if not fixed_length_section.format_version == 1: |
225 raise errors.UnableToParseFile( | 206 raise errors.UnableToParseFile( |
226 'Unsupported format version in: {0:d}'.format( | 207 'Unsupported format version in: {0:d}'.format( |
227 fixed_length_section.format_version)) | 208 fixed_length_section.format_version)) |
228 | 209 |
229 file_offset += self._FIXED_LENGTH_DATA_SECTION_SIZE | 210 variable_section_data_map = self._GetDataTypeMap( |
230 data_size = file_object.get_size() - file_offset | 211 'job_variable_length_data_section') |
231 | 212 |
232 try: | 213 try: |
233 variable_length_section = self._ReadStructure( | 214 variable_length_section, data_size = self._ReadStructureFromFileObject( |
234 file_object, file_offset, data_size, | 215 file_object, file_offset, variable_section_data_map) |
235 self._VARIABLE_LENGTH_DATA_SECTION, 'variable-length data section') | |
236 except (ValueError, errors.ParseError) as exception: | 216 except (ValueError, errors.ParseError) as exception: |
237 raise errors.UnableToParseFile(( | 217 raise errors.UnableToParseFile(( |
238 'Unable to parse variable-length data section with error: ' | 218 'Unable to parse variable-length data section with error: ' |
239 '{0!s}').format(exception)) | 219 '{0!s}').format(exception)) |
| 220 |
| 221 file_offset += data_size |
240 | 222 |
241 event_data = self._ParseEventData(variable_length_section) | 223 event_data = self._ParseEventData(variable_length_section) |
242 | 224 |
243 date_time = self._ParseLastRunTime(parser_mediator, fixed_length_section) | 225 date_time = self._ParseLastRunTime(parser_mediator, fixed_length_section) |
244 if date_time: | 226 if date_time: |
245 event = time_events.DateTimeValuesEvent( | 227 event = time_events.DateTimeValuesEvent( |
246 date_time, definitions.TIME_DESCRIPTION_LAST_RUN) | 228 date_time, definitions.TIME_DESCRIPTION_LAST_RUN) |
247 parser_mediator.ProduceEventWithEventData(event, event_data) | 229 parser_mediator.ProduceEventWithEventData(event, event_data) |
248 | 230 |
249 for trigger in variable_length_section.triggers.triggers_array: | 231 trigger_data_map = self._GetDataTypeMap('job_trigger') |
| 232 |
| 233 for trigger_index in range(0, variable_length_section.number_of_triggers): |
| 234 try: |
| 235 trigger, data_size = self._ReadStructureFromFileObject( |
| 236 file_object, file_offset, trigger_data_map) |
| 237 except (ValueError, errors.ParseError) as exception: |
| 238 raise errors.UnableToParseFile(( |
| 239 'Unable to parse trigger: {0:d} with error: {2!s}').format( |
| 240 trigger_index, exception)) |
| 241 |
| 242 file_offset += data_size |
| 243 |
250 event_data.trigger_type = trigger.trigger_type | 244 event_data.trigger_type = trigger.trigger_type |
251 | 245 |
252 date_time = self._ParseTriggerStartTime(parser_mediator, trigger) | 246 date_time = self._ParseTriggerStartTime(parser_mediator, trigger) |
253 if date_time: | 247 if date_time: |
254 event = time_events.DateTimeValuesEvent( | 248 event = time_events.DateTimeValuesEvent( |
255 date_time, 'Scheduled to start', time_zone=parser_mediator.timezone) | 249 date_time, 'Scheduled to start', time_zone=parser_mediator.timezone) |
256 parser_mediator.ProduceEventWithEventData(event, event_data) | 250 parser_mediator.ProduceEventWithEventData(event, event_data) |
257 | 251 |
258 date_time = self._ParseTriggerEndTime(parser_mediator, trigger) | 252 date_time = self._ParseTriggerEndTime(parser_mediator, trigger) |
259 if date_time: | 253 if date_time: |
260 event = time_events.DateTimeValuesEvent( | 254 event = time_events.DateTimeValuesEvent( |
261 date_time, 'Scheduled to end', time_zone=parser_mediator.timezone) | 255 date_time, 'Scheduled to end', time_zone=parser_mediator.timezone) |
262 parser_mediator.ProduceEventWithEventData(event, event_data) | 256 parser_mediator.ProduceEventWithEventData(event, event_data) |
263 | 257 |
264 # TODO: create a timeless event object if last_run_time and | 258 # TODO: create a timeless event object if last_run_time and |
265 # trigger_start_time are None? What should be the description of | 259 # trigger_start_time are None? What should be the description of |
266 # this event? | 260 # this event? |
267 | 261 |
268 | 262 |
269 manager.ParsersManager.RegisterParser(WinJobParser) | 263 manager.ParsersManager.RegisterParser(WinJobParser) |
LEFT | RIGHT |