dynamic hooks: hiding control flow changes within non ... · usenix association 23rd usenix...

17
This paper is included in the Proceedings of the 23rd USENIX Security Symposium. August 20–22, 2014 • San Diego, CA ISBN 978-1-931971-15-7 Open access to the Proceedings of the 23rd USENIX Security Symposium is sponsored by USENIX Dynamic Hooks: Hiding Control Flow Changes within Non-Control Data Sebastian Vogl, Technische Universität München; Robert Gawlik and Behrad Garmany, Ruhr-University Bochum; Thomas Kittel, Jonas Pfoh, and Claudia Eckert, Technische Universität München; Thorsten Holz, Ruhr-University Bochum https://www.usenix.org/conference/usenixsecurity14/technical-sessions/presentation/vogl

Upload: others

Post on 04-Jun-2020

17 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Dynamic Hooks: Hiding Control Flow Changes within Non ... · USENIX Association 23rd USENIX Security Symposium 813 Dynamic Hooks: Hiding Control Flow Changes within Non-Control Data

This paper is included in the Proceedings of the 23rd USENIX Security Symposium.

August 20–22, 2014 • San Diego, CA

ISBN 978-1-931971-15-7

Open access to the Proceedings of the 23rd USENIX Security Symposium

is sponsored by USENIX

Dynamic Hooks: Hiding Control Flow Changes within Non-Control Data

Sebastian Vogl, Technische Universität München; Robert Gawlik and Behrad Garmany, Ruhr-University Bochum; Thomas Kittel, Jonas Pfoh, and Claudia Eckert, Technische

Universität München; Thorsten Holz, Ruhr-University Bochum

https://www.usenix.org/conference/usenixsecurity14/technical-sessions/presentation/vogl

Page 2: Dynamic Hooks: Hiding Control Flow Changes within Non ... · USENIX Association 23rd USENIX Security Symposium 813 Dynamic Hooks: Hiding Control Flow Changes within Non-Control Data

USENIX Association 23rd USENIX Security Symposium 813

Dynamic Hooks: Hiding Control Flow Changes within Non-Control Data

Sebastian Vogl∗, Robert Gawlik†, Behrad Garmany†, Thomas Kittel∗,Jonas Pfoh∗, Claudia Eckert∗, Thorsten Holz†

∗Technische Universität München†Horst Görtz Institute for IT-Security, Ruhr-University Bochum

Abstract

Generally speaking, malicious code leverages hookswithin a system to divert the control flow. Without them,an attacker is blind to the events occurring in the sys-tem, rendering her unable to perform malicious activities(e.g., hiding of files or capturing of keystrokes). How-ever, while hooks are an integral part of modern attacks,they are at the same time one of their biggest weaknesses:Even the most sophisticated attack can be easily identi-fied if one of its hooks is found. In spite of this fact,hooking mechanisms have remained almost unchangedover the last years and still rely on the persistent mod-ification of code or control data to divert the controlflow. As a consequence, hooks represent an abnormal-ity within the system that is permanently evident and canin many cases easily be detected as the hook detectionmechanisms of recent years amply demonstrated.

In this paper, we propose a novel hooking concept thatwe refer to as dynamic hooking. Instead of modifyingpersistent control data permanently, this hooking mech-anisms targets transient control data such as return ad-dresses at run-time. The hook itself will thereby residewithin non-control data and remains hidden until it istriggered. As a result, there is no evident connection be-tween the hook and the actual control flow change, whichenables dynamic hooks to successfully evade existing de-tection mechanisms. To realize this idea, dynamic hooksmake use of exploitation techniques to trigger vulner-abilities at run-time. Due to this approach, dynamichooks cannot only be used to arbitrarily modify the con-trol flow, but can also be applied to conduct non-controldata attacks, which makes them more powerful than theirpredecessors. We implemented a prototype that makesuses of static program slicing and symbolic execution toautomatically extract paths for dynamic hooks that canthen be used by a human expert for their realization. Todemonstrate this, we used the output provided by ourprototype to implement concrete examples of dynamichooks for both modern Linux and Windows kernels.

1 Introduction

Over the last decade, the sophistication and technicallevel of malicious software (malware) has increased dra-matically. In the early 2000s, we saw malware such asthe I Love You [29] and Blaster worms [3] that gener-ally operated in user space with very little in the wayof defensive mechanisms. In contrast, we nowadays seecomplex kernel level malware such as Stuxnet, Duqu, andFlame [6] that show an increase in sophistication in thetarget of their attack, the exploitation methods used todeliver them, and their ability to evade detection. By tar-geting kernel space, modern malware effectively runs atthe same privilege level as the operating system (OS),enabling it to attack and modify any part of the systemincluding the kernel itself. In addition, malware can takeadvantage of stealth techniques that were originally onlyused by kernel rootkits to hide itself deep within the sys-tem. This makes the detection of malware increasinglydifficult, especially as malware continues to evolve, en-abling it to stay one step ahead of the defenders. Cur-rently, one the most sophisticated methods employed isdata-only malware [16, 41].

However, even very sophisticated malware such asdata-only malware has an Achilles’ heel: in general, mal-ware needs to intercept events within the system to beable to fulfill its purpose [27, 44]. Without this capabil-ity, malware would be unable to react to events or pro-vide fundamental functionality such as key logging andfile hiding, which would severely limit its possibilities.Event interception, however, requires malware to divertthe control flow of the infected system at run-time. Toachieve this, malware must install hooks in the systemthat facilitate the required control flow transfer on be-half of the malware whenever the desired event occurs.While malware might manage to hide itself, these hooksrepresent an abnormality that will be permanently visiblewithin the system and thus lends itself well to becomingthe basis of detection mechanisms. This insight led toa wide range of research that enable the monitoring ofmalware hooking behavior for the purpose of signature

Page 3: Dynamic Hooks: Hiding Control Flow Changes within Non ... · USENIX Association 23rd USENIX Security Symposium 813 Dynamic Hooks: Hiding Control Flow Changes within Non-Control Data

814 23rd USENIX Security Symposium USENIX Association

generation [47] or detecting malware based on controlflow modifications [15, 20, 43].

Although existing systems are not yet able to de-tect all hooks that are placed by malware, the remain-ing possibilities for malware to install hooks are con-stantly dwindling. Hooks that are based on code mod-ifications are usually no longer an option, since changesto code areas can be easily detected due to their static na-ture. This leaves attackers only with the option of datahooks [43,47], but even here the options are increasinglyrestricted by modern detection mechanisms. The reasonfor this development is that, in contrast to malware whereone can observe a constant evolution of techniques andmechanisms used, hooking techniques have not signifi-cantly changed over the course of recent years.

In this paper, we present a novel hooking concept thatwe refer to as dynamic hooking. In contrast to existinghooking mechanisms which persistently modify controldata, our hooking approach targets transient control datasuch as return addresses at run-time. As a consequence,the resulting control flow change that is introduced bythe hook only becomes visible when the hook is actu-ally triggered. This significantly complicates the detec-tion of dynamic hooks as security mechanisms can nolonger focus on persistent control data, but must alsotake transient control data into account. What is evenmore, the hook itself will thereby reside in non-controldata, which is much more difficult to analyze and ver-ify [4,15] when compared to control data that traditionalhooks target. Despite the fact that dynamic hooks residepurely in non-control data, they are able to reliably inter-cept the execution flow of functions similar to traditionalhooks. Furthermore, they can be used in pure data-onlyattacks, which are by themselves a realistic and danger-ous threat [3, 5]. Thus they are not only harder to detect,but also more powerful than their predecessors.

To provide these capabilities, dynamic hooks modifydata in such a way that they will trigger vulnerabilities atrun-time. Through this approach, they are able to arbi-trarily modify the control flow, while the hook itself onlyconsists of the data that triggers and exploits the vulner-ability. This makes them quite similar to traditional ex-ploitation techniques with the exception that they targetapplications that are already controlled by the attacker.Due to this fact, the attack surface for dynamic hooks ismuch broader compared to traditional exploitation, sincean attacker can not only attack external functions, butalso internal functions.

Furthermore, dynamic hooks can be obtained automat-ically in a manner comparable to automated exploit gen-eration [2]. To demonstrate this, we implemented a pro-totype that leverages static program slicing [40, 45] andsymbolic execution [34] to automatically extract satisfi-able, exploitable paths for dynamic hooks. The prototype

thereby provides detailed information about each jumpcondition in the path and the actual vulnerability in anintuitive format, which makes the output suitable for ex-ploit generation frameworks or a human expert. We usedthis prototype to automatically identify dynamic hooksfor recent Linux and Windows kernels. Additionally,we implemented proof of concepts (POCs) of dynamichooks that demonstrate how they can be used in prac-tice to intercept events such as system calls or to imple-ment backdoors. This proves that the suggested hookingmechanism is not only powerful, but also realistic.

In summary, we make the following contributions:

• We present a novel hooking concept called dynamichooking that targets transient control data at run-time instead of persistent control-data. This ap-proach bypasses existing hook detection techniquesproposed in the last few years.

• We show how dynamic hooks for OS kernels can beautomatically found by leveraging binary analysistechniques and implemented a prototype.

• We provide detailed POC implementations of dy-namic hooks for both Linux and Windows kernelsthat demonstrate their capabilities and possibilities.

2 Technical Background

Before presenting our approach to realize dynamichooks, we first review background information that isessential for the understanding of the remainder of thepaper. We begin by defining important terms and thendiscuss why malware in general requires hooks withinthe system to function. Finally, we cover existing hook-ing mechanisms and their countermeasures.

2.1 DefinitionsWe first introduce important terms that we will usethroughout the paper. In particular, we highlight the dif-ferences between control data and non-control data aswell as transient and permanent control data.

