2009년 09월 28일
커널 디버거 탐지 기법 우회
다음 코드 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;
}
일부 보안 드라이버에서는 실시간으로 KdDebuggerEnabled 에 직접 접근하여 디버깅중인지 체크하는데
이러한 경우 해당 드라이버에 한해서 IAT만 변조하는 방식으로 우회하여도 됩니다.
그러나 일반적인 경우 드라이버 초기화 작업에서만 디버깅중인지 체크하므로 위에 방법으로 왠만하면 우회가 가능합니다.
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;
}
일부 보안 드라이버에서는 실시간으로 KdDebuggerEnabled 에 직접 접근하여 디버깅중인지 체크하는데
이러한 경우 해당 드라이버에 한해서 IAT만 변조하는 방식으로 우회하여도 됩니다.
그러나 일반적인 경우 드라이버 초기화 작업에서만 디버깅중인지 체크하므로 위에 방법으로 왠만하면 우회가 가능합니다.
# by | 2009/09/28 22:40 | 리버스 엔지니어링 | 트랙백 | 덧글(1)





☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]