1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 from rekall import obj
25 from rekall import scan
26 from rekall import plugin
27
28 from rekall.plugins.windows import common
29 from rekall_lib import utils
30
31
33 """Scans for _KDDEBUGGER_DATA64 structures.
34
35 Note that this does not rely on signatures, as validity of hits is
36 calculated through list reflection.
37 """
38 checks = [("StringCheck", dict(needle="KDBG"))]
39
40 - def scan(self, offset=0, maxlen=None):
76
77
78 -class KDBGScan(plugin.KernelASMixin, common.AbstractWindowsCommandPlugin):
79 """Scan for possible _KDDEBUGGER_DATA64 structures.
80
81 The scanner is detailed here:
82 http://moyix.blogspot.com/2008/04/finding-kernel-global-variables-in.html
83
84 The relevant structures are detailed here:
85 http://doxygen.reactos.org/d3/ddf/include_2psdk_2wdbgexts_8h_source.html
86
87 We can see that _KDDEBUGGER_DATA64.Header is:
88
89 typedef struct _DBGKD_DEBUG_DATA_HEADER64 {
90 LIST_ENTRY64 List;
91 ULONG OwnerTag;
92 ULONG Size;
93 }
94
95 We essentially search for an owner tag of "KDBG", then overlay the
96 _KDDEBUGGER_DATA64 struct on it. We test for validity by reflecting
97 through the Header.List member.
98 """
99
100 __name = "kdbgscan"
101
102 __args = [
103 dict(name="full_scan", type="Boolean",
104 help="Scan the full address space.")
105 ]
106
129
130 table_header = [
131 dict(name="Key", width=50),
132 dict(name="Value")
133 ]
134
135 table_options = dict(
136 suppress_headers=True
137 )
138
140 """Renders the KPCR values as text"""
141
142 for kdbg in self.hits():
143 yield "Offset (V)", utils.HexInteger(kdbg.obj_offset)
144 yield "Offset (P)", utils.HexInteger(kdbg.obj_vm.vtop(
145 kdbg.obj_offset))
146
147
148
149 yield "KDBG owner tag check", kdbg.is_valid()
150
151 verinfo = kdbg.dbgkd_version64()
152 if verinfo:
153 yield "Version64", "{0:#x} (Major: {1}, Minor: {2})\n".format(
154 verinfo.obj_offset, verinfo.MajorVersion,
155 verinfo.MinorVersion)
156
157 yield "Service Pack (CmNtCSDVersion)", kdbg.ServicePack
158 yield "Build string (NtBuildLab)", kdbg.NtBuildLab.dereference()
159
160
161 try:
162
163 pslist = kdbg.PsActiveProcessHead.list_of_type(
164 "_EPROCESS", "ActiveProcessLinks")
165 num_tasks = len([x for x in pslist if x.pid > 0])
166 except AttributeError:
167 num_tasks = 0
168
169 try:
170 modules = self.session.plugins.modules(session=self.session)
171 num_modules = len(list(modules.lsmod()))
172 except AttributeError:
173 num_modules = 0
174
175 yield "PsActiveProcessHead", "{0:#x} ({1} processes)".format(
176 kdbg.PsActiveProcessHead, num_tasks)
177
178 yield "PsLoadedModuleList", "{0:#x} ({1} modules)".format(
179 kdbg.PsLoadedModuleList, num_modules)
180
181 yield "KernelBase", "{0:#x} (Matches MZ: {1})".format(
182 kdbg.KernBase, kdbg.obj_vm.read(kdbg.KernBase, 2) == "MZ")
183
184
185 pe_profile = self.session.LoadProfile("pe")
186
187 dos_header = pe_profile._IMAGE_DOS_HEADER(
188 offset=kdbg.KernBase, vm=kdbg.obj_vm)
189 nt_header = dos_header.NTHeader
190 if nt_header:
191 yield ("Major (OptionalHeader)",
192 nt_header.OptionalHeader.MajorOperatingSystemVersion)
193
194 yield("Minor (OptionalHeader)",
195 nt_header.OptionalHeader.MinorOperatingSystemVersion)
196
197
198 for kpcr in kdbg.kpcrs():
199 yield "KPCR", "{0:#x} (CPU {1})".format(
200 kpcr.obj_offset, kpcr.ProcessorBlock.Number)
201