Control data and non-control data. Control dataspecifies the target location of a branch instruction. Bychanging control data, an attacker can arbitrarily changethe control flow of an application. Examples of controldata are return addresses and function pointers.

In contrast, non-control data never contains the targetaddress for a control transfer. In certain cases, however,it may influence the control flow of an application. Forinstance, a conditional branch may depend on the valueof non-control data.

2

Page 4: Dynamic Hooks: Hiding Control Flow Changes within Non ... · USENIX Association 23rd USENIX Security Symposium 813 Dynamic Hooks: Hiding Control Flow Changes within Non-Control Data

USENIX Association 23rd USENIX Security Symposium 815

Transient and persistent control data. We considercontrol data to be transient when it cannot be reachedthrough a pointer-chain originating from a global vari-able. This essentially implies that there is no lasting con-nection between the application and the control data. In-stead, the control data is only visible in the current scopeof the execution such as a return address which is onlyvalid as long as a function executes.

By extension, we consider all control data that isreachable through a global variable as persistent, sincethe control data is permanently connected to the applica-tion and can thus always be accessed independent of thecurrent scope.

2.2 Malware and Hooking

Petroni et al. [27] estimated that about 96% of all root-kits require hooks within the system to function. Intu-itively, this makes sense: since the sole purpose of root-kits is to provide stealth, they have to hide all signs ofan infection. While existing structures can be hidden us-ing techniques such as direct kernel object manipulation(DKOM) [38], hooks enable rootkits to react to changesoccurring at run-time. Consider, for instance, that a hid-den process creates a new network connection or a childprocess. Naturally, a rootkit must also hide such newlycreated objects to achieve its goal. This, however, re-quires a rootkit to be notified of the occurrence of suchevents. Hooks solve this problem by enabling a rootkitto install callback functions in the system. This makesthem an integral part of rootkit functionality.

In practice, rootkit functionality is often mixed witha variety of malicious payloads. According to a reportby Microsoft released in 2012 [13], “some of the mostprevalent malware families today consistently use rootkitfunctionality”. The primary reason for this is that thesingle purpose of a rootkit is to avoid detection. Con-sequently, it is not a big surprise that the techniquesformerly only found in rootkits are increasingly beingadapted by malware. Since rootkits require hooks tofunction, this, however, also implies that any malwarebased on rootkit functionality will require the same.

2.3 Existing Hooking Mechanisms

In general, we distinguish between two different types ofhooks: code hooks and data hooks [11, 43, 47]. Codehooks work by directly patching the application’s coderegions: wherever the attacker wants to redirect the con-trol flow of the application, she overwrites existing in-structions with a branch instruction. As a result, the con-trol flow of the application is diverted every time the ex-ecution passes through the modified instructions.

The main problem with code hooks is that code re-gions are usually static. Therefore, it is generally suffi-cient to identify modifications to code regions to detectthis type of hook. Various techniques have been pro-posed that leverage such an approach [22, 27, 31]. Asa result, adversaries resorted to a different hooking formreferred to as data hooks. Instead of modifying code di-rectly, data hooks target persistent control data within theapplication. By modifying control data, the attacker isable to divert every control transfer that makes use of themodified data. For example, the most straightforwardmethod for intercepting the execution of system calls isto modify function pointers within the system call table.

To counter the threat of data hooks, researchers pro-posed various systems that aim to protect control datawithin an application [9, 20, 27, 43]. However, the mainfocus of these systems thereby lies in the protection offunction pointers that are allocated on the heap or residewithin the data region of the application. This is achievedby ensuring that each function pointer points to a validfunction according to its control flow graph (CFG). Tran-sient control data on the other side is generally ignoredby these approaches or they merely consider the protec-tion of return addresses, which is not the only kind oftransient control data. Instead transient function pointermay also exist as we will discuss in Section 5.1.

While researchers acknowledge that malware couldpotentially also target transient control data to modifythe control flow [20, 27, 43], these attacks are usuallyonly considered in the context of exploitation or return-oriented rootkits [16], but are not deemed to be rele-vant for hooking. The reasoning behind this assump-tion is that malware generally wants to change the con-trol flow of the target application indefinitely in order tobe continuously able to intercept events. Consequently,the malware must permanently redirect the control flowand thus target persistent control data as transient controldata is, by definition, only used by the system for a lim-ited amount of time. In this paper, we demonstrate thatthis assumption is false and can be used to circumventexisting defense mechanisms against hooking.

3 Dynamic Hooks

In the following, we introduce our novel hooking conceptthat we refer to as dynamic hooking. For this purpose, weprovide an overview of the concept, discuss the vulner-abilities that can be used to implement dynamic hooks,and cover the types of dynamic hooks that exist and theirproperties. Before doing so, however, we first state theattacker model that we assume throughout this paper.

3

Page 5: Dynamic Hooks: Hiding Control Flow Changes within Non ... · USENIX Association 23rd USENIX Security Symposium 813 Dynamic Hooks: Hiding Control Flow Changes within Non-Control Data

816 23rd USENIX Security Symposium USENIX Association

3.1 Attacker Model & ScopeIn the following, we assume that the attacker’s goal is toinstall persistent kernel malware such as a rootkit on thevictim’s system. For this purpose, we assume that theattacker has the ability to manipulate the kernel’s mem-ory arbitrarily either through a vulnerability or the abilityto load a kernel module (or driver). To avoid detection,the attacker wishes to hide all the hooks of the malware.That is, we are not concerned with the stealth of the mal-ware itself, but instead solely focus on its hooks. Conse-quently, we consider all malware detection mechanismsthat do not detect malware based on its hooks to be outof scope for the remainder of the paper. Furthermore, weassume the target system leverages common protectionmechanisms such as Address Space Layout Randomiza-tion (ASLR), stack canaries, and W ⊕X .

3.2 High-Level OverviewThe main problem with existing hooking mechanisms isthat they require the permanent change of code or func-tion pointers. Consequently, the desired control flowchange of the malware is permanently evident withinthe system [27]. The fundamental idea behind dynamichooks is to solve this problem by hiding the desired con-trol flow change within non-control data such that thereis no clear connection between the changes that the mal-ware conducts and the actual control flow change. Thisis accomplished with the help of exploitation techniques.

To exploit a vulnerable application, an attacker makesuse of specially crafted input data that—when processedby the application—will eventually trigger a vulnerabil-ity. If the vulnerability enables the attacker to overwriteimportant control structures such as a return address, shewill be able to modify and often control the executionflow of the application using techniques such as return-oriented programming (ROP) [35].

With dynamic hooks, we apply the same concepts thatare used in traditional exploitation scenarios to hooking.That is, we manipulate the input data of the functions wewant to hook in such a way that we will trigger a con-trol flow modifying vulnerability when the data is used.This effectively allows us to overwrite control data (e.g.,a return address) at run-time and enables us to controlthe execution flow of the application similar to a tradi-tional hook. The main difference, however, is that sucha dynamic hook will reside somewhere within the datastructures of the application unnoticed until its maliciouspayload is eventually used by the target function.

For this approach to work, we need to identify a con-trol flow modifying vulnerability in every function thatwe want to hook. At first glance this seems unlikely.However, there is a key difference between the exploita-tion of traditional vulnerabilities and vulnerabilities that

are used to realize dynamic hooks: the attacker alreadycontrols the application at the time she installs a hook. Ina traditional exploit, the attacker’s goal is to gain controlover an application. To achieve this, she needs to findan input to the application that will trigger a vulnerabil-ity. That is, the attacker can only control the externaldata which is provided to the application. In the caseof a dynamic hook, however, this restriction does not ap-ply. As the attacker controls the application, she is free toaccess and modify any internal data structure of the ap-plication. This results in a much stronger attacker modelwhen compared to traditional exploitation.

Finding and exploiting vulnerabilities in such a sce-nario becomes much easier for several reasons. First,many existing protection mechanisms such as ASLR,stack canaries, or W ⊕X only protect against an exter-nal attacker, but can be easily circumvented by an at-tacker that controls the application. Second, the attackercan prepare the code (or ROP chain) she wants to exe-cute when the vulnerability is triggered beforehand anddoes not have to provide it during the exploitation pro-cess. This enables the attacker to exploit vulnerabilitiesfor which traditional methods would be difficult due tospace constraints of the vulnerability. Third, the attacksurface for dynamic hooks is much broader. The attackercannot only attack functions that handle user input, butcan also target internal functions that cannot be influ-enced by the user. In fact, by manipulating internal datastructures, the attacker can create new vulnerabilities thatwould not occur during normal operation of the applica-tion, because the targeted data structures are normallyonly accessed and modified by the program itself. Thismay even allow the attacker to circumvent checks and fil-ters within the application as the manipulated data struc-tures may contain values that could never occur duringnormal operation and may thus not have been expectedby the programmer. Finally, to hook a specific event, thehook may be placed anywhere within the control flow ofthe handling code, it is not restricted to a single function.

Example. To illustrate the concept of dynamic hooksat a concrete example, consider the following code fromthe function in the Linux kernel (version 3.8):

1 s t r u c t l i s t _ h e a d {2 s t r u c t l i s t _ h e a d ∗ n e x t ;3 s t r u c t l i s t _ h e a d ∗ p rev ;4 } ;56 s t a t i c vo id l i s t _ d e l ( s t r u c t l i s t _ h e a d ∗ e n t r y )7 {8 e n t r y −>next −>prev = e n t r y −>prev ;9 e n t r y −>prev−>n e x t = e n t r y −>n e x t ;

10 }

This function essentially removes the given entry fromits list. If the attacker controls the and the

