More doc (registry / network)

This commit is contained in:
Clement Rouault
2016-01-05 18:03:53 +01:00
parent c73fc7934a
commit b2eede98b1
10 changed files with 193 additions and 29 deletions
-3
View File
@@ -139,9 +139,6 @@ Another example from a project::
out_ioctl += x86.Mov('EAX', 0x0C000000D)
out_ioctl += x86.Ret()
.. note::
TODO: prefix
:mod:`windows.native_exec.simple_x64` -- X64 Assembler
""""""""""""""""""""""""""""""""""""""""""""""""""""""
+21
View File
@@ -0,0 +1,21 @@
Network
=======
.. module:: windows.network
.. note::
See sample :ref:`sample_network_exploration`
:class:`Network` class
""""""""""""""""""""""
.. autoclass:: windows.network.Network
Connection classes
""""""""""""""""""
.. autoclass:: windows.network.TCP4Connection
.. autoclass:: windows.network.TCP6Connection
+11 -7
View File
@@ -13,7 +13,7 @@ CurrentProcess
.. autoclass:: CurrentProcess
:members:
:inherited-members:
CurrentThread
'''''''''''''
@@ -39,13 +39,13 @@ WinThread
.. autoclass:: WinThread
:members:
:inherited-members:
.. autoclass:: DeadThread
:members:
:inherited-members:
PEB Exploration
"""""""""""""""
@@ -59,10 +59,14 @@ The :class:`PEB` is accessible via ``process.peb`` and is of type :class:`PEB`.
.. autoclass:: PEB
:members:
:inherited-members:
.. autoclass:: WinUnicodeString
.. autoclass:: LoadedModule
.. autoclass:: LoadedModule
.. warning::
TODO: pe_parse.PEFile (sorry) but example at :ref:`sample_peb_exploration`
+5 -3
View File
@@ -1,8 +1,10 @@
Registry
""""""""
========
.. module:: windows.registry
REGISTRY
.. class:: Registry
.. autoclass:: Registry
:special-members: __getitem__
.. autoclass:: PyHKey
+37 -10
View File
@@ -1,7 +1,7 @@
Samples of code
===============
.. _sample_current_process:
.. _sample_current_process:
``windows.current_process``
"""""""""""""""""""""""""""
@@ -23,9 +23,9 @@ Output::
Allocated memory is at <0x3f0000>
Writing 'SOME STUFF' in allocation memory
Reading memory : <'SOME STUFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'>
.. _sample_remote_process:
.. _sample_remote_process:
Remote process : :class:`WinProcess`
""""""""""""""""""""""""""""""""""""
@@ -61,12 +61,12 @@ Output::
File "<string>", line 3, in <module>
File "<string>", line 2, in func
ImportError: No module named FAKE_MODULE
That's all ! killing the calc
.. _sample_peb_exploration:
.. _sample_peb_exploration:
:class:`PEB` exploration
""""""""""""""""""""""""
@@ -96,4 +96,31 @@ Output::
Here are some exports {0: 2001566688L, u'CreateFileA': 2001635616L, 42: 2001647872L, u'VirtualAlloc': 2001570704L}
Import DLL dependancies are (without api-*): [u'ntdll.dll', u'kernelbase.dll']
IAT Entry for ntdll!NtCreateFile = <IATEntry "NtCreateFile" ordinal 253> | addr = 0x77541128L
Sections: [<PESection ".text">, <PESection ".rdata">, <PESection ".data">, <PESection ".rsrc">, <PESection ".reloc">]
Sections: [<PESection ".text">, <PESection ".rdata">, <PESection ".data">, <PESection ".rsrc">, <PESection ".reloc">]
.. _sample_network_exploration:
:class:`Network` - socket exploration
"""""""""""""""""""""""""""""""""""""
.. literalinclude:: ..\..\samples\network.py
Output::
(cmd λ) python.exe network.py
Working on ipv4
== Listening ==
Some listening connections: [<TCP IPV4 Listening socket on 0.0.0.0:80>, <TCP IPV4 Listening socket on 0.0.0.0:135>, <TCP IPV4 Listening socket on 0.0.0.0:443>]
Listening ports are : [80, 135, 443, 445, 902, 912, 5357, 49152, 49153, 49154, 49155, 49157, 49159, 8307, 25340, 139, 139]
== Established ==
Some established connections: [<TCP IPV4 Connection 127.0.0.1:25340 -> 127.0.0.1:49472>, <TCP IPV4 Connection 127.0.0.1:49173 -> 127.0.0.1:49174>, <TCP IPV4 Connection 127.0.0.1:49174 -> 127.0.0.1:49173>]
== connection to localhost:80 ==
Our connection is [<TCP IPV4 Connection 127.0.0.1:49616 -> 127.0.0.1:80>]
Sending YOP
Closing socket
Sending LAIT
Traceback (most recent call last):
File ".\network.py", line 45, in <module>
s.send("LAIT")
socket.error: [Errno 10054] An existing connection was forcibly closed by the remote host
+2 -1
View File
@@ -10,4 +10,5 @@ This sections describes them by group of relation.
:maxdepth: 2
process.rst
registry.rst
registry.rst
network.rst
+42
View File
@@ -0,0 +1,42 @@
import sys
import os.path
import socket
sys.path.append(os.path.abspath(__file__ + "\..\.."))
import windows
if not windows.utils.check_is_elevated():
print("!!! Demo will fail because closing a connection require elevated process !!!")
print("Working on ipv4")
conns = windows.system.network.ipv4
print("== Listening ==")
print("Some listening connections: {0}".format([c for c in conns if not c.established][:3]))
print("Listening ports are : {0}".format([c.local_port for c in conns if not c.established]))
print("== Established ==")
print("Some established connections: {0}".format([c for c in conns if c.established][:3]))
TARGET_HOST = "localhost"
TARGET_PORT = 80
print("== connection to {0}:{1} ==".format(TARGET_HOST, TARGET_PORT))
s = socket.create_connection((TARGET_HOST, TARGET_PORT))
our_connection = [c for c in windows.system.network.ipv4 if c.established and c.remote_port == TARGET_PORT and c.remote_addr == s.getpeername()[0]]
print("Our connection is {0}".format(our_connection))
print("Sending YOP")
s.send("YOP")
print("Closing socket")
our_connection[0].close()
print("Sending LAIT")
s.send("LAIT")
+48
View File
@@ -12,26 +12,44 @@ class TCP4Connection(MIB_TCPROW_OWNER_PID):
@property
def established(self):
"""``True`` if connection is established else it's a listening socket"""
return self.dwState == MIB_TCP_STATE_ESTAB
@property
def remote_port(self):
""":type: :class:`int`"""
if not self.established:
return None
return socket.ntohs(self.dwRemotePort)
@property
def local_port(self):
""":type: :class:`int`"""
return socket.ntohs(self.dwLocalPort)
@property
def local_addr(self):
"""Local address IP (x.x.x.x)
:type: :class:`str`"""
return socket.inet_ntoa(struct.pack("<I", self.dwLocalAddr))
@property
def remote_addr(self):
"""remote address IP (x.x.x.x)
:type: :class:`str`"""
if not self.established:
return None
return socket.inet_ntoa(struct.pack("<I", self.dwRemoteAddr))
@property
def remote_proto(self):
"""Identification of the protocol associated with the remote port.
Equals ``remote_port`` if no protocol is associated with it.
:type: :class:`str` or :class:`int`
"""
try:
return socket.getservbyport(self.remote_port, 'tcp')
except socket.error:
@@ -39,12 +57,19 @@ class TCP4Connection(MIB_TCPROW_OWNER_PID):
@property
def remote_host(self):
"""Identification of the remote hostname.
Equals ``remote_addr`` if resolution fail
:type: :class:`str` or :class:`int`
"""
try:
return socket.gethostbyaddr(self.remote_addr)
except socket.error:
return self.remote_addr
def close(self):
"""Close the connection <require elevated process>"""
closing = MIB_TCPROW()
closing.dwState = MIB_TCP_STATE_DELETE_TCB
closing.dwLocalAddr = self.dwLocalAddr
@@ -66,30 +91,45 @@ class TCP6Connection(MIB_TCP6ROW_OWNER_PID):
@property
def established(self):
"""``True`` if connection is established else it's a listening socket"""
return self.dwState == MIB_TCP_STATE_ESTAB
@property
def remote_port(self):
""":type: :class:`int`"""
if not self.established:
return None
return socket.ntohs(self.dwRemotePort)
@property
def local_port(self):
""":type: :class:`int`"""
return socket.ntohs(self.dwLocalPort)
@property
def local_addr(self):
"""Local address IP
:type: :class:`str`"""
return self._str_ipv6_addr(self.ucLocalAddr)
@property
def remote_addr(self):
"""remote address IP
:type: :class:`str`"""
if not self.established:
return None
return self._str_ipv6_addr(self.ucRemoteAddr)
@property
def remote_proto(self):
"""Equals to self.remote_port for Ipv6"""
return self.remote_port
@property
def remote_host(self):
"""Equals to self.remote_addr for Ipv6"""
return self.remote_addr
def close(self):
@@ -157,4 +197,12 @@ class Network(object):
ipv4 = property(lambda self: self._get_tcp_ipv4_sockets())
"""List of TCP IPv4 socket (connection and listening)
:type: [:class:`TCP4Connection`]"""
ipv6 = property(lambda self: self._get_tcp_ipv6_sockets())
"""List of TCP IPv6 socket (connection and listening)
:type: [:class:`TCP6Connection`]
"""
+10
View File
@@ -17,6 +17,7 @@ class ExpectWindowsError(object):
KeyValue = collections.namedtuple("KeyValue", ["name", "value", "type"])
class PyHKey(object):
"""A windows registry key"""
def __init__(self, surkey, name, sam=_winreg.KEY_READ):
self.surkey = surkey
self.name = name
@@ -77,6 +78,7 @@ HKEY_USERS = PyHKey(DummyPHKEY(_winreg.HKEY_USERS, "HKEY_USERS"), "", _winreg.KE
class Registry(object):
"""The ``Windows`` registry: a read only mapping"""
registry_base_keys = {
"HKEY_LOCAL_MACHINE" : HKEY_LOCAL_MACHINE,
@@ -88,6 +90,14 @@ class Registry(object):
}
def __getitem__(self, name):
"""Get a registry key::
registry[r"HKEY_LOCAL_MACHINE\\Software"]
registry["HKEY_LOCAL_MACHINE"]["Software"]
:rtype: :class:`PyHKey`
"""
if name in self.registry_base_keys:
return self.registry_base_keys[name]
if "\\" not in name:
+17 -5
View File
@@ -28,16 +28,19 @@ class Kernel32Error(WindowsError):
class IphlpapiError(Kernel32Error):
def __new__(cls, func_name, code):
def __new__(cls, func_name, code, strerror=None):
win_error = ctypes.WinError(code)
api_error = super(Kernel32Error, cls).__new__(cls)
api_error.api_name = func_name
api_error.winerror = win_error.winerror
api_error.strerror = win_error.strerror
api_error.args = (func_name, win_error.winerror, win_error.strerror)
if strerror is not None:
api_error.strerror = strerror
else:
api_error.strerror = win_error.strerror
api_error.args = (func_name, api_error.winerror, api_error.strerror)
return api_error
def __init__(self, func_name, code):
def __init__(self, func_name, code, strerror=None):
pass
@@ -580,7 +583,16 @@ def RegCloseKey(hKey):
# ##### Iphlpapi (network list and stuff) ###### #
SetTcpEntry = TransparentIphlpapiProxy('SetTcpEntry')
def set_tcp_entry_error_check(func_name, result, func, args):
"""raise IphlpapiError if result is NOT 0 -- pretty print error 317"""
if result:
if result == 317:
raise IphlpapiError(func_name, result, "<require elevated process>".format(func_name))
raise IphlpapiError(func_name, result)
return args
SetTcpEntry = TransparentIphlpapiProxy('SetTcpEntry', error_check=set_tcp_entry_error_check)
@OptionalExport(IphlpapiProxy('GetExtendedTcpTable'))