Banner 1

Injecting Code Into Privileged Win32 Processes

For a while now, I've been searching for the optimal way to inject code into privileged Win32 processes like lsass.exe, csrss.exe, and winlogon.exe. There are many functions such as the LSA and SAM exports that even users logged in with full administrative rights cannot execute unless they do so under the context of one of these privileged processes. There are a few tricks that I learned along the way.

First, it is necessary to adjust the token privileges of your program so that debugging (SE_PRIVILEGE_ENABLED) is allowed. If you are injecting code into a lower privileged process, then this will not be needed.

Also, the target process will need to be opened with PROCESS_ALL_ACCESS rights.

Its all pretty easy on Windows 2000 and XP Service Pack 0 and 1. On these systems, you can use the documented CreateRemoteThread() function, but first the code you want to run in the security context of the remote process needs to exist in that process' virtual memory space. You can put it there by using VirtualAllocEx() and WriteProcessMemory().

With XP SP2 and later (2003, Vista) some new security measures prevent the traditional CreateRemoteThread() function from working properly. You should be able to open the process, allocate memory on its heap, and write data to the allocated region, but when trying to invoke the remote thread, it will fail with ERROR_NOT_ENOUGH_MEMORY.

On Vista, I found that an author can substitute the CreateRemoteThread() call with NtCreateThreadEx() export from ntdll.dll and it will allow for the thread to execute properly. This requires you to auto-detect the version of the operating system and branch to this different call if on Vista. Also, this is isn't really a universal solution, because NtCreateThreadEx() doesn't exist on pre-Vista sytsems. So now we're stuck with using CreateRemoteThread() on 2000 and XP SP 0,1 and NtCreateThreadEx() on Vista. This is already getting messy, and we still don't have a solution for XP SP2.

Also, the NtCreateThreadEx() function takes an undocumented structure, whose members can be initialized appropriately by reversing other binaries that use the function, but it looks really ugly in source code since I don't really know what the members are for, or why particular values are significant.

For XP SP2 I did a little debugging and found that inside CreateRemoteThread(), there is a call to ZwCreateThread() which is an export from ntdll.dll. The call is made while specifying that the thread should start suspended, which it does properly, however down the road still inside CreateRemoteThread() before ZwResumeThread() is called, there is a call to CsrClientCallServer() which fails and eventually leads to the error message.

This behavior makes you wonder, if you can just call ZwCreateThread() directly, then the call to CsrClientCallServer() will be avoided and the thread will execute. The problem is that ZwCreateThread() doesn't allow one to set the thread start address easily (you have to configure the INITIAL_TEB members to set EIP to your start address using mostly undocumented structures and functions).

However, this all can be avoided by using the RtlCreateUserThread() function instead, which configures and calls all the undocumented functions for you, and eventually invokes ZwCreateThread() with the result. Although RtlCreateUserThread() is undocumented also, its hardly as complex as the rest and is pretty simple to use.

At this point, we can successfully execute remote threads into privileged processes across all target platforms, but as mentioned before, its pretty messy. We're using three different, largely undocumented functions and auto-detecting which one to use based on the OS version.

The better solution is to create a secondary program that adds a service object (your injector program) to the service control manager database on the target system. Since you're administrator, which is required anyway, you'll be able to add these entries and start the service. This will enable the injector program to run with different access rights than normal code, and the traditional CreateRemoteThread() will work properly on Windows 2000, all of XP, and 2003/Vista. The API functions for adding and controlling the service are documented by MSDN and remain consistent across all of the platforms.

So, what is learned is that we can use a number of different functions to inject code into privileged remote processes, including RtlCreateUserThread() on XP SP2, and NtCreateThreadEx() on Vista, but the optimal way is to install a temporary service and allow CreateRemoteThread() to be the single API that accomplishes the task for all platforms.

Fuente:http://mnin.blogspot.com/2007/05/injecting-code-into-privileged-win32.html

No hay comentarios:

Powered by Bad Robot
Helped by Blackubay