Windows.Forensics.Lnk

This artifact parses LNK shortcut files.

A LNK file is a type of Shell Item that serves as a shortcut or reference to a specific file, folder, or application. It contains metadata and information about the accessed file or location and is a valuable forensic artifact. LNK files can be automatically created by the Windows operating system when a user accesses a file from a supported application or manually created by the user.

This artifact has several configurable options:

  • TargetGlob: glob targeting. Default targets *.lnk files in Startup and Recent paths.
  • IOCRegex: Regex search on key fields: StringData, TrackerData and PropertyStore.
  • IgnoreRegex: Ignore regex filter on key fields.
  • UploadLnk: uploads lnk hits.
  • SuspiciousOnly: only returns LNK files reporting a suspicious attribute.
  • SusSize: Any lnk over this size in bytes is suspicious.
  • SusArgSize: Any lnk with Argument strings over this size is suspicious.
  • SusArgRegex: Regex for suspicious strings in Arguments.
  • SusHostnameRegex: Regex for suspicious TrackerData Hostname.
  • VmPrefixMAC: Regex to match known Virtual Machine MacAddress prefix in TrackerData.
  • RiskyExe: Regex target exe to flag as risky.

List of fields targeted by filter regex:

  • StringData.TargetPath
  • StringData.Name
  • StringData.RelativePath
  • StringData.WorkingDir
  • StringData.Arguments
  • StringData.IconLocation
  • LinkTarget.LinkTarget
  • PropertyStore
  • TrackerData.MachineID
  • TrackerData.MacAddress

NOTE: regex startof (^) and endof ($) line modifiers will not work.

Windows.Forensics.Lnk also will highlight suspicious lnk attributes in a Suspicious field.

  • Large Size - Check for large size, default over 20000 bytes
  • Startup Path - Path with \Startup\
  • Zeroed Headers - Check for ShellHeader items zeroed.
  • Hidden window - Check for ShellLinkHeader.ShowCommand as SHOWMINNOACTIVE
  • Target Changed path - Check LNK TargetPath different from PropertyStore path.
  • Target Changed size - Check LNK ShellLinkHeader.FileSize different from PropertyStore size.
  • Risky target - Checks several LNK target paths to the RiskyExe regex.
  • WebDAV - Checks for NetworkProviderType = WNNC_NET_DAV
  • Line break in StringData.Name
  • Suspicious argument size - large sized arguments over 250 characters as default
  • Environment variable script - environment variable with a common script configured (bat|cmd|ps1|js|vbs|vbe|py)
  • No Target with environment variable - environment variable only execution
  • Suspicious hostname - some common malicious hostnames
  • Created in VM - Check TrackerData MacAddress for known VM prefix
  • Local Admin- check PropertyStore for indications LNK created by local admin UID 500
  • Cyrillic Language - check PropertyStore for Cyrillic strings
  • Chinese Language - check PropertyStore for Chinese strings
  • Korean Language - check PropertyStore for Korean strings
  • Persian Language - check PropertyStore for Persian strings
  • Vietnamese Language - check PropertyStore for Vietnamese strings
  • CodePage - checks for existence of a ExtraData code page setting. Rare enough to report on - 936:Simplified Chinese, 949:Korean, 950:Traditional Chinese
  • Has Overlay - check for overlay and extra data attached to LNK
  • Long Base64 - check for a long base64 blog over 20 decoded characters
  • Arguments have ticks - ticks are common in malicious LNK files
  • Arguments have environment variables - environment variables (%|$env:) are common in malicious LNKs
  • Arguments have rare characters - looks for specific rare characters that may indicate obfuscation (?|!|~|@)
  • Arguments have leading space - malicious LNK files may have a many leading spaces to obfuscate some tools
  • Arguments have http strings - LNKs are regularly used as a download cradle - https?://
  • Arguments have UNC strings
  • Suspicious arguments - some common malicious arguments observed in field (with mind to False positive)

name: Windows.Forensics.Lnk
author: Matt Green - @mgreen27
description: |
  This artifact parses LNK shortcut files.

  A LNK file is a type of Shell Item that serves as a shortcut or reference to a
  specific file, folder, or application. It contains metadata and information
  about the accessed file or location and is a valuable forensic artifact.
  LNK files can be automatically created by the Windows operating system when a
  user accesses a file from a supported application or manually created by the user.

  This artifact has several configurable options:

  - TargetGlob: glob targeting. Default targets *.lnk files in Startup and Recent paths.
  - IOCRegex: Regex search on key fields: StringData, TrackerData and PropertyStore.
  - IgnoreRegex: Ignore regex filter on key fields.
  - UploadLnk: uploads lnk hits.
  - SuspiciousOnly: only returns LNK files reporting a suspicious attribute.
  - SusSize: Any lnk over this size in bytes is suspicious.
  - SusArgSize: Any lnk with Argument strings over this size is suspicious.
  - SusArgRegex: Regex for suspicious strings in Arguments.
  - SusHostnameRegex: Regex for suspicious TrackerData Hostname.
  - VmPrefixMAC: Regex to match known Virtual Machine MacAddress prefix in TrackerData.
  - RiskyExe: Regex target exe to flag as risky.


  List of fields targeted by filter regex:

    - StringData.TargetPath
    - StringData.Name
    - StringData.RelativePath
    - StringData.WorkingDir
    - StringData.Arguments
    - StringData.IconLocation
    - LinkTarget.LinkTarget
    - PropertyStore
    - TrackerData.MachineID
    - TrackerData.MacAddress

    NOTE: regex startof (^) and endof ($) line modifiers will not work.


    Windows.Forensics.Lnk also will highlight suspicious lnk attributes in a Suspicious field.

    * Large Size - Check for large size, default over 20000 bytes
    * Startup Path - Path with \Startup\
    * Zeroed Headers - Check for ShellHeader items zeroed.
    * Hidden window - Check for ShellLinkHeader.ShowCommand as SHOWMINNOACTIVE
    * Target Changed path - Check LNK TargetPath different from PropertyStore path.
    * Target Changed size - Check LNK ShellLinkHeader.FileSize different from PropertyStore size.
    * Risky target - Checks several LNK target paths to the RiskyExe regex.
    * WebDAV - Checks for NetworkProviderType = WNNC_NET_DAV
    * Line break in StringData.Name
    * Suspicious argument size - large sized arguments over 250 characters as default
    * Environment variable script - environment variable with a common script configured (bat|cmd|ps1|js|vbs|vbe|py)
    * No Target with environment variable - environment variable only execution
    * Suspicious hostname - some common malicious hostnames
    * Created in VM - Check TrackerData MacAddress for known VM prefix
    * Local Admin- check PropertyStore for indications LNK created by local admin UID 500
    * Cyrillic Language - check PropertyStore for Cyrillic strings
    * Chinese Language - check PropertyStore for Chinese strings
    * Korean Language - check PropertyStore for Korean strings
    * Persian Language - check PropertyStore for Persian strings
    * Vietnamese Language - check PropertyStore for Vietnamese strings
    * CodePage - checks for existence of a ExtraData code page setting. Rare enough to report on - 936:Simplified Chinese, 949:Korean, 950:Traditional Chinese
    * Has Overlay - check for overlay and extra data attached to LNK
    * Long Base64 - check for a long base64 blog over 20 decoded characters
    * Arguments have ticks - ticks are common in malicious LNK files
    * Arguments have environment variables - environment variables (%|\$env:) are common in malicious LNKs
    * Arguments have rare characters - looks for specific rare characters that may indicate obfuscation (\?|\!|\~|\@)
    * Arguments have leading space - malicious LNK files may have a many leading spaces to obfuscate some tools
    * Arguments have http strings - LNKs are regularly used as a download cradle - https?://
    * Arguments have UNC strings
    * Suspicious arguments - some common malicious arguments observed in field (with mind to False positive)


reference:
  - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-shllink