4

Page 6: Dynamic Hooks: Hiding Control Flow Changes within Non ... · USENIX Association 23rd USENIX Security Symposium 813 Dynamic Hooks: Hiding Control Flow Changes within Non-Control Data

USENIX Association 23rd USENIX Security Symposium 817

field from the entry to be deleted, she essentially can trig-ger an arbitrary 8-byte write on a 64-bit architecture. Inparticular, she can write the value of into the mem-ory address (Line 8) and the value ofinto the memory address (Line 9). To use thiscode fragment for a dynamic hook, the attacker could,for instance, modify a specific entry within the systemand set its pointer to point to the return addressof the function and its pointer to pointto attacker-controlled code. When the entry is deleted,the function will then, while processing themalicious pointers, overwrite its own return address andactivate the code of the attacker on its return.

The example code above was selected as thefunction is used throughout the Linux kernel

and demonstrates the arguments stated above. In general,this function is not exploitable by an external attacker, asthe entries that are used by the function are created byother internal functions within the kernel. While thesefunctions initialize the values of the pointers correctly,an attacker that controls the kernel can modify them arbi-trarily, thus creating a new vulnerability. Thefunction does not expect the manipulated values and usesthem without checks. This enables an attacker to con-duct an arbitrary 8-byte write, which is not enough tointroduce shellcode into the system, but is sufficient totransfer the control flow to a previously prepared coderegion. In addition, the attacker is not hindered by anyof the protection mechanisms used by the Linux kernel,since she can disable W ⊕X for her code1, does not needto overwrite the stack canary, and knows the address ofher code or can calculate the address of the location ofthe return address2. Finally, since the functionis invoked by many other functions within the kernel, adynamic hook within this function is very effective.

3.3 Suitable VulnerabilitiesIn principle, any kind of vulnerability can be used to im-plement a dynamic hook. In this paper, however, wewill, for the sake of simplicity, focus on n-byte writes,sometimes also referred to as write-what-where primi-tives, such as the one presented in the previous example.Such n-byte writes enable an attacker to modify n bytesat an arbitrary memory location. In our example, the at-tacker controls an 8-byte write to an arbitrary memoryaddress. In x86-assembly, n-byte writes are essentially

1Note that this is necessary since the first write (Line 8) of the exam-ple will write the return address ( ) into the code ( ) ofthe attacker. However, this is not a problem in practice, as the attackercan set her code to be writable and executable. In fact, this is even thedefault for memory allocated in the Linux kernel via .

2The location of the return address depends solely on the address ofthe kernel stack and the size of the current function’s stack frame. Bothvalues are known to the attacker as we will describe in Section 4.2.

a memory instruction for which the source and thedestination operand can be controlled by an attacker. Anexample of a potential 8-byte write vulnerability in Intelassembly syntax is the following instruction:

mov [ r a x ] , rbx

If the attacker can control the contents of andat the time the instruction is executed, she can misuse itfor a dynamic hook. It goes without saying that suchinstructions appear frequently within software. In theLinux 3.8 kernel binary, for instance, we found more than103,000 instructions similar to the one shown abovethat can potentially be abused for an 8-byte write. Thiscorresponds to about 5% of all instructions (1,976,441)within the tested Linux kernel binary (Linux 64-bit 3.8kernel). Note that this does not include the approxi-mately 58,000 one, two, or four byte write instructions.Together, this equates to a total of 8% of all instructionsthat can potentially be used to realize a dynamic hook.

3.4 Types of Dynamic Hooks

Generally speaking, there are two different types of dy-namic hooks: dynamic control hooks and dynamic datahooks. The former target the control flow of the victimapplication and can be used as an alternative to tradi-tional hooks since they enable an attacker to interceptevents within the application. Dynamic data hooks, onthe other side, do not target control data, but rather othercritical data structures within an application. As an ex-ample, consider that an attacker wants to install a back-door. For this purpose, she places a dynamic hook into acontrol path that can be triggered from userland such as aspecific system call. However, instead of changing con-trol data, this dynamic hook will upon invocation directlyoverwrite the credentials of a predefined process and el-evate its privileges to root. Since the task credentials areusually a data value, this can be achieved with a singlememory write. Thus, instead of overwriting a return ad-dress, the attacker simply sets her hook to overwrite thememory location where the task credentials reside. Aspointed out by Chen et al. [10], such non-control dataattacks can be quite powerful.

While dynamic data hooks do not modify the controlflow directly, they can be used to influence the controlflow at a later point in time. Consider for instance datathat resides in memory and is processed by a just-in-timecompiler. If an attacker manages to overwrite this datawith dynamic hooks before it gets compiled, she can in-fluence the instructions that are introduced into the sys-tem, which can lead to arbitrary code execution [7].

5

Page 7: Dynamic Hooks: Hiding Control Flow Changes within Non ... · USENIX Association 23rd USENIX Security Symposium 813 Dynamic Hooks: Hiding Control Flow Changes within Non-Control Data

818 23rd USENIX Security Symposium USENIX Association

3.5 Properties of Dynamic Hooks

Components. Dynamic hooks always consist of twointegral components. On the one hand, there is the in-struction that activates the hook, which we refer to as thetrigger. In the case of an 8-byte write, the trigger is the

instruction that conducts the write on behalf of theattacker. Every path that leads to the execution of thetrigger is referred to as a trigger path. On the other hand,there is the data that was manipulated by the attacker andencodes the malicious action that the attacker wants toconduct. This is the payload of the hook. For n-bytewrites, the payload usually consists of two manipulatedpointers: the destination pointer, which contains the ad-dress that will be written to and the source pointer, whichspecifies the value that will be written.

Binding. While the same trigger can be shared amongdifferent dynamic hooks, each hook in general requiresits own payload. The reason for this is that the payloadcontains the actual data that specifies the control transfer.This data, however, will only be valid in a particular con-text. To overwrite a specific return address, for example,we must first be able to predict its exact location. Thisrequires us to know the exact path leading to the use ofthe payload by the trigger. In practice, this means thata payload and thus the dynamic hook is usually closelybound to a specific execution path. The closer the con-nection between an execution path and a dynamic hook,the better the control of the attacker over the hook.

In an ideal situation, a dynamic hook is exclusivelybound to a specific execution path. In this case, thepayload of the hook is only processed in the executionpath that leads to its trigger. This enables the attackerto predict possible modifications applied to the payloadbefore its use in addition to the state of the machine atthe time of the exploitation with high probability, sinceshe must only consider a single execution path. Similarto traditional exploits, this is essential information thatis required to be able to setup a dynamic hook correctly.After all, the attacker needs to correctly predict the exactaddress of the control data, which should be overwrit-ten and overwrite it with the precise address of the targetcode region. Without knowing the exact layout of thestack as well as the transformations that may be appliedto the payload before its use, this is a hard task.

If there are multiple paths that use the payload, thedynamic hook is only loosely bound to the path leadingto the trigger instruction. The more execution paths thepayload affects, the more difficult it will become for anattacker to control the hook. On the one hand, this is dueto the fact that it will become increasingly difficult topredict the necessary memory addresses and transforma-tions as has been described above. On the other hand, the

more functions access the actual payload that the attackermodified, the more likely it will be that the hook intro-duces side effects into the application that may lead tounexpected behavior and crash the application. Consider,for instance, that an entry that is used by thefunction has been modified to act as payload for a dy-namic hook. If the same entry is used by a differentfunction to iterate through all elements within the list,this will most likely lead to a crash of the system as the

and the pointer do not point to the previousand next element, respectively, as would have been ex-pected.

Coverage. Another important property of a dynamichook is coverage: as dynamic hooks should be closelybound to the execution path containing the trigger, itis essential that this triggering path is always executedwhen the target event that should be hooked is invoked.In this case, the dynamic hook provides full coverage.Otherwise, the hook may only be able to intercept someexecution paths of the target event, but not all. In thatcase, the hook has only partial coverage and must thus becombined with other dynamic hooks to be able to achievefull coverage of the target function. Note that while bind-ing is a property of the payload of the hook, coverage isa property of the trigger instruction.

3.6 Automated Path ExtractionSo far we have discussed the concept of dynamic hooksand provided an overview of the different types of dy-namic hooks and their properties. However, the creationof a dynamic hook still remains a manual process, whichcan—as in the case of traditional exploitation—be verytime-consuming and error-prone especially for complexbinaries such as modern OS kernels. We now describehow paths for dynamic hooks can be obtained automat-ically for a given binary. This is essentially a two-stepprocess: In the first step, we make use of static programslicing [40, 45] to extract potential paths that could beused for a dynamic hook. In the second step, we thenemploy symbolic execution [17, 34] to verify the satisfi-ability of the paths and to generate detailed informationfor their exploitation.

3.6.1 Program Slicing

To find possible locations for dynamic hooks within anapplication, an attacker has to find triggers that make useof a payload that she can control. Since trigger instruc-tions can be as simple as a memory move, there usuallyexist many triggering instructions in many paths of theapplication. To identify whether a particular trigger in-struction can be used for a dynamic hook, it is necessary

6

Page 8: Dynamic Hooks: Hiding Control Flow Changes within Non ... · USENIX Association 23rd USENIX Security Symposium 813 Dynamic Hooks: Hiding Control Flow Changes within Non-Control Data

USENIX Association 23rd USENIX Security Symposium 819

to analyze the data flow that leads to the particular in-struction. One technique that can be used for this pur-pose is static program slicing [40, 45].

