mirror of
https://github.com/HyperDbg/HyperDbg.git
synced 2026-08-26 08:53:21 +00:00
452 lines
No EOL
10 KiB
C++
452 lines
No EOL
10 KiB
C++
/**
|
|
* @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");
|
|
} |