Repository navigation
Feature : Hibernation Layer and plugins. - #1036
forensicxlab wants to merge 34 commits into
Conversation
Hibernation layerwriter is now working from Win1809 to Win22h2 hibernation.
…ded from Win8 to Win11. Testing in progress on hibernation files from the different OS versions.
…nation.Dump' plugin (provide the version of Windows)
|
Thanks very much for your contribution! This is quite a big change, so may take us some time to review (I also need to pull in some of the other guys who wrote our previous hibernation code to check it). So please don't despair, but this may take us some time... |
|
Hello @ikelos, Finally found some time to make adjustments to the code. I still have doubts about some of my choices for the implementation 🧐 Kind regards, |
|
Thanks Félix, unfortunately the chap that knows the hibernation stuff best ( @awalters ) is a little busy at the moment, so we haven't made much progress with it, but we haven't forgotten about it either. Could you describe your worries about the implementations choices you're not sure about please and hopefully one of us will be able to check out your concerns? |
|
|
||
| """Codecs used for encoding or decoding data should live here | ||
|
|
||
| # Temporary comment: |
There was a problem hiding this comment.
I wonder what's the best way to integrate algorithms into the "codecs" from the framework standpoint.
What are your recommandations about that ? Should I implement algorithms In seperate files ? I feel like I should but I have put both algorithms here for now :)
There was a problem hiding this comment.
Yeah, I'd probably put them both in different files, but there needs to be a way to register them (either the main code seeks them out, or they add themselves to a shared singleton object when they're imported). I don't know if it'll be overkill, but it might be pretty cool to build them into the existing python codec framework?
There was a problem hiding this comment.
Thanks, I'll get right on that.
| {} | ||
| ) # This will hold the mapping between the PageNumber in the decompressed data vs the physical page number. | ||
|
|
||
| if "plugins.Dump.version" in context.config: |
There was a problem hiding this comment.
The fact that this translation layer is meant to be used with the hibernation.Dump plugin makes me feel bad about this part.
Indeed the FirstKernelRestorePage and KernelPagesProcessed offsets can only be determine via the user input for now.
Is making a translation layer partially dependant to a plugin is an acceptable concept in the volatility3 framework ?
This concept is working well with this implementation and seems to have no side effects from all the tests I've made but an external eye from your side will be delightful :D I propably missed something.
There was a problem hiding this comment.
If this is the only requirement for the layer, then make it a requirement (like the kernel_virtual_offset for Intel layers), then anything can instantiate it as long as they provide the right version number for the layer (it might be better if the layer could figure it out for itself, but if not then ask the instantiator to provide it).
There was a problem hiding this comment.
Did not find a way to figure the version out by itself in my research at time of writing, I'll look at what’s done in the Intel layer thanks for the tip!
There was a problem hiding this comment.
Probably add a PluginRequirement and that should do you. 5:)
| ), | ||
| ] | ||
|
|
||
| def _generator(self): |
There was a problem hiding this comment.
The Idea here is to check if the HibernationLayer is indeed stacked before trying to make the conversion to the raw file using the layerwriter plugin. Feel like it's ugly though, did not find another cleaner way right now. I'll be happy to have your insights :D
There was a problem hiding this comment.
I mean, that's ok and it does reuse the LayerWriter class rather than implementing itself. If this whole plugin doesn't do anything other than call layerwriter, why don't we just document that to write out a hibernation layer, you should use layerwriter? A specific plugin for a specific layer type doesn't make a lot of sense? We might be able to update layerwriter so you can easily ask it to write all layers of a particular type (so you could say write out all HibernationLayer layers or something)? Essentially, improve the UI of the existing plugin to avoid the need for the new plugin.
There was a problem hiding this comment.
That's a very interesting idea.
I’ll leave both plugins in this PR so that the tests by the reviewer(s) can all be done on this branch. If the conclusion goes indeed in this way, I will implement your idea as soon as I can in a dedicated PR (if not proposed by somebody else in time :-) )
Hi @ikelos, Thank you for your quick responses every time. Kind Regards. |
|
FYI, just used that one on my local vol3 installation during the weekend and must say worked flawlessly. I could convert with no issues the EDIT: |
|
Thanks for the feedback, much appreciated! This is still waiting on @awalters for review at the moment, but we'll get to it once things have calmed down for everyone... 5:) |
|
Hello, Since I have a bit of time, I am working on a native python extension module using pyo3 for the decompression algorithms. The decompression speed is already a lot better with a pyo3 version of the xpress_lz77_plain_decompression algorithm tested. Currently working on the xpress_lz77_huffman rust binding before updating this PR. To be continued... |
|
Hello @ikelos, Just finished the implementation of the algorithms + packaging: Performances are now a lot better for the conversion of the hibernation file. It will also be useful for the prefetch plugin. I will post a PR for it if you are happy with adding xpress_lz77 in the requirements. Python 3.8 is required though, making some checks failed. Updated the pipeline, but I can still go back if we choose to check if the requirement is present for this translation layer (like in the cloudstorage/pcileech layers for example). Freezing to this point for now :) FYI: Rust will not be needed as a requirement to run volatility3 Thanks you! |
ikelos
left a comment
There was a problem hiding this comment.
Some errors that ruff picked up could do with some fixing, and the last merge seems to have made a mess of a few of the files. I'll give it a more thorough review once all that's cleaned up.
|
|
||
|
|
||
| """ | ||
| # Register codecs here. |
There was a problem hiding this comment.
So, had you been going to go the codec route?
| fail-fast: false | ||
| matrix: | ||
| <<<<<<< HEAD | ||
| host: [ubuntu-latest, windows-latest] |
There was a problem hiding this comment.
This seems like a failed merge, could you clear it up please?
| uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: ${{ matrix.python-version }} | ||
| - uses: actions/checkout@v4 |
There was a problem hiding this comment.
Changes just for formatting should be avoided if possible (some people will format it one way, and other a different way, and we'll end up playing pingpong...). I don't think any of the changes in this file are significant, so leave it out of the PR please...
| >>>>>>> develop | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - uses: actions/checkout@v4 |
| curl -sLO https://downloads.volatilityfoundation.org/volatility3/symbols/linux.zip | ||
| unzip linux.zip | ||
| cd - | ||
|
|
There was a problem hiding this comment.
More format only changes, look like this file can also be left out of the PR.
|
Hi there. Thanks for the review. I am still working on some enhancements to guess the Windows version without any arguments. Kind regards |
|
No problem, just wanted to make sure it wasn't waiting on me for some reason, take as long as you need! 5:) |
|
Hi @k1nd0ne, thanks for the layer. I was trying it on a Windows 11 24H2 Fast Startup 1. On 24H2 the kernel section is skipped with 2. The offset of that counter depends on the build, not only on the release. For each file below I walked the kernel chain of compression sets until it ends by itself, and looked for the header qwords that hold its page count and its byte length. Those relations hold exactly in every file, only the position of the block changes:
So a fixed offset per version would work for one 24H2 build and silently read the wrong counter on the other (the image comes out almost empty, with no error). Checking the counter against the chain (follow the sets, the page count must match exactly) picks the right one without a build number. The compression-set header is the same on both 24H2 files: the size is in bits 8-28 (bit 29 is not part of it, it is set on most sets), and bit 30 selects LZ77+Huffman. Every set of the 26100.1742 kernel section decompresses with those rules. I have a small patch for |
…uffman set size Two independent problems of the hibernation layer on Windows 11 Fast Startup files, validated on 21H2, 22H2, 23H2, 24H2, 25H2 and 26H1 lab VMs (see contrib/hibernation_checks/campaign_2026-10). 1. KernelPagesProcessed is not at 0x230 on build 26100 and later, and its offset depends on the build: 0x238 in 26100.1742, 26100.6584 and 28000.1340, 0x250 in a 26100.9445 file. With --version 0 the kernel section is skipped or mis-walked. New --version 4 (Windows 11 24H2 and later): the counter is read at the known offsets and accepted only if the chain of compression sets of the kernel section adds up to exactly that number of pages; a file where no candidate matches is refused with an explicit message. On those builds the set header carries the size in bits 8-28 (bit 29 is not part of it) and bit 30 selects LZ77+Huffman. 2. _uncompress asked the LZ77+Huffman decoder for 65536 bytes for every set. A set of fewer than 16 pages (present at the end of the kernel section of every Windows 11 21H2-24H2 file of the campaign) fails with "EOF Error" and aborts the whole conversion, including with the existing --version 0. The layer now passes the size of the set (pages * 4096). Versions 0 to 3 are otherwise unchanged.
…campaign logs) - hib_check.py: walks the chain of compression sets of a hiberfil.sys with the 23h2, 24h2-early (0x238) and 24h2 (0x250) layouts, finds the header qwords that bound the kernel section, reports set kinds and header bits, and with --decompress decodes every compressed set with the output size checked. Counters only, nothing identifying by default. - compare_outputs.py, count_nonzero_pages.py: page-by-page comparison of two Dump outputs, non-zero page count of a raw image. - test_hib_layout.py (16 tests of the tools) and test_hib_layer.py (3 tests of the real layer) on synthetic files generated in memory, no sample data. - campaign_2026-10/: logs of the campaign on Windows 11 21H2/22H2/23H2/24H2/ 25H2/26H1 lab VMs: per file hib_check output, Dump with this branch (twice), with the original code and with the wrong --version; unit tests x5, with the decoder fix reverted, and ruff.
hibernation: Windows 11 24H2+ support (build-dependent counter offset) and a decoder size fix.
volatility3/framework/layers/codecs/__init__.py imported the standard `codecs` module without using it (F401), which makes the lint-and-format workflow of the upstream PR volatilityfoundation#1036 fail with ruff 0.17.1. The file is now identical to the one on volatilityfoundation/volatility3 develop.
|
Hi @k1nd0ne, thanks for merging forensicxlab#1. The forensicxlab#2 removes it (the file becomes identical to the one on |
codecs: drop the unused import that fails the ruff job of volatilityfoundation#1036
Hello,
Details about the feature : https://www.forensicxlab.com/posts/hibernation/
Best regards.