The basic idea behind static program slicing is to tra-verse back through the control flow graph (CFG) of anapplication starting from a sink node and to extract eachnode that directly or indirectly influences the values usedat the sink. Applied to the problem of finding dynamichooks, static program slicing thus allows us to deter-mine where the values of the source and the destinationpointer in an n-byte write originate. To achieve this, wefirst identify all potentially vulnerable instructionswithin a given binary. These are essentially all in-structions which move a value contained within a registerto a memory location specified by another register. In thenext step, we then traverse the CFG of the binary back-wards at the assembler level until we encounter the firstinstruction that modifies the source register of the move.We record this instruction and continue with our back-ward traversal. Instead of looking for instructions thatmodify the source register of the original move, however,we will from here on search for instructions that modifythe source register of the last instruction we recorded. Ifwe continue this process, we eventually obtain the reg-ister or memory location where the value that is later oncontained within the source register originates. We thenrepeat the process for the destination register. All theinstructions that we recorded using this method form aslice of the binary. Each slice contains all the instruc-tions that affect a given vulnerable instruction.

We implemented a slicer which is capable of extract-ing potential paths that could be used for n-byte writesfrom a 64-bit Linux or Windows kernel binary. The im-plementation of the slicer is based on the disassemblerIDA Pro [14]. In particular, we make use of the CFG thatIDA provides to perform the above described static inter-procedural def-use analysis. Starting from each trigger,we perform a breadth-first search in a backwards direc-tion. We hereby make use of a register set to conduct theactual analysis. Initially, this register set consists of thesource and destination register. Whenever we encounteran instruction that modifies a register included within theregister set, we add the source register of the instructionto the set and remove the modified register. Since wewalk backwards through the instruction stream, this ef-fectively allows us to record and track the def-use chainsfor the source and destination register. In addition, werecord all instructions that we visit along the way, in or-der to be able to reconstruct the path that we explored incase we consider it to be potentially exploitable.

The challenge that remains to be solved is to deter-mine whether a slice can be used for a dynamic hookor not. To address this problem, we must know whetherthe registers in the vulnerable move can be controlled by

an attacker. We consider this to be the case if the val-ues of the source and destination register originate froma global variable. The reasoning behind this approachis that the data used within the move in this case stemsfrom a persistent location. Consequently, to control thefinal instruction, an attacker can modify the pointerchain starting from the global variable.

To identify global variables in the kernel, we assumethat each access to a fixed address or the Global Seg-ment register (GS) constitutes an access to a global vari-able. The reason for the latter is that both the Linuxand Windows kernels store important global variablesthat are valid for a particular CPU within a memory re-gion pointed to by this register. For instance, both Linuxand Windows store the address of the( ) or the ( ) structure of theprocess that is currently executing in this memory region.

If both the source and the destination register originatefrom a fixed address or the memory region pointed to byGS, we consider the path to be potentially exploitableand record it such that it can later on be used as input forthe symbolic execution engine.

3.6.2 Symbolic Execution

Symbolic Execution is a well-known program analy-sis method that has been proposed over three decadesago [8, 17]. The basic idea of symbolic execution is totreat input data of interest as symbols rather than con-crete values. These symbols can represent any possiblevalue and as we walk over the code of a program, thevalues become constrained. Branches, for instance, setup conditions that constrain symbolic variables. Each ofthese conditions can be represented as a logical formulawhich can then be fed into an SMT solver to obtain con-crete values that satisfy the path conditions. A profoundintroduction is available in the literature [25, 34].

We use forward symbolic execution to verify the sat-isfiability of our sliced paths and to produce detailed in-formation for the creation of the dynamic hooks. In theprocess, we utilize the VEX IR, which is a RISC likeintermediate representation with single static assignment(SSA) properties, deeply connected to the popular Val-grind toolkit [24]. Due to space limitations, we refrainfrom discussing this intermediate language in detail.

To verify satisfiability, we transform each basic blockof the sliced path into VEX IR code and execute the codesymbolically. The translation to VEX IR is achieved byutilizing a python framework called pyvex [36]. We dis-mantle every VEX statement that we obtain from pyvexand link the components of the statements into our owndata structures. These data structures are used to walkover the VEX code and by doing so, we semanticallymap the statements to Z3 expressions. Z3 is a theorem

7

Page 9: Dynamic Hooks: Hiding Control Flow Changes within Non ... · USENIX Association 23rd USENIX Security Symposium 813 Dynamic Hooks: Hiding Control Flow Changes within Non-Control Data

820 23rd USENIX Security Symposium USENIX Association

prover developed at Microsoft Research that we use tosolve our formulas [23].

As we walk over the VEX code of our sliced paths, wealso keep track of three global contexts, i.e., a memorycontext, CPU context, and the current jump condition.Each context consists of Z3 expressions that semanticallymirror the current state of the execution. Additionally,each basic block also keeps track of temporary VEX IRvariables in SSA form. By constant propagation, we usethese variables to resolve source and destination. Eachstore, load, and register set statement updates the corre-sponding context in form of Z3 expressions. Once we hita jump condition, we ask the solver whether we can takethe jump according to our context. If no solution exists,we can filter out the path. An unsatisfiable set of formu-las stops execution of the current path, and we move onwith the next slice.

At this point it is worth mentioning that we do not usesymbolic execution in the traditional sense to achievecode coverage. Our main goal is to check whether wecan walk down our paths and to determine what valuesets lead us to the end of the slice. We use the symbolicformulas to generate detailed information about the con-trolled registers at the time the vulnerability is triggeredas well as the jump conditions that must be fulfilled toactually reach the trigger. By processing over the VEXcode, the solver also gives us possible values to set.

4 Experiments

Based on the slicer and the symbolic execution engine,we created a prototype that we used to automatically ex-tract paths for dynamic hooks in a fully patched Win-dows 7 SP1 64-bit kernel and a Linux 64-bit 3.8 kernel.We chose this approach for three main reasons. First andforemost, since malware nowadays generally attacks thekernel, this approach allowed us to test the prototype in arealistic scenario. Second, kernel binaries are especiallycomplex, which makes them well suited for a thoroughtest of our implementation. Finally, by targeting Win-dows and Linux, the experiments show that the proposedmechanism is applicable to two of the most popular OSs.

In the following, we first discuss the results that weobtained by providing detailed statistics about the auto-matically extracted paths for both kernels. To demon-strate how useful the prototype is when it comes to theactual creation of the hooks, we also describe three con-crete POCs for dynamic hooks that we created based onthe information that the prototype provided.

4.1 Automated Path ExtractionAs stated above, we tested our prototype with a fullypatched Windows 7 SP1 64-bit kernel and a Linux 64-bit

3.8 kernel. The goal of the experiment was to automati-cally extract trigger paths that could then either be usedby a human expert to manually design dynamic hooks orto automatically generate exploits. Table 1 provides anoverview of the obtained results.

At first, we determined the number of instructionscontained within both kernel binaries for reference. Inthe next step, we obtained the number of potentially ex-ploitable 8-byte instructions. In the process, we onlycounted those instructions that move data from onegeneral purpose register into a memory location speci-fied by another general purpose register with the condi-tion that the involved registers were neither nor .The reason for this restriction is that our prototype imple-mentation currently does not support a memory model,meaning that we cannot track memory store and load op-erations in our slicer, which is why we currently ignoreany path that requires this functionality. We will coverthis limitation in more detail in Section 5.3. As Table 1shows, about 2 % of all instructions within the tested ker-nels are instructions that fulfill this criteria.

Next, we used the slicer to extract potentially ex-ploitable slices for each of the identified moves. Incase of Linux, the slicer considered about 4% of the

instructions as potentially exploitable, while on theWindows side about 20% of the instructions weremarked as possibly exploitable. We assume that the sig-nificant difference between Windows and Linux stemsfrom the fact that Linux has substantially more in-structions that store or load data from memory (61,651vs 37,272). Since the slicer does not support a memorymodel, it will abort whenever such a instruction ispart of a def-use chain. Due to their number, this sce-nario is more likely to occur on Linux than on Windows.

Finally, we symbolically executed each of the obtainedslices. In total, this led to 566 exploitable paths for Linuxand 379 exploitable paths for Windows. The symbolicexecution engine thereby produced the required value foreach conditional jump within the path and detailed infor-mation of the vulnerable instruction. In particular,the output3 specifies exactly which memory addressesmust be modified in what way to pass the conditionaljumps and where the source and destination values arelocated, respectively. This information can directly beapplied to generate exploits or to manually create a dy-namic hook as we will show in the next section.

4.2 Prototypes

We now present three concrete examples of dynamichooks to illustrate the capabilities and properties whichhave been discussed throughout the paper. We created

3An example of the output is shown in Section 4.2.3.

8

Page 10: Dynamic Hooks: Hiding Control Flow Changes within Non ... · USENIX Association 23rd USENIX Security Symposium 813 Dynamic Hooks: Hiding Control Flow Changes within Non-Control Data

USENIX Association 23rd USENIX Security Symposium 821

OS Size Instructions 8-byte moves Slices Paths

Linux 3.8 64-bit ( ) 18.8 MB 1,976,441 42,130 (2.1%) 1753 (4%) 566 (32%)Windows 7 SP1 64-bit ( ) 5.3 MB 1,330,791 26,694 (2.0%) 5450 (20%) 379 (07%)

Table 1: Overview of the 8-byte moves, the potentially exploitable slices, and the exploitable paths according to thesymbolic execution engine for the analyzed Linux and Windows kernels.

these examples based on the output provided by our pro-totype. The first and the third example focus on a dy-namic control hook, while the second example demon-strates a dynamic data hook. To ease the understand-ing of the examples, all hooks leverage a trigger instruc-tion within the function (as explained in Sec-tion 3.2) or its Windows equivalent. The first two hookswere implemented for Linux 3.8 and an Intel Core i7-2600 3.4 GHz CPU. To demonstrate that the proposedconcept is similarly applicable to Windows, the thirdhook was implemented on a fully patched version ofWindows 7 SP1 running on the same CPU.

