# Volatility
# Copyright (c) 2008-2014 Volatility Foundation
# Copyright (c) 2013,2014 Michael Ligh (michael.ligh@mnin.org)
# Copyleft (0) 2020, Patrick Eisoldt

# This file is part of Volatility.
#
# Volatility is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License Version 2 as
# published by the Free Software Foundation.  You may not use, modify or
# distribute this program under any other version of the GNU General
# Public License.
#
# Volatility 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 Volatility.  If not, see <http://www.gnu.org/licenses/>.
#

import os
import binascii
import volatility.obj as obj
import volatility.debug as debug
import volatility.utils as utils
import volatility.plugins.common as common
import volatility.win32.modules as modules

import volatility.win32.tasks as tasks
import volatility.plugins.filescan as filescan
import volatility.plugins.malware.devicetree as devicetree
import volatility.plugins.malware.svcscan as svcscan
import volatility.plugins.registry.registryapi as registryapi

vc_122_vtypes_x86 = {
  'UINT64_STRUCT' : [ 0x8, {
    'LowPart' : [ 0x0, ['unsigned long']],
    'HighPart' : [ 0x4, ['unsigned long']],
    'Value' : [ 0x0, ['unsigned long long']],
    } ],
  'CRYPTO_INFO_t' : [ 0x4468, {
    'ea' : [ 0x0, ['long']],
    'mode' : [ 0x4, ['long']],
    'ks' : [ 0x8, ['array', 5324, ['unsigned char']]],
    'ks2' : [ 0x14d4, ['array', 5324, ['unsigned char']]],
    'hiddenVolume' : [ 0x29a0, ['long']],
    'HeaderVersion' : [ 0x29a4, ['unsigned short']],
    'gf_ctx' : [ 0x29a8, ['GfCtx']],
    'master_keydata' : [ 0x4190, ['array', 256, ['unsigned char']]],
    'k2' : [ 0x42a8, ['array', 256, ['unsigned char']]],
    'salt' : [ 0x43a8, ['array', 64, ['unsigned char']]],
    'noIterations' : [ 0x43e8, ['long']],
    'pkcs5' : [ 0x43ec, ['long']],
    'volume_creation_time' : [ 0x43f0, ['unsigned long long']],
    'header_creation_time' : [ 0x43f8, ['unsigned long long']],
    'bProtectHiddenVolume' : [ 0x4400, ['long']],
    'bHiddenVolProtectionAction' : [ 0x4404, ['long']],
    'volDataAreaOffset' : [ 0x4408, ['unsigned long long']],
    'hiddenVolumeSize' : [ 0x4410, ['unsigned long long']],
    'hiddenVolumeOffset' : [ 0x4418, ['unsigned long long']],
    'hiddenVolumeProtectedSize' : [ 0x4420, ['unsigned long long']],
    'bPartitionInInactiveSysEncScope' : [ 0x4428, ['long']],
    'FirstDataUnitNo' : [ 0x4430, ['UINT64_STRUCT']],
    'RequiredProgramVersion' : [ 0x4438, ['unsigned short']],
    'LegacyVolume' : [ 0x443c, ['long']],
    'SectorSize' : [ 0x4440, ['unsigned long']],
    'VolumeSize' : [ 0x4448, ['UINT64_STRUCT']],
    'EncryptedAreaStart' : [ 0x4450, ['UINT64_STRUCT']],
    'EncryptedAreaLength' : [ 0x4458, ['UINT64_STRUCT']],
    'HeaderFlags' : [ 0x4460, ['unsigned long']],
    } ],
  'EXTENSION' : [ 0x4d0, {
    'bRootDevice' : [ 0x0, ['long']],
    'IsVolumeDevice' : [ 0x4, ['long']],
    'IsDriveFilterDevice' : [ 0x8, ['long']],
    'IsVolumeFilterDevice' : [ 0xc, ['long']],
    'UniqueVolumeId' : [ 0x10, ['long']],
    'nDosDriveNo' : [ 0x14, ['long']],
    'bShuttingDown' : [ 0x18, ['long']],
    'bThreadShouldQuit' : [ 0x1c, ['long']],
    'peThread' : [ 0x20, ['pointer', ['_KTHREAD']]],
    'keCreateEvent' : [ 0x24, ['_KEVENT']],
    'ListSpinLock' : [ 0x34, ['unsigned long']],
    'ListEntry' : [ 0x38, ['_LIST_ENTRY']],
    'RequestSemaphore' : [ 0x40, ['_KSEMAPHORE']],
    'hDeviceFile' : [ 0x54, ['pointer', ['void']]],
    'pfoDeviceFile' : [ 0x58, ['pointer', ['_FILE_OBJECT']]],
    'pFsdDevice' : [ 0x5c, ['pointer', ['_DEVICE_OBJECT']]],
    'cryptoInfo' : [ 0x60, ['pointer', ['CRYPTO_INFO_t']]],
    'HostLength' : [ 0x68, ['long long']],
    'DiskLength' : [ 0x70, ['long long']],
    'NumberOfCylinders' : [ 0x78, ['long long']],
    'TracksPerCylinder' : [ 0x80, ['unsigned long']],
    'SectorsPerTrack' : [ 0x84, ['unsigned long']],
    'BytesPerSector' : [ 0x88, ['unsigned long']],
    'PartitionType' : [ 0x8c, ['unsigned char']],
    'HostBytesPerSector' : [ 0x90, ['unsigned long']],
    'keVolumeEvent' : [ 0x94, ['_KEVENT']],
    'Queue' : [ 0xa8, ['EncryptedIoQueue']],
    'bReadOnly' : [ 0x248, ['long']],
    'bRemovable' : [ 0x24c, ['long']],
    'PartitionInInactiveSysEncScope' : [ 0x250, ['long']],
    'bRawDevice' : [ 0x254, ['long']],
    'bMountManager' : [ 0x258, ['long']],
    'SystemFavorite' : [ 0x25c, ['long']],
    'wszVolume' : [ 0x260, ['array', 260, ['wchar']]],
    'fileCreationTime' : [ 0x468, ['_LARGE_INTEGER']],
    'fileLastAccessTime' : [ 0x470, ['_LARGE_INTEGER']],
    'fileLastWriteTime' : [ 0x478, ['_LARGE_INTEGER']],
    'fileLastChangeTime' : [ 0x480, ['_LARGE_INTEGER']],
    'bTimeStampValid' : [ 0x488, ['long']],
    'UserSid' : [ 0x48c, ['pointer', ['void']]],
    'SecurityClientContextValid' : [ 0x490, ['long']],
    'SecurityClientContext' : [ 0x494, ['_SECURITY_CLIENT_CONTEXT']],
    } ],
  'Password' : [ 0x48, {
    'Length' : [ 0x0, ['unsigned long']],
    'Text' : [ 0x4, ['array', 65, ['unsigned char']]],
    'Pad' : [ 0x45, ['array', 3, ['unsigned char']]],
    } ],
}

