-
Notifications
You must be signed in to change notification settings - Fork 499
Volshell: Add Dedicated Method to retrieve EPROCESS/Task object #1381
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Hello @the-rectifier - nice timing on this as I was recently working on a similar feature as forcing people to do the list comprehension is pretty miserable as you noted. With that said, accepting only a
To work around this, the offset (virtual or physical) needs to be allowed to be specified as this is 1) 100% precise on which process to analyze 2) supports analysis of processes found from psscan / psxview. The cleanest way in my view would be optional parameters like pid=None,v_offset=None,p_offset=None and then the code branch based on which is set. If you are willing to work these offset parameters into your code then I can drop my code as I would rather encourage more external developers to contribute to the framework. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally looks fine, thanks! Just wondering about an alias to keep the naming more consistent...
Hello @atcuno, thanks for the reply! I wasn't aware of the issues with smearing. I just hacked up a quick way to interact with structures now that I started working on my thesis. That being said, I am not that familiar with volatility internals yet, to promise a timeline. I might look into a proper version sometime in the future but I think it'd be better to continue with your codebase |
@the-rectifier don't give up yet. The basic idea would be to allow either the virtual address or physical offset to be specified and then create an _EPROCESS object at it. For physical offsets, there is a helper function:
Let me know if you have any questions. |
I'd also be wary of putting too much into the generic volshell plugin. If a plugin can do it better I think we should leave the plugin to do it (even if that includes working on a physical process offset). Linking volshell functionality against a specific plugin (even a stock one) is a bad idea, as would duplicating the functionality be. I'm sure there's a solution, but I don't think it's necessary for the immediate term... |
I would be fine with code duplication in this case, even if copy/paste from the plugin, as being limited to |
I think you mean inconvenient. I've no problem loading up specific kernel offsets physical or virtual, but making volshell depend on psscan to find them rather than having to put a couple extra lines isn't worth the complexity it would bring to the command line tool in my opinion. It's really not difficult to make use of a plugin and if that's too many lines to type, a snippet would reduce that. We're currently in a state where the dependency on simple |
The psscan link was to the I was saying that code can be copy/pasted into the volshell side to avoid the dependency. Then passing in a physical offset to get the _EPROCESS would work inside of volshell. That offset would come from the user running psscan or psxview first and noticing the hidden process. |
My bad, that function doesn't look overly complex so I think I'd be ok duplicating it too... |
Thanks for the replies, all. I played with the code a bit, and I added this to the windows side of things: kvo = self.config['kernel.offset']
ntkrnlmp = self.context.module(self.current_symbol_table, layer_name='layer_name', offset=kvo)
eproc = ntkrnlmp.object(
object_type='_EPROCESS',
offset=v_offset,
absolute=True
) As @atcuno suggested, much like the However, I still can't wrap my head around what to do when a physical address is provided. Is there a way to get from the physical address to the corresponding virtual one? |
@the-rectifier if you look at the linux.psscan as an example you'll see that the object is made with offsets on the physical layer but its native layer is set to the virtual one. It's a sort of magical 'it just works'TM magic part of vol. It allows you to make an object on one layer, but then follow any pointers etc in another. |
Also, this discussion has made me think it might be useful to share scripts that people could import by Similar to how people make use of gdb configs. I need to think about sharing all the volshell snippets I use. |
Also, we need to be slightly careful when putting in code that accessesd sub-config values using |
eed9801
to
2fa3370
Compare
Hey all, happy new year! I've been working on my thesis and I figured I'll work on this, now that I have a slightly better understanding of the framework and its inner workings. I updated thank you @eve-mem for suggesting that linux virtual/physical offsets can be used interchangeably when creating the object also implemented some extra sanity checks if we know what PID are we expecting |
Happy New Year to you too! 5:D So basically, if you've got |
So I played with the code a bit, and before committing, I'd like to ask a few more questions:
|
No, that's not guaranteed, although it is convention. Add process layer will typically create a virtual layer, the layer below an intel layer is typically called The native layer machinery is independent of the OS, but it may also be unnecessary. If you've got the virtual address for it, that's best. If you've got a physical address for it and you know the virtual layer it lives in that comes a close second, but there isn't really a precedent. If you're intending to use a single offset parameter, don't it'll just confusing things, and other wise I'd say if someone provides more than one of (pid, virtual, physical) then you throw an error and say they need to provide only one... |
95c5c48
to
dfe3d25
Compare
Thanks for explaining the layers @ikelos, everything is much clearer now! I've made the changes you suggested, and also now I'm sourcing the layer names from the |
Also, the force-push removed the documentation commit, will do that when I finalize the code |
I probably would, how do you know whether they provided a virtual or a physical offset otherwise? If they both happen to be valid, you've no way of telling which one they meant... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking much better, thanks! I think there's still a few improvements to be had, but to be honest I'd forgotten we used print rather than vollog
within volshell, but that seems to be how the rest of it's coded...
volatility3/cli/volshell/linux.py
Outdated
) | ||
|
||
try: | ||
DescExitStateEnum(ptask.exit_state) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this statement to test for offset validity? If so I think something like is_valid
would work better, so ptask.exit_state.is_valid()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, yeah, fair enough. It will work, just sticks out a little to me...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shall I use is_valid()
then on all proc/tasks? On windows since dt()
breaks if the object is not valid, returning None
makes more sense, than just printing a warning
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it's alright, it just stands out to me as a method of testing (and getting a second example in the code base will make it harder to prevent if more people add it that way). There's currently a bit of a shift in the linux codebase where they're implementing check validity first rather than throwing exceptions. If you'd like to and can get it to work, it might be better in keeping with the rest of the codebase, but if you don't want to or it's tricky to achieve then that's fine...
volatility3/cli/volshell/linux.py
Outdated
@@ -50,6 +107,7 @@ def construct_locals(self) -> List[Tuple[List[str], Any]]: | |||
result += [ | |||
(["ct", "change_task", "cp"], self.change_task), | |||
(["lt", "list_tasks", "ps"], self.list_tasks), | |||
(["gp", "get_process"], self.get_process), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add "get_task"
to the end of that list too please? gt
won't work, but get_task
then would... Can't tell if it's worth adding that alias to windows too, I'll leave that one up to you...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't particularly like that we needed to mix process/task, so for the windows side I think i'd leave it just with the process suffix
volatility3/cli/volshell/linux.py
Outdated
@@ -40,6 +51,52 @@ def change_task(self, pid=None): | |||
return None | |||
print(f"No task with task ID {pid} found") | |||
|
|||
def get_process(self, pid=None, offset=None): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This implies offset is always a physical offset. Were you going to split that into physical_offset
and virtual_offset
or something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did split the code, basically the same as the windows side, but wanted to get your input on the is_valid()
thing before committing
volatility3/cli/volshell/windows.py
Outdated
@@ -44,11 +44,58 @@ def list_processes(self): | |||
) | |||
) | |||
|
|||
def get_process(self, pid=None, v_offset=None, p_offset=None): | |||
"""Returns the EPROCESS object that matches the pid. If v_offset/p_offset is provided, construct the EPROCESS object at the provided address. Only one parameter is allowed.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here with regards to Args:
and Returns:
. Also I kinda prefer variables have more descriptive names (although I'll allow it if you really want, since it is likely to be typed be developers quite often).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shall I use virtaddr
and physaddr
on both?
Ok, looks good, thanks! |
This PR introduces a
gp()
(get_process()/get_task()
) method to the Windows and Linux Volshell respectively.I couldn't find a way for one to (quickly) grab an arbitrary
EPROCESS
/Task
object from the shell and I thought it'd be quicker, when interactively exploring structures, to have a dedicated method rather than repeat a one-liner each time.Also, update
linux.pslist
version requirements, since they changed in fa06064: