1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
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
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
171
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
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
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
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
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
270 if len(buffer) >= buffer_size:
271 fd.write(buffer)
272 buffer = ""
273
274
275 if buffer != "":
276 fd.write(buffer)
277 buffer = ""
278
279
284
285
286 -class TestMls(testlib.HashChecker):
290
291
296