vc_122_vtypes_x64 = {
  'UINT64_STRUCT' : [ 0x8, {
    'LowPart' : [ 0x0, ['unsigned long']],
    'HighPart' : [ 0x4, ['unsigned long']],
    'Value' : [ 0x0, ['unsigned long long']],
    } ],
  'CRYPTO_INFO_t' : [ 0x4468, {
    'ea' : [ 0x0, ['long']],
    'mode' : [ 0x4, ['long']],
    'ks' : [ 0x8, ['array', 5324, ['unsigned char']]],
    'ks2' : [ 0x14d4, ['array', 5324, ['unsigned char']]],
    'hiddenVolume' : [ 0x29a0, ['long']],
    'HeaderVersion' : [ 0x29a4, ['unsigned short']],
    'gf_ctx' : [ 0x29a8, ['GfCtx']],
    'master_keydata' : [ 0x4190, ['array', 256, ['unsigned char']]],
    'k2' : [ 0x42a8, ['array', 256, ['unsigned char']]],
    'salt' : [ 0x43a8, ['array', 64, ['unsigned char']]],
    'noIterations' : [ 0x43e8, ['long']],
    'pkcs5' : [ 0x43ec, ['long']],
    'volume_creation_time' : [ 0x43f0, ['unsigned long long']],
    'header_creation_time' : [ 0x43f8, ['unsigned long long']],
    'bProtectHiddenVolume' : [ 0x4400, ['long']],
    'bHiddenVolProtectionAction' : [ 0x4404, ['long']],
    'volDataAreaOffset' : [ 0x4408, ['unsigned long long']],
    'hiddenVolumeSize' : [ 0x4410, ['unsigned long long']],
    'hiddenVolumeOffset' : [ 0x4418, ['unsigned long long']],
    'hiddenVolumeProtectedSize' : [ 0x4420, ['unsigned long long']],
    'bPartitionInInactiveSysEncScope' : [ 0x4428, ['long']],
    'FirstDataUnitNo' : [ 0x4430, ['UINT64_STRUCT']],
    'RequiredProgramVersion' : [ 0x4438, ['unsigned short']],
    'LegacyVolume' : [ 0x443c, ['long']],
    'SectorSize' : [ 0x4440, ['unsigned long']],
    'VolumeSize' : [ 0x4448, ['UINT64_STRUCT']],
    'EncryptedAreaStart' : [ 0x4450, ['UINT64_STRUCT']],
    'EncryptedAreaLength' : [ 0x4458, ['UINT64_STRUCT']],
    'HeaderFlags' : [ 0x4460, ['unsigned long']],
    } ],
  'Password' : [ 0x48, {
    'Length' : [ 0x0, ['unsigned long']],
    'Text' : [ 0x4, ['array', 65, ['unsigned char']]],
    'Pad' : [ 0x45, ['array', 3, ['unsigned char']]],
    } ],
  'EXTENSION' : [ 0x5e0, {
    'bRootDevice' : [ 0x0, ['long']],
    'IsVolumeDevice' : [ 0x4, ['long']],
    'IsDriveFilterDevice' : [ 0x8, ['long']],
    'IsVolumeFilterDevice' : [ 0xc, ['long']],
    'UniqueVolumeId' : [ 0x10, ['long']],
    'nDosDriveNo' : [ 0x14, ['long']],
    'bShuttingDown' : [ 0x18, ['long']],
    'bThreadShouldQuit' : [ 0x1c, ['long']],
    'peThread' : [ 0x20, ['pointer64', ['_KTHREAD']]],
    'keCreateEvent' : [ 0x28, ['_KEVENT']],
    'ListSpinLock' : [ 0x40, ['unsigned long long']],
    'ListEntry' : [ 0x48, ['_LIST_ENTRY']],
    'RequestSemaphore' : [ 0x58, ['_KSEMAPHORE']],
    'hDeviceFile' : [ 0x78, ['pointer64', ['void']]],
    'pfoDeviceFile' : [ 0x80, ['pointer64', ['_FILE_OBJECT']]],
    'pFsdDevice' : [ 0x88, ['pointer64', ['_DEVICE_OBJECT']]],
    'cryptoInfo' : [ 0x90, ['pointer64', ['CRYPTO_INFO_t']]],
    'HostLength' : [ 0x98, ['long long']],
    'DiskLength' : [ 0xa0, ['long long']],
    'NumberOfCylinders' : [ 0xa8, ['long long']],
    'TracksPerCylinder' : [ 0xb0, ['unsigned long']],
    'SectorsPerTrack' : [ 0xb4, ['unsigned long']],
    'BytesPerSector' : [ 0xb8, ['unsigned long']],
    'PartitionType' : [ 0xbc, ['unsigned char']],
    'HostBytesPerSector' : [ 0xc0, ['unsigned long']],
    'keVolumeEvent' : [ 0xc8, ['_KEVENT']],
    'Queue' : [ 0xe0, ['EncryptedIoQueue']],
    'bReadOnly' : [ 0x340, ['long']],
    'bRemovable' : [ 0x344, ['long']],
    'PartitionInInactiveSysEncScope' : [ 0x348, ['long']],
    'bRawDevice' : [ 0x34c, ['long']],
    'bMountManager' : [ 0x350, ['long']],
    'SystemFavorite' : [ 0x354, ['long']],
    'wszVolume' : [ 0x358, ['array', 260, ['wchar']]],
    'fileCreationTime' : [ 0x560, ['_LARGE_INTEGER']],
    'fileLastAccessTime' : [ 0x568, ['_LARGE_INTEGER']],
    'fileLastWriteTime' : [ 0x570, ['_LARGE_INTEGER']],
    'fileLastChangeTime' : [ 0x578, ['_LARGE_INTEGER']],
    'bTimeStampValid' : [ 0x580, ['long']],
    'UserSid' : [ 0x588, ['pointer64', ['void']]],
    'SecurityClientContextValid' : [ 0x590, ['long']],
    'SecurityClientContext' : [ 0x598, ['_SECURITY_CLIENT_CONTEXT']],
    } ],
}

