Files
2025-05-03 21:42:00 +02:00

311 lines
7.3 KiB
C++

#include "Misc.hpp"
#include "Debug.hpp"
#include "Globals.hpp"
/*
* @brief Checks whether a wide string is null or contains only null characters.
*
* @param[in] PWchar Pointer to a wide string.
*
* @return BOOLEAN True if null or only null characters, otherwise false.
*/
BOOLEAN
BeIsStringNull(
_In_ PWCHAR pWchar
)
{
return (pWchar == NULL || *pWchar == '\0');
}
/*
* @brief Checks whether a wide string is null-terminated.
*
* @param[in] Array Pointer to a wide string.
* @param[in] ArrayLength Length of the string.
*
* @return BOOLEAN True if null-terminated, otherwise false.
*/
BOOLEAN
BeIsStringTerminated(
_In_ PWCHAR array,
_In_ ULONG arrayLength
)
{
BOOLEAN bStringIsTerminated = FALSE;
USHORT index = 0;
while (index < arrayLength && bStringIsTerminated == FALSE)
{
if (array[index] == L'\0')
{
bStringIsTerminated = TRUE;
}
else
{
index++;
}
}
return bStringIsTerminated;
}
/*
* @brief Checks whether a wide string is null-terminated, not empty, and properly aligned.
*
* @param[in] TargetString The string to check.
* @param[in] Size The size of the string buffer.
*
* @return NTSTATUS STATUS_SUCCESS if valid, otherwise an error code.
*/
NTSTATUS
BeCheckStringIsAlignedNotEmptyAndTerminated(
_In_ PWCHAR targetString,
_In_ ULONG size
)
{
//
// Check alignment
//
if (size % sizeof(WCHAR) != 0)
{
LOG_MSG("Invalid alignment \r\n");
return STATUS_INVALID_BUFFER_SIZE;
}
if (!targetString)
{
LOG_MSG("Empty buffer \r\n");
return STATUS_INVALID_PARAMETER;
}
LOG_MSG("String received: %ws \r\n", targetString);
if (BeIsStringTerminated(targetString, size) == FALSE)
{
LOG_MSG("Not null terminated! \r\n");
return STATUS_UNSUCCESSFUL;
}
return STATUS_SUCCESS;
}
/*
* @brief Performs a case-insensitive substring search in a wide string.
*
* @param[in] String The string to search in.
* @param[in] Pattern The pattern to search for.
*
* @return PWCHAR Pointer to the match if found, otherwise NULL.
*/
PWCHAR
StrStrIW(
_In_ CONST PWCHAR string,
_In_ CONST PWCHAR pattern
) {
PWCHAR pptr, sptr, start;
for (start = (PWCHAR)string; *start != NULL; ++start)
{
while (((*start != NULL) && (RtlUpcaseUnicodeChar(*start) != RtlUpcaseUnicodeChar(*pattern))))
{
++start;
}
if (NULL == *start)
return NULL;
pptr = (PWCHAR)pattern;
sptr = (PWCHAR)start;
while (RtlUpcaseUnicodeChar(*sptr) == RtlUpcaseUnicodeChar(*sptr))
{
sptr++;
pptr++;
if (NULL == *pptr)
return (start);
}
}
return NULL;
}
/*
* @brief Extracts the base name from a full file path.
* Taken from: https://github.com/GetRektBoy724/DCMB/blob/main/DCMB/dcmb.c#L3
*
* @param[in] FullName Full file path.
*
* @return PCHAR Pointer to the base name within the string.
*/
PCHAR
GetBaseNameFromFullPath(
_In_ PCHAR fullName
)
{
SIZE_T fullNameLength = strlen(fullName);
for (SIZE_T I = fullNameLength; I > 0; I--)
{
if (*(fullName + I) == '\\')
{
return fullName + I + 1;
}
}
return NULL;
}
/*
* @brief Creates a security descriptor with full access to all users.
*
* @param[out] Sd Pointer to the created security descriptor.
*
* @return NTSTATUS STATUS_SUCCESS if successful, otherwise an error code.
*/
NTSTATUS
BeCreateSecurityDescriptor(
_Out_ PSECURITY_DESCRIPTOR* sd
)
{
NTSTATUS status = STATUS_SUCCESS;
// Create the DACL
/*
* Figured out that since we want full access to anyone, we can also just add a 0 ACL ... :)
*/
/*
ULONG daclSize = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG) + RtlLengthSid(SeExports->SeAuthenticatedUsersSid);
PACL Dacl = (PACL)ExAllocatePoolWithTag(NonPagedPool, daclSize, DRIVER_TAG);
if (!Dacl)
{
return STATUS_UNSUCCESSFUL;
}
NtStatus = RtlCreateAcl(Dacl, daclSize, ACL_REVISION);
if (!NT_SUCCESS(NtStatus))
{
ExFreePool(Dacl);
return NtStatus;
}
NtStatus = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, SECTION_ALL_ACCESS, SeExports->SeAuthenticatedUsersSid);
if (!NT_SUCCESS(NtStatus))
{
ExFreePool(Dacl);
return NtStatus;
}
*/
// Create the security descriptor
*sd = (PSECURITY_DESCRIPTOR)ExAllocatePoolWithTag(NonPagedPool, SECURITY_DESCRIPTOR_MIN_LENGTH, DRIVER_TAG); // TODO: FREE
if (!*sd)
{
ExFreePool(*sd);
// ExFreePool(Dacl);
return STATUS_UNSUCCESSFUL;
}
status = RtlCreateSecurityDescriptor(*sd, SECURITY_DESCRIPTOR_REVISION);
if (!NT_SUCCESS(status))
{
ExFreePool(sd);
// ExFreePool(Dacl);
return status;
}
status = RtlSetDaclSecurityDescriptor(*sd, TRUE, 0, FALSE); // 0 = Dacl
if (!NT_SUCCESS(status))
{
LOG_MSG("Failed to set DACL in security descriptor\n");
ExFreePool(*sd);
// ExFreePool(Dacl);
return status;
}
return status;
}
/*
* @brief Sets a named event to a specified state.
*
* @param[in] hEvent Handle to the event.
* @param[in] Set TRUE to signal the event, FALSE to reset it.
*
* @return NTSTATUS STATUS_SUCCESS if successful, otherwise an error code.
*/
NTSTATUS
BeSetNamedEvent(
_In_ HANDLE hEvent,
_In_ BOOLEAN set
) {
NTSTATUS status = STATUS_SUCCESS;
if (set)
{
status = BeGlobals::pZwSetEvent(hEvent, NULL);
if (!NT_SUCCESS(status))
{
LOG_MSG("Failed to set named event: 0x%X\n", status);
}
}
else
{
BeGlobals::pZwResetEvent(hEvent, NULL);
if (!NT_SUCCESS(status))
{
LOG_MSG("Failed to reset named event: 0x%X\n", status);
}
}
return status;
}
/*
* @brief Waits for an event to be signaled.
*
* @param[in] hEvent Handle to the event.
*
* @return NTSTATUS STATUS_SUCCESS if successful, otherwise an error code.
*/
NTSTATUS
BeWaitForEvent(
_In_ HANDLE hEvent
)
{
NTSTATUS Status = STATUS_SUCCESS;
Status = ZwWaitForSingleObject(hEvent, FALSE, NULL);
return Status;
}
/*
* @brief Creates a named event with a specified initial state.
*
* @param[out] PhEvent Pointer to a handle for the created event.
* @param[in] EventName Name of the event.
* @param[in] InitialSignaledState Initial state of the event (signaled or non-signaled).
*
* @return NTSTATUS STATUS_SUCCESS if successful, otherwise an error code.
*/
NTSTATUS
BeCreateNamedEvent(
_Out_ PHANDLE phEvent,
_In_ PUNICODE_STRING eventName,
_In_ BOOLEAN initialSignaledState
) {
//
// Add permissions to all users to our event, so that a lowpriv agent can still access the rootkit
//
PSECURITY_DESCRIPTOR sd = { 0 };
OBJECT_ATTRIBUTES oa = { 0 };
BeCreateSecurityDescriptor(&sd);
InitializeObjectAttributes(&oa, eventName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT | OBJ_KERNEL_HANDLE | OBJ_OPENIF, NULL, sd);
NTSTATUS Status = BeGlobals::pZwCreateEvent(phEvent, EVENT_ALL_ACCESS, &oa, NotificationEvent, initialSignaledState);
if (!NT_SUCCESS(Status))
DbgPrint("Failed to create named event: 0x%X\n", Status);
ExFreePool(sd);
return Status;
}