parameters:
  - name: TargetGlob
    default: C:\{ProgramData,Users\*\AppData\*}\Microsoft\Windows\{Start Menu\Programs\StartUp,Recent\**}\*.lnk
  - name: IocRegex
    type: regex
    description: A regex to filter on all fields
  - name: IgnoreRegex
    type: regex
    description: A regex to ignore ilter all fields
  - name: UploadLnk
    description: Also upload the link files themselves.
    type: bool
  - name: SuspiciousOnly
    description: Only returns LNK files reporting a suspicious attribute
    type: bool
  - name: SusSize
    description: Any lnk over this size in bytes is suspicious.
    default: 20000
    type: int
  - name: SusArgSize
    default: 250
    description: Any lnk with Argument strings over this size is suspicious.
    type: int
  - name: SusArgRegex
    description: Regex for suspicious strings in Argumetns.
    type: regex
    default: \\AppData\\|\\Users\\Public\\|\\Temp\\|comspec|&cd&echo| -NoP | -W Hidden | [-/]decode | -e.* (JAB|SUVYI|SQBFAFgA|aWV4I|aQBlAHgA)|start\s*[\\/]b|\.downloadstring\(|\.downloadfile\(|iex
  - name: SusHostnameRegex
    description: Regex for suspicious TrackerData Hastname.
    type: regex
    default: ^(Win-|Desktop-|Commando$)
  - name: VmPrefixMAC
    description: VM MacAddress prefix regex to compate to LNK TrackerData.
    type: regex
    default: ^(00:50:56|00:0C:29|00:05:69|00:1C:14|08:00:27|52:54:00|00:21:F6|00:14:4F|00:0F:4B|00:15:5D)
  - name: RiskyExe
    description: Regex target exe to flag as risky.
    type: regex
    default: \\(cmd|powershell|cscript|wscript|rundll32|regsvr32|mshta|wmic|conhost)\.exe$


export: |
     LET S = scope()

     LET GetClassName(GUID) = get(item=KnownGUIDLookup, member=GUID) || (
        version(function="reg_set_value") != NULL && stat(accessor="registry",
        filename="HKEY_CLASSES_ROOT/CLSID/{" + GUID + "}/@").Data.value ) || GUID

     LET GetPropertyValues(Values) = to_dict(item={
        SELECT _value.Value.Value[0]  AS _value, _value.Value.Description[0] AS _key
        FROM foreach(row=Values)
      })

     LET KnownGUIDLookup <= dict(
       `20D04FE0-3AEA-1069-A2D8-08002B30309D`="My Computer",
       `F02C1A0D-BE21-4350-88B0-7367FC96EF3C`="Computers and Devices",
       `679F85CB-0220-4080-B29B-5540CC05AAB6`="Quick Access",
       `DE61D971-5EBC-4F02-A3A9-6C82895E5C04`='AddNewPrograms',
       `724EF170-A42D-4FEF-9F26-B60E846FBA4F`='AdminTools',
       `A520A1A4-1780-4FF6-BD18-167343C5AF16`='AppDataLow',
       `A305CE99-F527-492B-8B1A-7E76FA98D6E4`='AppUpdates',
       `9E52AB10-F80D-49DF-ACB8-4330F5687855`='CDBurning',
       `DF7266AC-9274-4867-8D55-3BD661DE872D`='ChangeRemovePrograms',
       `D0384E7D-BAC3-4797-8F14-CBA229B392B5`='CommonAdminTools',
       `C1BAE2D0-10DF-4334-BEDD-7AA20B227A9D`='CommonOEMLinks',
       `0139D44E-6AFE-49F2-8690-3DAFCAE6FFB8`='CommonPrograms',
       `A4115719-D62E-491D-AA7C-E74B8BE3B067`='CommonStartMenu',
       `82A5EA35-D9CD-47C5-9629-E15D2F714E6E`='CommonStartup',
       `B94237E7-57AC-4347-9151-B08C6C32D1F7`='CommonTemplates',
       `0AC0837C-BBF8-452A-850D-79D08E667CA7`='Computer',
       `4BFEFB45-347D-4006-A5BE-AC0CB0567192`='Conflict',
       `6F0CD92B-2E97-45D1-88FF-B0D186B8DEDD`='Connections',
       `56784854-C6CB-462B-8169-88E350ACB882`='Contacts',
       `82A74AEB-AEB4-465C-A014-D097EE346D63`='ControlPanel',
       `2B0F765D-C0E9-4171-908E-08A611B84FF6`='Cookies',
       `B4BFCC3A-DB2C-424C-B029-7FE99A87C641`='Desktop',
       `FDD39AD0-238F-46AF-ADB4-6C85480369C7`='Documents',
       `088E3905-0323-4B02-9826-5D99428E115F`='Downloads',
       `374DE290-123F-4565-9164-39C4925E467B`='Downloads',
       `1777F761-68AD-4D8A-87BD-30B759FA33DD`='Favorites',
       `FD228CB7-AE11-4AE3-864C-16F3910AB8FE`='Fonts',
       `CAC52C1A-B53D-4EDC-92D7-6B2E8AC19434`='Games',
       `054FAE61-4DD8-4787-80B6-090220C4B700`='GameTasks',
       `D9DC8A3B-B784-432E-A781-5A1130A75963`='History',
       `4D9F7874-4E0C-4904-967B-40B0D20C3E4B`='Internet',
       `352481E8-33BE-4251-BA85-6007CAEDCF9D`='InternetCache',
       `BFB9D5E0-C6A9-404C-B2B2-AE6DB6AF4968`='Links',
       `F1B32785-6FBA-4FCF-9D55-7B8E7F157091`='LocalAppData',
       `2A00375E-224C-49DE-B8D1-440DF7EF3DDC`='LocalizedResourcesDir',
       `4BD8D571-6D19-48D3-BE97-422220080E43`='Music',
       `3DFDF296-DBEC-4FB4-81D1-6A3438BCF4DE`="Music",
       `C5ABBF53-E17F-4121-8900-86626FC2C973`='NetHood',
       `D20BEEC4-5CA8-4905-AE3B-BF251EA09B53`='Network',
       `31C0DD25-9439-4F12-BF41-7FF4EDA38722`='Objects3D',
       `2C36C0AA-5812-4B87-BFD0-4CD0DFB19B39`='OriginalImages',
       `69D2CF90-FC33-4FB7-9A0C-EBB0F0FCB43C`='PhotoAlbums',
       `33E28130-4E1E-4676-835A-98395C3BC3BB`='Pictures',
       `24AD3AD4-A569-4530-98E1-AB02F9417AA8`="LocalPictures",
       `DE92C1C7-837F-4F69-A3BB-86E631204A23`='Playlists',
       `76FC4E2D-D6AD-4519-A663-37BD56068185`='Printers',
       `9274BD8D-CFD1-41C3-B35E-B13F55A758F4`='PrintHood',
       `5E6C858F-0E22-4760-9AFE-EA3317B67173`='Profile',
       `62AB5D82-FDC1-4DC3-A9DD-070D1D495D97`='ProgramData',
       `905E63B6-C1BF-494E-B29C-65B732D3D21A`='ProgramFiles',
       `F7F1ED05-9F6D-47A2-AAAE-29D317C6F066`='ProgramFilesCommon',
       `6365D5A7-0F0D-45E5-87F6-0DA56B6A4F7D`='ProgramFilesCommonX64',
       `DE974D24-D9C6-4D3E-BF91-F4455120B917`='ProgramFilesCommonX86',
       `6D809377-6AF0-444B-8957-A3773F02200E`='ProgramFilesX64',
       `7C5A40EF-A0FB-4BFC-874A-C0F2E0B9FA8E`='ProgramFilesX86',
       `A77F5D77-2E2B-44C3-A6A2-ABA601054A51`='Programs',
       `7B81BE6A-CE2B-4676-A29E-EB907A5126C5`='Programs and Features',
       `DFDF76A2-C82A-4D63-906A-5644AC457385`='Public',
       `C4AA340D-F20F-4863-AFEF-F87EF2E6BA25`='PublicDesktop',
       `ED4824AF-DCE4-45A8-81E2-FC7965083634`='PublicDocuments',
       `3D644C9B-1FB8-4F30-9B45-F670235F79C0`='PublicDownloads',
       `DEBF2536-E1A8-4C59-B6A2-414586476AEA`='PublicGameTasks',
       `3214FAB5-9757-4298-BB61-92A9DEAA44FF`='PublicMusic',
       `B6EBFB86-6907-413C-9AF7-4FC2ABF07CC5`='PublicPictures',
       `2400183A-6185-49FB-A2D8-4A392A602BA3`='PublicVideos',
       `52A4F021-7B75-48A9-9F6B-4B87A210BC8F`='QuickLaunch',
       `AE50C081-EBD2-438A-8655-8A092E34987A`='Recent',
       `BD85E001-112E-431E-983B-7B15AC09FFF1`='RecordedTV',
       `B7534046-3ECB-4C18-BE4E-64CD4CB7D6AC`='RecycleBin',
       `8AD10C31-2ADB-4296-A8F7-E4701232C972`='ResourceDir',
       `3EB685DB-65F9-4CF6-A03A-E3EF65729F3D`='RoamingAppData',
       `B250C668-F57D-4EE1-A63C-290EE7D1AA1F`='SampleMusic',
       `C4900540-2379-4C75-844B-64E6FAF8716B`='SamplePictures',
       `15CA69B3-30EE-49C1-ACE1-6B5EC372AFB5`='SamplePlaylists',
       `859EAD94-2E85-48AD-A71A-0969CB56A6CD`='SampleVideos',
       `4C5C32FF-BB9D-43B0-B5B4-2D72E54EAAA4`='SavedGames',
       `7D1D3A04-DEBB-4115-95CF-2F29DA2920DA`='SavedSearches',
       `EE32E446-31CA-4ABA-814F-A5EBD2FD6D5E`='SEARCH_CSC',
       `98EC0E18-2098-4D44-8644-66979315A281`='SEARCH_MAPI',
       `190337D1-B8CA-4121-A639-6D472D16972A`='SearchHome',
       `8983036C-27C0-404B-8F08-102D10DCFD74`='SendTo',
       `7B396E54-9EC5-4300-BE0A-2482EBAE1A26`='SidebarDefaultParts',
       `A75D362E-50FC-4FB7-AC2C-A8BEAA314493`='SidebarParts',
       `625B53C3-AB48-4EC1-BA1F-A1EF4146FC19`='StartMenu',
       `B97D20BB-F46A-4C97-BA10-5E3608430854`='Startup',
       `43668BF8-C14E-49B2-97C9-747784D784B7`='SyncManager',
       `289A9A43-BE44-4057-A41B-587A76D7E7F9`='SyncResults',
       `0F214138-B1D3-4A90-BBA9-27CBC0C5389A`='SyncSetup',
       `1AC14E77-02E7-4E5D-B744-2EB1AE5198B7`='System',
       `D65231B0-B2F1-4857-A4CE-A8E7C6EA7D27`='SystemX86',
       `A63293E8-664E-48DB-A079-DF759E0509F7`='Templates',
       `5B3749AD-B49F-49C1-83EB-15370FBD4882`='TreeProperties',
       `0762D272-C50A-4BB0-A382-697DCD729B80`='UserProfiles',
       `F3CE0F7C-4901-4ACC-8648-D5D44B04EF8F`='UsersFiles',
       `18989B1D-99B5-455B-841C-AB7C74E4DDFC`='Videos',
       `F86FA3AB-70D2-4FC7-9C99-FCBF05467F3A`='Videos',
       `F38BF404-1D43-42F2-9305-67DE0B28FC23`='Windows')

     LET _PropertyValueDispatcher <= dict(
       `20D04FE0-3AEA-1069-A2D8-08002B30309D`="x=>dict(LongName='ComputerName')",
       `D5CDD502-2E9C-101B-9397-08002B2CF9AE`="x=>x.__DocumentSummaryInformation",
       `28636AA6-953D-11D2-B5D6-00C04FD918D0`="x=>x.__SHELL_DETAILS",
       `446D16B1-8DAD-4870-A748-402EA43D788C`="x=>x.__CACHE",
       `46588AE2-4CBC-4338-BBFC-139326986DCE`="x=>x.__User",
       `841E4F90-FF59-4D16-8947-E81BBFFAB36D`="x=>x.__Software",
       `86407DB8-9DF7-48CD-B986-F999ADC19731`="x=>x.__Share",
       `86D40B4D-9069-443C-819A-2A54090DCCEC`="x=>x.__Tile",
       `9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3`="x=>x.__AppUserModel",
       `B725F130-47EF-101A-A5F1-02608C9EEBAC`="x=>x.__STORAGE",
       `DABD30ED-0043-4789-A7F8-D013A4736622`="x=>x.__FolderDisplay",
       `E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD`="x=>x.__SEARCH",
       `F29F85E0-4FF9-1068-AB91-08002B27B3D9`="x=>x.__Document",
       `DEBDA43A-37B3-4383-91E7-4498DA2995AB`="x=>x.__NetworkInfo",
       `FB8D2D7B-90D1-4E34-BF60-6EAC09922BBF`="x=>x.__Hash")

     LET PropertyValueDispatcher(x) = eval(
        args=[x,],
        func=get(item=_PropertyValueDispatcher,
                 member=x.ParentOf.Format,
                 default='x=>"GUID not known"'))

     LET Profile = '''
     [
      ["ShellLinkHeader", 0, [
        ["HeaderSize", 0, "uint32"],
        ["__LinkClsID", 4, "String", {
            "length": 16,
            "term": ""
        }],
        ["LinkClsID", 0, "Value", {
            "value": "x=>format(format='%x', args=x.__LinkClsID)"
        }],
        ["LinkFlags", 20, "Flags", {
            "type": "uint32",
            "bitmap": {
                "HasLinkTargetIDList": 0,
                "HasLinkInfo": 1,
                "HasName": 2,
                "HasRelativePath": 3,
                "HasWorkingDir": 4,
                "HasArguments": 5,
                "HasIconLocation": 6,
                "IsUnicode": 7,
                "ForceNoLinkInfo": 8,
                "HasExpString": 9,
                "RunInSeparateProcess": 10,
                "HasDarwinID": 12,
                "RunAsUser": 13,
                "HasExpIcon": 14,
                "NoPidlAlias": 15,
                "RunWithShimLayer": 17,
                "ForceNoLinkTrack": 18,
                "EnableTargetMetadata": 19,
                "DisableLinkPathTracking": 20,
                "DisableKnownFolderTracking": 21,
                "DisableKnownFolderAlias": 22,
                "AllowLinkToLink": 23,
                "UnaliasOnSave": 24,
                "PreferEnvironmentPath": 25,
                "KeepLocalIDListForUNCTarget": 26
            }
        }],
        ["FileAttributes", 24, "Flags", {
            "type": "uint32",
            "bitmap": {
                "FILE_ATTRIBUTE_READONLY": 0,
                "FILE_ATTRIBUTE_HIDDEN": 1,
                "FILE_ATTRIBUTE_SYSTEM": 2,
                "FILE_ATTRIBUTE_DIRECTORY": 4,
                "FILE_ATTRIBUTE_ARCHIVE": 5,
                "FILE_ATTRIBUTE_NORMAL": 7,
                "FILE_ATTRIBUTE_TEMPORARY": 8,
                "FILE_ATTRIBUTE_SPARSE_FILE": 9,
                "FILE_ATTRIBUTE_REPARSE_POINT": 10,
                "FILE_ATTRIBUTE_COMPRESSED": 11,
                "FILE_ATTRIBUTE_OFFLINE": 12,
                "FILE_ATTRIBUTE_NOT_CONTENT_INDEXED": 13,
                "FILE_ATTRIBUTE_ENCRYPTED": 14,
            }
        }],
        ["CreationTime", 28, "WinFileTime", {
            "type": "uint64"
        }],
        ["AccessTime", 36, "WinFileTime", {
            "type": "uint64"
        }],
        ["WriteTime", 44, "WinFileTime", {
            "type": "uint64"
        }],

        ["FileSize", 52, "uint32"],
        ["IconIndex", 56, "uint32"],
        ["ShowCommand", 60, "Enumeration", {
            "type": "uint32",
            "map": {
                "SHOWNORMAL": 0x00000001,
                "SHOWMAXIMIZED": 0x00000003,
                "SHOWMINNOACTIVE": 0x00000007,
            }
        }],
        ["__HotKeyLow", 62, "Enumeration", {
            "type": "uint8",
            "map": {
                "No key assigned." : 0x00,
                "0" :   0x30,
                "1" :   0x31,
                "2" :   0x32,
                "3" :   0x33,
                "4" :   0x34,
                "5" :   0x35,
                "6" :   0x36,
                "7" :   0x37,
                "8" :   0x38,
                "9" :   0x39,
                "A" :   0x41,
                "B" :   0x42,
                "C" :   0x43,
                "D" :   0x44,
                "E" :   0x45,
                "F" :   0x46,
                "G" :   0x47,
                "H" :   0x48,
                "I" :   0x49,
                "J" :   0x4A,
                "K" :   0x4B,
                "L" :   0x4C,
                "M" :   0x4D,
                "N" :   0x4E,
                "O" :   0x4F,
                "P" :   0x50,
                "Q" :   0x51,
                "R" :   0x52,
                "S" :   0x53,
                "T" :   0x54,
                "U" :   0x55,
                "V" :   0x56,
                "W" :   0x57,
                "X" :   0x58,
                "Y" :   0x59,
                "Z" :   0x5A,
                "F1" :   0x70,
                "F2" :   0x71,
                "F3" :   0x72,
                "F4" :   0x73,
                "F5" :   0x74,
                "F6" :   0x75,
                "F7" :   0x76,
                "F8" :   0x77,
                "F9" :   0x78,
                "F10" :   0x79,
                "F11" :   0x7A,
                "F12" :   0x7B,
                "F13" :   0x7C,
                "F14" :   0x7D,
                "F15" :   0x7E,
                "F16" :   0x7F,
                "F17" :   0x80,
                "F18" :   0x81,
                "F19" :   0x82,
                "F20" :   0x83,
                "F21" :   0x84,
                "F22" :   0x85,
                "F23" :   0x86,
                "F24" :   0x87,
                "NumLock" :   0x90,
                "ScrollLock" :   0x91,
            }
        }],
        ["__HotKeyHigh", 63, "Enumeration", {
            "type": "uint8",
            "map": {
                "No modifier key used." : 0x00,
                "SHIFT" : 0x01,
                "CONTROL" : 0x02,
                "ALT" : 0x04,
            }
        }],
        ["HotKey", 0, "Value", {
            "value": "x=>if(condition= x.__HotKeyLow=~'No key assigned',
                            then=x.__HotKeyLow,
                            else=x.__HotKeyLow + ' + ' + x.__HotKeyHigh)"

        }],

        # The LinkTargetIDList only exists if the Link Flag is set otherwise it is empty.
        ["LinkTargetIDList", "x=>x.HeaderSize", "Union", {
            "selector": "x=>x.LinkFlags =~ 'HasLinkTargetIDList'",
            "choices": {
                "true": "LinkTargetIDList",
                "false": "Empty"
            }
        }],
        ["LinkInfo", "x=>x.LinkTargetIDList.EndOf", "Union", {
            "selector": "x=>x.LinkFlags =~ 'HasLinkInfo'",
            "choices": {
                "true": "LinkInfo",
                "false": "Empty"
            }
        }],

        # StringData flag checks
        ["__Name", "x=>x.LinkInfo.EndOf", "Union", {
            "selector": "x=>x.LinkFlags =~ 'HasName'",
            "choices": {
                "true": "Name",
                "false": "Empty"
            }
        }],
        ["__RelativePath", "x=>x.__Name.EndOf", "Union", {
            "selector": "x=>x.LinkFlags =~ 'HasRelativePath'",
            "choices": {
                "true": "RelativePath",
                "false": "Empty"
            }
        }],
        ["__WorkingDir", "x=>x.__RelativePath.EndOf", "Union", {
            "selector": "x=>x.LinkFlags =~ 'HasWorkingDir'",
            "choices": {
                "true": "WorkingDir",
                "false": "Empty"
            }
        }],
        ["__Arguments", "x=>x.__WorkingDir.EndOf", "Union", {
            "selector": "x=>x.LinkFlags =~ 'HasArguments'",
            "choices": {
                "true": "Arguments",
                "false": "Empty"
            }
        }],
        ["__IconLocation", "x=>x.__Arguments.EndOf", "Union", {
            "selector": "x=>x.LinkFlags =~ 'HasIconLocation'",
            "choices": {
                "true": "IconLocation",
                "false": "Empty"
            }
        }],
        ["StringData",0,"StringData"],
        ["ExtraData", "x=>x.__IconLocation.EndOf", "Array", {
                "type": "ExtraData",
                "count": 1000,
                "sentinel": "x=>x.Size < 0x00000004"
            }],
        ["Overlay", "x=>x.ExtraData.EndOf", "Overlay"],

      ]],

      # Struct size includes the size field
      ["LinkTargetIDList", "x=>x.IDListSize + 2", [
        ["IDListSize", 0, "uint16"],
        ["IDList", 2, "Array", {
           "type": "ItemIDList",
           "count": 1000   # Max count until sentinel
         }]
      ]],

      # Item List contains shell bags
      ["ItemIDList", "x=>x.ItemIDSize", [
        ["ItemIDSize", 0, "uint16"],
        ["Offset", 0, "Value", {"value": "x=>x.StartOf"}],
        ["Type", 2, "uint8"],
        ["TypeHex", 0, Value, {
          value: "x=>format(format='%#02x', args=x.Type)",
        }],

        # https://github.com/EricZimmerman/Lnk/blob/a9e6ebcf7e032efd1172ff8a88a4e870b446fa18/Lnk/LnkFile.cs#L131
        ["ShellBag", 0, "Union", {
           "selector": "x=>format(format='%#02x', args=x.Type)",
            "choices": {
               "0x00": "ShellBag0x00",
               "0x01": "ShellBag0x01",
               "0x02": "ShellBag0x20",
               "0x03": "ShellBag0x30",
               "0x04": "ShellBag0x40",

               "0x13": "ShellBagZipContentsWithParent",
               "0x1f": "ShellBag0x1f",
               "0x20": "ShellBag0x20",
               "0x21": "ShellBag0x20",
               "0x22": "ShellBag0x20",
               "0x23": "ShellBag0x20",
               "0x2a": "ShellBag0x20",
               "0x2e": "ShellBag0x20",
               "0x2f": "ShellBag0x20",
               "0x31": "ShellBag0x30",
               "0x32": "ShellBag0x32",
               "0x35": "ShellBag0x30",
               "0x36": "ShellBag0x30",
               "0x3a": "ShellBag0x30",
               "0x3a": "ShellBag0x30",
               "0x3f": "ShellBagZipContentsWithParent",
               "0x41": "ShellBag0x40",
               "0x42": "ShellBag0x40",
               "0x43": "ShellBag0x40",
               "0x46": "ShellBag0x40",
               "0x47": "ShellBag0x40",
               "0x4b": "ShellBagZipContentsWithParent",
               "0x52": "ShellBagZipContentsWithParent",
               "0x61": "ShellBag0x61",
               "0x71": "ShellBag0x71",
               "0x74": "ShellBag0x74",
               "0x77": "ShellBag0x74",
               "0x79": "ShellBagZipContents",
               "0xaa": "ShellBagZipContents",
               "0xae": "ShellBagZipContents",
               "0xb1": "ShellBag0x30",
               "0xc3": "ShellBag0xc3",
            }
        }]
        ]],

      ["ShellBag0x00", 0, [
        ["DataSize", 4, "uint16"],
        ["__Magic", 4, "uint32"],
        ["DataSig", 6, "uint32"],
        ["PropertySheetListSize", 10, "uint16"],
        ["IdentifierSize", 12, "uint16"],
        ["IdentifierData", 14, String, {
          length: "x=>x.IdentifierSize",
        }],
        ["PropertyList", "x=>14 + x.IdentifierSize", Array, {
            type: "PropertyStorage",
            count: 10,
            sentinel: "x=>x.StorageSize = 0",
        }],
        ["Properties", 0, "Value", {
            "value": 'x=>GetPropertyValues(Values=x.PropertyList.PropertyValue)'
        }],
        ["__CDBurnType", 0, Value, {value: "x=>x.__Magic = 0x4d677541"}],
        ["__ZipFileContents", 0, "ShellBagZipContents"],
        ["__CDBurn", 0, "ShellBagCDBurn"],
        ["__ItemNameDisplay", 0, Value, {
            value: "x=>get(item=x.Properties, field='System.ItemNameDisplay')",
         }],

        # Handle some special cases.
        ["Description", 0, "Value", {
            value: "x=> (x.__CDBurnType && x.__CDBurn.Description) ||
                        (x.__ItemNameDisplay && dict(Type='Variable',
                                                     Properties=x.Properties,
                                                     LongName=x.__ItemNameDisplay) ) ||
                         x.__ZipFileContents.Description",
        }]
      ]],

      ["ShellBagCDBurn", 0, [
        ["DataSize", 20, "uint16"],

        # Variable length search for the extension signature from the start of the struct.
        ["__pre", 0, "String", {
           "term_hex": "0400efbe"
        }],

        # The extension tag should be immediately after the search string.
        ["__ExtensionTag", "x=>len(list=x.__pre)", "uint32"],

        # Extension starts 4 bytes before the tag
        ["Extension", "x=>len(list=x.__pre) - 4", "Union", {
             "selector": "x=>format(format='%#x', args=x.__ExtensionTag)",
             "choices": {
                 "0xbeef0004": "Beef0004",
             }
        }],

        # Put all the data together in a convenient location
        ["Description", 0, "Value", {
            "value": 'x=>dict(
                Type="CDBurn",
                LongName=x.Extension.LongName)',
        }],
      ]],

      ["ShellBag0x01", 0, [
        ["ItemSize", 0, "uint16"],
        ["__SpecialDataSig", 4, "uint32"],
        ["__SpecialDataSigString", 14, String, {
           length: "x=>x.ItemSize - 14",
           term: "",
        }],
        ["Category", 8, Enumeration, {
           type: "uint8",
           choices: {
             "0": "All Control Panel Items",
             "1": "Appearance and Personalization",
             "2":  "Hardware and Sound",
             "3": "Network and Internet",
             "4": "Sound, Speech and Audio Devices",
             "5": "System and Security",
             "6": "Clock, Language, and Region",
             "7": "Ease of Access",
             "8": "Programs",
             "9": "User Accounts",
             "10": "Security Center",
             "11": "Mobile PC",
           }
        }],
        ["Description", 0, "Value", {
            "value": 'x=>dict(
                Type="Control Panel",
                LongName="Control Panel\\" + x.Category)',
        }],
      ]],

      ["ShellBag0x71", 0, [
        ["GUID", 14, "GUID"],
        ["Description", 0, "Value", {
            "value": 'x=>dict(
                Type="GUID: Control Panel",
                LongName="Control Panel\\" + GetClassName(GUID=x.GUID.Value))',
        }],
      ]],

      ["ShellBag0x74", 0, [
        ["Size", 4, "uint16"],

        # Variable length search for the extension signature from the
        # start of the struct.
        ["__pre", 0, "String", {
           "term_hex": "0400efbe"
        }],

        # The extension tag should be immediately after the search string.
        ["__ExtensionTag", "x=>len(list=x.__pre)", "uint32"],

        # Extension starts 4 bytes before the tag
        ["Extension", "x=>len(list=x.__pre) - 4", "Union", {
             "selector": "x=>format(format='%#x', args=x.__ExtensionTag)",
             "choices": {
                 "0xbeef0004": "Beef0004",
             }
        }],

        ["Description", 0, "Value", {
            "value": 'x=>dict(
                Type="Users Files Folder",
                LongName=x.Extension.LongName)',
        }],
      ]],

      # TODO
      ["ShellBag0x61", 0, [

      ]],

      ["ShellBag0xc3", 0, [

      ]],

      ["ShellBagZipContents", 0, [
         ["DateString", 0x24, String, {
            encoding: "utf16",
         }],
         ["__FolderNameSize1", 84, uint32],
         ["__FolderNameSize2", 88, uint32],
         ["__FolderNameSize", 0, Value, {
            value: "x=>x.__FolderNameSize1 || x.__FolderNameSize2"
          }],
         ["FolderName", 92, String, {
           encoding: "utf16",
           length: "x=>x.__FolderNameSize * 2",
         }],
         ["Description", 0, "Value", {
             "value": 'x=>dict(
               Type="Zip file contents",
               DateString=x.DateString,
               LongName=x.FolderName
             )'
         }]
      ]],

      ["ShellBagZipContentsWithParent", 0, [
         ["DateString", 0x24, String, {
            encoding: "utf16",
         }],
         ["__FolderNameSize", 84, uint32],
         ["__ParentFolderNameSize", 88, uint32],
         ["FolderName", 92, String, {
           encoding: "utf16",
           length: "x=>x.__FolderNameSize * 2",
         }],
         ["Start", 0, Value, {value: "x=>x.__FolderNameSize *2 + 94"}],
         ["ParentFolderName", "x=>x.__FolderNameSize *2 + 94", String, {
           encoding: "utf16",
           length: "x=>x.__ParentFolderNameSize * 2",
         }],
         ["Description", 0, "Value", {
             "value": 'x=>dict(
               Type="Zip file contents",
               DateString=x.DateString,
               LongName=x.FolderName,
               FullPath=x.ParentFolderName + x.FolderName
             )'
         }]
      ]],


      ["ShellBag0x40", 0, [
         ["Name", 5, "String", {
            encoding: "utf8",
         }],
         ["Description", 0, "Value", {
             "value": 'x=>dict(
               Type="NetworkLocation",
               LongName=x.Name
             )'
         }]
      ]],

      # A LinkInfo stores information about the destination of the link.
      ["LinkInfo", "x=>x.__LinkInfoSize", [
        ["__LinkInfoOffset", 0, "Value", {"value": "x=>x.StartOf"}],
        ["__LinkInfoSize", 0, "uint32"],
        ["__LinkInfoHeaderSize", 4, "uint32"],
        ["LinkInfoFlags", 8, "Flags", {
            "type": "uint32",
            "bitmap": {
                "VolumeIDAndLocalBasePath": 0,
                "CommonNetworkRelativeLinkAndPathSuffix": 1
            }
        }],
        ["__VolumeIDOffset", 0xc, "uint32"],
        ["__LocalBasePathOffset", 16, "uint32"],
        ["__CommonNetworkRelativeLinkOffset", 20, "uint32"],
        ["__CommonPathSuffixOffset", 24, "uint32"],
        ["__LocalBasePath", "x=>x.__LocalBasePathOffset", "String", {}],
        ["__CommonNetworkRelativePath", "x=>x.__CommonNetworkRelativeLinkOffset", "String"],
        ["__CommonPathSuffix", "x=>x.__CommonPathSuffixOffset", "String"],
        ["__VolumeID", "x=>x.__VolumeIDOffset", "VolumeID"],
        ["__CommonNetworkRelativeLink", "x=>x.__CommonNetworkRelativeLinkOffset", "CommonNetworkRelativeLink"],
        ["Target", 0, "Value", { # Depending on the LinkInfoFlags this struct needs to be interpreted differently.
            "value": '
               x=>if(condition=x.LinkInfoFlags =~ "VolumeIDAndLocalBasePath",
                     then=dict(Path=x.__LocalBasePath,
                               VolumeInfo=x.__VolumeID),
                     else=dict(Path=format(format="%v\\%v",
                               args=[x.__CommonNetworkRelativeLink.NetName, x.__CommonPathSuffix]),
                               RelativeLink=x.__CommonNetworkRelativeLink) )'
        }]
      ]],

      ["CommonNetworkRelativeLink", 0, [
        ["__CommonNetworkRelativeLinkSize", 0, "uint32"],
        ["__CommonNetworkRelativeLinkFlags", 4, "Flags", {
            "type": "uint32",
            "bitmap": {
                "ValidDevice": 0,
                "ValidNetType": 1,
            }
        }],
        ["__NetNameOffset", 8, "uint32"],
        ["__DeviceNameOffset", 12, "uint32"],
        ["NetworkProviderType", 16, "Enumeration", {
            "type": "uint32",
            "map": {
                "WNNC_NET_AVID": 0x001A0000,
                "WNNC_NET_DOCUSPACE": 0x001B0000,
                "WNNC_NET_MANGOSOFT": 0x001C0000,
                "WNNC_NET_SERNET": 0x001D0000,
                "WNNC_NET_RIVERFRONT1": 0X001E0000,
                "WNNC_NET_RIVERFRONT2": 0x001F0000,
                "WNNC_NET_DECORB": 0x00200000,
                "WNNC_NET_PROTSTOR": 0x00210000,
                "WNNC_NET_FJ_REDIR": 0x00220000,
                "WNNC_NET_DISTINCT": 0x00230000,
                "WNNC_NET_TWINS": 0x00240000,
                "WNNC_NET_RDR2SAMPLE": 0x00250000,
                "WNNC_NET_CSC": 0x00260000,
                "WNNC_NET_3IN1": 0x00270000,
                "WNNC_NET_EXTENDNET": 0x00290000,
                "WNNC_NET_STAC": 0x002A0000,
                "WNNC_NET_FOXBAT": 0x002B0000,
                "WNNC_NET_YAHOO": 0x002C0000,
                "WNNC_NET_EXIFS": 0x002D0000,
                "WNNC_NET_DAV": 0x002E0000,
                "WNNC_NET_KNOWARE": 0x002F0000,
                "WNNC_NET_OBJECT_DIRE": 0x00300000,
                "WNNC_NET_MASFAX": 0x00310000,
                "WNNC_NET_HOB_NFS": 0x00320000,
                "WNNC_NET_SHIVA": 0x00330000,
                "WNNC_NET_IBMAL": 0x00340000,
                "WNNC_NET_LOCK": 0x00350000,
                "WNNC_NET_TERMSRV": 0x00360000,
                "WNNC_NET_SRT": 0x00370000,
                "WNNC_NET_QUINCY": 0x00380000,
                "WNNC_NET_OPENAFS": 0x00390000,
                "WNNC_NET_AVID1": 0X003A0000,
                "WNNC_NET_DFS": 0x003B0000,
                "WNNC_NET_KWNP": 0x003C0000,
                "WNNC_NET_ZENWORKS": 0x003D0000,
                "WNNC_NET_DRIVEONWEB": 0x003E0000,
                "WNNC_NET_VMWARE": 0x003F0000,
                "WNNC_NET_RSFX": 0x00400000,
                "WNNC_NET_MFILES": 0x00410000,
                "WNNC_NET_MS_NFS": 0x00420000,
                "WNNC_NET_GOOGLE": 0x00430000,
            }
        }],
        ["__NetNameOffsetUnicode", 20, "uint32"],
        ["__DeviceNameOffsetUnicode", 24, "uint32"],
        ["__NetNameAscii", "x=>x.__NetNameOffset", "String"],
        ["__DeviceNameAscii", "x=>x.__DeviceNameOffset", "String"],
        ["__NetNameUnicode", "x=>x.__NetNameOffsetUnicode", "String", {"encoding": "utf16"}],
        ["__DeviceNameUnicode", "x=>x.__DeviceNameOffsetUnicode", "String", {"encoding": "utf16"}],
        ["NetName", 0, "Value", {
            "value": "x=>if(condition=x.__NetNameOffset, then=x.__NetNameAscii, else=x.__NetNameUnicode)"
        }],
        ["DeviceName", 0, "Value", {
            "value": "x=>if(condition=x.__DeviceNameOffset, then=x.__DeviceNameAscii, else=x.__DeviceNameUnicode)"
        }]
      ]],

      # This is a comment
      ["VolumeID", 0, [
        ["__VolumeIDSize", 0, "uint32"],
        ["DriveType", 4, "Enumeration", {
            "type": "uint32",
            "choices": {
                 "0": "DRIVE_UNKNOWN",
                 "1": "DRIVE_NO_ROOT_DIR",
                 "2": "DRIVE_REMOVABLE",
                 "3": "DRIVE_FIXED",
                 "4": "DRIVE_REMOTE",
                 "5": "DRIVE_CDROM",
                 "6": "DRIVE_RAMDISK"
            }
        }],
        ["DriveSerialNumber", 8, "uint32"],
        ["__VolumeLabelOffset", 12, "uint32"],
        ["__VolumeLabelOffsetUnicode", 16, "uint32"],
        ["__VolumeLabelAscii", "x=>x.__VolumeLabelOffset", "String"],
        ["__VolumeLabelUnicode", "x=>x.__VolumeLabelOffsetUnicode", "String", {"encoding": "utf16"}],
        ["VolumeLabel", 0, "Value", {
            "value": 'x=>if(condition=x.__VolumeLabelOffset,
               then=x.__VolumeLabelAscii, else=x.__VolumeLabelUnicode)'
        }]
      ]],

      # Volume name
      ["ShellBag0x20", 0, [
         ["__Name", 3, "String"],
         ["Subtype", 2, "BitField", {
           "type": "uint8",
           "start_bit": 0,
           "end_bit": 1,
         }],
         ["__GUID", 4, "GUID"],
         ["__GUIDFlag", 3, "uint8"],

         # Name is only valid if the first bit is set.
         ["Name", 3, "Value", {
             "value": "x=>(x.__GUIDFlag = 0x80 && GetClassName(GUID=x.__GUID.Value) ) ||
                          (x.Subtype && x.__Name) || ''",
         }],
         ["Description", 0, "Value", {
            "value": 'x=>dict(
                LongName=x.Name,
                ShortName=x.Name,
                GUID=if(condition=x.__GUIDFlag = 0x80, then=x.__GUID.Value),
                Type="Volume"
            )'
        }]
      ]],

      ["ShellBag0x2f", 0, [

      ]],

      ["ShellBag0x2e", 0, [

      ]],

      # Marks the root class My Computer
      ["ShellBag0x1f", 0, [
        ["Type", 0, "uint8"],
        ["UserPropertyType", 4, "uint8"],
        ["UserPropertyName", 13, "String", {length: 3}],
        ["GUID", 4, "GUID"],
        ["Description", 0, "Value", {
            "value": 'x=> ( x.UserPropertyType != 0x2f &&
              dict(
                 LongName=GetClassName(GUID=x.GUID.Value) || "My Computer",
                 GUID=x.GUID.Value,
                 Type="Root"
              )) || dict(
                 Type="UserPropertyType",
                 LongName=x.UserPropertyName
              )'
        }]
      ]],

      # Represent a file or directory
      ["ShellBag0x30", 0, [
        ["Size", 0, "uint16"],
        ["Type", 2, "uint8"],
        ["SubType", 2, "Flags", {
            "type": "uint8",
            "bitmap": {
                "File": 1,
                "Directory": 0,
                "Unicode": 4,
            }
        }],
        ["__LastModificationTime", 8, "uint32"],
        ["LastModificationTime", 8, "FatTimestamp"],
        ["ShortName", 14, "String"],

        # Variable length search for the extension signature from the start of the struct.
        ["__pre", 0, "String", {
            "term_hex": "0400efbe"
        }],

        # The extension tag should be immediately after the search string.
        ["__ExtensionTag", "x=>len(list=x.__pre)", "uint32"],

            # Extension starts 4 bytes before the tag
            ["Extension", "x=>len(list=x.__pre) - 4", "Union", {
                "selector": "x=>format(format='%#x', args=x.__ExtensionTag)",
                "choices": {
                    "0xbeef0004": "Beef0004",
                }
            }],

            # Put all the data together in a convenient location
            ["Description", 0, "Value", {
                "value": 'x=>dict(
                    Type=x.SubType,
                    Modified=if(condition=x.__LastModificationTime, then=x.LastModificationTime),
                    LastAccessed=if(condition=x.Extension.__LastAccessed, then=x.Extension.LastAccessed),
                    CreateDate=if(condition=x.Extension.__CreateDate, then=x.Extension.CreateDate),
                    ShortName=x.ShortName,
                    LongName=x.Extension.LongName,
                    MFTID=x.Extension.MFTReference.MFTID,
                    MFTSeq=x.Extension.MFTReference.SequenceNumber
                )'
            }]
        ]],

        ["ShellBag0x32", 0, [
          ["Size", 0, "uint16"],
          ["ShellBagZipContents", 0, "ShellBagZipContents"],
          ["__ShellBagZipContentsValid", 0, Value, {
            value: "x=>x.Size > 0x28",
           }],

          ["__pre", 0, "String", {
             "term_hex": "0400efbe"
          }],

          # The extension tag should be immediately after the search string.
          ["__ExtensionTag", "x=>len(list=x.__pre)", "uint32"],

          # Extension starts 4 bytes before the tag
          ["Extension", "x=>len(list=x.__pre) - 4", "Union", {
             "selector": "x=>format(format='%#x', args=x.__ExtensionTag)",
             "choices": {
                 "0xbeef0004": "Beef0004",
             }
          }],

          ["Description", 0, "Value", {
            "value": 'x=>if(condition=x.__ShellBagZipContentsValid AND NOT x.Extension.LongName,
                            then=x.ShellBagZipContents.Description,
                            else=dict(Type="File",
                                      LongName=x.Extension.LongName))',
          }],

        ]],

        ["Beef0004", 0, [
            ["Size", 0, "uint16"],
            ["Version", 2, "uint16"],
            ["__Signature", 4, "uint32"],
            ["Signature", 0, "Value", {
                "value": "x=>format(format='%#x', args=x.__Signature)"
            }],
            ["__CreateDate", 8, "uint32"],
            ["__LastAccessed", 12, "uint32"],

            ["CreateDate", 8, "FatTimestamp"],
            ["LastAccessed", 12, "FatTimestamp"],
            ["MFTReference", 20, "MFTReference"],
            ["LongName", "x=>if(condition=x.Version > 8, then=46, else=42)", "String", {
                "encoding": "utf16"
            }]
        ]],
        ["MFTReference", 0, [
            ["MFTID", 0, "BitField", {
                "type": "uint64",
                "start_bit": 0,
                "end_bit": 48,
            }],
            ["SequenceNumber", 0, "BitField", {
                "type": "uint64",
                "start_bit": 48,
                "end_bit": 64,
            }]
        ]],

        ["StringData",0,[
            ["TargetPath",0,"Value",{ "value":"x=> x.ParentOf.LinkInfo.Target.Path"}],
            ["Name",0,"Value",{ "value":"x=> x.ParentOf.__Name.StringData"}],
            ["RelativePath",0,"Value",{ "value":"x=> x.ParentOf.__RelativePath.StringData"}],
            ["WorkingDir",0,"Value",{ "value":"x=> x.ParentOf__WorkingDir.StringData"}],
            ["Arguments",0,"Value",{ "value":"x=> x.ParentOf.__Arguments.StringData"}],
            ["IconLocation",0,"Value",{ "value":"x=> x.ParentOf.__IconLocation.StringData"}],
        ]],

        ## StringDataBlock structs
        ["Name", "x=>x.Size + 2", [
            ["Offset", 0, "Value", {"value": "x=>x.StartOf"}],
            ["Characters", 0, "uint16"],
            ["Size", 0, "Value", {"value": "x=>x.Characters * 2"}],
            ["StringData", 2, "String", {
                "encoding": "utf16",
                "length": "x=>x.Size",
                "max_length": 10000,
                "term": "",
            }],
        ]],
        ["WorkingDir", "x=>x.Size + 2", [
            ["Offset", 0, "Value", {"value": "x=>x.StartOf"}],
            ["Characters", 0, "uint16"],
            ["Size", 0, "Value", {"value": "x=>x.Characters * 2"}],
            ["StringData", 2, "String", {
                "encoding": "utf16",
                "length": "x=>x.Size",
                "max_length": 10000,
                "term": "",
            }],
        ]],
        ["RelativePath", "x=>x.Size + 2", [
            ["Offset", 0, "Value", {"value": "x=>x.StartOf"}],
            ["Characters", 0, "uint16"],
            ["Size", 0, "Value", {"value": "x=>x.Characters * 2"}],
            ["StringData", 2, "String", {
                "encoding": "utf16",
                "length": "x=>x.Size",
                "max_length": 10000,
                "term": "",
            }],
        ]],
        ["Arguments", "x=>x.Size + 2", [
            ["Offset", 0, "Value", {"value": "x=>x.StartOf"}],
            ["Characters", 0, "uint16"],
            ["Size", 0, "Value", {"value": "x=>x.Characters * 2"}],
            ["SizeType", 0, "Value", {"value": "x=>format(format='%T',args=x.Size)"}],
            ["StringData", 2, "String", {
                "encoding": "utf16",
                "length": "x=>x.Size",
                "max_length": 50000,
                "term": "",
            }],
        ]],
        ["IconLocation", "x=>x.Size + 2", [
            ["Offset", 0, "Value", {"value": "x=>x.StartOf"}],
            ["Characters", 0, "uint16"],
            ["Size", 0, "Value", {"value": "x=>x.Characters * 2"}],
            ["StringData", 2, "String", {
                "encoding": "utf16",
                "length": "x=>x.Size",
                "max_length": 10000,
                "term": "",
            }],
        ]],
        ["ExtraData","x=>x.Size",[
            ["Offset",0,"Value",{"value":"x=>x.StartOf"}],
            ["Size",0,"uint32"],
            ["EndOf",0,"Value",{"value":"x=>x.EndOf"}],
            ["__Header",4,"uint32"],
            ["Header",0,"Value",{"value":"x=>'0x' + upcase(string=format(format='%08x',args=x.__Header))"}],
            ["BlockClass", 4, "Enumeration", {
                "type": "uint32",
                "map": {
                    "EnvironmentVariable": 0xA0000001,
                    "Console": 0xA0000002,
                    "TrackerData": 0xA0000003,
                    "CodePage": 0xA0000004,
                    "SpecialFolder": 0xA0000005,
                    "Darwin": 0xA0000006,
                    "IconEnvironment": 0xA0000007,
                    "Shim": 0xA0000008,
                    "PropertyStore": 0xA0000009,
                    "KnownFolder": 0xA000000B,
                    "VistaAndAboveIDList": 0xA000000C,
                }}],
            ["Data", 0, "Union", {
               "selector": "x=>x.Header",
                "choices": {
                    "0xA0000001": "EnvironmentVariableDataBlock",
                    "0xA0000002": "ConsoleDataBlock",
                    "0xA0000003": "TrackerDataBlock",
                    "0xA0000004": "ConsoleFEDataBlock",
                    "0xA0000005": "SpecialFolderDataBlock",
                    "0xA0000006": "DarwinDataBlock",
                    "0xA0000007": "IconEnvironmentDataBlock",
                    "0xA0000008": "ShimDataBlock",
                    "0xA0000009": "PropertyStoreDataBlock",
                    "0xA000000B": "KnownFolderDataBlock",
                    "0xA000000C": "VistaAndAboveIDListDataBlock",
                }
            }],
        ]],
        #0xA0000001
        ["EnvironmentVariableDataBlock", 0x00000314, [
            ["__DataBlockSize",0,"uint32"],
            ["__TargetAnsi", 8, "String", {"max_length": 260 }],
            ["__TargetUnicode", 268, "String", {
                "encoding": "utf16",
                "max_length": 520
            }],
            ["DataValue", 0, "Value",{
                "value": "x=>if(condition= x.__TargetAnsi=x.__TargetUnicode,
                                    then=x.__TargetAnsi,
                                    else=dict(Ascii=x.__TargetAnsi,Unicode=x.__TargetUnicode))" }],
        ]],
        #0xA0000002
        ["ConsoleDataBlock", 0x000000CC, [
            ["__DataBlockSize",0,"uint32"],
            ["FillAttributes",8,"Flags", {
                "type": "uint16",
                "bitmap": {
                    "FOREGROUND_BLUE": 0,
                    "FOREGROUND_GREEN": 1,
                    "FOREGROUND_RED": 2,
                    "FOREGROUND_INTENSITY": 3,
                    "BACKGROUND_BLUE": 4,
                    "BACKGROUND_GREEN": 5,
                    "BACKGROUND_RED": 6,
                    "BACKGROUND_INTENSITY": 7,
                }}],
            ["PopupFillAttributes",10,"Flags", {
                "type": "uint16",
                "bitmap": {
                    "FOREGROUND_BLUE": 0,
                    "FOREGROUND_GREEN": 1,
                    "FOREGROUND_RED": 2,
                    "FOREGROUND_INTENSITY": 3,
                    "BACKGROUND_BLUE": 4,
                    "BACKGROUND_GREEN": 5,
                    "BACKGROUND_RED": 6,
                    "BACKGROUND_INTENSITY": 7,
                }}],
            ["__ScreenBufferSizeX",12,"int16"],
            ["__ScreenBufferSizeY",14,"int16"],
            ["ScreenBufferSize",0,"Value",{
                "value":"x=>format(format='%v x %v',args=[x.__ScreenBufferSizeX,x.__ScreenBufferSizeY])"
            }],
            ["__WindowSizeX",16,"int16"],
            ["__WindowSizeY",18,"int16"],
            ["WindowSize",0,"Value",{
                "value":"x=>format(format='%v x %v',args=[x.__WindowSizeX,x.__WindowSizeY])"
            }],
            ["__WindowOriginX",20,"int16"],
            ["__WindowOriginY",22,"int16"],
            ["WindowOrigin",0,"Value",{
                "value":"x=>format(format='%v / %v',args=[x.__WindowOriginX,x.__WindowOriginY])"
            }],
            ["__FontSizeW",32,"int16"],
            ["__FontSizeH",34,"int16"],
            ["FontSize",0,"Value",{
                "value":"x=>if(condition= x.__FontSizeW=0,
                        then= x.__FontSizeH,
                        else= format(format='%v / %v',args=[x.__FontSizeW,x.__FontSizeH])) "
            }],
            ["__FontFamily", 36, "BitField", {
                type: "uint32",
                start_bit: 4,
                end_bit: 31,
            }],
            ["FontFamily", 0, "Value", {
                "value": "x=>get(item=dict(
                   `0`='DONTCARE',
                   `16`='ROMAN',
                   `32`='SWISS',
                   `48`='MODERN',
                   `64`='SCRIPT',
                   `80`='DECORATIVE',

                   `1`='ROMAN',
                   `2`='SWISS',
                   `3`='MODERN',
                   `4`='SCRIPT',
                   `5`='DECORATIVE'),
                member=x.__FontFamily)"
            }],
            ["__FontPitch", 36, "BitField", {
                type: "uint32",
                start_bit: 0,
                end_bit: 3,
            }],
            # TODO: implement Flag select for FontPitch
            ["FontPitch", 0 ,"Value",{
                "value":"x=>format(format='0x%02x',args=x.__FontPitch)"
            }],
            ["__FontWeight",40,"uint32"],
            ["BoldFont", 0 ,"Value",{
                "value":"x=>if(condition= 700<=x.__FontWeight,
                    then= True,
                    else= False)"
            }],
            ["FaceName", 44, "String", {
                "encoding": "utf16",
                "length": 64,
            }],
            ["__CursorSize",108,"uint32"],
            ["CursorSize", 0 ,"Value",{
                "value":"x=> if(condition= x.__CursorSize <= 25,
                                then= 'Small',
                        else=if(condition= x.__CursorSize >= 26 AND x.__CursorSize <= 50,
                                then= 'Medium',
                        else=if(condition= x.__CursorSize >= 51 AND x.__CursorSize <= 100,
                                else= 'Large',
                                else= x.__CursorSize )))"
            }],
            ["__FullScreen",112,"uint32"],
            ["FullScreen", 0 ,"Value",{
                "value":"x=> if(condition= x.__FullScreen > 0,
                                then= True,
                                else= False )"
            }],
            ["__QuickEdit",116,"uint32"],
            ["QuickEdit", 0 ,"Value",{
                "value":"x=> if(condition= x.__QuickEdit > 0,
                                then= True,
                                else= False )"
            }],
            ["__InsertMode",120,"uint32"],
            ["InsertMode", 0 ,"Value",{
                "value":"x=> if(condition= x.__InsertMode > 0,
                                then= True,
                                else= False )"
            }],
            ["__AutoPosition",124,"uint32"],
            ["AutoPosition", 0 ,"Value",{
                "value":"x=> if(condition= x.__AutoPosition > 0,
                                then= True,
                                else= False )"
            }],
            ["HistoryBufferSize",128,"uint32"],
            ["NumberOfHistoryBuffers",132,"uint32"],
            ["__HistoryNoDup",136,"uint32"],
            ["HistoryDuplicatesAllowed", 0 ,"Value",{
                "value":"x=> if(condition= x.__HistoryNoDup > 0,
                                then= True,
                                else= False )"
            }],
            ["ColorTable", 140, "Array", {
                "type": "uint32",
                "count": 16   # Max count until sentinel
            }],
        ]],
        #0xA0000003
        ["TrackerDataBlock", 0x00000060, [
            ["__DataBlockSize",0,"uint32"],
            ["__MachineID", 16, "String"],
            ["MachineID", 0, "Value",{ "value": "x=>if(condition= x.__MachineID=~'[^ -~]+', then=Null, else=x.__MachineID )" }],
            ["MacAddress", 0, "Value",{ "value": "x=>if(condition=x.MachineID,then=strip(suffix=':',string=regex_replace(source=split(string=x.FileDroid,sep='-')[-1],re='.{2}',replace='$0:')))" }],
            ["__CreationTimeHex", 0, "Value",{ "value": "x=>if(condition=x.MachineID,then='0x' + x.FileDroid[15:18] + x.FileDroid[9:13] + x.FileDroid[0:8] )" }],
            ["CreationTime", 0, "Value",{ "value": "x=>timestamp(epoch=int(int=( int(int=x.__CreationTimeHex) - 0x01B21DD213814000) / 10000))" }],
            ["__Droid0", 32, "GUID"],
            ["__Droid1", 48, "GUID"],
            ["__DroidBirth0", 64, "GUID"],
            ["__DroidBirth1", 80, "GUID"],
            ["VolumeDroid", 0, "Value",{"value": "x=>if(condition=x.MachineID,then=x.__Droid0.Value)" }],
            ["VolumeDroidBirth", 0, "Value",{ "value": "x=>if(condition=x.MachineID,then=x.__DroidBirth0.Value)" }],
            ["FileDroid", 0, "Value",{"value": "x=>if(condition=x.MachineID,then=x.__Droid1.Value)" }],
            ["FileDroidBirth", 0, "Value",{ "value": "x=>if(condition=x.MachineID,then=x.__DroidBirth1.Value)" }],
        ]],
        #0xA0000004
        ["ConsoleFEDataBlock", 0x0000000C, [
            ["__DataBlockSize",0,"uint32"],
            ["CodePage",8,"uint32"],
            ["DataValue",0,"Value",{"value":"x=>x.CodePage"}],
        ]],
        #0xA0000005
        ["SpecialFolderDataBlock", 0x00000010, [
            ["__DataBlockSize",0,"uint32"],
            ["SpecialFolderId",8,"uint32"],
            ["IdOffset",12,"uint32"],
            ["DataValue",0,"Value",{"value":"x=>x.SpecialFolderId"}],
        ]],
        #0xA0000006
        ["DarwinDataBlock", 0x00000314, [
            ["__DataBlockSize",0,"uint32"],
            ["__DarwinDataAnsi", 8, "String", {"max_length": 260 }],
            ["__DarwinDataUnicode", 268, "String", {
                "encoding": "utf16",
                "max_length": 520
            }],
            ["DataValue", 0, "Value",{
                "value": "x=>if(condition= x.__DarwinDataAnsi=x.__DarwinDataUnicode,
                                then=x.__DarwinDataAnsi,
                                else=dict(Ascii=x.__DarwinDataAnsi,
                                          Unicode=x.__DarwinDataUnicode))" }],
        ]],
        #0xA0000007
        ["IconEnvironmentDataBlock", 0x00000314, [
            ["__DataBlockSize",0,"uint32"],
            ["__TargetAnsi", 8, "String", {"max_length": 260 }],
            ["__TargetUnicode", 268, "String", {
                "encoding": "utf16",
                "max_length": 520,
            }],
            ["DataValue", 0, "Value",{
                "value": "x=>if(condition= x.__TargetAnsi=x.__TargetUnicode,
                                then=x.__TargetAnsi,
                                else=dict(Ascii=x.__TargetAnsi,
                                          Unicode=x.__TargetUnicode))" }],
        ]],
        #0xA0000008
        ["ShimDataBlock", "x=>x.__DataBlockSize", [
            ["__DataBlockSize",0,"uint32"],
            ["LayerName", 8, "String", {
                "encoding": "utf16",
                "length": "x=>x.__DataBlockSize - 8",
                "max_length": 10000
                }],
            ["DataValue",0,"Value",{"value":"x=>x.LayerName"}],
        ]],
        #0xA0000009
        ["PropertyStoreDataBlock", "x=>x.__DataBlockSize", [
            ["__DataBlockSize",0,"uint32"],
            ["PropertyStorage", 8, "Array", {
                "count": 1000,
                "type": "PropertyStorage",
                "sentinel": "x=>x.__DataBlockSize = 0"
            }],
            ["DataValue",0,"Value",{"value":"x=>x.PropertyStorage.PropertyValue"}],
        ]],
        #0xA000000B
        ["KnownFolderDataBlock", 0x00000314, [
            ["__DataBlockSize",0,"uint32"],
            ["__KnownFolderId", 8, "GUID"],
            ["GUID",0,"Value",{"value":"x=>x.__KnownFolderId.Value"}],
            ["__Offset", 24,"uint32"],
            ["KnownFolder", 0, "Value", {
                "value": "x=> get(item=KnownGUIDLookup, field=x.GUID)"
            }],
        ]],
        #0xA000000C
        ["VistaAndAboveIDListDataBlock", "x=>x.__BlockSize", [
            ["__DataBlockSize",0,"uint32"],
            ["IDList", 8, "ItemIDList"],
        ]],

        ["DocumentSummaryInformation", 10, [
          ["Offset", 0, "Value", {"value": "x=>x.StartOf"}],
          ["Type", 0, "uint32"],
        ]],

        ["PropertyStorage","x=>x.StorageSize", [
            ["StorageSize",0,"uint32"],
            ["Offset", 0, "Value", {"value": "x=>x.StartOf"}],
            ["Version",4,"String",{ "length":4 }], #Expect 1SPS / 0x53505331
            ["__Format", 8,"GUID"],
            ["Format", 0, "Value",{"value": "x=>x.__Format.Value" }],
            ["PropertyValue", 24, "Array", {
                "type": "PropertyValue",
                "count": 1000,
                "sentinel": "x=>x.__ValueSize = 0"
            }],
        ]],

        ["PropertyValue","x=>x.__ValueSize", [
            ["__ValueSize",0,"uint32"],
            ["ValueSize",0,"uint32"],
            ["Offset", 0, Value, {value: "x=>x.StartOf"}],
            ["__ID",4,"uint32"],
            ["GuidId",0,"Value",{"value": "x=>x.ParentOf.Format + '/' + str(str=x.__ID)"}],
            # These come from https://github.com/EricZimmerman/ExtensionBlocks/blob/master/ExtensionBlocks/Utils.cs
            ["Description", 0, "Value", {
                "value": "x=>PropertyValueDispatcher(x=x)"
            }],
            ["__DocumentSummaryInformation", 4, "DocumentSummaryInformation"],
            ["__NetworkInfo", 4, "Enumeration", {
                "type": "uint32",
                choices: {
                  "5":"WNET Local Name",
                  "6":"WNET Remote Name",
                  "7":"WNET Comment",
                  "8":"WNET Provider",
                  }}],
            ["__STORAGE", 4, "Enumeration", {
                "type": "uint32",
                "choices": {
                  "2":"System.ItemFolderNameDisplay",
                  "3":"Search ClassID",
                  "4":"System.ItemTypeText",
                  "8":"FileIndex",
                  "9":"Search Last Change USN",
                  "10":"System.ItemNameDisplay",
                  "12":"System.Size",
                  "13":"System.FileAttributes",
                  "14":"System.DateModified",
                  "15":"System.DateCreated",
                  "16":"System.DateAccessed",
                  "18":"File Allocation Size",
                  "19":"Search Contents",
                  "20":"Search ShortName",
                  "21":"File FRN",
                  "22":"Search Scope",
                  "23":"Item Name Sort Override",
                  "24":"Item Name Display Without Extension",
                  "25":"Folder Name Display",
                }}],
            ["__SHELL_DETAILS", 4, "Enumeration", {
                "type": "uint32",
                "choices": {
                  "0":"Find Data",
                  "1":"Network Resource",
                  "2":"Description ID",
                  "3":"Which Folder",
                  "4":"Network Location",
                  "5":"Computer Name",
                  "6":"Namespace CLSID",
                  "8":"Item Path Display Narrow",
                  "9":"Perceived Type",
                  "10":"Computer Simple Name",
                  "11":"Item Type",
                  "12":"File Count",
                  "14":"Total File Size",
                  "22":"Max Stack Count",
                  "23":"List Description",
                  "24":"Parsing Name",
                  "25":"SFGAO Flags",
                  "26":"Order",
                  "27":"Computer Description",
                  "29":"Contained Items",
                  "30":"ParsingPath",
                  "31":"Network Provider",
                  "32":"Delegate ID List",
                  "33":"Is SendTo Target",
                  "34":"Hide On Desktop",
                  "35":"Network Places Default Name",
                  "36":"Storage System Type",
                  "37":"Item SubType",
                  }}],
            ["__CACHE", 4, "Enumeration", {
                "type": "uint32",
                "choices": {
                  "100":"Thumbnail Cache Id",
                  "104":"Volume Id",
                  "105":"Tooltip Thumbnail Stream",
                  }}],
            ["__SEARCH", 4, "Enumeration", {
                "type": "uint32",
                "map": {
                    "FolderPath": 0x00000006,
                    "SearchRanking": 0x00000003,
                }}],
            ["__User", 4, "Enumeration", {
                "type": "uint32",
                "map": {
                    "SID": 0x00000004,
                }}],
            ["__Share", 4, "Enumeration", {
                "type": "uint32",
                "map": {
                    "Share Target Description": 0x00000002,
                }}],
            ["__Hash", 4, "Enumeration", {
                "type": "uint32",
                "map": {
                    "WinX Hash": 0x00000002,
                }}],
            ["__FolderDisplay", 4, "Enumeration", {
                "type": "uint32",
                "map": {
                    "Item Folder Path Display Narrow": 100,
                }}],
            ["__AppUserModel", 4, "Enumeration", {
                "type": "uint32",
                "choices": {
                  "2":"App User Model Relaunch Command",
                  "3":"App User Model Relaunch Icon Resource",
                  "4":"App User Model Relaunch Display Name Resource",
                  "5":"App User Model ID",
                  "6":"App User Model Is DestList Separator",
                  "7":"App User Model Is DestList Link",
                  "8":"App User Model Exclude From Show In New Install",
                  "9":"App User Model Prevent Pinning",
                  "10":"App User Model Best Shortcut",
                  "11":"App User Model Is Dual Mode",
                  "12":"App User Model Start Pin Option",
                  "13":"App User Model Relevance",
                  "14":"App User Model Host Environment",
                  "15":"App User Model Package Install Path",
                  "16":"App User Model Record State",
                  "17":"App User Model Package Family Name",
                  "18":"App User Model Installed By",
                  "19":"App User Model Parent ID",
                  "20":"App User Model Activation Context",
                  "21":"App User Model Package Full Name",
                  "22":"App User Model Package Relative Application ID",
                  "23":"App User Model Excluded From Launcher",
                  "24":"App User Model AppCompat ID",
                  "25":"App User Model Run Flags",
                  "26":"App User Model Toast Activator CLSID",
                  "27":"App User Model DestList Provided Title",
                  "28":"App User Model DestList Provided Description",
                  "29":"App User Model DestList Logo Uri",
                  "30":"App User Model DestList Provided Group Name",
                }}],
            ["__Software", 4, "Enumeration", {
                "type": "uint32",
                "choices": {
                  "2":"Publisher Display Name",
                  "3":"Software Registered Owner",
                  "4":"Software Registered Company",
                  "5":"Software AppId",
                  "6":"Software Support Url",
                  "7":"Software Support Telephone",
                  "8":"Software Help Link",
                  "9":"Software Install Location",
                  "10":"Software Install Source",
                  "11":"Software Date Installed",
                  "12":"Software Support Contact Name",
                  "13":"Software ReadMe Url",
                  "14":"Software Update Info Url",
                  "15":"Software Times Used",
                  "16":"Software Date Last Used",
                  "17":"Software Tasks File Url",
                  "18":"Software Parent Name",
                  "19":"Software Product ID",
                  "20":"Software Comments",
                  "997":"Software Null Preview Total Size",
                  "998":"Software Null Preview Subtitle",
                  "999":"Software Null Preview Title",
                  }}],
            ["__Tile", 4, "Enumeration", {
                "type": "uint32",
                "choices": {
                  "2":"Tile Small Image Location",
                  "4":"Tile Background Color",
                  "5":"Tile Foreground Color",
                  "11":"Tile Display Name",
                  "12":"Tile Image Location",
                  "13":"Tile Wide 310x150 Logo Path",
                  "14":"Tile Unknown Flags",
                  "15":"Tile Badge Logo Path",
                  "16":"Tile Suite Display Name",
                  "17":"Tile Suite Sor tName",
                  "18":"Tile Display Name Language",
                  "19":"Tile Square 310x310 Logo Path",
                  "20":"Tile Square 70x70 Logo Path",
                  "21":"Tile Fence Post",
                  "22":"Tile Install Progress",
                  "23":"Tile Encoded Target Path",
                }}],
            ["__Document", 4, "Enumeration", {
                "type": "uint32",
                "choices": {
                  "3":"Subject",
                  "4":"Author",
                  "5":"Keywords",
                  "6":"Comment",
                  "7":"Document Template",
                  "8":"Document Last Author",
                  "9":"Document Revision Number",
                  "10":"Document Total Editing Time",
                  "11":"Document Date Printed",
                  "12":"Document Date Created",
                  "13":"Document Date Saved",
                  "14":"Document Page Count",
                  "15":"Document Word Count",
                  "16":"Document Character Count",
                  "17":"Thumbnail",
                  "18":"Application Name",
                  "19":"Document Security",
                  "24":"High Keywords",
                  "25":"Low Keywords",
                  "26":"Medium Keywords",
                  "27":"Thumbnail Stream",
                }}],
            # https://github.com/EricZimmerman/ExtensionBlocks/blob/58e35b8457bf3006f672c972619bc0fb913fb7e4/ExtensionBlocks/PropertySheet.cs#L104
            ["Type", 9, "uint16"],
            ["__Value", 13, "Union", {
               selector: "x=>format(format='%#02x', args=x.Type)",
               choices: {
                  "0x1f": "LPWSTR",
                  "0x0b": "BOOL",
                  "0x00": "EmptyValue",
                  "0x01": "EmptyValue",
                  "0x02": "UINT16",
                  "0x03": "UINT32",
                  "0x04": "UINT8",
                  "0x08": "LPWSTR",
                  "0x0a": "UINT32",
                  "0x13": "UINT32",
                  "0x40": "FILETIME",
                  "0x14": "UINT64",
                  "0x15": "UINT64",
                  "0x16": "UINT32",
                  "0x17": "UINT32",
                  "0x48": "GUID",
               }
            }],
            ["Value", 0, "Value", { "value": "x=>x.__Value.Value"}],
        ]],
        ["GUID", 16, [
            ["__D1", 0, "uint32"],
            ["__D2", 4, "uint16"],
            ["__D3", 6, "uint16"],
            ["__D4", 8, "String", {"term": "", "length": 2}],
            ["__D5", 10, "String", {"term": "", "length": 6}],
            ["Value", 0, "Value", { "value": "x=>upcase(string=
                    format(format='%08x-%04x-%04x-%02x-%02x',
                        args=[x.__D1, x.__D2, x.__D3, x.__D4, x.__D5]))" }],
        ]],
        ["Overlay", "x=>x.Length", [
            ["Header", 0, "Value", {"value": "x=>format(format='0x%08x',args=read_file(filename=OSPath,offset=x.StartOf + 4,length=4))"}],
            ["Offset", 0, "Value", {"value": "x=>x.StartOf + 4"}],
            ["Length", 0, "Value", {"value": "x=>len(list=read_file(filename=OSPath, offset=x.StartOf + 4))"}],
            ["Entropy", 0, "Value", {"value": "x=>entropy(string=read_file(filename=OSPath,offset=x.StartOf + 4))"}],
            ["Magic", 0, "Value", {"value": "x=>magic(accessor='data',path=read_file(filename=OSPath,offset=x.StartOf + 4))"}],
        ]],

        ["LPWSTR", 0, [
           ["Size", 0, "uint32"],
           ["String", 4, String, {
              "term_hex": "00",
              "length": "x=>x.Size * 2",
              "encoding": "utf16"
           }],
           ["Value", 0, Value, {value: "x=>x.String"}],
        ]],
        ["BOOL", 0, [
           ["_v", 0, "uint8"],
           ["Value", 0, Value, {value: "x=>x._v != 0"}],
        ]],
        ["UINT8", 0, [
           ["Value", 0, "uint8"],
        ]],
        ["FILETIME", 0, [
           ["Value", 0, "WinFileTime"],
        ]],
        ["UINT16", 0, [
           ["Value", 0, "uint16"],
        ]],
        ["UINT32", 0, [
           ["Value", 0, "uint32"],
        ]],
        ["UINT64", 0, [
           ["Value", 0, "uint64"],
        ]],
        ["EmptyValue", 0, [
           ["Value", 0, Value, {value: "x=>0"}],
        ]],
        ["Empty", 0, []],
     ]
     '''

     LET _longestName(ShortName, LongName) = if(
         condition=len(list=LongName) < len(list=ShortName),
         then=ShortName, else=LongName)

     LET _fixfilename(name) = regex_replace(source=name, re="\\\\$", replace="")


     LET _fixpath(data) = SELECT
        _fixfilename(name=_longestName(ShortName=S.ShortName,
            LongName=S.LongName)) || "?" AS Name
      FROM foreach(row=data)
      WHERE NOT Name =~ "^My Computer$"

     LET fixpath(data) = join(array=_fixpath(data=data).Name, sep="\\")

     // Pretty format the PropertyStorage
     LET property_store(Parsed) = SELECT * FROM foreach(
       row=Parsed.ExtraData.Data.PropertyStorage.PropertyValue,
       query={
         SELECT * FROM foreach(row=_value,
           query={
             SELECT GuidId,Description,Type,Value FROM foreach(row=_value)
      })})

      LET ShowHeader(Parsed) = dict(
                Headersize = Parsed.HeaderSize,
                LinkClsID = Parsed.LinkClsID,
                LinkFlags = Parsed.LinkFlags,
                FileAttributes = Parsed.FileAttributes,
                FileSize = Parsed.FileSize,
                CreationTime = Parsed.CreationTime,
                AccessTime = Parsed.AccessTime,
                WriteTime = Parsed.WriteTime,
                IconIndex = Parsed.IconIndex,
                ShowCommand = Parsed.ShowCommand,
                HotKey = Parsed.HotKey
            )

      LET ShowLinkTarget(ShellBag) = dict(
         LinkTarget=fixpath(data=ShellBag.Description),
         LinkTargetIDList=Parsed.LinkTargetIDList
      )

      LET ShowExtraData(Parsed) = to_dict(item={
        SELECT  if(condition= BlockClass=~'^0x',
                  then= 'Overlay',
                  else= BlockClass ) as _key,
            if(condition= Data.DataValue,
                  then= Data.DataValue, else=
                if(condition= NOT BlockClass =~ '^0x',
                  then= Data,
                  else= dict(
                    Header=format(format='0x%x',args=read_file(filename=OSPath, offset=Offset,length=4)),
                    Offset=Offset,
                    Length=len(list=read_file(filename=OSPath, offset=Offset)),
                    Entropy=entropy(string=read_file(filename=OSPath,offset=Offset)),
                    Magic=magic(accessor='data',path=read_file(filename=OSPath,offset=Offset))
                )))  as _value
        FROM foreach(row=Parsed.ExtraData)
      })


sources:
  - query: |
     LET targets = SELECT OSPath, Mtime,Atime,Ctime,Btime,Size,
            read_file(filename=OSPath,offset=0,length=2) as _Header
        FROM glob(globs=TargetGlob)
        WHERE NOT IsDir AND _Header =~ '^L\x00$'

     LET lnk_files = SELECT *,
            parse_binary(filename=OSPath,
                profile=Profile, struct="ShellLinkHeader")  AS Parsed
        FROM targets

      LET parsed = SELECT
        dict(OSPath=OSPath, Size=Size,
            Mtime=Mtime,Btime=Btime) as SourceFile,
        ShowHeader(Parsed=Parsed) as ShellLinkHeader,
        Parsed.LinkInfo as LinkInfo,
        ShowLinkTarget(ShellBag=Parsed.LinkTargetIDList.IDList.ShellBag) as LinkTarget,
        Parsed.StringData as StringData,
        ShowExtraData(Parsed=Parsed) as ExtraData,
        property_store(data=Parsed) as PropertyStore,
        Parsed.Overlay as Overlay,
        Parsed
      FROM lnk_files

     -- Several dynamic functions to check propertystore for anormalities
      LET find_uid(propertystore) = SELECT regex_replace(source=Value,re='''S-1-5-\d{2}-\d+-\d+-\d+-''',replace='') as Value
        FROM propertystore WHERE Description = 'SID'
      LET find_oldpath(propertystore) = SELECT Value FROM propertystore WHERE Description = 'ParsingPath'
      LET find_oldsize(propertystore) = SELECT Value FROM propertystore WHERE Description = 'System.Size'

      LET results = SELECT parsed,
         SourceFile,
         ShellLinkHeader,
         LinkInfo,
         LinkTarget,
         StringData,
         if(condition=PropertyStore,
            then= if(condition= ExtraData.Overlay,
                     then= ExtraData + dict(PropertyStore=PropertyStore),
                     else= if(condition= Overlay.Length > 4,
                              then= ExtraData + dict(
                                  PropertyStore=PropertyStore
                                ) + dict(Overlay=to_dict(item=Overlay)),
                              else= ExtraData + dict(PropertyStore=PropertyStore))),
                              else= if(condition= ExtraData.Overlay,
                              then= ExtraData,
                              else= if(condition= Overlay.Length > 4,
                              then= ExtraData + dict(Overlay=to_dict(item=Overlay)),
                              else= ExtraData
                              )
                              )) as ExtraData,
          find_uid(propertystore=PropertyStore)[0].Value as UID,
          find_oldpath(propertystore=PropertyStore)[0].Value as OldPath,
          find_oldsize(propertystore=PropertyStore)[0].Value as OldSize
      FROM parsed
      WHERE if(condition= IocRegex,
                then= format(format='%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\s%s',
                args=[
                        StringData.TargetPath,
                        StringData.Name,
                        StringData.RelativePath,
                        StringData.WorkingDir,
                        StringData.Arguments,
                        StringData.IconLocation,
                        LinkTarget.LinkTarget,
                        ExtraData.TrackerData.MachineID,
                        ExtraData.TrackerData.MacAddress,
                        join(array=PropertyStore.Value,sep='\n')
                    ]) =~ IocRegex,
                else= True)
        AND NOT if(condition= IgnoreRegex,
                    then= format(format='%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\\s%s',
                    args=[
                        StringData.TargetPath,
                        StringData.Name,
                        StringData.RelativePath,
                        StringData.WorkingDir,
                        StringData.Arguments,
                        StringData.IconLocation,
                        LinkTarget.LinkTarget,
                        ExtraData.TrackerData.MachineID,
                        ExtraData.TrackerData.MacAddress,
                        join(array=PropertyStore.Value,sep='\n')
                    ]) =~ IgnoreRegex,
                    else= False)

      LET sus_cli(data) = dict(
                `Arguments have ticks` = data=~'''\^|\`|[a-z][\'\"]{2}[a-z]''',
                `Arguments have environment variables` = data=~'''\%|\$env:''',
                `Arguments have rare characters` = data=~'''\?\!\~\@''',
                `Arguments have leading space` = data=~ '^ ',
                `Arguments have http strings` = data=~'''(http|ftp)s?://''',
                `Arguments have UNC strings` = data=~'''(\s|^)\\\\[a-z0-9$_.-]+''',
                `Suspicious arguments` = data=~SusArgRegex
            )

      -- find largest base64 blob over 10 characters
      LET find_b64(data) = SELECT *
        FROM if(condition=data,
            then={
                SELECT Base64,  len(list=Base64) as Length
                FROM parse_records_with_regex(accessor='data',file=data, regex='''(?P<Base64>(https?://[^\s]+/)*[A-Za-z0-9+/]{10,}={0,2})''')
                WHERE NOT Base64 =~ '^http' -- Implementing negative regex match: We exclude b64 strings with http prefix.
                ORDER BY Length DESC
                LIMIT 1
            },
            else=null )


      LET add_suspicious = SELECT *, dict(
                `Large Size` = SourceFile.Size > SusSize,
                `Startup Path` = SourceFile.OSPath =~ '''\\Startup\\''',
                `Zeroed Headers` = ( ShellLinkHeader.FileSize=0 AND ShellLinkHeader.CreationTime=~'^1601-01' AND len(list=LinkInfo.LinkInfoFlags)=0 ),
                `Hidden window` = ShellLinkHeader.ShowCommand = 'SHOWMINNOACTIVE',
                `Target Changed path` = lowcase(string=LinkInfo.Target.Path) != lowcase(string=OldPath) AND OldPath,
                `Target Changed size` = ( ShellLinkHeader.FileSize - OldSize != 0 ) AND ShellLinkHeader.FileSize AND OldSize,
                `Risky target` = StringData.TargetPath =~ RiskyExe || LinkInfo.Target.Path =~ RiskyExe || LinkTarget.LinkTarget =~ RiskyExe,
                `WebDAV` = LinkInfo.Target.RelativeLink.NetworkProviderType = 'WNNC_NET_DAV',
                `Line break in StringData.Name` = StringData.Name =~ '''\n''',
                `Suspicious argument size` = len(list=StringData.Arguments) > SusArgSize,
                `Environment variable script` = ExtraData.EnvironmentVariable =~ '''\.(bat|cmd|ps1|js|vbs|vbe|py)$''',
                `No Target with environment variable` = ExtraData.EnvironmentVariable AND StringData.Arguments AND NOT (StringData.TargetPath OR StringData.RelativePath),
                `Suspicious hostname` = ExtraData.TrackerData.MachineID AND SusHostnameRegex AND ExtraData.TrackerData.MachineID=~SusHostnameRegex,
                `Created in VM` = ExtraData.TrackerData.MacAddress =~ VmPrefixMAC,
                `Local Admin` = UID='500',
                `Cyrillic Language` = format(format='%s%s',args=[LinkTarget,ExtraData])=~ '''[\x{0400}-\x{04FF}]''',
                `Chinese Language` = format(format='%s%s',args=[LinkTarget,ExtraData])=~ '''[\x{4E00}-\x{9FCC}]''',
                `Korean Language` = format(format='%s%s',args=[LinkTarget,ExtraData])=~ '''[\x{3131}-\x{314e}|\x{314f}-\x{3163}|\x{ac00}-\x{d7a3}]''',
                `Persian Language` = format(format='%s%s',args=[LinkTarget,ExtraData])=~ '''[\x{0600}-\x{06FF}]''',
                `Vietnamese Language` = format(format='%s%s',args=[LinkTarget,ExtraData])=~ '''[\x{0102}\x{0103}\x{0110}\x{0111}\x{01A0}\x{01A1}\x{01AF}\x{01B0}\x{1EA0}-\x{1EF9}]''',
                `CodePage` = ExtraData.CodePage,
                `Has Overlay` = if(condition=ExtraData.Overlay, then=True)
            ) as Suspicious,
            regex_replace(source=base64decode(string=find_b64(data=StringData.Arguments)[0].Base64),re='''[^ -~\s]''',replace='')  as ArgumentsDecoded,
            sus_cli(data=StringData.Arguments) as SuspiciousCli
        FROM results
        WHERE if(condition=SuspiciousOnly,
            then= join(array=Suspicious) =~ ''':(true|0x|\d)''' OR join(array=SuspiciousCli) =~ ''':(true|0x|\d)''' OR len(list=ArgumentsDecoded) > 20,
            else= True )

      LET add_suspiciousb64 = SELECT *
            if(condition= len(list=ArgumentsDecoded) > 20, then = dict(`Long Base64`=True) + sus_cli(data=ArgumentsDecoded)) as SuspiciousCliB64
        FROM add_suspicious

      LET upload_results = SELECT *,
            upload(file=SourceFile.OSPath) as UploadedLnk
        FROM add_suspiciousb64

      -- finally return rows and remove suspicious attributes that are not true
      SELECT
            SourceFile,
            ShellLinkHeader,
            LinkInfo,
            LinkTarget,
            if(condition= SuspiciousCliB64,
                then= to_dict(item=StringData) + dict(`DecodedBase64`=ArgumentsDecoded),
                else= StringData) as StringData,
            ExtraData,
            to_dict(item={SELECT * FROM items(item=Suspicious) WHERE _value }) +
                to_dict(item={SELECT * FROM items(item=SuspiciousCli) WHERE _value }) +
                to_dict(item={SELECT * FROM items(item=SuspiciousCliB64) WHERE _value })
                    as Suspicious
        FROM if(condition=UploadLnk,
            then= upload_results,
            else= add_suspiciousb64 )

column_types:
  - name: SourceFile.Mtime
    type: timestamp
  - name: SourceFile.Btime
    type: timestamp
  - name: ShellLinkHeader.CreationTime
    type: timestamp
  - name: ShellLinkHeader.AccessTime
    type: timestamp
  - name: ShellLinkHeader.WriteTime
    type: timestamp