4.2.1 Dynamic Control Hook: Intercepting Syscalls

A common functionality that kernel level malware re-quires is the possibility to intercept system calls. In thisexample, we show how a single dynamic hook can beused to intercept all system calls for a particular process.To achieve this, the hook is placed into the execution flowof the system call handler, which is—independent of thesystem call mechanism that is used (i.e., interrupt-based,sysenter-based, or syscall-based)—invoked whenever asystem call on the x86 architecture is executed. The mainpurpose of the syscall handler is to invoke the actual sys-tem call by using the system call number as an index intothe system call table.

Similar to other functions within the kernel, the sys-tem call handler can be audited for debugging reasons.Auditing can be enabled or disabled within the flagsfield of the struct associated with eachprocess. By setting the flag, ev-ery system call conducted by a process will also lead tothe invocation of the auditing functions. In particular,the function will be executedbefore the invocation of a system call and the function

will be executed after the sys-tem call, but before the system call handler hands controlback to user space. In our POC, the dynamic hook is setwithin the function.

When syscall auditing is enabled, thefunction records infor-

mation about the system call such as the syscallnumber and the arguments of the syscall within theaudit context of the process. The purpose of the

function is to reset the audit

context of the task before the system call returns. Inthe process of resetting the audit context, this functioninvokes the inline function , whichresets the within the audit context:1 s t a t i c i n l i n e void a u d i t _ f r e e _ n a m e s (2 s t r u c t a u d i t _ c o n t e x t ∗ c o n t e x t ) {3 . . .4 l i s t _ f o r _ e a c h _ e n t r y _ s a f e ( n , nex t ,5 &c o n t e x t −>n a m e s _ l i s t , l i s t ) {6 l i s t _ d e l (&n−> l i s t ) ;7 }8 . . .9 }

The function essentially iteratesover the of the audit context (Line 4) anddeletes every entry within the list (Line 6). Consequently,if we control the , we can control the entrythat is passed to the function, which in turn al-lows us to exploit its vulnerability. As theis not modified by the func-tion or anywhere else in the kernel4, the attacker isfree to modify it in any way she wants. That is, the

structure is exclusively bound to the exe-cution path within the syscall handler that we use for ourdynamic hook.

While the structure seems to be perfectlysuited for a dynamic hook, the triggering path placesadditional constraints on the hook. The problem arisesdue to the fact that the function is containedwithin a loop that iterates over all entries within the

list (Line 4). To iterate through the list,the loop will essentially follow the pointer in everyentry until one of them points back to the first elementin the list, which is . Since wewant to modify the and the pointer of an en-try within the list to conduct an arbitrary 8-byte write, wehave to take this problem into account and assure that thelist iteration will eventually terminate. To achieve this weinitialize the audit context as shown in Figure 1.

The basic idea behind this setup is to make use of aspecial address, referred to as a “magic address”, thatis a valid memory address, but at the same time con-tains valid x86 instructions. Due to little-endian byteorder, these valid instructions must be contained in re-

4While there are other functions in the kernel that try to access the, these attempts can be blocked by setting the first member

within the audit context ( ) to one.

9

Page 11: Dynamic Hooks: Hiding Control Flow Changes within Non ... · USENIX Association 23rd USENIX Security Symposium 813 Dynamic Hooks: Hiding Control Flow Changes within Non-Control Data

822 23rd USENIX Security Symposium USENIX Association

Trampoline

&context->name_list

Magic_Address

next:

next:

prev:

prev: Return Address

&Magic_Address

&context->name_list+ 0xe6eb:

+ 0x230:

+ 0x248:

Figure 1: The audit context structure that the attackeruses to set a dynamic hook within .

verse order within the address. In Figure 1, the in-struction encoded into the address is a negative relativejump ( (address) ⇒ (instruction)) thatwill upon execution transfer control to a trampoline, thatthen transfers control to an arbitrary address. Initiallywhen the loop begins iterating over the , itfollows the pointer to the first entry within the list,which is located at the magic address. The pointerstored at the magic address will in turn point back to the

, thus fulfilling the loop condition. How-ever, before the loop exits, the first entry in the list (lo-cated at the magic address) is processed by thefunction. Since the pointer of this entry points tothe location of a return address, the functionwill overwrite this return address with the value stored inthe pointer (prev → next = next), which points to

. Consequently, as soon as thereturn address is used, control will be transferred to theaddress of where the magicaddress is stored, leading to the execution of the magicaddress and the activation of the trampoline code. Notethat the hook requires the audit context region createdby the attacker to be writable and executable, since the

function conducts two write operations as hasbeen described in Section 3.2. This is not a big problemin practice, since every memory region allocated with

is by default writable and executable.

The final problem that remains is which return addresswe are actually going to overwrite and how we can pre-dict its location. As previously stated, the syscall handleris invoked before every system call and it will invoke theactual function handling the syscall. Thus, if we knowthe stack frame size of the syscall handler and the lo-cation of the kernel stack, we can predict where the re-turn address of the function that is invoked by the syscallhandler resides. The stack frame size can be obtainedfrom the assembler code of the syscall handler, while the

location of kernel stack can be obtained from a kernelvariable ( ). The targetreturn address will then reside at

.

Summary. A dynamic control hook for intercept-ing all system calls for a particular process can beplaced in the function. To en-sure that execution passes through this function, we setthe flag within thestruct of the target process. In the next step, we mod-ify the audit context of the target process in the way de-scribed above and use a trampoline to control the execu-tion flow. This enables us to reliably divert the controlflow at run-time. The resulting dynamic hook will havefull coverage and be exclusively bound to the executionpath leading to the function.

4.2.2 Dynamic Data Hook: Installing a Backdoor

In the second example, we demonstrate the possibilitiesof dynamic data hooks. In particular, we show how adynamic data hook can be used to install a backdoorwithin a Linux system that is capable of elevating the taskrights of a predefined process to root. For this purpose,we leverage the system call, which enables oneprocess to attach to another process for debugging rea-sons. To install the backdoor, we simulate that a processused the system call to attach to the tar-get process (i.e. the process that will contain the hook).This is achieved by manually applying the changes thatthe function conducts to the internaldata structures of the target process. Most importantly,the field of the task must be updated to include

, the field within the task mustbe set to 1, and the field must be set to the pro-cess which will later trigger the backdoor. We will deferthe discussion of this last change for the moment and ex-plain it in more detail later on.

Once the changes of the func-tion have been simulated, it is possible to invokethe function on the so prepared pro-cess. The execution of this function eventually leadsto the invocation of the function,which in turn invokes the function using the

pointer within the target process as argu-ment:1 void _ _ p t r a c e _ u n l i n k (2 s t r u c t t a s k _ s t r u c t ∗ c h i l d ) {3 . . .4 l i s t _ d e l (& c h i l d −> p t r a c e _ e n t r y ) ;5 . . .6 }

To use this code fragment for a dynamic data hook,we modify the ptrace_entry → next pointer and the

10

Page 12: Dynamic Hooks: Hiding Control Flow Changes within Non ... · USENIX Association 23rd USENIX Security Symposium 813 Dynamic Hooks: Hiding Control Flow Changes within Non-Control Data

USENIX Association 23rd USENIX Security Symposium 823

ptrace_entry → prev pointer of the target process. Thisenables us to conduct an arbitrary 8-byte write when the

function is invoked during the execution of. In particular, we set the pointer

to point to the task credentials that we want to overrideand the pointer to an address that is writable andends with four zero bytes. To understand this, we have totake a look at the Linux task credential structure, whichdefines the access rights of a process:

1 s t r u c t c r e d {2 . . .3 k u i d _ t u i d ; /∗ r e a l UID ∗ /4 k g i d _ t g i d ; /∗ r e a l GID ∗ /5 k u i d _ t s u i d ; /∗ saved UID ∗ /6 k g i d _ t s g i d ; /∗ saved GID ∗ /7 k u i d _ t e u i d ; /∗ e f f e c t i v e UID ∗ /8 k g i d _ t e g i d ; /∗ e f f e c t i v e GID ∗ /9 . . .

10 } ;

Each task contains three pairs of access rights and eachaccess right pair consists of a user id and a group id. Mostimportant for us is the effective user id ( ), whichspecifies the effective access rights of a process. Sincethe root user in Linux generally has the user id zero, ourgoal is to overwrite the field, which has a size of 4bytes, with zeroes. If we choose an address for thepointer that has its lower 32-bits set to zero and addition-ally set the pointer to point to the field of theprocess whose privileges we want to elevate, we will—due to the little endian byte order—overwrite the(prev → next = next) field with zeroes and thus set theaccess rights of the process to root. However, becausethe function will also write the pointerinto the address of (next → prev = prev),we have to ensure that the address used within thepointer points to a writable memory region that does notcontain crucial data. A possible address that can be usedfor this purpose is since this ad-dress usually points to the first 8-bytes of the physicalmemory of the machine, which is not used by the Linuxkernel. Finally, note that we will also override theof the process with the upper 32-bits of the address in thenext pointer. This will, however, not affect the process aslong as it has a valid .

We can now set up a dynamic hook as follows: First,we need to select a target process that remains runningon the system as it will contain the above described dy-namic hook. Good candidates are therefore backgrounddaemons such as the SSH daemon. Second, we need tospecify the victim process whose privileges we want toelevate and setup the dynamic hook within the target pro-cess. Since we need to know the address of the task structof the victim process in order to be able to set thepointer to its field, this process also needs to remainrunning. A good choice in this case could, for instance,