vc_124_vtypes_x86 = {
  'UINT64_STRUCT' : [ 0x8, {
    'LowPart' : [ 0x0, ['unsigned long']],
    'HighPart' : [ 0x4, ['unsigned long']],
    'Value' : [ 0x0, ['unsigned long long']],
    } ],
  'CRYPTO_INFO_t' : [ 0x4468, {
    'ea' : [ 0x0, ['long']],
    'mode' : [ 0x4, ['long']],
    'ks' : [ 0x8, ['array', 5324, ['unsigned char']]],
    'ks2' : [ 0x14d4, ['array', 5324, ['unsigned char']]],
    'hiddenVolume' : [ 0x29a0, ['long']],
    'HeaderVersion' : [ 0x29a4, ['unsigned short']],
    'gf_ctx' : [ 0x29a8, ['GfCtx']],
    'master_keydata' : [ 0x4190, ['array', 256, ['unsigned char']]],
    'k2' : [ 0x42a8, ['array', 256, ['unsigned char']]],
    'salt' : [ 0x43a8, ['array', 64, ['unsigned char']]],
    'noIterations' : [ 0x43e8, ['long']],
    'pkcs5' : [ 0x43ec, ['long']],
    'volume_creation_time' : [ 0x43f0, ['unsigned long long']],
    'header_creation_time' : [ 0x43f8, ['unsigned long long']],
    'bProtectHiddenVolume' : [ 0x4400, ['long']],
    'bHiddenVolProtectionAction' : [ 0x4404, ['long']],
    'volDataAreaOffset' : [ 0x4408, ['unsigned long long']],
    'hiddenVolumeSize' : [ 0x4410, ['unsigned long long']],
    'hiddenVolumeOffset' : [ 0x4418, ['unsigned long long']],
    'hiddenVolumeProtectedSize' : [ 0x4420, ['unsigned long long']],
    'bPartitionInInactiveSysEncScope' : [ 0x4428, ['long']],
    'FirstDataUnitNo' : [ 0x4430, ['UINT64_STRUCT']],
    'RequiredProgramVersion' : [ 0x4438, ['unsigned short']],
    'LegacyVolume' : [ 0x443c, ['long']],
    'SectorSize' : [ 0x4440, ['unsigned long']],
    'VolumeSize' : [ 0x4448, ['UINT64_STRUCT']],
    'EncryptedAreaStart' : [ 0x4450, ['UINT64_STRUCT']],
    'EncryptedAreaLength' : [ 0x4458, ['UINT64_STRUCT']],
    'HeaderFlags' : [ 0x4460, ['unsigned long']],
    } ],
  'EXTENSION' : [ 0x4d0, {
    'bRootDevice' : [ 0x0, ['long']],
    'IsVolumeDevice' : [ 0x4, ['long']],
    'IsDriveFilterDevice' : [ 0x8, ['long']],
    'IsVolumeFilterDevice' : [ 0xc, ['long']],
    'UniqueVolumeId' : [ 0x10, ['long']],
    'nDosDriveNo' : [ 0x14, ['long']],
    'bShuttingDown' : [ 0x18, ['long']],
    'bThreadShouldQuit' : [ 0x1c, ['long']],
    'peThread' : [ 0x20, ['pointer', ['_KTHREAD']]],
    'keCreateEvent' : [ 0x24, ['_KEVENT']],
    'ListSpinLock' : [ 0x34, ['unsigned long']],
    'ListEntry' : [ 0x38, ['_LIST_ENTRY']],
    'RequestSemaphore' : [ 0x40, ['_KSEMAPHORE']],
    'hDeviceFile' : [ 0x54, ['pointer', ['void']]],
    'pfoDeviceFile' : [ 0x58, ['pointer', ['_FILE_OBJECT']]],
    'pFsdDevice' : [ 0x5c, ['pointer', ['_DEVICE_OBJECT']]],
    'cryptoInfo' : [ 0x60, ['pointer', ['CRYPTO_INFO_t']]],
    'HostLength' : [ 0x68, ['long long']],
    'DiskLength' : [ 0x70, ['long long']],
    'NumberOfCylinders' : [ 0x78, ['long long']],
    'TracksPerCylinder' : [ 0x80, ['unsigned long']],
    'SectorsPerTrack' : [ 0x84, ['unsigned long']],
    'BytesPerSector' : [ 0x88, ['unsigned long']],
    'PartitionType' : [ 0x8c, ['unsigned char']],
    'HostBytesPerSector' : [ 0x90, ['unsigned long']],
    'keVolumeEvent' : [ 0x94, ['_KEVENT']],
    'Queue' : [ 0xa8, ['EncryptedIoQueue']],
    'bReadOnly' : [ 0x248, ['long']],
    'bRemovable' : [ 0x24c, ['long']],
    'PartitionInInactiveSysEncScope' : [ 0x250, ['long']],
    'bRawDevice' : [ 0x254, ['long']],
    'bMountManager' : [ 0x258, ['long']],
    'SystemFavorite' : [ 0x25c, ['long']],
    'wszVolume' : [ 0x260, ['array', 260, ['wchar']]],
    'fileCreationTime' : [ 0x468, ['_LARGE_INTEGER']],
    'fileLastAccessTime' : [ 0x470, ['_LARGE_INTEGER']],
    'fileLastWriteTime' : [ 0x478, ['_LARGE_INTEGER']],
    'fileLastChangeTime' : [ 0x480, ['_LARGE_INTEGER']],
    'bTimeStampValid' : [ 0x488, ['long']],
    'UserSid' : [ 0x48c, ['pointer', ['void']]],
    'SecurityClientContextValid' : [ 0x490, ['long']],
    'SecurityClientContext' : [ 0x494, ['_SECURITY_CLIENT_CONTEXT']],
    } ],
  'Password' : [ 0x48, {
    'Length' : [ 0x0, ['unsigned long']],
    'Text' : [ 0x4, ['array', 65, ['unsigned char']]],
    'Pad' : [ 0x45, ['array', 3, ['unsigned char']]],
    } ],
}

