Towards Automated Discovery of
Crash-Resistant Primitives in Binary Executables
Benjamin Kollenda1 Enes Göktaş2 Tim Blazytko1 Philipp Koppe1 Robert Gawlik1 R.K. Konoth2
Cristiano Giuffrida2 Herbert Bos2 Thorsten Holz1
1

Horst Görtz Institut for IT-Security (HGI), Ruhr-Universität Bochum, Germany
2Computer Science Institute, Vrije Universiteit Amsterdam, The Netherlands

timing side channels [21]. However, unless the attackers
reduce the entropy to zero, the final step in these attacks
on randomization still relies on trial and error, with a highlikelihood of crashes.
Today’s successful attacks against the residual entropy buildon the observation that various server applications automaticallyrestart upon a crash, enabling an attacker to repeatedly probe theaddress space in a brute-force manner [13]. Hence, recent work
proposed a variety of improvements to mitigate the attacks [30].
In this paper, we assume that information hiding is perfect, allof the proposed improvements against disclosure attacks arein place, the attacker cannot completely drop all entropy, andthe only way to find sensitive information is by performing acrashless brute-force attack. As a result, an attacker needs tofind novel crashless ways to bypass such sophisticated defenses.
If the target application has code fragments that do not crashwhen reading from or writing to inaccessible memory (because
they handle such violations themselves, say, in an exception
I. I NTRODUCTION
handler), attackers may use these fragments to probe for the
While arguably a weak defense by itself [42], address space secret information repeatedly. This technique was introduced
layout randomization (ASLR) plays a pivotal role in almost all by Gawlik et al. [22]. We define crash-resistant code as code
modern defenses that hide sensitive information at a random that will not crash the program upon an invalid memory access.
location in memory. ASLR can be categorized as a basic form It is markedly different from crash-tolerant code where a serverof information hiding, namely randomizing the location of application immediately re-forks worker processes or a web
code images, heaps and stacks in the address space. However browser re-opens a tab after a crash happened. While crashadvanced defenses increasingly rely on the information hiding tolerance can serve as a vector for attacks, it is much noisierprimitives provided by ASLR to (pseudo-)protect sensitive data and thus less attractive than crash resistance—thousands ofsuch as encryption keys [31], code pointers [17], [28], and crashes in a short amount of time may easily raise alarms inredirection tables [9]. If implemented properly, even attackers real-world scenarios. In contrast, crash resistance incurs nowith full read-write access over the process’ memory will not crashes at all and is therefore much stealthier.
Note that crash resistance in its intended form is a classic
be able to access the sensitive data, because they are tuckedaway at random memory locations in a huge address space. double-edged sword. On the one hand, it enhances software
Since the process memory will not contain a single pointer reliability and enables applications to automatically recoverto the hidden region(s), the only way for an adversary to get from malformed inputs that cause an access violation, also
to the secrets is by trial-and-error. It is almost certain that improving user experience. On the other hand, it permits attacksuch attempts will quickly access unmapped memory, which ers to abuse the crash-resistant code snippets, dubbed memory
normally incurs a crash. Hence, the sensitive information is oracles, to probe the address space [22] and even entropyreducing attacks have used such crash-resistant probes [24].
believed to be safe from attackers [31].
State-of-the-art attacks on information hiding try to reduce Note that the underlying principles of each memory oracle
the entropy of the randomization as much as possible. For can vary greatly. They can range from system level exception
instance, they trick the program into increasing the size of handlers, over system calls to application specific exception
the hidden region [24], or into performing gigantic memory handling.
allocations [35], or into leaking information via sophisticated
Unfortunately for attackers, finding crash-resistant primitives
Abstract—Many modern defenses rely on address space layout randomization (ASLR) to efficiently hide security-sensitive
metadata in the address space. Absent implementation flaws, anattacker can only bypass such defenses by repeatedly probing theaddress space for mapped (security-sensitive) regions, incurring
a noisy application crash on any wrong guess. Recent work showsthat modern applications contain idioms that allow the construction of crash-resistant code primitives, allowing an attacker toefficiently probe the address space without causing any visible
crash.
In this paper, we classify different crash-resistant primitives
and show that this problem is much more prominent thanpreviously assumed. More specifically, we show that rather
than relying on labor-intensive source code inspection to finda few “hidden” application-specific primitives, an attacker canfind such primitives semi-automatically, on many classes of realworld programs, at the binary level. To support our claims,
we develop methods to locate such primitives in real-worldbinaries. We successfully identified 29 new potential primitives
and constructed proof-of-concept exploits for four of them.

