Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WriteProcessMemory to SYSTEM process with SeDebugPrivilege enabled. (C, Vista)

I'm interested in injecting DLLs into SYSTEM owned processes on my Vista machine. I'm going about this using the traditional method of VirtualAllocEx, WriteProcessMemory and CreateRemoteThread. However, because this will be operating on SYSTEM processes, I enable SeDebugPivilege on the injecting process before opening the target process.


int EnableDebugPriv(LPCTSTR name) {
    HANDLE hToken;
    LUID luid;
    TOKEN_PRIVILEGES tkp;

    if(!OpenProcessToken(GetCurrentProcess(),
                         /*TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY*/
                         TOKEN_ALL_ACCESS,
                         &hToken))
        return 0;

    if(!LookupPrivilegeValue(NULL,name,&luid))
        return 0;

    tkp.PrivilegeCount=1;
    tkp.Privileges[0].Luid=luid;
    tkp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;

    if(!AdjustTokenPrivileges(hToken,false,&tkp,sizeof(tkp),NULL,NULL))
    {
        printf("!AdjustTokenPrivileges - %d\n",GetLastError());
        return 0;
    }
    if(GetLastError()==ERROR_NOT_ALL_ASSIGNED)
    {
        return 0;
    }

    CloseHandle(hToken);
    return 1;
}

Where the SE_DEBUG_NAME constant is passed as name.

After enabling SeDebugPrivilege, I go through the process of opening the target process, locating LoadLibrary, allocating space, writing the DLL path to memory, and creating the thread (checking all return values along the way):


if(NULL==(p=OpenProcess(PROCESS_ALL_ACCESS,FALSE,(DWORD)pid)))
...
if(NULL==(loadLib=(LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), 
                                         "LoadLibraryA")))
...
if(NULL==(dllBuff=(LPVOID)VirtualAllocEx(p,
                                         NULL,
                                         strlen(dllPath)+1,
                                         MEM_RESERVE|MEM_COMMIT,
                                         PAGE_READWRITE)))
...
if(NULL==WriteProcessMemory(p,
                            (LPVOID)dllBuff,
                            dllPath,
                            strlen(dllPath),
                            &written))
...
if(!CreateRemoteThread(p,
                       NULL,
                       NULL,
                       (LPTHREAD_START_ROUTINE)loadLib,
                       (LPVOID)dllBuff,
                       NULL,
                       NULL))
...

dllPath is a char* of the DLL's path (obviously), and pid is the PID of the target process. Both of these values are taken in through the command line and validated before being used.

The problem I'm having is that nothing is returning errors until CreateRemoteThread, which is returning an 8 ("Not enough storage"). HOWEVER, WriteProcessMemory is NOT writing any bytes to the process. After the call the written variable is always 0. No bytes are being written, but the function is not failing. I'm not sure why this is happening. I looked into other privileges, like the SeRestorePrivilege which promises write access to all processes, but nothing works.

I'm executing this program with Administrator rights.

Note: this WriteProcessMemory and CreateRemoteThread problem only happen when I run this program against higher privileged users (SYSTEM, LOCAL SERVICE, etc...). It works perfectly against a program owned by me (same privileges).

Edit: Here's a link to the whole source. http://pastebin.com/m77110d8e There's not much else there besides basic error checking, but maybe it will help?

like image 468
pcorey Avatar asked Jul 16 '09 01:07

pcorey


2 Answers

This has to do with session isolation in Vista or higher versions of Windows. Check out the source or disassembly for password dumping tools like Cain and Abel that purport Vista functionality. Essentially the process is the same but you'll be calling a different function for CreateRemoteThread (sorry, I don't think the function is exported, you just have to find it, so disassembly of working software is probably the best bet).

like image 79
mrduclaw Avatar answered Oct 23 '22 20:10

mrduclaw


You could try using RtlCreateUserThread, instead of CreateRemoteThread. This routine doesn't care what session the target process lives in. Just remember to have the thread call RtlExitUserThread before it ends. These threads don't clean up after themselves, like the CreateThread/CreateRemoteThread ones do.

The reactos code can give you a good look at what these routines are doing.

like image 39
otherchirps Avatar answered Oct 23 '22 19:10

otherchirps