HOWTO: Implement your own NtOpenProcess in kernel-mode

Writing a system utility but annoyed by the fact that you can’t open the processes of security software and rootkits, instead receiving “Access Denied” errors? This is commonly due to security software and rootkits hooking ZwOpenProcess. There are many ways they can do this: SSDT modification, inline hooking (detours), sysenter hooks, etc. There is a simple way of bypassing all of these methods: you can implement NtOpenProcess yourself (in a driver). Let’s go through the steps.

Firstly, we should declare some functions we’ll be using:

#include <ntifs.h>

NTKERNELAPI NTSTATUS NTAPI SeCreateAccessState(
    PACCESS_STATE AccessState,
    PVOID AuxData,
    ACCESS_MASK DesiredAccess,
    PGENERIC_MAPPING Mapping
    );

NTKERNELAPI VOID NTAPI SeDeleteAccessState(
    PACCESS_STATE AccessState
    );

Our custom NtOpenProcess will be called MyNtOpenProcess, and will be equivalent to the OpenProcess Windows API function. It will not perform any memory probing – you can’t call it from user-mode anyway. However, you can use this function to create a user-mode handle which can be used in user-mode.

NTSTATUS MyNtOpenProcess(
    PHANDLE ProcessHandle,
    ACCESS_MASK DesiredAccess,
    HANDLE ProcessId,
    KPROCESSOR_MODE AccessMode /* specify UserMode if you want the handle to be usable in user-mode */
    )
{
    /* Some local variables we'll be using */
    NTSTATUS status = STATUS_SUCCESS;
    ACCESS_STATE accessState;
    /* Some internal structure Windows uses - we don't need to know about it */
    char auxData[0xc8];
    PEPROCESS processObject = NULL;
    HANDLE processHandle = NULL;

Firstly, we need to create an access state:

status = SeCreateAccessState(
    &accessState,
    auxData,
    DesiredAccess,
    /* Highly OS-dependent code - the "52" was taken from a Vista SP1 kernel */
    (PGENERIC_MAPPING)((PCHAR)*PsProcessType + 52)
    );

if (!NT_SUCCESS(status))
    return status;

Now we grant whatever access to the process the caller wants, regardless of object permissions:

accessState.PreviouslyGrantedAccess |= accessState.RemainingDesiredAccess;
accessState.RemainingDesiredAccess = 0;

Now we get a pointer to the EPROCESS structure for the process:

status = PsLookupProcessByProcessId(ProcessId, &processObject);

if (!NT_SUCCESS(status))
{
    SeDeleteAccessState(&accessState);
    return status;
}

Finally, we open a handle to the process object:

status = ObOpenObjectByPointer(
    processObject,
    0,
    &accessState,
    0,
    *PsProcessType,
    AccessMode,
    &processHandle
    );

/* We don't need these two things anymore: */
SeDeleteAccessState(&accessState);
ObDereferenceObject(processObject);

/* If the handle was opened, we give it to our caller. */
if (NT_SUCCESS(status))
    *ProcessHandle = processHandle;

return status;

It’s pretty simple. Here’s the entire function:

NTSTATUS MyNtOpenProcess(
    PHANDLE ProcessHandle,
    ACCESS_MASK DesiredAccess,
    HANDLE ProcessId,
    KPROCESSOR_MODE AccessMode
    )
{
    NTSTATUS status = STATUS_SUCCESS;
    ACCESS_STATE accessState;
    char auxData[0xc8];
    PEPROCESS processObject = NULL;
    HANDLE processHandle = NULL;
    
    status = SeCreateAccessState(
        &accessState,
        auxData,
        DesiredAccess,
        (PGENERIC_MAPPING)((PCHAR)*PsProcessType + 52)
        );

    if (!NT_SUCCESS(status))
        return status;
    
    accessState.PreviouslyGrantedAccess |= accessState.RemainingDesiredAccess;
    accessState.RemainingDesiredAccess = 0;
    
    status = PsLookupProcessByProcessId(ProcessId, &processObject);
    
    if (!NT_SUCCESS(status))
    {
        SeDeleteAccessState(&accessState);
        return status;
    }
    
    status = ObOpenObjectByPointer(
        processObject,
        0,
        &accessState,
        0,
        *PsProcessType,
        AccessMode,
        &processHandle
        );
    
    SeDeleteAccessState(&accessState);
    ObDereferenceObject(processObject);
    
    if (NT_SUCCESS(status))
        *ProcessHandle = processHandle;
    
    return status;
}

Notes:

  • This same technique can be applied to any type of object: if you can get a pointer to a kernel object, you can use ObOpenObjectByPointer to open it as a handle.
  • This technique is vulnerable to inline hooks on ObOpenObjectByPointer. There is nothing you can do about this except read the function from disk and apply relocations as necessary.
  • The code I have supplied has not been tested. Use at your own risk.

HOWTO: Get the command line of a process

How would you get the command line of a process? Some people have suggested that you use remote thread injection, call GetCommandLine(), then IPC the result back. This might work most of the time on Windows XP, but on Windows Vista it doesn’t work on system and service processes. This is because CreateRemoteThread only works on processes in the same session ID as the caller – in Windows Vista, services and other system processes run in session 0 while user programs run in higher sessions. The best and safest way is to read a structure present in every Windows process.Continue reading →

Process Hacker

<advertisment>

I’ve been working a C# program for the past 2 weeks… Process Hacker is a process viewer/manager with special features, including:

  • Viewing, terminating, suspending and resuming threads
  • Viewing modules and their properties, function address look-ups, and reading module memory
  • Viewing memory regions, reading/writing data to memory regions (using a built-in hex editor control), changing page protection
  • Searching through memory, using literal bytes or regular expressions
  • Scanning for strings inside memory
  • Getting heap information
  • Getting DEP status and other information

Link: http://sourceforge.net/projects/processhacker

</advertisment>