hidden/Hidden/Helper.c

271 lines
6.5 KiB
C

#include "Helper.h"
#define HELPER_ALLOC_TAG 'rplH'
NTSTATUS QuerySystemInformation(SYSTEM_INFORMATION_CLASS Class, PVOID* InfoBuffer, PSIZE_T InfoSize)
{
PVOID info = NULL;
NTSTATUS status;
ULONG size = 0, written = 0;
// Query required size
status = ZwQuerySystemInformation(Class, 0, 0, &size);
if (status != STATUS_INFO_LENGTH_MISMATCH)
return status;
while (status == STATUS_INFO_LENGTH_MISMATCH)
{
size += written; // We should allocate little bit more space
if (info)
ExFreePoolWithTag(info, HELPER_ALLOC_TAG);
info = ExAllocatePoolWithTag(NonPagedPool, size, HELPER_ALLOC_TAG);
if (!info)
break;
status = ZwQuerySystemInformation(Class, info, size, &written);
}
if (!info)
return STATUS_ACCESS_DENIED;
if (!NT_SUCCESS(status))
{
ExFreePoolWithTag(info, HELPER_ALLOC_TAG);
return status;
}
*InfoBuffer = info;
*InfoSize = size;
return status;
}
NTSTATUS QueryProcessInformation(PROCESSINFOCLASS Class, HANDLE Process, PVOID* InfoBuffer, PSIZE_T InfoSize)
{
PVOID info = NULL;
NTSTATUS status;
ULONG size = 0, written = 0;
// Query required size
status = ZwQueryInformationProcess(Process, Class, 0, 0, &size);
if (status != STATUS_INFO_LENGTH_MISMATCH)
return status;
while (status == STATUS_INFO_LENGTH_MISMATCH)
{
size += written; // We should allocate little bit more space
if (info)
ExFreePoolWithTag(info, HELPER_ALLOC_TAG);
info = ExAllocatePoolWithTag(NonPagedPool, size, HELPER_ALLOC_TAG);
if (!info)
break;
status = ZwQueryInformationProcess(Process, Class, info, size, &written);
}
if (!info)
return STATUS_ACCESS_DENIED;
if (!NT_SUCCESS(status))
{
ExFreePoolWithTag(info, HELPER_ALLOC_TAG);
return status;
}
*InfoBuffer = info;
*InfoSize = size;
return status;
}
VOID FreeInformation(PVOID Buffer)
{
ExFreePoolWithTag(Buffer, HELPER_ALLOC_TAG);
}
NTSTATUS ResolveSymbolicLink(PUNICODE_STRING Link, PUNICODE_STRING Resolved)
{
OBJECT_ATTRIBUTES attribs;
HANDLE hsymLink;
ULONG written;
NTSTATUS status = STATUS_SUCCESS;
// Open symlink
InitializeObjectAttributes(&attribs, Link, OBJ_KERNEL_HANDLE, NULL, NULL);
status = ZwOpenSymbolicLinkObject(&hsymLink, GENERIC_READ, &attribs);
if (!NT_SUCCESS(status))
return status;
// Query original name
status = ZwQuerySymbolicLinkObject(hsymLink, Resolved, &written);
ZwClose(hsymLink);
if (!NT_SUCCESS(status))
return status;
return status;
}
//
// Convertion template:
// \\??\\C:\\Windows -> \\Device\\HarddiskVolume1\\Windows
//
NTSTATUS NormalizeDevicePath(PCUNICODE_STRING Path, PUNICODE_STRING Normalized)
{
UNICODE_STRING globalPrefix, dvcPrefix, sysrootPrefix;
NTSTATUS status;
RtlInitUnicodeString(&globalPrefix, L"\\??\\");
RtlInitUnicodeString(&dvcPrefix, L"\\Device\\");
RtlInitUnicodeString(&sysrootPrefix, L"\\SystemRoot\\");
if (RtlPrefixUnicodeString(&globalPrefix, Path, TRUE))
{
OBJECT_ATTRIBUTES attribs;
UNICODE_STRING subPath;
HANDLE hsymLink;
ULONG i, written, size;
subPath.Buffer = (PWCH)((PUCHAR)Path->Buffer + globalPrefix.Length);
subPath.Length = Path->Length - globalPrefix.Length;
for (i = 0; i < subPath.Length; i++)
{
if (subPath.Buffer[i] == L'\\')
{
subPath.Length = (USHORT)(i * sizeof(WCHAR));
break;
}
}
if (subPath.Length == 0)
return STATUS_INVALID_PARAMETER_1;
subPath.Buffer = Path->Buffer;
subPath.Length += globalPrefix.Length;
subPath.MaximumLength = subPath.Length;
// Open symlink
InitializeObjectAttributes(&attribs, &subPath, OBJ_KERNEL_HANDLE, NULL, NULL);
status = ZwOpenSymbolicLinkObject(&hsymLink, GENERIC_READ, &attribs);
if (!NT_SUCCESS(status))
return status;
// Query original name
status = ZwQuerySymbolicLinkObject(hsymLink, Normalized, &written);
ZwClose(hsymLink);
if (!NT_SUCCESS(status))
return status;
// Construct new variable
size = Path->Length - subPath.Length + Normalized->Length;
if (size > Normalized->MaximumLength)
return STATUS_BUFFER_OVERFLOW;
subPath.Buffer = (PWCH)((PUCHAR)Path->Buffer + subPath.Length);
subPath.Length = Path->Length - subPath.Length;
subPath.MaximumLength = subPath.Length;
status = RtlAppendUnicodeStringToString(Normalized, &subPath);
if (!NT_SUCCESS(status))
return status;
}
else if (RtlPrefixUnicodeString(&dvcPrefix, Path, TRUE))
{
Normalized->Length = 0;
status = RtlAppendUnicodeStringToString(Normalized, Path);
if (!NT_SUCCESS(status))
return status;
}
else if (RtlPrefixUnicodeString(&sysrootPrefix, Path, TRUE))
{
UNICODE_STRING subPath, resolvedLink, winDir;
WCHAR buffer[64];
SHORT i;
// Open symlink
subPath.Buffer = sysrootPrefix.Buffer;
subPath.MaximumLength = subPath.Length = sysrootPrefix.Length - sizeof(WCHAR);
resolvedLink.Buffer = buffer;
resolvedLink.Length = 0;
resolvedLink.MaximumLength = sizeof(buffer);
status = ResolveSymbolicLink(&subPath, &resolvedLink);
if (!NT_SUCCESS(status))
return status;
// \Device\Harddisk0\Partition0\Windows -> \Device\Harddisk0\Partition0
// Win10: \Device\BootDevice\Windows -> \Device\BootDevice
winDir.Length = 0;
for (i = (resolvedLink.Length - sizeof(WCHAR)) / sizeof(WCHAR); i >= 0; i--)
{
if (resolvedLink.Buffer[i] == L'\\')
{
winDir.Buffer = resolvedLink.Buffer + i;
winDir.Length = resolvedLink.Length - (i * sizeof(WCHAR));
winDir.MaximumLength = winDir.Length;
resolvedLink.Length = (i * sizeof(WCHAR));
break;
}
}
// \Device\Harddisk0\Partition0 -> \Device\HarddiskVolume1
// Win10: \Device\BootDevice -> \Device\HarddiskVolume2
status = ResolveSymbolicLink(&resolvedLink, Normalized);
if (!NT_SUCCESS(status))
return status;
// Construct new variable
subPath.Buffer = (PWCHAR)((PCHAR)Path->Buffer + sysrootPrefix.Length - sizeof(WCHAR));
subPath.MaximumLength = subPath.Length = Path->Length - sysrootPrefix.Length + sizeof(WCHAR);
status = RtlAppendUnicodeStringToString(Normalized, &winDir);
if (!NT_SUCCESS(status))
return status;
status = RtlAppendUnicodeStringToString(Normalized, &subPath);
if (!NT_SUCCESS(status))
return status;
}
else
{
return STATUS_INVALID_PARAMETER;
}
return STATUS_SUCCESS;
}
BOOLEAN IsWin8OrAbove()
{//TODO: cache it
RTL_OSVERSIONINFOW version;
NTSTATUS status;
RtlZeroMemory(&version, sizeof(version));
status = RtlGetVersion(&version);
if (!NT_SUCCESS(status))
LogWarning("Can't get an OS version, status:%x", status);
if (version.dwMajorVersion < 6)
return FALSE;
if (version.dwMajorVersion == 6 && version.dwMinorVersion < 2) // NT 6.2 == Win8
return FALSE;
return TRUE;
}