Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions volatility3/framework/layers/intel.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ def _page_is_valid(entry: int) -> bool:
"""Returns whether a particular page is valid based on its entry."""
return bool(entry & 1)

@staticmethod
def _page_is_dirty(entry: int) -> bool:
"""Returns whether a particular page is dirty based on its entry."""
return bool(entry & (1 << 6))

def canonicalize(self, addr: int) -> int:
"""Canonicalizes an address by performing an appropiate sign extension on the higher addresses"""
if self._bits_per_register <= self._maxvirtaddr:
Expand Down Expand Up @@ -259,6 +264,10 @@ def is_valid(self, offset: int, length: int = 1) -> bool:
except exceptions.InvalidAddressException:
return False

def is_dirty(self, offset: int) -> bool:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

My slight concern is that we only add this to the intel layer, and not the underlying TranslationLayerInterface, but I think we've done that in other places. I guess it just requires that any time we use it we ensure we know we're working with an intel layer (at the moment, that's likely to be all we're working with, but in the future it could be an arm layer or something else)...

"""Returns whether the page at offset is marked dirty"""
return self._page_is_dirty(self._translate_entry(offset)[0])

def mapping(
self, offset: int, length: int, ignore_errors: bool = False
) -> Iterable[Tuple[int, int, int, int, str]]:
Expand Down
13 changes: 11 additions & 2 deletions volatility3/framework/plugins/linux/malfind.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
#

from typing import List

import logging
from volatility3.framework import constants, interfaces
from volatility3.framework import renderers
from volatility3.framework.configuration import requirements
from volatility3.framework.objects import utility
from volatility3.framework.renderers import format_hints
from volatility3.plugins.linux import pslist

vollog = logging.getLogger(__name__)


class Malfind(interfaces.plugins.PluginInterface):
"""Lists process memory ranges that potentially contain injected code."""
Expand Down Expand Up @@ -47,7 +49,14 @@ def _list_injections(self, task):
proc_layer = self.context.layers[proc_layer_name]

for vma in task.mm.get_vma_iter():
if vma.is_suspicious() and vma.get_name(self.context, task) != "[vdso]":
vma_name = vma.get_name(self.context, task)
vollog.debug(
f"Injections : processing PID {task.pid} : VMA {vma_name} : {hex(vma.vm_start)}-{hex(vma.vm_end)}"
)
if (
vma.is_suspicious(proc_layer)
and vma.get_name(self.context, task) != "[vdso]"
):
data = proc_layer.read(vma.vm_start, 64, pad=True)
yield vma, data

Expand Down
20 changes: 19 additions & 1 deletion volatility3/framework/symbols/linux/extensions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ def get_name(self, context, task):
return fname

# used by malfind
def is_suspicious(self):
def is_suspicious(self, proclayer=None):
ret = False

flags_str = self.get_protection()
Expand All @@ -587,6 +587,24 @@ def is_suspicious(self):
ret = True
elif flags_str == "r-x" and self.vm_file.dereference().vol.offset == 0:
ret = True
elif proclayer and "x" in flags_str:
for i in range(self.vm_start, self.vm_end, 1 << constants.linux.PAGE_SHIFT):
try:
Comment thread
xabrouck marked this conversation as resolved.
if proclayer.is_dirty(i):
vollog.warning(
f"Found malicious (dirty+exec) page at {hex(i)} !"
)
# We do not attempt to find other dirty+exec pages once we have found one
ret = True
break
except (
exceptions.PagedInvalidAddressException,
exceptions.InvalidAddressException,
) as excp:
vollog.debug(f"Unable to translate address {hex(i)} : {excp}")
# Abort as it is likely that other addresses in the same range will also fail
ret = False
break
return ret


Expand Down