📘 Volatility3: Modern Windows Hibernation file analysis

Abstract Link to heading

In the Digital Forensics ecosystem, the field of memory forensics can help uncover artifacts that can’t be found anywhere else. That can include deleted files, network connections, running processes, rootkits, code injection, fileless malware and many more.

Microsoft introduced the hibernation feature in Windows 2000, allowing systems to be powered down while preserving their volatile state. This is achieved by saving RAM contents and processor context to a file called hiberfil.sys before shutting down inside the root folder of the filesystem drive. When the computer is turned on again, the system restores the volatile state from the saved file. Hibernation files are valuable for digital forensic professionals as they store temporary data from RAM to non-volatile storage, eliminating the requirement for specialized tools on the target device.

The Hibernation file structure has evolved in time. In this blog post, we will dive into the structure of the modern Windows hibernation file and propose a new translation layer for the volatility3 framework to create a raw memory image from a hibernation file.

The structure of a modern hibernation file Link to heading

The structure of the hibernation file can be divided into two variations:

  • From Windows XP to Windows 7 (old)
  • From Windows 8 to Windows 11 (modern)

The following image represent the modern structure.

alt text

In this blog post we will focus on the modern hibernation structure1, though you’ll notice that the underlying principle remains the same which is to compress and store the physical memory pages of the hibernated system in specific data structures called “restoration sets”.  

The file header Link to heading

The hibernation files start with a header called PO_MEMORY_IMAGE. The structure of this header may differ slightly depending on the operating system version, but its definition is publicly available in the kernel’s debugging symbols, which is very nice. The vergiliusproject2 gives us a nice description of this structure for each Windows version. Below is an example of the structure of the header.

alt text

The signature of the file for an exploitable hibernation file is ‘HIBR’. The ‘RSTR’ signature indicates that the system is resuming from the file, making it apparently useless when this is the case. Valuable forensics artifacts are available like the system time when it was put into the hibernation state.

Notice the “FirstBootRestorePage” and “FirstKernelRestorePage” attributes. Those values are storing the page number of the first restoration sets. Mutiplying those values by the size of a Windows x64 page (4096) we get the offset of the sections.

Windows currently divide the storage of the memory pages in 2 locations :

  • The boot section.
  • The kernel section.

You might notice the “SecureRestorePage” section, however this value seems to be always 0 and there is no publicly available explanation on what those pages are used for. It might be used in the future though to encrypt memory pages so only the host machine can decrypt them via its TPM?

To know how many pages are stored for each sections the information can be retrieved from specific attributes:

  • NumPagesForLoader”: The number of pages in the “Boot” section
  • PerfInfo->KernelPagesProcessed”: The number of pages in the “Kernel” section

Unfortunately for us, the attribute storing the location and number of pages for the Kernel section did change with the Windows OS updates. Below is a table tracking those changes.

Windows Versions FirstKernelRestorePage offset KernelPagesProcessed offset
Windows 8/8.1 0x68 0x1C8
Windows 10 2016 1507-1511 0x70 0x218
Windows 10 2016 1607 0x70 0x220
Windows 10 2016 1703 - Windows 11 23H2 0x70 0x230

The compression sets. Link to heading

A restoration set contains multiple compression sets. Each compression set contains a header structure giving information about how many page descriptors it contains, the compression algorithm used and the size of the compressed concatenated pages of the set.

The compression algorithm used can be one the following:

  • None: the pages are stored uncompressed
  • Xpress: The pages are stored using the Microsoft Xpress LZ77 Algorithm 3
  • HuffmanXpress: The pages are stored using the Microsoft Xpress LZ77+Huffman Algorithm 3 4

All the page descriptors are located after the header and are describing where the pages reside in the decompressed data.

alt text

Creating a volatility3 translation layer Link to heading

To be able to read multiple memory image formats, the volatility3 framework is using what’s called “Translation Layers”. Each layer in volatility3 focuses on a particular aspect of memory forensics, such as parsing specific data structures, analyzing various kinds of artifacts, or understanding specific evidence formats. The layers can be seen as individual building blocks that can be stacked on top of each other in a specific order to build the right context before extracting data for analysis. As an example, a memory image with the “vmem” format will induce the stacking of the “VmwareLayer” to be able to read such file format and extract memory pages.

In our case, when the framework is requesting several bytes at a specific physical address, it needs to understand the structure of the hibernation file and how to extract the right pages. For this, we have to indicate to the framework for a given memory “segment”, the corresponding set of pages.

The Hibernation layer role is to provide the volatility framework with the following information :

  • Check the file header to see if the layer needs to be stacked (check the signature to verify it is a hibernation file)
  • Build a list of segments: A segment is here to translates a given physical address to an offset inside of the uncompressed data of the relevant compression set.
  • Provide the decompression method for a given segment: Our layer needs to be able to decompress a given compression set and returns the number of bytes requested by the upper layer.

