Search
⌨️

[Win] Change DbgkDebugObjectType

Date
Select
Tags

1. Summary

해당 포스팅은 DbgkDebugObjectType의 값을 직접 생성한 ObjectType으로 변조하여 일반적인 디버깅을 막는 Anti-Debug 기법 또는 Anti-Debug기법을 Bypass하기 위해서 입니다.

2. DbgkDebugObjectType

DbgkDebugObjectType은 ntoskrnl.exe의 전역 변수로써 DebugObject Structure을 가르키는 포인터값 입니다.
해당 값은 NtCreateDebugObject, NtDebugActiveProcess등 DebugObject를 생성하거나 참조할 때 사용됩니다.
아래는 DbgkDebugObjectType과 직접 생성한 Anti-Debug 용 ObjectType과의 비교입니다.
nt!DbgBreakPointWithStatus: fffff803`3bffedc0 cc int 3 3: kd> dt _object_type poi(dbgkDebugObjectTYpe) ntdll!_OBJECT_TYPE +0x000 TypeList : _LIST_ENTRY [ 0xffffb98c`624c7e80 - 0xffffb98c`624c7e80 ] +0x010 Name : _UNICODE_STRING "DebugObject" +0x020 DefaultObject : (null) +0x028 Index : 0xf '' +0x02c TotalNumberOfObjects : 0 +0x030 TotalNumberOfHandles : 0 +0x034 HighWaterNumberOfObjects : 0 +0x038 HighWaterNumberOfHandles : 0 +0x040 TypeInfo : _OBJECT_TYPE_INITIALIZER +0x0b8 TypeLock : _EX_PUSH_LOCK +0x0c0 Key : 0x75626544 +0x0c8 CallbackList : _LIST_ENTRY [ 0xffffb98c`624c7f48 - 0xffffb98c`624c7f48 ] 3: kd> dx -id 0,0,ffffb98c62461040 -r1 (*((ntdll!_OBJECT_TYPE_INITIALIZER *)0xffffb98c624c7ec0)) (*((ntdll!_OBJECT_TYPE_INITIALIZER *)0xffffb98c624c7ec0)) [Type: _OBJECT_TYPE_INITIALIZER] [+0x000] Length : 0x78 [Type: unsigned short] [+0x002] ObjectTypeFlags : 0x8 [Type: unsigned short] [+0x002 ( 0: 0)] CaseInsensitive : 0x0 [Type: unsigned char] [+0x002 ( 1: 1)] UnnamedObjectsOnly : 0x0 [Type: unsigned char] [+0x002 ( 2: 2)] UseDefaultObject : 0x0 [Type: unsigned char] [+0x002 ( 3: 3)] SecurityRequired : 0x1 [Type: unsigned char] [+0x002 ( 4: 4)] MaintainHandleCount : 0x0 [Type: unsigned char] [+0x002 ( 5: 5)] MaintainTypeList : 0x0 [Type: unsigned char] [+0x002 ( 6: 6)] SupportsObjectCallbacks : 0x0 [Type: unsigned char] [+0x002 ( 7: 7)] CacheAligned : 0x0 [Type: unsigned char] [+0x003 ( 0: 0)] UseExtendedParameters : 0x0 [Type: unsigned char] [+0x003 ( 7: 1)] Reserved : 0x0 [Type: unsigned char] [+0x004] ObjectTypeCode : 0x0 [Type: unsigned long] [+0x008] InvalidAttributes : 0x0 [Type: unsigned long] [+0x00c] GenericMapping [Type: _GENERIC_MAPPING] [+0x01c] ValidAccessMask : 0x1f000f [Type: unsigned long] [+0x020] RetainAccess : 0x0 [Type: unsigned long] [+0x024] PoolType : NonPagedPoolNx (512) [Type: _POOL_TYPE] [+0x028] DefaultPagedPoolCharge : 0x0 [Type: unsigned long] [+0x02c] DefaultNonPagedPoolCharge : 0x58 [Type: unsigned long] [+0x030] DumpProcedure : 0x0 [Type: void (__cdecl*)(void *,_OBJECT_DUMP_CONTROL *)] [+0x038] OpenProcedure : 0x0 [Type: long (__cdecl*)(_OB_OPEN_REASON,char,_EPROCESS *,void *,unsigned long *,unsigned long)] [+0x040] CloseProcedure : 0xfffff8033c481de0 [Type: void (__cdecl*)(_EPROCESS *,void *,unsigned __int64,unsigned __int64)] [+0x048] DeleteProcedure : 0xfffff8033c3136c0 [Type: void (__cdecl*)(void *)] [+0x050] ParseProcedure : 0x0 [Type: long (__cdecl*)(void *,void *,_ACCESS_STATE *,char,unsigned long,_UNICODE_STRING *,_UNICODE_STRING *,void *,_SECURITY_QUALITY_OF_SERVICE *,void * *)] [+0x050] ParseProcedureEx : 0x0 [Type: long (__cdecl*)(void *,void *,_ACCESS_STATE *,char,unsigned long,_UNICODE_STRING *,_UNICODE_STRING *,void *,_SECURITY_QUALITY_OF_SERVICE *,_OB_EXTENDED_PARSE_PARAMETERS *,void * *)] [+0x058] SecurityProcedure : 0xfffff8033c2691a0 [Type: long (__cdecl*)(void *,_SECURITY_OPERATION_CODE,unsigned long *,void *,unsigned long *,void * *,_POOL_TYPE,_GENERIC_MAPPING *,char)] [+0x060] QueryNameProcedure : 0x0 [Type: long (__cdecl*)(void *,unsigned char,_OBJECT_NAME_INFORMATION *,unsigned long,unsigned long *,char)] [+0x068] OkayToCloseProcedure : 0x0 [Type: unsigned char (__cdecl*)(_EPROCESS *,void *,void *,char)] [+0x070] WaitObjectFlagMask : 0x0 [Type: unsigned long] [+0x074] WaitObjectFlagOffset : 0x0 [Type: unsigned short] [+0x076] WaitObjectPointerOffset : 0x0 [Type: unsigned short]
C
복사
1: kd> dt _object_type poi(FFFFF8033A0342E0) ntdll!_OBJECT_TYPE +0x000 TypeList : _LIST_ENTRY [ 0xffffb98c`6249b0c0 - 0xffffb98c`6249b0c0 ] +0x010 Name : _UNICODE_STRING "Holiam" +0x020 DefaultObject : (null) +0x028 Index : 0x45 'E' +0x02c TotalNumberOfObjects : 0 +0x030 TotalNumberOfHandles : 0 +0x034 HighWaterNumberOfObjects : 0 +0x038 HighWaterNumberOfHandles : 0 +0x040 TypeInfo : _OBJECT_TYPE_INITIALIZER +0x0b8 TypeLock : _EX_PUSH_LOCK +0x0c0 Key : 0x696c6f48 +0x0c8 CallbackList : _LIST_ENTRY [ 0xffffb98c`6249b188 - 0xffffb98c`6249b188 ] 1: kd> dx -id 0,0,ffffb98c62461040 -r1 (*((ntdll!_OBJECT_TYPE_INITIALIZER *)0xffffb98c6249b100)) (*((ntdll!_OBJECT_TYPE_INITIALIZER *)0xffffb98c6249b100)) [Type: _OBJECT_TYPE_INITIALIZER] [+0x000] Length : 0x78 [Type: unsigned short] [+0x002] ObjectTypeFlags : 0x0 [Type: unsigned short] [+0x002 ( 0: 0)] CaseInsensitive : 0x0 [Type: unsigned char] [+0x002 ( 1: 1)] UnnamedObjectsOnly : 0x0 [Type: unsigned char] [+0x002 ( 2: 2)] UseDefaultObject : 0x0 [Type: unsigned char] [+0x002 ( 3: 3)] SecurityRequired : 0x0 [Type: unsigned char] [+0x002 ( 4: 4)] MaintainHandleCount : 0x0 [Type: unsigned char] [+0x002 ( 5: 5)] MaintainTypeList : 0x0 [Type: unsigned char] [+0x002 ( 6: 6)] SupportsObjectCallbacks : 0x0 [Type: unsigned char] [+0x002 ( 7: 7)] CacheAligned : 0x0 [Type: unsigned char] [+0x003 ( 0: 0)] UseExtendedParameters : 0x0 [Type: unsigned char] [+0x003 ( 7: 1)] Reserved : 0x0 [Type: unsigned char] [+0x004] ObjectTypeCode : 0x0 [Type: unsigned long] [+0x008] InvalidAttributes : 0x0 [Type: unsigned long] [+0x00c] GenericMapping [Type: _GENERIC_MAPPING] [+0x01c] ValidAccessMask : 0x0 [Type: unsigned long] [+0x020] RetainAccess : 0x0 [Type: unsigned long] [+0x024] PoolType : NonPagedPool | NonPagedPoolExecute | NonPagedPoolBase (0) [Type: _POOL_TYPE] [+0x028] DefaultPagedPoolCharge : 0x0 [Type: unsigned long] [+0x02c] DefaultNonPagedPoolCharge : 0x58 [Type: unsigned long] [+0x030] DumpProcedure : 0x0 [Type: void (__cdecl*)(void *,_OBJECT_DUMP_CONTROL *)] [+0x038] OpenProcedure : 0x0 [Type: long (__cdecl*)(_OB_OPEN_REASON,char,_EPROCESS *,void *,unsigned long *,unsigned long)] [+0x040] CloseProcedure : 0x0 [Type: void (__cdecl*)(_EPROCESS *,void *,unsigned __int64,unsigned __int64)] [+0x048] DeleteProcedure : 0x0 [Type: void (__cdecl*)(void *)] [+0x050] ParseProcedure : 0x0 [Type: long (__cdecl*)(void *,void *,_ACCESS_STATE *,char,unsigned long,_UNICODE_STRING *,_UNICODE_STRING *,void *,_SECURITY_QUALITY_OF_SERVICE *,void * *)] [+0x050] ParseProcedureEx : 0x0 [Type: long (__cdecl*)(void *,void *,_ACCESS_STATE *,char,unsigned long,_UNICODE_STRING *,_UNICODE_STRING *,void *,_SECURITY_QUALITY_OF_SERVICE *,_OB_EXTENDED_PARSE_PARAMETERS *,void * *)] [+0x058] SecurityProcedure : 0xfffff8033c2691a0 [Type: long (__cdecl*)(void *,_SECURITY_OPERATION_CODE,unsigned long *,void *,unsigned long *,void * *,_POOL_TYPE,_GENERIC_MAPPING *,char)] [+0x060] QueryNameProcedure : 0x0 [Type: long (__cdecl*)(void *,unsigned char,_OBJECT_NAME_INFORMATION *,unsigned long,unsigned long *,char)] [+0x068] OkayToCloseProcedure : 0x0 [Type: unsigned char (__cdecl*)(_EPROCESS *,void *,void *,char)] [+0x070] WaitObjectFlagMask : 0x0 [Type: unsigned long] [+0x074] WaitObjectFlagOffset : 0x0 [Type: unsigned short] [+0x076] WaitObjectPointerOffset : 0x0 [Type: unsigned short]
C
복사
당장 눈에 보이는 차이점으로는ObjectTypeFlag, ValidAccessMask, CloseProcedure, DeleteProcedure 가 있습니다.
1.
ObjectTypeFlag
DebugObject (0x08) - Set SecurityRequired BitFlag
Holiam(0x00)
2.
ValidAccessMask
DebugObject (0x1f000f) - DEBUG_ALL_ACEESS
Holiam (0x00)
3.
Close and Delete Procedure
DebugObject Close Procedure (0xfffff8033c481de0) - DbgkpCloseObject Function
1: kd> u 0xfffff8033c481de0 nt!DbgkpCloseObject: fffff803`3c481de0 4983f901 cmp r9,1 fffff803`3c481de4 0f870f010000 ja nt!DbgkpCloseObject+0x119 (fffff803`3c481ef9) fffff803`3c481dea 488bc4 mov rax,rsp fffff803`3c481ded 48895808 mov qword ptr [rax+8],rbx fffff803`3c481df1 48896810 mov qword ptr [rax+10h],rbp fffff803`3c481df5 48897018 mov qword ptr [rax+18h],rsi fffff803`3c481df9 48897820 mov qword ptr [rax+20h],rdi fffff803`3c481dfd 4156 push r14
C
복사
DebugObject DeleteProcedure (0xfffff8033c3136c0) - AlpcConnectionCleanupProcedure
nt!AlpcConnectionCleanupProcedure: fffff803`3c3136c0 c20000 ret 0 fffff803`3c3136c3 cc int 3 fffff803`3c3136c4 cc int 3 fffff803`3c3136c5 cc int 3 fffff803`3c3136c6 cc int 3 fffff803`3c3136c7 cc int 3 fffff803`3c3136c8 cc int 3 fffff803`3c3136c9 cc int 3
C
복사
Holiam (0x00)