be a shell process within a screen session.To activate the backdoor, we need to call the

syscall with the argument on the targetprocess. However, the backdoor cannot be activated byany process because only the tracing process can detachfrom the traced process. Since we simulate the changesconducted by , the process which canexecute the call, is the process that wespecify as during the setup of the dynamic hook.While this ensures that the backdoor cannot be triggeredby accident, this requires us to specify the process thattriggers the backdoor when we setup the dynamic hook.The easiest way to solve this problem is to specify thevictim process as parent of the target process. In thiscase the victim, whose privileges will be elevated, cantrigger the backdoor itself.

Summary. A dynamic data hook can be used to imple-ment a backdoor that can be triggered from user spacewith arbitrary access rights. In our example, the back-door is closely bound to the process that was specifiedas the tracing process and to the execution path within

. In addition, the hook only providespartial coverage as only the detach call to a specific pro-cess will trigger it, which is desired behavior in the caseof a backdoor.

4.2.3 Dynamic Control Hook: Process Termination

To show that the proposed hooking concept can be ap-plied to other OSs as well, we will in our final examplepresent a dynamic control hook that we implemented ona fully patched version of Windows 7. In particular, thehook is capable of intercepting the termination of an ar-bitrary process, which can, for instance, be useful in situ-ations where a malicious process on the system is foundand terminated by a security application or the user. Dueto the hook, the malware would be notified of this eventand could react to it.

When a process is exiting on Windows 7, the functionis invoked which in turn invokes

various cleanup functions that prepare the termination ofthe process. One of these functions is

. To support a wide range of appli-cations, Windows provides processes with the possibilityto request a change to the system’s clock interval [32].This enables programs that have a demand for a fasterresponse time to decrease the clock interval and thus toincrease the number of clock-based interrupts. When aprocess emits such a request, the process is added to the

list, which is used by the OS tomanage all timer resolution changes. As the name sug-gests, the purpose of the

function is to remove processes from the man-

11

Page 13: Dynamic Hooks: Hiding Control Flow Changes within Non ... · USENIX Association 23rd USENIX Security Symposium 813 Dynamic Hooks: Hiding Control Flow Changes within Non-Control Data

824 23rd USENIX Security Symposium USENIX Association

agement list once they exit. Our automated path extrac-tion tool discovered the following path within this func-tion:

1 −−−−SLICE−−−−2 0 x000000014042c396 mov rax , gs :188 h3 0 x000000014042c39f mov rbx , [ r a x +70h ]4 0 x000000014042c3c6 mov rcx , [ rbx +4A8h ]5 0 x000000014042c3cd mov rax , [ rbx +4B0h ]6 0 x000000014042c3d4 mov [ r a x ] , r c x7 0 x000000014042c3d7 mov [ r c x +8 ] , r a x89 −−−−SYMBOLIC−−−−

10 Jump C o n d i t i o n i n : BB_0x14042c39011 Concat (0 x0 , E x t r a c t (0 x1f , 0x0 ,12 MEM[RBX+0 x440 ] ) ) >> Concat (0 x0 , 0 xc ) &1 == 01314 CPU CONTEXT/CONTROLLED REGISTERS15 RCX −> MEM[MEM[MEM[0 x188+GS]+0 x70 ]+0 x4a8 ]16 RAX −> MEM[MEM[MEM[0 x188+GS]+0 x70 ]+0 x4b0 ]

To remove a process from thelist, the

function obtains the forward and the backward pointer(Line 4 and Line 5) from the structure of theprocess and performs the discussed list delete operation(Line 6 and Line 7). The only prerequisite for this pathis that the 13th least significant bit of the memory wordat location +0x440 is not set (Line 11). Bymanipulating this memory word and the pointers, whichare located within in the struct of the processat offset 0x4A8 (Line 4) and offset 0x4B0 (line 5) re-spectively, we can thus perform an arbitrary 8-byte writeand change the control flow. In our POC we set the for-ward pointer ( ) to point to our shellcode and the back-ward pointer ( ) to point to the return address of

. Just as in the caseof our first example, the location of the latter can be ob-tained by subtracting the sum of the stack frames of theinvoking functions from the start address of the kernelstack, which is stored within the variablecontained within the structure of the thread ofthe process. Similarly, the area where the shellcode re-sides must be writable and executable. On Windows,we can allocate such a memory region by invoking the

function with the argument.

One last problem that remains, however, is that theentry structure of a process is

unfortunately not exclusively bound to the path of ourdynamic hook, since the list isalso used by other functions such as

. The solution to this problem is quite sim-ple, though: since the list isnot critical for the execution of a process and the

function does on topof that not iterate through the list, but rather accessesthe forward and backward pointers directly, we can sim-

ply remove the entry from the linked list. As a re-sult, the manipulated entry will no longer be processedby other management functions, which will bind the

entry structure exclusively toour trigger path. In our experiments, removing processesfrom the list did not affect theirexecution in any way. The proposed dynamic hook there-fore serves as an example that an exclusive binding of ahook payload must not be given by the target application,but can also be manually enforced by the creator of thehook.

Summary. By manipulating theentry structure of a process in the way described

above we can install a dynamic hook and intercept thetermination of an arbitrary process on Windows. Whilethe manipulated structure is by default not exclusivelybound to the trigger path, the creator of the hook canenforce an exclusive binding manually by removing themanipulated entry from its linked list. In addition, thepresented dynamic hook had full coverage in our experi-ments. It was even triggered if we forcefully terminatedthe process using the task manager.

5 Discussion

Up to this point, we have not discussed what kinds oftransient control data exist. This is why it may seem tothe reader that dynamic control hooks could be mitigatedby protecting return addresses alone. In this section, wecover this topic in more detail and show that this is notthe case. In addition, we cover possible countermeasuresagainst dynamic hooks and review the limitations of theproposed hooking concept and our current prototype.

5.1 Transient Control Data

Instead of targeting persistent control data such as func-tion pointers in the system call table, dynamic controlhooks change transient control data at run-time. Whilereturn addresses are a popular example of transient con-trol data, it is not the only kind of transient control datathat exists. For instance, if a function allocates a localfunction pointer, this pointer will reside on the stack andnot in the data segment or the heap. Instead of over-writing the return address, an attacker can in such a casesimilarly target the function pointer. While this is a ratherunlikely scenario, it demonstrates a very important classof attacks where a local variable on the stack is changedto achieve the desired control flow change. This class ofattacks is not restricted to function pointers alone. Con-sider, for example, the following code from the sys-

12

Page 14: Dynamic Hooks: Hiding Control Flow Changes within Non ... · USENIX Association 23rd USENIX Security Symposium 813 Dynamic Hooks: Hiding Control Flow Changes within Non-Control Data

USENIX Association 23rd USENIX Security Symposium 825

tem call in the Linux kernel5:1 s t r u c t fd {2 s t r u c t f i l e ∗ f i l e ;3 i n t n e e d _ p u t ;4 } ;56 SYSCALL_DEFINE3 ( read , unsigned i n t , fd , char7 _ _ u s e r ∗ , buf , s i z e _ t , c o u n t ) {8 s t r u c t fd f = f d g e t ( fd ) ;9 . . .

10 r e t = f . f i l e −>f_op−>r e a d ( f . f i l e , buf ,11 count , pos ) ;12 . . .13 }

In this case, a local structure ( ) is al-located on the stack (Line 8). The structure containsa pointer to another structure ( ),which in-turn contains a function pointer that is calledin Line 10. With the help of a dynamic hook, an at-tacker could modify the pointer within the local struc-ture (Line 2) and point it to an attacker-controlled struc-ture instead. If she manages this before the function callin Line 10 is executed, this will effectively allow her tocontrol the function call and thus enable her to arbitrarilychange the control flow.

Instead of targeting a return address or a functionpointer directly, the attacker in this scenario modifies alocal pointer on the stack. This approach enables her tocontrol any data that the local function accesses usingthis pointer. In the kernel, where objects in general areaccessed through pointer chains, this represents a power-ful attack vector, which effectively provides control overany object that the pointer references. Since similar codeexists in many other functions within the kernel, this at-tack vector must be taken into account when one consid-ers countermeasures against dynamic hooks.

5.2 CountermeasuresDynamic hooks are installed by an attacker that alreadycontrols the application, which renders many of the ex-isting defense mechanisms against exploits ineffective.However, while dynamic hooks are a powerful attackvector, there are, of course, countermeasures that can beused to reduce the attack surface. In the following, wefirst discuss possible countermeasures against dynamiccontrol hooks, before we present defense mechanismsfor dynamic data hooks.

Dynamic control hooks. What makes dynamic con-trol hooks difficult to detect is that they do not perma-nently modify control data. Instead, their payload is hid-den within non-control data and the actual control flow

5For better readability we directly included the functioninto the system call. In the actual code the function call in Line 10will occur in the function.

modification only occurs at run-time. This enables themto evade popular hook detection mechanisms such asHookSafe [43] or SBCFI [27], which only protect per-sistent control data, but ignore transient control data onthe stack. However, at some point during the execution,dynamic control hooks must override control data in or-der to divert the control flow. Thus while a dynamic hookmay be hidden at first, it will become visible when it istriggered. The resulting control flow change can poten-tially be detected using control flow integrity (CFI) andrelated approaches [1, 15, 20, 39, 42, 46, 48].

