Files
2023-02-03 16:08:09 +01:00

1252 lines
44 KiB
C++

#include "HookMain.h"
#pragma intrinsic(_ReturnAddress)
HOOK_DLL_DATA HookDllData = { 0 };
#include "HookedFunctions.h"
#include "HookHelper.h"
#include "Tls.h"
#include "Scylla/VersionPatch.h"
void FakeCurrentParentProcessId(PSYSTEM_PROCESS_INFORMATION pInfo);
void FakeCurrentOtherOperationCount(PSYSTEM_PROCESS_INFORMATION pInfo);
void FilterHandleInfo(PSYSTEM_HANDLE_INFORMATION pHandleInfo, PULONG pReturnLengthAdjust);
void FilterHandleInfoEx(PSYSTEM_HANDLE_INFORMATION_EX pHandleInfoEx, PULONG pReturnLengthAdjust);
void FilterProcess(PSYSTEM_PROCESS_INFORMATION pInfo);
void FilterObjects(POBJECT_TYPES_INFORMATION pObjectTypes);
void FilterObject(POBJECT_TYPE_INFORMATION pObject, bool zeroTotal);
void FilterHwndList(HWND * phwndFirst, PUINT pcHwndNeeded);
SAVE_DEBUG_REGISTERS ArrayDebugRegister[100] = { 0 }; //Max 100 threads
// https://forum.tuts4you.com/topic/40011-debugme-vmprotect-312-build-886-anti-debug-method-improved/#comment-192824
// https://github.com/x64dbg/ScyllaHide/issues/47
// https://github.com/mrexodia/TitanHide/issues/27
#define BACKUP_RETURNLENGTH() \
ULONG TempReturnLength = 0; \
if(ReturnLength != nullptr) \
TempReturnLength = *ReturnLength
#define RESTORE_RETURNLENGTH() \
if(ReturnLength != nullptr) \
(*ReturnLength) = TempReturnLength
NTSTATUS NTAPI HookedNtSetInformationThread(HANDLE ThreadHandle, THREADINFOCLASS ThreadInformationClass, PVOID ThreadInformation, ULONG ThreadInformationLength)
{
if (ThreadInformationClass == ThreadHideFromDebugger && ThreadInformationLength == 0) // NB: ThreadInformation is not checked, this is deliberate
{
if (ThreadHandle == NtCurrentThread ||
HandleToULong(NtCurrentTeb()->ClientId.UniqueProcess) == GetProcessIdByThreadHandle(ThreadHandle)) //thread inside this process?
{
return STATUS_SUCCESS;
}
}
return HookDllData.dNtSetInformationThread(ThreadHandle, ThreadInformationClass, ThreadInformation, ThreadInformationLength);
}
NTSTATUS NTAPI HookedNtQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength)
{
if (SystemInformationClass == SystemKernelDebuggerInformation ||
SystemInformationClass == SystemProcessInformation ||
SystemInformationClass == SystemSessionProcessInformation ||
SystemInformationClass == SystemHandleInformation ||
SystemInformationClass == SystemExtendedHandleInformation ||
SystemInformationClass == SystemExtendedProcessInformation || // Vista+
SystemInformationClass == SystemCodeIntegrityInformation || // Vista+
SystemInformationClass == SystemKernelDebuggerInformationEx || // 8.1+
SystemInformationClass == SystemKernelDebuggerFlags || // 10+
SystemInformationClass == SystemCodeIntegrityUnlockInformation) // 10+
{
NTSTATUS ntStat = HookDllData.dNtQuerySystemInformation(SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength);
if (NT_SUCCESS(ntStat) && SystemInformation != nullptr && SystemInformationLength != 0)
{
if (SystemInformationClass == SystemKernelDebuggerInformation)
{
BACKUP_RETURNLENGTH();
((PSYSTEM_KERNEL_DEBUGGER_INFORMATION)SystemInformation)->KernelDebuggerEnabled = FALSE;
((PSYSTEM_KERNEL_DEBUGGER_INFORMATION)SystemInformation)->KernelDebuggerNotPresent = TRUE;
RESTORE_RETURNLENGTH();
}
else if (SystemInformationClass == SystemHandleInformation)
{
BACKUP_RETURNLENGTH();
ULONG ReturnLengthAdjust = 0;
FilterHandleInfo((PSYSTEM_HANDLE_INFORMATION)SystemInformation, &ReturnLengthAdjust);
if (ReturnLengthAdjust <= TempReturnLength)
TempReturnLength -= ReturnLengthAdjust;
RESTORE_RETURNLENGTH();
}
else if (SystemInformationClass == SystemExtendedHandleInformation)
{
BACKUP_RETURNLENGTH();
ULONG ReturnLengthAdjust = 0;
FilterHandleInfoEx((PSYSTEM_HANDLE_INFORMATION_EX)SystemInformation, &ReturnLengthAdjust);
if (ReturnLengthAdjust <= TempReturnLength)
TempReturnLength -= ReturnLengthAdjust;
RESTORE_RETURNLENGTH();
}
else if (SystemInformationClass == SystemProcessInformation ||
SystemInformationClass == SystemSessionProcessInformation ||
SystemInformationClass == SystemExtendedProcessInformation)
{
BACKUP_RETURNLENGTH();
PSYSTEM_PROCESS_INFORMATION ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)SystemInformation;
if (SystemInformationClass == SystemSessionProcessInformation)
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)((PSYSTEM_SESSION_PROCESS_INFORMATION)SystemInformation)->Buffer;
FilterProcess(ProcessInfo);
FakeCurrentParentProcessId(ProcessInfo);
FakeCurrentOtherOperationCount(ProcessInfo);
RESTORE_RETURNLENGTH();
}
else if (SystemInformationClass == SystemCodeIntegrityInformation)
{
BACKUP_RETURNLENGTH();
((PSYSTEM_CODEINTEGRITY_INFORMATION)SystemInformation)->CodeIntegrityOptions = CODEINTEGRITY_OPTION_ENABLED;
RESTORE_RETURNLENGTH();
}
else if (SystemInformationClass == SystemKernelDebuggerInformationEx)
{
BACKUP_RETURNLENGTH();
((PSYSTEM_KERNEL_DEBUGGER_INFORMATION_EX)SystemInformation)->DebuggerAllowed = FALSE;
((PSYSTEM_KERNEL_DEBUGGER_INFORMATION_EX)SystemInformation)->DebuggerEnabled = FALSE;
((PSYSTEM_KERNEL_DEBUGGER_INFORMATION_EX)SystemInformation)->DebuggerPresent = FALSE;
RESTORE_RETURNLENGTH();
}
else if (SystemInformationClass == SystemKernelDebuggerFlags)
{
BACKUP_RETURNLENGTH();
*(PUCHAR)SystemInformation = 0;
RESTORE_RETURNLENGTH();
}
else if (SystemInformationClass == SystemCodeIntegrityUnlockInformation)
{
BACKUP_RETURNLENGTH();
// The size of the buffer for this class changed from 4 to 36, but the output should still be all zeroes
RtlZeroMemory(SystemInformation, SystemInformationLength);
RESTORE_RETURNLENGTH();
}
}
return ntStat;
}
return HookDllData.dNtQuerySystemInformation(SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength);
}
static ULONG ValueProcessBreakOnTermination = FALSE;
static ULONG ValueProcessDebugFlags = PROCESS_DEBUG_INHERIT; // actual value is no inherit
static bool IsProcessHandleTracingEnabled = false;
#ifndef STATUS_INVALID_PARAMETER
#define STATUS_INVALID_PARAMETER ((DWORD )0xC000000DL)
#endif
// Instrumentation callback
static LONG volatile InstrumentationCallbackHookInstalled = 0;
static ULONG NumManualSyscalls = 0;
extern "C"
ULONG_PTR
NTAPI
InstrumentationCallback(
_In_ ULONG_PTR ReturnAddress, // ECX/R10
_Inout_ ULONG_PTR ReturnVal // EAX/RAX
)
{
if (InterlockedOr(TlsGetInstrumentationCallbackDisabled(), 0x1) == 0x1)
return ReturnVal; // Do not recurse
const PVOID ImageBase = NtCurrentPeb()->ImageBaseAddress;
const PIMAGE_NT_HEADERS NtHeaders = RtlImageNtHeader(ImageBase);
if (NtHeaders != nullptr && ReturnAddress >= (ULONG_PTR)ImageBase &&
ReturnAddress < (ULONG_PTR)ImageBase + NtHeaders->OptionalHeader.SizeOfImage)
{
// Syscall return address within the exe file
ReturnVal = (ULONG_PTR)(ULONG)STATUS_PORT_NOT_SET;
// Uninstall ourselves after we have completed the sequence { NtQIP, NtQIP }. More NtSITs will follow but we can't do anything about them
NumManualSyscalls++;
if (NumManualSyscalls >= 2)
{
InstallInstrumentationCallbackHook(NtCurrentProcess, TRUE);
}
}
InterlockedAnd(TlsGetInstrumentationCallbackDisabled(), 0);
return ReturnVal;
}
NTSTATUS NTAPI HookedNtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength)
{
if (NumManualSyscalls == 0 &&
InterlockedOr(&InstrumentationCallbackHookInstalled, 0x1) == 0)
{
InstallInstrumentationCallbackHook(NtCurrentProcess, FALSE);
}
NTSTATUS Status;
if (ProcessInformationClass == ProcessDebugObjectHandle && // Handle ProcessDebugObjectHandle early
ProcessInformation != nullptr &&
ProcessInformationLength == sizeof(HANDLE) &&
(ProcessHandle == NtCurrentProcess || HandleToULong(NtCurrentTeb()->ClientId.UniqueProcess) == GetProcessIdByProcessHandle(ProcessHandle)))
{
// Verify (1) that the handle has PROCESS_QUERY_INFORMATION access, and (2) that writing
// to ProcessInformation and/or ReturnLength does not cause any access or alignment violations
Status = HookDllData.dNtQueryInformationProcess(ProcessHandle,
ProcessDebugPort, // Note: not ProcessDebugObjectHandle
ProcessInformation,
sizeof(HANDLE),
ReturnLength);
if (!NT_SUCCESS(Status))
return Status;
// The kernel calls DbgkOpenProcessDebugPort here
// This should be done in a try/except block, but since we are a mapped DLL we cannot use SEH.
// Rely on the fact that the NtQIP call we just did wrote to the same buffers successfully
*(PHANDLE)ProcessInformation = nullptr;
if (ReturnLength != nullptr)
*ReturnLength = sizeof(HANDLE);
return STATUS_PORT_NOT_SET;
}
if ((ProcessInformationClass == ProcessDebugFlags ||
ProcessInformationClass == ProcessDebugPort ||
ProcessInformationClass == ProcessBasicInformation ||
ProcessInformationClass == ProcessBreakOnTermination ||
ProcessInformationClass == ProcessHandleTracing ||
ProcessInformationClass == ProcessIoCounters) &&
(ProcessHandle == NtCurrentProcess || HandleToULong(NtCurrentTeb()->ClientId.UniqueProcess) == GetProcessIdByProcessHandle(ProcessHandle)))
{
Status = HookDllData.dNtQueryInformationProcess(ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength, ReturnLength);
if (NT_SUCCESS(Status) && ProcessInformation != nullptr && ProcessInformationLength != 0)
{
if (ProcessInformationClass == ProcessDebugFlags)
{
BACKUP_RETURNLENGTH();
*((ULONG *)ProcessInformation) = ((ValueProcessDebugFlags & PROCESS_NO_DEBUG_INHERIT) != 0) ? 0 : PROCESS_DEBUG_INHERIT;
RESTORE_RETURNLENGTH();
}
else if (ProcessInformationClass == ProcessDebugPort)
{
BACKUP_RETURNLENGTH();
*((HANDLE *)ProcessInformation) = nullptr;
RESTORE_RETURNLENGTH();
}
else if (ProcessInformationClass == ProcessBasicInformation) //Fake parent
{
BACKUP_RETURNLENGTH();
((PPROCESS_BASIC_INFORMATION)ProcessInformation)->InheritedFromUniqueProcessId = ULongToHandle(GetExplorerProcessId());
RESTORE_RETURNLENGTH();
}
else if (ProcessInformationClass == ProcessBreakOnTermination)
{
BACKUP_RETURNLENGTH();
*((ULONG *)ProcessInformation) = ValueProcessBreakOnTermination;
RESTORE_RETURNLENGTH();
}
else if (ProcessInformationClass == ProcessHandleTracing)
{
BACKUP_RETURNLENGTH();
RESTORE_RETURNLENGTH(); // Trigger any possible exceptions caused by messing with the output buffer before changing the final return status
Status = IsProcessHandleTracingEnabled ? STATUS_SUCCESS : STATUS_INVALID_PARAMETER;
}
else if (ProcessInformationClass == ProcessIoCounters)
{
BACKUP_RETURNLENGTH();
((PIO_COUNTERS)ProcessInformation)->OtherOperationCount = 1;
RESTORE_RETURNLENGTH();
}
}
return Status;
}
return HookDllData.dNtQueryInformationProcess(ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength, ReturnLength);
}
NTSTATUS NTAPI HookedNtSetInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength)
{
if (ProcessHandle == NtCurrentProcess || HandleToULong(NtCurrentTeb()->ClientId.UniqueProcess) == GetProcessIdByProcessHandle(ProcessHandle))
{
if (ProcessInformationClass == ProcessBreakOnTermination)
{
if (ProcessInformationLength != sizeof(ULONG))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
// NtSetInformationProcess will happily dereference this pointer
if (ProcessInformation == NULL)
{
return STATUS_ACCESS_VIOLATION;
}
// A process must have debug privileges enabled to set the ProcessBreakOnTermination flag
if (!HasDebugPrivileges(NtCurrentProcess))
{
return STATUS_PRIVILEGE_NOT_HELD;
}
ValueProcessBreakOnTermination = *((ULONG *)ProcessInformation);
return STATUS_SUCCESS;
}
// Don't allow changing the debug inherit flag, and keep track of the new value to report in NtQIP
if (ProcessInformationClass == ProcessDebugFlags)
{
if (ProcessInformationLength != sizeof(ULONG))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
if (ProcessInformation == NULL)
{
return STATUS_ACCESS_VIOLATION;
}
ULONG Flags = *(ULONG*)ProcessInformation;
if ((Flags & ~PROCESS_DEBUG_INHERIT) != 0)
{
return STATUS_INVALID_PARAMETER;
}
if ((Flags & PROCESS_DEBUG_INHERIT) != 0)
{
ValueProcessDebugFlags &= ~PROCESS_NO_DEBUG_INHERIT;
}
else
{
ValueProcessDebugFlags |= PROCESS_NO_DEBUG_INHERIT;
}
return STATUS_SUCCESS;
}
//PROCESS_HANDLE_TRACING_ENABLE -> ULONG, PROCESS_HANDLE_TRACING_ENABLE_EX -> ULONG,ULONG
if (ProcessInformationClass == ProcessHandleTracing)
{
bool enable = ProcessInformationLength != 0; // A length of 0 is valid and indicates we should disable tracing
if (enable)
{
if (ProcessInformationLength != sizeof(ULONG) && ProcessInformationLength != (sizeof(ULONG) * 2))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
// NtSetInformationProcess will happily dereference this pointer
if (ProcessInformation == NULL)
{
return STATUS_ACCESS_VIOLATION;
}
PPROCESS_HANDLE_TRACING_ENABLE_EX phtEx = (PPROCESS_HANDLE_TRACING_ENABLE_EX)ProcessInformation;
if (phtEx->Flags != 0)
{
return STATUS_INVALID_PARAMETER;
}
}
IsProcessHandleTracingEnabled = enable;
return STATUS_SUCCESS;
}
}
return HookDllData.dNtSetInformationProcess(ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength);
}
NTSTATUS NTAPI HookedNtQueryObject(HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength)
{
NTSTATUS ntStat = HookDllData.dNtQueryObject(Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength, ReturnLength);
if ((ObjectInformationClass == ObjectTypesInformation ||
ObjectInformationClass == ObjectTypeInformation) &&
(NT_SUCCESS(ntStat) && ObjectInformation))
{
if (ObjectInformationClass == ObjectTypesInformation)
{
BACKUP_RETURNLENGTH();
FilterObjects((POBJECT_TYPES_INFORMATION)ObjectInformation);
RESTORE_RETURNLENGTH();
}
else if (ObjectInformationClass == ObjectTypeInformation)
{
BACKUP_RETURNLENGTH();
FilterObject((POBJECT_TYPE_INFORMATION)ObjectInformation, false);
RESTORE_RETURNLENGTH();
}
}
return ntStat;
}
NTSTATUS NTAPI HookedNtYieldExecution()
{
HookDllData.dNtYieldExecution();
return STATUS_ACCESS_DENIED; //better than STATUS_SUCCESS or STATUS_NO_YIELD_PERFORMED
}
NTSTATUS NTAPI HookedNtGetContextThread(HANDLE ThreadHandle, PCONTEXT ThreadContext)
{
DWORD ContextBackup = 0;
BOOLEAN DebugRegistersRequested = FALSE;
if (ThreadHandle == NtCurrentThread ||
HandleToULong(NtCurrentTeb()->ClientId.UniqueProcess) == GetProcessIdByThreadHandle(ThreadHandle)) //thread inside this process?
{
if (ThreadContext)
{
ContextBackup = ThreadContext->ContextFlags;
ThreadContext->ContextFlags &= ~CONTEXT_DEBUG_REGISTERS;
DebugRegistersRequested = ThreadContext->ContextFlags != ContextBackup;
}
}
NTSTATUS ntStat = HookDllData.dNtGetContextThread(ThreadHandle, ThreadContext);
if (ContextBackup)
{
ThreadContext->ContextFlags = ContextBackup;
if (DebugRegistersRequested)
{
ThreadContext->Dr0 = 0;
ThreadContext->Dr1 = 0;
ThreadContext->Dr2 = 0;
ThreadContext->Dr3 = 0;
ThreadContext->Dr6 = 0;
ThreadContext->Dr7 = 0;
#ifdef _WIN64
ThreadContext->LastBranchToRip = 0;
ThreadContext->LastBranchFromRip = 0;
ThreadContext->LastExceptionToRip = 0;
ThreadContext->LastExceptionFromRip = 0;
#endif
}
}
return ntStat;
}
NTSTATUS NTAPI HookedNtSetContextThread(HANDLE ThreadHandle, PCONTEXT ThreadContext)
{
DWORD ContextBackup = 0;
if (ThreadHandle == NtCurrentThread ||
HandleToULong(NtCurrentTeb()->ClientId.UniqueProcess) == GetProcessIdByThreadHandle(ThreadHandle)) //thread inside this process?
{
if (ThreadContext)
{
ContextBackup = ThreadContext->ContextFlags;
ThreadContext->ContextFlags &= ~CONTEXT_DEBUG_REGISTERS;
}
}
NTSTATUS ntStat = HookDllData.dNtSetContextThread(ThreadHandle, ThreadContext);
if (ContextBackup)
{
ThreadContext->ContextFlags = ContextBackup;
}
return ntStat;
}
void NTAPI HandleKiUserExceptionDispatcher(PEXCEPTION_RECORD pExcptRec, PCONTEXT ContextFrame)
{
if (ContextFrame && (ContextFrame->ContextFlags & CONTEXT_DEBUG_REGISTERS))
{
int slotIndex = ThreadDebugContextFindFreeSlotIndex();
if (slotIndex != -1)
{
ThreadDebugContextSaveContext(slotIndex, ContextFrame);
}
ContextFrame->Dr0 = 0;
ContextFrame->Dr1 = 0;
ContextFrame->Dr2 = 0;
ContextFrame->Dr3 = 0;
ContextFrame->Dr6 = 0;
ContextFrame->Dr7 = 0;
}
}
#ifdef _WIN64
void NTAPI HookedKiUserExceptionDispatcher()
{
// inline assembly is not supported in x86_64 with CL. a more elegant
// way to do this would be to modify the project to include an .asm
// source file that defines 'HookedKiUserExceptionDispatcher' for both
// 32 and 64 bit.
// the + 8 in the line below is because we arrive at this function via
// a CALL instruction which causes the stack to shift. This CALL in
// the trampoline is necessary because HandleKiUserExceptionDispatcher
// will end in a RET instruction, and the CALL preserves the stack.
PCONTEXT ContextFrame = (PCONTEXT)(((UINT_PTR)_AddressOfReturnAddress()) + 8);
HandleKiUserExceptionDispatcher(nullptr, ContextFrame);
}
#else
VOID NAKED NTAPI HookedKiUserExceptionDispatcher()// (PEXCEPTION_RECORD pExcptRec, PCONTEXT ContextFrame) //remove DRx Registers
{
//MOV ECX,DWORD PTR SS:[ESP+4] <- ContextFrame
//MOV EBX,DWORD PTR SS:[ESP] <- pExcptRec
__asm
{
MOV EAX, [ESP + 4]
MOV ECX, [ESP]
PUSH EAX
PUSH ECX
CALL HandleKiUserExceptionDispatcher
jmp HookDllData.dKiUserExceptionDispatcher
}
//return HookDllData.dKiUserExceptionDispatcher(pExcptRec, ContextFrame);
}
#endif
static DWORD_PTR KiUserExceptionDispatcherAddress = 0;
NTSTATUS NTAPI HookedNtContinue(PCONTEXT ThreadContext, BOOLEAN RaiseAlert) //restore DRx Registers
{
DWORD_PTR retAddress = (DWORD_PTR)_ReturnAddress();
if (!KiUserExceptionDispatcherAddress)
{
UNICODE_STRING NtdllName = RTL_CONSTANT_STRING(L"ntdll.dll");
PVOID Ntdll;
if (NT_SUCCESS(LdrGetDllHandle(nullptr, nullptr, &NtdllName, &Ntdll)))
{
ANSI_STRING KiUserExceptionDispatcherName = RTL_CONSTANT_ANSI_STRING("KiUserExceptionDispatcher");
LdrGetProcedureAddress(Ntdll, &KiUserExceptionDispatcherName, 0, (PVOID*)&KiUserExceptionDispatcherAddress);
}
}
if (ThreadContext != nullptr &&
retAddress >= KiUserExceptionDispatcherAddress && retAddress < (KiUserExceptionDispatcherAddress + 0x100))
{
int index = ThreadDebugContextFindExistingSlotIndex();
if (index != -1)
{
ThreadContext->Dr0 = ArrayDebugRegister[index].Dr0;
ThreadContext->Dr1 = ArrayDebugRegister[index].Dr1;
ThreadContext->Dr2 = ArrayDebugRegister[index].Dr2;
ThreadContext->Dr3 = ArrayDebugRegister[index].Dr3;
ThreadContext->Dr6 = ArrayDebugRegister[index].Dr6;
ThreadContext->Dr7 = ArrayDebugRegister[index].Dr7;
ThreadDebugContextRemoveEntry(index);
}
}
return HookDllData.dNtContinue(ThreadContext, RaiseAlert);
}
#ifndef _WIN64
PVOID NTAPI HandleNativeCallInternal(DWORD eaxValue, DWORD ecxValue)
{
for (ULONG i = 0; i < _countof(HookDllData.HookNative); i++)
{
if (HookDllData.HookNative[i].eaxValue == eaxValue)
{
if (HookDllData.HookNative[i].ecxValue)
{
if (HookDllData.HookNative[i].ecxValue == ecxValue)
{
return HookDllData.HookNative[i].hookedFunction;
}
}
else
{
return HookDllData.HookNative[i].hookedFunction;
}
}
}
return 0;
}
#endif
void NAKED NTAPI HookedNativeCallInternal()
{
#ifndef _WIN64
__asm
{
PUSHAD
PUSH ECX
PUSH EAX
CALL HandleNativeCallInternal
cmp eax, 0
je NoHook
POPAD
ADD ESP,4
PUSH ECX
PUSH EAX
CALL HandleNativeCallInternal
jmp eax
NoHook:
POPAD
jmp HookDllData.NativeCallContinue
}
#endif
}
NTSTATUS NTAPI HookedNtClose(HANDLE Handle)
{
OBJECT_HANDLE_FLAG_INFORMATION flags;
NTSTATUS Status;
if (HookDllData.dNtQueryObject != nullptr)
Status = HookDllData.dNtQueryObject(Handle, ObjectHandleFlagInformation, &flags, sizeof(OBJECT_HANDLE_FLAG_INFORMATION), nullptr);
else
Status = NtQueryObject(Handle, ObjectHandleFlagInformation, &flags, sizeof(OBJECT_HANDLE_FLAG_INFORMATION), nullptr);
if (NT_SUCCESS(Status))
{
if (flags.ProtectFromClose)
{
return STATUS_HANDLE_NOT_CLOSABLE;
}
return HookDllData.dNtClose(Handle);
}
return STATUS_INVALID_HANDLE;
}
NTSTATUS NTAPI HookedNtDuplicateObject(HANDLE SourceProcessHandle, HANDLE SourceHandle, HANDLE TargetProcessHandle, PHANDLE TargetHandle, ACCESS_MASK DesiredAccess, ULONG HandleAttributes, ULONG Options)
{
if (Options & DUPLICATE_CLOSE_SOURCE)
{
// If a process is being debugged and duplicates a handle with DUPLICATE_CLOSE_SOURCE, *and* the handle has the ProtectFromClose bit set, a STATUS_HANDLE_NOT_CLOSABLE exception will occur.
// This is actually the exact same exception we already check for in NtClose, but the difference is that this NtClose call happens inside the kernel which we obviously can't hook.
// When a process is not being debugged, NtDuplicateObject will simply return success without closing the source. This is because ObDuplicateObject ignores NtClose return values
OBJECT_HANDLE_FLAG_INFORMATION HandleFlags;
NTSTATUS Status;
if (HookDllData.dNtQueryObject != nullptr)
Status = HookDllData.dNtQueryObject(SourceHandle, ObjectHandleFlagInformation, &HandleFlags, sizeof(HandleFlags), nullptr);
else
Status = NtQueryObject(SourceHandle, ObjectHandleFlagInformation, &HandleFlags, sizeof(HandleFlags), nullptr);
if (NT_SUCCESS(Status) && HandleFlags.ProtectFromClose)
{
// Prevent the exception
Options &= ~DUPLICATE_CLOSE_SOURCE;
}
}
return HookDllData.dNtDuplicateObject(SourceProcessHandle, SourceHandle, TargetProcessHandle, TargetHandle, DesiredAccess, HandleAttributes, Options);
}
//////////////////////////////////////////////////////////////
////////////////////// TIME FUNCTIONS ////////////////////////
//////////////////////////////////////////////////////////////
static DWORD OneTickCount = 0;
DWORD WINAPI HookedGetTickCount(void)
{
if (!OneTickCount)
{
OneTickCount = HookDllData.dGetTickCount();
}
else
{
OneTickCount++;
}
return OneTickCount;
}
ULONGLONG WINAPI HookedGetTickCount64(void) //yes we can use DWORD
{
if (!OneTickCount)
{
if (HookDllData.dGetTickCount)
{
OneTickCount = HookDllData.dGetTickCount();
}
else
{
OneTickCount = RtlGetTickCount();
}
}
else
{
OneTickCount++;
}
return OneTickCount;
}
static SYSTEMTIME OneLocalTime = {0};
static SYSTEMTIME OneSystemTime = {0};
void WINAPI HookedGetLocalTime(LPSYSTEMTIME lpSystemTime)
{
if (!OneLocalTime.wYear)
{
RealGetLocalTime(&OneLocalTime);
if (HookDllData.dGetSystemTime)
{
RealGetSystemTime(&OneSystemTime);
}
}
else
{
IncreaseSystemTime(&OneLocalTime);
if (HookDllData.dGetSystemTime)
{
IncreaseSystemTime(&OneSystemTime);
}
}
if (lpSystemTime)
{
memcpy(lpSystemTime, &OneLocalTime, sizeof(SYSTEMTIME));
}
}
void WINAPI HookedGetSystemTime(LPSYSTEMTIME lpSystemTime)
{
if (!OneSystemTime.wYear)
{
RealGetSystemTime(&OneSystemTime);
if (HookDllData.dGetLocalTime)
{
RealGetLocalTime(&OneLocalTime);
}
}
else
{
IncreaseSystemTime(&OneSystemTime);
if (HookDllData.dGetLocalTime)
{
IncreaseSystemTime(&OneLocalTime);
}
}
if (lpSystemTime)
{
memcpy(lpSystemTime, &OneSystemTime, sizeof(SYSTEMTIME));
}
}
static LARGE_INTEGER OneNativeSysTime = {0};
NTSTATUS WINAPI HookedNtQuerySystemTime(PLARGE_INTEGER SystemTime)
{
if (!OneNativeSysTime.QuadPart)
{
HookDllData.dNtQuerySystemTime(&OneNativeSysTime);
}
else
{
OneNativeSysTime.QuadPart++;
}
NTSTATUS ntStat = HookDllData.dNtQuerySystemTime(SystemTime);
if (ntStat == STATUS_SUCCESS)
{
if (SystemTime)
{
SystemTime->QuadPart = OneNativeSysTime.QuadPart;
}
}
return ntStat;
}
static LARGE_INTEGER OnePerformanceCounter = {0};
static LARGE_INTEGER OnePerformanceFrequency = {0};
NTSTATUS NTAPI HookedNtQueryPerformanceCounter(PLARGE_INTEGER PerformanceCounter, PLARGE_INTEGER PerformanceFrequency)
{
if (!OnePerformanceCounter.QuadPart)
{
HookDllData.dNtQueryPerformanceCounter(&OnePerformanceCounter, &OnePerformanceFrequency);
}
else
{
OnePerformanceCounter.QuadPart++;
}
NTSTATUS ntStat = HookDllData.dNtQueryPerformanceCounter(PerformanceCounter, PerformanceFrequency);
if (ntStat == STATUS_SUCCESS)
{
if (PerformanceFrequency) //OPTIONAL
{
PerformanceFrequency->QuadPart = OnePerformanceFrequency.QuadPart;
}
if (PerformanceCounter)
{
PerformanceCounter->QuadPart = OnePerformanceCounter.QuadPart;
}
}
return ntStat;
}
//////////////////////////////////////////////////////////////
////////////////////// TIME FUNCTIONS ////////////////////////
//////////////////////////////////////////////////////////////
static BOOL isBlocked = FALSE;
BOOL NTAPI HookedNtUserBlockInput(BOOL fBlockIt)
{
if (isBlocked == FALSE && fBlockIt != FALSE)
{
isBlocked = TRUE;
return TRUE;
}
else if (isBlocked != FALSE && fBlockIt == FALSE)
{
isBlocked = FALSE;
return TRUE;
}
return FALSE;
}
//GetLastError() function might not change if a debugger is present (it has never been the case that it is always set to zero).
DWORD WINAPI HookedOutputDebugStringA(LPCSTR lpOutputString) //Worst anti-debug ever
{
if (RtlNtMajorVersion() >= 6) // Vista or later
return 0;
NtCurrentTeb()->LastErrorValue = NtCurrentTeb()->LastErrorValue + 1; //change last error
return 1; //WinXP EAX -> 1
}
HWND NTAPI HookedNtUserFindWindowEx(HWND hWndParent, HWND hWndChildAfter, PUNICODE_STRING lpszClass, PUNICODE_STRING lpszWindow, DWORD dwType)
{
HWND resultHwnd = HookDllData.dNtUserFindWindowEx(hWndParent, hWndChildAfter, lpszClass, lpszWindow, dwType);
if (resultHwnd)
{
if (IsWindowClassNameBad(lpszClass) || IsWindowNameBad(lpszWindow))
{
return 0;
}
if (HookDllData.EnableProtectProcessId == TRUE)
{
DWORD dwProcessId;
if (HookDllData.dNtUserQueryWindow)
{
dwProcessId = HandleToULong(HookDllData.dNtUserQueryWindow(resultHwnd, WindowProcess));
}
else
{
dwProcessId = HandleToULong(HookDllData.NtUserQueryWindow(resultHwnd, WindowProcess));
}
if (dwProcessId == HookDllData.dwProtectedProcessId)
{
return 0;
}
}
}
return resultHwnd;
}
NTSTATUS NTAPI HookedNtSetDebugFilterState(ULONG ComponentId, ULONG Level, BOOLEAN State)
{
return HasDebugPrivileges(NtCurrentProcess) ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
}
void FilterHwndList(HWND * phwndFirst, PULONG pcHwndNeeded)
{
for (UINT i = 0; i < *pcHwndNeeded; i++)
{
if (phwndFirst[i] != nullptr && IsWindowBad(phwndFirst[i]))
{
if (i == 0)
{
// Find the first HWND that belongs to a different process (i + 1, i + 2... may still be ours)
for (UINT j = i + 1; j < *pcHwndNeeded; j++)
{
if (phwndFirst[j] != nullptr && !IsWindowBad(phwndFirst[j]))
{
phwndFirst[i] = phwndFirst[j];
break;
}
}
}
else
{
phwndFirst[i] = phwndFirst[i - 1]; //just override with previous
}
}
}
}
NTSTATUS NTAPI HookedNtUserBuildHwndList(HDESK hDesktop, HWND hwndParent, BOOLEAN bChildren, ULONG dwThreadId, ULONG lParam, HWND* pWnd, PULONG pBufSize)
{
NTSTATUS ntStat = HookDllData.dNtUserBuildHwndList(hDesktop, hwndParent, bChildren, dwThreadId, lParam, pWnd, pBufSize);
if (NT_SUCCESS(ntStat) && pWnd != nullptr && pBufSize != nullptr)
{
FilterHwndList(pWnd, pBufSize);
}
return ntStat;
}
NTSTATUS NTAPI HookedNtUserBuildHwndList_Eight(HDESK hDesktop, HWND hwndParent, BOOLEAN bChildren, BOOLEAN bUnknownFlag, ULONG dwThreadId, ULONG lParam, HWND* pWnd, PULONG pBufSize)
{
NTSTATUS ntStat = ((t_NtUserBuildHwndList_Eight)HookDllData.dNtUserBuildHwndList)(hDesktop, hwndParent, bChildren, bUnknownFlag, dwThreadId, lParam, pWnd, pBufSize);
if (NT_SUCCESS(ntStat) && pWnd != nullptr && pBufSize != nullptr)
{
FilterHwndList(pWnd, pBufSize);
}
return ntStat;
}
HANDLE NTAPI HookedNtUserQueryWindow(HWND hwnd, WINDOWINFOCLASS WindowInfo)
{
if ((WindowInfo == WindowProcess || WindowInfo == WindowThread) && IsWindowBad(hwnd))
{
if (WindowInfo == WindowProcess)
return NtCurrentTeb()->ClientId.UniqueProcess;
if (WindowInfo == WindowThread)
return NtCurrentTeb()->ClientId.UniqueThread;
}
return HookDllData.dNtUserQueryWindow(hwnd, WindowInfo);
}
HWND NTAPI HookedNtUserGetForegroundWindow()
{
HWND Hwnd = HookDllData.dNtUserGetForegroundWindow();
if (Hwnd != nullptr && IsWindowBad(Hwnd))
{
Hwnd = (HWND)HookDllData.NtUserGetThreadState(THREADSTATE_ACTIVEWINDOW);
}
return Hwnd;
}
//WIN XP: CreateThread -> CreateRemoteThread -> NtCreateThread
NTSTATUS NTAPI HookedNtCreateThread(PHANDLE ThreadHandle,ACCESS_MASK DesiredAccess,POBJECT_ATTRIBUTES ObjectAttributes,HANDLE ProcessHandle,PCLIENT_ID ClientId,PCONTEXT ThreadContext,PINITIAL_TEB InitialTeb,BOOLEAN CreateSuspended)
{
if (ProcessHandle == NtCurrentProcess)
{
return STATUS_INSUFFICIENT_RESOURCES;//STATUS_INVALID_PARAMETER STATUS_INVALID_HANDLE STATUS_INSUFFICIENT_RESOURCES
}
return HookDllData.dNtCreateThread(ThreadHandle, DesiredAccess, ObjectAttributes, ProcessHandle, ClientId,ThreadContext, InitialTeb,CreateSuspended);
}
//WIN 7: CreateThread -> CreateRemoteThreadEx -> NtCreateThreadEx
NTSTATUS NTAPI HookedNtCreateThreadEx(PHANDLE ThreadHandle,ACCESS_MASK DesiredAccess,POBJECT_ATTRIBUTES ObjectAttributes,HANDLE ProcessHandle,PUSER_THREAD_START_ROUTINE StartRoutine,PVOID Argument,ULONG CreateFlags,ULONG_PTR ZeroBits,SIZE_T StackSize,SIZE_T MaximumStackSize,PPS_ATTRIBUTE_LIST AttributeList)
{
if (HookDllData.EnableNtCreateThreadExHook == TRUE) //prevent hide from debugger
{
if (CreateFlags & THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER)
{
CreateFlags ^= THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER;
}
}
if (HookDllData.EnablePreventThreadCreation == TRUE)
{
if (ProcessHandle == NtCurrentProcess)
{
return STATUS_INSUFFICIENT_RESOURCES;//STATUS_INVALID_PARAMETER STATUS_INVALID_HANDLE STATUS_INSUFFICIENT_RESOURCES
}
}
return HookDllData.dNtCreateThreadEx(ThreadHandle, DesiredAccess, ObjectAttributes, ProcessHandle, StartRoutine, Argument, CreateFlags, ZeroBits, StackSize, MaximumStackSize,AttributeList);
}
void FilterHandleInfo(PSYSTEM_HANDLE_INFORMATION pHandleInfo, PULONG pReturnLengthAdjust)
{
*pReturnLengthAdjust = 0;
const ULONG TrueCount = pHandleInfo->NumberOfHandles;
for (ULONG i = 0; i < TrueCount; ++i)
{
// TODO: protect processes by name too
if ((HookDllData.EnableProtectProcessId == TRUE && (ULONG)(pHandleInfo->Handles[i].UniqueProcessId == HookDllData.dwProtectedProcessId)) &&
IsObjectTypeBad(pHandleInfo->Handles[i].ObjectTypeIndex))
{
pHandleInfo->NumberOfHandles--;
*pReturnLengthAdjust += sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO);
for (ULONG j = i; j < TrueCount - 1; ++j)
{
pHandleInfo->Handles[j] = pHandleInfo->Handles[j + 1];
RtlZeroMemory(&pHandleInfo->Handles[j + 1], sizeof(pHandleInfo->Handles[j + 1]));
}
i--;
}
}
}
void FilterHandleInfoEx(PSYSTEM_HANDLE_INFORMATION_EX pHandleInfoEx, PULONG pReturnLengthAdjust)
{
*pReturnLengthAdjust = 0;
const ULONG TrueCount = (ULONG)pHandleInfoEx->NumberOfHandles;
for (ULONG i = 0; i < TrueCount; ++i)
{
// TODO: protect processes by name too
if ((HookDllData.EnableProtectProcessId == TRUE && (ULONG)(pHandleInfoEx->Handles[i].UniqueProcessId == HookDllData.dwProtectedProcessId)) &&
IsObjectTypeBad(pHandleInfoEx->Handles[i].ObjectTypeIndex))
{
pHandleInfoEx->NumberOfHandles--;
*pReturnLengthAdjust += sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX);
for (ULONG j = i; j < TrueCount - 1; ++j)
{
pHandleInfoEx->Handles[j] = pHandleInfoEx->Handles[j + 1];
RtlZeroMemory(&pHandleInfoEx->Handles[j + 1], sizeof(pHandleInfoEx->Handles[j + 1]));
}
i--;
}
}
}
void FilterObjects(POBJECT_TYPES_INFORMATION pObjectTypes)
{
POBJECT_TYPE_INFORMATION pObject = pObjectTypes->TypeInformation;
for (ULONG i = 0; i < pObjectTypes->NumberOfTypes; i++)
{
FilterObject(pObject, true);
pObject = (POBJECT_TYPE_INFORMATION)(((PCHAR)(pObject + 1) + ALIGN_UP(pObject->TypeName.MaximumLength, ULONG_PTR)));
}
}
void FilterObject(POBJECT_TYPE_INFORMATION pObject, bool zeroTotal)
{
UNICODE_STRING debugObjectName = RTL_CONSTANT_STRING(L"DebugObject");
if (RtlEqualUnicodeString(&debugObjectName, &pObject->TypeName, FALSE))
{
// Subtract just one from both counts for our debugger, unless the query was a generic one for all object types
pObject->TotalNumberOfObjects = zeroTotal || pObject->TotalNumberOfObjects == 0 ? 0 : pObject->TotalNumberOfObjects - 1;
pObject->TotalNumberOfHandles = zeroTotal || pObject->TotalNumberOfHandles == 0 ? 0 : pObject->TotalNumberOfHandles - 1;
}
}
void FakeCurrentParentProcessId(PSYSTEM_PROCESS_INFORMATION pInfo)
{
while (true)
{
if (pInfo->UniqueProcessId == NtCurrentTeb()->ClientId.UniqueProcess)
{
pInfo->InheritedFromUniqueProcessId = ULongToHandle(GetExplorerProcessId());
break;
}
if (pInfo->NextEntryOffset == 0)
break;
pInfo = (PSYSTEM_PROCESS_INFORMATION)((DWORD_PTR)pInfo + pInfo->NextEntryOffset);
}
}
void FakeCurrentOtherOperationCount(PSYSTEM_PROCESS_INFORMATION pInfo)
{
while (true)
{
if (pInfo->UniqueProcessId == NtCurrentTeb()->ClientId.UniqueProcess)
{
LARGE_INTEGER one;
one.QuadPart = 1;
pInfo->OtherOperationCount = one;
break;
}
if (pInfo->NextEntryOffset == 0)
break;
pInfo = (PSYSTEM_PROCESS_INFORMATION)((DWORD_PTR)pInfo + pInfo->NextEntryOffset);
}
}
void FilterProcess(PSYSTEM_PROCESS_INFORMATION pInfo)
{
PSYSTEM_PROCESS_INFORMATION pPrev = pInfo;
while (TRUE)
{
if (IsProcessNameBad(&pInfo->ImageName) || ((HookDllData.EnableProtectProcessId == TRUE) && (HandleToULong(pInfo->UniqueProcessId) == HookDllData.dwProtectedProcessId)))
{
if (pInfo->ImageName.Buffer)
ZeroMemory(pInfo->ImageName.Buffer, pInfo->ImageName.Length);
if (pInfo->NextEntryOffset == 0) //last element
{
pPrev->NextEntryOffset = 0;
}
else
{
pPrev->NextEntryOffset += pInfo->NextEntryOffset;
}
}
else
{
pPrev = pInfo;
}
if (pInfo->NextEntryOffset == 0)
{
break;
}
else
{
pInfo = (PSYSTEM_PROCESS_INFORMATION)((DWORD_PTR)pInfo + pInfo->NextEntryOffset);
}
}
}
NTSTATUS NTAPI HookedNtResumeThread(HANDLE ThreadHandle, PULONG PreviousSuspendCount)
{
DWORD dwProcessId = GetProcessIdByThreadHandle(ThreadHandle);
if (dwProcessId != HandleToULong(NtCurrentTeb()->ClientId.UniqueProcess)) //malware starts the thread of another process
{
DumpMalware(dwProcessId);
TerminateProcessByProcessId(dwProcessId); //terminate it
DbgPrint((PCH)"Malware called ResumeThread");
DbgBreakPoint();
return STATUS_SUCCESS;
}
else
{
return HookDllData.dNtResumeThread(ThreadHandle, PreviousSuspendCount);
}
}
HANDLE hNtdllFile = INVALID_HANDLE_VALUE;
HANDLE hNtdllSection = INVALID_HANDLE_VALUE;
NTSTATUS NTAPI HookedNtOpenFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, ULONG ShareAccess, ULONG OpenOptions)
{
NTSTATUS status = HookDllData.dNtOpenFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, ShareAccess, OpenOptions);
if (NT_SUCCESS(status))
{
UNICODE_STRING usNtdll;
RtlInitUnicodeString(&usNtdll, L"\\ntdll.dll");
if (RtlUnicodeStringContains(ObjectAttributes->ObjectName, &usNtdll, TRUE))
{
hNtdllFile = *FileHandle;
}
}
return status;
}
NTSTATUS NTAPI HookedNtCreateSection(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PLARGE_INTEGER MaximumSize, ULONG SectionPageProtection, ULONG AllocationAttributes, HANDLE FileHandle)
{
if (AllocationAttributes == SEC_IMAGE_NO_EXECUTE && RtlNtMajorVersion() <= 6 && (RtlNtMajorVersion() < 6 || RtlNtMinorVersion() < 2))
{
// Fix for VMProtect. It attempts to use SEC_IMAGE_NO_EXECUTE on OSes that don't support it.
AllocationAttributes = SEC_IMAGE;
}
NTSTATUS status = HookDllData.dNtCreateSection(SectionHandle, DesiredAccess, ObjectAttributes, MaximumSize, SectionPageProtection, AllocationAttributes, FileHandle);
if (NT_SUCCESS(status) && hNtdllFile != INVALID_HANDLE_VALUE && FileHandle == hNtdllFile)
{
hNtdllFile = INVALID_HANDLE_VALUE;
hNtdllSection = *SectionHandle;
}
return status;
}
void DestroyMappedNtApi(const char *szProcName, PVOID hRealNtdll, PVOID pMapping)
{
PVOID ProcedureAddress;
ANSI_STRING ProcedureName;
RtlInitAnsiString(&ProcedureName, (PSTR)szProcName);
if (NT_SUCCESS(LdrGetProcedureAddress(hRealNtdll, &ProcedureName, 0, &ProcedureAddress)))
{
SIZE_T delta = (ULONG_PTR)ProcedureAddress - (ULONG_PTR)hRealNtdll;
PUCHAR pMappedApi = (PUCHAR)pMapping + delta;
#ifdef _WIN64
if (*(PDWORD)pMappedApi != 0xB8D18B4C) // mov r10,rcx; mov eax, callNr
return;
PVOID ProtAddress = pMappedApi;
SIZE_T RegionSize = 5;
ULONG OldProtect;
if (NT_SUCCESS(NtProtectVirtualMemory(NtCurrentProcess, &ProtAddress, &RegionSize, PAGE_READWRITE, &OldProtect)))
{
*(PWORD)pMappedApi = 0x0B0F; // UD2
*(PWORD)(pMappedApi + 3) = 0x0B0F; // UD2
NtProtectVirtualMemory(NtCurrentProcess, &ProtAddress, &RegionSize, OldProtect, &OldProtect);
}
#else
if (*pMappedApi != 0xB8) // mov eax, callNr
return;
PVOID ProtAddress = pMappedApi;
SIZE_T RegionSize = 2;
ULONG OldProtect;
if (NT_SUCCESS(NtProtectVirtualMemory(NtCurrentProcess, &ProtAddress, &RegionSize, PAGE_READWRITE, &OldProtect)))
{
*(PWORD)pMappedApi = 0x0B0F; // UD2
NtProtectVirtualMemory(NtCurrentProcess, &ProtAddress, &RegionSize, OldProtect, &OldProtect);
}
#endif
}
}
NTSTATUS NTAPI HookedNtMapViewOfSection(HANDLE SectionHandle, HANDLE ProcessHandle, PVOID* BaseAddress, ULONG_PTR ZeroBits, SIZE_T CommitSize, PLARGE_INTEGER SectionOffset, PSIZE_T ViewSize, SECTION_INHERIT InheritDisposition, ULONG AllocationType, ULONG Win32Protect)
{
NTSTATUS status = HookDllData.dNtMapViewOfSection(SectionHandle, ProcessHandle, BaseAddress, ZeroBits, CommitSize, SectionOffset, ViewSize, InheritDisposition, AllocationType, Win32Protect);
if (NT_SUCCESS(status) && ProcessHandle == NtCurrentProcess && hNtdllSection != INVALID_HANDLE_VALUE && SectionHandle == hNtdllSection)
{
hNtdllSection = INVALID_HANDLE_VALUE;
ApplyNtdllVersionPatch(ProcessHandle, *BaseAddress);
// Prevent syscall numbers from being extracted from API code.
PVOID hRealNtdll;
UNICODE_STRING usNtdll;
RtlInitUnicodeString(&usNtdll, L"ntdll.dll");
if (NT_SUCCESS(LdrGetDllHandle(NULL, NULL, &usNtdll, &hRealNtdll)))
{
DestroyMappedNtApi("NtSetInformationProcess", hRealNtdll, *BaseAddress); // If VMProtect can syscall this, it will unset the instrumentation callback.
DestroyMappedNtApi("NtQueryInformationProcess", hRealNtdll, *BaseAddress);
DestroyMappedNtApi("NtSetInformationThread", hRealNtdll, *BaseAddress);
DestroyMappedNtApi("NtQueryInformationThread", hRealNtdll, *BaseAddress);
DestroyMappedNtApi("NtQuerySystemInformation", hRealNtdll, *BaseAddress);
DestroyMappedNtApi("NtQueryVirtualMemory", hRealNtdll, *BaseAddress);
}
}
return status;
}