/**
Anti-Debugging in NtQueryObject - ObjectAllTypesInformation
Copyright (C) 2018 soxfmr@foxmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.  If not, see .
*/
#include 
#include 
#define DEBUG_OBJECT_NAME L"DebugObject"
typedef struct _UNICODE_STRING {
	USHORT Length;
	USHORT MaximumLength;
	PWSTR Buffer;
} UNICODE_STRING;
typedef enum _OBJECT_INFORMATION_CLASS {
    ObjectBasicInformation = 0,
    ObjectNameInformation = 1,
    ObjectTypeInformation = 2,
    ObjectAllTypesInformation = 3,
    ObjectHandleInformation = 4
} OBJECT_INFORMATION_CLASS;
/**
* The following structure contains partial members of the entire data structure
* As the public documentation shown, the TotalNumberOfObjects should follows by
* TotalNumberOfHandles instead of in reverseing order (Represent in code snippet of book <<逆向工程核心原理>>)
* For the completely structure information: https://doxygen.reactos.org/d6/d07/struct__OBJECT__TYPE__INFORMATION.html
*/
typedef struct _OBJECT_TYPE_INFORMATION {
	UNICODE_STRING TypeName;
	ULONG TotalNumberOfObjects;
	ULONG TotalNumberOfHandles;
} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
typedef struct _OBJECT_ALL_TYPES_INFORMATION {
	ULONG NumberOfObjectTypes;
	OBJECT_TYPE_INFORMATION ObjectTypeInformation[1];
} OBJECT_ALL_TYPES_INFORMATION, *POBJECT_ALL_TYPES_INFORMATION;
typedef NTSTATUS (NTAPI *PNTQUERYOBJECT)(
	HANDLE Handle,
	OBJECT_INFORMATION_CLASS ObjectInformationClass,
	PVOID ObjectInformation,
	ULONG ObjectInformationLength,
	PULONG ReturnLength
);
VOID WriteLog(TCHAR* lpMessage)
{
	HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	WriteConsole(hOutput, lpMessage, _tcslen(lpMessage), NULL, NULL);
}
/**
* If you were compile the program in Debug mode, you must disable the RTC runtime check option (/RTCu)
* Otherwise the RTC runtime function will be call at the end of this function and overwrite the return value of `eax`
*/
BOOL NtQueryObjectDebuggerDetect()
{
	ULONG i = 0;
	BOOL bRet = FALSE;
	PNTQUERYOBJECT pNtQueryObject = NULL;
	POBJECT_TYPE_INFORMATION pObjectTypeInfo = NULL;
	POBJECT_ALL_TYPES_INFORMATION pObjectAllTypesInfo = NULL;
	
	UCHAR *pNextTypeLocation = NULL;
	UCHAR *pObjectTypeLocation = NULL;
	
	ULONG dwObjAllTypesLen = 0;
	PVOID pObjectAllTypesBuffer = NULL;
	pNtQueryObject = (PNTQUERYOBJECT) GetProcAddress(GetModuleHandle(L"ntdll.dll"), 
		"NtQueryObject");
	if (pNtQueryObject == NULL)
	{
		WriteLog(L"Cannot obtain the address of NtQueryObject\n");
		return bRet;
	}
	pNtQueryObject(NULL, ObjectAllTypesInformation, &dwObjAllTypesLen, sizeof(dwObjAllTypesLen), &dwObjAllTypesLen);
	pObjectAllTypesBuffer = VirtualAlloc(NULL, dwObjAllTypesLen, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 
	if (0 != pNtQueryObject((HANDLE) -1, ObjectAllTypesInformation, pObjectAllTypesBuffer, dwObjAllTypesLen, NULL))
	{
		WriteLog(L"Cannot obtain the object of all types info\n");
		goto release;
	}
	pObjectAllTypesInfo = (POBJECT_ALL_TYPES_INFORMATION) pObjectAllTypesBuffer;
	pObjectTypeLocation = (UCHAR*) pObjectAllTypesInfo->ObjectTypeInformation;
	for (i = 0; i < pObjectAllTypesInfo->NumberOfObjectTypes; i++)
	{
		pObjectTypeInfo = (POBJECT_TYPE_INFORMATION) pObjectTypeLocation;
		if (wcscmp(DEBUG_OBJECT_NAME, pObjectTypeInfo->TypeName.Buffer) == 0)
		{
			bRet = pObjectTypeInfo->TotalNumberOfObjects > 0 ? TRUE : FALSE;
			break;
		}
		
		// This make me confuse a bit, but seems the Buffer is locate at the end
		// of OBJECT_TYPE_INFORMATION object (I guess :) )
		pObjectTypeLocation = (UCHAR*) pObjectTypeInfo->TypeName.Buffer;
		pObjectTypeLocation += pObjectTypeInfo->TypeName.MaximumLength;
		// Address align, 0xFFFFFFFC on x86, and 0xFFFFFFFFFFFFFFF8 for AMD64
		pNextTypeLocation = (UCHAR*) ((ULONG) pObjectTypeLocation & -sizeof(void*));
		// If the alignment operation reduce the address which is lesser than 
		// the desire size of the buffer, then we should add the alignment size to it
		if (pNextTypeLocation < pObjectTypeLocation)
			pNextTypeLocation += sizeof(ULONG);
		pObjectTypeLocation = pNextTypeLocation;
	}
release:
	
	if (pObjectAllTypesBuffer != NULL)
	{
		VirtualFree(pObjectAllTypesBuffer, 0, MEM_RELEASE);
	}
	return bRet;
}
int main()
{
	if (NtQueryObjectDebuggerDetect())
	{
		WriteLog(L"[-] Debugger Detected!\n");
	} else 
	{
		WriteLog(L"[+] Pass!\n");
	}
	
	system("pause");
	return 0;
}