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의 ValidAccessMask를 DEBUG_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 값을 모니터링 하는 방식으로 더 발전하여 사용이 가능해 보입니다.