Skip to content
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

volshell: change dt() output to show where pointers lead #1028

Draft
wants to merge 10 commits into
base: develop
Choose a base branch
from
54 changes: 48 additions & 6 deletions volatility3/cli/volshell/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,20 @@ def disassemble(self, offset, count=128, layer_name=None, architecture=None):
for i in disasm_types[architecture].disasm(remaining_data, offset):
print(f"0x{i.address:x}:\t{i.mnemonic}\t{i.op_str}")

def _get_type_name_with_pointer(self, member_type, depth=0) -> str:
eve-mem marked this conversation as resolved.
Show resolved Hide resolved
"""Takes a member_type from and returns the subtype name with a * if the member_type is
a pointer otherwise it returns just the normal type name."""
pointer_marker = "*" * depth
try:
if member_type.vol.object_class == objects.Pointer:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be better to use isinstance than equality? It's interesting this is a different test than the isinstance below used for display_type They should probably match to avoid weird discrepancies! 5:P

sub_member_type = member_type.vol.subtype
return self._get_type_name_with_pointer(sub_member_type, depth + 1)
except AttributeError:
pass # not all objects get a `object_class`, and those that don't are not pointers.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They should all get a type_name, but then you're having to do string comparisons (although pointer should be a built-in type, so the name shouldn't change?). Happy with either route...

finally:
member_type_name = pointer_marker + member_type.vol.type_name
return member_type_name

def display_type(
self,
object: Union[
Expand Down Expand Up @@ -344,16 +358,38 @@ def display_type(
volobject.vol.type_name, layer_name=self.current_layer, offset=offset
)

# add special case for pointer so that information about the struct the
# pointer is pointing to is shown rather than simply the fact this is a
# pointer object.
dereference_count = 0
while isinstance(volobject, objects.Pointer):
# check that we can follow the pointer before dereferencing
if volobject.is_readable():
volobject = volobject.dereference()
dereference_count = dereference_count + 1
else:
break

if dereference_count == 0:
dereference_comment = ""
elif dereference_count == 1:
dereference_comment = "(dereferenced once)"
else:
dereference_comment = f"(dereferenced {dereference_count} times)"

if hasattr(volobject.vol, "size"):
print(f"{volobject.vol.type_name} ({volobject.vol.size} bytes)")
print(
f"{volobject.vol.type_name} ({volobject.vol.size} bytes) {dereference_comment}"
)
elif hasattr(volobject.vol, "data_format"):
data_format = volobject.vol.data_format
print(
"{} ({} bytes, {} endian, {})".format(
"{} ({} bytes, {} endian, {} {})".format(
volobject.vol.type_name,
data_format.length,
data_format.byteorder,
"signed" if data_format.signed else "unsigned",
dereference_comment,
)
)

Expand All @@ -363,15 +399,21 @@ def display_type(
relative_offset, member_type = volobject.vol.members[member]
longest_member = max(len(member), longest_member)
longest_offset = max(len(hex(relative_offset)), longest_offset)
longest_typename = max(len(member_type.vol.type_name), longest_typename)
member_type_name = self._get_type_name_with_pointer(
member_type
) # special case for pointers to show what they point to
longest_typename = max(len(member_type_name), longest_typename)

for member in sorted(
volobject.vol.members, key=lambda x: (volobject.vol.members[x][0], x)
):
relative_offset, member_type = volobject.vol.members[member]
len_offset = len(hex(relative_offset))
len_member = len(member)
len_typename = len(member_type.vol.type_name)
member_type_name = self._get_type_name_with_pointer(
member_type
) # special case for pointers to show what they point to
len_typename = len(member_type_name)
if isinstance(volobject, interfaces.objects.ObjectInterface):
# We're an instance, so also display the data
print(
Expand All @@ -381,7 +423,7 @@ def display_type(
member,
" " * (longest_member - len_member),
" ",
member_type.vol.type_name,
member_type_name,
" " * (longest_typename - len_typename),
" ",
self._display_value(getattr(volobject, member)),
Expand All @@ -394,7 +436,7 @@ def display_type(
member,
" " * (longest_member - len_member),
" ",
member_type.vol.type_name,
member_type_name,
)

@classmethod
Expand Down