Paper-Windows Memory Forensics Detecting Unintentionally Hidden Injected Code by Examining Page Table Entries
Paper-Windows Memory Forensics Detecting Unintentionally Hidden Injected Code by Examining Page Table Entries
Digital Investigation
journal homepage: www.elsevier.com/locate/diin
a r t i c l e i n f o a b s t r a c t
Article history: Malware utilizes code injection techniques to either manipulate other processes (e.g. done by banking
trojans) or hide its existence. With some exceptions, such as ROP gadgets, the injected code needs to be
executable by the CPU (at least at some point in time). In this work, we cover and evaluate hiding
Keywords: techniques that prevent executable pages (containing injected code) from being reported by current
Memory forensics detection tools. These techniques can either be implemented by malware in order to hide its injected
Code injection
code (as already observed) or can, in one case, unintentionally be taken care of by the operating system
Detection
through its paging mechanism. In a second step, we present an approach to reveal such pages despite the
Windows
Malware
mentioned hiding techniques by examining Page Table Entries. We implement our approach in a plugin
Rekall for the memory forensic framework Rekall, which automatically reports any memory region containing
executable pages, and evaluate it against own implementations of different hiding techniques, as well as
against real-world malware samples.
© 2019 The Author(s). Published by Elsevier Ltd on behalf of DFRWS. This is an open access article under
the CC BY-NC-ND license (http://creativecommons.org/licenses/by-nc-nd/4.0/).
1. Introduction tools/plugins for code injection detection are not able to cope with
the existing injection techniques and fail to reliably reveal existing
Memory forensics has become more and more important over malware utilizing certain hiding techniques. This is due to the in-
the last decade for different reasons: On the one hand, we observe formation they rely on, for example the VAD (Russinovich et al.,
malware that does not persist itself on a persistent storage device 2005; Dolan-Gavitt, 2007), which has a protection field that plu-
and can only be observed in the running state of the victim host. On gins use to detect executable code. An attacker can, however, create
the other hand, live analysis is not always capable of generating executable memory in a certain way so the VAD does not indicate
reliable results as the victim host might be compromised with a that it is executable and detection mechanisms won't report it. On
kernel level Rootkit, using attack techniques that effectively the other hand, it is possible to exploit the paging mechanism in
manipulate information gathered during the analysis. The presence order to hide injected code. As some plugins prevent to report
of such malware can be proven by analyzing a main memory image empty memory (filled with zeros or not yet allocated), they fail to
of the system (captured by one of the many existing techniques, report memory regions related to code injection when the corre-
which we do not want to discuss here). Besides kernel level mal- sponding pages have been paged out. This can also happen unin-
ware, there is also user space malware which uses its own set of tentionally, when the Operating Sytem writes malicious pages into
techniques in order to get its task accomplished. One such tech- the pagefile on memory shortage.
nique are code injections. In this work, we introduce a novel approach to reveal all
executable pages that are of potential interest for an investigator for
a given user space process, despite the hiding techniques covered in
1.1. Motivation
this paper. Ignored are only yet not allocated memory pages and
unmodified pages of mapped image files (loaded executables and
User space malware utilizes code injection techniques to
DLLs), as these don't contain any injected code. In order to retrieve
manipulate other processes or hide its existence. However, current
the actual executable state of a page and to differentiate yet not
allocated memory from currently inaccessible memory, we
* Corresponding author. examine the Page Table Entries which we enumerate via the paging
E-mail address: [email protected] (F. Block). structures, instead of the VADS, as it is faster and more reliable
https://doi.org/10.1016/j.diin.2019.04.008
1742-2876/© 2019 The Author(s). Published by Elsevier Ltd on behalf of DFRWS. This is an open access article under the CC BY-NC-ND license (http://creativecommons.org/
licenses/by-nc-nd/4.0/).
S4 F. Block, A. Dewald / Digital Investigation 29 (2019) S3eS12
(White et al., 2012). While this work also covers mapped files, our injection techniques and especially fundamentals about Page
focus is on anonymous memory as mapped files are already mostly Table entries, which are required for the analysis and algorithm
covered by White et al. (2013). presented in Section 4. In Section 3 we describe how injected code
The resulting plugin has been evaluated on both, x86 and can be hidden from detection tools/plugins, Section 5 covers the
x86_64 Windows 7 and Windows 10 VMs. The source code and evaluation of our and other detection plugins on the code injection
binary format (where applicable) respectively links and hashes of techniques and real-world malware examples which utilize the
all applications, malware samples and plugins used in this work are hiding techniques, and Section 6 concludes this paper.
publicly available in our online repository (Block, 2019), to allow an
easy reproducibility and verification of our results. 2. Fundamentals
1.2. Contributions This section describes the basics of our work. The first part
covers the code injection techniques that are used for the evalua-
The contributions of this paper are: tion. As already mentioned, we are in general interested in
executable pages but not in all kinds, as for example unmodified
! An algorithm which retrieves a page's actual protection from its pages of mapped image files are not interesting in the context of
PTE value and hence, its executable state despite any hiding code injections. Thus, the subsequent sections describe how we can
technique described in this work. retrieve the information needed to get the executable state of each
! A Rekall plugin that implements the algorithm and prints all page and differentiate interesting from uninteresting pages.
VADs with executable pages, potentially containing malicious
code. 2.1. Code injection techniques
ROP chain that gets written to an already existing RW memory 2.3. Page Table Entries and the Page Frame Number database
region and the second is the result of executing the ROP chain: a
newly allocated RWX memory region where the shellcode gets A Page Table Entry (short PTE) is part of the translation process
copied to and executed. from a virtual to a physical address and consists of a 64 bit value,
split into bitfields and flags (Cohen, 2014) (Intel Corporation, 2018a,
2.1.4. Process Hollowing p. 4e27). For an active page, it contains the so called Page Frame
The general approach of this technique has not changed Number (short PFN), which points at the physical page containing
significantly from the first known description in 2004 by Keong the content for the virtual page. The Page Frame Number database
(2004) and boils down to the following steps: (short PFN DB) is an array of _MMPFN structs with the PFN as an
index, which keeps track of physical pages and is maintained by the
1. Create a process in the suspended state (ideally with a benign Windows Operating System (Yosifovich et al., 2017, p. 425). It is
executable). primarily used to accelerate the process of finding available phys-
2. Unmap the memory region of the original executable (e.g. via ical pages but serves also valuable information for our purposes.
the ZwUnmapViewOfSection API). Every PFN DB entry describes one physical page and contains a field
3. Write the new executable to the victim process (e.g. via the called PrototypePte (accessible via its u4 member), which is a bit flag
WriteProcessMemory API). that is set when the physical page belongs to shared memory.
4. The start address of the suspended thread is patched with the There are two major types of PTEs to distinguish: The ones that
one from the new executable. are accessed by the MMU to translate a virtual into a physical
5. Thread is resumed (e.g. via the ResumeThread API). address and the so called prototype PTEs, which are used in the
context of shared memory and are stored in a different area of the
kernel address space (Cohen, 2016). Throughout this paper we call
2.1.5. Gargoyle the first type MMU PTE and the second prototype PTE. A prototype
Gargoyle is not an injection but a hiding technique that can PTE tries to solve the problem of updating the information for a
however be applied to injected code. The trick of Gargoyle is to set page shared among different processes (Martignetti, 2012b, p.
the permissions of all pages containing the malicious code to non- 295e300) (the details on how a prototype PTE works are not
executable as long as the code doesn't need to run and only sets important for this work). The PFN DB entry has a member called
them executable as long as the code is running. PteAddress which points to the physical page's describing PTE. For
private memory, this is a MMU PTE and for shared memory it is a
Now that we have shortly revisited those different injection prototype PTE in which case the PrototypePte flag indicates just that
techniques, the next sections describe fundamentals about private and hence, allows us to differentiate private from shared memory.
and shared memory, PTEs, transition state and further basics. Pages belonging to mapped image files (loaded executable or
DLL) have this flag set as long as they are not modified. As soon as
2.2. Private and shared memory they are modified, the Copy-on-write protection comes into play
and a new private page is mapped for this page and process, pre-
Private memory is described by a VAD, only visible to the venting modification side effects on other processes. With the new
owning process and does only contain anonymous memory (no page comes also a new PFN DB entry, which now has the Proto-
mapped files). While the creation of private memory specifies a typePte flag unset (Cohen, 2016) and allows us to identify modified
certain protection for the resulting memory pages, it is possible to pages for mapped image files.
change the protection of all or specific pages, belonging to the VAD,
later on. This change can either restrict the access (e.g. from EXE- 2.4. The different states of Page Table Entries
CUTE_READWRITE to READWRITE) or extend it (e.g. from initially
READONLY to EXECUTE_READWRITE). For each state, a MMU PTE can be in, there is a specific struct in
Shared memory on the other hand is, as the name suggests, Windows, describing its bitfields and flags. Depending on the state
intended to be shared among different processes to allow an easy respectively applied struct, the same bits can have a different
exchange of data. It is, however, also used by the image loader to meaning so it is important to apply the correct struct before
map the executables, DLLs and device drivers into memory interpreting a MMU PTE value. We refer to a certain state in the
(Yosifovich et al., 2017, p. 316). The image loader typically uses following sections also as an instance of a specific struct. While the
Copy-on-write protection for them, so a memory modification will knowledge about the translation process is considered common
not affect other processes or the file itself. knowledge and not in particular required to understand the rest of
Besides this automatic creation of shared memory, it is also this work, the different states and their function within Windows
possible to create shared memory manually, which applies to files are fundamental and are explained in more Detail in the following
and anonymous memory. This memory is normally shared among sections.
multiple processes but can also be used by just one process The following sections will also cover the Protection member
(Yosifovich et al., 2017, p. 315). The shared memory is represented which is a bit field, storing a value defined by Windows' memory
by a so called section object (Yosifovich et al., 2017, p. 405), created manager and represents a page's protection. The value corresponds
with a specific protection. There seems to be, however, no docu- to Windows' memory protections (Microsoft Corporation, 2019a)
mented way to change that protection after creation. In order to but uses different constants (Martignetti, 2012b, p. 104) (for
access shared memory, a process must map at least one view of the example a value of 6 means EXECUTE_READWRITE (ReactOS
section object, which creates a VAD and maps it into the process’ Foundation, 2013)).
virtual address space. This view can have a different, but not an
arbitrary protection: It is possible to assign a protection less or 2.4.1. Hardware state
equal to that of the section object (e.g. from EXECUTE_READWRITE There is one flag that is shared among all MMU PTEs: The Valid
to READWRITE but not the other way around) (Martignetti, 2012b, p. flag. Only if this flag is set, the virtual address belongs to an active
310). The same applies for protection changes of the corresponding physical page and the MMU will process the PTE. The struct that can
memory pages later on. be applied in this case to interpret the PTE is _MMPTE_HARDWARE,
S6 F. Block, A. Dewald / Digital Investigation 29 (2019) S3eS12
which contains a member called NoExecute that corresponds to bit that can be set anyways). This initial MMU PTE value is in this case
63 (Intel Corporation, 2018a, p. 4e27) (the NX bit). By checking this zero and changed when the page is accessed for the first time. For
bit we can determine a page's executable state as an unset NX bit in private memory, such a PTE state is also called demand zero, as on
this case allows the CPU to fetch and execute instructions. A MMU access, a page of zeros is mapped in the process' address space
PTE in hardware state can belong to a private page or to shared (Yosifovich et al., 2017, p. 384). The unaccessed state also occurs for
memory (anonymous, mapped data or image file) and can't be all types of shared memory, while in this case a page access typi-
distinguished solely on the PTE value. For this differentiation, the cally leads to the mapping of already existing memory into the
PrototypePte flag of the PFN DB entry must be examined. process' address space. Besides the MMU PTE value of zero, there
are two known cases where a not yet accessed page has a non-zero
2.4.2. Transition state PTE value. The first is the result of changing the protection of a page
If the Valid flag is unset, the MMU does not process the PTE any in the unaccessed state. The new protection is then stored in the
further but a page fault is generated where the Operating System Protection field (can be read by applying the _MMPTE_SOFTWARE
will interpret the state of the PTE and act accordingly (Cohen, 2014). struct), while all other fields remain zero. The only exception from
While a MMU PTE in transition state is not valid (has an unset Valid this are mapped image files. When the protection of a not yet
flag), the corresponding physical page is still available and the accessed image file's page is changed, it goes into the proto-pointer
PageFrameNumber still points to it. This state is, as the name sug- state.
gests, a transition phase from an active state into another one (the The second case are so called guard pages which technically are
next state depends on the type of memory) and gives the process a also demand zero pages. Guard pages allow to reserve a huge
last chance to access the page before it is removed from its working memory space while not having to commit much of it (the mini-
set and the physical page freed for other content. This state can, mum would be one page for the guard page itself), which comes at
similar to the hardware state, be reached for private and shared a lower cost (Martignetti, 2012b, p. 173). On access to a guard page, a
memory. The struct to apply in this case is _MMPTE_TRANSITION STATUS_GUARD_PAGE_VIOLATION exception is thrown which can be
and a MMU PTE in this state has the Valid and Prototype flag unset reacted on (e.g. committing more pages). This mechanism is used
and the Transition flag set. Regarding the executable state for this by the Virtual Memory Manager to automatically increase the user
case see Section 4.1. mode stack (Martignetti, 2012b, p. 402) and when used by appli-
cations can be handled in the code. These pages share the same
2.4.3. Proto-pointer PTE characterstic as demand zero pages with modified protections: In all
In this state, the MMU PTE is an instance of _MMPTE_PROTOTYPE our tests, the MMU PTE had only the Protection field set.
and should not be confused with a prototype PTE: It serves in fact as
a pointer to a prototype PTE and hence is called in this work a 2.5. Large and huge pages
proto-pointer PTE (Martignetti, 2012b, p. 297). A proto-pointer PTE
has the Valid flag unset and the Prototype flag set. The proto-pointer It is possible to allocate large and huge pages that have a size of
PTE is only used in the context of shared memory and only occurs 2-Mbyte and 1-Gbyte accordingly on x86 architectures (Yosifovich
when the corresponding physical page has been accessed before, et al., 2017, pp. 303e304). “Some processors support configurable
but is currently not anymore in the working set (a MMU PTE for a page sizes, but Windows does not use this feature.” (Yosifovich
not yet accessed shared memory page would be in the unaccessed et al., 2017, p. 405) While the physical page for normal sized
state; see Section 2.4.5). pages are referenced by the entries in the Page-Table (ignoring all
There are two cases to differentiate: special cases right now), large pages are referenced by an entry in
the Page-Directory Table and huge pages by an entry in the Page-
! If the ProtoAddress field has a value of 0xffffffff0000 (or 0xffffffff for Directory-Pointer Table (see Intel's Documentation (Intel
x86), the ProtoAddress does not directly point to a prototype PTE Corporation, 2018a, p. 4e21). Large and huge pages have bit 1
(its address must be gathered from the VAD (Martignetti, 2012b, p. (Valid or Present flag) and 7 (LargePage or PS flag) set, marking them
311)) and the page protection has to be gathered in a special way: as a large/huge page (Intel Corporation, 2018a, pp. 4-24e4-27), are
The _MMPTE_SOFTWARE struct must be applied to the MMU PTE in non-pageable and not part of the working set (Yosifovich et al.,
order to extract its executable state from the Protection field. The 2017, p. 304).
differentiation is important since the Protection field is on different
positions for _MMPTE_PROTOTYPE and _MMPTE_SOFTWARE. 3. (Un)Intentionally hiding injected code
! In all other cases, the ProtoAddress points to a prototype PTE. The
protection value can then not be read from the MMU PTE and This Section will primarily describe the hiding techniques in the
must be gathered through the prototype PTE (see Section 4.2.4). context of the malfind and hashtest plugins, as they implement a
generic approach of detecting injected code respectively executable
pages. The results for the other plugins are described in Section 5.1.
2.4.4. Pagefile state Volatility and Rekall's malfind plugin examines the protection
Another invalid state occurs when the physical page has been field of VADs in order to identify injected code. When a VAD has,
written to the pagefile (paged out). This state is represented by a besides a few other criteria, a specific protection that includes the
MMU PTE instance of _MMPTE_SOFTWARE, where the Valid, Proto- WRITE and EXECUTE rights, malfind will identify this VAD as
type and Transition flags are all unset but the PageFileHigh field has a potentially malicious and report it. That means, all VADs without
non-zero value (Yosifovich et al., 2017, p. 384). In this case, the these rights are not considered by this plugin. As already stated in
page's content cannot be read anymore from RAM but must be 2014 by Ligh et al. (2014), the VAD's protection field only contains
gathered from the pagefile. the initial protection, set during its allocation. So a VAD, with a
specific protection can contain pages with differing protections. It is
2.4.5. Unaccessed state for example possible to allocate a VAD with a protection of
When a VAD has been created but its page(s) not yet been READONLY and later on, change the protection of all containing
accessed, there is no need to actually map a physical page and pages (e.g. via VirtualProtectEx (Microsoft Corporation, 2019c)) to
hence, the MMU PTE value does not need to be set (there isn't a PFN EXECUTE_READWRITE (KSL group, 2017a). So in order to hide its
F. Block, A. Dewald / Digital Investigation 29 (2019) S3eS12 S7
code from malfind and other plugins relying on the protection field, must be examined. Its state and the information stored in the
the attacker just has to allocate the memory initially with a pro- corresponding PFN DB entry help us decide, whether or not we are
tection without the WRITE or EXECUTE right and later on, add this interested in the according page, and dictates how we have to
right to the pages containing the malicious code. As an alternative, gather its protection information. The following sub sections
malware can also use an already existing VAD, without the WRITE describe our analysis on PTEs and the page protection, an algorithm
or EXECUTE right, and inject its code in an unused area while adding to retrieve all executable pages of interest and an analysis on pro-
these rights to the corresponding page(s). Because the WRITE right cesses with deactivated Data Execution Prevention. All analysis
is only required as long as code needs to be written, the final page results are based on extensive tests on Windows 7 #64 and Win-
protection does not require this right at all. There is one further dows 10 #64 VMs, primarily using the memory allocation tool
scenario: Injected code can be hidden from malfind by using shared MemTest by Martignetti (2012a), WinDbg and Rekall (Google Inc,
memory (in particular anonymous) with a protection of EXECU- 2018a) (see also the documentation for test setups in our public
TE_WRITECOPY (Monnappa, 2017), as it is explicitly omitted by the repository (Block, 2019)).
plugin. These hiding techniques, except for the EXECUTE_WRITE-
COPY trick, also work for hashtest. 4.1. Retrieving the protection for a page in transition
The other way to hide injected code is to make it unavailable,
from a memory forensics perspective. As paged out pages are not There is more than one source that offers a Protection field for a
present in RAM anymore but only in the pagefile(s), they are per page in transition state, which includes at least the PFN DB's Orig-
default not part of a memory dump. The problem with plugins such inalPte member (used by hashtest (White et al., 2013, p. 63)) and the
as malfind and hashtest occurs when they try to access the data MMU PTE (instance of _MMPTE_TRANSITION). The OriginalPte field
behind an executable page. malfind on the one hand wants to is for example used to store the protection value while the page is
ignore empty pages, as there is nothing to investigate, and hence active, especially when the permission of a page is changed
does not report a VAD at all, if all pages appear empty. hashtest's (Martignetti, 2012b, pp. 198,310). In order to find the correct and
purpose on the other hand is to compare memory pages and hence fastest source for the page's protection (the MMU PTE would be
is not interested in unavailable memory. Since both, an actual faster regarding the plugin runtime, as we already have its PTE
empty page and a paged out page that might contain malicious value and wouldn't have to read and examine the PFN DB entry), we
content, appear to malfind's internal check for empty pages as set up several experiments to see when and how the MMU PTE's
empty, a VAD with e.g. EXECUTE_READWRITE protection is not re- and OriginalPte's Protection field are set (the details about the setup
ported by malfind if all pages are paged out. hashtest's output shows and tests are documented in our repository (Block, 2019)). The re-
the VAD in this case in its output, but reports that no page for that sults for private memory can be summarized as follows:
VAD is executable.
Paging out pages can for example be triggered manually with ! When a page in transition state gets active again (hardware
the SetProcessWorkingSetSize API (Martignetti, 2012a; Microsoft state), the old MMU PTE's Protection field defines the resulting
Corporation, 2019b), which allows to set the minimum and MMU PTE's protection (NX flag and so on). The OriginalPte does
maximum working set size of a given process and if both values are not influence the final protection.
set to "1, “removes as many pages as possible from the working set ! When the page goes from active into transition state, the new
of the specified process” (Microsoft Corporation, 2019b). The result MMU PTE's Protection field is copied from the OriginalPte. In this
from a successful function call is, for private pages, typically first, a case, the old MMU PTE value does not influence the Protection
PTE state change from hardware to transition, and afterwards to field.
pagefile state: The pages are written to the pagefile. While the
change from transition to pagefile can sometimes take some time, it So, as a private page in transition state has the same Protection
is possible to accelerate this process by allocating and accessing value as OriginalPte and moreover, the MMU PTE's Protection field
new memory. dictates the protection for the page when it is getting active again,
This hiding might, however, also happen unintentionally we use the MMU PTE to retrieve the page's protection.
(without any assistance by the malware). When the Operating While the OriginalPte's Protection field would be safe to use for
System e.g. requires physical pages for new processes and the pages private pages, the situation changes for shared memory. A PFN DB
containing malicious code haven't been accessed lately, they can entry describes one physical page, which, however, can be shared
get paged out. This automatic and the manual hiding works for among various processes with different protections for their view.
both, private and shared memory and hence can also be used to When, for example, mapping a view with READWRITE protection of
hide modified mapped image files from hashtest (it is, however, not a EXECUTE_READWRITE section object, the OriginalPte's Protection
perfectly reliable as the Windows Operating System decides if and field will state EXECUTE_READWRITE, while the page in the process'
when it writes pages to the pagefile). While Rekall supports the address space is not executable. The reason why hashtest uses the
integration of pagefiles and hence can prevent this hiding tech- OriginalPte is probably the fact that the MMU PTE for shared
nique, Volatility does not. memory does not seem to ever enter the transition state but
It should be noted that e.g. malfind prints a VAD referring to directly changes into the proto-pointer state, in which case the
non-empty pages, despite the fact that the memory has never been protection is, in particular for mapped image files, not always
accessed by the process. This happens when a process maps a view available from the MMU PTE. When and how the protection must
of shared memory with active physical pages (they are not paged be retrieved for these cases is described in Section 4.2.4.
out) but has not yet accessed them itself. While this behavior
doesn't hide any potential malicious content, it adds data to the 4.2. Executable page detection algorithm
investigation which has never been part of the associated process.
Fig. 1 illustrates the algorithm used to retrieve executable pages.
4. Analysis As mentioned in Section 1, we are not interested in not yet allocated
memory pages and unmodified pages of mapped image files. So,
In order to detect executable pages of interest despite any of the there are further tests for some pages, besides their executable
hiding techniques described in the previous Section, the MMU PTEs state, that have to be done before they are included in the
S8 F. Block, A. Dewald / Digital Investigation 29 (2019) S3eS12
pages of mapped image files, which we don't want to include. As we information: The Protection field of the MMU PTE (instance of
can't distinguish a private from a shared page solely from its PTE _MMPTE_SOFTWARE). If the PageFileHigh value is greater than zero,
value, we have to examine the PFN DB via the PTE's Page- we examine the Protection field for an EXECUTE right and include
FrameNumber field. If the PFN DB entry has not the PrototypePte bit the page on a positive match. If the field has at this point a value of
field set, it belongs to a private page (which includes modified zero, it would mean an unknown state and will be reported with a
pages from mapped image files) and we can include it. If it is set, the warning.
page belongs to shared memory and we examine the correspond-
ing VAD for a mapped image file. We only include the page if it is 4.3. Mapped data files
not related to a mapped image file, which includes, besides shared
anonymous memory, also mapped data files (see Section 4.3 for While loading an executable/DLL is done by the Windows
further details). Loader and involves several tasks (resolving the imported func-
tions, aligning the PE sections in memory, …) and the Copy-on-
4.2.4. Proto-pointer PTE write protection, mapping a file as data file does not. A mapped data
If the Valid flag is not set but, when applying the file is typically used to perform read/write operations with the
_MMPTE_PROTOYPE struct, the Prototype field is set, the MMU PTE is speed advantage of an in-memory file (called mapped file I/O
a proto-pointer PTE. This state is, depending on our tests and ob- (Yosifovich et al., 2017, p. 405). It is, however, also possible to map a
servations, in most cases the default for shared memory as soon as data file with the EXECUTE_READWRITE protection and execute
the page is not valid anymore. The PTE containing the actual page's code contained in that file. As in this case no Copy-on-write is used,
state is the prototype PTE, which in some cases has to be accessed in a modification to a page will not lead to a new physical page
order to get a page's protection as the MMU PTE does not always respectively PFN DB entry and also not to a change of the Proto-
contain the protection for this state. If, however, the MMU PTE typePte field (this flag will remain set). So while we ignore pages
contains the protection, it must be gathered from here as the pro- belonging to mapped image files with the PrototypePte flag, we
totype PTE might not contain the correct protection (see Section 4.1). include mapped data files for two reasons: We can't be sure if the
If the ProtoAddress field has a value of 0xffffffff0000 (or 0xffffffff pages have been modified and a mapped data file with EXECUTE
for x86), we can get the page's protection by applying the permission is something to look into (we did not find a single
_MMPTE_SOFTWARE struct and reading the Protection field. If it is benign instance in all our test environments).
executable and the page does not belong to a mapped image file, we
include it. 4.4. Data Execution Prevention
If the ProtoAddress field has another value, it normally means the
MMU PTE belongs to a mapped image file and could be ignored. When DEP is not active for a running process, which is the
Besides pages of image files with changed protections (for those, default for non-essential x86 programs and services on Windows
the ProtoAddress value is changed to 0xffffffff0000 and we could client versions (Yosifovich et al., 2017, p. 320), it can execute code
read the protection as explained before), we observed in Windows from pages with e.g. READWRITE protection. Active MMU PTEs
10 single instances of memory that are no mapped image files but (instances of _MMPTE_HARDWARE), however, had the NX bit set for
still have a ProtoAddress different from 0xffffffff0000, so we have to non-executable pages during our analysis and hence, a CPU with
further examine this state as we want to test these pages for being Hardware NX support will not fetch and execute instructions from
executable. It should be noted that, in the following cases, the page those pages. The way this still works is as follows: When the
is tested for being part of a mapped image file and only included if it Windows Operating System gets an access violation from the CPU
is not. First, we read the MMU PTE's Protection field by applying the for a non-executable page belonging to a process without DEP, it
_MMPTE_PROTOTYPE struct. If this field is not zero we check it for unsets the NX bit for that page and the CPU is now able to execute
being executable. If it is, we have to read the prototype PTE in order the containing code.
to get the page's protection. The states, the prototype PTE can be in This behavior makes it, with our approach, pretty easy to spot
are similar to the MMU PTE and also examined in a similar way (as for example code execution triggered by stack buffer overflows. If
explained in the other sections and shown in Fig. 1), with one the shellcode is stored and executed in a page from the stack, only
exception: If the Prototype flag is set, the prototype PTE is an this page is marked as executable (NX bit unset) and stands out
instance of _MMPTE_SUBSECTION and its protection can be read from otherwise only READWRITE pages. The VAD's protection stays
from the Protection field. unaffected by this behavior and hence has still its initial value
(typically READWRITE for VADs containing stacks). There is,
4.2.5. Transition state however, one caveat: When the page is for example paged out, the
As described in Section 4.1 we can retrieve the protection for a MMU PTE's (instance of _MMPTE_SOFTWARE) protection field is
page in this state from the MMU PTE by applying the set with its actual protection, which is READWRITE and not
_MMPTE_TRANSITION struct and reading its Protection value. If the EXECUTE_READWRITE since its protection has not been changed
value corresponds with any protection containing EXECUTE rights, explicitly. The same goes for this page when it is paged in again: The
we perform the same checks regarding shared memory as NX bit will be set again (because the protection field does not say
described in Section 4.2.3, before including the page. Regarding this EXECUTABLE), until a new code execution attempt occurs. So in
state and shared memory, see Section 4.2.4. those cases, we can't detect the former executable page.
Rekall's malfind didn't differ in our evaluation for the identification An appended _m to an executable name means that it has been
of suspicious memory regions, we don't differentiate them in the modified to initially allocate the memory with READONLY protec-
following sections. Regarding the hashtest plugin we used a modi- tion and afterwards changes it to EXECUTE_READWRITE. The addi-
fied version (Block, 2019) because the one from the author's re- tional _h and _a for Gargoyle indicates, whether the page containing
pository (White, 2013) was not compatible with a more current the shellcode is currently hidden (not executable) or active
version of Volatility and had a bug in the interpretation of PTE (executable).
values. The result of each plugin for a specific executable can be As can be seen in Table 1, no plugin detected all memory regions
read as follows: The first letter (in capitals) indicates if all processes containing the injected code. Also our plugin did not detect the
with injected executable code have been identified and the second memory pages containing the shellcode while they are hidden by
letter (in non capitals) indicates if all injected executable memory Gargoyle, which is however the expected behavior since those
regions/pages have been identified. pages are not executable in these cases. The P/a status for malthfind
and threadmap means that they were not always able to detect the
! A or a All processes/pages have been identified. injected code, but when, they detected all executable memory re-
! N or n None of the processes/pages have been identified. gions. When looking for the differences between the original code
! P or p At least one process/page has been identified, but not all. injectors and our modification, we can see that it was possible to
! F The process has been identified by the plugin as malicious but hide from malfind, Psinfo (except Process Hollowing attacks) and
results from a False Positive. hashtest.
The detection rate gets worse when the malicious pages are
We also evaluated the code injection techniques with paged out paged out. In this case, malfind, malthfind and hashtest do report
pages (see Section 3). If those results differ from the results without none of the executable pages (only hashtest does at least print the
paged out pages, the differing result is also given in Table 1, memory region, but states that zero executable pages are contained
included in brackets after the original result (e.g. “P/a (N/n)”). If no in it) while Psinfo does now only report the Process Hollowing
differing value is provided in brackets, the result was the same as related pages. Furthermore, atombombing and Gargoyle_a/Gargoy-
without paged out pages. le_m_a are not detected by any plugin, except ptenum. The fact that
ptenum does not detect DEP with paged out pages is, again, the
5.1. Evaluation with code injection PoCs expected result, as the pages are not executable anymore (see
Section 4.4).
The executables listed in Table 1 implement the injection
techniques described in Section 2.1 and are available in our re- 5.2. Evaluation with malware
pository (Block, 2019). Most of them are only slight modifications of
the original author's code. Among the executables are also some The malware samples evaluated in this Section have been picked
additions, demonstrating the hiding techniques described in Sec- for their code injection behavior, as they implemented some hiding
tion 3: techniques. Their analysis was done with API monitoring and a
before and after comparison of memory dumps. In the following we
! RS Implements the Remote Shellcode Injection (Block, 2019). describe the code injection/hiding specific behavior of each mal-
! DEP Stores and executes shellcode on the stack (a PoC for the ware sample that was present at the time of the memory dump
scenario described in Section 4.4). with a focus on anonymous memory. If not specified otherwise, the
! selfmodify This executable modifies its own executable code, allocated memory is private.
serving as a test scenario for hashtest and paged out pages.
! atombombing AtomBombing PoC by Liberman (2016). ! Rig Exploit Kit (Muhammad et al., 2018; Security, 2018b) Cre-
! loadExe The Process Hollowing PoC by Keong (2004). ates two new processes with EXECUTE_READWRITE memory
! procHollow A newer implementation of Process Hollowing by regions.
Leitch (2014). ! Formbook (Jullian, 2018; Security, 2017b) Creates one new
! reflectiveDLL The Reflective DLL Injection PoC by Fewer (2013). process with several EXECUTE_READWRITE shared memory re-
! Gargoyle The Gargoyle hiding technique PoC by Lospinoso gions and one READWRITE region but with executable pages in
(2017). it.
Table 1
Evaluation of Code Injection Detection plugins with Code Injection PoCs (without and with paged out pages; the results for the latter case are given in brackets if the results
differ).
RS A/a (N/n) N/n (F/n) P/a N/n A/a (N/n) P/a (N/n) A/a (N/n) A/a
RS_m N/n F/n P/a N/n N/n P/a (N/n) N/n A/a
DEP N/n N/n (F/n) N/n N/n F/n P/a (N/n) N/n A/a (N/n)
selfmodify e e e e e e A/a (N/n) A/a
atombombing A/a (N/n) N/n N/n N/n A/a (F/n) N/n A/a (N/n) A/a
loadExe A/a (N/n) A/a P/n A/a A/a P/a (N/n) A/a (N/n) A/a
loadExe_m N/n A/a P/n A/a A/a P/a (N/n) N/n A/a
procHollow A/a (N/n) A/a P/a A/a A/a P/a (N/n) A/a (N/n) A/a
procHollow_m N/n A/a P/a A/a A/a P/a (N/n) N/n A/a
reflectiveDLL A/a (N/n) N/n (F/n) P/p N/n A/a (F/n) P/p (N/n) A/a (N/n) A/a
reflectiveDLL_m N/n N/n (F/n) P/p N/n F/n (N/n) P/p (N/n) N/n A/a
Gargoyle_h A/a (N/n) N/n N/n N/n A/a (N/n) N/n A/a (N/n) N/n
Gargoyle_m_h N/n N/n N/n N/n N/n N/n N/n N/n
Gargoyle_a A/a (N/n) N/n N/n N/n A/a (N/n) A/a (N/n) A/a (N/n) A/a
Gargoyle_m_a N/n N/n N/n N/n N/n A/a (N/n) N/n A/a
F. Block, A. Dewald / Digital Investigation 29 (2019) S3eS12 S11
Table 2
Evaluation of Code Injection Detection plugins with Malware Samples.
Rig Exploit Kit A/a N/n P/p N/n A/a P/p A/a A/a
Formbook A/p N/n N/n N/n A/p N/n A/p A/a
Form Grabber P/p N/n P/p N/n P/p P/p A/p A/a
Ghostminer A/p N/n N/n N/n A/p N/n A/p A/a
Kronos A/p A/a A/p A/p A/a N/n A/a A/a
Olympic Destroyer N/n N/n N/n N/n F/n N/n A/n A/a
! Form Grabber (Jullian, 2017; Security, 2017a) Has a READWRITE possible to enumerate the PFN DB in order to gather page pro-
memory region in its own address space with executable pages tections (see Section 4.1), this will only work for pages in hardware
and allocates a new EXECUTE_READWRITE memory region and transition state, as all others have no associated PFN DB entry.
within an existing, benign process.
! Ghostminer (Aprozper and Bitensky, 2018; Chronicle, 2018a)
References
Creates a new process with several EXECUTE_READWRITE and
READWRITE memory regions, all containing executable pages. Aprozper, A., Bitensky, G., 2018. Ghostminer: Cryptomining Malware Goes Fileless
! Kronos (Chronicle, 2018b; Lechtik, 2018) Creates one new pro- [Visited on 22.11.2018]. URL. https://blog.minerva-labs.com/ghostminer-
cess with a EXECUTE_WRITECOPY shared memory region and a cryptomining-malware-goes-fileless.
Block, F., 2019. The Public Repository Containing the Code and Binaries Used in This
EXECUTE_READWRITE memory region. Work [Visited on 25.03.2019]. URL. https://github.com/f-block/DFRWS-USA-
! Olympic Destroyer (Mercer and Rascagneres, 2018; Security, 2019.
2018a) Creates one new process with a READWRITE memory Chronicle, 2018. Virustotal - ghostminer sample [Visited on 22.11.2018]. URL.
https://www.virustotal.com/#/file/
region containing one executable page. 40a507a88ba03b9da3de235c9c0afdfcf7a0473c8704cbb26e16b1b782becd4d/
detection.
As we don't possess the source code for the malware samples Chronicle, 2018. Virustotal - kronos sample [Visited on 22.11.2018]. URL. https://
www.virustotal.com/#/file/
and hence were not able to influence the memory allocation pro-
9806d1b664c73712bc029e880543dfa013fdd128dd33682c2cfe5ad24de075b9/
cess or reliably force the process to page out the injected code (see detection.
Section 3), we evaluated the samples only as is. Cohen, M., 2014. Windows Virtual Address Translation and the Pagefile [Visited on
As can be seen in Table 2, no plugin, except ptenum, was able to 19.12.2018]. URL. http://blog.rekall-forensic.com/2014/10/windows-virtual-
address-translation-and.html.
detect all memory regions containing executable pages created by Cohen, M., 2016. Rekall and the Windows Pfn Database [Visited on 19.12.2018]. URL.
the malware samples. Especially the executable page of Olympic https://web.archive.org/web/20170906073820/http://blog.rekall-forensic.com/
Destroyer was revealed by no other plugin (in particular malfind and 2016/05/.
Countercept, 2018. Gargoyle volatility plugin [Visited on 24.12.2018]. URL. https://
hashtest). Only hashtest did at least indicate the containing process, github.com/countercept/volatility-plugins/blob/master/gargoyle.py.
as the malware sample drops a new executable which is not part of Dolan-Gavitt, B., 2007. The vad tree: a process-eye view of physical memory. Digit.
hashtest's database. Invest. 4, 62e64.
enSilo inc, 2016. Atombombing: Brand New Code Injection for Windows [Visited on
20.09.2018]. URL. https://blog.ensilo.com/atombombing-brand-new-code-
6. Conclusion and future work injection-for-windows.
Fewer, S., 2013. Reflective Dll Injection - Github [Visited on 09.01.2019]. URL.
https://github.com/stephenfewer/ReflectiveDLLInjection.
In this work, we demonstrate that it is possible to prevent Google Inc, 2018. Rekall memory forensic framework [Visited on 23.09.2018]. URL.
injected code from being reported by current code injection http://www.rekall-forensic.com.
Google Inc, 2018. Rekall memory forensic framework - github [Visited on
detection plugins. We introduce a novel approach that is able to
23.09.2018]. URL. https://github.com/google/rekall.
detect executable pages despite any intentional (or unintentional) Google Inc, 2019. Rekall's Malfind Plugin [Visited on 16.01.2019]. URL. https://
hiding technique described in Section 3. Only DEP with paged out github.com/google/rekall/blob/master/rekall-core/rekall/plugins/windows/
malware/malfind.py.
pages and Gargoyle were successful in hiding from our plugin, but
Hammond, A., 2018. Hunting for Gargoyle Memory Scanning Evasion [Visited on
this behavior is expected as the affected pages are not executable in 24.12.2018]. URL. https://www.countercept.com/blog/hunting-for-gargoyle/.
these cases (see Sections 4.4 and 2.1.5). We implemented a Rekall Intel Coporation, 2018. Intel® 64 and ia-32 Architectures Software Developer's
plugin that leverages our introduced approach, which we publicly Manual. Volume 3A: System Programming Guide. Part 1 [Visited on 28.12.2018].
URL. https://software.intel.com/sites/default/files/managed/7c/f1/253668-sdm-
release alongside with this paper. vol-3a.pdf.
Because our plugin reports all executable pages (with the Jullian, R., 2017. Analyzing a Form-Grabber Malware [Visited on 22.11.2018]. URL.
mentioned exclusions), no matter if they are part of a code injection https://thisissecurity.stormshield.com/2017/09/28/analyzing-form-grabber-
malware-targeting-browsers/.
or benign, it can produce a huge amount of data that would need to be Jullian, R., 2018. In-depth Formbook Malware Analysis - Obfuscation and Process
investigated. The main problem are modified pages of mapped image Injection [Visited on 22.11.2018]. URL. https://thisissecurity.stormshield.com/
files as described in the work by White et al. (2013). As the plugin 2018/03/29/in-depth-formbook-malware-analysis-obfuscation-and-process-
injection/.
supports to omit those, it can be used as an improved malfind plugin Keong, T.C., 2004. Dynamic Forking of Win32 Exe [Visited on 20.09.2018]. URL.
(but would miss code injections in mapped image files). Otherwise, it https://web.archive.org/web/20070808231220/http://www.security.org.sg/
is not suitable for large processes but can be used for small ones or in a code/loadexe.html.
KSL group, 2017. Threadmap Documentation [Visited on 20.01.2019]. URLhttps://
before vs. after comparison. This is why our plugin should be inte- github.com/kslgroup/threadmap/raw/master/threadmap/%20documentation.
grated with code injection detection plugins, in particular hashtest, in pdf.
order to strip benign data and improve their results. KSL group, 2017. Threadmap Volatility Plugin [Visited on 20.10.2018]. URL. https://
github.com/kslgroup/threadmap.
As we rely on the paging structures to identify executable pages,
Lechtik, M., 2018. Deep Dive into Upas Kit vs. Kronos [Visited on 22.11.2018]. URL.
our approach does not work if the page tables are paged out and the https://research.checkpoint.com/deep-dive-upas-kit-vs-kronos/.
pagefile is not given. For these cases, a fallback mechanism should Leitch, J., 2014. Process Hollowing Poc - Github [Visited on 21.09.2018]. URL. https://
be implemented which investigates all VADs, similar to the existing github.com/m0n0ph1/Process-Hollowing.
Liberman, T., 2016. Atombombing: Brand New Code Injection for Windows - Github
malfind plugin. This fallback will, however, again be prone to the [Visited on 20.09.2018]. URL. https://github.com/BreakingMalwareResearch/
hiding techniques described in this work. While it would be atom-bombing.
S12 F. Block, A. Dewald / Digital Investigation 29 (2019) S3eS12
Ligh, M.H., Case, A., Levy, J., Walters, A., 2014. The Art of Memory Forensics: malfofind.py.
Detecting Malware and Threats in Windows, Linux, and Mac Memory. John Pshoul, D., 2017. Malthfind Volatility Plugin [Visited on 20.10.2018]. URL. https://
Wiley & Sons. github.com/volatilityfoundation/community/blob/master/DimaPshoul/
Lospinoso, J., 2017. Gargoyle - a Memory Scanning Evasion Technique - Github malthfind.py.
[Visited on 20.12.2018]. URL. https://github.com/JLospinoso/gargoyle. ReactOS Foundation, 2013. Techwiki:memory protection constants [Visited on
Martignetti, E., 2012. What makes it page? sample programs [Visited on 22.11.2018]. URL. https://www.reactos.org/wiki/Techwiki:Memory_Protection_
13.01.2019]. URL. http://www.opening-windows.com/wmip/testcode/ constants.
download/license.html. Russinovich, M.E., Solomon, D.A., Allchin, J., 2005. Microsoft Windows Internals:
Martignetti, E., 2012. What makes it page? Windows 7 (x64) Virtual Memory Microsoft Windows Server 2003, Windows XP, and Windows 2000, vol. 4.
Manager. CreateSpace Independent Publishing Platform. Microsoft Press Redmond.
Mercer, W., Rascagneres, P., 2018. Olympic Destroyer Takes Aim at Winter Olympics Security, Payload, 2017. Hybrid analysis - form grabber sample [Visited on
[Visited on 22.11.2018]. URL. https://blog.talosintelligence.com/2018/02/ 22.11.2018]. URL. https://www.hybrid-analysis.com/sample/9cdb1a336d111
olympic-destroyer.html#more. fd9fc2451f0bdd883f99756da12156f7e59cca9d63c1c1742ce?environmentId.
Microsoft Corporation, 2018. About Atom Tables [Visited on 09.01.2019]. URL. Security, Payload, 2017. Hybrid analysis - formbook sample [Visited on 22.11.2018].
https://docs.microsoft.com/en-us/windows/desktop/dataxchg/about-atom- URL. https://www.hybrid-analysis.com/sample/
tables. 6e4ec3712cf641a31f4e9e4af7d9d7a84fd7da4cc2875c6aceb9a283ed0330d7?
Microsoft Corporation, 2019. Memory Protection Constants [Visited on 19.01.2019]. environmentId¼100.
URL. https://docs.microsoft.com/en-us/windows/desktop/Memory/memory- Security, Payload, 2018. Hybrid analysis - olympic destroyer sample [Visited on
protection-constants. 22.11.2018]. URL. https://www.hybrid-analysis.com/sample/edb1ff2521fb4bf74
Microsoft Corporation, 2019. Setprocessworkingsetsize Function [Visited on 8111f92786d260d40407a2e8463dcd24bb09f908ee13eb9?environmentId¼100.
18.01.2019]. URL. https://docs.microsoft.com/en-us/windows/desktop/api/ Security, Payload, 2018. Hybrid analysis - rig exploit kit sample [Visited on
winbase/nf-winbase-setprocessworkingsetsize. 22.11.2018]. URL. https://www.hybrid-analysis.com/sample/8b86662ab617d110
Microsoft Corporation, 2019. Virtualprotectex function [Visited on 09.01.2019]. URL. 79f16d95d4d584e8acb4a374b87edf341195ab9e043ed1d2?
https://msdn.microsoft.com/en-us/library/windows/desktop/aa366899 environmentId¼100.
(v¼vs.85).aspx. The Volatility Foundation, 2017. Volatility's Malfind Plugin [Visited on 16.01.2019].
Monnappa, K.A., 2016. Detecting malicious processes using psinfo volatility plugin URL. https://github.com/volatilityfoundation/volatility/blob/master/volatility/
[Visited on 25.10.2018]. URL. https://cysinfo.com/detecting-malicious- plugins/malware/malfind.py.
processes-psinfo-volatility-plugin/. The Volatility Foundation, 2019. Volatility [Visited on 15.01.2019]. URL. https://
Monnappa, K.A., 2016. Hollowfind Volatility Plugin [Visited on 11.10.2018]. URL. github.com/volatilityfoundation/volatility/tree/
https://github.com/monnappa22/HollowFind. 9df8aa6daabc29c74bf261574ffb5cde2315c7f8.
Monnappa, K.A., 2016. Psinfo Volatility Plugin [Visited on 25.10.2018]. URL. https:// White, A., 2013. Hashtest Volatility Plugin [Visited on 16.01.2019]. URL. https://
github.com/monnappa22/Psinfo. github.com/a-white/Hashtest.
Monnappa, K.A., 2017. Detecting Deceptive Process Hollowing Techniques Using White, A., Schatz, B., Foo, E., 2012. Surveying the user space through user alloca-
Hollowfind Volatility Plugin [Visited on 09.01.2019]. URL. https://cysinfo.com/ tions. Digit. Invest. 9. S3eS12, [Visited on 15.01.2019]. URL. https://www.dfrws.
detecting-deceptive-hollowing-techniques/. org/sites/default/files/session-files/paper-surveying_the_user_space_through_
Muhammad, I., Ahmed, S., Faizan, H., Gardezi, Z., 2018. A Deep Dive into Rig Exploit user_allocations.pdf.
Kit Delivering Grobios Trojan [Visited on 22.11.2018]. URL. https://www.fireeye. White, A., Schatz, B., Foo, E., 2013. Integrity verification of user space code. Digit.
com/blog/threat-research/2018/05/deep-dive-into-rig-exploit-kit-delivering- Invest. 10, S59eS68.
grobios-trojan.html. Yosifovich, P., Solomon, D.A., Ionescu, A., 2017. Windows Internals, Part 1: System
Pshoul, D., 2017. Malfofind Volatility Plugin [Visited on 20.10.2018]. URL. https:// Architecture, Processes, Threads, Memory Management, and More. Microsoft
github.com/volatilityfoundation/community/blob/master/DimaPshoul/ Press.