Package rekall :: Package plugins :: Package linux :: Module fs
[frames] | no frames]

Source Code for Module rekall.plugins.linux.fs

  1  # Rekall Memory Forensics 
  2  # 
  3  # Copyright 2013 Google Inc. All Rights Reserved. 
  4  # 
  5  # This program is free software; you can redistribute it and/or modify 
  6  # it under the terms of the GNU General Public License as published by 
  7  # the Free Software Foundation; either version 2 of the License, or (at 
  8  # your option) any later version. 
  9  # 
 10  # This program is distributed in the hope that it will be useful, but 
 11  # WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
 13  # General Public License for more details. 
 14  # 
 15  # You should have received a copy of the GNU General Public License 
 16  # along with this program; if not, write to the Free Software 
 17  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 18  """This module implements filesystem-related plugins for Linux.""" 
 19   
 20  from rekall import testlib 
 21   
 22  from rekall.plugins import core 
 23  from rekall.plugins.linux import common 
 24  from rekall.plugins.overlays.linux import vfs 
 25   
 26   
 27  __author__ = "Jordi Sanchez <parki.san@gmail.com>" 
 28   
 29   
30 -def InodeToPermissionString(inode):
31 """Represents an inode's permisions as an ls-like string.""" 32 33 result = [] 34 if inode.type == "S_IFSOCK": 35 result.append("s") 36 elif inode.type == "S_IFLNK": 37 result.append("l") 38 elif inode.type == "S_IFREG": 39 result.append("-") 40 elif inode.type == "S_IFBLK": 41 result.append("b") 42 elif inode.type == "S_IFDIR": 43 result.append("d") 44 elif inode.type == "S_IFCHR": 45 result.append("c") 46 elif inode.type == "S_IFIFO": 47 result.append("f") 48 else: 49 result.append(" ") 50 51 result.append("r" if inode.mode.S_IRUSR else "-") 52 result.append("w" if inode.mode.S_IWUSR else "-") 53 if inode.mode.S_ISUID: 54 result.append("s" if inode.mode.S_IXUSR else "S") 55 else: 56 result.append("x" if inode.mode.S_IXUSR else "-") 57 58 result.append("r" if inode.mode.S_IRGRP else "-") 59 result.append("w" if inode.mode.S_IWGRP else "-") 60 if inode.mode.S_ISGID: 61 result.append("s" if inode.mode.S_IXGRP else "S") 62 else: 63 result.append("x" if inode.mode.S_IXGRP else "-") 64 65 result.append("r" if inode.mode.S_IROTH else "-") 66 result.append("w" if inode.mode.S_IWOTH else "-") 67 result.append("x" if inode.mode.S_IXOTH else "-") 68 if inode.mode.S_ISVTX: 69 result.append("t" if inode.mode.S_IXOTH else "T") 70 71 return "".join(result)
72 73
74 -class Mfind(common.LinuxPlugin):
75 """Finds a file by name in memory.""" 76 77 __name = "mfind" 78 79 __args = [ 80 dict(name="path", default="/", positional=True, 81 help="Path to the file."), 82 dict(name="device", 83 help="Name of the device to match.") 84 ] 85 86 table_header = [ 87 dict(name="divider", type="Divider"), 88 dict(name="device", hidden=True), 89 dict(name="mount", hidden=True), 90 dict(name="perms", width=11), 91 dict(name="uid", width=10, align="r"), 92 dict(name="gid", width=10, align="r"), 93 dict(name="size", width=14, align="r"), 94 dict(name="mtime", width=24), 95 dict(name="atime", width=24), 96 dict(name="ctime", width=24), 97 dict(name="inode", width=10, align="r"), 98 dict(name="file", hidden=True), 99 dict(name="path"), 100 ] 101 102
103 - def find(self, path, device=None, mountpoint=None):
104 """Yields a list of files matching the path on the given mountpoint. 105 106 If no mountpoint is specified, all mountpoints are searched. 107 This is akin to doing ls -ld, except that a list is returned because 108 several mount points may hold files which are candidates for such path. 109 """ 110 111 if not mountpoint: 112 mount_plugin = self.session.plugins.mount(session=self.session) 113 mountpoints = mount_plugin.get_mount_points() 114 else: 115 mountpoints = [mountpoint] 116 117 for mountpoint in mountpoints: 118 if device != None and mountpoint.device != device: 119 continue 120 121 if path and not path.startswith(unicode(mountpoint.name)): 122 continue 123 124 current_file = vfs.File(mountpoint=mountpoint, 125 dentry=mountpoint.sb.s_root, 126 is_root=True, 127 session=self.session) 128 129 if path == unicode(mountpoint.name): 130 # Return a file for the mountpoint root 131 yield current_file 132 else: 133 remaining_path = path[len(mountpoint.name):] 134 traversal_list = remaining_path.split("/") 135 136 i = 0 137 found = True 138 while i < len(traversal_list): 139 component_to_search = traversal_list[i] 140 if component_to_search == "." or not component_to_search: 141 i += 1 142 continue 143 144 found = False 145 for file_ in current_file.walk(): 146 if file_.name == component_to_search: 147 found = True 148 current_file = file_ 149 150 i += 1 151 152 if found: 153 yield current_file
154
155 - def collect(self):
156 mount_plugin = self.session.plugins.mount(session=self.session) 157 mountpoints = mount_plugin.get_mount_points() 158 159 for mountpoint in mountpoints: 160 files = list(self.find(self.plugin_args.path, 161 device=self.plugin_args.device, 162 mountpoint=mountpoint)) 163 164 if files: 165 divider = "Files on device %s mounted at %s.\n" % ( 166 mountpoint.device, mountpoint.name) 167 yield dict(divider=divider) 168 169 for file_ in files: 170 yield self.collect_file(mountpoint, file_)
171
172 - def collect_file(self, mountpoint, file_):
173 inode = file_.dentry.d_inode 174 fullpath = file_.fullpath 175 atime = self.session.profile.UnixTimeStamp( 176 value=inode.i_atime.tv_sec) 177 mtime = self.session.profile.UnixTimeStamp( 178 value=inode.i_mtime.tv_sec) 179 ctime = self.session.profile.UnixTimeStamp( 180 value=inode.i_ctime.tv_sec) 181 182 return dict(perms=InodeToPermissionString(inode), 183 uid=inode.i_uid, gid=inode.i_gid, 184 size=inode.i_size, mtime=mtime, 185 atime=atime, ctime=ctime, 186 inode=inode.i_ino, 187 path=fullpath, 188 device=mountpoint.device, 189 file=file_, 190 mount=mountpoint.name)
191 192
193 -class Mls(Mfind):
194 """Lists the files in a mounted filesystem.""" 195 196 __name = "mls" 197 198 __args = [ 199 dict(name="recursive", type="Boolean", 200 help="Recursive listing"), 201 dict(name="unallocated", type="Boolean", 202 help="Show files that have no inode information."), 203 ] 204
205 - def collect(self):
206 for file_info in super(Mls, self).collect(): 207 entry = file_info.get("file") 208 if entry: 209 yield dict( 210 divider="Files on device %s mounted at %s.\n" % ( 211 entry.mountpoint.device, entry.mountpoint.name)) 212 213 if not entry.is_directory(): 214 yield self.collect_file(entry.mountpoint, entry) 215 else: 216 for file_ in entry.walk( 217 recursive=self.plugin_args.recursive, 218 unallocated=self.plugin_args.unallocated): 219 yield self.collect_file(entry.mountpoint, file_)
220 221
222 -class Mcat(core.DirectoryDumperMixin, Mfind):
223 """Returns the contents available in memory for a given file. 224 225 Ranges of the file that are not present in memory are returned blank. 226 """ 227 228 __name = "mcat" 229 230 table_header = [ 231 dict(name="start", width=12), 232 dict(name="end", width=12), 233 dict(name="path", width=80), 234 dict(name="dump_name", width=80), 235 ] 236
237 - def collect(self):
238 renderer = self.session.GetRenderer() 239 for file_info in super(Mcat, self).collect(): 240 file_obj = file_info.get("file") 241 if not file_obj: 242 continue 243 244 page_size = self.session.kernel_address_space.PAGE_SIZE 245 buffer_size = 1024*1024 246 buffer = "" 247 248 # Write buffered output as a sparse file. 249 path = file_info["path"] 250 with renderer.open( 251 filename=path, 252 directory=self.plugin_args.dump_dir, 253 mode="wb") as fd: 254 255 for range_start, range_end in file_obj.extents: 256 yield dict(start=range_start, end=range_end, 257 path=path, dump_name=fd.name) 258 259 fd.seek(range_start) 260 for offset in range(range_start, range_end, page_size): 261 page_index = offset / page_size 262 to_write = min(page_size, file_obj.size - offset) 263 data = file_obj.GetPage(page_index) 264 if data != None: 265 buffer += data[:to_write] 266 else: 267 buffer += "\x00" * to_write 268 269 # Dump the buffer when it's full. 270 if len(buffer) >= buffer_size: 271 fd.write(buffer) 272 buffer = "" 273 274 # Dump the remaining data in the buffer. 275 if buffer != "": 276 fd.write(buffer) 277 buffer = ""
278 279
280 -class TestMfind(testlib.HashChecker):
281 PARAMETERS = dict( 282 commandline="mfind %(file)s" 283 )
284 285
286 -class TestMls(testlib.HashChecker):
287 PARAMETERS = dict( 288 commandline="mls %(file)s" 289 )
290 291
292 -class TestMcat(testlib.HashChecker):
293 PARAMETERS = dict( 294 commandline="mcat %(file)s --dump_dir %(tempdir)s" 295 )
296