In order to detect dynamic control hooks with CFI, itis crucial that every control transfer of an application isverified. If a single control transfer is missed, this canpotentially be abused by an attacker to install a dynamichook. However, finding all possible control transfer in-structions within complex software such as an OS kernelis a difficult problem. This is especially true if we con-sider attacks on transient control data such as the onepresent in the last section. Even worse, control trans-fer instructions can often have more than a single tar-get. Consequently, one must not only identify all controltransfer locations, but also all the possible targets of thesetransfers to avoid false positives. Additionally, if thereare multiple possible targets for a given control transferinstruction, an attacker can still launch return-to-libc likeattacks [37], which is a general problem of CFI mech-anisms [48]. Finally, every check of a control transfercomes at a cost [39]: the more instructions we verify, thehigher the overhead will be and for applications that areoptimized for performance such as an OS kernel, even asmall overhead can have a huge impact.

While current CFI approaches are not yet able to solveall of these problems, they certainly reduce the attacksurface and make it more difficult to install dynamiccontrol hooks. The results presented in this paper canhelp to further improve these mechanisms by using thediscussed techniques to automatically extract possibletriggers from a given application and adding additionalchecks to verify them. To increase the performance, onecould make use of lazy control flow verification as pro-posed by Bletsch et al. [7]. This could result in an ef-fective and efficient detection system, which might notbe able to eliminate dynamic control hooks entirely, butwill significantly raise the bar for an attacker.

Dynamic data hooks. The defense mechanisms dis-cussed above make use of the fact that dynamic controlhooks have to eventually modify the control flow. Thatis, the detection mechanisms do not focus on the hookitself, but rather target the effects of the hook’s invoca-tion. The idea behind dynamic data hooks is to com-plicate detection even further by modifying non-controldata instead of control data. As a result, defenders can no

13

Page 15: Dynamic Hooks: Hiding Control Flow Changes within Non ... · USENIX Association 23rd USENIX Security Symposium 813 Dynamic Hooks: Hiding Control Flow Changes within Non-Control Data

826 23rd USENIX Security Symposium USENIX Association

longer concentrate on the control flow of the applicationalone, but rather have to detect integrity violations withinthe data of the application.

Verifying the integrity of data structures is a difficultproblem. Petroni et al. [26] were the first to propose ageneral architecture for the detection of kernel data in-tegrity violations. Since then various systems have beenproposed that try to detect or prevent malicious modifi-cation of kernel data structures [9, 15, 19, 30, 33]. Whatis common to all these approaches, however, is that theyonly enforce integrity checks, but leave the creation ofthe actual integrity constraints to a human expert. To thebest of our knowledge, the only approach that tries togenerate integrity constraints for kernel data structuresautomatically is Gibraltar [4]. While this approach pro-vides a good starting point and could support a humanexpert in the creation of integrity constraints, the authorsacknowledge that the generated invariants are “neithersound nor complete” [4]. Creating reliable and evasion-resistant integrity constraints is, however, the basis forthe detection of dynamic data hooks.

To be able to effectively protect kernel data structures,additional research in the field of automatic integrity con-straint generation is required. Techniques that are ableto generate signatures for kernel data structures such asthe ones presented by Lin et al. [21] or Dolan-Gavitt etal. [12], could thereby provide a good starting for furtherresearch, as the generated signatures could potentiallybe used to infer integrity invariants. In the meanwhile,initial defense mechanism could use systems such asHookMap [43] or K-Tracer [18] in combination with thetechniques presented in this paper to generate integrityconstraints for known dynamic hooks that can then beenforced by one of the systems mentioned above.

Summary. While the threat of dynamic control hookscan potentially be reduced with the help of (kernel-level)CFI mechanisms, dynamic data hooks pose a difficultproblem that cannot be easily solved. To detect dynamicdata hooks, reliable integrity constraints are required thatallow the automatic verification of the kernel data re-gions. Until these constraints are available, one could re-duce the attack surface with the help of manual integrityspecifications or by automatically creating integrity con-straints for known attacks.

5.3 LimitationsDynamic Hooks. Dynamic hooks essentially face twolimitations. First and foremost, not every function maycontain a vulnerability that can be used to implement adynamic hook. In contrast, it is likely that there are func-tions which are immune against the attack. However, thisis not a big problem in practice: if a particular function

cannot be hooked directly, it may still be possible to in-tercept calls to the function by hooking a function thatimmediately precedes or follows the function in the exe-cution flow. After all, not every function contains a func-tion pointer either. Function pointer hooks have never-theless been proven to be very effective in practice.

Second, similar to traditional exploits, a dynamic hookmay face restrictions that are caused by the vulnerabilityit is exploiting. For instance, specific hooks such as theone presented in our first prototype (see Section 4.2.1)may require that certain memory areas are writable andexecutable. Depending on its restrictions, a dynamichook may therefore not be suitable for every scenario.This, however, heavily depends on the particular hook.

Automated Path Extraction. While our prototype al-ready produces very valuable paths that can be used toimplement powerful dynamic hooks as we have shownin Section 4.2, it also faces some limitations. First, ourslicer does not yet support a detailed memory model.As a result, we are unable to find dynamic hooks onpaths where registers, which are currently monitored, areloaded with values from the stack. This situation fre-quently occurs when subfunctions are called. In thiscase, the calling function often stores register values tem-porarily on the stack to guarantee that they are not over-written by the subfunction. During our experiments, theslicer ignored 79,853 such paths due to this restriction.

Second, the symbolic execution engine currently onlyhandles a subset of the available x86 instructions. Mostimportantly, it is unable to handle some instructions thatare a ring-0 privilege. This is, however, a restriction inthe VEX intermediate language. In the experiments weconducted, this led to 949 (55%, Linux) and 4,908 (90%,Windows) paths that could not be verified.

Finally, the slicer and the symbolic execution enginecurrently do not consider the properties of binding andcoverage, while determining whether a path could beused for a dynamic hook or not. Consequently, not allof the paths extracted by our prototype will be suited forthe implementation of a dynamic hook. As described inSection 3.5, especially the property of binding can be alimiting factor. If a payload is only loosely bound, it islikely that the hook will introduce side effects that canlead to a crash of the system. Determining automaticallywhether a path has exclusive binding or full coverage isdifficult though. As the discussed POCs show, even pay-loads that initially seem unsuited for the implementationof a dynamic hook can through subtle manipulations ofthe involved data structures yield very reliable hooks. Todesignate the binding of a payload, we thus not only haveto identify whether a payload is used in multiple loca-tions, but we also have to establish how many of thoseusages can be controlled by the attacker. This requires

14

Page 16: Dynamic Hooks: Hiding Control Flow Changes within Non ... · USENIX Association 23rd USENIX Security Symposium 813 Dynamic Hooks: Hiding Control Flow Changes within Non-Control Data

USENIX Association 23rd USENIX Security Symposium 827

a profound semantic understanding of the data structuresand functions involved.

6 Related Work

To the best of our knowledge, Petroni et al. [27] werethe first to consider the hooking of transient control data.However, their work is primarily focused on the detec-tion of persistent control flow modifications. Attacks ontransient control data are thereby only mentioned as alimitation of their system. Hofmann et al. [15] presenteda “return to schedule” rootkit that overwrites return ad-dresses of sleeping processes to periodically invoke itselfand evade hook detection mechanisms. While related toour work, this approach does not leverage exploitationtechniques to change the control of an application at run-time. As a consequence, the technique only enables therootkit to reschedule itself, but it does not allow it to in-tercept events within the system, which is the actual goalof a hooking mechanism.

In addition, there has also been a lot of work con-cerned with the possibilities of non-control data attacks.Chen et al. [10] were the first to demonstrate that non-control data attacks are indeed a dangerous and realis-tic threat. Sparks and Butler [38] presented DKOM as ageneral mechanism to hide objects within kernel space.Baliga et al. [5] extended this work and presented anotherclass of stealthy attacks that do not have the goal of hid-ing objects, but rather target crucial kernel data structuresto subvert the integrity of the system. Finally, Prakash etal. [28] discussed the manipulation of semantic values inthe kernel to evade virtual machine introspection (VMI).

7 Conclusion

In this paper, we presented a novel hooking concept thatwe coined dynamic hooks. The main insight behind thisconcept is that existing hooking mechanisms are basedon the permanent modification of persistent control data.As a consequence, the resulting hooks are constantly ev-ident within the system and can be detected by verifyingpersistent control data alone.

Dynamic hooks solve this problem by targeting tran-sient control data at run-time. This is achieved by apply-ing exploitation techniques to the problem of hooking.To install a dynamic hook, an attacker will modify theinternal data structures of an application in such a waythat its usage will trigger a vulnerability at run-time. Thehook thereby only consists of the modified data as wellas the exploitation logic. This results in a powerful attackmodel with a wide range of possibilities as the attackercan make use of the entire arsenal of exploitation mecha-nisms to achieve her goal. At the same time, the hook

will remain hidden in non-control data until it is trig-gered, which makes dynamic hooks not only powerful,but also difficult to detect in practice.

To show the applicability of the approach, we imple-mented a prototype that is capable of automatically ex-tracting paths for dynamic hooks from recent Linux andWindows kernels. The experiments that we conductedprove that dynamic hooks are not only a dangerous, butare also a realistic threat that can be applied to practicalscenarios such as system call hooking and backdooring.In future work, we plan to further improve our proto-type implementation and to make use of it to generate in-tegrity constraints instead of attack vectors that can thenbe used for the reliable detection of dynamic hooks.

Acknowledgment

We would like to thank the anonymous reviewers fortheir constructive and valuable comments. This workwas supported by the German Federal Ministry of Ed-ucation and Research (BMBF) under grant 16BY1207B(iTES).

References

[1] ABADI, M., BUDIU, M., ERLINGSSON, U., AND LIGATTI, J.Control-flow Integrity. In ACM Conference on Computer andCommunications Security (CCS) (2005).

