TitanHide/TitanHideTest/main.cpp
2026-07-16 23:57:05 +02:00

539 lines
20 KiB
C++

#include <windows.h>
#include <stdio.h>
#include <Subauth.h>
#include "..\TitanHide\TitanHide.h"
//Thanks to:
//http://www.codeproject.com/Articles/30815/An-Anti-Reverse-Engineering-Guide
//http://pferrie.host22.com/papers/antidebug.pdf
//http://resources.infosecinstitute.com/anti-debugging-detecting-system-debugger/
bool CheckProcessDebugFlags()
{
// Much easier in ASM but C/C++ looks so much better
typedef int (WINAPI * pNtQueryInformationProcess)
(HANDLE, UINT, PVOID, ULONG, PULONG);
DWORD NoDebugInherit = 0;
int Status;
// Get NtQueryInformationProcess
pNtQueryInformationProcess NtQIP = (pNtQueryInformationProcess)
GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")),
"NtQueryInformationProcess");
Status = NtQIP(GetCurrentProcess(),
0x1f, // ProcessDebugFlags
&NoDebugInherit, sizeof(NoDebugInherit), NULL);
if(Status != 0x00000000)
{
printf("NtQueryInformationProcess failed with %X\n", Status);
return false;
}
if(NoDebugInherit == FALSE)
return true;
else
return false;
}
bool CheckProcessDebugPort()
{
// Much easier in ASM but C/C++ looks so much better
typedef int (WINAPI * pNtQueryInformationProcess)
(HANDLE, UINT, PVOID, ULONG, PULONG);
DWORD_PTR DebugPort = 0;
ULONG ReturnSize = 0;
int Status;
// Get NtQueryInformationProcess
pNtQueryInformationProcess NtQIP = (pNtQueryInformationProcess)
GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")),
"NtQueryInformationProcess");
Status = NtQIP(GetCurrentProcess(),
0x7, // ProcessDebugPort
&DebugPort, sizeof(DebugPort), &ReturnSize);
if(Status != 0x00000000)
{
printf("NtQueryInformationProcess failed with %X, %u\n", Status, ReturnSize);
return false;
}
if(DebugPort)
return true;
else
return false;
}
bool CheckProcessDebugObjectHandle()
{
// Much easier in ASM but C/C++ looks so much better
typedef int (WINAPI * pNtQueryInformationProcess)
(HANDLE, UINT, PVOID, ULONG, PULONG);
DWORD_PTR DebugHandle = 0;
int Status;
ULONG ReturnSize = 0;
// Get NtQueryInformationProcess
pNtQueryInformationProcess NtQIP = (pNtQueryInformationProcess)
GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")),
"NtQueryInformationProcess");
Status = NtQIP(GetCurrentProcess(),
30, // ProcessDebugHandle
&DebugHandle, sizeof(DebugHandle), &ReturnSize);
if(Status != 0x00000000)
{
if(Status != 0xC0000353) //STATUS_PORT_NOT_SET
printf("NtQueryInformationProcess failed with %X, %u\n", Status, ReturnSize);
return false;
}
if(DebugHandle)
{
CloseHandle((HANDLE)DebugHandle);
return true;
}
else
return false;
}
bool HideFromDebugger()
{
typedef NTSTATUS(NTAPI * NT_SET_INFORMATION_THREAD)(
IN HANDLE ThreadHandle,
IN ULONG ThreadInformationClass,
IN PVOID ThreadInformation,
IN ULONG ThreadInformationLength
);
NT_SET_INFORMATION_THREAD NtSIT = (NT_SET_INFORMATION_THREAD)
GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")),
"NtSetInformationThread");
return NT_SUCCESS(NtSIT(GetCurrentThread(),
0x11, //ThreadHideFromDebugger
0,
0));
}
typedef struct _OBJECT_TYPE_INFORMATION
{
UNICODE_STRING TypeName;
ULONG TotalNumberOfObjects;
ULONG TotalNumberOfHandles;
} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
typedef struct _OBJECT_ALL_INFORMATION
{
ULONG NumberOfObjects;
OBJECT_TYPE_INFORMATION ObjectTypeInformation[1];
} OBJECT_ALL_INFORMATION, *POBJECT_ALL_INFORMATION;
typedef enum _OBJECT_INFORMATION_CLASS
{
ObjectBasicInformation,
ObjectNameInformation,
ObjectTypeInformation,
ObjectTypesInformation,
ObjectDataInformation
} OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS;
typedef struct _TEST_OBJECT_ATTRIBUTES
{
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} TEST_OBJECT_ATTRIBUTES, *PTEST_OBJECT_ATTRIBUTES;
bool CheckObjectTypeInformation()
{
typedef NTSTATUS(NTAPI * pNtCreateDebugObject)(PHANDLE, ULONG, PTEST_OBJECT_ATTRIBUTES, ULONG);
typedef NTSTATUS(NTAPI * pNtQueryObject)(HANDLE, OBJECT_INFORMATION_CLASS, PVOID, ULONG, PULONG);
pNtCreateDebugObject NtCDO = (pNtCreateDebugObject)GetProcAddress(
GetModuleHandle(TEXT("ntdll.dll")),
"NtCreateDebugObject");
pNtQueryObject NtQO = (pNtQueryObject)GetProcAddress(
GetModuleHandle(TEXT("ntdll.dll")),
"NtQueryObject");
if(NtCDO == NULL || NtQO == NULL)
return false;
TEST_OBJECT_ATTRIBUTES ObjectAttributes = { sizeof(TEST_OBJECT_ATTRIBUTES) };
HANDLE DebugObjectHandle = NULL;
NTSTATUS Status = NtCDO(&DebugObjectHandle, 0x0008, &ObjectAttributes, 0);
if(!NT_SUCCESS(Status))
return false;
// Preserve every handle owned by the protected process, not merely one.
// The active debugger may independently hold multiple handles to its own
// debug object, all of which should be removed from the reported total.
HANDLE DuplicateHandles[2] = {};
ULONG OwnedHandleCount = 1;
for(HANDLE& DuplicatedHandle : DuplicateHandles)
{
if(DuplicateHandle(
GetCurrentProcess(),
DebugObjectHandle,
GetCurrentProcess(),
&DuplicatedHandle,
0,
FALSE,
DUPLICATE_SAME_ACCESS))
{
OwnedHandleCount++;
}
}
bool Detected = false;
ULONG RequiredLength = 0;
Status = NtQO(DebugObjectHandle, ObjectTypeInformation, NULL, 0, &RequiredLength);
if(Status != (NTSTATUS)0xC0000004L || RequiredLength < sizeof(OBJECT_TYPE_INFORMATION)) // STATUS_INFO_LENGTH_MISMATCH
{
Detected = true;
}
else
{
OBJECT_TYPE_INFORMATION* TypeInformation = (OBJECT_TYPE_INFORMATION*)HeapAlloc(
GetProcessHeap(), HEAP_ZERO_MEMORY, RequiredLength);
if(TypeInformation == NULL)
{
Detected = true;
}
else
{
Status = NtQO(DebugObjectHandle, ObjectTypeInformation, TypeInformation, RequiredLength, NULL);
if(!NT_SUCCESS(Status) ||
TypeInformation->TotalNumberOfObjects == 0 ||
TypeInformation->TotalNumberOfHandles < OwnedHandleCount)
{
Detected = true;
}
// VMProtect 3.9.5+ overlaps ReturnLength with TypeName.Buffer.
Status = NtQO(DebugObjectHandle,
ObjectTypeInformation,
TypeInformation,
RequiredLength,
(PULONG)&TypeInformation->TypeName.Buffer);
if(!NT_SUCCESS(Status) ||
*(PULONG)&TypeInformation->TypeName.Buffer != RequiredLength ||
TypeInformation->TotalNumberOfObjects == 0 ||
TypeInformation->TotalNumberOfHandles < OwnedHandleCount)
{
Detected = true;
}
HeapFree(GetProcessHeap(), 0, TypeInformation);
}
}
for(HANDLE DuplicatedHandle : DuplicateHandles)
{
if(DuplicatedHandle != NULL)
CloseHandle(DuplicatedHandle);
}
CloseHandle(DebugObjectHandle);
return Detected;
}
// ObjectListCheck uses NtQueryObject to check the environments
// list of objects and more specifically for the number of
// debug objects. This function can cause an exception (although rarely)
// so either surround it in a try catch or __try __except block
// but that shouldn't happen unless one tinkers with the function
bool CheckObjectList()
{
__try
{
typedef NTSTATUS(NTAPI * pNtQueryObject)(HANDLE, OBJECT_INFORMATION_CLASS, PVOID, ULONG, PULONG);
POBJECT_ALL_INFORMATION pObjectAllInfo = NULL;
void* pMemory = NULL;
NTSTATUS Status;
ULONG Size = 0;
// Get NtQueryObject
pNtQueryObject NtQO = (pNtQueryObject)GetProcAddress(
GetModuleHandle(TEXT("ntdll.dll")),
"NtQueryObject");
// Get the size of the list
Status = NtQO(NULL, ObjectTypesInformation, //ObjectAllTypesInformation
&Size, sizeof(ULONG), &Size);
// Allocate room for the list
pMemory = VirtualAlloc(NULL, SIZE_T(Size), MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE);
if(pMemory == NULL)
return false;
// Now we can actually retrieve the list
Status = NtQO(GetCurrentProcess(), ObjectTypesInformation, pMemory, Size, NULL);
// Status != STATUS_SUCCESS
if(Status != STATUS_SUCCESS)
{
VirtualFree(pMemory, 0, MEM_RELEASE);
return false;
}
// We have the information we need
pObjectAllInfo = (POBJECT_ALL_INFORMATION)pMemory;
unsigned char* pObjInfoLocation = (unsigned char*)pObjectAllInfo->ObjectTypeInformation;
ULONG NumObjects = pObjectAllInfo->NumberOfObjects;
for(UINT i = 0; i < NumObjects; i++)
{
POBJECT_TYPE_INFORMATION pObjectTypeInfo = (POBJECT_TYPE_INFORMATION)pObjInfoLocation;
// The debug object will always be present
wchar_t DebugObject[] = L"DebugObject";
auto DebugObjectLength = wcslen(DebugObject) * sizeof(wchar_t);
if(pObjectTypeInfo->TypeName.Length == DebugObjectLength && !memcmp(pObjectTypeInfo->TypeName.Buffer, DebugObject, DebugObjectLength)) //UNICODE_STRING is not NULL-terminated (pointed to by deepzero!)
{
// Are there any objects?
if(pObjectTypeInfo->TotalNumberOfObjects || pObjectTypeInfo->TotalNumberOfHandles)
{
VirtualFree(pMemory, 0, MEM_RELEASE);
return true;
}
else
{
VirtualFree(pMemory, 0, MEM_RELEASE);
return false;
}
}
// Get the address of the current entries
// string so we can find the end
pObjInfoLocation = (unsigned char*)pObjectTypeInfo->TypeName.Buffer;
// Add the size
pObjInfoLocation += pObjectTypeInfo->TypeName.MaximumLength;
// Skip the trailing null and alignment bytes
ULONG_PTR tmp = ((ULONG_PTR)pObjInfoLocation) & -(int)sizeof(void*);
// Not pretty but it works
if((ULONG_PTR)tmp != (ULONG_PTR)pObjInfoLocation)
tmp += sizeof(void*);
pObjInfoLocation = ((unsigned char*)tmp);
}
VirtualFree(pMemory, 0, MEM_RELEASE);
return false;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
puts("exception!");
return false;
}
}
enum PROCESSINFOCLASS
{
ProcessBasicInformation = 0, // 0, q: PROCESS_BASIC_INFORMATION, PROCESS_EXTENDED_BASIC_INFORMATION
ProcessQuotaLimits, // qs: QUOTA_LIMITS, QUOTA_LIMITS_EX
ProcessIoCounters, // q: IO_COUNTERS
ProcessVmCounters, // q: VM_COUNTERS, VM_COUNTERS_EX
ProcessTimes, // q: KERNEL_USER_TIMES
ProcessBasePriority, // s: KPRIORITY
ProcessRaisePriority, // s: ULONG
ProcessDebugPort, // q: HANDLE
ProcessExceptionPort, // s: HANDLE
ProcessAccessToken, // s: PROCESS_ACCESS_TOKEN
ProcessLdtInformation, // 10
ProcessLdtSize,
ProcessDefaultHardErrorMode, // qs: ULONG
ProcessIoPortHandlers, // (kernel-mode only)
ProcessPooledUsageAndLimits, // q: POOLED_USAGE_AND_LIMITS
ProcessWorkingSetWatch, // q: PROCESS_WS_WATCH_INFORMATION[]; s: void
ProcessUserModeIOPL,
ProcessEnableAlignmentFaultFixup, // s: BOOLEAN
ProcessPriorityClass, // qs: PROCESS_PRIORITY_CLASS
ProcessWx86Information,
ProcessHandleCount, // 20, q: ULONG, PROCESS_HANDLE_INFORMATION
ProcessAffinityMask, // s: KAFFINITY
ProcessPriorityBoost, // qs: ULONG
ProcessDeviceMap, // qs: PROCESS_DEVICEMAP_INFORMATION, PROCESS_DEVICEMAP_INFORMATION_EX
ProcessSessionInformation, // q: PROCESS_SESSION_INFORMATION
ProcessForegroundInformation, // s: PROCESS_FOREGROUND_BACKGROUND
ProcessWow64Information, // q: ULONG_PTR
ProcessImageFileName, // q: UNICODE_STRING
ProcessLUIDDeviceMapsEnabled, // q: ULONG
ProcessBreakOnTermination, // qs: ULONG
ProcessDebugObjectHandle, // 30, q: HANDLE
ProcessDebugFlags, // qs: ULONG
ProcessHandleTracing, // q: PROCESS_HANDLE_TRACING_QUERY; s: size 0 disables, otherwise enables
ProcessIoPriority, // qs: ULONG
ProcessExecuteFlags, // qs: ULONG
ProcessResourceManagement,
ProcessCookie, // q: ULONG
ProcessImageInformation, // q: SECTION_IMAGE_INFORMATION
ProcessCycleTime, // q: PROCESS_CYCLE_TIME_INFORMATION
ProcessPagePriority, // q: ULONG
ProcessInstrumentationCallback, // 40
ProcessThreadStackAllocation, // s: PROCESS_STACK_ALLOCATION_INFORMATION, PROCESS_STACK_ALLOCATION_INFORMATION_EX
ProcessWorkingSetWatchEx, // q: PROCESS_WS_WATCH_INFORMATION_EX[]
ProcessImageFileNameWin32, // q: UNICODE_STRING
ProcessImageFileMapping, // q: HANDLE (input)
ProcessAffinityUpdateMode, // qs: PROCESS_AFFINITY_UPDATE_MODE
ProcessMemoryAllocationMode, // qs: PROCESS_MEMORY_ALLOCATION_MODE
ProcessGroupInformation, // q: USHORT[]
ProcessTokenVirtualizationEnabled, // s: ULONG
ProcessConsoleHostProcess, // q: ULONG_PTR
ProcessWindowInformation, // 50, q: PROCESS_WINDOW_INFORMATION
ProcessHandleInformation, // q: PROCESS_HANDLE_SNAPSHOT_INFORMATION // since WIN8
ProcessMitigationPolicy, // s: PROCESS_MITIGATION_POLICY_INFORMATION
ProcessDynamicFunctionTableInformation,
ProcessHandleCheckingMode,
ProcessKeepAliveCount, // q: PROCESS_KEEPALIVE_COUNT_INFORMATION
ProcessRevokeFileHandles, // s: PROCESS_REVOKE_FILE_HANDLES_INFORMATION
MaxProcessInfoClass
};
bool NTAPI NtSetInformationProcess(
IN HANDLE ProcessHandle,
IN PROCESSINFOCLASS ProcessInformationClass,
IN PVOID ProcessInformation,
IN ULONG ProcessInformationLength
)
{
typedef NTSTATUS(NTAPI * NTSETINFORMATIONPROCESS)
(
IN HANDLE ProcessHandle,
IN PROCESSINFOCLASS ProcessInformationClass,
IN PVOID ProcessInformation,
IN ULONG ProcessInformationLength
);
static NTSETINFORMATIONPROCESS NtSIP = 0;
if(!NtSIP)
{
NtSIP = (NTSETINFORMATIONPROCESS)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtSetInformationProcess");
if(!NtSIP)
return false;
}
return NT_SUCCESS(NtSIP(ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength));
}
bool CheckSystemDebugger()
{
typedef struct _SYSTEM_KERNEL_DEBUGGER_INFORMATION
{
BOOLEAN DebuggerEnabled;
BOOLEAN DebuggerNotPresent;
} SYSTEM_KERNEL_DEBUGGER_INFORMATION, *PSYSTEM_KERNEL_DEBUGGER_INFORMATION;
enum SYSTEM_INFORMATION_CLASS { SystemKernelDebuggerInformation = 35 };
typedef NTSTATUS(__stdcall * ZW_QUERY_SYSTEM_INFORMATION)(IN SYSTEM_INFORMATION_CLASS SystemInformationClass, IN OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength);
ZW_QUERY_SYSTEM_INFORMATION ZwQuerySystemInformation;
SYSTEM_KERNEL_DEBUGGER_INFORMATION Info;
ZwQuerySystemInformation = (ZW_QUERY_SYSTEM_INFORMATION)GetProcAddress(GetModuleHandleA("ntdll.dll"), "ZwQuerySystemInformation");
if(ZwQuerySystemInformation && NT_SUCCESS(ZwQuerySystemInformation(SystemKernelDebuggerInformation, &Info, sizeof(Info), NULL)))
{
if(Info.DebuggerEnabled || !Info.DebuggerNotPresent)
{
return true;
}
}
return false;
}
bool CheckSystemDebugControl()
{
enum SYSDBG_COMMAND { SysDbgQueryModuleInformation = 0 };
typedef NTSTATUS(__stdcall * ZW_SYSTEM_DEBUG_CONTROL)(IN SYSDBG_COMMAND Command, IN PVOID InputBuffer OPTIONAL, IN ULONG InputBufferLength, OUT PVOID OutputBuffer OPTIONAL, IN ULONG OutputBufferLength, OUT PULONG ReturnLength OPTIONAL);
static const NTSTATUS STATUS_DEBUGGER_INACTIVE = (NTSTATUS)0xC0000354L;
ZW_SYSTEM_DEBUG_CONTROL ZwSystemDebugControl = (ZW_SYSTEM_DEBUG_CONTROL)GetProcAddress(GetModuleHandleA("ntdll.dll"), "ZwSystemDebugControl");
if(ZwSystemDebugControl == NULL)
{
return false;
}
return ZwSystemDebugControl(SysDbgQueryModuleInformation, NULL, 0, NULL, 0, NULL) != STATUS_DEBUGGER_INACTIVE;
}
bool CheckNtClose()
{
__try
{
CloseHandle((HANDLE)0x1234);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
return true;
}
return false;
}
int main(int argc, char* argv[])
{
char title[256] = "";
sprintf_s(title, "pid: %d", (int)GetCurrentProcessId());
SetConsoleTitleA(title);
BOOL IsWow64 = FALSE;
#ifndef _WIN64
IsWow64Process(GetCurrentProcess(), &IsWow64);
#endif
while(1)
{
printf("ProcessDebugFlags: %d\n", CheckProcessDebugFlags());
printf("ProcessDebugPort: %d\n", CheckProcessDebugPort());
printf("ProcessDebugObjectHandle: %d\n", CheckProcessDebugObjectHandle());
printf("NtQueryObject: %d\n", CheckObjectList());
printf("NtQueryObjectType: %d\n", CheckObjectTypeInformation());
printf("CheckSystemDebugger: %d\n", CheckSystemDebugger());
if(!IsWow64) // This syscall is not implemented in wow64.dll
printf("SystemDebugControl: %d\n", CheckSystemDebugControl());
printf("CheckNtClose: %d\n", CheckNtClose());
//printf("ThreadHideFromDebugger: %d\n", HideFromDebugger());
puts("");
if(argc > 1)
break;
Sleep(1000);
}
/*int pid=0;
printf("pid: ");
scanf("%d", &pid);
if(OpenProcess(PROCESS_ALL_ACCESS, false, pid))
puts("OpenProcess OK!");
else
puts("OpenProcess FAILED...");
printf("%u\n", GetCurrentProcessId());*/
/*HANDLE hDevice=CreateFileA("\\\\.\\TitanHide", GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
if(hDevice==INVALID_HANDLE_VALUE)
puts("invalid handle...");
else
{
puts("handle ok!");
printf("pid: ");
ULONG pid=0;
scanf("%d", &pid);
DWORD written=0;
HIDE_INFO HideInfo;
HideInfo.Pid=pid;
HideInfo.Arg=0;
HideInfo.Command=HidePid;
HideInfo.Type=HideProcessDebugFlags|HideProcessDebugPort|HideProcessDebugObjectHandle|HideDebugObject;
WriteFile(hDevice, &HideInfo, sizeof(HIDE_INFO), &written, 0);
CloseHandle(hDevice);
}
system("pause");*/
return 0;
}