Implementing Windows 8 ROP Mitigation for Fun and Profit

The story begins when I saw the new Windows 8 security mitigation implemented by PsValidateUserStack() kernel function( I believe this method introduced by Piotr Bania for the first time). This function is implemented for protecting users from stack exchange method used in modern exploits for bypassing DEP and ASLR by pointing ESP to the attacker controlled heap address range. If you check this function, you will see all references to it are from memory management functions such as NtAllocateVirtualMemory() etc.

What this function actually does is monitoring ESP value when one of memory manipulation functions are called. PsValidateUserStack will get bottom and top of stack for current thread from ETHREAD and check it against current ESP value. If ESP doesn’t point to the actual Stack address range which allocated during thread creation and initialization, the function will terminate the process by throwing  a STATUS_STACK_BUFFER_OVERRUN exception. Here is the PsValidateUserStack() pseudo code reversed by Alex Ionescu :

char __cdecl PsValidateUserStack()

{

char Status; // al@1

_KTRAP_FRAME *TrapFrame; // ecx@3

_TEB *Teb; // ecx@3

void *.Eip; // [sp+10h] [bp-88h]@3

unsigned int .Esp; // [sp+14h] [bp-84h]@3

void *StackLimit; // [sp+18h] [bp-80h]@3

void *StackBase; // [sp+1Ch] [bp-7Ch]@3

_EXCEPTION_RECORD ExitStatus; // [sp+24h] [bp-74h]@6

CPPEH_RECORD ms_exc; // [sp+80h] [bp-18h]@3

 

CurrentThread = (_ETHREAD *)__readfsdword(0x124u);

Status = LOBYTE(CurrentThread->Tcb.___u42.UserAffinity.Reserved[0]);// // PreviousMode == User

if ( Status )

{

__asm { bt      dword ptr [edx+58h], 13h }  // // KernelStackResident, ReadyTransition, Alertable

Status = _CF;

if ( _CF != 1 )

{

TrapFrame = CurrentThread->Tcb.TrapFrame;

.Esp = TrapFrame->HardwareEsp;

.Eip = (void *)TrapFrame->Eip;

Teb = (_TEB *)CurrentThread->Tcb.Teb;

ms_exc.disabled = 0;

StackLimit = Teb->DeallocationStack;

StackBase = Teb->NtTib.StackBase;

ms_exc.disabled = -2;

Status = .Esp;

if ( .Esp < (unsigned int)StackLimit || .Esp >= (unsigned int)StackBase )

{

memset(&ExitStatus, 0, 0x50u);

ExitStatus.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN;

ExitStatus.ExceptionAddress = .Eip;

ExitStatus.NumberParameters = 2;

ExitStatus.ExceptionInformation[0] = 4;

ExitStatus.ExceptionInformation[1] = .Esp;

Status = DbgkForwardException(&ExitStatus, 1, 1);

if ( !Status )

{

Status = DbgkForwardException(&ExitStatus, 0, 1);

if ( !Status )

Status = ZwTerminateProcess((HANDLE)0xFFFFFFFF, ExitStatus.ExceptionCode);

}

}

}

}

return Status;

}

Protection mechanism is pretty simple. So I decided to implement it from user-mode for other versions of Windows operation system. It was one day of pure fun :) what actually my code does is monitoring ESP value each time a memory management function is called, just like the kernel! And in case of anomaly, rise the STATUS_STACK_BUFFER_OVERRUN exception.

Note 1: This is a 32bit version of the program. You need to manually inject it into your desired process (or use AppInit_DLLs to do it globally).
Note 2: check out Dan Rosenberg blog to see how easy it is to bypass this mitigation ;)

Download RopDosham

Demo