mirror of
https://github.com/volatilityfoundation/volatility
synced 2026-06-08 18:04:46 +00:00
206 lines
6.8 KiB
Python
206 lines
6.8 KiB
Python
# Volatility
|
|
#
|
|
# This file is part of Volatility.
|
|
#
|
|
# Volatility is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# Volatility is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with Volatility. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
|
|
"""
|
|
@author: Joe Sylve
|
|
@license: GNU General Public License 2.0
|
|
@contact: joe.sylve@gmail.com
|
|
@organization: Digital Forensics Solutions
|
|
"""
|
|
|
|
import volatility.obj as obj
|
|
import volatility.debug as debug
|
|
import volatility.plugins.linux.common as linux_common
|
|
|
|
class kmem_cache(obj.CType):
|
|
def get_type(self):
|
|
raise NotImplementedError
|
|
|
|
def get_name(self):
|
|
return str(self.name.dereference_as("String", length = 255))
|
|
|
|
class kmem_cache_slab(kmem_cache):
|
|
def get_type(self):
|
|
return "slab"
|
|
|
|
# volatility does not support indexing pointers
|
|
# and the definition of nodelists changes from array to pointer
|
|
def _get_nodelist(self):
|
|
ent = self.nodelists
|
|
|
|
if type(ent) == obj.Pointer:
|
|
ret = obj.Object("kmem_list3", offset = ent.dereference(), vm = self.obj_vm)
|
|
|
|
elif type(ent) == obj.Array:
|
|
ret = ent[0]
|
|
else:
|
|
debug.error("Unknown nodelists types. %s" % type(ent))
|
|
|
|
return ret
|
|
|
|
def _get_free_list(self):
|
|
|
|
slablist = self._get_nodelist().slabs_free
|
|
|
|
for slab in slablist.list_of_type("slab", "list"):
|
|
yield slab
|
|
|
|
def _get_partial_list(self):
|
|
slablist = self._get_nodelist().slabs_partial
|
|
|
|
for slab in slablist.list_of_type("slab", "list"):
|
|
yield slab
|
|
|
|
def _get_full_list(self):
|
|
slablist = self._get_nodelist().slabs_full
|
|
|
|
for slab in slablist.list_of_type("slab", "list"):
|
|
yield slab
|
|
|
|
def _get_object(self, offset):
|
|
return obj.Object(self.struct_type,
|
|
offset = offset,
|
|
vm = self.obj_vm,
|
|
parent = self.obj_parent,
|
|
name = self.struct_type)
|
|
def __iter__(self):
|
|
|
|
if not self.unalloc:
|
|
for slab in self._get_full_list():
|
|
for i in range(self.num):
|
|
yield self._get_object(slab.s_mem.v() + i * self.buffer_size)
|
|
|
|
for slab in self._get_partial_list():
|
|
if not self.num or self.num == 0:
|
|
return
|
|
|
|
bufctl = obj.Object("Array",
|
|
offset = slab.v() + slab.size(),
|
|
vm = self.obj_vm,
|
|
parent = self.obj_parent,
|
|
targetType = "unsigned int",
|
|
count = self.num)
|
|
|
|
unallocated = [0] * self.num
|
|
|
|
i = slab.free
|
|
while i != 0xFFFFFFFF:
|
|
if i >= self.num:
|
|
break
|
|
unallocated[i] = 1
|
|
i = bufctl[i]
|
|
|
|
for i in range(0, self.num):
|
|
if unallocated[i] == self.unalloc:
|
|
yield self._get_object(slab.s_mem.v() + i * self.buffer_size)
|
|
|
|
if self.unalloc:
|
|
for slab in self._get_free_list():
|
|
for i in range(self.num):
|
|
yield self._get_object(slab.s_mem.v() + i * self.buffer_size)
|
|
|
|
class LinuxKmemCacheOverlay(obj.ProfileModification):
|
|
conditions = {'os': lambda x: x == 'linux'}
|
|
before = ['BasicObjectClasses'] # , 'LinuxVTypes']
|
|
|
|
def modification(self, profile):
|
|
|
|
if profile.get_symbol("cache_chain"):
|
|
profile.object_classes.update({'kmem_cache': kmem_cache_slab})
|
|
|
|
class linux_slabinfo(linux_common.AbstractLinuxCommand):
|
|
"""Mimics /proc/slabinfo on a running machine"""
|
|
|
|
def get_all_kmem_caches(self):
|
|
linux_common.set_plugin_members(self)
|
|
cache_chain = self.addr_space.profile.get_symbol("cache_chain")
|
|
slab_caches = self.addr_space.profile.get_symbol("slab_caches")
|
|
|
|
if cache_chain: #slab
|
|
caches = obj.Object("list_head", offset = cache_chain, vm = self.addr_space)
|
|
listm = "next"
|
|
ret = [cache for cache in caches.list_of_type("kmem_cache", listm)]
|
|
elif slab_caches: #slub
|
|
debug.info("SLUB is currently unsupported.")
|
|
ret = []
|
|
else:
|
|
debug.error("Unknown or unimplemented slab type.")
|
|
|
|
return ret
|
|
|
|
def get_kmem_cache(self, cache_name, unalloc, struct_name = ""):
|
|
|
|
if struct_name == "":
|
|
struct_name = cache_name
|
|
|
|
for cache in self.get_all_kmem_caches():
|
|
if cache.get_name() == cache_name:
|
|
cache.newattr("unalloc", unalloc)
|
|
cache.newattr("struct_type", struct_name)
|
|
return cache
|
|
|
|
debug.debug("Invalid kmem_cache: {0}".format(cache_name))
|
|
return []
|
|
|
|
def calculate(self):
|
|
linux_common.set_plugin_members(self)
|
|
|
|
for cache in self.get_all_kmem_caches():
|
|
if cache.get_type() == "slab":
|
|
active_objs = 0
|
|
active_slabs = 0
|
|
num_slabs = 0
|
|
# shared_avail = 0
|
|
|
|
for slab in cache._get_full_list():
|
|
active_objs += cache.num
|
|
active_slabs += 1
|
|
|
|
for slab in cache._get_partial_list():
|
|
active_objs += slab.inuse
|
|
active_slabs += 1
|
|
|
|
for slab in cache._get_free_list():
|
|
num_slabs += 1
|
|
|
|
num_slabs += active_slabs
|
|
num_objs = num_slabs * cache.num
|
|
|
|
yield [cache.get_name(),
|
|
active_objs,
|
|
num_objs,
|
|
cache.buffer_size,
|
|
cache.num,
|
|
1 << cache.gfporder,
|
|
active_slabs,
|
|
num_slabs]
|
|
|
|
def render_text(self, outfd, data):
|
|
self.table_header(outfd, [("<name>", "<30"),
|
|
("<active_objs>", "<13"),
|
|
("<num_objs>", "<10"),
|
|
("<objsize>", "<10"),
|
|
("<objperslab>", "<12"),
|
|
("<pagesperslab>", "<15"),
|
|
("<active_slabs>", "<14"),
|
|
("<num_slabs>", "<7"),
|
|
])
|
|
|
|
for info in data:
|
|
self.table_row(outfd, info[0], info[1], info[2], info[3], info[4], info[5], info[6], info[7])
|