vc_124_vtypes_x64 = {
  'UINT64_STRUCT' : [ 0x8, {
    'LowPart' : [ 0x0, ['unsigned long']],
    'HighPart' : [ 0x4, ['unsigned long']],
    'Value' : [ 0x0, ['unsigned long long']],
    } ],
  'CRYPTO_INFO_t' : [ 0x4468, {
    'ea' : [ 0x0, ['long']],
    'mode' : [ 0x4, ['long']],
    'ks' : [ 0x8, ['array', 5324, ['unsigned char']]],
    'ks2' : [ 0x14d4, ['array', 5324, ['unsigned char']]],
    'hiddenVolume' : [ 0x29a0, ['long']],
    'HeaderVersion' : [ 0x29a4, ['unsigned short']],
    'gf_ctx' : [ 0x29a8, ['GfCtx']],
    'master_keydata' : [ 0xc, ['array', 256, ['unsigned char']]],
    'master_keydata2' : [ 0x14c4, ['array', 256, ['unsigned char']]],
    'k2' : [ 0x42a8, ['array', 256, ['unsigned char']]],
    'salt' : [ 0x43a8, ['array', 64, ['unsigned char']]],
    'noIterations' : [ 0x43e8, ['long']],
    'pkcs5' : [ 0x43ec, ['long']],
    'volume_creation_time' : [ 0x43f0, ['unsigned long long']],
    'header_creation_time' : [ 0x43f8, ['unsigned long long']],
    'bProtectHiddenVolume' : [ 0x4400, ['long']],
    'bHiddenVolProtectionAction' : [ 0x4404, ['long']],
    'volDataAreaOffset' : [ 0x4408, ['unsigned long long']],
    'hiddenVolumeSize' : [ 0x4410, ['unsigned long long']],
    'hiddenVolumeOffset' : [ 0x4418, ['unsigned long long']],
    'hiddenVolumeProtectedSize' : [ 0x4420, ['unsigned long long']],
    'bPartitionInInactiveSysEncScope' : [ 0x4428, ['long']],
    'FirstDataUnitNo' : [ 0x4430, ['UINT64_STRUCT']],
    'RequiredProgramVersion' : [ 0x4438, ['unsigned short']],
    'LegacyVolume' : [ 0x443c, ['long']],
    'SectorSize' : [ 0x4440, ['unsigned long']],
    'VolumeSize' : [ 0x4448, ['UINT64_STRUCT']],
    'EncryptedAreaStart' : [ 0x4450, ['UINT64_STRUCT']],
    'EncryptedAreaLength' : [ 0x4458, ['UINT64_STRUCT']],
    'HeaderFlags' : [ 0x4460, ['unsigned long']],
    } ],
  'Password' : [ 0x48, {
    'Length' : [ 0x0, ['unsigned long']],
    'Text' : [ 0x4, ['array', 65, ['unsigned char']]],
    'Pad' : [ 0x45, ['array', 3, ['unsigned char']]],
    } ],
  'EXTENSION' : [ 0x5e0, {
    'bRootDevice' : [ 0x0, ['long']],
    'IsVolumeDevice' : [ 0x4, ['long']],
    'IsDriveFilterDevice' : [ 0x8, ['long']],
    'IsVolumeFilterDevice' : [ 0xc, ['long']],
    'UniqueVolumeId' : [ 0x10, ['long']],
    'nDosDriveNo' : [ 0x14, ['long']],
    'bShuttingDown' : [ 0x18, ['long']],
    'bThreadShouldQuit' : [ 0x1c, ['long']],
    'peThread' : [ 0x20, ['pointer64', ['_KTHREAD']]],
    'keCreateEvent' : [ 0x28, ['_KEVENT']],
    'ListSpinLock' : [ 0x40, ['unsigned long long']],
    'ListEntry' : [ 0x48, ['_LIST_ENTRY']],
    'RequestSemaphore' : [ 0x58, ['_KSEMAPHORE']],
    'hDeviceFile' : [ 0x78, ['pointer64', ['void']]],
    'pfoDeviceFile' : [ 0x80, ['pointer64', ['_FILE_OBJECT']]],
    'pFsdDevice' : [ 0x88, ['pointer64', ['_DEVICE_OBJECT']]],
    'cryptoInfo' : [ 0x90, ['pointer64', ['CRYPTO_INFO_t']]],
    'HostLength' : [ 0x98, ['long long']],
    'DiskLength' : [ 0xa0, ['long long']],
    'NumberOfCylinders' : [ 0xa8, ['long long']],
    'TracksPerCylinder' : [ 0xb0, ['unsigned long']],
    'SectorsPerTrack' : [ 0xb4, ['unsigned long']],
    'BytesPerSector' : [ 0xb8, ['unsigned long']],
    'PartitionType' : [ 0xbc, ['unsigned char']],
    'HostBytesPerSector' : [ 0xc0, ['unsigned long']],
    'keVolumeEvent' : [ 0xc8, ['_KEVENT']],
    'Queue' : [ 0xe0, ['EncryptedIoQueue']],
    'bReadOnly' : [ 0x340, ['long']],
    'bRemovable' : [ 0x344, ['long']],
    'PartitionInInactiveSysEncScope' : [ 0x348, ['long']],
    'bRawDevice' : [ 0x34c, ['long']],
    'bMountManager' : [ 0x350, ['long']],
    'SystemFavorite' : [ 0x354, ['long']],
    'wszVolume' : [ 0x358, ['array', 260, ['wchar']]],
    'fileCreationTime' : [ 0x560, ['_LARGE_INTEGER']],
    'fileLastAccessTime' : [ 0x568, ['_LARGE_INTEGER']],
    'fileLastWriteTime' : [ 0x570, ['_LARGE_INTEGER']],
    'fileLastChangeTime' : [ 0x578, ['_LARGE_INTEGER']],
    'bTimeStampValid' : [ 0x580, ['long']],
    'UserSid' : [ 0x588, ['pointer64', ['void']]],
    'SecurityClientContextValid' : [ 0x590, ['long']],
    'SecurityClientContext' : [ 0x598, ['_SECURITY_CLIENT_CONTEXT']],
    } ],
}

