The following is based upon research conducted on Win7 SP1 64-bit.
A process can change its own execute flags e.g. ExecuteDisable or DisableThunkEmulation
by calling the "ZwSetInformationProcess" function with the "ProcessInformationClass"
parameter to ProcessExecuteFlags 0x22.
In Wow64 processes:
This is usually done at process startup within the "LdrpInitializeProcess" function.
The "LdrpInitializeProcess" function checks to see if the "IMAGE_DLLCHARACTERISTICS_NX_COMPAT"
flag is set in the PE header. If set, permanent DEP is assumed. The function also checks to
see if SEHOP is applicable to the process based upon the global settings, IEFO registry value,
and MajorLinkerVersion and MinorLinkerVersion of image. Finally the call to the
"ZwSetInformationClass" function is issued passing the collected info. to the kernel via the
Since the process of collecting info. is done is usermode, we can manipulate the
value passed to the system call to be zero and the call will succeed!
The "NtSetInformationProcess" function ensures that the function call acts only on itself i.e.
the "hProcess" parameter is set -1, otherwise the call is rejected.
Then a call to the "KeSetExecuteOptions" function is made to reflect the new value passed into
the "_KPROCESS" structure in a substructure called "_KEXECUTE_OPTIONS", which looks like below.
unsigned char ExecuteDisable:1;
unsigned char ExecuteEnable:1;
unsigned char DisableThunkEmulation:1;
unsigned char Permanent:1;
unsigned char ExecuteDispatchEnable:1;
unsigned char ImageDispatchEnable:1;
unsigned char DisableExceptionChainValidation:1;
unsigned char Spare:1;
The "KeSetExecuteOptions" function ensures that no spare or unused bits are set, otherwise
an error STATUS_INVALID_PARAMETER (0xC000000D) is returned.
The function also ensures that the process is 32-bit (Wow64), otherwise (Native64) an error
STATUS_INVALID_PARAMETER (0xC000000D) is returned.
Before going any further, the function ensures that the "Permanent" bit is not set, otherwise
an error STATUS_ACCESS_DENIED (0xC0000022) is returned. The rest can be expected except that:
1) If "ExecuteDisable" is supplied as 1, the "ExecuteEnable" is unset.
2) If "ExecuteEnable" is supplied as 1, the "ExecuteDispatchEnable" and "ImageDispatchEnable"
are set as such.
Once the "KeSetExecuteOptions" function returns a non-error, the "MmRemoveExecuteGrants"
function is called if the "ZwSetInformationProcess" call was made to set ExecuteDisable.
The whole thing is ignored and the "_KEXECUTE_OPTIONS" structure is left blank.