in real-world software is labor-intensive, manual work. Given
their underlying mechanisms and use these properties asa new application, finding such a specific primitive is difficult
a way to identify additional instances of memory oracles.
and rare, especially in the absence of source code. Thus, in its• We show that it is possible to discover (otherwise
original form, the approach was difficult to use in a genericextremely hard-to-find) crash-resistant code primitives
way across many applications. Furthermore, the concept wasin an automated fashion in both client applications on
thought to be only applicable to client applications.
Windows and servers on Linux.
In this paper, we present semi-automated methods to locate• We are the first to find and use crash-resistant codecrash-resistant primitives in a given binary executable and genprimitives on server applications. In contrast to crasheralize the basic concept of crash resistance by demonstrating
tolerant approaches, which simply exploit the fact thatthat the method is also applicable to server applications. Basedserver applications typically restart upon a crash, ouron our observation of the root cause for the crash-resistanttechnique offers much more flexibility and stealthinessprimitives, we developed two different strategies on how tofor an adversary.
locate further instances of them in binary executables. Both
• We evaluated our techniques on five popular servers andserve as a starting point for fully automated identification of
two browser applications and found 29 new crash-resistantsuch primitives and we demonstrate that our methods canprimitives, of which we developed four into fully fledged
find them quickly in a number of real-world server and client
proof-of-concepts. In addition, we discuss how attackers
applications on different platforms. While our techniques docan exploit these primitives to bypass any defense utilizing
not produce fully-fledged memory oracles in an automatedinformation hiding.
way, we substantially reduce the engineering work required toII. BACKGROUND AND R ELATED W ORK
analyze a given binary executable. More specifically, we areable to identify in an automated way code constructs that canIn the following, we provide a brief overview of the technicalserve as crash-resistant primitives.
concepts we use in the rest of this paper to classify crashThe first approach targets the interface between a user- resistant primitives and detect them in an automated way.
mode program and the kernel, such as system calls on Linuxor API calls on Windows. This builds on the intuition that A. Crash-resistant Primitives
many such calls allow the kernel to respond to an invalid
Several papers [13], [21], [41] have shown that serveruser address given as a parameter by returning an error code applications are vulnerable to guessing attacks against defenses(without crashing) to user space. We leverage taint analysis based on randomization due to their crash-tolerant nature, i.e.,
to track which bytes in attacker-controlled memory eventually a network service typically restarts in an automated way upondetermine the appropriate parameters in calls that fit crash a crash. This enables an attacker to perform brute-force attacks
resistance (e.g., system calls that return -EFAULT on access and eventually reach her goal. On the downside, the induced
faults). Intuitively, by modifying these memory locations, the crashes are noisy and a defender might easily notice a server
attacker may probe the address space—assuming that the application crashing thousands of times in a small amount ofprogram does not also dereference the address outside the crash- time. Such attacks relying on crash-tolerant code were believed
resistant code fragment. We explore this idea for both server to not affect client applications given their hard crash policy:
applications on Linux and client applications on Windows to client programs usually do not restart after a crash and thus an
study if this approach is feasible in practice.
attacker is limited to a single try to bypass a given defense.
The second approach targets exception handling code, since
A new twist on crashes was proposed by Gawlik et al. [22],this is a common technique to guard program code and respond who demonstrated that so called memory oracles can beto error conditions—hence a prime candidate for crash-resistant leveraged to probe arbitrary memory regions and discovercode. We look for code structures that paper over access reference-less memory. The authors showed two examples ofviolations, thus yielding candidates for crash-resistant code such primitives: one usable in Internet Explorer which abuses awhich we subsequently vet. In a first step, we extract the system feature, and one in the 64bit version of Firefox which is
exception handlers from a binary and then use symbolic based on a program specific performance optimization involving
execution to determine which ones handle access violations. exception handlers. Furthermore the authors noted that some
Given that exception handling is commonly used for client system calls, like access, might be usable as memory oracles.
applications on Windows [22], we focus our analysis on such In this paper we build on these findings to define categories
programs.
of memory oracles and develop tools that aid in the search for
Using these two methods we successfully found 29 new similar primitives.
crash-resistant primitives in popular server applications andweb browsers. We also developed four primitives found in B. Information Hiding Defenses
Nginx 1.9, Lighttpd 1.4, Internet Explorer 11 and Firefox 46
Software-based fault isolation (SFI [20], [45]) is a techniqueinto proof-of-concept exploits to demonstrate the effectiveness that allows code to be executed with strong safety andof our approach.
security guarantees by adding checks to critical operations
such as memory accesses or control flow transfers. Similarly,
In summary, we make the following four contributions:• We classify known crash-resistant primitives based ontechniques like SoftBound [34] or baggy bounds checking [7]2enable memory safety, preventing many attack vectors in a However, as crash resistance allows scanning the whole address
generic way. Unfortunately, the overhead induced by such space, the stack can be located [24] and the return addresses
approaches is prohibitively high in practice [43], which prevents overwritten.
a widespread adoption. As a more efficient alternative, several
Another recent defense that aims to protect against meanrecent defenses [9], [17], [28], [31] rely on information hiding ingful control flow hijacks is ASLR-Guard [31]. The mainto prohibit an attacker from obtaining valuable information concept is that an attacker is rendered unable to retrieve asuch as encryption keys, code pointers, and redirection tables. plain text code pointer, so any control flow hijack attack is
However, any defense based on information hiding is at risk reduced to pure chance. This is achieved by (i) removing links
in the presence of crash resistance. Most prominently, address between data pointers and code pointers and (ii) encoding any
space layout randomization (ASLR) can be bypassed as it code pointers stored to data memory. The first countermeasure
is possible to either locate the memory location of a library ensures that a data pointer leak (which is explicitly allowed
directly or instead locate otherwise reference-less structures within the threat model) gives no indication of the location ofthat contain pointers to loaded binary images. For example, executable code. With the common form of ASLR the address
on Windows this is the case for thread information blocks of the data section, which can be located by the attacker, allows(TEBs) and process environments blocks (PEBs), two data inferring the location of executable code of the same module
structures which allow an attacker to retrieve the location by simply adding a static offset. The first countermeasure isof all loaded modules. In practice, however, information combined with a pointer protection scheme that never writes
leaks providing the location of code images are common. In plain text code pointers to data locations. This includes mostcontrast, inferring addresses of data structures belonging to prominently the stack, which can be located and leaked bystronger defenses beyond ASLR is not commonly possible. an adversary. However, using a crash-resistant primitive, it isSuch advanced defenses typically assume an attacker equipped possible to just probe memory until the executable code iswith an information leak—and thus full knowledge of the found. An attacker does not need to infer the location frommemory layout of the process—with the exception of the either data pointers or saved code pointers: after the executable
meta data structures of the defense in question. Commonly, code has been located, known attacks like JIT-ROP [42] canthis is implemented by only keeping the addresses to these be used again.
structures in a register and preventing any write of this value toApart from models that merely restrict an attacker’s knowlmemory. Without knowledge of the exact location, an attacker edge of the memory layout, some defenses impose additional
can thus not overwrite the data and the defense can enforce properties on the memory. The principle of execute-only
certain properties on the protected program. Examples of such memory (XoM) [8], [23] allows for an additional access right,
advanced defenses are Code-Pointer Integrity (CPI) [28] and in contrast to the standard of execute access implying read
any Control Flow Integrity (CFI) solution relying on a shadow access. Without the possibility of reading the code, an adversary
stack [14], [17] to protect backwards edges. Armed with crash has no way of determining the actual bytes used to implement
resistance, an attacker can locate the hidden region of CPI (both a given functionality. If this technique is combined with somethe sparse region and the hash-table based implementation [22]) form of fine-grained ASLR, it prevents code-reuse attacks
and modify the metadata of any pointer. This means that the requiring knowledge about the exact code either statically,
main assumption of CPI, namely that the pointer metadata e.g. ROP [38], or at run time, e.g. JIT-ROP. Against theseof any code pointer cannot be modified by an attacker and defenses, memory oracles are less useful as probing primitives
thus any use of crafted pointers is prevented, no longer holds are mainly utilized to locate memory, whereas XoM does nottrue. A similar attack is possible for shadow stack-based CFI use any information hiding in this regard. As such, when using
solutions. These solutions hide the location of the shadow stack plain probing attempts, the result of trying to read code wouldfrom the attacker by using, for example, a dedicated register still indicate inaccessible or unmapped memory. However,or thread local storage. If an attacker can find the stack via with crash-resistant primitives that allow broad capture ofcrash-resistant probing, she can modify the information stored any exception, it could be possible to brute-force the code
there.
layout. A similar attack might be possible against sophisticated
The same holds true for implementations that instead of using defense solutions such as Readactor [15] and Readactor++ [16],a dedicated shadow stack rely on separating safe and unsafe which focus on both hiding code pointers from an attacker andstacks. The SafeStack [28] implementation by CPI, which is enforcing XoM.
now included in LLVM, provides such a feature and uses theAn important type of defense that can hamper the successnative stack only for statically proven safe variables. This means of memory probing is runtime re-randomization [9], [12].
an attacker cannot overflow a local stack variable to overwrite Employing runtime re-randomization can substantially decrease
return addresses. Additionally, the compiler ensures that no the success probability of either the scanning itself or thereferences to the SafeStack are written to memory outside following attack step. Due to the “moving target”, it is harderof the SafeStack itself, resulting in a reference-less memory for an attacker to locate the code she needs and at the same
region. As return addresses are located on the SafeStack, a time abuse it within the time constraints given by the defense.
control-flow hijack based on overwriting return addresses is no However, crash-resistant primitives that allow invalid executions
longer applicable, without being able to pivot the stack pointer. to be recovered can also weaken the security guarantees of3

these defenses: given enough tries, such schemes can likely be
bypassed due to the chance of using the right randomizationin the attack attempt.

