打造一款属于自己的远程管理软件(一)
作者:CQITer小编 时间:2018-03-17 16:46
本人为了工作中便于管理手中大量的计算机一直在寻找一款合适的远程控制软件。鉴于网上下载的远程控制软件大多都被不同程度地植入后门,于是萌生了自己打造一款远控的想法,正好借着这个机会重新拾起快要被遗忘了的C++,也借此将源代码与大众网友分享。采用成熟的MFC框架技术来搭建远控客户端和服务端,实现了进程管理、文件管理、服务管理、远程SHELL和屏幕监视功能,层次结构清晰,为日后软件版本的迭代留下了扩展空间。
编程环境Visual Studio 2010
连接方式采用反弹型连接方式,被控端主动连接控制端从而能够轻松穿透大多数防火墙。
工作流程

被控端连接控制端,并将计算机信息上报控制端显示。
typedef struct tagSytemInit { char computer[32]; //计算机名 char user[32]; //用户名 char os[72]; //操作系统 char processor[16]; //处理器信息 char mem[16]; //内存信息 char version[16]; //软件版本 char HDSerial[32]; //硬盘序列号 }SYSTEMINIT,*LPSYSTEMINIT; 2、临时连接结构该结构用来存储连接到控制端上的socket信息以及相应的硬盘序列号。在后面的使用中将此结构存储到vector中用于管理被控端。
typedef struct tagTmpSocket { SOCKET ClientSocket; char HDSerial[64]; }TMPSOCKET,*LPTMPSOCKET; 3、进程通信结构控制端控制被控端,实现进程之间的通信。
typedef struct tagLinkInfo { SOCKET s; string strBindIp; //被控端IP u_short BindPort; //监听端口 }LINKINFO,*LPLINKINFO; 基本通信类CTcpTran是整个远控的基础通信类,用于实现socket网络通信的初始化,封装相应的API函数。使用类来封装Socket API可以避免代码的重复,便于调试。
CTcpTran类中的4个基本成员函数如下:
SOCKET InitSocket(int SocketType, string strBindIp,u_short BindPort,int opt); //初始化socket,选择连接类型 SOCKET myaccept(SOCKET s,struct sockaddr* addr,int* addrlen); //本地监听处理函数 int mysend(SOCKET sock, const char *buf, int len, int flag,int overtime); //发送数据 int myrecv(SOCKET sock, char *buf, int len, int flag , int overtime,char*EndMark,BOOL soonflag=FALSE); //接收数据 InitSocket函数InitSocket参数解释如下,SocketType为连接类型,当值为 SOCKET_BIND时表示绑定本地端口,服务器监听端口等待客户端来连接,当值为SOCKET_NOBIND时表示不绑定,服务端主动连接客户端。strBindIp为要绑定的IP地址,”"(空)为本地任意地址,这样做的目的是当服务器有多块网卡时,不论哪个网段上的客户程序都能与服务器通信。uBindPort为要绑定的端口。
SOCKET CTcpTran::InitSocket( int SocketType, string strBindIp,u_short BindPort,int opt){
SOCKET socketid = INVALID_SOCKET;
socketid = socket(PF_INET,SOCK_STREAM,0); //建立一个流式套接字句柄
SOCKADDR_IN sockStruct; //初始化一个地址结构
sockStruct.sin_family = AF_INET; //使用TCP/IP协议
if( strBindIp.empty() )
{
sockStruct.sin_addr.S_un.S_addr = INADDR_ANY; //如果strBindIp为空,则为本地任意地址
}else
{
sockStruct.sin_addr.S_un.S_addr = inet_addr(strBindIp.c_str());
}
sockStruct.sin_port = htons(BindPort); //转换为网络字节
if( SocketType == SOCKETNOBIND )
{
if(connect(socketid,(LPSOCKADDR)&sockStruct,sizeof(sockStruct)) == SOCKET_ERROR) //不绑定,直接连接,被控端选择非绑定方式连接
{
// AfxMessageBox("InitSocket 错误");
closesocket(socketid);
shutdown(socketid,2);
socketid = INVALID_SOCKET;
}
m_Socket = socketid;
}else if( SocketType == SOCKETBIND ) //控制端选择绑定本地端口
{
if(bind(socketid,(sockaddr*)&sockStruct,sizeof(sockaddr_in)) == SOCKET_ERROR) //绑定地址结构
{
closesocket(socketid);
socketid = INVALID_SOCKET;
}else
{
if( listen(socketid,SOMAXCONN) == SOCKET_ERROR ) //进入监听
{
closesocket(socketid);
socketid = INVALID_SOCKET;
}
}
m_Socket = socketid;
}
return socketid; //返回建立的socket
} myaccept函数
服务器接收客户端的连接请求,创建一个新的套接字和参数addr指定的客户端套接字建立连接通道。s表示处于监听状态的流套接字。addr表示新创建的套接字地址结构。addrlen表示新创建套接字的地址结构的长度。
SOCKET CTcpTran::myaccept(SOCKET s,struct sockaddr* addr,int* addrlen){
SOCKET accpsocket = INVALID_SOCKET;
accpsocket = accept(s,addr,addrlen);
return accpsocket;
}
mysend函数