alt text

Implementation of the different compression algorithms Link to heading

Windows is using two proprietary compression algorithms to compress the pages:

  • Xpress: The Microsoft Xpress LZ77 Decompression Algorithm 3
  • HuffmanXpress: Microsoft Xpress LZ77+Huffman Decompression Algorithm 3 4

Those two algorithms were implemented and added to the volatility3 framework codecs without the needs of using the Windows API via cstruct (making this layer OS independant). Those algorithms are well documented but python3 is not really the best programming language to perform bitwise operations. Thus the developpement of those two algorithm took time to make sure that the decompressed page using our implementation is giving the same result as the native API 5

Proof Of Concept Link to heading

After implementing this new translation layer, it was time to test it against multiple hibernation files. Knowing that we need to do a lot of decompressions operations, the hibernation layer is meant to be combine with the “layerwriter” plugin to create a raw memory image and then analyze it with the windows plugins. Indeed, the decompression of a set takes time and most of the plugin need to scan the entire memory dump pages making a lot of decompression operations thus slowing the framework. Creating a raw memory dump first is the best approach here for performances. To this end, 2 new plugins were added to the volatility3 framework:

  • windows.hibernation.Info : Display the basic information about the hibernation file and if it seems exploitable.
  • windows.hibernation.Dump : Convert the hibernation file into a raw memory dump (based on the layerwriter plugin)

The generation of the raw memory file was performed on 8 hibernations files from different versions of Windows:

Version / Target hiberfile size Conversion time
Windows 8 x64 / Laptop 8GB ~30 minutes
Windows 10 1507 x64 / Laptop 8GB ~20 minutes
Windows 10 1607 x64 / Laptop 8GB ~20 minutes
Windows 10 1809 x64 / KVM 8GB ~10 minutes
Windows 10 1809 x64 / KVM 4GB ~5 minutes
Windows 10 22H02 x64 / Laptop 8GB ~60 minutes
Windows 10 22H02 x64 / Laptop 16GB ~100 minutes
Windows 11 23H02 x64 / Laptop 8GB ~100 minutes

Note : On Windows 1809 hiberfile from a KVM, it was found that pages were located only in the boot section and none in the kernel section. The compressed data were either using the Xpress LZ77 compression or were not compressed but the Huffman variant was not identified. On Windows 22H2, most of the pages are located inside the kernel section using both plain LZ77 and LZ77+Huffman compression. It is not clear how Microsoft decides which compression algorithm is used and if both sections are used to store the pages.

Usage : Conversion Link to heading

Firstly, we check if the hibernation file seems exploitable :

~/work/DFIR/volatility3» ./vol.py -f hiberfil_Win10_1507.sys windows.hibernation.Info
Volatility 3 Framework 2.5.1
Progress:  100.00               PDB scanning finished                         
Variable        Value
Signature       b'HIBR'
PageSize        4096
Comment The hibernation file header signature is correct.
System Time     2023-11-03 20:32:25
FirstBootRestorePage    0x23
NumPagesForLoader       32199

Next, we can try to convert the hibernation file to a raw file:

~/work/DFIR/volatility3» ./vol.py -f hiberfil_Win10_1507.sys windows.hibernation.Dump -h
usage: volatility windows.hibernation.Dump [-h] --version VERSION

optional arguments:
  -h, --help         show this help message and exit
  --version VERSION  The Windows version of the hibernation file : 
        0=>[Windows 10 1703 to Windows 11 23H2] 
        1=>[Windows 8/8.1] 
        2=>[Windows 10 1507 to 1511] 
        3=>[Windows 10 1607]
~/work/DFIR/volatility3» ./vol.py -f hiberfil_Win10_1507.sys windows.hibernation.Dump --version 2
Status
Progress:   99.99               Writing layer memory_layer                    
The hibernation file was converted to memory_layer.raw

Example: pslist Link to heading

~/work/DFIR/volatility3» ./vol.py -f memory_layer.raw windows.pslist
Volatility 3 Framework 2.5.1
Progress:  100.00		PDB scanning finished
PID	PPID	ImageFileName	Offset(V)	Threads	Handles	SessionId	Wow64	CreateTime	ExitTime	File output

