/** * @file hprdbgctrl.cpp * @author Sina Karvandi (sina@rayanfam.com) * @brief Main interface to connect applications to driver * @details * @version 0.1 * @date 2020-04-11 * * @copyright This project is released under the GNU Public License v3. * */ #include "pch.h" // // Global Variables // using namespace std; HANDLE Handle; BOOLEAN IsVmxOffProcessStart; // Show whether the vmxoff process start or not Callback Handler = 0; TCHAR driverLocation[MAX_PATH] = { 0 }; /** * @brief Set the function callback that will be called if anything received from the kernel * * @param handler Function that handles the messages */ void __stdcall HyperdbgSetTextMessageCallback(Callback handler) { Handler = handler; } /** * @brief Show messages received from kernel driver * * @param Fmt */ void ShowMessages(const char* Fmt, ...) { va_list ArgList; char TempMessage[PacketChunkSize]; va_start(ArgList, Fmt); int sprintfresult = vsprintf_s(TempMessage, PacketChunkSize - 1, Fmt, ArgList); va_end(ArgList); if (sprintfresult != -1) { if (Handler != NULL) { Handler(TempMessage); } else { printf(TempMessage); } } else { MessageBoxA(0, "Error occured in send date to managed code !", "error", 0); } } /** * @brief Detect VMX support * * @return true if vmx is supported * @return false if vmx is not supported */ bool VmxSupportDetection() { return AsmVmxSupportDetection(); } /** * @brief SetPrivilege enables/disables process token privilege * * @param hToken * @param lpszPrivilege * @param bEnablePrivilege * @return BOOL */ BOOL SetPrivilege(HANDLE hToken, LPCTSTR lpszPrivilege, BOOL bEnablePrivilege) { LUID luid; BOOL bRet = FALSE; if (LookupPrivilegeValue(NULL, lpszPrivilege, &luid)) { TOKEN_PRIVILEGES tp; tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = (bEnablePrivilege) ? SE_PRIVILEGE_ENABLED : 0; // // Enable the privilege or disable all privileges. // if (AdjustTokenPrivileges(hToken, FALSE, &tp, NULL, (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL)) { // // Check to see if you have proper access. // You may get "ERROR_NOT_ALL_ASSIGNED". // bRet = (GetLastError() == ERROR_SUCCESS); } } return bRet; } #if !UseDbgPrintInsteadOfUsermodeMessageTracking /** * @brief Read kernel buffers using IRP Pending * * @param Device Driver handle */ void ReadIrpBasedBuffer(HANDLE Device) { BOOL Status; ULONG ReturnedLength; REGISTER_NOTIFY_BUFFER RegisterEvent; UINT32 OperationCode; ShowMessages(" =============================== Kernel-Mode Logs (Driver) ===============================\n"); RegisterEvent.hEvent = NULL; RegisterEvent.Type = IRP_BASED; // // allocate buffer for transfering messages // char* OutputBuffer = (char*)malloc(UsermodeBufferSize); try { while (TRUE) { if (!IsVmxOffProcessStart) { ZeroMemory(OutputBuffer, UsermodeBufferSize); Sleep(200); // we're not trying to eat all of the CPU ;) Status = DeviceIoControl( Device, // Handle to device IOCTL_REGISTER_EVENT, // IO Control code &RegisterEvent, // Input Buffer to driver. SIZEOF_REGISTER_EVENT * 2, // Length of input buffer in bytes. (x 2 is bcuz as the driver is x64 and has 64 bit values) OutputBuffer, // Output Buffer from driver. UsermodeBufferSize, // Length of output buffer in bytes. &ReturnedLength, // Bytes placed in buffer. NULL // synchronous call ); if (!Status) { ShowMessages("Ioctl failed with code 0x%x\n", GetLastError()); break; } ShowMessages("========================= Kernel Mode (Buffer) =========================\n"); OperationCode = 0; memcpy(&OperationCode, OutputBuffer, sizeof(UINT32)); ShowMessages("Returned Length : 0x%x \n", ReturnedLength); ShowMessages("Operation Code : 0x%x \n", OperationCode); switch (OperationCode) { case OPERATION_LOG_NON_IMMEDIATE_MESSAGE: ShowMessages("A buffer of messages (OPERATION_LOG_NON_IMMEDIATE_MESSAGE) :\n"); ShowMessages("%s\n", OutputBuffer + sizeof(UINT32)); break; case OPERATION_LOG_INFO_MESSAGE: ShowMessages("Information log (OPERATION_LOG_INFO_MESSAGE) :\n"); ShowMessages("%s\n", OutputBuffer + sizeof(UINT32)); break; case OPERATION_LOG_ERROR_MESSAGE: ShowMessages("Error log (OPERATION_LOG_ERROR_MESSAGE) :\n"); ShowMessages("%s\n", OutputBuffer + sizeof(UINT32)); break; case OPERATION_LOG_WARNING_MESSAGE: ShowMessages("Warning log (OPERATION_LOG_WARNING_MESSAGE) :\n"); ShowMessages("%s\n", OutputBuffer + sizeof(UINT32)); break; default: break; } ShowMessages("========================================================================\n"); } else { // // the thread should not work anymore // return; } } } catch (const std::exception&) { ShowMessages(" Exception !\n"); } } /** * @brief Create a thread for pending buffers * * @param Data * @return DWORD Device Handle */ DWORD WINAPI ThreadFunc(void* Data) { // // Do stuff. This will be the first function called on the new thread. // When this function returns, the thread goes away. See MSDN for more details. // Test Irp Based Notifications // ReadIrpBasedBuffer(Data); return 0; } #endif /** * @brief Install the driver * * @return int return zero if it was successful or non-zero if there was error */ HPRDBGCTRL_API int HyperdbgInstallDriver() { ReadVendorString(); // // The driver is not started yet so let us the install driver. // First setup full path to driver name. // if (!SetupDriverName(driverLocation, sizeof(driverLocation))) { return 1; } if (!ManageDriver(DRIVER_NAME, driverLocation, DRIVER_FUNC_INSTALL )) { ShowMessages("Unable to install driver\n"); // // Error - remove driver. // ManageDriver(DRIVER_NAME, driverLocation, DRIVER_FUNC_REMOVE ); return 1; } return 0; } /** * @brief Uninstall the driver * * @return int return zero if it was successful or non-zero if there was error */ HPRDBGCTRL_API int HyperdbgUninstallDriver() { // // Unload the driver if loaded. Ignore any errors. // if (driverLocation[0] != (TCHAR)0) { ManageDriver(DRIVER_NAME, driverLocation, DRIVER_FUNC_REMOVE ); } return 0; } /** * @brief Load the driver * * @return int return zero if it was successful or non-zero if there was error */ HPRDBGCTRL_API int HyperdbgLoad() { string CpuID; DWORD ErrorNum; BOOL Status; HANDLE hProcess; HANDLE hToken; CpuID = ReadVendorString(); ShowMessages("The CPU Vendor is : %s\n", CpuID.c_str()); if (CpuID == "GenuineIntel") { ShowMessages("The Processor virtualization technology is VT-x.\n"); } else { ShowMessages("This program is not designed to run in a non-VT-x environemnt !\n"); return 1; } if (VmxSupportDetection()) { ShowMessages("VMX Operation is supported by your processor .\n"); } else { ShowMessages("VMX Operation is not supported by your processor .\n"); return 1; } // // Enable Debug privilege // hProcess = GetCurrentProcess(); if (OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hToken)) { SetPrivilege(hToken, SE_DEBUG_NAME, TRUE); CloseHandle(hToken); } Handle = CreateFileA("\\\\.\\HyperdbgHypervisorDevice", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, /// lpSecurityAttirbutes OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); /// lpTemplateFile if (Handle == INVALID_HANDLE_VALUE) { ErrorNum = GetLastError(); if (ErrorNum == 5) { ShowMessages("Error: Access denied! Are you sure you have administrator rights?\n"); } else { ShowMessages("CreateFile failed with error: 0x%x\n", ErrorNum); } return 1; } #if !UseDbgPrintInsteadOfUsermodeMessageTracking HANDLE Thread = CreateThread(NULL, 0, ThreadFunc, Handle, 0, NULL); if (Thread) { ShowMessages("Thread Created successfully !!!\n"); } #endif return 0; } /** * @brief Unload driver * * @return int return zero if it was successful or non-zero if there was error */ HPRDBGCTRL_API int HyperdbgUnload() { BOOL Status; if (!Handle) { ShowMessages("Handle not found, probably the driver is not initialized.\n"); return 1; } ShowMessages("Terminating VMX !\n"); // // Send IOCTL to mark complete all IRP Pending // Status = DeviceIoControl( Handle, // Handle to device IOCTL_TERMINATE_VMX, // IO Control code NULL, // Input Buffer to driver. 0, // Length of input buffer in bytes. (x 2 is bcuz as the driver is x64 and has 64 bit values) NULL, // Output Buffer from driver. 0, // Length of output buffer in bytes. NULL, // Bytes placed in buffer. NULL // synchronous call ); // // wait to make sure we don't use an invalid handle in another Ioctl // if (!Status) { ShowMessages("Ioctl failed with code 0x%x\n", GetLastError()); } // // Send IOCTL to mark complete all IRP Pending // Status = DeviceIoControl( Handle, // Handle to device IOCTL_RETURN_IRP_PENDING_PACKETS_AND_DISALLOW_IOCTL, // IO Control code NULL, // Input Buffer to driver. 0, // Length of input buffer in bytes. (x 2 is bcuz as the driver is x64 and has 64 bit values) NULL, // Output Buffer from driver. 0, // Length of output buffer in bytes. NULL, // Bytes placed in buffer. NULL // synchronous call ); // // wait to make sure we don't use an invalid handle in another Ioctl // if (!Status) { ShowMessages("Ioctl failed with code 0x%x\n", GetLastError()); } // // Indicate that the finish process start or not // IsVmxOffProcessStart = TRUE; Sleep(1000); // Wait so next thread can return from IRP Pending // // Send IRP_MJ_CLOSE to driver to terminate Vmxs // if (!CloseHandle(Handle)) { ShowMessages("Error : 0x%x\n", GetLastError()); }; ShowMessages("You're not on hypervisor anymore !\n"); }