-
Notifications
You must be signed in to change notification settings - Fork 481
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
Fix for windows.strings revmap offsets #1043
base: develop
Are you sure you want to change the base?
Changes from all commits
c96a9f3
cc420b1
0eaffb5
f035eb8
044bd8e
a1b0f51
d2992cf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,7 +18,7 @@ | |
class Strings(interfaces.plugins.PluginInterface): | ||
"""Reads output from the strings command and indicates which process(es) each string belongs to.""" | ||
|
||
_version = (1, 2, 0) | ||
_version = (2, 0, 0) | ||
_required_framework_version = (2, 0, 0) | ||
strings_pattern = re.compile(rb"^(?:\W*)([0-9]+)(?:\W*)(\w[\w\W]+)\n?") | ||
|
||
|
@@ -47,7 +47,13 @@ def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface] | |
|
||
def run(self): | ||
return renderers.TreeGrid( | ||
[("String", str), ("Physical Address", format_hints.Hex), ("Result", str)], | ||
[ | ||
("String", str), | ||
("Region", str), | ||
("PID", int), | ||
("Physical Address", format_hints.Hex), | ||
("Virtual Address", format_hints.Hex), | ||
], | ||
self._generator(), | ||
) | ||
|
||
|
@@ -81,22 +87,40 @@ def _generator(self) -> Generator[Tuple, None, None]: | |
last_prog: float = 0 | ||
line_count: float = 0 | ||
num_strings = len(string_list) | ||
for offset, string in string_list: | ||
for phys_offset, string in string_list: | ||
line_count += 1 | ||
try: | ||
revmap_list = [ | ||
name + ":" + hex(offset) for (name, offset) in revmap[offset >> 12] | ||
] | ||
except (IndexError, KeyError): | ||
revmap_list = ["FREE MEMORY"] | ||
yield ( | ||
0, | ||
( | ||
str(string, "latin-1"), | ||
format_hints.Hex(offset), | ||
", ".join(revmap_list), | ||
), | ||
|
||
# calculate the offset for this string within a 4096 page so | ||
# that this offset can be added to mappings which are all | ||
# page aligned. This ensures that a string located at phy | ||
# add 0x1e64cd20 would carry the 0xd20 to the virtual offsets | ||
# displayed in the plugin output. Without this it would show | ||
# only the page that the string was found, rather than the | ||
# actually addr. 0xFFF is 4095 e.g. all lower bits set. | ||
offset_within_page = phys_offset & 0xFFF | ||
|
||
mapping_entry = revmap.get( | ||
phys_offset >> 12, | ||
[{"region": "Unallocated", "pid": -1, "offset": 0x00}], | ||
) | ||
|
||
for item in mapping_entry: | ||
# Get the full virtual address not just the page start | ||
# If the string is in unalloacted memory, we set the offset to 0x00 | ||
offset = item.get("offset", 0x00) | ||
virtual_address = offset + offset_within_page | ||
|
||
yield ( | ||
0, | ||
( | ||
str(string.strip(), "latin-1"), | ||
item.get("region", "Unallocated"), | ||
item.get("pid", -1), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This also should default to a |
||
format_hints.Hex(phys_offset), | ||
format_hints.Hex(virtual_address), | ||
), | ||
) | ||
|
||
prog = line_count / num_strings * 100 | ||
if round(prog, 1) > last_prog: | ||
last_prog = round(prog, 1) | ||
|
@@ -147,14 +171,46 @@ def generate_mapping( | |
if isinstance(layer, intel.Intel): | ||
# We don't care about errors, we just wanted chunks that map correctly | ||
for mapval in layer.mapping(0x0, layer.maximum_address, ignore_errors=True): | ||
offset, _, mapped_offset, mapped_size, maplayer = mapval | ||
for val in range(mapped_offset, mapped_offset + mapped_size, 0x1000): | ||
cur_set = reverse_map.get(val >> 12, set()) | ||
cur_set.add(("kernel", offset)) | ||
reverse_map[val >> 12] = cur_set | ||
( | ||
virt_offset, | ||
_virt_size, | ||
phy_offset, | ||
phy_mapping_size, | ||
_phy_layer_name, | ||
) = mapval | ||
|
||
# for each page within the mapping we need to store the phy_offset and | ||
# the matching virt_offset | ||
for offset_to_page_within_mapping in range(0, phy_mapping_size, 0x1000): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hard coded 0x1000 |
||
# calculate the page number for this phy_offset, e.g. the ">> 12" | ||
# drops the bits that would address an offset within the page. | ||
# This means that all offsets within the same page get the same | ||
# physical_page number. | ||
physical_page = ( | ||
phy_mapping_size + offset_to_page_within_mapping | ||
) >> 12 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hard coded 12 |
||
|
||
# get the existing mappings for this physical page from the | ||
# reverse map set. | ||
cur_set = reverse_map.get(physical_page, list()) | ||
|
||
# add a mapping for this virtual offset, taking care to add the | ||
# offset_to_page_within_mapping to ensure that all pages match correctly. | ||
# Without this the 2nd, 3rd etc pages would all incorrectly map to the same | ||
# virtual offset. | ||
cur_set.append( | ||
{ | ||
"region": "Kernel", | ||
"pid": -1, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be a |
||
"offset": virt_offset + offset_to_page_within_mapping, | ||
} | ||
) | ||
|
||
# store these results back in the reverse_map | ||
reverse_map[physical_page] = cur_set | ||
if progress_callback: | ||
progress_callback( | ||
(offset * 100) / layer.maximum_address, | ||
(virt_offset * 100) / layer.maximum_address, | ||
"Creating reverse kernel map", | ||
) | ||
|
||
|
@@ -178,22 +234,37 @@ def generate_mapping( | |
|
||
proc_layer = context.layers[proc_layer_name] | ||
if isinstance(proc_layer, linear.LinearlyMappedLayer): | ||
# this follows the same pattern as the kernel mappings above. | ||
for mapval in proc_layer.mapping( | ||
0x0, proc_layer.maximum_address, ignore_errors=True | ||
): | ||
mapped_offset, _, offset, mapped_size, maplayer = mapval | ||
for val in range( | ||
mapped_offset, mapped_offset + mapped_size, 0x1000 | ||
( | ||
virt_offset, | ||
_virt_size, | ||
phy_offset, | ||
phy_mapping_size, | ||
_phy_layer_name, | ||
) = mapval | ||
for offset_to_page_within_mapping in range( | ||
0, phy_mapping_size, 0x1000 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is hardcoding the page size (which then agrees with the value 12 also hardcoded everywhere). That's ok, but I think it would be better to pull them out and make them constants in the plugin (just so they stay the same if the code ever changes). |
||
): | ||
cur_set = reverse_map.get(mapped_offset >> 12, set()) | ||
cur_set.add( | ||
(f"Process {process.UniqueProcessId}", offset) | ||
physical_page = ( | ||
phy_offset + offset_to_page_within_mapping | ||
) >> 12 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hard coded 12 |
||
cur_set = reverse_map.get(physical_page, list()) | ||
cur_set.append( | ||
{ | ||
"region": "Process", | ||
"pid": process.UniqueProcessId, | ||
"offset": virt_offset | ||
+ offset_to_page_within_mapping, | ||
} | ||
) | ||
reverse_map[mapped_offset >> 12] = cur_set | ||
reverse_map[physical_page] = cur_set | ||
# FIXME: make the progress for all processes, rather than per-process | ||
if progress_callback: | ||
progress_callback( | ||
(offset * 100) / layer.maximum_address, | ||
(virt_offset * 100) / proc_layer.maximum_address, | ||
f"Creating mapping for task {process.UniqueProcessId}", | ||
) | ||
|
||
|
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.
Hard coded 12