1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 from rekall import obj
21 from rekall import testlib
22 from rekall.plugins import core
23 from rekall.plugins.windows import common
24
25
26
27
28 -class Malfind(core.DirectoryDumperMixin, common.WinProcessFilter):
29 "Find hidden and injected code"
30
31 __name = "malfind"
32
33 dump_dir_optional = True
34 default_dump_dir = None
35
37 """
38 Check if a VAD region is either entirely unavailable
39 due to paging, entirely consiting of zeros, or a
40 combination of the two. This helps ignore false positives
41 whose VAD flags match task._injection_filter requirements
42 but there's no data and thus not worth reporting it.
43
44 @param vad: an MMVAD object in kernel AS
45 @param address_space: the process address space
46 """
47
48 PAGE_SIZE = 0x1000
49 all_zero_page = "\x00" * PAGE_SIZE
50
51 offset = 0
52 while offset < vad.Length:
53 next_addr = vad.Start + offset
54 if (address_space.is_valid_address(next_addr) and
55 address_space.read(next_addr, PAGE_SIZE) != all_zero_page):
56 return False
57 offset += PAGE_SIZE
58
59 return True
60
62 """Detects injected vad regions.
63
64 This looks for private allocations that are committed,
65 memory-resident, non-empty (not all zeros) and with an
66 original protection that includes write and execute.
67
68 It is important to note that protections are applied at
69 the allocation granularity (page level). Thus the original
70 protection might not be the current protection, and it
71 also might not apply to all pages in the VAD range.
72
73 @param vad: an MMVAD object.
74
75 @returns: True if the MMVAD looks like it might
76 contain injected code.
77 """
78
79 protect = str(vad.u.VadFlags.ProtectionEnum)
80 write_exec = "EXECUTE" in protect and "WRITE" in protect
81
82
83 if not write_exec:
84 return False
85
86
87 if ((vad.u.VadFlags.PrivateMemory == 1 and
88 vad.Tag == "VadS") or
89
90
91 (vad.u.VadFlags.PrivateMemory == 0 and
92 protect != "EXECUTE_WRITECOPY")):
93 return not self._is_vad_empty(vad, task_as)
94
95 return False
96
98 cc = self.session.plugins.cc()
99 for task in self.filter_processes():
100 task_as = task.get_process_address_space()
101 if not task_as:
102 continue
103
104 with cc:
105 cc.SwitchProcessContext(task)
106 for vad in task.RealVadRoot.traverse():
107 self.session.report_progress("Checking %r of pid %s",
108 vad, task.UniqueProcessId)
109
110 if self._injection_filter(vad, task_as):
111 renderer.section()
112 renderer.format(
113 "Process: {0} Pid: {1} Address: {2:#x}\n",
114 task.ImageFileName, task.UniqueProcessId, vad.Start)
115
116 renderer.format("Vad Tag: {0} Protection: {1}\n",
117 vad.Tag, vad.u.VadFlags.ProtectionEnum)
118
119 renderer.format("Flags: {0}\n", vad.u.VadFlags)
120 renderer.format("\n")
121
122 dumper = self.session.plugins.dump(
123 offset=vad.Start, rows=4)
124 dumper.render(renderer, suppress_headers=True)
125
126 renderer.format("\n")
127
128 disassembler = self.session.plugins.dis(
129 offset=vad.Start, length=0x40)
130 disassembler.render(renderer, suppress_headers=True)
131
132 if self.dump_dir:
133 filename = "{0}.{1:d}.{2:08x}-{3:08x}.dmp".format(
134 task.ImageFileName, task.pid, vad.Start,
135 vad.End)
136
137 with renderer.open(directory=self.dump_dir,
138 filename=filename,
139 mode='wb') as fd:
140 self.session.report_progress(
141 "Dumping %s" % filename)
142
143 self.CopyToFile(task_as, vad.Start, vad.End, fd)
144
145
147 "Detect unlinked DLLs"
148
149 __name = "ldrmodules"
150
151 table_header = [
152 dict(name="divider", type="Divider"),
153 dict(name="_EPROCESS", hidden=True),
154 dict(name="base", style="address"),
155 dict(name="in_load", width=5),
156 dict(name="in_load_path", width=80, hidden=True),
157 dict(name="in_init", width=5),
158 dict(name="in_init_path", width=80, hidden=True),
159 dict(name="in_mem", width=5),
160 dict(name="in_mem_path", width=80, hidden=True),
161 dict(name="mapped")
162 ]
163
165 return dict(
166 _EPROCESS=self.session.profile._EPROCESS(),
167 base_address=0,
168 in_load=False,
169 in_load_path=self.session.profile._UNICODE_STRING(),
170 in_init=False,
171 in_init_path=self.session.profile._UNICODE_STRING(),
172 in_mem=False,
173 in_mem_path=self.session.profile._UNICODE_STRING(),
174 mapped_filename=self.session.profile._UNICODE_STRING(),
175 )
176
178 """Iterates over all vads and returns executable regions.
179
180 Yields:
181 vad objects which are both executable and have a file name.
182 """
183 self.session.report_progress("Inspecting Pid %s",
184 task.UniqueProcessId)
185
186 for vad in task.RealVadRoot.traverse():
187 try:
188 file_obj = vad.ControlArea.FilePointer
189 protect = str(vad.u.VadFlags.ProtectionEnum)
190 if "EXECUTE" in protect and "WRITE" in protect:
191 yield vad, file_obj.FileName
192 except AttributeError:
193 pass
194
195
197 for task in self.filter_processes():
198
199
200 inloadorder = dict((mod.DllBase.v(), mod)
201 for mod in task.get_load_modules())
202
203 ininitorder = dict((mod.DllBase.v(), mod)
204 for mod in task.get_init_modules())
205
206 inmemorder = dict((mod.DllBase.v(), mod)
207 for mod in task.get_mem_modules())
208
209
210 mapped_files = dict((vad.Start, name)
211 for vad, name in self.list_mapped_files(task))
212
213 yield dict(divider=task)
214
215
216
217 for base in mapped_files.keys():
218 yield dict(_EPROCESS=task,
219 base=base,
220 in_load=base in inloadorder,
221 in_load_path=inloadorder.get(
222 base, obj.NoneObject()).FullDllName,
223 in_init=base in ininitorder,
224 in_init_path=ininitorder.get(
225 base, obj.NoneObject()).FullDllName,
226 in_mem=base in inmemorder,
227 in_mem_path=inmemorder.get(
228 base, obj.NoneObject()).FullDllName,
229 mapped=mapped_files[base])
230
231
236