A working PAE patch for Windows Vista, 32-bit

September 29, 2009

Download: http://www.mediafire.com/file/yjgidzjzdti/PatchPae.zip. See readme.txt for full instructions. Note: .NET Framework 2.0 is required.

Changing the memory limit

If you disassemble ntkrnlpa.exe, you will notice a function called MxMemoryLicense. This is called at system startup and sets a global variable named MiTotalPagesAllowed, which the kernel consults when deciding how much of your precious installed RAM to ignore. It goes something like this:

ULONG totalPagesAllowed;
ULONG returnLength;

if (NT_SUCCESS(ZwQueryLicenseValue(..., &totalPagesAllowed, 4, &returnLength)) && totalPagesAllowed)
{
    MiTotalPagesAllowed = totalPagesAllowed * 256;
}
else
{
    MiTotalPagesAllowed = 0x80000; // 2 GB
}

...

PatchPae finds this segment and patches the code so that MiTotalPagesAllowed is always set to 0×2000000, which is 128 GB in total.

Bypassing kernel verification

If you try to boot the resulting kernel, the Windows Loader will reject it because it will fail to verify its digital signature. There are ways around this, such as selecting “Disable Driver Signature Enforcement” at startup. However, these various methods are only temporary. To fix this we also need to patch winload.exe. This is quite simple – BlImgLoadPEImageEx calls ImgpValidateImageHash to validate each image to be loaded. We can patch the code so that the return value of ImgpValidateImageHash is always seen as STATUS_SUCCESS, and the loader doesn’t know the images have been modified.

Putting it together

Note that we have to use bcdedit to disable verification of winload.exe. This can be done by running bcdedit /set nointegritychecks 1. This is best done with a new boot entry, so that you can select your other boot entry at startup if something goes wrong. Finally, we have to set the kernel to be our patched kernel, and the loader to be our patched loader: bcdedit /set kernel <patched kernel name>, and bcdedit /set path \Windows\system32\<patched loader name>.


12 ways to terminate a process

May 10, 2009

TerminateProcess or NtTerminateProcess

Everyone knows about TerminateProcess. You simply open a handle to the target process and call TerminateProcess. In case TerminateProcess is hooked, you can call the equivalent Native API function NtTerminateProcess.

CreateRemoteThread, ExitProcess

For this method you will have to find the address of ExitProcess within the target process. It is usually the same as ExitProcess for your process, so you can use GetModuleHandle and GetProcAddress. You can then create a thread inside the target process which executes ExitProcess, killing the target process.

NtQuerySystemInformation or toolhelp32, TerminateThread or NtTerminateThread

Simply loop through the threads of the target process and terminate each one using TerminateThread. If it’s hooked, call NtTerminateThread.

NtQuerySystemInformation or toolhelp32, SetThreadContext

Loop through the threads of the target process and set their contexts using SetThreadContext; modify their contexts so that eip points to ExitProcess.

DuplicateHandle

Loop from 0 to 4096 and call DuplicateHandle with Options = 1, leaving TargetProcess and TargetProcessHandle null. This will close most, if not all handles opened by the target process. This method works best for complex applications like security software – it doesn’t crash Notepad, for example.

CreateJobObject, AssignProcessToJobObject, TerminateJobObject (and their Native API equivalents)

Create a job object using CreateJobObject, assign the target process to it using AssignProcessToJobObject, and terminate it using TerminateJobObject. This only works if the process is not already associated with a job object. This technique works well if NtAssignProcessToJobObject and NtTerminateJobObject are not hooked because NtTerminateJobObject calls PsTerminateProcess directly.

NtCreateDebugObject, NtDebugActiveProcess, CloseHandle

People usually implement this technique by using DebugActiveProcess and then exiting the current process. They do this because they don’t know how DebugActiveProcess works. Behind the scenes kernel32 is calling ntdll which calls NtDebugActiveProcess with an already-created debug object. You don’t have to exit the current process for the debuggee to get killed; you just need to close the debug object. When it is closed, the kernel will kill the debuggee using PsTerminateProcess.

