易陆发现互联网技术论坛

 找回密码
 开始注册
查看: 1964|回复: 0
收起左侧

C++一款属于自己的远程管理

[复制链接]
发表于 2021-7-20 09:46:37 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?开始注册

x
采用成熟的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)5 g6 A" f1 A% `: k' D
{
8 T/ i* p4 ]" v' C        SOCKET socketid = INVALID_SOCKET;8 F7 i% U4 Z' ]
        socketid = socket(PF_INET,SOCK_STREAM,0);               //建立一个流式套接字句柄- Z! {. B0 b  B
SOCKADDR_IN sockStruct; //初始化一个地址结构. n4 b1 @& h  T" f) v& }% m7 O. Z
sockStruct.sin_family = AF_INET; //使用TCP/IP协议/ j) S' j; l( D8 c" W

  \# N3 i$ I6 h" x& ]4 Vif( strBindIp.empty() )3 ]4 q2 a/ j5 i9 o* y, D3 O/ w! [
{" W- B6 R& K0 `) D3 j
sockStruct.sin_addr.S_un.S_addr = INADDR_ANY; //如果strBindIp为空,则为本地任意地址 1 I2 j5 A$ ~- J1 P4 m. m  M" }
) H( b' S- x8 |. K4 `9 `8 I
}else; ~6 D' O6 Y. a0 G4 J
{- y3 Z$ p* x. h. b+ C- q; H
sockStruct.sin_addr.S_un.S_addr = inet_addr(strBindIp.c_str());   \6 f: g3 q0 I- n* ?( k. J6 u: `
}. z( ?) x: U9 L- _

, u# t( Z7 c; U; j' `
5 {7 Z+ Y5 ^/ S! K sockStruct.sin_port = htons(BindPort); //转换为网络字节
2 D; \7 ^  \9 \9 W0 H
; o0 ?" q& D$ M. vif( SocketType == SOCKETNOBIND )
% Y, t+ s7 V$ }* k6 r/ X- A {
" J* z9 r2 r* jif(connect(socketid,(LPSOCKADDR)&sockStruct,sizeof(sockStruct)) == SOCKET_ERROR) //不绑定,直接连接,被控端选择非绑定方式连接( U" T  f  e5 i" h
{
) K# y3 K, z6 l2 N- J/ P// AfxMessageBox("InitSocket 错误");5 c/ @! B' E3 G; s# z2 F4 _
closesocket(socketid);% w& l8 W1 |4 P8 c& x$ F
shutdown(socketid,2);
8 E+ R) S# `3 E9 _ socketid = INVALID_SOCKET;7 W% K0 R  o2 D' ^0 E% t2 w
}; s' k; L' I+ E) p
4 h. j% t0 R2 r+ Z
m_Socket = socketid;% y2 A! ^. l' K5 ^
" h% y6 F& w% t4 o
}else if( SocketType == SOCKETBIND ) //控制端选择绑定本地端口) u- ]" t6 A' Y0 o1 D: s& @2 a, u
{
3 d1 z) H7 C/ H3 N1 l8 Q7 R* Y0 Uif(bind(socketid,(sockaddr*)&sockStruct,sizeof(sockaddr_in)) == SOCKET_ERROR) //绑定地址结构
% R- [9 o7 S- s1 P6 V$ o3 P7 q# Z {) T9 `% z; s, g2 n- I* Z
closesocket(socketid);, V" I, Z" P2 m' r2 z
socketid = INVALID_SOCKET;. t/ ~7 B5 W* F3 S. E% g

/ D* B; N; m, P0 I5 `2 s }else
% D; o/ _& ]- @8 T  K- q {
* |* Y& ]. F: \$ ^3 t( V/ D$ J- E: {if( listen(socketid,SOMAXCONN) == SOCKET_ERROR ) //进入监听
2 |8 g5 ~2 |# D( s+ { {8 m( T: f( j/ E+ U. n: L4 t9 D; c
closesocket(socketid);
. l* n  _+ b! v( X: ?' u! s/ w socketid = INVALID_SOCKET;7 }: k# K- l+ {$ F  o* j
}$ u2 U6 S( Y4 v( F) G: ?
}, ^! T4 ?0 c* `
4 G; w- o. G4 |2 D9 `$ l
m_Socket = socketid;
6 m% p  b: A6 ]1 \" z }
% R: p2 D8 |" m1 K* k2 l, |9 L- z+ R+ z
return socketid; //返回建立的socket
5 @# e+ {+ A% r" m" y8 m3 g} myaccept函数服务器接收客户端的连接请求,创建一个新的套接字和参数addr指定的客户端套接字建立连接通道。s表示处于监听状态的流套接字。addr表示新创建的套接字地址结构。addrlen表示新创建套接字的地址结构的长度。SOCKET        CTcpTran::myaccept(SOCKET s,struct sockaddr* addr,int* addrlen): K  U6 o, D  n# c: T
{- Q% b( N1 K, n' ^5 m
        SOCKET accpsocket  = INVALID_SOCKET;
, c% y# S! D  L& ~0 a        accpsocket = accept(s,addr,addrlen);" G4 e% Q9 `7 b1 @0 K$ \# y
return accpsocket;
6 d0 o0 n; L7 p8 g" h' o# q7 V+ O& }' A' p}
7 y8 Z4 g5 ?  _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)
; p6 M& r# \' X+ p; [9 n{
$ Q$ E# C7 B- |: N' xint ret;; b2 o8 [3 k4 I
int nLeft = len; //待发送的字节数
7 U; S- W1 t' ?* ~, C2 l: _int idx = 0; //发送缓冲区索引
* E6 |8 B- v3 g* l% e2 @4 Y$ f: v5 @0 Q1 b, U& W5 E4 `, t' P8 V5 p7 g
fd_set readfds; 8 d3 z) |" O' c- p: [# Y" @' D' V. P" K
struct timeval timeout;
; d) g' b4 q  ^  a timeout.tv_sec = 0;" p$ K; D! j) ~+ \- S$ @
timeout.tv_usec = 500; - e7 ]% u3 f2 P! n- d4 W8 [1 g
DWORD s_time = GetTickCount(); //获取系统时间(从操作系统运行开始到当前的时间),第一次计时
3 J$ t+ y" u  S: }2 k; lwhile ( nLeft > 0 )6 i, A8 U; d6 s: ]- g( m- Q
{
% T( B8 {8 ^9 F6 c7 _' Z4 ~ MSG msg;" U$ l. [/ ?' M# T( l5 ?6 C; [
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ;' E. K5 C& R; ]2 m# _: `( B
if(msg.message == WM_QUIT)
# t* a3 ^- _8 |$ `, u% ?5 D8 W  Q) k5 V {
0 L% v, }( ^5 rreturn 0;
6 K- S. o$ d1 _* F7 Z }% R. r0 I6 J1 M& t

) o+ g: m  ^9 h FD_ZERO( &readfds ); //每次循环更新文件描述符
0 w2 X. d4 F* r' G# ]6 U, h FD_SET( sock , &readfds );+ C. g1 K* q2 r% r& p$ \8 h3 x
% `1 m* P4 b% g- ^* t  o) C% S
int errorret = select( 0 , NULL, &readfds, NULL , &timeout ); //时间阻塞式监控,检测套接字是否可写
2 P0 e7 c% c( w3 l0 f/ ?, G# [3 v& v* N* L% r# `1 h4 r3 ?
if( errorret == SOCKET_ERROR )) W2 m3 r3 M; @+ D" Y- w
{5 {( W- [6 Y3 x% r' E% q
// AfxMessageBox("mysendEx SOCKET 错误");
0 s, ?4 Z" s" V  I* {9 ~/ |" mreturn SOCKET_ERROR;$ W) e% K* a/ f% n* h& J! X
}
6 C! d" q6 l# O+ J, \
. e0 W* c( g+ ~2 H4 l DWORD e_time = GetTickCount( ); //第二次计时
$ b% [+ a$ o- L. `if ( !FD_ISSET( sock , &readfds ) ) //检测是否可以发送,如果为否表示正在占用
, X8 H/ B) n, z) L7 N {: a7 Q( a: X; ?

( {1 @; ?$ }. B) k0 Aif( e_time - s_time > overtime*1000 ) //检测时间窗口是否超时9 e0 G6 c/ ~7 U+ B" Y  j0 ~) ?
{
! R) [0 F; y( Z; I// AfxMessageBox("mysendEx发送数据超时");
) q" J6 V5 e; ^/ j# Areturn 0;
3 k3 x# a5 w9 b  W0 L }
6 v1 ~" W. E3 p, C" M$ M; [else7 k! q% a! ~: O6 \+ s- I
{
* c1 f- K+ T( g. {, `7 Dcontinue;% ~! y% A) q+ Y; V9 M+ x- e, P! A
}! c# |: y* H8 \0 B5 M5 W: s
}+ p# X7 S6 W# V2 {8 C) N# A

( c! O7 @/ Y1 e% E2 b5 B ret = send( sock, &buf[idx], nLeft, flag ); //返回实际发送的字节数7 b, j/ M, ?6 s/ D5 @8 H
- M5 P* s0 W( c  G0 C) L
if ( ret <= 0 )5 ~5 S( X9 t  Z/ f" L6 L
{
; z. X8 n) c: q( \. ~- |) X) d- Ureturn ret;
; _/ `$ G2 z, `  r8 {. \5 N! ~ }+ J7 F: L; X: T

0 E3 s* S8 m/ E' S nLeft -= ret; //剩余字节数-% P) X. e# m5 u( _
idx += ret; //索引值+
: N+ t7 O! H# B4 w3 |0 W9 O
! L) |& e  C+ E9 c' d }
/ g1 n1 C1 Z, D) I, xreturn len; //返回发送字节数5 k9 O# ]  t, r& v- k- b
}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)
6 D+ Q  c; i. u5 k0 G2 h{5 k; z. j' U* I3 L- O+ i
int ret;' a2 Y& a" Y$ f) K1 n
int nLeft = len;3 ?. h* `5 O( Z2 |+ M  Q8 T
int idx = 0;1 y% y/ K8 g+ O4 {* W. o, W) F
int nCount = 0;
  a% Y5 p* O1 \' P7 Z fd_set readfds;
" U2 q; c* a1 z8 M0 z2 G struct timeval timeout;6 L8 ^; H! Z+ v( @/ R9 S
timeout.tv_sec = 0;  i3 c& N: m. y/ u9 J! c
timeout.tv_usec = 500;& ?* S- h5 |" u. _8 d$ s5 P% y
DWORD s_time = GetTickCount();3 T3 J  r4 ^2 o4 G! @$ W, r; v

/ s4 B' V6 U& M  ?7 }while ( nLeft > 0 )
# y3 E( P2 R/ E! f9 M {& s/ b- m. z& V8 h# h
//接收消息
) a& T2 O# c% l7 p* h6 K! O7 X* t MSG msg;
: \/ B1 }# {( w& r: y PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ;4 x# |) v3 ^* @+ G
if(msg.message == WM_QUIT)+ _; A2 D' c# ?; Z8 R5 p0 o! H
return 0;
! c  r3 c; H: y' w! A- o# d1 I, A) `% l
FD_ZERO( &readfds );4 t3 Q$ ^3 g; W- T
FD_SET( sock , &readfds );& d4 }) D1 J1 ]2 m. w/ C
if( select( 0 , &readfds , NULL , NULL , &timeout ) == SOCKET_ERROR )
; z5 d( \  b2 O2 } {
# B' K7 g& |" t% _- p4 L// AfxMessageBox("recv SOCKET 错误");* a  j3 I4 D  Y* E
return SOCKET_ERROR;* j4 N/ t; O# X- m. z: `) L
}
6 ^/ ]- U# f% H1 F% R: J  A( {& |7 i- K7 e  L! z
DWORD e_time = GetTickCount( );
/ q7 g: Q# ^+ R, z. {if ( !FD_ISSET( sock , &readfds ) )
% o1 a1 J" ^* b: g9 O& Y7 {* E  t {
; B* s) V3 e! y# Z7 \, Lif( e_time - s_time > overtime*1000 )
/ Q1 {: s3 U4 M! q/ f2 q8 U {
# M5 j) C4 y7 S, n4 @+ h2 u// AfxMessageBox("recv SOCKET 超时");
3 O7 r9 Z! T2 Q/ a: @& Z$ Sreturn SOCKET_TIMEOUT;/ Y$ s- Q; h/ s5 [1 H
}1 ^& M5 F5 s! e7 S, H# Q
else* E3 _4 V1 c& K2 u- v
continue;) m1 @/ S$ P% p5 t6 A
}
1 y+ j4 Y" Q5 r: L* |) P; |" E; z3 O( A
ret = recv( sock, &buf[idx], nLeft, flag );+ [% O% C% k8 j6 Y. a' J+ l) N6 v: N
if( soonflag == TRUE )
+ H: E; r% F0 z: ?; U; ~6 |3 ^ {2 L: X# c/ ?  }+ c# d
return ret;
0 C$ g7 l, E- ^  F" R }% l* }, v$ f0 ]( I4 l" A

$ V, A& v2 o$ L* q1 q3 P s_time = e_time ; // 只要有数据就重新置初始时间值0 A5 Z! x8 \4 D0 u4 @7 T# h

; e8 S* ^/ M/ dif ( ret <= 0 )2 {. B0 o& r: U
{
- B% D5 j' x2 K% }. X' D- Qint LastError = GetLastError();
$ u  I- _8 q( |9 h! I4 H" o+ i" Hif ( ( -1 == ret ) && ( WSAETIMEDOUT == LastError ) )
% z' d6 r( N: ?. x: Z) ycontinue;
' Y; l6 g" D# n( w4 Z- L8 F1 k7 nif ( ( -1 == ret ) && ( WSAEWOULDBLOCK == LastError ) )5 u1 ^6 ~4 T/ W- E/ F+ w
{5 s$ X9 }/ K. n  i! E
if ( nCount < 2000 )
) ]% G, j5 Y2 l {
. e( R; [5 Z% _ Sleep( 10 );
$ Q  [/ e  ]1 c9 p nCount++;5 N) A8 G" @8 y3 B4 C
continue;
4 x* w6 K  g0 M: r }
& n" }1 h7 U5 D# U# ~ }
0 Z5 c0 ^% T9 H: L  I6 j9 t! vreturn ret;, h3 }& q+ |" F2 ^( ]& t4 C, c! v
}6 J7 c' w9 a7 m) S+ K
nCount = 0;
% |) Y  f' g1 C; K, O8 `* F1 @7 R8 L- V; Y: m
nLeft -= ret;  J7 f( Q' [3 A4 c/ ^. {) B
idx += ret;" [0 H5 u$ x+ k7 Z- x
# |9 V" @  x. ?" O9 R
if( EndMark != NULL && idx>5); m: \9 g5 s3 \/ Z" o
{
' e+ c) i' F4 h4 x% u$ q1 p8 {if( strstr(buf+(idx-5),EndMark) != NULL )
: u' g$ W8 J# L" ~# g+ R% f/ |5 U {7 h9 I  s0 Z2 z/ h% R. C7 c
break;0 f2 _' _+ H, H9 o' {0 R( M
}" ]) w8 H* Y; `1 [: x9 m+ Y
}# j) l9 r3 W+ x& x7 ^# W
}
" ~+ [' e* B0 U$ a) N1 Y, Y
  `3 C/ E  d+ ^, t' H" U& Creturn idx;4 x' T4 `& ]; s: M! B9 D2 J4 p
}
4 j# r! ^# K$ J0 H. U  l主界面                                功能界面进程管理                                  文件管理                                  服务管理                                  远程SHELL                                   远程桌面                                 
您需要登录后才可以回帖 登录 | 开始注册

本版积分规则

关闭

站长推荐上一条 /4 下一条

北京云银创陇科技有限公司以云计算运维,代码开发

QQ|返回首页|Archiver|小黑屋|易陆发现技术论坛 点击这里给我发消息

GMT+8, 2026-4-8 15:54 , Processed in 0.046471 second(s), 22 queries .

Powered by Discuz! X3.4 Licensed

© 2012-2025 Discuz! Team.

快速回复 返回顶部 返回列表