the control flow by overwriting code pointers or other sensitive
pointers. In practice, it may be necessary to carry out (parts of)the sequence multiple times in order to bypass multi-process
sandboxing schemes or to escalate the privileges of the user.
We assume that a defense relying on information hiding, forexample one of those discussed in Section II-B, is employedby the target application. Thus an attacker needs to leverage acrash-resistant primitive in the second attack phase with thehelp of the following steps (Figure 1):
1) Overwrite a value in memory: the attacker uses a memory
corruption primitive to prepare the memory for the next
step, usually overwriting pointers to data which are thenprobed later; modifying data can cause usually benign
functions to exhibit unintended/malicious behavior.
2) Trigger execution of probing: the attacker forces the
program to execute the probing primitive. This is trivial via
a control-flow hijacking attack, but we focus on locating
primitives legitimately accessible to the attacker, e.g.,functions in a scripting environment.
3) Infer the state of the probed location: finally, the attacker
requires an indication whether or not the probing attempt
succeeded. In the easiest case, this is directly inferredfrom a return value or similar information, but usually
the attacker needs to infer the state indirectly, e.g., via
memory changes or execution timings.
These steps can be repeated several times to probe othermemory locations until enough information about the memory
layout is known to the attacker.
In the remainder of this section, we describe our classification of crash-resistant primitives and outline how we locate
additional candidates in a (semi-)automated way for each type.
Note that we do not cover functionality intended for querying
the memory layout of a process, such as the /proc file system
under Linux or functions like VirtualQuery or IsBadReadPtr
on Windows.

C. Threat ModelIn the following section, we introduce several techniques todetect crash-resistant code within a given binary executable.
Several conditions must hold for these code snippets to be
useful for an attacker. To this end, we assume the following
threat model in the rest of this paper, which is realistic andmatches the capabilities of a real-world attacker. Further, it
is consistent with recent research [15], [16], [18], [33], [40],[42]:• Arbitrary read/write primitive: The attacker can readfrom and write to arbitrary memory locations.
• Information leak: An information leak allows the adversary to infer the location of data protected via some kindof randomization scheme such as ASLR. For example, theadversary can locate the base address of module locations,but she cannot access reference-less memory locations.
• Computational capabilities: The attacker can perform
computations during the attack. This can be some formof scripting environment on the client side or a server accepting multiple connections. The latter allows an attacker
to query the state of the server with one connection andact on this information with another one.
• Writable ⊕ Executable memory: Memory pages aremarked as either executable or writable, but not both at
the same time.
• State-of-the-art defenses: The target application employssome kind of state-of-the-art defense to thwart code-reuseattacks. This can be either an information hiding schemesuch as a shadow stack-based CFI approach, or some kindof defense to prevent control-flow hijacking attacks such
as CPI.
• Hard crash policy: The application does not automatically restart after a crash. This includes automaticallyrestarting a crashed worker process or a user opening a
website again.

A. Syscalls and OS API Functions
Modern operating systems allow for the quasi-parallel
execution of different, isolated user space processes. This alsomeans that a fault in a single program must not cause anotherindependent program or the whole system to fail. This isachieved by handling errors, e.g., invalid memory accesses, ona per-program basis. However, once a program needs to passdata to the operating system, any error in this data (or often in
the case of a memory error, in the location of this data) can

III. H IGH -L EVEL OVERVIEW
In code-reuse attacks, the exploitation procedure of memory
corruption vulnerabilities can be subdivided into three phases.
Initially, the attacker leverages a memory corruption vulnerability to establish a read/write primitive. Depending on thekind of vulnerability, an attacker may be able to read some
out-of-bounds bytes in order to disclose some information
about the address space layout, or leverage some other kind of
information leak. In the second phase, the attacker prepares thepayload, for instance, by relocating a static ROP chain [38], thecounterfeit objects of the COOP attack [40], or by compilinga JIT-ROP chain [42]. Meanwhile, it may be necessary forthe attacker to also bypass code-reuse defenses such as finegrained randomization [11], [26], [46], shadow stack-based CFI
solutions [14], [17], CPI [28], and other information hidingbased approaches [9], [18], [31]. Finally, the attacker hijacks(returns EFAULT if address not valid)

recv (fd, A, ...)
step 2:
make program use the pointerin crash tolerant function

A
step 1:change pointer in memory

step 3:check for success ofthe probe operation

Figure 1: Attacker’s procedure to probe memory without crashing4

potentially impede the stability of the whole system. As such,whenever data is passed from user space to kernel space, theOS must perform strict error checking.
To allow an application to react to an error in its data,a failure state is usually returned. If this event is properly
handled, the application can resume execution. However, inthe case of a scanning attempt, this property can leak valuable
information to the attacker. If she is able to influence the data
in a way that causes a failure state to be reported for invalid
addresses and success for valid ones, she is able to probe theaddress space and uncover hidden memory regions. The actual
implementation of such a primitive is heavily OS dependent,
however it is applicable to any program allowing manipulationof input data and inferring the error state afterwards.
On Windows systems, the OS exposes a set of system
API functions which are then translated to system calls
after preprocessing in user space. The result is an often
heavily abstracted interface to the underlying syscalls. This isproblematic in the context of memory probing, because anyaccess to the supplied memory region can lead to a fault inuser space, preventing the OS from gracefully reporting theerror state to the program. In contrast to this, programs runningon Linux are free to access syscalls directly or with minimal
abstraction. While both system operate on a similar principle—
a specified interface is provided for the user programs—we hadto account for the differences and chose to develop different
techniques for the Windows system API and Linux syscalls.
1) Linux syscall interface: The Linux kernel exposes a setof well documented syscalls to the user space. These are used
to perform kernel-level functionalities from user space, such as
file- or network-related operations, and memory management.
In case an error occurs during a syscall, the kernel returns -1
to the user process to indicate that something went wrong andassigns the appropriate error code to the errno variable in user
space.
Several syscalls require the application to provide pointers tomemory in user space such that the kernel can read data from orwrite data to that area. In case the address is invalid, the kernel
sets the errno variable to EFAULT [5], which indicates thatthe memory location is not accessible. EFAULT is a common
error code that many popular system calls use. Examples
include connect, read, write, epoll_wait, recvfrom, open,
and many others. If an attacker has control over the memory
address of the relevant syscall parameter, she can potentiallyprobe the address space for accessible memory areas withoutcrashing the application.
For instance, many servers contain a main loop like this:
1
2
3
4
5
6
7
8

An attacker who is able to control the buf pointer can provide
any address and discover whether or not it is valid. Note thatthe server will not crash.
The detection of crash-resistant candidates can be automatedas follows. Because of their relevance for crash-resistantprobing candidates, we maintain a list of all syscalls that
may return EFAULT and monitor their occurrence during an
instrumented, automated execution. We use taint analysis to
identify which parameters can be influenced by an attacker
and execute unit tests to analyze which syscalls can potentiallybe executed during a run of the application. As a result, we
obtain a list of potential candidates.
2) Windows API: In contrast to Linux, user-mode
applications on Windows exclusively utilize the API
provided by the operating system [39]. As a result, Windows
never exposes the system calls directly to the application.
Nevertheless, the same method outlined above can be applied:
if an API function accepts a pointer as an argument and an
attacker can control this pointer, she can point it to arbitrary
memory addresses and observe the return value or side effects
to infer the resulting state. An example for this concept is the
API function VirtualQuery, it is used to obtain informationon the state of a memory address. If an attacker is able tocontrol the argument ptr and knows the location of mem info,
she can probe any page for its state and permissions:
1
2
3
4
5

void * ptr = NULL ;PMEMORY_BASIC_INFORMATION mem_info = malloc ( sizeof (MEMORY_BASIC_INFORMATION ) ) ;...
VirtualQuery ( ptr , mem_info , sizeof (MEMORY_BASIC_INFORMATION ) ) ;...

Listing 2: Example for VirtualQuery API call on Windows