[2] AVGERINOS, T., CHA, S. K., HAO, B. L. T., AND BRUMLEY,D. AEG: Automatic Exploit Generation. In Symposium on Net-work and Distributed System Security (NDSS) (2011).

[3] BAILEY, M., COOKE, E., JAHANIAN, F., WATSON, D., ANDNAZARIO, J. The Blaster Worm: Then and Now. IEEE Securityand Privacy Magazine 3, 4 (2005).

[4] BALIGA, A., GANAPATHY, V., AND IFTODE, L. DetectingKernel-Level Rootkits Using Data Structure Invariants. IEEETransactions on Dependable and Secure Computing 8, 5 (2011).

[5] BALIGA, A., KAMAT, P., AND IFTODE, L. Lurking in the Shad-ows: Identifying Systemic Threats to Kernel Data. In IEEE Sym-posium on Security and Privacy (2007).

[6] BENCSÁTH, B., PÉK, G., BUTTYÁN, L., AND FÉLEGYHÁZI,M. The Cousins of Stuxnet: Duqu, Flame, and Gauss. FutureInternet 4 (2012).

[7] BLETSCH, T., JIANG, X., AND FREEH, V. Mitigating code-reuse attacks with control-flow locking. In Annual Computer Se-curity Applications Conference (ACSAC) (2011).

[8] BOYER, R. S., ELSPAS, B., AND LEVITT, K. N. SELECT–Formal System for Testing and Debugging Programs by Sym-bolic Execution. In Proceedings of the International Conferenceon Reliable Software (1975).

[9] CARBONE, M., CUI, W., LU, L., LEE, W., PEINADO, M., ANDJIANG, X. Mapping Kernel Objects to Enable Systematic In-tegrity Checking. In ACM Conference on Computer and Com-munications Security (CCS) (2009).

[10] CHEN, S., XU, J., SEZER, E. C., GAURIAR, P., AND IYER,R. K. Non-control-data Attacks Are Realistic Threats. InUSENIX Security Symposium (2005).

15

Page 17: Dynamic Hooks: Hiding Control Flow Changes within Non ... · USENIX Association 23rd USENIX Security Symposium 813 Dynamic Hooks: Hiding Control Flow Changes within Non-Control Data

828 23rd USENIX Security Symposium USENIX Association

[11] CUI, A., AND STOLFO, S. J. Defending Embedded Systemswith Software Symbiotes. In Symposium on Recent Advances inIntrusion Detection (RAID) (2011).

[12] DOLAN-GAVITT, B., SRIVASTAVA, A., TRAYNOR, P., ANDGIFFIN, J. Robust signatures for kernel data structures. In ACMConference on Computer and Communications Security (CCS)(2009).

[13] GOUDEY, H. Microsoft Malware Protection Center, ThreatReport: Rootkits. Tech. rep., Microsoft Corporation,June 2012.

.

[14] HEX-RAYS. IDA Pro, February 2014. https://www.hex-rays.com/products/ida/.

[15] HOFMANN, O. S., DUNN, A. M., KIM, S., ROY, I., ANDWITCHEL, E. Ensuring operating system kernel integrity withosck. In Conference on Architectural Support for ProgrammingLanguages and Operating Systems (ASPLOS) (2011).

[16] HUND, R., HOLZ, T., AND FREILING, F. C. Return-orientedrootkits: Bypassing kernel code integrity protection mechanisms.In USENIX Security Symposium (2009).

[17] KING, J. C. Symbolic execution and program testing. In Com-munications of the ACM (CACM) (1976).

[18] LANZI, A., SHARIF, M. I., AND LEE, W. K-Tracer: A Sys-tem for Extracting Kernel Malware Behavior. In Symposium onNetwork and Distributed System Security (NDSS) (2009).

[19] LEE, H., MOON, H., JANG, D., KIM, K., LEE, J., PAEK,Y., AND KANG, B. B. KI-Mon: A Hardware-assisted Event-triggered Monitoring Platform for Mutable Kernel Object. InUSENIX Security Symposium (2013).

[20] LI, J., WANG, Z., BLETSCH, T., SRINIVASAN, D., GRACE,M., AND JIANG, X. Comprehensive and efficient protection ofkernel control data. IEEE Transactions on Information Forensicsand Security 6, 4 (2011).

[21] LIN, Z., RHEE, J., ZHANG, X., XU, D., AND JIANG, X. Sig-Graph: Brute Force Scanning of Kernel Data Structure InstancesUsing Graph-based Signatures. In Symposium on Network andDistributed System Security (NDSS) (2011).

[22] LITTY, L., LAGAR-CAVILLA, H. A., AND LIE, D. HypervisorSupport for Identifying Covertly Executing Binaries. In USENIXSecurity Symposium (2008).

[23] MICROSOFT-RESEARCH. Z3: Theorem Prover, February 2014.http://z3.codeplex.com/.

[24] NETHERCOTE, N., AND SEWARD, J. Valgrind: A Frameworkfor Heavyweight Dynamic Binary Instrumentation. In ACM SIG-PLAN Conference on Programming Language Design and Imple-mentation (PLDI) (2007). http://www.valgrind.org/.

[25] PASAREANU, C. S., AND VISSER, W. A survey of new trendsin symbolic execution for software testing and analysis. Int. J.Softw. Tools Technol. Transf. 11, 4 (2009).

[26] PETRONI, JR., N. L., FRASER, T., WALTERS, A., AND AR-BAUGH, W. A. An Architecture for Specification-based Detec-tion of Semantic Integrity Violations in Kernel Dynamic Data. InUSENIX Security Symposium (2006).

[27] PETRONI, JR., N. L., AND HICKS, M. Automated detectionof persistent kernel control-flow attacks. In ACM Conference onComputer and Communications Security (CCS) (2007).

[28] PRAKASH, A., VENKATARAMANI, E., YIN, H., AND LIN, Z.Manipulating semantic values in kernel data structures: Attackassessments and implications. In Conference on Dependable Sys-tems and Networks (DSN) (Jun 2013).

[29] RAVI, S., RAGHUNATHAN, A., KOCHER, P., AND HATTAN-GADY, S. Security in embedded systems. ACM Transactions onEmbedded Computing Systems 3, 3 (2004).

[30] RHEE, J., RILEY, R., XU, D., AND JIANG, X. DefeatingDynamic Data Kernel Rootkit Attacks via VMM-Based Guest-Transparent Monitoring. In Availability, Reliability and Security(ARES) (2009).

[31] RILEY, R., JIANG, X., AND XU, D. Guest-transparent preven-tion of kernel rootkits with vmm-based memory shadowing. InSymposium on Recent Advances in Intrusion Detection (RAID)(2008).

[32] RUSSINOVICH, M., SOLOMON, D. A., AND IONESCU, A. Win-dows Internals Part I, 6 ed. Microsoft Press, 2012.

[33] SCHNEIDER, C., PFOH, J., AND ECKERT, C. Bridging the Se-mantic Gap Through Static Code Analysis. In Proceedings ofEuroSec’12, 5th European Workshop on System Security (2012).

[34] SCHWARTZ, E. J., AVGERINOS, T., AND BRUMLEY, D. AllYou Ever Wanted to Know About Dynamic Taint Analysis andForward Symbolic Execution (but Might Have Been Afraid toAsk). In IEEE Symposium on Security and Privacy (2010).

[35] SHACHAM, H. The geometry of innocent flesh on the bone.In ACM Conference on Computer and Communications Security(CCS) (2007).

[36] SHOSHITAISHVILI, Y. Python bindings for Valgrind’s VEX IR,February 2014. https://github.com/zardus/pyvex.

[37] SOLAR DESIGNER. Getting around non-executable stack (andfix), Aug. 1997.

[38] SPARKS, S., AND BUTLER, J. Shadow Walker: Raising The BarFor Windows Rootkit Detection. Phrack 11, 63 (2005).

[39] SZEKERES, L., PAYER, M., WEI, T., AND SONG, D. SoK:Eternal War in Memory. In IEEE Symposium on Security andPrivacy (2013).

[40] TIP, F. A survey of program slicing techniques. Tech. rep., Am-sterdam, The Netherlands, The Netherlands, 1994.

[41] VOGL, S., PFOH, J., KITTEL, T., AND ECKERT, C. Persistentdata-only malware: Function Hooks without Code. In Symposiumon Network and Distributed System Security (NDSS) (2014).

[42] WANG, Z., AND JIANG, X. HyperSafe: A Lightweight Ap-proach to Provide Lifetime Hypervisor Control-Flow Integrity.In IEEE Symposium on Security and Privacy (2010).

[43] WANG, Z., JIANG, X., CUI, W., AND NING, P. Countering ker-nel rootkits with lightweight hook protection. In ACM Confer-ence on Computer and Communications Security (CCS) (2009).

[44] WANG, Z., JIANG, X., CUI, W., AND WANG, X. CounteringPersistent Kernel Rootkits through Systematic Hook Discovery.In Symposium on Recent Advances in Intrusion Detection (RAID)(2008).

[45] WEISER, M. Program slicing. In International Conference onSoftware Engineering (ICSE) (1981).

[46] XIA, Y., LIU, Y., CHEN, H., AND ZANG, B. CFIMon: De-tecting Violation of Control Flow Integrity Using PerformanceCounters. In Conference on Dependable Systems and Networks(DSN) (2012).

[47] YIN, H., LIANG, Z., AND SONG, D. Hookfinder: Identifyingand understanding malware hooking behaviors. In Symposium onNetwork and Distributed System Security (NDSS) (2008).

[48] ZHANG, M., AND SEKAR, R. Control Flow Integrity for COTSBinaries. In USENIX Security Symposium (2013).

16