#---------------------------------------------------------------------
# VeracryptPassphrase Plugin
#---------------------------------------------------------------------
            
class VeracryptPassphrase(common.AbstractWindowsCommand):
    """Veracrypt Cached Passphrase Finder"""

    def __init__(self, config, *args, **kwargs):
        common.AbstractWindowsCommand.__init__(self, config, *args, **kwargs)
        config.add_option('MIN-LENGTH', short_option = 'M', default = 4,
                          help = 'Mimumim length of passphrases to identify',
                          action = 'store', type = 'int')

    @staticmethod
    def scan_module(addr_space, module_base, min_length):
        
        dos_header = obj.Object("_IMAGE_DOS_HEADER", 
                                offset = module_base, 
                                vm = addr_space)

        nt_header = dos_header.get_nt_header()

        # Finding the PE data section 
        data_section = None
        for sec in nt_header.get_sections():
            if str(sec.Name) == ".data":
                data_section = sec
                break

        if not data_section:
            raise StopIteration

        base = sec.VirtualAddress + module_base
        size = sec.Misc.VirtualSize

        # Looking for the Length member, DWORD-aligned 
        ints = obj.Object("Array", targetType = "int", 
                          offset = base, count = size / 4, 
                          vm = addr_space)
                          
    
        for length in ints:
            # Min and max passphrase lengths 
            if length >= min_length and length <= 64:
                offset = length.obj_offset + 4
                passphrase = addr_space.read(offset, length)
                if not passphrase:
                    continue
                # All characters in the range must be ASCII
                chars = [c for c in passphrase if ord(c) >= 0x20 and ord(c) <= 0x7F]
                if len(chars) != length:
                    continue
                # At least three zero-bad bytes must follow 
                if addr_space.read(offset + length, 3) != "\x00" * 3:
                    continue
                yield offset, passphrase 

    def calculate(self):
        addr_space = utils.load_as(self._config)
        for mod in modules.lsmod(addr_space):
            # Finding the VC kernel module
            if str(mod.BaseDllName).lower() == "veracrypt.sys" or str(mod.BaseDllName).lower() == "veracrypt-x64.sys":        
                for offset, password in self.scan_module(addr_space, mod.DllBase, self._config.MIN_LENGTH):
                    yield offset, password

    def render_text(self, outfd, data):
        for offset, passphrase in data:
            outfd.write("Found at {0:#x} length {1}: {2}\n".format(
                offset, len(passphrase), passphrase))