4	0	System	0xe5072e280300	182	-	N/A	False	2023-09-30 14:52:10.000000 	N/A	Disabled
136	4	Registry	0xe5072e2ee040	4	-	N/A	False	2023-09-30 14:52:09.000000 	N/A	Disabled
400	4	smss.exe	0xe507322aa0c0	3	-	N/A	False	2023-09-30 14:52:10.000000 	N/A	Disabled
532	484	csrss.exe	0xe50732242140	13	-	0	False	2023-09-30 14:52:11.000000 	N/A	Disabled
628	484	wininit.exe	0xe50734c6a080	5	-	0	False	2023-09-30 14:52:12.000000 	N/A	Disabled
636	620	csrss.exe	0xe50734c6f140	13	-	1	False	2023-09-30 14:52:12.000000 	N/A	Disabled
700	628	services.exe	0xe50734cf0100	17	-	0	False	2023-09-30 14:52:12.000000 	N/A	Disabled
708	628	lsass.exe	0xe50734d25080	9	-	0	False	2023-09-30 14:52:12.000000 	N/A	Disabled
840	700	svchost.exe	0xe50734d8e280	29	-	0	False	2023-09-30 14:52:12.000000 	N/A	Disabled
868	628	fontdrvhost.ex	0xe50734db9180	5	-	0	False	2023-09-30 14:52:12.000000 	N/A	Disabled
932	700	svchost.exe	0xe50734b25540	13	-	0	False	2023-09-30 14:52:12.000000 	N/A	Disabled
[TRUNCATED]

Example : netscan Link to heading

~/work/DFIR/volatility3» ./vol.py -f memory_layer.raw windows.netscan
Volatility 3 Framework 2.5.1
Progress:  100.00		PDB scanning finished
Offset	Proto	LocalAddr	LocalPort	ForeignAddr	ForeignPort	State	PID	Owner	Created

0xe507320e1b00	TCPv4	127.0.0.1	49743	127.0.0.1	49742	ESTABLISHED	6660	RiotClientServ	2023-09-30 14:52:33.000000
0xe50733c5ba60	TCPv4	192.168.122.74	49883	8.247.201.124	443	ESTABLISHED	6660	RiotClientServ	2023-09-30 14:52:38.000000
0xe50734ab2d00	TCPv4	0.0.0.0	135	0.0.0.0	0	LISTENING	932	svchost.exe	2023-09-30 14:52:12.000000
0xe50734ab2d00	TCPv6	::	135	::	0	LISTENING	932	svchost.exe	2023-09-30 14:52:12.000000
0xe50734ab2e50	TCPv4	0.0.0.0	49664	0.0.0.0	0	LISTENING	628	wininit.exe	2023-09-30 14:52:12.000000
0xe50734ab2e50	TCPv6	::	49664	::	0	LISTENING	628	wininit.exe	2023-09-30 14:52:12.000000
0xe50734ab34e0	TCPv4	0.0.0.0	49664	0.0.0.0	0	LISTENING	628	wininit.exe	2023-09-30 14:52:12.000000
0xe50734ab38d0	TCPv4	0.0.0.0	135	0.0.0.0	0	LISTENING	932	svchost.exe	2023-09-30 14:52:12.000000
0xe50734d624e0	TCPv4	192.168.122.74	49687	20.223.46.67	443	ESTABLISHED	2552	MsMpEng.exe	2023-09-30 14:52:17.000000
0xe5073540a990	TCPv4	192.168.122.74	139	0.0.0.0	0	LISTENING	4	System	2023-09-30 14:52:12.000000
0xe5073540b410	TCPv4	0.0.0.0	49665	0.0.0.0	0	LISTENING	952	svchost.exe	2023-09-30 14:52:12.000000
0xe5073540b800	TCPv4	0.0.0.0	49666	0.0.0.0	0	LISTENING	1416	svchost.exe	2023-09-30 14:52:12.000000
0xe5073540c130	TCPv4	0.0.0.0	49666	0.0.0.0	0	LISTENING	1416	svchost.exe	2023-09-30 14:52:12.000000
0xe5073540c130	TCPv6	::	49666	::	0	LISTENING	1416	svchost.exe	2023-09-30 14:52:12.000000
0xe5073540c3d0	TCPv4	0.0.0.0	49665	0.0.0.0	0	LISTENING	952	svchost.exe	2023-09-30 14:52:12.000000
0xe5073540c3d0	TCPv6	::	49665	::	0	LISTENING	952	svchost.exe	2023-09-30 14:52:12.000000
[TRUNCATED]

Conclusion Link to heading

For all tested files, the framework was able to extract and decompress all of the pages in each restoration sets. The hibernation layer currently only support Windows 8 x64 to Windows 11 23H2 x64 hibernation files. Windows server hibernation analysis was not tested yet but it will come in time. Hopping the forensics community will also test this new addition and give some feedback to improve this layer. You can find the feature here: https://github.com/forensicxlab/volatility3/tree/feature/hibernation-layer.

Hoping this article will bring back the interests of the Digital Forensics community to hibernation files which are very valuable when available.

Special thanks to Chad Tilbury @chadtilbury who gave me the motivation to dive into this project and the team of researchers behind the Hibernation file structure analysis (Joe T. Sylve, Vico Marziale, Golden G. Richard III).

Do not hesitate to reach me at felix.guyard@forensicxlab.com to enhance this article or to comment on the integration to the volatility framework.