Not everything is executable: NX bit and Data Execution Prevention

The idea of non-executable memory regions was introduced in late 90’s when the special exploitation techniques used buffer overflow vulnerabilities to attack the operating systems. To secure the operating system from such attacks, Microsoft implemented this security measure starting with two of their products: Windows XP SP2 and Server 2003. The implementation is known as ‘Data Execution Prevention‘ or DEP in short. The assumption behind the design was that by making certain regions of the memory as non-executable, we can prevent the break-ins to the system by malicious attackers. Many techniques on how to bypass the DEP has already been explored and available in public. In this article, we take a look at the internals of DEP mechanism which would help the developers, IT admins and reverse engineering community. Readers are expected to know basics of address translation.

DEP Is applied in two parts:

  • Hardware-enforced DEP makes use of the NX bit to mark the memory page no-execute if it does not have code. This one requires processor supporting the NX bit.
  • Software-enforced DEP is introduced to block programs that take advantage of exception handling mechanisms in windows. This one is independent of the hardware so runs on any processor.

The implementation of DEP is transparent to the user and enforced by the applications and services. Hardware-enforced DEP marks the memory pages as executable or non-executable by changing the state of NX bit. Marking the memory page as non-executable means, you cannot run the code from these memory pages and any attempt would result in memory access violation exception. This also implies that a memory page cannot be executable and writable at the same time.

Note: AMD defines it as no-execute page-protection (NX) processor feature and Intel defines it as Execute Disable (XD) bit feature.

Where is NX bit?

NX bit comes into picture with Paging mechanism in PAE mode. Figure below shows the translation table entry (Page Table Entry (PTE)) layout in non-PAE mode, PAE mode and Long Mode(x64 architecture).

The NX bit in PTE specifies if the instruction can run from the page (defined by PTE) or not. Code execution from the page for which NX bit is set would result in page fault (Exception).

NX bit (if CPU supports it) is available for use in x86 architecture (PAE mode) and in x64 architecture. In x86 architecture, CPUID instruction can be used to query the Extended Processor Info and Feature bits to check if processor supports this feature. The non-PAE mode PTE does not have NX bit as shown in the figure above and PAE mode should be turned on to make use of this feature.

In x64 architecture, translation table entry size is 64 bit by default however you have to Enable NX feature by setting the NXE (No-Execute Enable) bit in EFER (Extended Feature Enable Register). It is one of the MSR (Model Specific Register).

You can dump the MSR by providing the register address. The EFER register address is C0000080h.  