#---------------------------------------------------------------------
# VeracryptSummary Plugin
#---------------------------------------------------------------------

class VeracryptSummary(common.AbstractWindowsCommand):
    """Veracrypt Summary"""

    def calculate(self):
        addr_space = utils.load_as(self._config)

        # we currently don't use this on x64 because for some reason the 
        # x64 version actually doesn't create a DisplayVersion value 
        memory_model = addr_space.profile.metadata.get('memory_model')
        if memory_model == '32bit':
            regapi = registryapi.RegistryApi(self._config)
            regapi.reset_current()
            regapi.set_current(hive_name = "software")
            x86key = "Microsoft\\Windows\\CurrentVersion\\Uninstall"
            x64key = "Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
            for subkey in regapi.reg_get_all_subkeys(None, key = x86key):
                if str(subkey.Name) == "Veracrypt":
                    subpath = x86key + "\\" + subkey.Name
                    version = regapi.reg_get_value("software", 
                                            key = subpath, 
                                            value = "DisplayVersion")
                    if version:
                        yield "Registry Version", "{0} Version {1}".format(
                            str(subkey.Name),
                            version)

        scanner = VeracryptPassphrase(self._config)
        for offset, passphrase in scanner.calculate():
            yield "Password", "{0} at offset {1:#x}".format(
                        passphrase, offset)

        for proc in tasks.pslist(addr_space):
            if str(proc.ImageFileName).lower() == "veracrypt.exe":     
                yield "Process", "{0} at {1:#x} pid {2}".format(
                        proc.ImageFileName,
                        proc.obj_offset, 
                        proc.UniqueProcessId)   

        scanner = svcscan.SvcScan(self._config)
        for service in scanner.calculate():
            name = str(service.ServiceName.dereference())
            if name == "veracrypt":
                yield "Service", "{0} state {1}".format(
                        name, 
                        service.State)

        for mod in modules.lsmod(addr_space):
            basename = str(mod.BaseDllName or '').lower()
            fullname = str(mod.FullDllName or '').lower()
            if (basename.endswith(("veracrypt.sys","veracrypt-x64.sys")) or 
                        fullname.endswith(("veracrypt.sys","veracrypt-x64.sys"))):
                yield "Kernel Module",  "{0} at {1:#x} - {2:#x}".format(
                        mod.BaseDllName, 
                        mod.DllBase, 
                        mod.DllBase + mod.SizeOfImage)

        scanner = filescan.SymLinkScan(self._config)
        for symlink in scanner.calculate():
            object_header = symlink.get_object_header()
            if "VeraCryptVolume" in str(symlink.LinkTarget or ''):
                yield "Symbolic Link", "{0} -> {1} mounted {2}".format(
                        str(object_header.NameInfo.Name or ''), 
                        str(symlink.LinkTarget or ''), 
                        str(symlink.CreationTime or ''))

        scanner = filescan.FileScan(self._config)
        for fileobj in scanner.calculate():
            filename = str(fileobj.file_name_with_device() or '')
            if "VeraCryptVolume" in filename:
                yield "File Object", "{0} at {1:#x}".format(
                        filename,
                        fileobj.obj_offset)
        
        scanner = filescan.DriverScan(self._config)
        for driver in scanner.calculate():
            object_header = driver.get_object_header() 
            driverext = driver.DriverExtension
            drivername = str(driver.DriverName or '')
            servicekey = str(driverext.ServiceKeyName or '')
            if (drivername.endswith("veracrypt") or 
                        servicekey.endswith("veracrypt")):
                yield "Driver", "{0} at {1:#x} range {2:#x} - {3:#x}".format(
                        drivername, 
                        driver.obj_offset, 
                        driver.DriverStart, 
                        driver.DriverStart + driver.DriverSize)
                for device in driver.devices():
                    header = device.get_object_header()
                    devname = str(header.NameInfo.Name or '')
                    type = devicetree.DEVICE_CODES.get(device.DeviceType.v())
                    yield "Device", "{0} at {1:#x} type {2}".format(
                        devname or "<HIDDEN>", 
                        device.obj_offset, 
                        type or "UNKNOWN")
                    if type == "FILE_DEVICE_DISK":
                        data = addr_space.read(device.DeviceExtension, 2000)
                        ## the file-hosted container path. no other fields in
                        ## the struct are character based, so we should not 
                        ## hit false positives on this scan. 
                        try:
                            offset = data.find("\\\x00?\x00?\x00\\\x00")
                            if offset == -1:
                                container = "<HIDDEN>"
                            else:
                                container = obj.Object("String", length = 255, 
                                            offset = device.DeviceExtension + offset, 
                                            encoding = "utf16",
                                            vm = addr_space)
                            yield "Container", "Path: {0}".format(container)
                        except AttributeError:
                            print "AttributeError at Line 388ff"

    def render_text(self, outfd, data):
        for field, info in data:
            outfd.write("{0:20} {1}\n".format(field, info))