3. POC

사용한 환경은 아래와 같습니다.
Windows 10 19043.1110 Visual Studio 2019 Comunity

3.1 Anti-Debug

Anti-Debug 용도의 Object 생성 소스코드는 아래와 같습니다.
#include "driver.h" NTSTATUS CreateObjectType() { OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; NTSTATUS ntStatus = STATUS_SUCCESS; UNICODE_STRING Name; RtlZeroMemory(&ObjectTypeInitializer, sizeof(OBJECT_TYPE_INITIALIZER)); // Initalize ObjectTypeInitializer ObjectTypeInitializer.Length = sizeof(OBJECT_TYPE_INITIALIZER); // Set ObjectTypeInitalizer Length RtlInitUnicodeString(&Name, L"Holiam"); // Set Name ntStatus = ObCreateObjectType(&Name, &ObjectTypeInitializer, 0, &pObjectType); DbgPrintEx(DPFLTR_ACPI_ID, 0, "[+] Object Address: %p\n", &pObjectType); if (ntStatus != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_ACPI_ID, 0, "[!] ObCreateObjectType Error\n"); DbgPrintEx(DPFLTR_ACPI_ID, 0, "[!] Error NTSTATUS : %x \n", ntStatus); } return ntStatus; } NTSTATUS DriverEntry( IN PDRIVER_OBJECT pDriver, IN PUNICODE_STRING pRegPath ) { UNREFERENCED_PARAMETER(pDriver); UNREFERENCED_PARAMETER(pRegPath); DbgPrintEx(DPFLTR_ACPI_ID, 0, "[+] Load Driver\n"); pDriver->DriverUnload = UnloadDriver; NTSTATUS ret = STATUS_SUCCESS; UINT64 qwDbgObjectPatternAddress; //find ntoskrnl.exe addr pvNtAddress = FindAddressinKernel(pDriver); //find the DbgkDebugObjectType pattern qwDbgObjectPatternAddress = (UINT64)FindPatternInSection(pvNtAddress, (char*)"PAGE", (char*)"\x48\x8b\x05\x00\x00\x00\x00\x41\xb9\x00\x00\x00\x02", (char*)"xxx????xxxxxx"); if (qwDbgObjectPatternAddress == 0) DbgPrintEx(DPFLTR_ACPI_ID, 0, "[!] Can't find KernelAddress \n"); qwDbgObjectTypeAddress = (UINT64)ResolveRelativeAddress((PVOID)qwDbgObjectPatternAddress, 3, 7); //backup original "DebugObject" memmove(&pDbgObjType, (PVOID)qwDbgObjectTypeAddress, 8); if(&pDbgObjType == NULL) DbgPrintEx(DPFLTR_ACPI_ID, 0, "[!] Can't Copy DbgkDebugObjectType \n"); //create object type ret = CreateObjectType(); if (ret != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_ACPI_ID, 0, "[!] Failed a Registration\n"); DbgPrintEx(DPFLTR_ACPI_ID, 0, "[!] Error NTSTATUS : %x \n", ret); } //Change DbgkDebugObjectType memmove((PVOID)qwDbgObjectTypeAddress, pObjectType, 8); DbgPrintEx(DPFLTR_ACPI_ID, 0, "[+] Changed done \n"); return STATUS_SUCCESS; }
C
복사
생성하는 Object의 ValidAccessMask가 0인 경우 디버깅이 불가능합니다.
해당 방식이 아니더라도 기존의 DebugObject ValidAccessMask를 0으로 변조할 경우 동일하게 디버깅이 불가합니다.
개인적으로 테스트 한 결과 ObjectType을 생성하게 되면 정상적인 방법으로 삭제가 불가능하므로 기존 DebugObject의 ValidAccessMask를 변조하는 것이 더 좋은 방법으로 보입니다.

