def ParseRow(self, parser_mediator, query, row, **unused_kwargs): """Parses a row from the database. Args: parser_mediator (ParserMediator): mediates interactions between parsers and other components, such as storage and dfvfs. query (str): query that created the row. row (sqlite3.Row): row. """ query_hash = hash(query) event_data = AndroidWebViewCacheEventData() event_data.content_length = self._GetRowValue(query_hash, row, 'contentlength') event_data.query = query event_data.url = self._GetRowValue(query_hash, row, 'url') timestamp = self._GetRowValue(query_hash, row, 'expires') if timestamp is not None: date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp) event = time_events.DateTimeValuesEvent( date_time, definitions.TIME_DESCRIPTION_EXPIRATION) parser_mediator.ProduceEventWithEventData(event, event_data) timestamp = self._GetRowValue(query_hash, row, 'lastmodify') if timestamp is not None: date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp) event = time_events.DateTimeValuesEvent( date_time, definitions.TIME_DESCRIPTION_MODIFICATION) parser_mediator.ProduceEventWithEventData(event, event_data)
def ParseMessageRow(self, parser_mediator, query, row, **unused_kwargs): """Parses a message row from the database. Args: parser_mediator (ParserMediator): mediates interactions between parsers and other components, such as storage and dfvfs. query (str): query that created the row. row (sqlite3.Row): row resulting from query. """ query_hash = hash(query) event_data = TangoAndroidMessageEventData() event_data.message_identifier = self._GetRowValue( query_hash, row, 'msg_id') # TODO: payload is a base64 encoded binary blob, we need to find the # structure to extract the relevant bits. # event_data.payload = self._GetRowValue(query_hash, row, 'payload') event_data.direction = self._GetRowValue(query_hash, row, 'direction') timestamp = self._GetRowValue(query_hash, row, 'create_time') if timestamp: date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp) event = time_events.DateTimeValuesEvent( date_time, definitions.TIME_DESCRIPTION_CREATION) parser_mediator.ProduceEventWithEventData(event, event_data) timestamp = self._GetRowValue(query_hash, row, 'send_time') if timestamp: date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp) event = time_events.DateTimeValuesEvent( date_time, definitions.TIME_DESCRIPTION_SENT) parser_mediator.ProduceEventWithEventData(event, event_data)
def testProperties(self): """Tests the properties.""" java_time_object = java_time.JavaTime(timestamp=1281643591546) self.assertEqual(java_time_object.timestamp, 1281643591546) java_time_object = java_time.JavaTime() self.assertIsNone(java_time_object.timestamp)
def ParseRow(self, parser_mediator, row, query=None, **unused_kwargs): """Parses a row from the database. Args: parser_mediator (ParserMediator): mediates interactions between parsers and other components, such as storage and dfvfs. row (sqlite3.Row): row. query (Optional[str]): query. """ # Note that pysqlite does not accept a Unicode string in row['string'] # and will raise "IndexError: Index must be int or string". All indexes are # thus raw strings. event_data = AndroidWebViewCacheEventData() event_data.content_length = row['contentlength'] event_data.query = query event_data.url = row['url'] if row['expires'] is not None: date_time = dfdatetime_java_time.JavaTime(timestamp=row['expires']) event = time_events.DateTimeValuesEvent( date_time, definitions.TIME_DESCRIPTION_EXPIRATION) parser_mediator.ProduceEventWithEventData(event, event_data) if row['lastmodify'] is not None: date_time = dfdatetime_java_time.JavaTime( timestamp=row['lastmodify']) event = time_events.DateTimeValuesEvent( date_time, definitions.TIME_DESCRIPTION_MODIFICATION) parser_mediator.ProduceEventWithEventData(event, event_data)
def testCopyToDateTimeString(self): """Tests the CopyToDateTimeString function.""" java_time_object = java_time.JavaTime(timestamp=1281643591546) date_time_string = java_time_object.CopyToDateTimeString() self.assertEqual(date_time_string, '2010-08-12 20:06:31.546') java_time_object = java_time.JavaTime() date_time_string = java_time_object.CopyToDateTimeString() self.assertIsNone(date_time_string)
def testGetNormalizedTimestamp(self): """Tests the _GetNormalizedTimestamp function.""" java_time_object = java_time.JavaTime(timestamp=1281643591546) normalized_timestamp = java_time_object._GetNormalizedTimestamp() self.assertEqual(normalized_timestamp, decimal.Decimal('1281643591.546')) java_time_object = java_time.JavaTime() normalized_timestamp = java_time_object._GetNormalizedTimestamp() self.assertIsNone(normalized_timestamp)
def testGetTimeOfDay(self): """Tests the GetTimeOfDay function.""" java_time_object = java_time.JavaTime(timestamp=1281643591546) time_of_day_tuple = java_time_object.GetTimeOfDay() self.assertEqual(time_of_day_tuple, (20, 6, 31)) java_time_object = java_time.JavaTime() time_of_day_tuple = java_time_object.GetTimeOfDay() self.assertEqual(time_of_day_tuple, (None, None, None))
def testGetDate(self): """Tests the GetDate function.""" java_time_object = java_time.JavaTime(timestamp=1281643591546) date_tuple = java_time_object.GetDate() self.assertEqual(date_tuple, (2010, 8, 12)) java_time_object = java_time.JavaTime() date_tuple = java_time_object.GetDate() self.assertEqual(date_tuple, (None, None, None))
def testGetDateWithTimeOfDay(self): """Tests the GetDateWithTimeOfDay function.""" java_time_object = java_time.JavaTime(timestamp=1281643591546) date_with_time_of_day_tuple = java_time_object.GetDateWithTimeOfDay() self.assertEqual(date_with_time_of_day_tuple, (2010, 8, 12, 20, 6, 31)) java_time_object = java_time.JavaTime() date_with_time_of_day_tuple = java_time_object.GetDateWithTimeOfDay() self.assertEqual(date_with_time_of_day_tuple, (None, None, None, None, None, None))
def testGetPlasoTimestamp(self): """Tests the GetPlasoTimestamp function.""" java_time_object = java_time.JavaTime(timestamp=1281643591546) expected_micro_posix_timestamp = 1281643591546000 micro_posix_timestamp = java_time_object.GetPlasoTimestamp() self.assertEqual(micro_posix_timestamp, expected_micro_posix_timestamp) java_time_object = java_time.JavaTime() micro_posix_timestamp = java_time_object.GetPlasoTimestamp() self.assertIsNone(micro_posix_timestamp)
def testCopyToStatTimeTuple(self): """Tests the CopyToStatTimeTuple function.""" java_time_object = java_time.JavaTime(timestamp=1281643591546) expected_stat_time_tuple = (1281643591, 5460000) stat_time_tuple = java_time_object.CopyToStatTimeTuple() self.assertEqual(stat_time_tuple, expected_stat_time_tuple) java_time_object = java_time.JavaTime() expected_stat_time_tuple = (None, None) stat_time_tuple = java_time_object.CopyToStatTimeTuple() self.assertEqual(stat_time_tuple, expected_stat_time_tuple)
def ParseStatusRow(self, parser_mediator, query, row, **unused_kwargs): """Parses a status row from the database. Args: parser_mediator (ParserMediator): mediates interactions between parsers and other components, such as storage and dfvfs. query (str): query that created the row. row (sqlite3.Row): row resulting from query. """ query_hash = hash(query) event_data = TwitterAndroidStatusEventData() event_data.query = query event_data.identifier = self._GetRowValue(query_hash, row, '_id') event_data.author_identifier = self._GetRowValue( query_hash, row, 'author_id') event_data.username = self._GetRowValue(query_hash, row, 'username') event_data.content = self._GetRowValue(query_hash, row, 'content') event_data.favorited = self._GetRowValue(query_hash, row, 'favorited') event_data.retweeted = self._GetRowValue(query_hash, row, 'retweeted') timestamp = self._GetRowValue(query_hash, row, 'time') if timestamp: date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp) event = time_events.DateTimeValuesEvent( date_time, definitions.TIME_DESCRIPTION_CREATION) parser_mediator.ProduceEventWithEventData(event, event_data)
def testCopyFromDateTimeString(self): """Tests the CopyFromDateTimeString function.""" java_time_object = java_time.JavaTime() java_time_object.CopyFromDateTimeString('2010-08-12') self.assertEqual(java_time_object._timestamp, 1281571200000) self.assertEqual(java_time_object._time_zone_offset, 0) java_time_object.CopyFromDateTimeString('2010-08-12 21:06:31') self.assertEqual(java_time_object._timestamp, 1281647191000) self.assertEqual(java_time_object._time_zone_offset, 0) java_time_object.CopyFromDateTimeString('2010-08-12 21:06:31.546875') self.assertEqual(java_time_object._timestamp, 1281647191546) self.assertEqual(java_time_object._time_zone_offset, 0) java_time_object.CopyFromDateTimeString( '2010-08-12 21:06:31.546875-01:00') self.assertEqual(java_time_object._timestamp, 1281647191546) self.assertEqual(java_time_object._time_zone_offset, -60) java_time_object.CopyFromDateTimeString( '2010-08-12 21:06:31.546875+01:00') self.assertEqual(java_time_object._timestamp, 1281647191546) self.assertEqual(java_time_object._time_zone_offset, 60) java_time_object.CopyFromDateTimeString('1601-01-02 00:00:00') self.assertEqual(java_time_object._timestamp, -11644387200000) self.assertEqual(java_time_object._time_zone_offset, 0)
def ParseSmsRow(self, parser_mediator, query, row, **unused_kwargs): """Parses an SMS row. Args: parser_mediator (ParserMediator): mediates interactions between parsers and other components, such as storage and dfvfs. query (str): query that created the row. row (sqlite3.Row): row. """ query_hash = hash(query) sms_read = self._GetRowValue(query_hash, row, 'read') sms_type = self._GetRowValue(query_hash, row, 'type') event_data = AndroidSMSEventData() event_data.address = self._GetRowValue(query_hash, row, 'address') event_data.body = self._GetRowValue(query_hash, row, 'body') event_data.offset = self._GetRowValue(query_hash, row, 'id') event_data.query = query event_data.sms_read = self.SMS_READ.get(sms_read, 'UNKNOWN') event_data.sms_type = self.SMS_TYPE.get(sms_type, 'UNKNOWN') timestamp = self._GetRowValue(query_hash, row, 'date') date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp) event = time_events.DateTimeValuesEvent( date_time, definitions.TIME_DESCRIPTION_CREATION) parser_mediator.ProduceEventWithEventData(event, event_data)
def ParseCookieRow(self, parser_mediator, query, row, **unused_kwargs): """Parses a row from the database. Args: parser_mediator (ParserMediator): mediates interactions between parsers and other components, such as storage and dfvfs. query (str): query that created the row. row (sqlite3.Row): row. """ query_hash = hash(query) cookie_name = self._GetRowValue(query_hash, row, 'name') cookie_value = self._GetRowValue(query_hash, row, 'value') path = self._GetRowValue(query_hash, row, 'path') hostname = self._GetRowValue(query_hash, row, 'domain') if hostname.startswith('.'): hostname = hostname[1:] secure = self._GetRowValue(query_hash, row, 'secure') # The WebView database stores the secure flag as a integer type, # but we represent it as a boolean. secure = secure != 0 if secure: scheme = 'https' else: scheme = 'http' url = '{0:s}://{1:s}{2:s}'.format(scheme, hostname, path) event_data = WebViewCookieEventData() event_data.cookie_name = cookie_name event_data.data = cookie_value event_data.host = hostname event_data.offset = self._GetRowValue(query_hash, row, '_id') event_data.path = path event_data.query = query event_data.secure = secure event_data.url = url timestamp = self._GetRowValue(query_hash, row, 'expires') if timestamp: date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp) else: date_time = dfdatetime_semantic_time.SemanticTime('Infinity') event = time_events.DateTimeValuesEvent( date_time, definitions.TIME_DESCRIPTION_EXPIRATION) parser_mediator.ProduceEventWithEventData(event, event_data) # Go through all cookie plugins to see if there are is any specific parsing # needed. for cookie_plugin in self._cookie_plugins: try: cookie_plugin.UpdateChainAndProcess( parser_mediator, cookie_name=cookie_name, cookie_data=cookie_value, url=url) except errors.WrongPlugin: pass
def testCopyFromString(self): """Tests the CopyFromString function.""" java_time_object = java_time.JavaTime() expected_timestamp = 1281571200000 java_time_object.CopyFromString(u'2010-08-12') self.assertEqual(java_time_object.timestamp, expected_timestamp) expected_timestamp = 1281647191000 java_time_object.CopyFromString(u'2010-08-12 21:06:31') self.assertEqual(java_time_object.timestamp, expected_timestamp) expected_timestamp = 1281647191546 java_time_object.CopyFromString(u'2010-08-12 21:06:31.546875') self.assertEqual(java_time_object.timestamp, expected_timestamp) expected_timestamp = 1281650791546 java_time_object.CopyFromString(u'2010-08-12 21:06:31.546875-01:00') self.assertEqual(java_time_object.timestamp, expected_timestamp) expected_timestamp = 1281643591546 java_time_object.CopyFromString(u'2010-08-12 21:06:31.546875+01:00') self.assertEqual(java_time_object.timestamp, expected_timestamp) expected_timestamp = -11644387200000 java_time_object.CopyFromString(u'1601-01-02 00:00:00') self.assertEqual(java_time_object.timestamp, expected_timestamp)
def ParseZeitgeistEventRow(self, parser_mediator, row, query=None, **unused_kwargs): """Parses zeitgeist event row. Args: parser_mediator (ParserMediator): mediates interactions between parsers and other components, such as storage and dfvfs. row (sqlite3.Row): row. query (Optional[str]): query. """ # Note that pysqlite does not accept a Unicode string in row['string'] and # will raise "IndexError: Index must be int or string". event_data = ZeitgeistActivityEventData() event_data.offset = row['id'] event_data.query = query event_data.subject_uri = row['subj_uri'] date_time = dfdatetime_java_time.JavaTime(timestamp=row['timestamp']) event = time_events.DateTimeValuesEvent( date_time, eventdata.EventTimestamp.UNKNOWN) parser_mediator.ProduceEventWithEventData(event, event_data)
def ParseContactRow(self, parser_mediator, query, row, **unused_kwargs): """Parses a status row from the database. Args: parser_mediator (ParserMediator): mediates interactions between parsers and other components, such as storage and dfvfs. query (str): query that created the row. row (sqlite3.Row): row resulting from query. """ query_hash = hash(query) event_data = TwitterAndroidContactEventData() event_data.query = query event_data.identifier = self._GetRowValue(query_hash, row, '_id') event_data.user_identifier = self._GetRowValue(query_hash, row, 'user_id') event_data.username = self._GetRowValue(query_hash, row, 'username') event_data.name = self._GetRowValue(query_hash, row, 'name') event_data.description = self._GetRowValue(query_hash, row, 'description') event_data.web_url = self._GetRowValue(query_hash, row, 'web_url') event_data.location = self._GetRowValue(query_hash, row, 'location') event_data.followers = self._GetRowValue(query_hash, row, 'followers') event_data.friends = self._GetRowValue(query_hash, row, 'friends') event_data.statuses = self._GetRowValue(query_hash, row, 'statuses') event_data.image_url = self._GetRowValue(query_hash, row, 'image_url') timestamp = self._GetRowValue(query_hash, row, 'profile_created') if timestamp: date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp) event = time_events.DateTimeValuesEvent( date_time, definitions.TIME_DESCRIPTION_CREATION) parser_mediator.ProduceEventWithEventData(event, event_data) timestamp = self._GetRowValue(query_hash, row, 'updated') if timestamp: date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp) event = time_events.DateTimeValuesEvent( date_time, definitions.TIME_DESCRIPTION_UPDATE) parser_mediator.ProduceEventWithEventData(event, event_data) timestamp = self._GetRowValue(query_hash, row, 'friendship_time') if timestamp: date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp) event = time_events.DateTimeValuesEvent( date_time, definitions.TIME_DESCRIPTION_MODIFICATION) parser_mediator.ProduceEventWithEventData(event, event_data)
def ParseFileObject(self, parser_mediator, file_object): """Parses an Android usage-history file-like object. Args: parser_mediator (ParserMediator): mediates interactions between parsers and other components, such as storage and dfvfs. file_object (dfvfs.FileIO): file-like object. Raises: UnableToParseFile: when the file cannot be parsed. """ data = file_object.read(self._HEADER_READ_SIZE) if not data.startswith(b'<?xml'): raise errors.UnableToParseFile( 'Not an Android usage history file [not XML]') _, _, data = data.partition(b'\n') if not data.startswith(b'<usage-history'): raise errors.UnableToParseFile( 'Not an Android usage history file [wrong XML root key]') # The current offset of the file-like object needs to point at # the start of the file for ElementTree to parse the XML data correctly. file_object.seek(0, os.SEEK_SET) xml = ElementTree.parse(file_object) root_node = xml.getroot() for application_node in root_node: package_name = application_node.get('name', None) for part_node in application_node.iter(): if part_node.tag != 'comp': continue last_resume_time = part_node.get('lrt', None) if last_resume_time is None: parser_mediator.ProduceExtractionWarning( 'missing last resume time.') continue try: last_resume_time = int(last_resume_time, 10) except ValueError: parser_mediator.ProduceExtractionWarning( 'unsupported last resume time: {0:s}.'.format( last_resume_time)) continue event_data = AndroidAppUsageEventData() event_data.component = part_node.get('name', None) event_data.package = package_name date_time = dfdatetime_java_time.JavaTime( timestamp=last_resume_time) event = time_events.DateTimeValuesEvent( date_time, definitions.TIME_DESCRIPTION_LAST_RESUME) parser_mediator.ProduceEventWithEventData(event, event_data)
def ParseCallsRow(self, parser_mediator, query, row, **unused_kwargs): """Parses a Call record row. Args: parser_mediator (ParserMediator): mediates interactions between parsers and other components, such as storage and dfvfs. query (str): query that created the row. row (sqlite3.Row): row. """ query_hash = hash(query) call_type = self._GetRowValue(query_hash, row, 'type') call_type = self.CALL_TYPE.get(call_type, 'UNKNOWN') duration = self._GetRowValue(query_hash, row, 'duration') timestamp = self._GetRowValue(query_hash, row, 'date') event_data = AndroidCallEventData() event_data.call_type = call_type event_data.duration = self._GetRowValue(query_hash, row, 'duration') event_data.name = self._GetRowValue(query_hash, row, 'name') event_data.number = self._GetRowValue(query_hash, row, 'number') event_data.offset = self._GetRowValue(query_hash, row, 'id') event_data.query = query date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp) event = time_events.DateTimeValuesEvent(date_time, 'Call Started') parser_mediator.ProduceEventWithEventData(event, event_data) if duration: if isinstance(duration, str): try: duration = int(duration, 10) except ValueError: duration = 0 # The duration is in seconds and the date value in milliseconds. timestamp += duration * 1000 date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp) event = time_events.DateTimeValuesEvent(date_time, 'Call Ended') parser_mediator.ProduceEventWithEventData(event, event_data)
def ParseCallsRow(self, parser_mediator, row, query=None, **unused_kwargs): """Parses a Call record row. Args: parser_mediator (ParserMediator): mediates interactions between parsers and other components, such as storage and dfvfs. row (sqlite3.Row): row. query (Optional[str]): query. """ # Note that pysqlite does not accept a Unicode string in row['string'] and # will raise "IndexError: Index must be int or string". call_type = self.CALL_TYPE.get(row['type'], u'UNKNOWN') duration = row['duration'] timestamp = row['date'] event_data = AndroidCallEventData() event_data.call_type = call_type event_data.duration = row['duration'] event_data.name = row['name'] event_data.number = row['number'] event_data.offset = row['id'] event_data.query = query date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp) event = time_events.DateTimeValuesEvent(date_time, u'Call Started') parser_mediator.ProduceEventWithEventData(event, event_data) if duration: if isinstance(duration, py2to3.STRING_TYPES): try: duration = int(duration, 10) except ValueError: duration = 0 # The duration is in seconds and the date value in milliseconds. timestamp += duration * 1000 date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp) event = time_events.DateTimeValuesEvent(date_time, u'Call Ended') parser_mediator.ProduceEventWithEventData(event, event_data)
def ParseLibrary(self, parser_mediator, cache=None, database=None, table=None, **unused_kwargs): """Parses the library table. Args: """ if database is None: raise ValueError('Missing database value.') if table is None: raise ValueError('Missing table value.') strings = cache.GetResults('strings') if not strings: esedb_table = database.get_table_by_name('string') strings = self._GetDictFromStringsTable(parser_mediator, esedb_table) cache.StoreDictInCache('string', strings) backup_folder_list = "" event_data = FileHistoryLibraryEventData() for esedb_record in table.records: if parser_mediator.abort: break record_values = self._GetRecordValues(parser_mediator, table.name, esedb_record) parentid = record_values.get('parentId') childid = record_values.get('childId') backup_folder_list += str(strings.get(parentid)) + "\\" \ + str(strings.get(childid)) + "," event_data.backup_folder = backup_folder_list date_time = dfdatetime_java_time.JavaTime(timestamp=0) event = time_events.DateTimeValuesEvent( date_time, definitions.TIME_DESCRIPTION_NOT_A_TIME) parser_mediator.ProduceEventWithEventData(event, event_data)
def ParseZeitgeistEventRow(self, parser_mediator, query, row, **unused_kwargs): """Parses a zeitgeist event row. Args: parser_mediator (ParserMediator): mediates interactions between parsers and other components, such as storage and dfvfs. query (str): query that created the row. row (sqlite3.Row): row. """ query_hash = hash(query) event_data = ZeitgeistActivityEventData() event_data.offset = self._GetRowValue(query_hash, row, 'id') event_data.query = query event_data.subject_uri = self._GetRowValue(query_hash, row, 'subj_uri') timestamp = self._GetRowValue(query_hash, row, 'timestamp') date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp) event = time_events.DateTimeValuesEvent( date_time, definitions.TIME_DESCRIPTION_UNKNOWN) parser_mediator.ProduceEventWithEventData(event, event_data)
def ParseSmsRow(self, parser_mediator, row, query=None, **unused_kwargs): """Parses an SMS row. Args: parser_mediator (ParserMediator): mediates interactions between parsers and other components, such as storage and dfvfs. row (sqlite3.Row): row. query (Optional[str]): query. """ # Note that pysqlite does not accept a Unicode string in row['string'] and # will raise "IndexError: Index must be int or string". event_data = AndroidSMSEventData() event_data.address = row['address'] event_data.body = row['body'] event_data.offset = row['id'] event_data.query = query event_data.sms_read = self.SMS_READ.get(row['read'], u'UNKNOWN') event_data.sms_type = self.SMS_TYPE.get(row['type'], u'UNKNOWN') date_time = dfdatetime_java_time.JavaTime(timestamp=row['date']) event = time_events.DateTimeValuesEvent( date_time, definitions.TIME_DESCRIPTION_CREATION) parser_mediator.ProduceEventWithEventData(event, event_data)
def ParseContactRow(self, parser_mediator, query, row, **unused_kwargs): """Parses a contact row from the database. Args: parser_mediator (ParserMediator): mediates interactions between parsers and other components, such as storage and dfvfs. query (str): query that created the row. row (sqlite3.Row): row resulting from query. """ query_hash = hash(query) event_data = TangoAndroidContactEventData() first_name = self._GetRowValue(query_hash, row, 'first_name') try: decoded_text = base64_decode(first_name) event_data.first_name = codecs.decode(decoded_text, 'utf-8') except ValueError: event_data.first_name = first_name parser_mediator.ProduceExtractionError( 'unable to parse first name: {0:s}'.format(first_name)) last_name = self._GetRowValue(query_hash, row, 'last_name') try: decoded_text = base64_decode(last_name) event_data.last_name = codecs.decode(decoded_text, 'utf-8') except ValueError: event_data.last_name = last_name parser_mediator.ProduceExtractionError( 'unable to parse last name: {0:s}'.format(last_name)) event_data.birthday = self._GetRowValue(query_hash, row, 'birthday') event_data.gender = self._GetRowValue(query_hash, row, 'gender') status = self._GetRowValue(query_hash, row, 'status') try: decoded_text = base64_decode(status) event_data.status = codecs.decode(decoded_text, 'utf-8') except ValueError: event_data.status = status parser_mediator.ProduceExtractionError( 'unable to parse status: {0:s}'.format(status)) event_data.distance = self._GetRowValue(query_hash, row, 'distance') is_friend = self._GetRowValue(query_hash, row, 'friend') event_data.is_friend = False if is_friend: event_data.is_friend = True event_data.friend_request_type = self._GetRowValue( query_hash, row, 'friend_request_type') friend_request_message = self._GetRowValue(query_hash, row, 'friend_request_message') try: decoded_text = base64_decode(friend_request_message) event_data.friend_request_message = codecs.decode( decoded_text, 'utf-8') except ValueError: event_data.friend_request_message = friend_request_message parser_mediator.ProduceExtractionError( 'unable to parse status: {0:s}'.format(friend_request_message)) timestamp = self._GetRowValue(query_hash, row, 'last_active_time') if timestamp: date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp) event = time_events.DateTimeValuesEvent( date_time, definitions.TIME_DESCRIPTION_LAST_ACTIVE) parser_mediator.ProduceEventWithEventData(event, event_data) timestamp = self._GetRowValue(query_hash, row, 'last_access_time') if timestamp: date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp) event = time_events.DateTimeValuesEvent( date_time, definitions.TIME_DESCRIPTION_LAST_ACCESS) parser_mediator.ProduceEventWithEventData(event, event_data) timestamp = self._GetRowValue(query_hash, row, 'friend_request_time') if timestamp: date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp) event = time_events.DateTimeValuesEvent( date_time, definitions.TIME_DESCRIPTION_SENT) parser_mediator.ProduceEventWithEventData(event, event_data)
def ParseReceiverData( self, parser_mediator, row, query=None, **unused_kwargs): """Parses a single row from the receiver and cache response table. Args: parser_mediator (ParserMediator): mediates interactions between parsers and other components, such as storage and dfvfs. row (sqlite3.Row): row. query (Optional[str]): query. """ # Note that pysqlite does not accept a Unicode string in row['string'] and # will raise "IndexError: Index must be int or string". data = {} key_url = row['request_key'] data_dict = {} description = u'MacKeeper Entry' # Check the URL, since that contains vital information about the type of # event we are dealing with. if key_url.endswith(u'plist'): description = u'Configuration Definition' data[u'text'] = u'Plist content added to cache.' elif key_url.startswith(u'http://event.zeobit.com'): description = u'MacKeeper Event' try: _, _, part = key_url.partition(u'?') data[u'text'] = part.replace(u'&', u' ') except UnicodeDecodeError: data[u'text'] = u'N/A' elif key_url.startswith(u'http://account.zeobit.com'): description = u'Account Activity' _, _, activity = key_url.partition(u'#') if activity: data[u'text'] = u'Action started: {0:s}'.format(activity) else: data[u'text'] = u'Unknown activity.' elif key_url.startswith(u'http://support.') and u'chat' in key_url: description = u'Chat ' try: jquery = codecs.decode(row['data'], u'utf-8') except UnicodeDecodeError: jquery = u'' data_dict = self._ExtractJQuery(jquery) data = self._ParseChatData(data_dict) data[u'entry_type'] = data_dict.get(u'type', u'') if data[u'entry_type'] == u'comment': description += u'Comment' elif data[u'entry_type'] == u'outgoing': description += u'Outgoing Message' elif data[u'entry_type'] == u'incoming': description += u'Incoming Message' else: # Empty or not known entry type, generic status message. description += u'Entry' data[u'text'] = u';'.join(self._DictToListOfStrings(data_dict)) if not data[u'text']: data[u'text'] = u'No additional data.' event_data = MacKeeperCacheEventData() event_data.description = description event_data.event_type = data.get(u'event_type', None) event_data.offset = row['id'] event_data.query = query event_data.record_id = data.get(u'id', None) event_data.room = data.get(u'room', None) event_data.text = data.get(u'text', None) event_data.url = key_url event_data.user_name = data.get(u'user', None) event_data.user_sid = data.get(u'sid', None) time_value = row['time_string'] if isinstance(time_value, py2to3.INTEGER_TYPES): date_time = dfdatetime_java_time.JavaTime(timestamp=time_value) event = time_events.DateTimeValuesEvent( date_time, eventdata.EventTimestamp.ADDED_TIME) else: try: timestamp = timelib.Timestamp.FromTimeString(time_value) except errors.TimestampError: parser_mediator.ProduceExtractionError( u'Unable to parse time string: {0:s}'.format(time_value)) return event = time_events.TimestampEvent( timestamp, eventdata.EventTimestamp.ADDED_TIME) parser_mediator.ProduceEventWithEventData(event, event_data)
def ParseFileObject(self, parser_mediator, file_object): """Parses a Java WebStart Cache IDX file-like object. Args: parser_mediator (ParserMediator): mediates interactions between parsers and other components, such as storage and dfvfs. file_object (dvfvs.FileIO): a file-like object to parse. Raises: UnableToParseFile: when the file cannot be parsed. """ file_header_map = self._GetDataTypeMap('java_idx_file_header') try: file_header, file_offset = self._ReadStructureFromFileObject( file_object, 0, file_header_map) except (ValueError, errors.ParseError) as exception: raise errors.UnableToParseFile( 'Unable to parse file header with error: {0!s}'.format( exception)) if not file_header.format_version in self._SUPPORTED_FORMAT_VERSIONS: raise errors.UnableToParseFile('Unsupported format version.') if file_header.format_version == 602: section1_map = self._GetDataTypeMap('java_idx_602_section1') elif file_header.format_version in (603, 604): section1_map = self._GetDataTypeMap('java_idx_603_section1') elif file_header.format_version == 605: section1_map = self._GetDataTypeMap('java_idx_605_section1') try: section1, data_size = self._ReadStructureFromFileObject( file_object, file_offset, section1_map) except (ValueError, errors.ParseError) as exception: raise errors.UnableToParseFile(( 'Unable to parse section 1 (format version: {0:d}) with error: ' '{1!s}').format(file_header.format_version, exception)) file_offset += data_size if file_header.format_version == 602: section2_map = self._GetDataTypeMap('java_idx_602_section2') elif file_header.format_version in (603, 604, 605): file_offset = 128 section2_map = self._GetDataTypeMap('java_idx_603_section2') try: section2, data_size = self._ReadStructureFromFileObject( file_object, file_offset, section2_map) except (ValueError, errors.ParseError) as exception: raise errors.UnableToParseFile(( 'Unable to parse section 2 (format version: {0:d}) with error: ' '{1!s}').format(file_header.format_version, exception)) file_offset += data_size if not section2.url: raise errors.UnableToParseFile('URL not found in file.') date_http_header = None for _ in range(section2.number_of_http_headers): http_header_map = self._GetDataTypeMap('java_idx_http_header') try: http_header, data_size = self._ReadStructureFromFileObject( file_object, file_offset, http_header_map) except (ValueError, errors.ParseError) as exception: parser_mediator.ProduceExtractionWarning( 'Unable to parse HTTP header value at offset: 0x{0:08x}'. format(file_offset)) break file_offset += data_size if http_header.name == 'date': date_http_header = http_header break event_data = JavaIDXEventData() event_data.idx_version = file_header.format_version event_data.ip_address = getattr(section2, 'ip_address', None) event_data.url = section2.url date_time = dfdatetime_java_time.JavaTime( timestamp=section1.modification_time) # TODO: Move the timestamp description into definitions. event = time_events.DateTimeValuesEvent(date_time, 'File Hosted Date') parser_mediator.ProduceEventWithEventData(event, event_data) if section1.expiration_time: date_time = dfdatetime_java_time.JavaTime( timestamp=section1.expiration_time) event = time_events.DateTimeValuesEvent( date_time, definitions.TIME_DESCRIPTION_EXPIRATION) parser_mediator.ProduceEventWithEventData(event, event_data) if date_http_header: # A HTTP header date and time should be formatted according to RFC 1123. # The date "should" be in UTC or have associated time zone information # in the string itself. If that is not the case then there is no reliable # method for Plaso to determine the proper time zone, so the assumption # is that the date and time is in UTC. try: date_time = dfdatetime_time_elements.TimeElements() date_time.CopyFromStringRFC1123(date_http_header.value) except ValueError as exception: parser_mediator.ProduceExtractionWarning(( 'Unable to parse date HTTP header string: {0:s} with error: ' '{1!s}').format(date_http_header.value, exception)) date_time = dfdatetime_semantic_time.InvalidTime() event = time_events.DateTimeValuesEvent( date_time, definitions.TIME_DESCRIPTION_FILE_DOWNLOADED) parser_mediator.ProduceEventWithEventData(event, event_data)
def ParseFileObject(self, parser_mediator, file_object, **kwargs): """Parses a Java WebStart Cache IDX file-like object. Args: parser_mediator: A parser mediator object (instance of ParserMediator). file_object: A file-like object. Raises: UnableToParseFile: when the file cannot be parsed. """ file_object.seek(0, os.SEEK_SET) try: magic = self.IDX_SHORT_STRUCT.parse_stream(file_object) except (IOError, construct.FieldError) as exception: raise errors.UnableToParseFile( 'Unable to parse Java IDX file with error: {0:s}.'.format( exception)) # Fields magic.busy and magic.incomplete are normally 0x00. They # are set to 0x01 if the file is currently being downloaded. Logic # checks for > 1 to avoid a race condition and still reject any # file with other data. # Field magic.idx_version is the file version, of which only # certain versions are supported. if magic.busy > 1 or magic.incomplete > 1: raise errors.UnableToParseFile('Not a valid Java IDX file') if not magic.idx_version in [602, 603, 604, 605]: raise errors.UnableToParseFile('Not a valid Java IDX file') # Obtain the relevant values from the file. The last modified date # denotes when the file was last modified on the HOST. For example, # when the file was uploaded to a web server. if magic.idx_version == 602: section_one = self.IDX_602_STRUCT.parse_stream(file_object) last_modified_date = section_one.last_modified_date url = section_one.url ip_address = 'Unknown' http_header_count = section_one.FieldCount elif magic.idx_version in [603, 604, 605]: # IDX 6.03 and 6.04 have two unused bytes before the structure. if magic.idx_version in [603, 604]: file_object.read(2) # IDX 6.03, 6.04, and 6.05 files use the same structures for the # remaining data. section_one = self.IDX_605_SECTION_ONE_STRUCT.parse_stream( file_object) last_modified_date = section_one.last_modified_date if file_object.get_size() > 128: file_object.seek(128, os.SEEK_SET) # Static offset for section 2. section_two = self.IDX_605_SECTION_TWO_STRUCT.parse_stream( file_object) url = section_two.url ip_address = section_two.ip_address http_header_count = section_two.FieldCount else: url = 'Unknown' ip_address = 'Unknown' http_header_count = 0 # File offset is now just prior to HTTP headers. Make sure there # are headers, and then parse them to retrieve the download date. download_date = None for field in range(0, http_header_count): field = self.JAVA_READUTF_STRING.parse_stream(file_object) value = self.JAVA_READUTF_STRING.parse_stream(file_object) if field.string == 'date': # Time string "should" be in UTC or have an associated time zone # information in the string itself. If that is not the case then # there is no reliable method for plaso to determine the proper # timezone, so the assumption is that it is UTC. try: download_date = timelib.Timestamp.FromTimeString( value.string, gmt_as_timezone=False) except errors.TimestampError: download_date = None parser_mediator.ProduceExtractionError( 'Unable to parse time value: {0:s}'.format( value.string)) if not url or not ip_address: raise errors.UnableToParseFile( 'Unexpected Error: URL or IP address not found in file.') event_data = JavaIDXEventData() event_data.idx_version = magic.idx_version event_data.ip_address = ip_address event_data.url = url date_time = dfdatetime_java_time.JavaTime(timestamp=last_modified_date) # TODO: Move the timestamp description into eventdata. event = time_events.DateTimeValuesEvent(date_time, 'File Hosted Date') parser_mediator.ProduceEventWithEventData(event, event_data) if section_one: expiration_date = section_one.get('expiration_date', None) if expiration_date: date_time = dfdatetime_java_time.JavaTime( timestamp=expiration_date) event = time_events.DateTimeValuesEvent( date_time, definitions.TIME_DESCRIPTION_EXPIRATION) parser_mediator.ProduceEventWithEventData(event, event_data) if download_date: event = time_events.TimestampEvent( download_date, definitions.TIME_DESCRIPTION_FILE_DOWNLOADED) parser_mediator.ProduceEventWithEventData(event, event_data)
def ParseFileObject(self, parser_mediator, file_object, **kwargs): """Parses a Java WebStart Cache IDX file-like object. Args: parser_mediator: A parser mediator object (instance of ParserMediator). file_object: A file-like object. Raises: UnableToParseFile: when the file cannot be parsed. """ file_header_map = self._GetDataTypeMap('java_idx_file_header') try: file_header, file_offset = self._ReadStructureFromFileObject( file_object, 0, file_header_map) except (ValueError, errors.ParseError) as exception: raise errors.UnableToParseFile( 'Unable to parse file header with error: {0!s}'.format( exception)) if not file_header.format_version in self._SUPPORTED_FORMAT_VERSIONS: raise errors.UnableToParseFile('Unsupported format version.') if file_header.format_version == 602: section1_map = self._GetDataTypeMap('java_idx_602_section1') elif file_header.format_version in (603, 604): section1_map = self._GetDataTypeMap('java_idx_603_section1') elif file_header.format_version == 605: section1_map = self._GetDataTypeMap('java_idx_605_section1') try: section1, data_size = self._ReadStructureFromFileObject( file_object, file_offset, section1_map) except (ValueError, errors.ParseError) as exception: raise errors.UnableToParseFile(( 'Unable to parse section 1 (format version: {0:d}) with error: ' '{1!s}').format(file_header.format_version, exception)) file_offset += data_size if file_header.format_version == 602: section2_map = self._GetDataTypeMap('java_idx_602_section2') elif file_header.format_version in (603, 604, 605): file_offset = 128 section2_map = self._GetDataTypeMap('java_idx_603_section2') try: section2, data_size = self._ReadStructureFromFileObject( file_object, file_offset, section2_map) except (ValueError, errors.ParseError) as exception: raise errors.UnableToParseFile(( 'Unable to parse section 2 (format version: {0:d}) with error: ' '{1!s}').format(file_header.format_version, exception)) file_offset += data_size if not section2.url: raise errors.UnableToParseFile('URL not found in file.') date_http_header = None for _ in range(section2.number_of_http_headers): http_header_map = self._GetDataTypeMap('java_idx_http_header') try: http_header, data_size = self._ReadStructureFromFileObject( file_object, file_offset, http_header_map) except (ValueError, errors.ParseError) as exception: parser_mediator.ProduceExtractionError( 'Unable to parse HTTP header value at offset: 0x{0:08x}'. format(file_offset)) break file_offset += data_size if http_header.name == 'date': date_http_header = http_header break event_data = JavaIDXEventData() event_data.idx_version = file_header.format_version event_data.ip_address = getattr(section2, 'ip_address', None) event_data.url = section2.url date_time = dfdatetime_java_time.JavaTime( timestamp=section1.modification_time) # TODO: Move the timestamp description into definitions. event = time_events.DateTimeValuesEvent(date_time, 'File Hosted Date') parser_mediator.ProduceEventWithEventData(event, event_data) if section1.expiration_time: date_time = dfdatetime_java_time.JavaTime( timestamp=section1.expiration_time) event = time_events.DateTimeValuesEvent( date_time, definitions.TIME_DESCRIPTION_EXPIRATION) parser_mediator.ProduceEventWithEventData(event, event_data) if date_http_header: # A HTTP header date and string "should" be in UTC or have an associated # time zone information in the string itself. If that is not the case # then there is no reliable method for plaso to determine the proper # time zone, so the assumption is that it is UTC. try: download_date = timelib.Timestamp.FromTimeString( date_http_header.value, gmt_as_timezone=False) except errors.TimestampError: parser_mediator.ProduceExtractionError( 'Unable to parse date HTTP header value: {0:s}'.format( date_http_header.value)) if download_date: event = time_events.TimestampEvent( download_date, definitions.TIME_DESCRIPTION_FILE_DOWNLOADED) parser_mediator.ProduceEventWithEventData(event, event_data)
def ParseReceiverData( self, parser_mediator, query, row, **unused_kwargs): """Parses a single row from the receiver and cache response table. Args: parser_mediator (ParserMediator): mediates interactions between parsers and other components, such as storage and dfvfs. query (str): query that created the row. row (sqlite3.Row): row. """ query_hash = hash(query) data = {} key_url = self._GetRowValue(query_hash, row, 'request_key') data_dict = {} description = 'MacKeeper Entry' # Check the URL, since that contains vital information about the type of # event we are dealing with. if key_url.endswith('plist'): description = 'Configuration Definition' data['text'] = 'Plist content added to cache.' elif key_url.startswith('http://event.zeobit.com'): description = 'MacKeeper Event' try: _, _, part = key_url.partition('?') data['text'] = part.replace('&', ' ') except UnicodeDecodeError: data['text'] = 'N/A' elif key_url.startswith('http://account.zeobit.com'): description = 'Account Activity' _, _, activity = key_url.partition('#') if activity: data['text'] = 'Action started: {0:s}'.format(activity) else: data['text'] = 'Unknown activity.' elif key_url.startswith('http://support.') and 'chat' in key_url: description = 'Chat ' try: jquery = self._GetRowValue(query_hash, row, 'data') jquery = codecs.decode(jquery, 'utf-8') except UnicodeDecodeError: jquery = '' data_dict = self._ExtractJQuery(jquery) data = self._ParseChatData(data_dict) data['entry_type'] = data_dict.get('type', '') if data['entry_type'] == 'comment': description += 'Comment' elif data['entry_type'] == 'outgoing': description += 'Outgoing Message' elif data['entry_type'] == 'incoming': description += 'Incoming Message' else: # Empty or not known entry type, generic status message. description += 'Entry' data['text'] = ';'.join(self._DictToListOfStrings(data_dict)) if not data['text']: data['text'] = 'No additional data.' event_data = MacKeeperCacheEventData() event_data.description = description event_data.event_type = data.get('event_type', None) event_data.offset = self._GetRowValue(query_hash, row, 'id') event_data.query = query event_data.record_id = data.get('id', None) event_data.room = data.get('room', None) event_data.text = data.get('text', None) event_data.url = key_url event_data.user_name = data.get('user', None) event_data.user_sid = data.get('sid', None) time_value = self._GetRowValue(query_hash, row, 'time_string') if isinstance(time_value, py2to3.INTEGER_TYPES): date_time = dfdatetime_java_time.JavaTime(timestamp=time_value) event = time_events.DateTimeValuesEvent( date_time, definitions.TIME_DESCRIPTION_ADDED) else: try: timestamp = timelib.Timestamp.FromTimeString(time_value) except errors.TimestampError: parser_mediator.ProduceExtractionWarning( 'Unable to parse time string: {0:s}'.format(time_value)) return event = time_events.TimestampEvent( timestamp, definitions.TIME_DESCRIPTION_ADDED) parser_mediator.ProduceEventWithEventData(event, event_data)