To implement this technique, you can create a debug object using NtCreateDebugObject (specifying the kill-on-close flag), debug the process using NtDebugActiveProcess (the process handle needs PROCESS_SUSPEND_RESUME access), and close the handle to the debug object using CloseHandle. Here are the definitions:

#define DEBUG_OBJECT_READEVENT 0x1
#define DEBUG_OBJECT_PROCESSASSIGN 0x2
#define DEBUG_OBJECT_SETINFORMATION 0x4
#define DEBUG_OBJECT_QUERYINFORMATION 0x8

#define DEBUG_OBJECT_KILLONCLOSE 0x1

NTSTATUS NTAPI NtCreateDebugObject(
    PHANDLE DebugObjectHandle,
    ACCESS_MASK DesiredAccess,
    POBJECT_ATTRIBUTES ObjectAttributes,
    ULONG Flags
    );

NTSTATUS NTAPI NtDebugActiveProcess(
    HANDLE ProcessHandle,
    HANDLE DebugObjectHandle
    );

VirtualQueryEx, VirtualProtectEx

Loop through the memory regions of the target process using VirtualQueryEx and set their protections to PAGE_NOACCESS. The program will crash as soon as it context-switches into user-mode code because it will be unable to read any code from memory.

VirtualQueryEx, WriteProcessMemory

Loop through the memory regions of the target process and write random data to it using WriteProcessMemory.

VirtualAllocEx

Call VirtualAllocEx in a loop until you can’t reserve any more memory in the target process. It will crash when it is unable to allocate any more memory.

PsTerminateProcess

PsTerminateProcess is an internal kernel-mode function which is not exported by ntoskrnl. You will need to locate it by scanning kernel-mode memory for a specific signature, which I will not post here. WARNING: On XP you should locate PspTerminateProcess instead, which is stdcall. On Vista PsTerminateProcess is thiscall (first argument goes in ecx), so you will need some hand-coded assembly.

typedef NTSTATUS (*_PsTerminateProcess)(
    PEPROCESS Process,
    NTSTATUS ExitStatus
    );

PspTerminateThreadByPointer

This function is not exported either. WARNING: On XP, there are two arguments. On Vista, there are three.

/* XP */
typedef NTSTATUS (NTAPI *_PspTerminateThreadByPointer51)(
    PETHREAD Thread,
    NTSTATUS ExitStatus
    );

/* Vista */
typedef NTSTATUS (NTAPI *_PspTerminateThreadByPointer60)(
    PETHREAD Thread,
    NTSTATUS ExitStatus,
    BOOLEAN DirectTerminate
    );

A note about process handles

Before you get started on these methods, you will need to know the ways of getting a handle to the victim process. Surely, the only way to do this is by calling OpenProcess/NtOpenProcess, right? Wrong. If you can’t get a handle with the right access because of a hooked function (such as with security software), you can open the target process with SYNCHRONIZE access (or whatever access you think will be granted) and call DuplicateHandle to get new access rights. This won’t always work though because security software vendors are starting to hook ZwDuplicateObject to prevent this.

On Windows Vista there are two Native API functions named NtGetNextProcess and NtGetNextThread. Almost no one knows about this and almost no one hooks these two functions. Here are their definitions:

NTSTATUS NTAPI NtGetNextProcess(
    HANDLE ProcessHandle,
    ACCESS_MASK DesiredAccess,
    ULONG HandleAttributes,
    ULONG Flags,
    PHANDLE NewProcessHandle
    );

NTSTATUS NTAPI NtGetNextThread(
    HANDLE ProcessHandle,
    HANDLE ThreadHandle,
    ACCESS_MASK DesiredAccess,
    ULONG HandleAttributes,
    ULONG Flags,
    PHANDLE NewThreadHandle
    );

NtQuerySystemInformation: a simple way to bypass rootkits which hide processes by hooking

