volatilityfoundation / volatility3

Volatility 3.0 development
http://volatilityfoundation.org/
Other
2.61k stars 447 forks source link

What steps would be needed to add a new OS to Volatility? #765

Open IridiumXOR opened 2 years ago

IridiumXOR commented 2 years ago

Hi, I want to extend Volatility 3 in order to support a brand new OS. What are the steps to do it?

ikelos commented 2 years ago

Hmmmm, good question. Apart from adding some plugins that work on it, you'll need to tinker with the automagic code a bit. The automagic should automatically choose itself based on the os prefix of the plugin (so you'll need to start a new namespace under plugins, like linux/mac/windows that are there at the moment). You also therefore might get something that builds up to an IntelLayer, but not anything special that might handle swap or other special page fault handling (as with windows). I'm hoping that's about all you'd need to do, but I guess the best option is to try it and ask for help if things go wrong? I suspect, while we've tried to avoid making assumptions about things like the OS or layer that things might be built on, we'll not have gotten it perfect and there'll be some places that'll need fixing up to make it more generic. Hopefully that wouldn't be too big a task, but as I say, we probably won't know until we try....

If it helps, I know someone did some work on adding in FreeBSD support, but then they never actually committed to the public repo, so it looks like that work may have been wasted. If you're able to, I strongly recommend filing draft pull requests, so at least others can help out and maybe push it over the line if time/effort becomes an issue. Hope that answers the question?

SourceDiver42 commented 2 years ago

I am currently adding FreeBSD support to vol3 for a school project, and I had to do some modifications to the dwarf2json program. I think I also got the KASLR part running in the automagic part (I modified the mac code) and it manages to find 2 symbols in a memory dump for the KASLR test, like the mac find_aslr() does it. The part I am stuck at is the DTB address and the layer stuff that was added in vol3. KPML4phys supposedly points to the page directory, but Elyse Bonds paper uses an offset in another symbol, whereas the existing implementation in vol2 subtracts the kernbase address from the KPML4phys address. The biggest issue is knowing if the symbols I am using are physical addresses or virtual addresses, if I need to KASLR-shift them and to know which layers I need in the end and what I need to do to get them to do their job. The vol2 implementation seemingly did not implement KASLR for instance. I get some DTB address on a test dump, but I always get the volatility3.framework.exceptions.PagedInvalidAddressException: Page Fault at entry 0x0 in table page directory pointer exception when running a certain plugin, or I get Unsatisfied requirement plugins.PsList.primary: Memory layer for the kernel Unsatisfied requirement plugins.PsList.freebsd: FreeBSD kernel Symbols messages that are not helpful at all, when running Pslist. On another plugin, I get unresolved symbol exceptions, because some symbols in my JSON are dumped as _unnamed__, followed by some numbers. There are many undocumented things in the codebase which make it very hard to get much progress done. There is so much uncertainty when adding an OS, I for instance don't know how to reliably test if my DTB is correctly calculated.

ikelos commented 2 years ago

There was another student that did some work on this but unfortunately never got far enough to commit it. I've added @npetroni since I believe he was more aware of the work than I was.

I'm afraid the error messages are about as specific as we can get? There is no good generic heuristic for determining the DTB on an x86 system. Since each process has its own DTB, even something that found pages which looked like a top level directory would not be able to determine the most useful one for memory analysis. Windows provided a shortcut of a self-referential pointer, and as a fallback structures that contain the kernel module's base load address so we can cross-reference to figure it out. For mac/linux we identify the correct symbols, and then use a built-in symbol to tell use where the table should live. There are no shortcuts unfortunately, it's up to the layer developer to determine where the DTB is, and that it's accurate. I recommend turning debugging up to full (-vvvvvvv) and using various vollog methods inside your code to verify the state of the layer in the automagic.

I don't know where you're getting the symbols from, but I suspect that they're likely relative to the kernel start, which may or may not be somewhere random in memory (depending on where the OS decides to put it, ie, whether there's KASLR or not) as such, you should probably consider it virtual.

You'd load the layer based on the correct DTB, and then construct a module with the symbol table, and an offset saying where that module lives (which, since it's the kernel module we're interest in, will be the kernel virtual offset).

If you have suggestions on what things need documenting, and would like to submit pull requests to document them, we'd be happy to review them. You're some of the first people looking to add a whole new operating system to the framework, and I'm sorry it isn't as easy as you'd like, but unfortunately each operating system has its own quirks, as you're finding, and it's difficult to document/cater for them all. My best suggestion for determining whether a DTB is likely correct or not, is to try and map the virtual space. If you get a lot of errors, chances are it's just random data, not a DTB.

I hope this helps in some way?

IridiumXOR commented 2 years ago

There was another student that did some work on this but unfortunately never got far enough to commit it. I've added @npetroni since I believe he was more aware of the work than I was.

I'm afraid the error messages are about as specific as we can get? There is no good generic heuristic for determining the DTB on an x86 system. Since each process has its own DTB, even something that found pages which looked like a top level directory would not be able to determine the most useful one for memory analysis. Windows provided a shortcut of a self-referential pointer, and as a fallback structures that contain the kernel module's base load address so we can cross-reference to figure it out. For mac/linux we identify the correct symbols, and then use a built-in symbol to tell use where the table should live. There are no shortcuts unfortunately, it's up to the layer developer to determine where the DTB is, and that it's accurate. I recommend turning debugging up to full (-vvvvvvv) and using various vollog methods inside your code to verify the state of the layer in the automagic.

I don't know where you're getting the symbols from, but I suspect that they're likely relative to the kernel start, which may or may not be somewhere random in memory (depending on where the OS decides to put it, ie, whether there's KASLR or not) as such, you should probably consider it virtual.

You'd load the layer based on the correct DTB, and then construct a module with the symbol table, and an offset saying where that module lives (which, since it's the kernel module we're interest in, will be the kernel virtual offset).

If you have suggestions on what things need documenting, and would like to submit pull requests to document them, we'd be happy to review them. You're some of the first people looking to add a whole new operating system to the framework, and I'm sorry it isn't as easy as you'd like, but unfortunately each operating system has its own quirks, as you're finding, and it's difficult to document/cater for them all. My best suggestion for determining whether a DTB is likely correct or not, is to try and map the virtual space. If you get a lot of errors, chances are it's just random data, not a DTB.

I hope this helps in some way?

I have deeply explored (and solved) this problem of OS-agnostic virtual to physical address translation in this paper https://www.s3.eurecom.fr/docs/tops22_oliveri.pdf. On x86, ARM and RISC-V it is possible to recover the kernel MMU radix tree without any knowledge on the OS, however, it is an extrema-ratio if you known anything about the OS (only the CPU architecture)

IridiumXOR commented 2 years ago

If I understand correctly, an automagic layer, after it has identified the dump as a dump of the OS XXX, it appends to the context the symbol table relative to the kernel version present in the dump right? I have write an automagic for my new OS (modifing also other parts of Vol3) but if I check the context table in volshell, I see only the table added by the ELF memory layer... it seems that the stacker, after it has stacked the new layer, does not "copy" the added symbol table to the context... do you have any idea?

ikelos commented 2 years ago

Correct, the stacker is purely to stack a layer and I don't believe any symbol tables that may be used are copied across. If a particular layer requires a symbol table, it should load it into the context itself when it is constructed (which will be done on the real context when that stacking process completes).