While VirtualQuery is trivially able to serve as a memory
oracle, the functions targeted by our framework do not
explicitly state their crash-resistant nature in the documentation.
Therefore we need to locate them ourselves using the following
steps. First, we reduce the set of all available Windows API
functions to only those functions with crash-resistant properties.
For this we apply a basic form of fuzzing to the Windows
API functions. In the second step, we attempt to find code
paths to these crash-resistant API functions by harvesting API
calls, tracing instructions, and filtering the results via custom
analysis scripts. Third, we classify the pointer arguments of thecrash-resistant API functions to figure out if we can actuallycontrol the pointer on the execution path: only if an attackercontrollable pointer is found, we can construct a corresponding
crash-resistant primitive.

while ( true ) { // server loop...
if ( read ( fd , buf , MAX_BUF_LEN ) < 0) {terminate_connection ( fd , " read failed " ) ;continue ;}...
}B. Exception Handlers
Another feature of common operating systems and programming languages is allowing a program to recover froman exception. These exceptions can range from a software
generated exception to hardware faults. For our purposes, thepossibility of handling an invalid memory access and resuming
execution afterwards is especially critical. Low-level languages
like C/C++ allow a programmer to explicitly add constructs

Listing 1: Server loop with error handling5

to catch faults and tell the operating system how to resolve next handler. The filters are implemented as separate functions
them. Essentially the operating system or language runtime on the binary level and referenced in SEH structures. If anprovides information about the fault to a specific subroutine exception is not handled and it is considered fatal by thein the program which then can choose from a set of options. operating system, it causes program termination. This is also
Commonly these options include simply ignoring the ex- the case for access violations generated by scanning attempts.
ception, executing the next instruction as if nothing happened, If an attacker can control dereferences inside of a guarded
resuming execution at a different location instead, or passing code block and the corresponding filter allows either handlingthe exception along to another handler. In the latter case, if or ignoring of access violations, she is able to scan arbitrary
the exception is not handled by the program, the OS will memory.
usually terminate the program. A crash-resistant primitive using
To automatically locate potential memory oracles, we first
exception handling requires the program to dereference an need to collect all available exception handlers and their
attacker controlled pointer inside a code block that is covered guarded code regions. This is done via static analysis of theby an exception handler. After a probing attempt, the result target binary. We then discard any exception handlers whichmust be visible to the attacker, either explicitly by a return value are not able to handle access violations as indicated by theiror similar values, or implicitly with the help of side channels filters. For this we symbolically execute the filter functions.
(e.g., timing). In addition, the exception handler must allow The resulting set of potential code locations is then analyzed
memory faults to be handled, which can be excluded using the with the tools described in the previous section: instead of
information provided for each fault to filter out unsupported system APIs, we now target the guarded code locations.
exceptions.
Under Linux, exception handling is implemented as signal C. Swallowed exceptions
handling. A signal is a software interrupt that can be handled
On further investigation we also added a third class of
by a process in three ways: (i) it can be ignored, (ii) it can be possible memory oracles which was not covered before. Therecaught by a signal handler, or (iii) the signal’s default action are circumstances where exceptions are silently ignored. Herecan be performed [6]. For example, the default action of the we do not consider cases where an exception handler of asignal SIGSEGV (i.e., segmentation fault or access violation) is program simply ignores the fault and continues execution or
the termination of the process.
a system API detects an error and the user program does
In contrast, Windows utilizes two techniques for exception not check the error status. While leading to the same result,handling, Structured Exception Handling (SEH) [36], [39] suppressing of memory faults, these methods deliver the error
and its extension Vectored Exception Handling (VEH) [37]. status to the user program, it just does not act on them. Instead
While SEH-based exception handlers operate locally on a swallowed exceptions give no feedback to the user program
guarded function, VEH-based exception handlers can be that an exception occurred. An example are user-kernel-userused globally within the process. The following example callbacks [10], where the exception handling mechanism canshows a SEH-guarded block with its corresponding fil- not support the context switches. The result is that the callingter:
program has no way of detecting that an exception occurred.
We do not consider this class of crash-resistant primitives in1__try {
2...
our analysis.
3
4
5
6
7
8
9
10

// guarded codevalue = * ptr ;...

IV. I MPLEMENTATION}__except ( EXCEPTION_EXECUTE_HANDLER ){value = -1;}

In the following, we briefly outline the implementation of
our framework and describe the reasons for our design choices.
Implementation details are available in the corresponding
technical report [27].

Listing 3: Example for Structured Exception Handling (SEH) withcorresponding filter on Windows

A. Syscalls on LinuxOn Linux, we use dynamic taint tracking to isolate viablecandidates. We target common server applications with test
cases, allowing for sufficient code coverage. As we reuse test
cases and want to support additional applications with minorchanges, we chose a minimally invasive approach. The server
program is instrumented with libdft [25]—a data flow tracking
library which we extended with byte granular taint tracking—and the corresponding client program is controlled by ourmonitor application. The monitor can send client and server
custom commands to control the taint state and invalidate
pointer arguments. After a test run we obtain a list of potential
crash-resistant primitives with details on which arguments wereThis exception handler could be used to probe memory
addresses, if an attacker controls the value of ptr. In the case ofany exception, including access violations, value would be set
to -1; if the location is readable, it would be set to the content
of that address. Specifying EXCEPTION EXECUTE HANDLER as
the filter expression allows the handler to be executed for all
types of exceptions.
Any exception leads to the evaluation of the corresponding
filter expression which determines the appropriate action. The
filter can (i) simply resume the program execution (i.e., ignore
the exception completely), (ii) transfer the control flow tothe exception handler, or (iii) forward the exception to the6chmodconnect
epoll wait
mkdir
open
read
recv
recvfrom
send
sendmsg
statfssymlink
unlinkwrite

C. Exception Handlers

PostgreSQL

Memcached

Syscalls

lighttpd

As the Windows API does not define error states as uniformly
as the Linux syscall interface, we need to isolate appropriate
target functions ourselves. For this we use a fuzzing approach togather a list of functions that handle invalid pointer arguments
gracefully. Afterwards we locate any usage of these functionsin the targeted applications. For this we use the dynamic
instrumentation framework DynamoRIO [19]. The resulting
list of call sites is then reduced using heuristics to only retain
promising candidates. At the end of this analysis phase, theresults need to be manually verified to exclude any false
positives, mainly those cases in which the pointer arguments
are either short lived stack variables or volatile heap locations,and thus cannot be controlled by the attacker.

Cherokee

B. Windows API Functions

Nginx

Table I: Syscalls indicated as potential (±) or valid (+) cr primitives
by our framework on Linux. Green circled ones were manually verified
to be usable as a cr primitive. The red non-circled plus sign indicatesa result manually verified to be a false positive.

valid or invalid during the test run. This list is then verified
manually to eliminate false positives.

±
±
+
±
±
+

±
±

+

±
±

±

+

±

±
±
±
±
±

±

±
±

±
±
±