April 25, 2009

You’ve probably seen code like this:

NTSTATUS MyRootkitNtQuerySystemInformation(
    ULONG SystemInformationClass,
    PVOID SystemInformation,
    ULONG SystemInformationLength,
    PULONG ReturnLength
)
    if (SystemInformationClass == 5) // SystemProcessInformation
    {
        // do some pointer manipulation to hide our rootkit process
        ...
    }
    else
    {
        return OriginalNtQuerySystemInformation(...);
    }
}

For example, this is what Hacker Defender does to hide itself. What most people don’t know is that there are two more system information classes to enumerate processes!

SystemSessionProcessInformation (53)
SystemSessionProcessInformation is exactly the same as SystemProcessInformation except that you specify a session ID and the kernel returns processes in that session. You do this by passing a SYSTEM_SESSION_PROCESS_INFORMATION structure to NtQuerySystemInformation:

#define SystemSessionProcessInformation 53

typedef struct _SYSTEM_SESSION_PROCESS_INFORMATION
{
    ULONG SessionId;
    ULONG BufferLength;
    PVOID Buffer;
} SYSTEM_SESSION_PROCESS_INFORMATION, PSYSTEM_SESSION_PROCESS_INFORMATION;

...
SYSTEM_SESSION_PROCESS_INFORMATION info;
PVOID buffer = malloc(whatever_you_want);
ULONG returnLength;

info.SessionId = session_id_to_get_processes_for;
info.BufferLength = size_of_the_buffer;
info.Buffer = buffer;

