From af2d6206763a661ced9687f1c7b31b7888d3d0ce Mon Sep 17 00:00:00 2001 From: k1nd0ne Date: Tue, 23 Jul 2024 22:02:34 +0200 Subject: [PATCH] Improving lsof --- volatility3/framework/plugins/linux/lsof.py | 53 +++++++++++++++++-- .../framework/symbols/linux/__init__.py | 21 +++++++- 2 files changed, 69 insertions(+), 5 deletions(-) diff --git a/volatility3/framework/plugins/linux/lsof.py b/volatility3/framework/plugins/linux/lsof.py index d970ad8a9..f9aeafe14 100644 --- a/volatility3/framework/plugins/linux/lsof.py +++ b/volatility3/framework/plugins/linux/lsof.py @@ -3,7 +3,7 @@ # """A module containing a collection of plugins that produce data typically found in Linux's /proc file system.""" -import logging +import logging, datetime from typing import List, Callable from volatility3.framework import renderers, interfaces, constants @@ -76,14 +76,59 @@ class Lsof(plugins.PluginInterface): ) for pid, task_comm, _task, fd_fields in fds_generator: - fd_num, _filp, full_path = fd_fields + ( + fd_num, + _filp, + full_path, + inode_num, + imode, + ctime, + mtime, + atime, + file_size, + ) = fd_fields - fields = (pid, task_comm, fd_num, full_path) + fields = ( + pid, + task_comm, + fd_num, + full_path, + inode_num, + imode, + ctime, + mtime, + atime, + file_size, + ) yield (0, fields) def run(self): pids = self.config.get("pid", None) symbol_table = self.config["kernel"] - tree_grid_args = [("PID", int), ("Process", str), ("FD", int), ("Path", str)] + tree_grid_args = [ + ("PID", int), + ("Process", str), + ("FD", int), + ("Path", str), + ("Inode", int), + ("Mode", str), + ("LastChange", datetime.datetime), + ("LastModify", datetime.datetime), + ("LastAccessed", datetime.datetime), + ("Size", int), + ] return renderers.TreeGrid(tree_grid_args, self._generator(pids, symbol_table)) + + def generate_timeline(self): + filter_func = pslist.PsList.create_pid_filter(self.config.get("pid", None)) + for row in self._generator( + pslist.PsList.list_tasks( + self.context, self.config["kernel"], filter_func=filter_func + ) + ): + _depth, row_data = row + description = f'Process {row_data[1]} ({row_data[0]}) Open "{row_data[4]}"' + yield description, timeliner.TimeLinerType.CHANGED, row_data[5] + yield description, timeliner.TimeLinerType.MODIFIED, row_data[6] + yield description, timeliner.TimeLinerType.ACCESSED, row_data[7] diff --git a/volatility3/framework/symbols/linux/__init__.py b/volatility3/framework/symbols/linux/__init__.py index c4e2587f4..b9321f369 100644 --- a/volatility3/framework/symbols/linux/__init__.py +++ b/volatility3/framework/symbols/linux/__init__.py @@ -1,6 +1,7 @@ # This file is Copyright 2019 Volatility Foundation and licensed under the Volatility Software License 1.0 # which is available at https://www.volatilityfoundation.org/license/vsl-v1.0 # +import stat, datetime from typing import Iterator, List, Tuple, Optional, Union from volatility3 import framework @@ -265,8 +266,26 @@ class LinuxUtilities(interfaces.configuration.VersionableInterface): for fd_num, filp in enumerate(fds): if filp != 0: full_path = LinuxUtilities.path_for_file(context, task, filp) + dentry = filp.get_dentry() + if dentry != 0: + inode_object = dentry.d_inode + inode_num = inode_object.i_ino + file_size = inode_object.i_size # file size in bytes + imode = stat.filemode( + inode_object.i_mode + ) # file type & Permissions - yield fd_num, filp, full_path + # Timestamps + ctime = datetime.datetime.fromtimestamp( + inode_object.i_ctime.tv_sec + ) # last change time + mtime = datetime.datetime.fromtimestamp( + inode_object.i_mtime.tv_sec + ) # last modify time + atime = datetime.datetime.fromtimestamp( + inode_object.i_atime.tv_sec + ) # last access time + yield fd_num, filp, full_path, inode_num, imode, ctime, mtime, atime, file_size @classmethod def mask_mods_list(