Aside from the system level candidates, we also target
application-specific memory oracles in the form of exception
handlers. For this we use the fact that under 64bit Windows
every function in an application needs to provide stack unrolling connection state to probe a new memory address), we still foundinformation in case it is contained in the call stack of an usable primitives in practice. Note that our goal is simply for the
exception. As such, we can parse the corresponding .pdata worker process not to crash and a graceful process termination
section and retrieve the list of all exception handlers in an is sufficient for our purposes. As the worker process is expected
executable module. We then use symbolic execution and the to terminate after serving a request, this does not constituteSMT solver Z3 [32] to filter out the exception filters that allow any abnormal action.
Table I shows all the candidates reported by the framework.
either all exceptions or at least access violations to be handled.
As
depicted by the non-circled plus-minus sign, many of theAfter this analysis step, we reuse the analysis methods wecandidates
end up in a segmentation fault if we automaticallydeveloped for the tracking of API functions and target the
alter
the
targetmemory locations with an invalid memorycode covered in the exception handlers. At the end, we again
address.
We
haveconfirmed our framework has flagged all
manually verify the results.
these cases correctly using manual inspection. Despite theV. E VALUATION R ESULTS
many invalid candidates, our framework discovered a usable
Based on our prototype implementation, we now discuss the crash-resistant primitive, depicted with a green circled plus
results of our analysis on binary executables for both Linux sign, in all of our server programs (with the two potential
candidates confirmed via manual verification).
and Windows.
Four candidates in total were indicated as valid candidates by
A. Syscalls on Linuxthe framework. We confirmed that our framework has flagged
We evaluated our framework with widely used server all these cases correctly using manual inspection, except theapplications on Linux. In particular, using our framework, we valid candidate on Memcached which turned out to be a false
ran the standard test suites for the following server programs: positive (depicted as a red non-circled plus sign). Manual
Nginx 1.9, Cherokee 1.2, Lighttpd 1.4, and Memcached 1.4. inspection revealed that the connection handling thread exits
We focus on such popular server programs since they all handle after the candidate syscall epoll wait returns an error code,
multiple connections per process. An attacker can simply use while the server keeps running—which our framework currently
one connection to probe a memory address (using a discovered interprets as correct behavior. Subsequent connections, however,crash-resistant primitive) and another connection to exercise never get processed by the now terminated connection handlingher arbitrary read/write primitives and modify the state of the thread and the primitive is effectively unusable for multiple
probing connection.
probing attempts. This false positive can be simply eliminatedFor completeness, we also consider server programs that by checking the status of connection handling threads, a strategy
handle every new connection in an independent worker process, which our current prototype does not yet support in a genericfocusing our analysis on PostgreSQL 9.0. In such cases, the way. From our analysis, we found usable candidates in recv inattacker can only use a single connection to probe and modify Nginx, epoll wait in Cherokee and PostgreSQL, and read in
the state of the program. While exploitation is generally Lighttpd and Memcached. We exemplify how such candidates
more complicated (it might be harder to restore the preferred can be used as crash-resistant primitives in Section VI.
7

Table II: The number of unique code locations that are guarded by
C-specific handlers during an Internet Explorer 11 run. The code
locations that appear on the execution path are from the set after
symbolic execution (SB).

B. Windows API Functions

We had to first collect crash-resistant API functions on
Windows. We extracted 20,672 API functions from the MSDN
library, of which 11,521 (55.7%) contained at least one pointerDLL# guarded program codeargument. Hence, only these functions served as inputs for the
before SB
after SB
execution pathanalysis phase via our custom API fuzzer. As a result, we founduser3270
63
40
400 API functions that are candidates for a crash-resistancekernel32
76
66
14
primitive both under Windows 7 and 10.
mshtml129
103
ieframe34
22
6
In the next step, we attempted to locate these functions
kernelbase
96
81
0
on execution paths, outlined here exemplary for Internet
ntdll
113
65
19
Explorer 11 (64bit) on Windows 10. For this, we logged all
jscript922
64
rpcrt462
20
6
calls to target API functions while visiting the top 500 websites
sechost133
110from alexa.com [1]. In addition, we ran browser and JavaScript
ws2 3282
29
10benchmarks [2], [44] to increase the code coverage. Only 25
xmllite1021crash-resistant API functions were found on an execution path.
Finally, we used our analysis scripts to determine if these
Table III: Unique exception filters in different DLLs before and after
functions were triggered from a JavaScript context. We found symbolic execution (SB).
12 functions with this characteristic.
DLL# filter functions
To be a usable crash-resistant primitive, we have to trigger
them from JavaScript and control their arguments; in addition,
before SB
after SB
we must be able to intercept the return value. To analyze these
x64
x32
x64
x32
two properties, we created instruction traces and analyzed theuser32917
215
resulting execution paths. Unfortunately, all candidates had tokernel3260
750
3
mshtml128
33
92
be excluded after a manual analysis since all of the pointerieframe29
6
17
0
arguments were unusable for our purposes. The reasons forkernelbase
54
21
39
19
this are threefold. First, most functions were query functions
ntdll
71
25
23
15
jscript919534(e.g., GetPwrCapabilities) which are usually called by
rpcrt450
11
8
1supplying a stack-allocated structure. If such a pointer is invalid,sechost126
26
4
1
then the stack pointer is corrupted. This leads to an illegal
ws2 3255
25
3
17
xmllite10020memory access and causes the program’s termination. Second,a majority of the remaining candidates’ pointer arguments were
dereferenced outside of the target function. This also leads toan illegal memory access if the pointer is invalid. Third, weTable II provides an overview of the amount of program
cannot control the pointer arguments of some candidates sincecode that is guarded with C-specific exception handlers for a
the pointers were volatile heap pointers which had no previous
subset of the loaded DLLs. In addition, the table shows thereferences stored in memory.
code locations that are guarded with crash-resistant candidates
This negative result for Windows API functions does not(including the exception handlers that use catch-all filters) as
imply that no crash-resistant primitive can be constructed using
well as their number of occurrences on the execution path.
our method. The coverage of test cases influences the number
For instance, there are 63 crash-resistant candidates from 70
of excluded functions after code path analysis: only 25 of the
exception handlers in user32.dll, whereby 40 code locations
400 candidate API functions were observed on execution paths.
that are guarded by those are executed while browsing the
Further work on improving code coverage may lead to moremost popular websites. Contrary, sechost.dll guards 133
candidates, and hence yield crash-resistant primitives.
code locations, whereby 11 crash-resistant candidates exist andno guarded code location was triggered during our test. In
C. Exception Handlers
addition, Table III shows that symbolic execution significantly
To test the feasibility of our approach leveraging excep- reduces the set of exception filters, since it drops the majority
tion handlers, we collected the executed code blocks during of filter functions given that they are not fit for our purposes.
normal usage. Again we use Internet Explorer 11 (64bit) on As described before, we use symbolic execution to exclude all
Windows 10 as an example. We instrumented the browser with filters that do not allow access violations to be handled. For
DynamoRIO and browsed again the top 500 websites from example, only 4 of 126 filter functions remain in sechost.dll,
alexa.com [1]. Then, we analyzed all DLLs that have been while 9 of 129 are left in mshtml.dll. In total, we foundloaded by the browser and extracted the exception handlers. 6,745 C-specific exception handlers in 187 analyzed DLLs.
Afterwards, we reduced this set by symbolically executing These exception filters use 5,751 different filter functions. Afterthe corresponding filters and cross-referencing the remaining the symbolic execution, 808 filters remain that handle accessexception handlers with those that have been visited.
violations, including catch-all filters. These filter functions are8

used by 1,797 exception handlers.
was located in the application itself, namely jscript9.dll,
In the next step, we cross-referenced the visited code blocks the memory oracle in Firefox is due to an exception handler
with those filtered exceptions. These exception handlers may in ntdll.dll. While all applications import this library, thelead to crash-resistant primitives that are known to be triggered. corresponding primitive was only on the execution path when
In absolute numbers, these guarded code parts have been using Firefox. Another difference is that the exception handler
triggered 736,512 times during our test, whereby 385 different is not flagged as catch-all, instead it excludes certain exception
code parts have been visited. To sum up, this analysis step types, but as it handles access violations it is usable for our
reduced the target set from 6,745 to 385 C-specific handlers. purposes. Due to the way the memory oracle is used within
To further reduce the candidate set, we used our debugger the process, it does not require a manual trigger, instead a
script to only select functions that are triggered via JavaScript. background thread continuously calls the vulnerable function.
For this we assumed that any function which has a reference This means we only need to write the address to probe to theto part of the JavaScript engine in its call stack is valid. The appropriate object and read back the result after giving theparallel thread a chance to probe.
survivors after this step were then manually verified.
While we focused our code path analysis on Firefox andInternet Explorer, the results of the previous analysis steps can C. Nginx 1.9
On Nginx, our framework found that the crash-resistant
be reused for any application. This means the static analysis of
the system DLLs can be performed once and then be applied primitive associated to the recv syscall becomes available
after the server receives a partial request. In detail, the server
to any target program.
allocates a Nginx-specific ngx buf t struct object for a
VI. P ROOF - OF -C ONCEPT E XPLOITS
connection once some request data comes in (only deallocatedTo demonstrate the practical applicability of our automati- later, when request processing completes). In our proof-ofcally discovered crash-resistant primitives, we developed four concept exploit, we use parallel connections to implement
proof-of-concept exploits that we discuss next. Note that we the individual memory probes. We first send a recognizablefocussed on locating the memory oracle itself, so we assumed a signature via a partial request over an independent connection,
memory read/write primitive to be present. During our tests we so that the server allocates the buffer and saves the signatureemulated such a vulnerability by modifying the target binary. therein. While the first connection is waiting for the request
to complete, i.e. for a double newline marking the end of the
A. Internet Explorer 11
request, we use a second parallel connection to leak the buffer
Our proof-of-concept exploit for Internet Explorer 11 relies object containing our signature. Once we leak it, we perform
on the function MUTX::Enter contained in jscript9.dll. It arbitrary writes to the buffer to reinitialize it, i.e., set all its
contains a call to EnterCriticalSection that is encapsulated pointers to the memory address we are probing for. Finally,in a try-catch block. The exception filter address field within we send more data to complete a full request over the firstthe scope table contains 0x1, which indicates that regardless of connection. If the memory address overwritten in the buffer
the exception code, all exceptions are caught and the execution was inaccessible, the server gracefully closes the connection
resumes at the exception handler. The CRITICAL SECTION without sending back any response data. Otherwise, the server
structure passed to EnterCriticalSection lies within the sends the requested file back to the client over the connection.
ScriptEngine object at a fixed offset. The ScriptEngine
object also contains a status field that indicates whether D. Cherokee 1.2
On Cherokee, our framework found a crash-resistant primthe last call to EnterCriticalSection failed. This status
field is cleared before the call and set in the exception itive associated to the epoll wait syscall. Unlike Nginx,
handler. The CRITICAL SECTION structure contains a pointer Cherokee’s default configuration starts multiple threads toto a debug info structure. Under certain circumstances, serve parallel incoming requests. Each idle thread calls theEnterCriticalSection reads the field at offset 0x10 from epoll wait syscall in a loop, with a timeout of 1 second
that debug info structure. By setting three additional fields between iterations. Corrupting a given thread’s epoll objectof the CRITICAL SECTION structure to certain values, we can pointer with an inaccessible memory address will cause theforce the correct circumstances. An attacker can overwrite thread to stop serving client requests and stall in a tight loop of
the pointer to debug info with x − 0x10 to probe address x. failing epoll wait invocations. This induces a performance
MUTX::Enter is called by Internet Explorer’s JavaScript engine degradation attack on the Cherokee (lower capacity and higher
once it processes new JavaScript code and thus, can easily be overhead), resulting in a timing side channel. In our proof-ofconcept exploit, we first leak the location of a given thread’s
triggered by adding a new script tag to the DOM.
cherokee fdpoll epoll t object and then corrupt it to
B. Firefox 46
probe memory. For each probe, we overwrite the struct
As another example, we chose Firefox 46.0.1 64bit on epoll event pointer in the target object and measure theWindows 10. As the general approach for both proof-of-concept time for the server to handle 1,000 requests. We noticed there
exploits is similar, we only highlight the key differences. In is significant time difference compared to the baseline whencontrast to Internet Explorer, where the exception handler even a single thread is non-functional. With all threads running9

correctly (baseline), the server handles all the requests in 5.7
seconds, and when a single thread is non-functional, it does
so in 9.3 seconds (on average, with marginal variations acrossruns). Based on the time difference, we can distinguish whether
the probed memory address is accessible (former case) or not(latter case).
VII. D ISCUSSION
In the following, we discuss limitations of our current
prototype implementations and reflect on the lessons learned.
We also explain the reasons for our disjoint approaches forlocating memory oracles on different operating systems.
A. Locating Primitives of Previous Workan exception can be effective in limiting the danger of a specificexception handler. Even applications that heavily use exception
handling do not necessarily contain a memory oracle, if theproper filtering is performed. However we also located multiple
examples of catch-all filters or filters with broad filtering criteria.
Some of these were combined with memory dereferences
outside of the protected code area, which usually indicatesa handler which should not cover access violations, but does
so anyway due to too broad filtering. Another observationis that exception handling is much more common in client
applications on Windows than it is in servers for Linux. Thiscan be explained by the differences in the way memory faults
are reported on these systems. Linux uses the signal model,
requiring a global signal handler to catch the corresponding
signal [4], whereas Windows allows the usage of SEH, which
provides a comfortable way to protect specific code blocks.

To verify our tool chain, we searched for the known memory
oracles in both Internet Explorer and Firefox [22]. The primitive
in IE is based on an exception handler that is set to handle
all possible exceptions. As our tool looks for this kind of C. Potential countermeasures
exception handler, we were able to locate this candidate in an
Depending on the system and application different counautomated way. After a security update, the handler handles termeasures are possible. We outline some possible defenses
a set of exception classes configured by a system setting. To ranging from a system redesign to ad-hoc fixes in either thedetect this new version of the primitive, we had to manually application or the system itself.
verify it due to the filter calling another function to allow System design changes Completely eliminating memory
configuring the behavior.
oracles would most likely require fundamental changes to
The primitive in Firefox, on the other hand, was not located both programs and the underlying operating systems. Most
automatically because this application uses a vectored exception of these countermeasures intentionally reduce the feature set
handler (VEH) that is registered during runtime. As we do provided to user space programs and therefore the balance
not cover this class of handlers in our current prototype between loss of functionality and gain of security must be
implementation, our framework can not locate this candidate. considered. Given a mechanism to either recover from access
Note that this is not a fundamental limitation of our approach. violations or querying the state of memory addresses (either
Further work can support this class by locating all calls to directly or indirectly), an attacker can construct crash-resistant
AddVectoredExceptionHandler and extracting the handler primitives and bypass information hiding defenses. As such,address. In addition, the semantics for the symbolic execution we propose the following properties:
need to be modified to account for the different function• any access violation is critical for the application andprototype.
yields to termination
Oikonomopoulos et al. [35] recently introduced a technique• exception handling can only be used for program-levelthat allows an adversary to use allocations to narrow down the
exceptions (e.g., C++ exceptions), not system-level (e.g.,
location of reference-less memory. While not directly related toaccess violations)crash-resistance, this method also provides a kind of memory• error reporting and data collection is possible, but careoracle, but it does not rely on any fault handling. Howevermust be taken to not allow resuming the normal execution
it requires the availability of the kernel feature overcommit,• system APIs and system calls must terminate the offending
which is the ability to allocate more virtual memory than isapplication on a memory error, as if the application
available as physical memory. We did not locate an allocation
received the fault
oracle as it is completely different to the primitives we targeted.
• exception masking must not be possible, any fault nomatter the callstack terminates the process
B. Differences between results on Linux and Windows• facilities to infer the memory layout, e.g., information in
On Linux we were able to directly target syscalls and their/proc or VirtualQuery, are questionable and should becrash-resistant nature. On Windows, certain system APIs also
removed to prevent probing using themprovide a similar behavior, but as the Windows API often• allocation functions that allow specifying the desired
contains more levels of abstraction, not all invalid arguments
address should be removed
are passed to the system calls and, instead, result in an exception• the memory layout of restarting processes must not persist
in the user-level code. However, we were still able to locate
between restarts
such APIs on Windows.
Besides relying on system-level functionality, a user program Improving exception filtering A less general approach would
can also use exception handling to detect and resolve potential be to narrow the exceptions caught by specific exception
memory errors. Our results show that filtering prior to handling handlers. This usually means that the exception filters must not10

accept more than the minimal needed set of exception codes. applications using expected access violations for performance
While some handlers might need to catch access violations, optimizations, we wanted to establish a baseline of how many
their widespread use is questionable. In addition to hardening such faults are generated during normal usage in practice. A
the exception handling in applications the system level oracles well known instance of this design choice can be found inneed to be covered as well. This could, for example, be achieved the Firefox web browser, so we used this program to testby treating a memory error within the system API or system our theory. We added logging code to report any fault caught
call the same as any error in the application. This means and handled in the browser. Using this modified version, we
instead of either silently discarding the exception or catching it crawled the top 40,000 websites according to Alexa [1] andand setting the appropriate error state, but allowing execution logged any occurrence. Our tests showed that none of theseto continue, the application would need to explicitly employ websites exhibited an access violation when accessing the site.
exception handling around these functions. This results in less
Additionally, we tested the corner case of using asm.jspossibilities for an attacker to abuse such functionality, if the heavy websites in the form of a dedicated asm.js benchapplication can ensure no invalid pointer is passed to this API mark [3]. This tool represents a stress test as it always forces
during normal operation.
native code to be generated and applies some optimizations,
Restricting access violations Another, more compatible, ap- one of them being the usage of faults to catch out-of-boundproach concerning memory probing itself is to only allow accesses. While we observed access violations, they are far
handling and resuming of expected access violations. There are less frequent than during a probing attack similar to the one
two common reasons for a memory access to fail: (i) there is described by Gawlik et. al. [22] with multiple thousands per
no mapped memory at the given address or (ii) the permissions second. The benchmark triggered faults in groups of up to 20of the memory do not allow the intended access. The first in short succession, but the overall rate was much lower ascase almost always results from a wrong calculation, or in our there were breaks between the groups. Even if we interpret thecase an exploit attempt, so it should be considered abnormal peak rate as our baseline, the faults caused by actual scanningbehavior. The application tried to access memory that it has attempts are several orders of magnitude more frequent.
As such, we conclude that the rate of access violations can
not previously allocated and it also was not allocated byprovidea viable heuristic for a defense. Even if an attacker
the operating system for the process, so there should be notries
tocircumvent
detection by performing a far slower scan,
references to this memory region. This is different compared
she
will
be
slowedto a level where the duration will mostto the second case where the address itself is valid—there is
likely
be
too
high
to
be practical.
allocated memory at the specified location, but its permissions
do not match the requested access.
Generating a fault based on permissions can be intended, it
can be used for performance reasons as seen in Firefox [22],so the application explicitly allocates a region of memory,
but marks it as inaccessible. In a way the program expects
an access violation to occur under some previously known
circumstances. As such it can be viable to only allow accessviolations that occur at mapped memory to be handled. This issimilar to the method described by Gawlik et al. in regards toremoving the scanning primitive from Firefox, but we propose
to employ this policy at the system level. This means any
memory access to an unmapped page causes an unrecoverable
error, without invoking any exception handler in the faulting
process. This can be simulated by the application itself by
performing checks on the supplied exception information andterminating in the case of an unmapped access. Using thisapproach would still allow optimizations as used in Firefox,
but scanning attempts would be detected at the first unmapped
region encountered. While not providing as much security as a
hard policy concerning memory errors, it reduces the odds ofsuccessful guessing significantly. This results in information
hiding providing the same security guarantees as in the absenceof crash resistance.
Rate based detection An orthogonal defense is a simple
anomaly detection that analyzes the number of access violations.
In principle, this is similar to the detection of crashes forserver applications to detect a BROP attack [29]. With some11

VIII. C ONCLUSION
In this paper, we showed that crash-resistant primitives are
not unique oddities. Most importantly, we demonstrated thatmemory oracles exhibit specific properties that can be used
to locate them in real-world applications. We showed that it
is possible to develop tools that ease the discovery of thosecode locations even for complex, closed-source programs. Once
located, these primitives can be used by an attacker in the same
way as demonstrated by previous work [22]. In addition, ourresults show that not only client programs are threatened bycrash resistance: even servers can exhibit not only crash-tolerant
behavior (as demonstrated before), but such applications arealso susceptible to this new kind of vulnerabilities. Overall,our results demonstrate that locating a crash-resistant primitive
is no longer left to pure chance, but poses a threat for defenses
that rely on information hiding in any kind of application.
ACKNOWLEDGEMENTS
We thank the anonymous reviewers for their valuablecomments. This work was supported by the European Commission through the projects H2020 ICT-32-2014 “SHARCS”
under Grant Agreement No. 644571, H2020 MSCA-RISE2015 “PROTASIS” under Grant Agreement No. 690972 and
ERC Starting Grant No. 640110 “BASTION”, and by the
Netherlands Organisation for Scientific Research through the
NWO 639.023.309 VICI “Dowsing” project.

The paper reflects only the authors’ view and the Agency
and the Commission are not responsible for any use that may
be made of the information it contains.
R EFERENCES[1] Alexa - Actionable Analytics for the Web. http://www.alexa.com/.
[2] BrowserBench. http://browserbench.org/.
[3] MASSIVE - the asm.js benchmark. https://kripken.github.io/Massive/.
[4] WineHQ - Structured Exception Handling. https://www.winehq.org/docs/
winedev-guide/seh.
[5] ERRNO(3) Linux Programmer’s Manual. Linux Manual Page, 2016.
[6] SIGNAL(7) Linux Programmer’s Manual. Linux Manual Page, 2016.
[7] P. Akritidis, M. Costa, M. Castro, and S. Hand. Baggy bounds checking:An efficient and backwards-compatible defense against out-of-bounds
errors. In USENIX Security Symposium, 2009.
[8] M. Backes, T. Holz, B. Kollenda, P. Koppe, S. Nürnberger, and J. Pewny.
You can run but you can’t read: Preventing disclosure exploits inexecutable code. In ACM Conference on Computer and Communications
Security (CCS), 2014.
[9] M. Backes and S. Nürnberger. Oxymoron: Making fine-grained memory
randomization practical by allowing code sharing. In USENIX Security
Symposium, 2014.
[10] P. Betts.
The case of the disappearing OnLoad exception.
http://blog.paulbetts.org/index.php/2010/07/20/the-case-of-thedisappearing-onload-exception-user-mode-callback-exceptions-in-x64/.
[11] S. Bhatkar, D. C. DuVarney, and R. Sekar. Efficient techniques forcomprehensive protection from memory error exploits. In USENIX
Security Symposium, 2005.
[12] D. Bigelow, T. Hobson, R. Rudd, W. Streilein, and H. Okhravi. Timely
rerandomization for mitigating memory disclosures. In ACM SIGSAC
Conference on Computer and Communications Security, 2015.
[13] A. Bittau, A. Belay, A. Mashtizadeh, D. Mazieres, and D. Boneh. Hacking
blind. In IEEE Symposium on Security and Privacy, 2014.
[14] N. Carlini, A. Barresi, M. Payer, D. Wagner, and T. R. Gross. Controlflow bending: On the effectiveness of control-flow integrity. In USENIX
Security Symposium, 2015.
[15] S. Crane, C. Liebchen, A. Homescu, L. Davi, P. Larsen, A.-R. Sadeghi,
S. Brunthaler, and M. Franz. Readactor: Practical code randomization
resilient to memory disclosure. In IEEE Symposium on Security andPrivacy, 2015.
[16] S. Crane, S. Volckaert, F. Schuster, C. Liebchen, P. Larsen, L. Davi,
A.-R. Sadeghi, T. Holz, B. D. Sutter, and M. Franz. It’s a TRAP: Table
Randomization and Protection against Function Reuse Attacks. In ACM
Conference on Computer and Communications Security (CCS), 2015.
[17] T. H. Dang, P. Maniatis, and D. Wagner. The performance cost of shadow
stacks and stack canaries. In ACM Symposium on Information, Computerand Communications Security (ASIACCS), 2015.
[18] L. Davi, C. Liebchen, A.-R. Sadeghi, K. Z. Snow, and F. Monrose.
Isomeron: Code randomization resilient to (just-in-time) return-oriented
programming. In Symposium on Network and Distributed System Security(NDSS), 2015.
[19] DynamoRIO contributors. DynamoRIO Dynamic Instrumentation Tool
Platform. http://www.dynamorio.org/.
[20] U. Erlingsson, M. Abadi, M. Vrable, M. Budiu, and G. C. Necula. XFI:
Software guards for system address spaces. In Symposium on Operating
Systems Design and Implementation (OSDI), 2006.
[21] I. Evans, S. Fingeret, J. González, U. Otgonbaatar, T. Tang, H. Shrobe,
S. Sidiroglou-Douskos, M. Rinard, and H. Okhravi. Missing the point(er): On the effectiveness of code pointer integrity. In IEEE Symposium
on Security and Privacy, 2015.
[22] R. Gawlik, B. Kollenda, P. Koppe, B. Garmany, and T. Holz. Enablingclient-side crash-resistance to overcome diversification and information
hiding. In Symposium on Network and Distributed System Security(NDSS), 2016.
[23] J. Gionta, W. Enck, and P. Ning. HideM: Protecting the contents ofuserspace memory in the face of disclosure vulnerabilities. In ACM
Conference on Data and Application Security and Privacy, 2015.
[24] E. Göktaş, R. Gawlik, B. Kollenda, E. Athanasopoulos, G. Portokalidis,
C. Giuffrida, and H. Bos. Undermining information hiding (and what to
do about it). In USENIX Security Symposium, 2016.
[25] V. P. Kemerlis, G. Portokalidis, K. Jee, and A. D. Keromytis. libdft:
Practical dynamic data flow tracking for commodity systems. In ACM
SIGPLAN Notices, 2012.

12[26] C. Kil, J. Jim, C. Bookholt, J. Xu, and P. Ning. Address space layout
permutation (ASLP): Towards fine-grained randomization of commodity
software. In Annual Computer Security Applications Conference (ACSAC),
2006.
[27] B. Kollenda, E. Göktaş, T. Blazytko, P. Koppe, R. Gawlik, R. Konoth,
C. Giuffrida, H. Bos, and T. Holz. Towards Automated Discovery
of Crash-Resistant Primitives in Binary Executables. Technical report,
Ruhr-University Bochum, 2017.
[28] V. Kuznetsov, L. Szekeres, M. Payer, G. Candea, R. Sekar, and D. Song.
Code-pointer integrity. In Symposium on Operating Systems Design and
Implementation (OSDI), 2014.
[29] V. Kuznetsov, L. Szekeres, M. Payer, G. Candea, and D. Song. Poster:
Getting the point(er): On the feasibility of attacks on code-pointerintegrity. In IEEE Symposium on Security and Privacy, 2015.
[30] K. Lu, S. Nürnberger, M. Backes, and W. Lee. How to make ASLR win
the clone wars: Runtime re-randomization. In Symposium on Network
and Distributed System Security (NDSS), 2016.
[31] K. Lu, C. Song, B. Lee, S. P. Chung, T. Kim, and W. Lee. ASLRguard: Stopping address space leakage for code reuse attacks. In ACM
Conference on Computer and Communications Security (CCS), 2015.
[32] Microsoft Research. The Z3 Theorem Prover. https://github.com/
Z3Prover/z3.
[33] V. Mohan, P. Larsen, S. Brunthaler, K. W. Hamlen, and M. Franz. OpaqueControl-Flow Integrity. In Symposium on Network and Distributed System
Security (NDSS), 2015.
[34] S. Nagarakatte, J. Zhao, M. M. Martin, and S. Zdancewic. SoftBound:
Highly compatible and complete spatial memory safety for C. In
ACM SIGPLAN Workshop on Programming Languages and Analysis for
Security (PLAS), 2009.
[35] A. Oikonomopoulos, E. Athanasopoulos, H. Bos, and C. Giuffrida. Poking
holes in information hiding. In USENIX Security Symposium, 2016.
[36] M. Pietrek. A crash course on the depths of win32 structured exception
handling. Microsoft Systems Journal, 1997.
[37] M. Pietrek. New vectored exception handling in Windows XP. MSDN
Magazine, 2001.
[38] M. Prandini and M. Ramilli. Return-Oriented Programming. In IEEE
Symposium on Security and Privacy, 2012.
[39] M. Russinovich, D. A. Solomon, and A. Ionescu. Windows Internals,
Part 1. Microsoft Press, 2012.
[40] F. Schuster, T. Tendyck, C. Liebchen, L. Davi, A.-R. Sadeghi, and T. Holz.
Counterfeit object-oriented programming: On the difficulty of preventing
code reuse attacks in C++ applications. In IEEE Symposium on Security
and Privacy, 2015.
[41] H. Shacham, M. Page, B. Pfaff, E.-J. Goh, N. Modadugu, and D. Boneh.
On the effectiveness of address-space randomization. In ACM Conference
on Computer and Communications Security (CCS), 2004.
[42] K. Z. Snow, F. Monrose, L. Davi, A. Dmitrienko, C. Liebchen, and A.-R.
Sadeghi. Just-in-time code reuse: On the effectiveness of fine-grainedaddress space layout randomization. In IEEE Symposium on Security
and Privacy, 2013.
[43] L. Szekeres, M. Payer, T. Wei, and D. Song. Sok: Eternal war in memory.
In IEEE Symposium on Security and Privacy, 2013.
[44] Thomas Patzke. Browser Crasher. https://github.com/thomaspatzke/
BrowserCrasher.
[45] R. Wahbe, S. Lucco, T. E. Anderson, and S. L. Graham. Efficient
software-based fault isolation. In ACM Symposium on Operating Systems
Principles, 1993.
[46] R. Wartell, V. Mohan, K. W. Hamlen, and Z. Lin. Binary stirring: Selfrandomizing instruction addresses of legacy x86 binary code. In ACM
Conference on Computer and Communications Security (CCS), 2012.