Windows C++ / NtQueryObject
Author | External |
Platform | Windows |
Language | C++ |
Technique | NtQueryObject |
Description:
Original source code available here: https://gist.github.com/soxfmr/16c495d6e4ad99e9e46f5bfd558d152f
Code
/**
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 <https://www.gnu.org/licenses/>.
*/
#include <tchar.h>
#include <Windows.h>
#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;
}
Created
June 22, 2022
Last Revised
April 22, 2024