1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 import os
27
28 from rekall.plugins.windows import common
29 from rekall.plugins import core
30 from rekall import plugin
31 from rekall_lib import utils
32
33
34 -class PEDump(common.WindowsCommandPlugin):
35 """Dump a PE binary from memory."""
36
37 __name = "pedump"
38
39 __args = [
40 dict(name="image_base", type="SymbolAddress", required=False,
41 positional=True,
42 help="The address of the image base (dos header)."),
43
44 dict(name="out_file",
45 help="The file name to write."),
46
47 dict(name="address_space", type="AddressSpace",
48 help="The address space to use."),
49
50 dict(name="out_fd",
51 help="A file like object to write the output.")
52 ]
53
57
58 - def WritePEFile(self, fd=None, address_space=None, image_base=None):
59 """Dumps the PE file found into the filelike object.
60
61 Note that this function can be used for any PE file (e.g. executable,
62 dll, driver etc). Only a base address need be specified. This makes this
63 plugin useful as a routine in other plugins.
64
65 Args:
66 fd: A writable filelike object which must support seeking.
67 address_space: The address_space to read from.
68 image_base: The offset of the dos file header.
69 """
70 dos_header = self.pe_profile._IMAGE_DOS_HEADER(
71 offset=image_base, vm=address_space)
72
73 image_base = dos_header.obj_offset
74 nt_header = dos_header.NTHeader
75
76
77 data = dos_header.obj_vm.read(
78 image_base, min(1000000, nt_header.OptionalHeader.SizeOfHeaders))
79
80 if not data:
81 return
82
83 fd.seek(0)
84 fd.write(data)
85
86 for section in nt_header.Sections:
87
88 size_of_section = min(10000000, section.SizeOfRawData)
89 physical_offset = min(100000000, int(section.PointerToRawData))
90
91 data = section.obj_vm.read(
92 section.VirtualAddress + image_base, size_of_section)
93
94 fd.seek(physical_offset, 0)
95 fd.write(data)
96
119
120
121 -class ProcExeDump(core.DirectoryDumperMixin, common.WinProcessFilter):
122 """Dump a process to an executable file sample"""
123
124 __name = "procdump"
125
126 dump_dir_optional = True
127
128 __args = [
129 dict(name="out_fd",
130 help="A file like object to write the output.")
131 ]
132
133 table_header = [
134 dict(name="_EPROCESS", width=50),
135 dict(name="Filename"),
136 ]
137
139 """Dump a process from memory into an executable.
140
141 In windows PE files are mapped into memory in sections. Each section is
142 mapped into a region within the process virtual memory from a region in
143 the executable file:
144
145 File on Disk Memory Image
146 0-> ------------ image base-> ------------
147 Header Header
148 ------------ ------------
149 Section 1
150 ------------ ------------
151 Section 2 Section 1
152 ------------ ------------
153
154 ------------
155 Section 2
156 ------------
157
158 This plugin simply copies the sections from memory back into the file on
159 disk. Its likely that some of the pages in memory are not actually
160 memory resident, so we might get invalid page reads. In this case the
161 region on disk is null padded. If that happens it will not be possible
162 to run the executable, but the executable can still be disassembled and
163 analysed statically.
164
165 References:
166 http://code.google.com/p/corkami/downloads/detail?name=pe-20110117.pdf
167
168 NOTE: Malware can mess with the headers after loading. The remap option
169 allows to remap the sections on the disk file so they do not collide.
170
171 Args:
172 remap: If set, allows to remap the sections on disk so they do not
173 overlap.
174
175 out_fd: Alternatively, a filelike object can be provided directly.
176 """
177 super(ProcExeDump, self).__init__(*args, **kwargs)
178 self.pedump = PEDump(session=self.session)
179 if self.dump_dir is None and not self.plugin_args.out_fd:
180 raise plugin.PluginError("Dump dir must be specified.")
181
183 """Renders the tasks to disk images, outputting progress as they go"""
184 for task in self.filter_processes():
185 pid = task.UniqueProcessId
186
187 task_address_space = task.get_process_address_space()
188 if not task_address_space:
189 self.session.logging.info(
190 "Can not get task address space - skipping.")
191 continue
192
193 if self.plugin_args.out_fd:
194 self.pedump.WritePEFile(
195 self.plugin_args.out_fd,
196 task_address_space, task.Peb.ImageBaseAddress)
197 yield task, "User FD"
198
199
200 else:
201 filename = u"executable.%s_%s.exe" % (
202 utils.EscapeForFilesystem(task.name), pid)
203
204 yield task, filename
205
206 with self.session.GetRenderer().open(
207 directory=self.dump_dir,
208 filename=filename,
209 mode="wb") as fd:
210
211 self.pedump.WritePEFile(
212 fd, task_address_space, task.Peb.ImageBaseAddress)
213
214
216 """Dump DLLs from a process address space"""
217
218 __name = "dlldump"
219
220 __args = [
221 dict(name="regex", default=".", type="RegEx",
222 help="A Regular expression for selecting the dlls to dump.")
223 ]
224
225 table_header = [
226 dict(name="_EPROCESS"),
227 dict(name="base", style="address"),
228 dict(name="module", width=20),
229 dict(name="filename")
230 ]
231
233 for task in self.filter_processes():
234 task_as = task.get_process_address_space()
235
236
237 for module in task.get_load_modules():
238 process_offset = task_as.vtop(task.obj_offset)
239 if process_offset:
240
241
242 if not self.plugin_args.regex.search(
243 utils.SmartUnicode(module.BaseDllName)):
244 continue
245
246 base_name = os.path.basename(
247 utils.SmartUnicode(module.BaseDllName))
248
249 dump_file = "module.{0}.{1:x}.{2:x}.{3}".format(
250 task.UniqueProcessId, process_offset, module.DllBase,
251 utils.EscapeForFilesystem(base_name))
252
253 yield dict(_EPROCESS=task,
254 base=module.DllBase,
255 module=module.BaseDllName,
256 filename=dump_file)
257
258
259 with self.session.GetRenderer().open(
260 filename=dump_file,
261 directory=self.dump_dir,
262 mode="wb") as fd:
263 self.pedump.WritePEFile(fd, task_as, module.DllBase)
264
265 else:
266 self.session.logging.error(
267 "Cannot dump %s@%s at %#x\n",
268 task.ImageFileName, module.BaseDllName,
269 int(module.DllBase))
270
271
315