#---------------------------------------------------------------------
# VeraCryptMaster Plugin
#---------------------------------------------------------------------

class VeraCryptMaster(common.AbstractWindowsCommand):
    """Recover VeraCrypt 1.22 Master Keys"""

    version_map = {
            # the most recent - released mar 2018
            '1.22' : {'32bit': vc_122_vtypes_x86, '64bit': vc_122_vtypes_x64},
            '1.24' : {'32bit': vc_124_vtypes_x86, '64bit': vc_124_vtypes_x64}, 
            }
    
    def __init__(self, config, *args, **kwargs):
        common.AbstractWindowsCommand.__init__(self, config, *args, **kwargs)
        config.add_option('DUMP-DIR', short_option = 'D', default = None,
                        help = 'Directory in which to dump the keys')
        config.add_option('VERSION', short_option = 'T', default = '1.22', 
                        help = 'Veracrypt version string (default: 1.22)')

    @staticmethod
    def apply_types(addr_space, ver):
        """Apply the VeraCrypt types for a specific version of VC. 

        @param addr_space: <volatility.BaseAddressSpace>
        @param ver: <string> version 
        """

        mm_model = addr_space.profile.metadata.get('memory_model', '32bit')
        try:
            vtypes = VeraCryptMaster.version_map[str(ver)][mm_model]
            addr_space.profile.vtypes.update(vtypes)
            addr_space.profile.merge_overlay({
            'EXTENSION' : [ None, {
                'wszVolume' : [ None, ['String', dict(length = 260, encoding = "utf16")]],
            }], 
            'CRYPTO_INFO_t' : [ None, { 
                'mode' : [ None, ['Enumeration', dict(target = "long", 
                            choices = {1: 'XTS', 
                                       2: 'LWR', 
                                       3: 'CBC', 
                                       4: 'OUTER_CBC', 
                                       5: 'INNER_CBC'})]],
                'ea' : [ None, ['Enumeration', dict(target = "long", 
                            choices = {1: 'AES', 
                                       2: 'SERPENT', 
                                       3: 'TWOFISH', 
                                       4: 'BLOWFISH', 
                                       5: 'CAST', 
                                       6: 'TRIPLEDES'})]],
            }]})
            addr_space.profile.compile()
        except KeyError:
            debug.error("Veracrypt version {0} is not supported".format(ver))

    def calculate(self):
        addr_space = utils.load_as(self._config)
        self.apply_types(addr_space, self._config.VERSION)
        scanner = filescan.DriverScan(self._config)
        for driver in scanner.calculate():    
            drivername = str(driver.DriverName or '')
            if drivername.endswith("veracrypt"):
                for device in driver.devices():
                    code = device.DeviceType.v()
                    type = devicetree.DEVICE_CODES.get(code)
                    if type == 'FILE_DEVICE_DISK':
                        yield device
        
    def render_text(self, outfd, data):
        for device in data:
            ext = device.DeviceExtension.dereference_as("EXTENSION")
            if not ext.is_valid():
                continue
            outfd.write("Container: {0}\n".format(ext.wszVolume))
            outfd.write("Hidden Volume: {0}\n".format("Yes" if ext.cryptoInfo.hiddenVolume == 1 else "No"))
            outfd.write("Removable: {0}\n".format("Yes" if ext.bRemovable == 1 else "No"))
            outfd.write("Read Only: {0}\n".format("Yes" if ext.bReadOnly == 1 else "No"))
            outfd.write("Disk Length: {0} (bytes)\n".format(ext.DiskLength))
            outfd.write("Host Length: {0} (bytes)\n".format(ext.HostLength))
            outfd.write("Encryption Algorithm: {0}\n".format(ext.cryptoInfo.ea))
            outfd.write("Mode: {0}\n".format(ext.cryptoInfo.mode))
            outfd.write("Master Key\n")
            if self._config.VERSION == "1.24":
                key1 = device.obj_vm.read(ext.cryptoInfo.master_keydata.obj_offset, 32)
                key2 = device.obj_vm.read(ext.cryptoInfo.master_keydata2.obj_offset, 32)
                addr = ext.cryptoInfo.master_keydata.obj_offset
                outfd.write("{0}\n".format("\n".join(
                        ["{0:#010x}  {1:<48}  {2}".format(addr + o, h, ''.join(c))
                        for o, h, c in utils.Hexdump(key1+key2)
                        ])))    
            else:
                key = device.obj_vm.read(ext.cryptoInfo.master_keydata.obj_offset, 32)
                addr = ext.cryptoInfo.master_keydata.obj_offset
                outfd.write("{0}\n".format("\n".join(
                        ["{0:#010x}  {1:<48}  {2}".format(addr + o, h, ''.join(c))
                        for o, h, c in utils.Hexdump(key)
                        ])))
            if self._config.DUMP_DIR:
                if not os.path.isdir(self._config.DUMP_DIR):
                    debug.error("The path {0} is not a valid directory".format(self._config.DUMP_DIR))
                name = "{0:#x}_master.key".format(addr)
                keyfile = os.path.join(self._config.DUMP_DIR, name)
                with open(keyfile, "wb") as handle:
                    if self._config.VERSION == "1.24":
                        handle.write(key1)
                        handle.write(key2)
                        outfd.write("Dumped {0} + {1} bytes to {2}\n".format(len(key1),len(key2), keyfile))
                    else:
                        handle.write(key)
                        outfd.write("Dumped {0} bytes to {1}\n".format(len(key), keyfile))
            outfd.write("\n")
