# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# Mobius Forensic Toolkit
# Copyright (C) 2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2018 Eduardo Aguiar
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
import struct
import datetime

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief known SIDs
# @reference http://support.microsoft.com/kb/243330
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
KNOWN_SIDS = {'S-1-5-6' : 'service',
              'S-1-5-7' : 'anonymous',
              'S-1-5-8' : 'proxy',
             'S-1-5-18' : 'local system',
             'S-1-5-19' : 'local service',
             'S-1-5-20' : 'network service'}

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief get data as string
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def get_data_as_string (data, value=''):
  return data.get_data_as_string ('utf-16') if data else value

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief get NT datetime from timestamp
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def get_nt_datetime (timestamp):
  if timestamp:
    delta = datetime.timedelta (seconds=timestamp // 10000000)
    date = datetime.datetime (1601, 1, 1, 0, 0, 0) + delta
    text = str (date)[:19]
  else:
    text = ''

  return text

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief get computer name
# @param registry registry
# @reference http://support.microsoft.com/kb/102987/en-us
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def get_computer_name (registry):
  try:
    computername = get_data_as_string (registry.get_data_by_path ('HKLM\\SYSTEM\\CurrentControlSet\\Control\\ComputerName\\ComputerName\\ComputerName'))
  except:
    computername = None

  return computername

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief get username from SID
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def get_username_from_sid (registry, sid):
  username = KNOWN_SIDS.get (sid)
  
  if not username:
    rid = int (sid.split ('-')[-1])
    data = registry.get_data_by_path ('HKLM\\SAM\\SAM\\Domains\\Account\\Users\\%08X\\V' % rid)

    if data:
      offset, size = struct.unpack ('II', data.data[12:20])
      username = unicode (data.data[0xcc + offset:0xcc + offset + size], 'utf-16')

  return username

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 
# @brief get folder path from GUID
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def get_folder_path_from_guid (registry, guid):
  path = None
  key = registry.get_key_by_path ('\\HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FolderDescriptions\\{%s}' % guid)
  
  if key:
    name = get_data_as_string (key.get_data_by_name ('Name'))
    relative_path = get_data_as_string (key.get_data_by_name ('RelativePath'))
    parent_folder = get_data_as_string (key.get_data_by_name ('ParentFolder'))
        
    if relative_path:
      path = relative_path
      
      if parent_folder:
	parent_guid = parent_folder[1:-1]
	parent_path = get_folder_path_from_guid (registry, parent_guid)
	
	if parent_path:
	  path = '%s\\%s' % (parent_path, path)
	  
    elif name:
      path = '%%%s%%' % name

  return path    

# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# @brief iterate through HKEY_USERS keys
# @reference http://www.systemlookup.com/ActiveSetup/292-setup50_exe.html
# GUID 44BBA840-CC51-11CF-AAFA-00AA00B6015C Microsoft Outlook Express setup library
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
def iter_hkey_users (registry):
  for key in registry.get_key_by_mask ('\\HKU\\*'):

    if key.name == '.DEFAULT':
      username = '.DEFAULT'

    else:
      username = get_data_as_string (key.get_data_by_path ('Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Logon User Name')) or \
                 get_data_as_string (key.get_data_by_path ('Software\\Microsoft\\Active Setup\\Installed Components\\{44BBA840-CC51-11CF-AAFA-00AA00B6015C}\\Username')) or \
                 get_username_from_sid (registry, key.name) or key.name

    yield username, key