3.2 Anti-Anti-Debug

Anti-Anti-Debug의 경우 Object의 ValidAccessMaskDEBUG_ALL_ACCESS (0x1f000f)로 생성하여 DbgkDebugObjectType을 변조할 경우 정상적으로 디버깅이 가능합니다.
아래는 일부 소스코드입니다.
#include "driver.h" NTSTATUS CreateObjectType() { OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; NTSTATUS ntStatus = STATUS_SUCCESS; UNICODE_STRING Name; RtlZeroMemory(&ObjectTypeInitializer, sizeof(OBJECT_TYPE_INITIALIZER)); // Initalize ObjectTypeInitializer ObjectTypeInitializer.Length = sizeof(OBJECT_TYPE_INITIALIZER); // Set ObjectTypeInitalizer Length ObjectTypeInitializer.ValidAccessMask = DEBUG_ALL_ACCESS; ObjectTypeInitializer.CloseProcedure = pDbgObjType->TypeInfo.CloseProcedure; ObjectTypeInitializer.DeleteProcedure = pDbgObjType->TypeInfo.DeleteProcedure; RtlInitUnicodeString(&Name, L"Holiam"); // Set Name ntStatus = ObCreateObjectType(&Name, &ObjectTypeInitializer, 0, &pObjectType); DbgPrintEx(DPFLTR_ACPI_ID, 0, "[+] Object Address: %p\n", &pObjectType); if (ntStatus != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_ACPI_ID, 0, "[!] ObCreateObjectType Error\n"); DbgPrintEx(DPFLTR_ACPI_ID, 0, "[!] Error NTSTATUS : %x \n", ntStatus); } return ntStatus; } NTSTATUS DriverEntry( IN PDRIVER_OBJECT pDriver, IN PUNICODE_STRING pRegPath ) { UNREFERENCED_PARAMETER(pDriver); UNREFERENCED_PARAMETER(pRegPath); DbgPrintEx(DPFLTR_ACPI_ID, 0, "[+] Load Driver\n"); pDriver->DriverUnload = UnloadDriver; NTSTATUS ret = STATUS_SUCCESS; UINT64 qwDbgObjectPatternAddress; //find ntoskrnl.exe addr pvNtAddress = FindAddressinKernel(pDriver); //find the DbgkDebugObjectType pattern qwDbgObjectPatternAddress = (UINT64)FindPatternInSection(pvNtAddress, (char*)"PAGE", (char*)"\x48\x8b\x05\x00\x00\x00\x00\x41\xb9\x00\x00\x00\x02", (char*)"xxx????xxxxxx"); if (qwDbgObjectPatternAddress == 0) DbgPrintEx(DPFLTR_ACPI_ID, 0, "[!] Can't find KernelAddress \n"); qwDbgObjectTypeAddress = (UINT64)ResolveRelativeAddress((PVOID)qwDbgObjectPatternAddress, 3, 7); //backup original "DebugObject" memmove(&pDbgObjType, (PVOID)qwDbgObjectTypeAddress, 8); if(&pDbgObjType == NULL) DbgPrintEx(DPFLTR_ACPI_ID, 0, "[!] Can't Copy DbgkDebugObjectType \n"); //create object type ret = CreateObjectType(); if (ret != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_ACPI_ID, 0, "[!] Failed a Registration\n"); DbgPrintEx(DPFLTR_ACPI_ID, 0, "[!] Error NTSTATUS : %x \n", ret); } //Change DbgkDebugObjectType memmove((PVOID)qwDbgObjectTypeAddress, pObjectType, 8); DbgPrintEx(DPFLTR_ACPI_ID, 0, "[+] Changed done \n"); return STATUS_SUCCESS; }
C
복사
드라이버를 로드 한 후 DbgkDebugObjectType을 확인 해 보겠습니다.
0: kd> dps DbgkDebugObjectType fffff802`508fa0f0 ffff8c8d`0e2feae0 fffff802`508fa0f8 00000001`ffffff0f fffff802`508fa100 00000001`000003e8 0: kd> dt _object_type ffff8c8d`0e2feae0 nt!_OBJECT_TYPE +0x000 TypeList : _LIST_ENTRY [ 0xffff8c8d`0e2feae0 - 0xffff8c8d`0e2feae0 ] +0x010 Name : _UNICODE_STRING "Holiam" +0x020 DefaultObject : (null) +0x028 Index : 0x45 'E' +0x02c TotalNumberOfObjects : 0 +0x030 TotalNumberOfHandles : 0 +0x034 HighWaterNumberOfObjects : 0 +0x038 HighWaterNumberOfHandles : 0 +0x040 TypeInfo : _OBJECT_TYPE_INITIALIZER +0x0b8 TypeLock : _EX_PUSH_LOCK +0x0c0 Key : 0x696c6f48 +0x0c8 CallbackList : _LIST_ENTRY [ 0xffff8c8d`0e2feba8 - 0xffff8c8d`0e2feba8 ] 0: kd> dx -id 0,0,ffff8c8d07c61040 -r1 (*((ntkrnlmp!_OBJECT_TYPE_INITIALIZER *)0xffff8c8d0e2feb20)) (*((ntkrnlmp!_OBJECT_TYPE_INITIALIZER *)0xffff8c8d0e2feb20)) [Type: _OBJECT_TYPE_INITIALIZER] [+0x000] Length : 0x78 [Type: unsigned short] [+0x002] ObjectTypeFlags : 0x0 [Type: unsigned short] [+0x002 ( 0: 0)] CaseInsensitive : 0x0 [Type: unsigned char] [+0x002 ( 1: 1)] UnnamedObjectsOnly : 0x0 [Type: unsigned char] [+0x002 ( 2: 2)] UseDefaultObject : 0x0 [Type: unsigned char] [+0x002 ( 3: 3)] SecurityRequired : 0x0 [Type: unsigned char] [+0x002 ( 4: 4)] MaintainHandleCount : 0x0 [Type: unsigned char] [+0x002 ( 5: 5)] MaintainTypeList : 0x0 [Type: unsigned char] [+0x002 ( 6: 6)] SupportsObjectCallbacks : 0x0 [Type: unsigned char] [+0x002 ( 7: 7)] CacheAligned : 0x0 [Type: unsigned char] [+0x003 ( 0: 0)] UseExtendedParameters : 0x0 [Type: unsigned char] [+0x003 ( 7: 1)] Reserved : 0x0 [Type: unsigned char] [+0x004] ObjectTypeCode : 0x0 [Type: unsigned long] [+0x008] InvalidAttributes : 0x0 [Type: unsigned long] [+0x00c] GenericMapping [Type: _GENERIC_MAPPING] [+0x01c] ValidAccessMask : 0x1f000f [Type: unsigned long] [+0x020] RetainAccess : 0x0 [Type: unsigned long] [+0x024] PoolType : NonPagedPool | NonPagedPoolExecute | NonPagedPoolBase (0) [Type: _POOL_TYPE] [+0x028] DefaultPagedPoolCharge : 0x0 [Type: unsigned long] [+0x02c] DefaultNonPagedPoolCharge : 0x58 [Type: unsigned long] [+0x030] DumpProcedure : 0x0 [Type: void (__cdecl*)(void *,_OBJECT_DUMP_CONTROL *)] [+0x038] OpenProcedure : 0x0 [Type: long (__cdecl*)(_OB_OPEN_REASON,char,_EPROCESS *,void *,unsigned long *,unsigned long)] [+0x040] CloseProcedure : 0xfffff80250481de0 [Type: void (__cdecl*)(_EPROCESS *,void *,unsigned __int64,unsigned __int64)] [+0x048] DeleteProcedure : 0xfffff802503136c0 [Type: void (__cdecl*)(void *)] [+0x050] ParseProcedure : 0x0 [Type: long (__cdecl*)(void *,void *,_ACCESS_STATE *,char,unsigned long,_UNICODE_STRING *,_UNICODE_STRING *,void *,_SECURITY_QUALITY_OF_SERVICE *,void * *)] [+0x050] ParseProcedureEx : 0x0 [Type: long (__cdecl*)(void *,void *,_ACCESS_STATE *,char,unsigned long,_UNICODE_STRING *,_UNICODE_STRING *,void *,_SECURITY_QUALITY_OF_SERVICE *,_OB_EXTENDED_PARSE_PARAMETERS *,void * *)] [+0x058] SecurityProcedure : 0xfffff802502691a0 [Type: long (__cdecl*)(void *,_SECURITY_OPERATION_CODE,unsigned long *,void *,unsigned long *,void * *,_POOL_TYPE,_GENERIC_MAPPING *,char)] [+0x060] QueryNameProcedure : 0x0 [Type: long (__cdecl*)(void *,unsigned char,_OBJECT_NAME_INFORMATION *,unsigned long,unsigned long *,char)] [+0x068] OkayToCloseProcedure : 0x0 [Type: unsigned char (__cdecl*)(_EPROCESS *,void *,void *,char)] [+0x070] WaitObjectFlagMask : 0x0 [Type: unsigned long] [+0x074] WaitObjectFlagOffset : 0x0 [Type: unsigned short] [+0x076] WaitObjectPointerOffset : 0x0 [Type: unsigned short]
C
복사
생성한 오브젝트가 DbgkDebugObjectType로 변경되어 있으며, 정상적으로 ObTypeIndexTable(0x45)에 추가되었습니다.
디버깅 후 확인해보면
0: kd> dt _object_type ffff8c8d`0e2feae0 nt!_OBJECT_TYPE +0x000 TypeList : _LIST_ENTRY [ 0xffff8c8d`0e2feae0 - 0xffff8c8d`0e2feae0 ] +0x010 Name : _UNICODE_STRING "Holiam" +0x020 DefaultObject : (null) +0x028 Index : 0x45 'E' +0x02c TotalNumberOfObjects : 1 +0x030 TotalNumberOfHandles : 1 +0x034 HighWaterNumberOfObjects : 1 +0x038 HighWaterNumberOfHandles : 1 +0x040 TypeInfo : _OBJECT_TYPE_INITIALIZER +0x0b8 TypeLock : _EX_PUSH_LOCK +0x0c0 Key : 0x696c6f48 +0x0c8 CallbackList : _LIST_ENTRY [ 0xffff8c8d`0e2feba8 - 0xffff8c8d`0e2feba8 ]
C
복사
정상적으로 핸들과 오브젝트 값이 증가하였으며, 기존의 DebugObject의 경우
0: kd> dt _object_type ffff8c8d`07cc77a0 nt!_OBJECT_TYPE +0x000 TypeList : _LIST_ENTRY [ 0xffff8c8d`07cc77a0 - 0xffff8c8d`07cc77a0 ] +0x010 Name : _UNICODE_STRING "DebugObject" +0x020 DefaultObject : (null) +0x028 Index : 0xf '' +0x02c TotalNumberOfObjects : 0 +0x030 TotalNumberOfHandles : 0 +0x034 HighWaterNumberOfObjects : 0 +0x038 HighWaterNumberOfHandles : 0 +0x040 TypeInfo : _OBJECT_TYPE_INITIALIZER +0x0b8 TypeLock : _EX_PUSH_LOCK +0x0c0 Key : 0x75626544 +0x0c8 CallbackList : _LIST_ENTRY [ 0xffff8c8d`07cc7868 - 0xffff8c8d`07cc7868 ]
C
복사
참조되지 않는것을 확인하였습니다.
해당 기법으로 함수 내부적으로 DbgkObjectType을 참조하지 않는 방식의 Anti-Debug의 경우 Bypass가 가능합니다.

3.3 FreeObjectType? DeleteObjectType?

Microsoft에서 공식적으로 ObjectType을 삭제하는 함수는 존재하지 않습니다.
개인적으로 지인분들에게 조언을 구하면서 구현을 해 보려 하였으나, ObjectType이 삭제 되지 않아 더 연구중입니다.

4. Outro

DebugObject 관련 연구를 진행하던 중 해당 전역변수를 변조하면 어떻게 될까에서 시작된 연구였는데, 생각보다 쓰임새가 많아 보여 정리하였습니다.
좀 더 발전하여 DebugObject의 ValidAccessMask의 값을 0으로 변조하고, 해당 값 및 DbgkDebugObjectType 값을 모니터링 하는 방식으로 더 발전하여 사용이 가능해 보입니다.