Many applications use SetUnhandledExceptionFilter to catch unexpeted exception. This API let application be able to hook top-level exception handler of a process. Through it app has a chance to dump debugging information or report abnormal status before process exit. This function also be used as an anti-debugging trick: If a debugger attach to a process, top-level exception handler won’t be invoked, so we can hide our logic inside the exception handler.
Sounds good, but there can be only one top-level exception handler for a process. If not only one module, could be legacy code or 3-party lib, uses SetUnhandledExceptionFilter, the result may be unwanted.
How to check top-level exception handler by windbg? Although this is a process-specific information, we need full memory dump or two machine live debugging to get the handler. First, set the process context to the process you want to check, search for the kernel32!BasepCurrentTopLevelFilter, this is where the pointer to the top-level exception handler stored :
1: kd> x kernel32!BasepCurrentTopLevelFilter
2: 76d0a5d0 kernel32!BasepCurrentTopLevelFilter =
3: kd> dd 76d0a5d0 L1
4: 76d0a5d0 d849453d
So the address of the handler is 0xd849456d? No. Since WinXP SP2, Windows will encoding the addres. We have to decode it. On Vista SP2, basicly encoding is XOR with process cookie. Cookie is avaliable in EPROCESS structure. That is why we need full memory dump or two machine live debugging.
1: kd> dt _EPROCESS 83625d90
2: ntdll!_EPROCESS
3: +0x000 Pcb : _KPROCESS
4: +0x080 ProcessLock : _EX_PUSH_LOCK
5: +0x088 CreateTime : _LARGE_INTEGER 0x1cb01ba`83f00f26
6: … skipped
7: +0x234 PriorityClass : 0x2 ''
8: +0x238 VadRoot : _MM_AVL_TABLE
9: +0x258 Cookie : 0x4905fc08
10: +0x25c AlpcContext : _ALPC_PROCESS_CONTEXT
1: kd> uf ntdll!rtldecodepointer
2: ntdll!RtlDecodePointer:
3: 77170a18 8bff mov edi,edi
4: 77170a1a 55 push ebp
5: 77170a1b 8bec mov ebp,esp
6: 77170a1d 51 push ecx
7: 77170a1e 6a00 push 0
8: 77170a20 6a04 push 4
9: 77170a22 8d45fc lea eax,[ebp-4]
10: 77170a25 50 push eax
11: 77170a26 6a24 push 24h
12: 77170a28 6aff push 0FFFFFFFFh
13: 77170a2a e865f40200 call ntdll!ZwQueryInformationProcess (7719fe94)
14: 77170a2f 85c0 test eax,eax
15: 77170a31 0f8cf8660400 jl ntdll!RtlDecodePointer+0x1b (771b712f)
16:
17: ntdll!RtlDecodePointer+0x21:
18: 77170a37 8a45fc mov al,byte ptr [ebp-4]
19: 77170a3a 241f and al,1Fh
20: 77170a3c b120 mov cl,20h
21: 77170a3e 2ac8 sub cl,al
22: 77170a40 8b4508 mov eax,dword ptr [ebp+8]
23: 77170a43 d3c8 ror eax,cl
24: 77170a45 3345fc xor eax,dword ptr [ebp-4]
25: 77170a48 c9 leave
26: 77170a49 c20400 ret 4
1: void main(){
2: DWORD Pointer = 0xd849456d ;
3: DWORD Cookie = 0x4905fc08;
4: DWORD result = 0;
5: //
6: //decoding process
7: //
8: __asm{
9: mov al,byte ptr [Cookie]
10: and al,1Fh
11: mov cl,20h
12: sub cl,al
13: mov eax,dword ptr [Pointer]
14: ror eax,cl
15: xor eax,dword ptr [Cookie]
16: mov result,eax
17: };
18: }
1: kd> ln 0040C1D0
2: d:\xxx\src\utility\util_crashhandler.cpp(xxx)
3: (0040c1d0) xxx!CrashHandlerExceptionFilter | (0040c310) xxx!SetCrashHandlerFilter
4: Exact matches:
5: xxx!CrashHandlerExceptionFilter (struct _EXCEPTION_POINTERS *)