打造一款属于自己的远程控制软件一
liebian365 2024-10-30 04:48 23 浏览 0 评论
本人为了工作中便于管理手中大量的计算机一直在寻找一款合适的远程控制软件。鉴于网上下载的远程控制软件大多都被不同程度地植入后门,于是萌生了自己打造一款远控的想法,正好借着这个机会重新拾起快要被遗忘了的C++,也借此将源代码与大众网友分享。采用成熟的MFC框架技术来搭建远控客户端和服务端,实现了进程管理、文件管理、服务管理、远程SHELL和屏幕监视功能,层次结构清晰,为日后软件版本的迭代留下了扩展空间。
编程环境
Visual Studio 2010
连接方式
采用反弹型连接方式,被控端主动连接控制端从而能够轻松穿透大多数防火墙。
工作流程
基本传输结构
1、被控端上报基本计算机信息结构
被控端连接控制端,并将计算机信息上报控制端显示。
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函数
mysend函数用来发送指定的套接字数据。sock为指定的Socket。buf为用来存放要发送的数据的缓冲区。len为待发送数据的长度。flag一般设置为0。overtime为超时时间。这里采用了select机制防止I/O操作阻塞,提高了程序运行效率。这里要注意每次执行select操作之前都要更新文件描述符,因为select操作会更改文件描述符。
int CTcpTran::mysend(SOCKET sock, const char *buf, int len, int flag,int overtime){int ret;int nLeft = len; //待发送的字节数int idx = 0; //发送缓冲区索引fd_set readfds; struct timeval timeout; timeout.tv_sec = 0;timeout.tv_usec = 500;DWORD s_time = GetTickCount(); //获取系统时间(从操作系统运行开始到当前的时间),第一次计时while ( nLeft > 0 ){MSG msg;PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ;if(msg.message == WM_QUIT){return 0;}FD_ZERO( &readfds ); //每次循环更新文件描述符FD_SET( sock , &readfds );int errorret = select( 0 , NULL, &readfds, NULL , &timeout ); //时间阻塞式监控,检测套接字是否可写if( errorret == SOCKET_ERROR ){// AfxMessageBox("mysendEx SOCKET 错误");return SOCKET_ERROR;}DWORD e_time = GetTickCount( ); //第二次计时if ( !FD_ISSET( sock , &readfds ) ) //检测是否可以发送,如果为否表示正在占用{if( e_time - s_time > overtime*1000 ) //检测时间窗口是否超时{// AfxMessageBox("mysendEx发送数据超时");return 0;}else{continue;}}ret = send( sock, &buf[idx], nLeft, flag ); //返回实际发送的字节数if ( ret <= 0 ){return ret;}nLeft -= ret; //剩余字节数-idx += ret; //索引值+}return len; //返回发送字节数 }
myrecv函数
myrecv函数用来接收指定的套接字数据。sock为接收端套接字描述符。buf 用来存放接收到的数据的缓冲区。len为接收数据的缓冲区的大小。flag一般设置为0。overtime为超时时间。endmark为结束标记。soonflag为是否立即返回结果,默认为否。与mysend函数一样采用select机制防止I/O操作阻塞。
int CTcpTran::myrecv(SOCKET sock, char *buf, int len, int flag , int overtime ,char*EndMark,BOOL soonflag){int ret;int nLeft = len;int idx = 0;int nCount = 0;fd_set readfds;struct timeval timeout;timeout.tv_sec = 0;timeout.tv_usec = 500;DWORD s_time = GetTickCount();while ( nLeft > 0 ){//接收消息MSG msg;PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ;if(msg.message == WM_QUIT)return 0;FD_ZERO( &readfds );FD_SET( sock , &readfds );if( select( 0 , &readfds , NULL , NULL , &timeout ) == SOCKET_ERROR ){// AfxMessageBox("recv SOCKET 错误");return SOCKET_ERROR;}DWORD e_time = GetTickCount( );if ( !FD_ISSET( sock , &readfds ) ){if( e_time - s_time > overtime*1000 ){// AfxMessageBox("recv SOCKET 超时");return SOCKET_TIMEOUT;}elsecontinue;}ret = recv( sock, &buf[idx], nLeft, flag );if( soonflag == TRUE ){return ret;}s_time = e_time ; // 只要有数据就重新置初始时间值if ( ret <= 0 ){int LastError = GetLastError();if ( ( -1 == ret ) && ( WSAETIMEDOUT == LastError ) )continue;if ( ( -1 == ret ) && ( WSAEWOULDBLOCK == LastError ) ){if ( nCount < 2000 ){Sleep( 10 );nCount++;continue;}}return ret;}nCount = 0;nLeft -= ret;idx += ret;if( EndMark != NULL && idx>5){if( strstr(buf+(idx-5),EndMark) != NULL ){break;}}}return idx;}
主界面
功能界面
进程管理
文件管理
服务管理
远程SHELL
远程桌面
相关推荐
- 精品博文嵌入式6410中蓝牙的使用
-
BluetoothUSB适配器拥有一个BluetoothCSR芯片组,并使用USB传输器来传输HCI数据分组。因此,LinuxUSB层、BlueZUSB传输器驱动程序以及B...
- win10跟这台计算机连接的前一个usb设备工作不正常怎么办?
-
前几天小编闲来无事就跑到网站底下查看粉丝朋友给小编我留言询问的问题,还真的就给小编看到一个问题,那就是win10跟这台计算机连接的一个usb设备运行不正常怎么办,其实这个问题的解决方法时十分简单的,接...
- 制作成本上千元的键盘,厉害在哪?
-
这是稚晖君亲自写的开源资料!下方超长超详细教程预警!!全文导航:项目简介、项目原理说明、硬件说明、软件说明项目简介瀚文智能键盘是一把我为自己设计的——多功能、模块化机械键盘。键盘使用模块化设计。左侧的...
- E-Marker芯片,USB数据线的“性能中枢”?
-
根据线缆行业的研究数据,在2019年搭载Type-C接口的设备出货量已达到20亿台,其中80%的笔记本电脑和台式电脑采用Type-C接口,50%的智能手机和平板电脑也使用Type-C接口。我们都知道,...
- ZQWL-USBCANFD二次开发通讯协议V1.04
-
修订历史:1.功能介绍1.1型号说明本文档适用以下型号: ZQWL-CAN(FD)系列产品,USB通讯采用CDC类实现,可以在PC机上虚拟出一个串口,串口参数N,8,1格式,波特率可以根据需要设置(...
- win10系统无法识别usb设备怎么办(win10不能识别usb)
-
从驱动入手,那么win10系统无法识别usb设备怎么办呢?今天就为大家分享win10系统无法识别usb设备的解决方法。1、右键选择设备管理器,如图: 2、点击更新驱动程序,如图: 3、选择浏览...
- 微软七月Win8.1可选补丁有内涵,含大量修复
-
IT之家(www.ithome.com):微软七月Win8.1可选补丁有内涵,含大量修复昨日,微软如期为Win7、Win8.1发布7月份安全更新,累计为6枚安全补丁,分别修复总计29枚安全漏洞,其中2...
- 如何从零开始做一个 USB 键盘?(怎么制作usb)
-
分两种情况:1、做一个真正的USB键盘,这种设计基本上不涉及大量的软件编码。2、做一个模拟的USB键盘,实际上可以没有按键功能,这种的需要考虑大量的软件编码,实际上是一个单片机。第一种设计:买现成的U...
- 电脑识别U盘失败?5个实用小技巧,让你轻松搞定USB识别难题
-
电脑识别U盘失败?5个实用小技巧,让你轻松搞定USB识别难题注意:有些方法会清除USB设备里的数据,请谨慎操作,如果不想丢失数据,可以先连接到其他电脑,看能否将数据复制出来,或者用一些数据恢复软件去扫...
- 未知usb设备设备描述符请求失败怎么解决
-
出现未知daousb设备设备描述符请求失du败解决办zhi法如下:1、按下Windows+R打开【运行】;2、在版本运行的权限输入框中输入:services.msc按下回车键打开【服务】;2、在服务...
- 读《飘》47章20(飘每章概括)
-
AndAhwouldn'tleaveMissEllen'sgrandchildrenfornotrashystep-patobringup,never.Here,Ah...
- 英翻中 消失的过去 37(消失的英文怎么说?)
-
翻译(三十七):消失的过去/茱迪o皮考特VanishingActs/JodiPicoult”我能做什么?“直到听到了狄利亚轻柔的声音,我才意识到她已经在厨房里站了好一会儿了。当她说话的时候,...
- RabbitMQ 延迟消息实战(rabbitmq如何保证消息不被重复消费)
-
现实生活中有一些场景需要延迟或在特定时间发送消息,例如智能热水器需要30分钟后打开,未支付的订单或发送短信、电子邮件和推送通知下午2:00开始的促销活动。RabbitMQ本身没有直接支持延迟...
- Java对象拷贝原理剖析及最佳实践(java对象拷贝方法)
-
作者:宁海翔1前言对象拷贝,是我们在开发过程中,绕不开的过程,既存在于Po、Dto、Do、Vo各个表现层数据的转换,也存在于系统交互如序列化、反序列化。Java对象拷贝分为深拷贝和浅拷贝,目前常用的...
- 如何将 Qt 3D 渲染与 Qt Quick 2D 元素结合创建太阳系行星元素?
-
Qt组件推荐:QtitanRibbon:遵循MicrosoftRibbonUIParadigmforQt技术的RibbonUI组件,致力于为Windows、Linux和MacOSX提...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)