In this article, we will learn how DEP works and what are the most common exploitation techniques to bypass it.

Data Execution Prevention or DEP is a technique that allows us to set certain pages of memory as non-executable, meaning the code placed there will not be run. This is useful for defeating against attacks that try to supply shellcodes with user's input, for example into heap or stack. Following the W^X principle, common data segments like stack, heap, .bss, .ro, .data will be set as writable but not executable and common code segments such as .text, .plt will be set as executable, but not writable.

DEP is implemented both in hardware and software.

Hardware-enforced DEP relies on processor hardware to mark memory with an attribute that indicates that code should not be executed from that memory. The bit is called Execute Disable Bit (XD) in Intel CPUs and no-execute page-protection (NX) in AMD CPUs. On Intel, it's only available with the long mode (64-bit mode) and legacy Physical Address Extension (PAE) page-table formats.

To understand where this bit is located, we need to review how MMU maps a virtual address to physical memory on IA32. Generally, the physical memory is divided into 4KB chunks (could be greater, but no matter for now). Virtual addresses are what each process sees and uses to reference functions and data in its machine code. At the background, the system takes the address and maps it to the physical address by traversing 3 tables and an offset (on Intel w/ PAE extension): Page Directory Pointer Table, Page Directory, Page Table and Page Table Entry.


To map a virtual address 0xBF80EE6B, the system will use its bits to find the physical record. For example, 0XBF80EE6B is 10111111100000001110111001101011 in binary.
First 2 bits (10) will point to an index into PDPT
Next 9 bits (111111100) will point to an index into PD
Next 9 bits (000001110) will point to an index into PT
And finally, the rest 12 bits (111001101011) will indicate the page offset.


This can be summarized with Paging Structure table from Intel manuals. As you can see, bit 0x63 (XD) can be set on both PD and PT, allowing for some granularity. Here, higher granularity specifications of XD override finer granularity.

Software-implemented DEP is very limited in its functionality. All it does is protect Window's exception handling by not allowing exception handlers to be placed on the stack or heap (Sounds like SafeSEH, doesn't it?). Luckily all modern CPUs support hardware-enforced DEP.

Applications can use the VirtualAlloc function to allocate executable memory or VirtualProtect to change the protection on a region of committed pages in the virtual address space. Both could be found in Kernel32.dll. It's also possible to set permanent DEP with SetProcessDEPPolicy which will call NtSetInformationProcess so that any attempt to change NX/XD bits will result in STATUS_ACCESS_VIOLATION exception.

How to bypass

Bypass DEP w/ ROP Chains

The idea behind this approach is to call a system function that will let us bypass DEP by either turning it off or moving to an already executable location.

Here is the menu of the most useful functions for bypassing DEP (some may or may not be available in a specific version of Windows):

VirtualAlloc - reserves, commits or changes the state of a region of pages in the virtual address space of the calling process. This approach means we will create a new heap, copy our shellcode there and execute it.

HeapCreate - creates a private heap object that can be used by the calling process. The function reserves space in the virtual address space of the process and allocates physical storage for a specified initial portion of this block. Same as VirtualAlloc but requires more API calls to succeed.

SetProcessDEPPolicy - changes data execution prevention (DEP) and DEP-ATL thunk emulation settings for a 32-bit process when DEP Policy is set to OptIn or OptOut. With this function, we can turn off DEP and execute shellcode from the stack.

NtSetInformationProcess - undocumented internal function. Allows you to change the DEP policy for the current process so you can execute your shellcode from the stack.

VirtualProtect - changes the protection on a region of committed pages in the virtual address space of the calling process, for example, by marking the location where shellcode is written as executable.

WriteProcessMemory - writes data to an area of memory in a specified process. The entire area to be written to must be accessible or the operation fails. This function can be used to write shellcode into an executable location.

To call this functions we will need to use Return Oriented Programming (ROP) to set up a chain of ROP gadgets. ROP takes advantage of already existing binary code in the target application. Each binary snippet usually follows the "useful code + return instruction" format: xor eax, eax ret; pop ebx pop eax ret. By chaining those together, we can execute our malicious code.

  _In_opt_ LPVOID lpAddress,
  _In_     SIZE_T dwSize,
  _In_     DWORD  flAllocationType,
  _In_     DWORD  flProtect

For example, if we want to use VirtualAlloc function, we need to push arguments onto the stack in the right order, get the function address and call it. If we search through the target application's code space, we usually can find a number of gadgets to achieve this.

JIT Spraying

To prevent people from messing with DEP on/off switch, Microsoft turned on permanent DEP on IE8. Fortunately, IE, like all other browsers has support for scripting languages, like JavaScropt, ActionScript, Flash, etc. And due to their just-in-time compilation nature, these browsers have to write bytecode into executable data regions. Dionysus Blazakis was the one to research this technique and told everyone about it on Blackhat 10.
The idea behind JIT Spraying is to generate malicious bytecode by writing some java/action script and letting the jit compiler to write it onto the heap. Now if we can redirect execution to that part of memory, it will be executed even if DEP is turned on.

For example, if we have a simple JS code:

function jit() {
var y= ( 
    return y;

Javascript on Safari 4.0.5 will convert it into the following bytecode right after we call jit():

XOR EAX, 33333333
JNZ 04450573
XOR EAX, 44444444

Safari also had a Use-After-Free vulnerability, but for the purposes of this article let's just mention that it allowed us to redirect execution to any address in memory. Now, with DEP enabled, that wasn't very fruitful as we could not execute code from the stack, instead, JIT Spraying was required.

The idea is to execute our jit() function many times to fill out the memory with compiled XOR bytecode. If the XOR string is long, the address assigned to each jit block will end with 0xXXYY0000. If the number of blocks is high, we can try to predict the XXYYs.

The trick with XXYYs is due to ASLR - it randomizes the address space, but only for the very first call of the jit() function. Later, if each consecutive JIT block is less than 0x010000, the memory will grow linearly, e.g. 0x06060000, 0x06070000, 0x06080000, etc. We then find the first XOR op address that won't have null bytes in it, which for Safari happened to be 0x0104 (this happens to be the 10th argument to the jit function). If we redirect the code somewhere in the middle of the memory, for example to 0x060800104, we will have a place to put our shellcode which will be executed.

I am planning on writing a dedicated article about JIT Spraying and modern browser exploitation later, so stay tuned and subscribe to all the things.

Part 1 - Windows Defender Exploit Guard for Pentesters - Validate Exception Chains (SEHOP)
Part 2 - Windows Defender Exploit Guard for Pentesters - ASLR
Part 3 - Windows Defender Exploit Guard for Pentesters - DEP
Part 4 - Windows Defender Exploit Guard for Pentesters - CFG
Part 5 - Windows Defender Exploit Guard for Pentesters - CIG & ACG