다음 코드 2줄로 우회가 가능합니다.
extern PBOOLEAN KdDebuggerEnabled; // 선언..
*KdDebuggerEnabled = FALSE; // 우회 코드
KdDebuggerEnabled 변수를 직접적으로 접근하지 않는 방식을 사용하여도 이 방법은 통합니다.
왜냐하면 결국엔 그 함수들은 저 전역변수를 참조하게 됩니다.
심지어 WinDbg 조차도 저렇게 값을 임의로 바꾸면 Attach가 안됩니다.
따라서 이러한 경우 커널 디버거는 우회가 되는데 WinDbg로 Attach 하여서 디버깅하는데 조금 문제가 생길것입니다.
따라서 디버거를 탐지하는 코드가 실행되는 경우에는 우선 저렇게 전역변수를 FALSE로 바꾸고
디버거 탐지코드가 실행되었다면 다시 KdDebuggerEnabled 커널 전역변수를 TRUE로 바꿔주면
WinDbg로 Attach 도 되고 디버깅이 가능해집니다.
커널 디버거를 탐지하는 대상 코드는 아래와 같고 이러한 코드는 이전에 말했듯이 내부적으로
위에 커널 전역변수를 사용하므로 우회가 됩니다.
bool __stdcall IsDebugPort(PVOID Object)
{
void *pZwQueryInformationProcess; // eax@2
bool result; // eax@4
signed int bDebug; // [sp+10h] [bp-4h]@1
int v4; // [sp+Ch] [bp-8h]@2
UNICODE_STRING DestinationString; // [sp+4h] [bp-10h]@3
bDebug = 0;
if ( PsLookupProcessByProcessId(Object, &Object) >= 0
&& ((ObOpenObjectByPointer(Object, 0, 0, 0, 0, 0, &v4),
ObfDereferenceObject(Object), pZwQueryInformationProcess = (void
*)g_ZwQueryInformationProcess, g_ZwQueryInformationProcess)
||
(RtlInitUnicodeString(&DestinationString,
L"ZwQueryInformationProcess"), pZwQueryInformationProcess =
MmGetSystemRoutineAddress(&DestinationString),
g_ZwQueryInformationProcess = (int)pZwQueryInformationProcess,
pZwQueryInformationProcess)) )
{
((int (__stdcall *)(int, signed int, signed int *, signed int, _DWORD))pZwQueryInformationProcess)(
v4,
7,
&bDebug,
4,
0); // 이 함수에 두 번째 인자 ProcessDebugPort를 넘기고 있다.
// 즉, 이것은 디버그중인지 체크한다고 보면 될것이다.
result = bDebug == -1; // -1(0xFFFFFFFF) 일 경우 디버깅중인 상태입니다.
}
else
{
result = 0;
}
return result;
}