Skip to content

Instantly share code, notes, and snippets.

@jaredcatkinson
Last active February 24, 2024 15:21
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save jaredcatkinson/f1cd44a8605e05c2661bdeca558c03e1 to your computer and use it in GitHub Desktop.
Save jaredcatkinson/f1cd44a8605e05c2661bdeca558c03e1 to your computer and use it in GitHub Desktop.
Get-ExtendedAttribute is a function to iterate through the C:\ volume looking for files with Extended Attributes. This code is beta and meant only for the purpose of a blog post on detection methodology.
# This is really beta code used in my Detection Methodology post. I plan to write more efficient code when I get some more time.
function Get-ExtendedAttribute
{
foreach($file in (Get-ChildItem -Path C:\ -Recurse))
{
$obj = Get-ExtendedAttribute -FilePath $file.FullName | Where-Object {$_ -ne $null}
$obj | Add-Member -MemberType NoteProperty -Name FileName -Value $file.FullName
Write-Output $obj
}
}
function GetExtendedAttribute
{
param
(
[Parameter()]
[string]
$FilePath
)
if(Test-Path -Path $FilePath -PathType Container)
{
# FILE_DIRECTORY_FILE
$FileMode = 0x00000002
}
else
{
# FILE_NON_DIRECTORY_FILE
$FileMode = 0x00000040
}
try
{
$FILE_READ_EA = 0x00000008
$FILE_RANDOM_ACCESS = 0x00000800
$READ_CONTROL = 0x00020000
$FILE_OPEN_FOR_BACKUP_INTENT = 0x00004000
$FileHandle = NtOpenFile -FilePath $FilePath -AccessMask ($READ_CONTROL -bor $FILE_READ_EA) -ShareAccess ([System.IO.FileShare]::Delete -bor [System.IO.FileShare]::ReadWrite) -OpenOptions ($FILE_OPEN_FOR_BACKUP_INTENT -bor $FILE_RANDOM_ACCESS -bor $FileMode)
$EA = ZwQueryEaFile -FileHandle $FileHandle
if($EA -ne $null)
{
Write-Output $EA
}
}
catch
{
}
}
$Mod = New-InMemoryModule -ModuleName GetExtendedAttribute
$OBJECT_ATTRIBUTES = struct $Mod OBJECT_ATTRIBUTES @{
Length = field 0 Int32
RootDirectory = field 1 IntPtr
ObjectName = field 2 IntPtr
Attributes = field 3 UInt32
SecurityDescriptor = field 4 IntPtr
SecurityQualityOfService = field 5 IntPtr
}
$IO_STATUS_BLOCK = struct $Mod IO_STATUS_BLOCK @{
Status = field 0 IntPtr
Information = field 1 IntPtr
}
$UNICODE_STRING = struct $Mod UNICODE_STRING @{
Length = field 0 UInt16
MaximumLength = field 1 UInt16
Buffer = field 2 IntPtr
}
$FILE_FULL_EA_INFORMATION = struct $Mod FILE_FULL_EA_INFORMATION @{
NextEntryOffset = field 0 UInt32
Flags = field 1 byte
EaNameLength = field 2 byte
EaValueLength = field 3 UInt16
EaName = field 4 char[] -MarshalAs @('ByValArray', 1)
}
$FunctionDefinitions = @(
(func ntdll NtOpenFile ([UInt32]) @(
[IntPtr].MakeByRefType(), #_Out_ PHANDLE FileHandle
[UInt32], #_In_ ACCESS_MASK DesiredAccess
$OBJECT_ATTRIBUTES.MakeByRefType(), #_In_ POBJECT_ATTRIBUTES ObjectAttributes
$IO_STATUS_BLOCK.MakeByRefType(), #_Out_ PIO_STATUS_BLOCK IoStatusBlock
[System.IO.FileShare], #_In_ ULONG ShareAccess
[UInt32] #_In_ ULONG OpenOptions
) -EntryPoint NtOpenFile),
(func ntdll RtlInitUnicodeString ([void]) @(
$UNICODE_STRING.MakeByRefType(), #_Inout_ PUNICODE_STRING DestinationString
[string] #_In_opt_ PCWSTR SourceString
) -EntryPoint RtlInitUnicodeString),
(func ntdll ZwQueryEaFile ([UInt32]) @(
[IntPtr], #_In_ HANDLE FileHandle
$IO_STATUS_BLOCK.MakeByRefType(), #_Out_ PIO_STATUS_BLOCK IoStatusBlock
[IntPtr], #_Out_ PVOID Buffer
[UInt32], #_In_ ULONG Length
[bool], #_In_ BOOLEAN ReturnSingleEntry
[IntPtr], #_In_opt_ PVOID EaList
[UInt32], #_In_ ULONG EaListLength
[IntPtr], #_In_opt_ PULONG EaIndex
[bool] #_In_ BOOLEAN RestartScan
) -EntryPoint ZwQueryEaFile)
)
$Types = $FunctionDefinitions | Add-Win32Type -Module $mod -Namespace ArpCache
$Ntdll = $Types['ntdll']
function NtOpenFile
{
param
(
[Parameter(Mandatory = $true)]
[string]
$FilePath,
[Parameter(Mandatory = $true)]
[UInt32]
$AccessMask,
[Parameter(Mandatory = $true)]
[System.IO.FileShare]
$ShareAccess,
[Parameter(Mandatory = $true)]
[UInt32]
$OpenOptions
)
$FileHandle = [IntPtr]::Zero
$UnicodeString = RtlInitUnicodeString -SourceString "\??\$($FilePath)"
$unicodeIntPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($UNICODE_STRING::GetSize())
[System.Runtime.InteropServices.Marshal]::StructureToPtr($UnicodeString, $unicodeIntPtr, $true)
$ObjectAttributes = [Activator]::CreateInstance($OBJECT_ATTRIBUTES)
$ObjectAttributes.Length = $OBJECT_ATTRIBUTES::GetSize()
$ObjectAttributes.ObjectName = $unicodeIntPtr
$ObjectAttributes.RootDirectory = [IntPtr]::Zero
$ObjectAttributes.Attributes = 0x40 #OBJ_CASE_INSENSITIVE
$ObjectAttributes.SecurityDescriptor = [IntPtr]::Zero
$ObjectAttributes.SecurityQualityOfService = [IntPtr]::Zero
$IoStatusBlock = [Activator]::CreateInstance($IO_STATUS_BLOCK)
$SUCCESS = $Ntdll::NtOpenFile([ref]$FileHandle, $AccessMask, [ref]$ObjectAttributes, [ref]$IoStatusBlock, $ShareAccess, $OpenOptions)
if($SUCCESS -ne 0)
{
throw "Unable to open file handle"
}
Write-Output $FileHandle
[System.Runtime.InteropServices.Marshal]::FreeHGlobal($unicodeIntPtr)
}
function RtlInitUnicodeString
{
param
(
[Parameter(Mandatory = $true)]
[string]
$SourceString
)
$DestinationString = [Activator]::CreateInstance($UNICODE_STRING)
$Ntdll::RtlInitUnicodeString([ref]$DestinationString, $SourceString)
Write-Output $DestinationString
}
function ZwQueryEaFile
{
param
(
[Parameter(Mandatory = $true)]
[IntPtr]
$FileHandle
)
$IoStatusBlock = [Activator]::CreateInstance($IO_STATUS_BLOCK)
$buffer = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(0xFFFF)
$SUCCESS = $Ntdll::ZwQueryEaFile($FileHandle, [ref]$IoStatusBlock, $Buffer, 0xFFFF, $true, [IntPtr]::Zero, 0, [IntPtr]::Zero, $false)
if($SUCCESS -eq 3221225554) # STATUS_NO_EAS_ON_FILE
{
}
elseif($SUCCESS -eq 0) # NT_STATUS
{
$FileEaInformation = $buffer -as $FILE_FULL_EA_INFORMATION
$NameOffset = [IntPtr]::Add($buffer, 8)
$Name = [System.Runtime.InteropServices.Marshal]::PtrToStringAnsi($NameOffset, $FileEaInformation.EaNameLength)
$ValueOffset = [IntPtr]::Add($NameOffset, $FileEaInformation.EaNameLength + 1)
$Value = New-Object -TypeName byte[]($FileEaInformation.EaValueLength)
[System.Runtime.InteropServices.Marshal]::Copy($ValueOffset, $Value, 0, $Value.Length)
$obj = New-Object -TypeName psobject
$obj | Add-Member -MemberType NoteProperty -Name Name -Value $Name
$obj | Add-Member -MemberType NoteProperty -Name Value -Value ([System.Text.Encoding]::ASCII.GetString($Value))
$obj | Add-Member -MemberType NoteProperty -Name ValueData -Value $Value
$obj | Add-Member -MemberType NoteProperty -Name NextEntryOffset -Value $FileEaInformation.NextEntryOffset
$obj | Add-Member -MemberType NoteProperty -Name Flags -Value $FileEaInformation.Flags
Write-Output $obj
}
else
{
throw "ZwQueryEaFile Error: $($SUCCESS)"
}
[System.Runtime.InteropServices.Marshal]::FreeHGlobal($Buffer)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment