From 53e131831d2ec95b2018919a2d21e3254b946b35 Mon Sep 17 00:00:00 2001 From: hakril Date: Tue, 29 Mar 2016 23:41:54 +0200 Subject: [PATCH] Writing / updating some doc --- TODO | 28 +++++---- doc/source/network.rst | 16 +++-- doc/source/process.rst | 2 +- doc/source/registry.rst | 2 +- doc/source/various.rst | 1 + doc/source/windows.rst | 18 ++---- windows/winobject/network.py | 101 ++++++++++++++++++++++++++++++-- windows/winobject/service.py | 46 ++++++++++++++- windows/winobject/system.py | 109 +++++++++++++++++++++++++---------- windows/winobject/wmi.py | 2 +- 10 files changed, 256 insertions(+), 69 deletions(-) diff --git a/TODO b/TODO index d51397f..ace0b59 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,7 @@ TODO: - Documentation + - Pass 0.2 when doc is done <3 - ProcessMemory object ? (metasm like) - - Extend Registry feature (write) - remove pe_parse.transform_ctypes_fields (use utils.transform_ctypes_fields) - DBG @@ -10,7 +10,6 @@ TODO: - Test !! (bp, BP_HX, bp on only on process, bp_hx on only one thread..) - test breakpoint with specific target - - Threading - Quid IAT hook stub ? just einit threads and remove this ? @@ -25,36 +24,41 @@ TODO: - rethink OptionalExport ? not useful with lazy resolution (or we need to force resolution..) - Readme - - Debugger ? Veh ? - TransparentApiProxy - double name (params and args) for same info.. - 32 <-> 64 - * What about ``NtWow64QueryVirtualMemory64`` ? - Parse .IDL file for more COM NAME->IID CHANGELOG: - * NEW REGISTRY -> change examples and documentation * WinProcess is not a PROCESSENTRY32 anymore (change doc) -FIXME: - - WMI - - COM initialisation when injected in another process - - The CoInitialize might be already called - - Fix that +Documentation + * Debugger + * LocalDebugger + * volumes + * system.version stuff + * windows.com + * windows.wintrust + * New stuff in exception ? + * system.firewall.network + * system.services + * New stuff in WMI ?(think not just change in internal) + * windows.utils + * verif samples + +FIXME: - setup.py build seems to raise an error - winutils.create_process : use WinProcess._from_handle - Push("[ECX]") in simple_x64 as a "H" rex and i think it should not.. RESSOURCE - * read http://www.codeproject.com/Articles/18975/Listing-Used-Files \ No newline at end of file diff --git a/doc/source/network.rst b/doc/source/network.rst index a9ca9c5..2e64fd3 100644 --- a/doc/source/network.rst +++ b/doc/source/network.rst @@ -1,19 +1,27 @@ Network ======= -.. module:: windows.network +.. module:: windows.winobject.network .. note:: See sample :ref:`sample_network_exploration` -.. autoclass:: windows.network.Network +.. autoclass:: Network Connections """"""""""" -.. autoclass:: windows.network.TCP4Connection +.. autoclass:: TCP4Connection -.. autoclass:: windows.network.TCP6Connection \ No newline at end of file +.. autoclass:: TCP6Connection + +Firewall +"""""""" + +.. autoclass:: Firewall + + +.. autoclass:: FirewallRule \ No newline at end of file diff --git a/doc/source/process.rst b/doc/source/process.rst index d9f732c..fd0f77b 100644 --- a/doc/source/process.rst +++ b/doc/source/process.rst @@ -1,7 +1,7 @@ Processes and Threads """"""""""""""""""""" -.. module:: windows.winobject +.. module:: windows.winobject.process CurrentProcess '''''''''''''' diff --git a/doc/source/registry.rst b/doc/source/registry.rst index 62d7ffa..9660357 100644 --- a/doc/source/registry.rst +++ b/doc/source/registry.rst @@ -1,7 +1,7 @@ Registry ======== -.. module:: windows.registry +.. module:: windows.winobject.registry .. note:: diff --git a/doc/source/various.rst b/doc/source/various.rst index 78abdd3..f60226c 100644 --- a/doc/source/various.rst +++ b/doc/source/various.rst @@ -13,4 +13,5 @@ This sections describes them by group of relation. exception.rst registry.rst network.rst + service.rst com.rst \ No newline at end of file diff --git a/doc/source/windows.rst b/doc/source/windows.rst index fdd29e7..127ae5f 100644 --- a/doc/source/windows.rst +++ b/doc/source/windows.rst @@ -7,14 +7,15 @@ This module exports some objects representing the current state of the system. It also offers some submodules aimed to help the interfacing with ``Windows`` and native code execution. The defaults objects accessible in ``windows`` are: - * ``system`` of type :class:`windows.winobject.System` - * ``current_process`` of type :class:`windows.winobject.CurrentProcess` - * ``current_thread`` of type :class:`windows.winobject.CurrentThread` + * ``system`` of type :class:`windows.winobject.system.System` + * ``current_process`` of type :class:`windows.winobject.process.CurrentProcess` + * ``current_thread`` of type :class:`windows.winobject.process.CurrentThread` The submodules that you might use by themself are: * :mod:`windows.native_exec` * :mod:`windows.winproxy` * :mod:`windows.utils` + * :mod:`windows.com` .. _object_system: @@ -23,15 +24,6 @@ The ``system`` object .. currentmodule:: windows.winobject -.. autoclass:: windows.winobject.System +.. autoclass:: windows.winobject.system.System :no-show-inheritance: - .. autoattribute:: windows.winobject.System.registry - :annotation: - - Object of class :class:`windows.registry.Registry` - - .. autoattribute:: windows.winobject.System.network - :annotation: - - Object of class :class:`windows.network.Network` \ No newline at end of file diff --git a/windows/winobject/network.py b/windows/winobject/network.py index 26c4849..71dc77f 100644 --- a/windows/winobject/network.py +++ b/windows/winobject/network.py @@ -11,7 +11,7 @@ from windows.generated_def.windef import * class TCP4Connection(MIB_TCPROW_OWNER_PID): - + """A TCP4 socket (connected or listening)""" @property def established(self): """``True`` if connection is established else it's a listening socket""" @@ -87,6 +87,7 @@ class TCP4Connection(MIB_TCPROW_OWNER_PID): class TCP6Connection(MIB_TCP6ROW_OWNER_PID): + """A TCP6 socket (connected or listening)""" @staticmethod def _str_ipv6_addr(addr): return ":".join(c.encode('hex') for c in addr) @@ -170,8 +171,13 @@ def get_MIB_TCP6TABLE_OWNER_PID_from_buffer(buffer): return _GENERATED_MIB_TCP6TABLE_OWNER_PID.from_buffer(buffer) class Firewall(cominterfaces.INetFwPolicy2): + """The windows firewall""" @property def rules(self): + """The rules of the firewall + + :type: [:class:`FirewallRule`] -- A list of rule + """ ifw_rules = cominterfaces.INetFwRules() self.get_Rules(ifw_rules) @@ -200,102 +206,183 @@ class Firewall(cominterfaces.INetFwPolicy2): @property def current_profile_types(self): + """Mask of the profiles currently enabled + + :type: :class:`long` + """ cpt = gdef.LONG() self.get_CurrentProfileTypes(cpt) return cpt.value + @property + def enabled(self): + """A maping of the active firewall profiles + + { + + ``NET_FW_PROFILE_TYPE2_.NET_FW_PROFILE2_DOMAIN(0x1L)``: ``True`` or ``False``, + + ``NET_FW_PROFILE_TYPE2_.NET_FW_PROFILE2_PRIVATE(0x2L)``: ``True`` or ``False``, + + ``NET_FW_PROFILE_TYPE2_.NET_FW_PROFILE2_PUBLIC(0x4L)``: ``True`` or ``False``, + + } + + + :type: :class:`dict` + """ + profiles = [gdef.NET_FW_PROFILE2_DOMAIN, gdef.NET_FW_PROFILE2_PRIVATE, gdef.NET_FW_PROFILE2_PUBLIC] + return {prof: self.enabled_for_profile_type(prof) for prof in profiles} + + def enabled_for_profile_type(self, profile_type): enabled = gdef.VARIANT_BOOL() self.get_FirewallEnabled(profile_type, enabled) return enabled.value - @property - def enabled(self): - profiles = [gdef.NET_FW_PROFILE2_DOMAIN, gdef.NET_FW_PROFILE2_PRIVATE, gdef.NET_FW_PROFILE2_PUBLIC] - return {prof: self.enabled_for_profile_type(prof) for prof in profiles} class FirewallRule(cominterfaces.INetFwRule): + """A rule of the firewall""" @property def name(self): + """Name of the rule + + :type: :class:`unicode` + """ name = gdef.BSTR() self.get_Name(name) return name.value @property def description(self): + """Description of the rule + + :type: :class:`unicode` + """ description = gdef.BSTR() self.get_Description(description) return description.value @property def application_name(self): + """Name of the application to which apply the rule + + :type: :class:`unicode` + """ applicationname = gdef.BSTR() self.get_ApplicationName(applicationname) return applicationname.value @property def service_name(self): + """Name of the service to which apply the rule + + :type: :class:`unicode` + """ servicename = gdef.BSTR() self.get_ServiceName(servicename) return servicename.value @property def protocol(self): + """Protocol to which apply the rule + + :type: :class:`long` + """ protocol = gdef.LONG() self.get_Protocol(protocol) return protocol.value @property def local_address(self): + """Local address of the rule + + :type: :class:`unicode` + """ local_address = gdef.BSTR() self.get_LocalAddresses(local_address) return local_address.value @property def remote_address(self): + """Remote address of the rule + + :type: :class:`unicode` + """ remote_address = gdef.BSTR() self.get_RemoteAddresses(remote_address) return remote_address.value @property def direction(self): + """Direction of the rule, values might be: + + * ``NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN(0x1L)`` + * ``NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_OUT(0x2L)`` + + subclass of :class:`long` + """ direction = gdef.NET_FW_RULE_DIRECTION() self.get_Direction(direction) return direction.value @property def interface_types(self): + """Types of interface of the rule + + :type: :class:`unicode` + """ interface_type = gdef.BSTR() self.get_InterfaceTypes(interface_type) return interface_type.value @property def local_port(self): + """Local port of the rule + + :type: :class:`unicode` + """ local_port = gdef.BSTR() self.get_LocalPorts(local_port) return local_port.value @property def remote_port(self): + """Remote port of the rule + + :type: :class:`unicode` + """ remote_port = gdef.BSTR() self.get_RemotePorts(remote_port) return remote_port.value @property def action(self): + """Action of the rule, values might be: + + * ``NET_FW_ACTION_.NET_FW_ACTION_BLOCK(0x0L)`` + * ``NET_FW_ACTION_.NET_FW_ACTION_ALLOW(0x1L)`` + + subclass of :class:`long` + """ action = gdef.NET_FW_ACTION() self.get_Action(action) return action.value @property def enabled(self): + """``True`` if rule is enabled""" enabled = gdef.VARIANT_BOOL() self.get_Enabled(enabled) return enabled.value @property def grouping(self): + """Grouping of the rule + + :type: :class:`unicode` + """ grouping = gdef.BSTR() self.get_RemotePorts(grouping) return grouping.value @@ -314,6 +401,10 @@ class Network(object): @property def firewall(self): + """The firewall of the system + + :type: :class:`Firewall` + """ windows.com.init() firewall = Firewall() windows.com.create_instance(self.NetFwPolicy2, firewall) diff --git a/windows/winobject/service.py b/windows/winobject/service.py index fac5a1a..f54d1f5 100644 --- a/windows/winobject/service.py +++ b/windows/winobject/service.py @@ -13,7 +13,32 @@ SERVICE_CONTROLE_ACCEPTED = {x:x for x in []} SERVICE_FLAGS = {x:x for x in [SERVICE_RUNS_IN_SYSTEM_PROCESS]} -service_status = namedtuple("ServiceStatus", ["type", "state", "control_accepted", "flags"]) +ServiceStatus = namedtuple("ServiceStatus", ["type", "state", "control_accepted", "flags"]) +""" +``type`` might be one of: + + * ``SERVICE_KERNEL_DRIVER(0x1L)`` + * ``SERVICE_FILE_SYSTEM_DRIVER(0x2L)`` + * ``SERVICE_WIN32_OWN_PROCESS(0x10L)`` + * ``SERVICE_WIN32_SHARE_PROCESS(0x20L)`` + * ``SERVICE_INTERACTIVE_PROCESS(0x100L)`` + +``state`` might be on of: + + * ``SERVICE_STOPPED(0x1L)`` + * ``SERVICE_START_PENDING(0x2L)`` + * ``SERVICE_STOP_PENDING(0x3L)`` + * ``SERVICE_RUNNING(0x4L)`` + * ``SERVICE_CONTINUE_PENDING(0x5L)`` + * ``SERVICE_PAUSE_PENDING(0x6L)`` + * ``SERVICE_PAUSED(0x7L)`` + +``flags`` might be one of: + + * ``0`` + * ``SERVICE_RUNS_IN_SYSTEM_PROCESS(0x1L)`` + +""" class Service(object): def __repr__(self): @@ -21,23 +46,39 @@ class Service(object): @utils.fixedpropety def name(self): + """The name of the service + + :type: :class:`str` + """ return self.lpServiceName @utils.fixedpropety def description(self): + """The description of the service + + :type: :class:`str` + """ return self.lpDisplayName @utils.fixedpropety def status(self): + """The status of the service + + :type: :class:`ServiceStatus` + """ status = self.ServiceStatusProcess stype = SERVICE_TYPE.get(status.dwServiceType, status.dwServiceType) sstate = SERVICE_STATE.get(status.dwCurrentState, status.dwCurrentState) scontrol = status.dwControlsAccepted sflags = SERVICE_FLAGS.get(status.dwServiceFlags, status.dwServiceFlags) - return service_status(stype, sstate, scontrol, sflags) + return ServiceStatus(stype, sstate, scontrol, sflags) @utils.fixedpropety def process(self): + """The process running the service (if any) + + :type: :class:`WinProcess ` or ``None`` + """ pid = self.ServiceStatusProcess.dwProcessId if not pid: return None @@ -48,6 +89,7 @@ class Service(object): class ServiceA(Service, ENUM_SERVICE_STATUS_PROCESSA): + """A Service object with ascii data""" pass def enumerate_services(): diff --git a/windows/winobject/system.py b/windows/winobject/system.py index 0b238b9..8b9eeab 100644 --- a/windows/winobject/system.py +++ b/windows/winobject/system.py @@ -21,14 +21,16 @@ from windows.generated_def.winstructs import * class System(object): """Represent the current ``Windows`` system ``Python`` is running on""" - network = network.Network() # Object of class :class:`windows.network.Network` - registry = registry.Registry() # Object of class :class:`windows.registry.Registry` + network = network.Network() + """Object of class :class:`windows.winobject.network.Network`""" + registry = registry.Registry() + """Object of class :class:`windows.winobject.registry.Registry`""" @property def processes(self): """The list of running processes - :type: [:class:`WinProcess`] -- A list of Process + :type: [:class:`process.WinProcess`] -- A list of Process """ return self.enumerate_processes() @@ -36,17 +38,23 @@ class System(object): def threads(self): """The list of running threads - :type: [:class:`WinThread`] -- A list of Thread + :type: [:class:`process.WinThread`] -- A list of Thread """ return self.enumerate_threads() @property def logicaldrives(self): + """List of logical drives [C:\, ...] + + :type: [:class:`volume.LogicalDrive`] -- A list of LogicalDrive + """ return volume.enum_logical_drive() @property def services(self): - """The list of services (TODO: BETTER DOC)""" + """The list of services + + :type: [:class:`service.ServiceA`] -- A list of Service""" return service.enumerate_services() #@property @@ -87,42 +95,29 @@ class System(object): @utils.fixedpropety def wmi(self): + r"""An object to perform wmi request to "root\\cimv2" + + :type: :class:`wmi.WmiRequester`""" return wmi.WmiRequester() #TODO: use GetComputerNameExA ? and recover other names ? @utils.fixedpropety def computer_name(self): + """The name of the computer + + :type: :class:`str` + """ size = DWORD(0x1000) buf = ctypes.c_buffer(size.value) winproxy.GetComputerNameA(buf, ctypes.byref(size)) return buf[:size.value] - @staticmethod - def enumerate_processes(): - process_entry = PROCESSENTRY32() - process_entry.dwSize = ctypes.sizeof(process_entry) - snap = winproxy.CreateToolhelp32Snapshot(windef.TH32CS_SNAPPROCESS, 0) - winproxy.Process32First(snap, process_entry) - res = [] - res.append(process.WinProcess._from_PROCESSENTRY32(process_entry)) - while winproxy.Process32Next(snap, process_entry): - res.append(process.WinProcess._from_PROCESSENTRY32(process_entry)) - return res - - @staticmethod - def enumerate_threads(): - thread_entry = process.WinThread() - thread_entry.dwSize = ctypes.sizeof(thread_entry) - snap = winproxy.CreateToolhelp32Snapshot(windef.TH32CS_SNAPTHREAD, 0) - threads = [] - winproxy.Thread32First(snap, thread_entry) - threads.append(copy.copy(thread_entry)) - while winproxy.Thread32Next(snap, thread_entry): - threads.append(copy.copy(thread_entry)) - return threads - @utils.fixedpropety def version(self): + """The version of the system + + :type: (:class:`int`, :class:`int`) -- (Major, Minor) + """ data = self.get_version() result = data.dwMajorVersion, data.dwMinorVersion if result == (6,2): @@ -133,6 +128,28 @@ class System(object): @utils.fixedpropety def version_name(self): + """The name of the system version, values are: + + * Windows Server 2016 + * Windows 10 + * Windows Server 2012 R2 + * Windows 8.1 + * Windows Server 2012 + * Windows 8 + * Windows Server 2008 + * Windows 7 + * Windows Server 2008 + * Windows Vista + * Windows XP Professional x64 Edition + * TODO: version (5.2) + is_workstation + bitness == 32 (don't even know if possible..) + * Windows Server 2003 R2 + * Windows Server 2003 + * Windows XP + * Windows 2000 + * "Unknow Windows ".format(version, is_workstation) + + :type: :class:`str` + """ version = self.version is_workstation = self.product_type == VER_NT_WORKSTATION if version == (10, 0): @@ -165,6 +182,14 @@ class System(object): @utils.fixedpropety def product_type(self): + """The product type, value might be: + + * VER_NT_WORKSTATION(0x1L) + * VER_NT_DOMAIN_CONTROLLER(0x2L) + * VER_NT_SERVER(0x3L) + + :type: :class:`long` or :class:`int` (or subclass) + """ version_map = {x:x for x in [VER_NT_WORKSTATION, VER_NT_DOMAIN_CONTROLLER, VER_NT_SERVER]} version = self.get_version() return version_map.get(version.wProductType, version.wProductType) @@ -188,4 +213,28 @@ class System(object): req = "{0:04x}{1:04x}".format(*tup) winproxy.VerQueryValueA(buf, "\\StringFileInfo\\{0}\\ProductVersion".format(req), ctypes.byref(bufptr), ctypes.byref(bufsize)) bufstr = ctypes.cast(bufptr, LPCSTR) - return bufstr.value \ No newline at end of file + return bufstr.value + + @staticmethod + def enumerate_processes(): + process_entry = PROCESSENTRY32() + process_entry.dwSize = ctypes.sizeof(process_entry) + snap = winproxy.CreateToolhelp32Snapshot(windef.TH32CS_SNAPPROCESS, 0) + winproxy.Process32First(snap, process_entry) + res = [] + res.append(process.WinProcess._from_PROCESSENTRY32(process_entry)) + while winproxy.Process32Next(snap, process_entry): + res.append(process.WinProcess._from_PROCESSENTRY32(process_entry)) + return res + + @staticmethod + def enumerate_threads(): + thread_entry = process.WinThread() + thread_entry.dwSize = ctypes.sizeof(thread_entry) + snap = winproxy.CreateToolhelp32Snapshot(windef.TH32CS_SNAPTHREAD, 0) + threads = [] + winproxy.Thread32First(snap, thread_entry) + threads.append(copy.copy(thread_entry)) + while winproxy.Thread32Next(snap, thread_entry): + threads.append(copy.copy(thread_entry)) + return threads \ No newline at end of file diff --git a/windows/winobject/wmi.py b/windows/winobject/wmi.py index 526d57b..a5cab13 100644 --- a/windows/winobject/wmi.py +++ b/windows/winobject/wmi.py @@ -11,7 +11,7 @@ from windows.generated_def.interfaces import IWbemLocator, IWbemServices, IEnumW class WmiRequester(object): - """Perform WMI request: NOT STABLE""" + """Perform WMI request""" INSTANCE = None