Skip to content
Please update to the latest release 0.77.3 to address Multiple CVEs.
Windows.Forensics.Amcache

Windows.Forensics.Amcache

Parses the Amcache.hve registry hive to enumerate executed binaries, installed programs, and drivers.

The Amcache.hve is a registry artifact that stores metadata used by the OS’s application compatibility infrastructure to record metadata about binaries present on the system. This includes file paths, hashes, timestamps, and install/interaction information for executables and drivers.

NOTE: potential evidence of execution must be corroborated by additional artifacts.


name: Windows.Forensics.Amcache
author: Matthieu Chatelan, Yann Malherbe
description: |
  Parses the Amcache.hve registry hive to enumerate executed binaries,
  installed programs, and drivers.
  
  The Amcache.hve is a registry artifact that stores metadata used by
  the OS's application compatibility infrastructure to record metadata
  about binaries present on the system. This includes file paths,
  hashes, timestamps, and install/interaction information for
  executables and drivers.

  NOTE: potential evidence of execution must be corroborated by
  additional artifacts.

reference:
    - https://www.ssi.gouv.fr/uploads/2019/01/anssi-coriin_2019-analysis_amcache.pdf
    - https://github.com/libyal/dtformats/blob/main/documentation/AMCache%20file%20(AMCache.hve)%20format.asciidoc

type: CLIENT

precondition: SELECT OS From info() where OS = 'windows'

parameters:
  - name: amCacheGlob
    default: "%SYSTEMROOT%/appcompat/Programs/Amcache.hve"
  - name: NTFS_CACHE_SIZE
    type: int
    default: 1000

  - name: File
    description: Version `From Windows 8/2012 to Windows 10 1709`. This key is constituted of several subkeys where each representing a volume GUID that contains subkeys looking like `Root\File\<GUID>\<MFTId>`
    type: bool
    default: Y

  - name: Programs
    description: Version `From Windows 8/2012 to Windows 10 1709`, This key contains installed programs only in subkeys like `Root\Programs\<AppID>` which contains information about the PE in subkeys.
    type: bool
    default: Y

  - name: Generic
    description: Version `From Windows 8 to Windows 10 1507`, The Generic key contains one subkey named 0, which in turn contains one subkey per driver installed on the system. Each of these subkeys is actually named as the SHA-1 of the driver it represents, preceded by ’0000’ like `\Root\Generic\0\0000<SHA1>`
    type: bool
    default: Y

  - name: InventoryDriverBinary
    description: Version `From Windows 10 1607`, n this key, each entry is named after the SHA-1 of the driver, preceded by ’0000’, and the subkey representing the drivers.
    type: bool
    default: N

  - name: InventoryApplication
    description: Version `From Windows 10 1607`, This key contains the installation of a program and also programs installed via an AppXPackage.
    type: bool
    default: Y

  - name: InventoryDeviceContainer
    description: Version `From Windows 10 1607`, records OS devices such as Bluetooth, printers, etc. Has links to DevicePnps
    type: bool
    default: N

  - name: InventoryDriverPackage
    description: Version `From Windows 10 1607`, records Package information that links to both DeviceContainers and DevicePnPs
    type: bool
    default: N

  - name: InventoryApplicationFile
    description: Version `From Windows 10 1607`, records EXE files that are part of a program.
    type: bool
    default: Y

  - name: InventoryDevicePnp
    description: Version `From Windows 10 1607`, records Plug and Play (PnP) devices such as Bluetooth, USB, etc. More verbose details than those contained in DeviceContainers
    type: bool
    default: N

  - name: InventoryApplicationShortcut
    description: Version `From Windows 10 1709`, contains information about LNK files found on the computer in the Start Menu directory
    type: bool
    default: Y

