Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Freebsd 8.4 support #678

Open
wants to merge 4 commits into
base: freebsd_support
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions tools/freebsd/module.c
Expand Up @@ -58,9 +58,13 @@ struct ps_strings vol_ps_strings;
struct freebsd32_ps_strings vol_freebsd32_ps_strings;
#endif

#if defined __freeBSD_kernel__ && __FreeBSD_version >= 1100040
struct fdescenttbl vol_fdescenttbl;
#endif
struct filedesc vol_filedesc;
#if defined __freeBSD_kernel__ && __FreeBSD_version >= 1000028
struct filedescent vol_filedescent;
#endif

struct file vol_file;

Expand Down
68 changes: 68 additions & 0 deletions volatility/plugins/freebsd/tcpconns.py
@@ -0,0 +1,68 @@
# Volatility
# Copyright (C) 2019 Volatility Foundation
#
# 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/>.
#

import volatility.obj as obj
import volatility.utils as utils
import volatility.plugins.freebsd.common as freebsd_common
from volatility.renderers import TreeGrid
from volatility.renderers.basic import Address
import socket

class freebsd_tcpconns(freebsd_common.AbstractFreebsdCommand):
"""List TCP connections"""

def __init__(self, config, *args, **kwargs):
freebsd_common.AbstractFreebsdCommand.__init__(self, config, *args, **kwargs)

def calculate(self):
freebsd_common.set_plugin_members(self)


tcbinfo_addr = self.addr_space.profile.get_symbol('tcbinfo')
if not tcbinfo_addr:
raise RuntimeError("Unsupported version: don't know where to find the list of connections")

info = obj.Object('inpcbinfo', offset = tcbinfo_addr, vm = self.addr_space)
c = info.ipi_listhead.dereference().lh_first.dereference().cast("inpcb")
while c.v():
endpoints = c.inp_inc.inc_ie
local_ip = endpoints.ie_dependladdr.ie46_local.ia46_addr4.s_addr
remote_ip = endpoints.ie_dependfaddr.ie46_foreign.ia46_addr4.s_addr
local_port = endpoints.ie_lport
remote_port = endpoints.ie_fport

# TCP state should be accessible through c.inp_ppcb.cast("tcpcb").t_state
# but the module.c did not include its definition so we
# don't know how to access it

c = c.inp_list.le_next
yield (local_ip, remote_ip, socket.htons(local_port), socket.htons(remote_port))

def unified_output(self, data):
return TreeGrid([
('Local IP', str),
('Remote IP', str),
('Local port', int),
('Remote port', int),

], self.generator(data))

def generator(self, data):
for (lip, rip, lp, rp) in data:
yield (0, [str(lip), str(rip), int(lp), int(rp)])
45 changes: 37 additions & 8 deletions volatility/plugins/overlays/freebsd/freebsd.py
Expand Up @@ -26,6 +26,7 @@
import zipfile