0: kd> rdmsr C0000080
msr[c0000080] = 00000000`00000d01

 Value ‘d01’ can be expended into binary as:

00000000 00000000 00000000 00000000 00000000 00000000 00001101 00000001

Following bits are set:

Bit 0 – System Call Extension Bit. Setting this bit to 1 enables the SYSCALL and SYSRET instructions.
Bit 8 – Long Mode Enable(LME) Bit. This enables the long mode however if long mode is active or not is decided by LMA bit (bit 10) which processor enables when Paging is enabled. So to Enable Long mode Paging is required.
Bit 10 – Long Mode Active(LMA) Bit. Processor enables this bit when LAE and Paging is enabled. When LMA is 1, processor is either in Compatibility mode or 64 bit mode. It depends on the value of L bit CS descriptor.
Bit 11 – No-Execute Enable(NXE) Bit.

If the NXE bit is disabled in EFER, a Page Fault would occur if NX bit is not cleared in PTE. The NX bit controls the page execution capability from all the pages mapped by the PTE i.e. NX bit in Map level 4 in x64 Paging, controls all the pages (512*512*512 = 128MB) referred by the table entry. An exception to this is the PAE mode PDPT (Page directory pointer table) which does not contain this bit. The NX bit, if supported by processor is not dependent on processor privilege level.

In short:

  • No-Execute feature is processor specific.
  • The feature is available in PAE mode in x86 architecture (32 bit PTEs don’t have NX bit available) or in Long mode. So even if processor supports it, the non-PAE mode cannot use this feature.
  • No-Execute protection is offered on per-Virtual Memory page basis.
  • The x64 architecture has PTE size of 64 bit so this feature is available by default (almost all processors support it today).
  • If NX bit is supported, windows automatically enables PAE mode to support Hardware-enforced DEP.

The DEP Policy

DEP can be explicitly enabled or disabled for a specific process however this is controlled by DEP policy.

Settings for current policy is stored in _KUSER_SHARED_DATA which is generally stored @fffff78000000000 in x64 architecture and @ffdf0000 in x86 architecture or you can use the ‘!kuser’ WinDbg Command to get the shared user-mode page and its Virtual Address location.

0: kd> !kuser
_KUSER_SHARED_DATA at ffdf0000
TickCount: fa00000 * 0000000000005e82 (0:00:06:18.031)
TimeZone Id: 0
ImageNumber Range: [14c .. 14c]
Crypto Exponent: 0
SystemRoot: ‘C:\Windows’

0: kd> dt _KUSER_SHARED_DATA ffdf0000 -y nx
+0x2d5 NXSupportPolicy : 0x2 ”

 In GetSystemDepPolicy API, ‘NxSupportPolicy’ is at offset ‘2d5’ as shown above.

0:000> uf kernel32!getsystemdeppolicy
00000001`800ded50 0fb60c25d502fe7f movzx ecx,byte ptr [SharedUserData+0x2d5 (00000000`7ffe02d5)]
00000001`800ded58 33d2 xor edx,edx
00000001`800ded5a 83e103 and ecx,3
00000001`800ded5d 741d je kernel32!GetSystemDEPPolicy+0x2c (00000001`800ded7c) Branch

 Based on the DEP policy settings you can explicitly enable\disable the DEP for a Process (executable).

0: kd> !process 0 0 lsass.exe
PROCESS 85275d40 SessionId: 0 Cid: 025c Peb: 7ffdf000 ParentCid: 01e4
DirBase: 3ec33100 ObjectTable: 96322f08 HandleCount: 534.
Image: lsass.exe
0: kd> dt nt!_KPROCESS 85275d40 flags
+0x06c Flags : _KEXECUTE_OPTIONS
0: kd> dt nt!_KPROCESS 85275d40 Flags.
+0x06c Flags :
+0x000 ExecuteDisable : 0y1
+0x000 ExecuteEnable : 0y0
+0x000 DisableThunkEmulation : 0y1
+0x000 Permanent : 0y1
+0x000 ExecuteDispatchEnable : 0y0
+0x000 ImageDispatchEnable : 0y0
+0x000 DisableExceptionChainValidation : 0y1
+0x000 Spare : 0y0
+0x000 ExecuteOptions : 0x4d ‘M’

NX Compatibility of PE files

During compilation and linking process, a section can be marked as execute as shown below. Also, /NXCOMPAT flag is by default enabled. Loader makes use of the IMAGE_SECTION_HEADER Characteristics flag IMAGE_SCN_MEM_EXECUTE and IMAGE_DLLCHARACTERISTICS_NX_COMPAT flag in Optional Header DllCharacteristics to set the execution options for the process being spawned\initialized. If processor supports NX bit and Hardware-enforced DEP is enabled via DEP policy and Process is not excluded explicitly then during process creation OS makes sure that PE sections containing data are on the pages with NX bit set in the PTE which is pointing to these data pages. In short, any execution from the data pages from the process address space will result in exception.

ATL (Active Template Libraries) has code present inside data section so we need to make sure correct Process specific DEP policy (PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION) is applied else it would result in exception.

Note: Only OptIn and OptOut policy settings allow explicit setting of DEP for Process.

1: kd> !dh ntdll
10B magic #
9.00 linker version
D4600 size of code
63200 size of initialized data
0 size of uninitialized data
0 address of entry point
1000 base of code
—– new —–
77070000 image base
1000 section alignment
200 file alignment
3 subsystem (Windows CUI)
6.01 operating system version
6.01 image version
6.01 subsystem version
13C000 size of image
400 size of headers
14033F checksum
00040000 size of stack reserve
00001000 size of stack commit
00100000 size of heap reserve
00001000 size of heap commit
140 DLL characteristics
Dynamic base
NX compatible
.text name
FA0C9 virtual size
1000 virtual address
FA200 size of raw data
400 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
60000020 flags
(no align specified)
Execute Read

In windows Software-enforced DEP is used only for exception handler chain validation. I will discuss it in another post related to exception dispatching and handling.

Leave a Reply

Your email address will not be published. Required fields are marked *