sources:
 - name: File
   query: |
      SELECT * FROM if(
        condition=File,
        then={
          SELECT * FROM foreach(
              row={
                SELECT FullPath from glob(globs=expand(path=amCacheGlob))
              },
              query={
                SELECT get(item=scope(), member="100") As ProductId,
                       get(item=scope(), member="101") As SHA1,
                       get(item=scope(), member="15") As FullPath,
                       get(item=scope(), member="11") As ModificationTime,
                       get(item=scope(), member="12") As CreationTime,
                       Key.Mtime as LastModifiedKey
                FROM read_reg_key(
                   root=pathspec(DelegatePath=FullPath),
                   globs='/Root/File/*/*',
                   accessor='raw_reg'
                )
              }
            )
        }
      )

 - name: Programs
   query: |
      SELECT * FROM if(
        condition=Programs,
        then={
            SELECT * FROM foreach(
          row={
            SELECT FullPath from glob(globs=expand(path=amCacheGlob))
          }, query={
                SELECT get(item=scope(), member="0") As Name,
                       get(item=scope(), member="1") As Version,
                       get(item=scope(), member="2") As Publisher,
                       get(item=scope(), member="a") As InstallationTime,
                       get(item=scope(), member="b") As UninstallationTime,
                       Key.Mtime as LastModifiedKey
                FROM read_reg_key(
                   root=pathspec(DelegatePath=FullPath),
                   globs='/Root/Programs/*',
                   accessor='raw_reg'
                )
            })
        }
      )

 - name: Generic
   query: |
      SELECT * FROM if(
        condition=Generic,
        then={
            SELECT * FROM foreach(
          row={
            SELECT FullPath from glob(globs=expand(path=amCacheGlob))
          }, query={
                SELECT Key.Mtime as LastModifiedKey,
                       Key.OSPath.Path as SHA1
                FROM read_reg_key(
                   root=pathspec(DelegatePath=FullPath),
                   globs='/Root/Generic/0/*',
                   accessor='raw_reg'
                )
            })
        }
      )

 - name: InventoryDriverBinary
   query: |
      SELECT * FROM if(
        condition=InventoryDriverBinary,
        then={
            SELECT * FROM foreach(
              row={
                SELECT FullPath from glob(globs=expand(path=amCacheGlob))
              }, query={
                SELECT Key.Mtime as Timestamp,
                       DriverName,
                       DriverVersion,
                       Product,
                       ProductVersion,
                       DriverCompany,
                       Service,
                       DriverType,
                       DriverTimeStamp,
                       ImageSize,
                       substr(str=DriverId, start=4, end=44) AS SHA1,
                       split(string=Key.OSPath.Path,sep='"')[1] as FullPath
                FROM read_reg_key(
                   root=pathspec(DelegatePath=FullPath),
                   globs='/Root/InventoryDriverBinary/*',
                   accessor='raw_reg'
                )
            })
        }
      )

 - name: InventoryApplication
   query: |
      SELECT * FROM if(
        condition=InventoryApplication,
        then={
            SELECT * FROM foreach(
              row={
                SELECT FullPath from glob(globs=expand(path=amCacheGlob))
              }, query={
                SELECT Key.Mtime as Timestamp,
                       Name,
                       PackageFullName,
                       Version,
                       Publisher,
                       Source AS SourceApp,
                       Type,
                       substr(str=ProgramInstanceId, start=4, end=44) AS SHA1,
                       ManifestPath,
                       InstallDate,
                       Language,
                       UninstallString

                FROM read_reg_key(
                   root=pathspec(DelegatePath=FullPath),
                   globs='/Root/InventoryApplication/*',
                   accessor='raw_reg'
                )
            })
        }
      )

 - name: InventoryDeviceContainer
   query: |
      SELECT * FROM if(
        condition=InventoryDeviceContainer,
        then={
            SELECT * FROM foreach(
              row={
                SELECT FullPath from glob(globs=expand(path=amCacheGlob))
              }, query={
                SELECT Key.Mtime as Timestamp,
                       ModelName,
                       FriendlyName,
                       ModelNumber,
                       Manufacturer,
                       PrimaryCategory,
                       Categories,
                       ModelId
                FROM read_reg_key(
                   root=pathspec(DelegatePath=FullPath),
                   globs='/Root/InventoryDeviceContainer/*',
                   accessor='raw_reg'
                )
            })
        }
      )

 - name: InventoryDriverPackage
   query: |
      SELECT * FROM if(
        condition=InventoryDriverPackage,
        then={
            SELECT * FROM foreach(
              row={
                SELECT FullPath from glob(globs=expand(path=amCacheGlob))
              }, query={
                SELECT Key.Mtime as Timestamp,
                       SYSFILE,
                       Version,
                       Provider,
                       Date,
                       Class,
                       Directory,
                       ClassGuid
                FROM read_reg_key(
                   root=pathspec(DelegatePath=FullPath),
                   globs='/Root/InventoryDriverPackage/*',
                   accessor='raw_reg'
                )
            })
        }
      )

 - name: InventoryApplicationFile
   query: |
      SELECT * FROM if(
        condition=InventoryApplicationFile,
        then={
            SELECT * FROM foreach(
              row={
                SELECT FullPath from glob(globs=expand(path=amCacheGlob))
              }, query={
                SELECT Key.Mtime as Timestamp,
                       Name,
                       ProductName,
                       ProductVersion,
                       Size,
                       Usn,
                       substr(str=FileId, start=4, end=44) AS SHA1,
                       LowerCaseLongPath AS FullPath,
                       OriginalFileName,
                       BinaryType,
                       LinkDate,
                       AppxPackageFullName
                FROM read_reg_key(
                   root=pathspec(DelegatePath=FullPath),
                   globs='/Root/InventoryApplicationFile/*',
                   accessor='raw_reg'
                )
            })
        }
      )

 - name: InventoryDevicePnp
   query: |
      SELECT * FROM if(
        condition=InventoryDevicePnp,
        then={
            SELECT * FROM foreach(
              row={
                SELECT FullPath from glob(globs=expand(path=amCacheGlob))
              }, query={
                SELECT Key.Mtime as Timestamp,
                       DriverName,
                       Enumerator,
                       Model,
                       Manufacturer,
                       Description,
                       InstallDate,
                       ParentId,
                       MatchingId
                FROM read_reg_key(
                   root=pathspec(DelegatePath=FullPath),
                   globs='/Root/InventoryDevicePnp/*',
                   accessor='raw_reg'
                )
            })
        }
      )

 - name: InventoryApplicationShortcut
   query: |
      SELECT * FROM if(
        condition=InventoryApplicationShortcut,
        then={
            SELECT * FROM foreach(
              row={
                SELECT FullPath from glob(globs=expand(path=amCacheGlob))
              }, query={
                SELECT Key.Mtime as Timestamp,
                       ShortcutPath
                FROM read_reg_key(
                   root=pathspec(DelegatePath=FullPath),
                   globs='/Root/InventoryApplicationShortcut/*',
                   accessor='raw_reg'
                )
            })
        }
      )