NtQuerySystemInformation(SystemSessionProcessInformation, &info, sizeof(SYSTEM_SESSION_PROCESS_INFORMATION, &returnLength);
...
/* buffer will be filled with SYSTEM_PROCESS_INFORMATION structures, just like with SystemProcessInformation */
...

SystemExtendedProcessInformation (57)
This is similar to SystemProcessInformation, except that you get more information (obviously). Ever wondered why PageDirectoryBase was always 0 when you used SystemProcessInformation? With SystemExtendedProcessInformation, it’s actually filled in. Here are the revised structs:

#define SystemExtendedProcessInformation 57

typedef struct _SYSTEM_THREAD_INFORMATION
{
    LARGE_INTEGER KernelTime;
    LARGE_INTEGER UserTime;
    LARGE_INTEGER CreateTime;
    ULONG WaitTime;
    PVOID StartAddress;
    CLIENT_ID ClientId;
    LONG Priority;
    LONG BasePriority;
    ULONG ContextSwitches;
    ULONG ThreadState;
    ULONG WaitReason;
} SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION;

typedef struct _SYSTEM_EXTENDED_THREAD_INFORMATION
{
    SYSTEM_THREAD_INFORMATION ThreadInfo;
    PVOID StackBase;
    PVOID StackLimit;
    PVOID Win32StartAddress;
    PVOID TebAddress; /* This is only filled in on Vista and above */
    ULONG Reserved1;
    ULONG Reserved2;
    ULONG Reserved3;
} SYSTEM_EXTENDED_THREAD_INFORMATION, *PSYSTEM_EXTENDED_THREAD_INFORMATION;

typedef struct _SYSTEM_PROCESS_INFORMATION
{
    ULONG NextEntryOffset;
    ULONG NumberOfThreads;
    LARGE_INTEGER SpareLi1;
    LARGE_INTEGER SpareLi2;
    LARGE_INTEGER SpareLi3;
    LARGE_INTEGER CreateTime;
    LARGE_INTEGER UserTime;
    LARGE_INTEGER KernelTime;
    UNICODE_STRING ImageName;
    KPRIORITY BasePriority;
    ULONG UniqueProcessId;
    ULONG InheritedFromUniqueProcessId;
    ULONG HandleCount;
    ULONG SessionId;
    PVOID PageDirectoryBase;
    VM_COUNTERS VirtualMemoryCounters;
    SIZE_T PrivatePageCount;
    IO_COUNTERS IoCounters;
    SYSTEM_EXTENDED_THREAD_INFORMATION Threads[1];
} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;

...
PVOID buffer = malloc(whatever_size);
ULONG returnLength;

NtQuerySystemInformation(SystemExtendedProcessInformation, buffer, size_of_the_buffer, &returnLength);
...

The Bug Check Tool

March 27, 2009

Ever wanted to BSOD your computer? Found that the Ctrl+ScrollLock feature in Windows is too limited?

Try the FREE (and open source) Bug Check Tool!

Bug Check Tool

This revolutionary tool allows you to crash your computer while specifying the BSOD code and the four associated parameters. Additionally it includes a database of a 34 BSOD codes, complete with descriptions.

Get the source code now at https://processhacker.svn.sourceforge.net/svnroot/processhacker/misc/bugcheck!


HOWTO: Crash Windows Vista’s UAC elevation dialog

March 8, 2009
  1. Make sure you’re logged in as an administrator and UAC is on.
  2. Open an installation program or any program that requires elevation.
  3. Once the elevation dialog appears, don’t touch anything and hold down the space bar.
  4. While it is being held down, press the down arrow.
  5. The dialog will disappear. Wait for a few seconds and you will be returned to your desktop, as normal.
  6. In your taskbar there will be a Windows Error Reporting window. The UAC elevation dialog just crashed.

HOWTO: Implement your own NtOpenProcess in kernel-mode

February 19, 2009

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[0x34];
    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 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[0x34];
    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.

Why freezing/suspending explorer.exe is a bad idea

January 30, 2009

The reason: notification icons (sometimes called “tray icons”). Programs update their notification icons by sending window messages to Explorer. Guess what happens when Explorer is busy, or in this case, suspended. The client program has to wait for its timeout, which will then cause noticible lag on most single-threaded GUI programs. This may even explain the reason for any random program lags you may have experienced!

Just a thought.


HOWTO: Protect and unprotect Vista’s DRM-protected processes!

January 25, 2009

I could only find two previous attempts at doing this – D-Pin Purr, which is heavily obfuscated, and this PDF which contains the solution but doesn’t present any code. The solution is quite obvious for anyone familiar with WinDbg, but I’ll go through it here.

While I was going through the Windows kernel in IDA, I discovered this little function:

PsIsProtectedProcess

As you can see, PsIsProtectedProcess takes one argument, accesses some data in it, and does some binary arithmetic. Since there is only one process-related structure that is that large (548 bytes), it had to be an EPROCESS. The binary arithmetic had to be there because the structure contained a bitfield. The field the function is referencing turns out to be ProtectedProcess. Thanks to Microsoft, we can now program our own driver to modify this field and unprotect/protect any process we want! The code is quite simple:

BOOLEAN GetProcessProtected(int pid)
{
    PEPROCESS processObject;
    BOOLEAN protected;

    PsLookupProcessByProcessId(pid, &processObject);
    protected = (*(PULONG)((PCHAR)processObject + 0x224) >> 0xb) & 1;
    ObDereferenceObject(processObject);

    return protected;
}

void SetProcessProtected(int pid, BOOLEAN value)
{
    PEPROCESS processObject;

    PsLookupProcessByProcessId(pid, &processObject);

    if (value)
        *(PULONG)((PCHAR)processObject + 0x224) |= 1 << 0xb;
    else
        *(PULONG)((PCHAR)processObject + 0x224) &= ~(1 << 0xb);

    ObDereferenceObject(processObject);
}

Note: do NOT use this code, because it has NOT been tested and lacks many safety checks. However, I have confirmed that a slightly modified version of the code works on Windows Vista SP1.


HOWTO: Get the command line of a process

January 24, 2009

For a different method, see HOWTO: Get the command line of a process in Unicode or ANSI.

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. Read the rest of this entry »


Process file name spoofing/faking by memory modification

January 23, 2009

Since the people at the Process Explorer forums don’t really care about this issue, I’m posting it here.

The problem: processes can fake their own file location. This was originally discovered in 2006, but almost no one knew/knows about it. Task managers and security tools often rely on the file names of processes to determine their security risk – through online ratings, file signature verifications, or hashing. The problem is that this information is stored in processes’ memory1 – which they are free to modify. I’ve tested several process managers/security tools, and an alarming numberTM are vulnerable. You can download the test program.

Operating system: Windows XP
Tested programs (in no particular order):

The test program

As you can see, I have renamed the test executable to smss.exe and asked it to disguise itself as the Windows Session Manager (located at C:\Windows\system32\smss.exe). If at any point you think I am faking my screenshots, you can look at the username of my test program – the real session manager always runs under NT AUTHORITY\SYSTEM.

Windows Task Manager

Windows Task Manager

This isn’t unusual; task manager on XP always refuses to end processes which have the name of a critical system process. This has often been exploited by malware authors in the past. The important thing to note is that Windows Task Manager on Windows Vista can show the file names of processes and is not affected by the file name spoofing exploit.

AnVir Task Manager

AnVir Task Manager getting owned

This program was very disappointing – not only was the user interface extremely ugly and bloated, it actually got fooled by my test program. There were no warnings about the fact that a system process was running under a normal user account, and it told me my test program was “CRITICAL SYSTEM!!!”. This wouldn’t be bad if the program was non-commercial or free software, but it’s nagware and keeps on telling me to “Update to AnVir Task Manager Pro”.

MKN Task Manager

MKN Task Manager getting owned as well

The installer for this program was named “MKN_TaskExplorer_Tryout_Setup.exe”, but there doesn’t seem to be any place I can enter a registration key. I’ll assume it’s freeware. This program gets fooled as well. Interestingly, the process properties window states that my test program has no parent process. Even AnVir Task Manager knew that my test program was started by the Command Prompt. I guess the developers hardcoded a list of processes-to-not-display-parents-for.

PrcView

PrcView

PrcView is better than the previous two programs in that instead of pretending to know the file name of my test program, it simply fails. The reason for this is that when any program tries to enumerate the modules of my test program, they will find that the main module’s file name is blank (see Process Explorer’s module list below). This is just an interesting side-effect – my program doesn’t actually try to erase it.

HijackFree

HijackFree

Same as above.

Process Explorer

Process Explorer

The really bad thing about Process Explorer failing the test is that people often use it to verify the signatures of executables.

Process Hacker

Process Hacker

I wrote this program, so I just had to include it here.

Security Task Manager

Security Task Manager

Security Task Manager also fails to get the test program’s file name. Wait… “Probably system process without file”. Uh… how is a system process supposed to run without a file? I highly doubt the Windows kernel would create a new system process filled with vacuum and then assemble all the code in memory…

File.net Windows Process Viewer

File.net Windows Task Manager

Fails to get the test program’s file name.

Conclusion

So, you ask, what is the correct way to get a process’ file name? Let’s go through what programs usually do to get the file names of processes:

  • Some programs use the toolhelp32 functions. This is vulnerable to file name spoofing.
  • Some programs (and the .NET Framework) use the file name of the main module. This method gives you blank file names as you saw earlier. Note that this is because my test program erases the original string in order to prevent tools from discovering the real file name. Real malware may not be that nice and may simply overwrite the original string!
  • Some programs use QueryFullProcessImageName, which is not vulnerable to the exploit. However, it only works on Windows Vista.
  • The best way is to use the (undocumented) function NtQueryInformationProcess with ProcessImageFileName (27, or 0x1b). This gives you the file name in native format, so you’ll have to do some extra work to convert it to DOS format. On Windows Vista, there is a new information class named ProcessImageFileNameWin32 (43, or 0x2b) which gives you the file name in DOS format. This is what QueryFullProcessImageName calls.

Notes

1 – in RTL_USER_PROCESS_PARAMETERS which is referenced by the PEB. See the excellent NT Internals website for more details.