找回密码
 注册
查看: 1967|回复: 0

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

[复制链接]

1

主题

0

回帖

12

积分

管理员

积分
12
QQ
发表于 2021-7-20 09:46:37 | 显示全部楼层 |阅读模式
采用成熟的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)
4 u, N/ D" [2 _! E: R{& X& S$ m  o* W
        SOCKET socketid = INVALID_SOCKET;
+ m0 c4 l& v/ A        socketid = socket(PF_INET,SOCK_STREAM,0);               //建立一个流式套接字句柄
! K2 J/ M7 ?. L6 F) y9 p SOCKADDR_IN sockStruct; //初始化一个地址结构
4 m4 H/ u0 B7 j# }4 E# ]& j, p: x sockStruct.sin_family = AF_INET; //使用TCP/IP协议  t6 ?1 Q7 a8 r8 m3 R3 A3 `6 f

) H' n1 l/ R- dif( strBindIp.empty() )
0 R- q, w" I* q- t' L* e9 f {
3 |$ u* ?6 D* `5 M3 I sockStruct.sin_addr.S_un.S_addr = INADDR_ANY; //如果strBindIp为空,则为本地任意地址 . n- U5 h- \- q

0 e- h% |+ L5 m& m }else% _3 v) d6 c# {4 {; {$ w1 v+ j6 z7 V
{  Y+ W' R. h% P+ F; ~/ w% W
sockStruct.sin_addr.S_un.S_addr = inet_addr(strBindIp.c_str()); / D7 b% `5 @# ^# S; }* ^
}
3 j. h  f' Z' F5 l
4 w* Q* r$ J9 D
+ J( x# B- ^, y& v0 p3 N, D& s sockStruct.sin_port = htons(BindPort); //转换为网络字节9 n! _, [  [! C3 O3 m4 g9 _7 i

# H2 Z# c& t7 B: r* z- H8 S1 Dif( SocketType == SOCKETNOBIND )5 \9 I2 l+ J7 c  q) s
{1 P: H. v/ w- p; {. o7 s6 z
if(connect(socketid,(LPSOCKADDR)&sockStruct,sizeof(sockStruct)) == SOCKET_ERROR) //不绑定,直接连接,被控端选择非绑定方式连接- E$ Z, o; i, ~: Y* h
{
1 `) @9 [" Q6 b* Y6 h* I! ?- J// AfxMessageBox("InitSocket 错误");
- }9 w- u: r' y; c closesocket(socketid);0 [) h/ H+ z9 @
shutdown(socketid,2);0 }5 {$ h, s0 g9 N& o7 R( L0 w
socketid = INVALID_SOCKET;
1 I/ e4 P- Y% J  A& V! Q  J$ L }% n. F4 D' X2 m# l, }. z

8 G! A; r8 a& I- G- x4 M3 y m_Socket = socketid;
6 P4 r& T0 ]5 |5 T/ }5 w3 K0 ?! ?
}else if( SocketType == SOCKETBIND ) //控制端选择绑定本地端口
" _3 k. E: a% | {, b) U1 p9 T' n
if(bind(socketid,(sockaddr*)&sockStruct,sizeof(sockaddr_in)) == SOCKET_ERROR) //绑定地址结构+ Y' t4 `5 P! F7 K. r" K9 |
{3 T& O0 }. ~- V5 B# W
closesocket(socketid);; R& U7 t; m, A- z; x2 A
socketid = INVALID_SOCKET;/ I7 o( W' |3 G: E6 _6 Z
4 I+ B" ]8 A; P8 x2 o7 D
}else8 l9 w" Q/ E9 z" F* P* V
{
$ v$ @, b5 {" A- V, Dif( listen(socketid,SOMAXCONN) == SOCKET_ERROR ) //进入监听% m$ y7 `5 O, R& b
{
# O  M5 e; K( w3 L+ z( d/ a closesocket(socketid);
( Z4 k+ C2 }" g1 ? socketid = INVALID_SOCKET;
( Y* `1 K, c/ ~( c$ F. M, n }2 m) Y/ a7 c! U; t( g% }# ~6 Y$ e& o, G
}
* [- }9 S' o9 L. j3 z8 l  D& E
0 K% N% Q# a5 j* y- v& M m_Socket = socketid;2 U- L4 D- `7 M1 ^" g! m2 i; A; o
}
7 m) L7 ~: J# J+ s
2 q3 Y& u; k# V, a  v0 V/ Dreturn socketid; //返回建立的socket- S( U' [. \& `6 s" o5 J4 Y, Z1 t
} myaccept函数服务器接收客户端的连接请求,创建一个新的套接字和参数addr指定的客户端套接字建立连接通道。s表示处于监听状态的流套接字。addr表示新创建的套接字地址结构。addrlen表示新创建套接字的地址结构的长度。SOCKET        CTcpTran::myaccept(SOCKET s,struct sockaddr* addr,int* addrlen)) |4 M: g1 m0 d* b: [! W
{: [0 T9 C" y  J* v  q" S
        SOCKET accpsocket  = INVALID_SOCKET;7 z; H( V2 W  Z# M5 M% d6 {
        accpsocket = accept(s,addr,addrlen);
6 _7 t- h4 @# X2 \( lreturn accpsocket;
- v  }5 @* _  l( l- j}+ ]8 H) W2 [2 ~: C7 b
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)
- n9 r1 Y4 o  K* J/ M2 z  p{
+ M: K/ H: b* D/ [" iint ret;
! K1 q9 f/ v9 j) F  T" o0 mint nLeft = len; //待发送的字节数
5 C% a# }# C5 \: ?% f" s8 Tint idx = 0; //发送缓冲区索引' f  W7 x5 \% i. `# Q% c
5 h5 u2 E" f* w" X
fd_set readfds; " D( {* ], X6 N5 i
struct timeval timeout; # ?/ n7 X. X4 E% [
timeout.tv_sec = 0;1 P% A$ f- M, p0 p2 J
timeout.tv_usec = 500;
; o  u: l( [3 |4 a5 @" j DWORD s_time = GetTickCount(); //获取系统时间(从操作系统运行开始到当前的时间),第一次计时9 ]6 V2 u, v; u6 Z
while ( nLeft > 0 )& v0 M4 z6 m0 N( A
{$ l1 H$ ^( s& h9 J# n+ n! H6 X
MSG msg;, X1 d# x5 A# d( ~. n! F. F1 d7 p& x
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ;
3 W$ }" ?" l; f/ R1 c1 Bif(msg.message == WM_QUIT)! Y& J, I9 Z6 F+ c8 D
{" I) w* ~' M# ^  G9 C
return 0;4 c3 Z7 L; X- S) ~: d; Q' l
}6 J% i& m# P$ k5 I; Z; a
$ g' ^; w+ _/ b+ _3 ^+ A! E; V
FD_ZERO( &readfds ); //每次循环更新文件描述符
: S( y& E* t- N" E FD_SET( sock , &readfds );
% s& ~+ ^1 C$ `( f
/ m/ S5 m) j# J' {! D% Zint errorret = select( 0 , NULL, &readfds, NULL , &timeout ); //时间阻塞式监控,检测套接字是否可写+ f$ X  R+ t2 P( \
' Q& r, p" m/ Y# r2 v
if( errorret == SOCKET_ERROR )( M+ q, G+ j% `2 @' t# Q3 P
{
5 e# g& D4 _, g& v// AfxMessageBox("mysendEx SOCKET 错误");; V1 V& x: l8 j  }: q. j5 u
return SOCKET_ERROR;  n3 s$ Z' D" B& Y5 d/ |
}
' d* |. x( u4 p  X! y6 J' ^7 b9 @8 `+ m1 ^( ^
DWORD e_time = GetTickCount( ); //第二次计时
/ n- R- q0 D1 \: w, t! Sif ( !FD_ISSET( sock , &readfds ) ) //检测是否可以发送,如果为否表示正在占用
" d( Q5 X: W$ `0 H {
4 X9 B5 G3 @7 K- Y; e  ~0 S6 D' ?( B0 D% i+ E% H
if( e_time - s_time > overtime*1000 ) //检测时间窗口是否超时
- h6 K7 r. p" w0 i5 Q* s7 E {
( t. N9 g2 w7 p+ F9 M" K0 U// AfxMessageBox("mysendEx发送数据超时");0 d, k# z4 S- Q* x+ ^
return 0;5 y0 a" R4 b( f0 m
}
+ z+ @9 g1 }# }# }/ [. p% Zelse' T6 ]6 }) |$ C, f" x
{0 D$ ~0 h+ `8 G' R  s9 u6 o! `
continue;
$ i' a' I5 q9 c  ?+ D# p4 ^ }
9 G% `5 o! _- u7 P* k4 b4 u4 d% O }
  u5 x& o& x, M' ?( X, [6 _) H5 J& H4 Y# H8 R8 [0 A; \& ^6 z' N
ret = send( sock, &buf[idx], nLeft, flag ); //返回实际发送的字节数
& A) l5 e; L0 H% J# }  }" U
9 g; s$ C, ~! Vif ( ret <= 0 )- [3 q5 w! c! P( S" B" q9 W
{
7 ]  L% U+ |- K( f, m* qreturn ret;
/ x1 z% @  H% g% i8 m }
3 E# ^/ g$ F3 k4 f6 `: Q7 c; `3 h) \# a6 [# G, @* t6 p
nLeft -= ret; //剩余字节数-; {, V4 p" a/ E6 v1 m3 R
idx += ret; //索引值+! [- G- j+ |0 y/ |  c/ q2 s% W
5 P( [# Q7 U& z9 X- l8 q
}
; w& k# E1 s8 r: Ureturn len; //返回发送字节数$ L8 D( T8 ?7 Y* N1 k
}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)
& [2 x8 E5 x6 s1 `, e{" B, k& E$ s) \) u. G
int ret;
- \0 }5 x$ o+ j5 X5 i# i+ Uint nLeft = len;  ~4 @% `/ J6 T% C/ V: I& s+ M
int idx = 0;
$ D8 g4 ^9 z0 c4 B6 Q0 ~) E1 zint nCount = 0;1 G) o+ g+ R, \' B4 K4 E
fd_set readfds;
+ `* o: ^; I' z3 Q) b: H8 ? struct timeval timeout;; A. s. \! _. t  O. \
timeout.tv_sec = 0;
! ?3 x7 b) V2 E. U7 k2 } timeout.tv_usec = 500;5 g. L  Q$ g* P3 O$ c
DWORD s_time = GetTickCount();- ~& Y7 d1 Y8 S# a, q: V  k% _
$ {/ h: n- a5 l. A/ E' w
while ( nLeft > 0 )4 f4 E' Z4 g) N' v/ {5 c9 ~
{
8 a( Z4 N. a6 P! y+ [//接收消息
, v% L3 C' g, ]0 w MSG msg;
% v  z0 v4 s2 I% H- l+ C PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ;) B; |7 P5 ?7 }: S5 G2 S
if(msg.message == WM_QUIT)
& ]3 D) X5 S; Q3 ^" ~5 N5 \return 0;
! c1 [' d" I2 w
7 y- P$ [# |- M( y FD_ZERO( &readfds );* {" C6 O5 L, e. M. [
FD_SET( sock , &readfds );6 q3 y8 H3 F  R
if( select( 0 , &readfds , NULL , NULL , &timeout ) == SOCKET_ERROR )
8 m6 Z6 x5 d& S+ u/ @  J4 l4 u5 ? {( ]  U; J' O9 f2 r7 p- f! I
// AfxMessageBox("recv SOCKET 错误");. X) Q5 c7 l, t' `
return SOCKET_ERROR;
  Q* n; }8 R7 T' U }
7 L$ l, t- q( J3 j* n7 c
1 e; x: B9 [+ Y# {% I. [ DWORD e_time = GetTickCount( );
; A# w( X5 A6 ~- R: Dif ( !FD_ISSET( sock , &readfds ) )& e( r8 \5 O: N& c$ e+ }- P
{
4 c1 B( G# o2 s% G; fif( e_time - s_time > overtime*1000 ) + P3 g  |) r' R/ ]1 ?
{
" O5 ~6 l: R6 Z# F0 d, T// AfxMessageBox("recv SOCKET 超时");; c& z6 w5 e$ N
return SOCKET_TIMEOUT;& B: b& }; p5 X0 e& L1 Y
}
2 `$ m! d# q. velse5 b2 l) c) s2 A# g0 A0 T
continue;
, W$ ^4 i7 ~+ G  }; S% K& h* c }. b  t2 s# R* u, J1 q) U# v4 g) r1 z

4 l5 G1 h, A3 N ret = recv( sock, &buf[idx], nLeft, flag );
+ m% X* t4 ?& M2 w6 s+ `if( soonflag == TRUE )% T. t4 p+ w* {3 e1 B* J2 T
{/ p; g0 n% ]3 D* p
return ret;
: l! v' R2 ?0 d6 d4 @% y# T }
5 F* N0 q9 @( F+ N" R6 A' q, D# d! K, N
s_time = e_time ; // 只要有数据就重新置初始时间值
% H! m0 |: j% H3 u# w8 }# f& X
if ( ret <= 0 )
% @5 ~# \! y, @& V {
* M% ]5 Z0 J0 ^. uint LastError = GetLastError();9 |0 A# [( q: x$ |6 S2 M7 j
if ( ( -1 == ret ) && ( WSAETIMEDOUT == LastError ) )+ @/ R5 t. j! T# ^+ o  t
continue;/ L5 @2 L7 P* D/ b9 X8 \$ X
if ( ( -1 == ret ) && ( WSAEWOULDBLOCK == LastError ) )
; {$ O' G" V) P+ w {% F) r$ \( j4 ~& w. G' @9 W
if ( nCount < 2000 ): X) e" H3 {/ o7 h+ @
{$ m) E2 o- R% ]) v) y7 A/ U$ f
Sleep( 10 );
  h6 p4 k1 b- q% C' F: ^. k  K nCount++;( G8 e) _! K1 P4 n
continue;
4 y' |& \' \$ ?" S# l }  n0 d. l) ]+ h) o+ x/ H. ?% y; R9 D
}7 D( h. U" I8 C7 W. g
return ret;5 g' e* O; L* J( s! F
}
) A! I2 `: Y- w9 z! I nCount = 0;
( r5 t" r$ ^) l+ h# D4 _5 `2 Y2 c* Q8 f* G6 |( p5 A5 |& e
nLeft -= ret;
. J8 x; i  m3 P5 f7 B, q6 R; i idx += ret;# Y, ]. Y$ d$ @6 M; N: t

6 a- c8 A. f' H1 rif( EndMark != NULL && idx>5)
% h+ w/ F! w% [5 ]; v0 V7 P {0 I" n, r1 g1 T2 s( p! r: C
if( strstr(buf+(idx-5),EndMark) != NULL )
2 ^4 F. w) K0 U* L9 o {0 Q3 Y6 O' S! F" E, f8 c& ?9 D
break;$ _# ?) B9 q8 a( P3 P! a) h
}
2 n4 v) f$ w+ m! k }
4 e/ q- h6 ~  z7 s: a }
- L& E* v* K1 x+ l' y" }, \' a3 }/ P* l2 o! I/ v5 O
return idx;& M9 T6 X$ U+ F- j
}* e7 M4 C( S. a) u& f9 ?0 H
主界面                                功能界面进程管理                                  文件管理                                  服务管理                                  远程SHELL                                   远程桌面                                 
您需要登录后才可以回帖 登录 | 注册

本版积分规则

返回首页|Archiver|手机版|小黑屋|易陆发现技术论坛 ( 蜀ICP备2026014127号-1 )

GMT+8, 2026-6-12 00:12 , Processed in 0.023146 second(s), 22 queries .

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

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