import volatility.debug as debug
import volatility.exceptions as exceptions
import volatility.dwarf as dwarf
import volatility.obj as obj
import volatility.plugins as plugins
Expand All @@ -43,9 +44,6 @@
'IA32ValidAS' : [ 0x0, ['VolatilityFreebsdValidAS']],
'AMD64ValidAS' : [ 0x0, ['VolatilityFreebsdValidAS']],
}],
'cdev' : [ None, {
'si_name' : [ None, ['String', dict(length = 256)]],
}],
'domain' : [ None, {
'dom_family' : [ None, ['Enumeration', dict(target = 'int', choices = {
1: 'AF_UNIX',
Expand Down Expand Up @@ -317,11 +315,16 @@ def get_process_address_space(self):
process_as = self.obj_vm.__class__(self.obj_vm.base, self.obj_vm.get_config(), dtb = self.obj_vm.vtop(self.p_vmspace.vm_pmap.pm_pdpt), skip_as_check = True)
elif self.obj_vm.profile.metadata.get('arch', 'x86') == 'x86':
process_as = self.obj_vm.__class__(self.obj_vm.base, self.obj_vm.get_config(), dtb = self.obj_vm.vtop(self.p_vmspace.vm_pmap.pm_pdir), skip_as_check = True)
elif self.obj_vm.profile.metadata.get('arch', 'x86') == 'x64':
# Around 9.3 precomputed cr3 became part of the structure
elif self.obj_vm.profile.metadata.get('arch', 'x86') == 'x64' and hasattr(self.p_vmspace.vm_pmap, "pm_cr3"):
if self.p_vmspace.vm_pmap.pm_ucr3 != 0xffffffffffffffffL:
process_as = self.obj_vm.__class__(self.obj_vm.base, self.obj_vm.get_config(), dtb = self.p_vmspace.vm_pmap.pm_ucr3, skip_as_check = True)
else:
process_as = self.obj_vm.__class__(self.obj_vm.base, self.obj_vm.get_config(), dtb = self.p_vmspace.vm_pmap.pm_cr3, skip_as_check = True)
elif self.obj_vm.profile.metadata.get('arch', 'x86') == 'x64' and hasattr(self.p_vmspace.vm_pmap, "pm_pml4"):
process_as = self.obj_vm.__class__(self.obj_vm.base, self.obj_vm.get_config(), dtb = self.obj_vm.vtop(self.p_vmspace.vm_pmap.pm_pml4), skip_as_check = True)
else:
raise RuntimeError('Unknown pmap structure')

process_as.name = 'Process {0}'.format(self.p_pid)

Expand Down Expand Up @@ -377,11 +380,23 @@ def get_commandline(self):

def lsof(self):
if self.p_fd.fd_lastfile != -1:
files = obj.Object('Array', offset = self.p_fd.fd_files.fdt_ofiles.obj_offset, vm = self.obj_vm, targetType = 'filedescent', count = self.p_fd.fd_lastfile + 1)
for n, f in enumerate(files):
if f.fde_file.v():
yield f.fde_file, n
# This is the most recent version with a separate table struct for filedescent structs
if hasattr(self.p_fd, "fd_files"):
filedescents = obj.Object('Array', offset = self.p_fd.fd_files.fdt_ofiles.obj_offset, vm = self.obj_vm, targetType = 'filedescent', count = self.p_fd.fd_lastfile + 1)
files = (i.fde_file for i in filedescents)
# In 8.4.0, type of fd_ofiles is `struct file **`
elif hasattr(self.p_fd, "fd_ofiles") \
and isinstance(self.p_fd.fd_ofiles, obj.Pointer) \
and isinstance(self.p_fd.fd_ofiles.dereference(), obj.Pointer) \
and self.p_fd.fd_ofiles.dereference().dereference().obj_type == "file":
fileptrs = obj.Object('Array', offset = self.p_fd.fd_ofiles, vm = self.obj_vm, targetType = 'Pointer', count = self.p_fd.fd_lastfile + 1)
files = (i.dereference_as("file") for i in fileptrs)
else:
raise RuntimeError("Unknown filedesc structure")

for n, f in enumerate(files):
if f:
yield f, n

class vm_map_entry(obj.CType):
def get_perms(self):
Expand Down Expand Up @@ -530,6 +545,19 @@ class FreebsdOverlay(obj.ProfileModification):
def modification(self, profile):
profile.merge_overlay(freebsd_overlay)

class cdev(obj.CType):

@property
def si_name(self):
orig = self.m("si_name")
# in versions before 9.1.0, this member is a char pointer
if isinstance(orig, obj.Pointer):
return obj.Object("String", offset=orig.v(), vm=self.obj_vm, length=64)
# after that the indirection was removed and the statically allocated
# array is used directly
else:
return obj.Object("String", offset=orig.obj_offset, vm=self.obj_vm, length=64)


class FreebsdObjectClasses(obj.ProfileModification):
conditions = {'os': lambda x: x == 'freebsd'}
Expand All @@ -544,4 +572,5 @@ def modification(self, profile):
'proc': proc,
'vm_map_entry': vm_map_entry,
'vnode': vnode,
'cdev': cdev,
})