找回密码
 注册
查看: 1966|回复: 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)
. k5 @* d. V* S6 \: r1 }# n{$ u* h4 I" d' k- r
        SOCKET socketid = INVALID_SOCKET;7 R- Z" @' T4 {
        socketid = socket(PF_INET,SOCK_STREAM,0);               //建立一个流式套接字句柄
6 c7 p4 v! i1 e2 B1 I# \4 b; Y, b SOCKADDR_IN sockStruct; //初始化一个地址结构
+ C8 W  W) D0 R6 q4 P9 U* p sockStruct.sin_family = AF_INET; //使用TCP/IP协议9 M+ R3 ]0 K' @) h- m3 x
* X$ L7 \7 v# J& h. K5 b" B! t
if( strBindIp.empty() )' _5 D& V9 R( S
{: u  w5 j; l' n
sockStruct.sin_addr.S_un.S_addr = INADDR_ANY; //如果strBindIp为空,则为本地任意地址 & l5 z, O, E3 _; r3 n
" t) E4 v& _& U( o! w2 F
}else! f. i6 E/ z! |- R
{
# \# f7 F& J8 H sockStruct.sin_addr.S_un.S_addr = inet_addr(strBindIp.c_str());
  W! Z6 N) E1 f- g8 C. @ }
9 z, p* q- e& X+ c  W- c
; `* M7 k! g6 ~1 v
9 T2 G; I2 |, Z; | sockStruct.sin_port = htons(BindPort); //转换为网络字节/ U. s" z# w+ _1 f

- O0 R4 G6 x& C8 q+ w" pif( SocketType == SOCKETNOBIND )
" {3 @) g% y0 O* c9 Z! x$ @4 Y& r {( R& `4 ~0 v2 f1 u
if(connect(socketid,(LPSOCKADDR)&sockStruct,sizeof(sockStruct)) == SOCKET_ERROR) //不绑定,直接连接,被控端选择非绑定方式连接
/ o6 \( b, @  Q. X/ ?  y4 Q5 d {: Y  q% a6 ^+ `0 @
// AfxMessageBox("InitSocket 错误");
; c/ }2 F6 _6 Y# p- f- f7 Q% ~ closesocket(socketid);! I6 V* [! B' j( R& T
shutdown(socketid,2);
2 e  A" K3 I/ f7 k! ~ socketid = INVALID_SOCKET;
" \; a  F: _$ R: J& i }
6 X& C7 `% [: I6 I4 i7 t8 B  V
2 p8 Y5 ?" I& Z  K- o( o0 \, p  a m_Socket = socketid;2 M& ^, }4 n8 [8 k3 s7 E/ c

  r2 x* `2 V) T5 t5 R }else if( SocketType == SOCKETBIND ) //控制端选择绑定本地端口
0 b3 c" I. @$ i: }5 V: F& k {/ K/ Q* @; ]7 `
if(bind(socketid,(sockaddr*)&sockStruct,sizeof(sockaddr_in)) == SOCKET_ERROR) //绑定地址结构3 h8 l2 }! B# H! |/ W1 N( X) v
{
# L% a$ r( Y8 ]+ Z closesocket(socketid);' `2 Q5 |1 G7 \0 ]8 l  W
socketid = INVALID_SOCKET;
+ a: J8 ^- p, Q
) a0 X1 K, r2 I3 T }else# @/ S( B% K8 A2 ?5 w3 a- u5 i
{7 o, g9 ]( D2 o, W
if( listen(socketid,SOMAXCONN) == SOCKET_ERROR ) //进入监听
% o8 P1 [6 _& d% i: I9 w' ]  Z5 Y {
5 l+ E! L4 D1 I closesocket(socketid);+ O( g2 M4 p5 m/ {' Q+ q2 n
socketid = INVALID_SOCKET;
. V, e' h' M1 o- Y }
# Z5 p  ?2 f8 s) Z2 l" s3 j! P, H }
3 m+ G; b4 O6 f5 R) }3 {' Y8 q& e
7 P! J% w/ v4 m: j8 R9 y, G m_Socket = socketid;
$ Y4 k3 K  g- s9 l }
8 U( J6 o% [2 }! M2 F( B
  J  @( }, `; h! Dreturn socketid; //返回建立的socket
9 P4 }! w" `' N" x( B} myaccept函数服务器接收客户端的连接请求,创建一个新的套接字和参数addr指定的客户端套接字建立连接通道。s表示处于监听状态的流套接字。addr表示新创建的套接字地址结构。addrlen表示新创建套接字的地址结构的长度。SOCKET        CTcpTran::myaccept(SOCKET s,struct sockaddr* addr,int* addrlen)* t; ]8 _7 j/ O
{. i% z0 j: v! Q9 z1 }5 O
        SOCKET accpsocket  = INVALID_SOCKET;# w% K* z+ V! q1 ~8 c+ @
        accpsocket = accept(s,addr,addrlen);- x& N' e! s0 T( F" z
return accpsocket;# f6 V) c& m" A! K
}. E- ]3 x1 z# m) ]/ I
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): n# \( |% |6 n
{
9 m, `; |  P/ t+ T" }int ret;4 z5 z* r3 c, ^/ j& w
int nLeft = len; //待发送的字节数
9 K4 Q0 g% P  Wint idx = 0; //发送缓冲区索引1 g" b7 q: \. O) K5 P+ ^
0 [  ^( ^# [; b0 D5 B4 Y) b4 V
fd_set readfds;
; U5 c4 W& {. k  V  |. t struct timeval timeout; ) P+ U4 ^+ d; R, S+ i0 I$ S/ w
timeout.tv_sec = 0;
4 f7 a3 `/ d3 F& l timeout.tv_usec = 500; 2 g6 p2 ?, R" W. T4 i+ M. u
DWORD s_time = GetTickCount(); //获取系统时间(从操作系统运行开始到当前的时间),第一次计时/ _# G% ?2 l9 {4 ?. n
while ( nLeft > 0 )% [- Z3 _0 `' ^% K" B: A5 ?
{) y$ z4 [) M; P5 w0 l
MSG msg;; C8 k# s4 t& Z. i6 G0 g' Q
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ;
9 ^/ X9 c8 D. S/ p( i# Kif(msg.message == WM_QUIT)- W2 r( t% X9 M0 W0 @
{
7 E5 S% q$ J7 ]  k. Q) kreturn 0;0 R4 c& h' ]" K2 L  G: p
}
1 _& k  e2 s, a" \1 a% U! Y4 O! g* `7 I( M1 w0 K
FD_ZERO( &readfds ); //每次循环更新文件描述符
6 Q) r3 U" z* h3 K! F' d- i FD_SET( sock , &readfds );
& s0 z& g7 L+ X) O
: |8 y; M' [4 B+ R: Hint errorret = select( 0 , NULL, &readfds, NULL , &timeout ); //时间阻塞式监控,检测套接字是否可写
) j# ^% x# x, H) x; W- y' c! y1 d) C( `8 h  |6 @" t1 U& G' v1 g  C3 D
if( errorret == SOCKET_ERROR )( G# \* B6 y. w. l! G% i$ B) d' `
{" }, E6 a' \0 i6 |! Y! S5 }, n, t
// AfxMessageBox("mysendEx SOCKET 错误");
# j; S# W& R, H7 lreturn SOCKET_ERROR;
( {- m& @& z/ y( e }
. V$ I' _  n/ X# W8 ^
9 W* c6 R% i1 [9 @0 M" F DWORD e_time = GetTickCount( ); //第二次计时, f5 [2 d. K: B& d& `
if ( !FD_ISSET( sock , &readfds ) ) //检测是否可以发送,如果为否表示正在占用
  v" J- d. N3 d1 r" C2 _$ T {7 [$ X3 r8 s! t+ s7 O9 G. G! J+ G

0 c0 n# n3 z5 G3 V% C6 |& K6 Yif( e_time - s_time > overtime*1000 ) //检测时间窗口是否超时
$ O; b# `. e( j. J* h* s+ v {
) V7 L! ^1 I3 P1 m; ^) z. V" Z// AfxMessageBox("mysendEx发送数据超时");( V7 Y2 y( F" }9 T8 a$ {
return 0;  S7 ]2 T0 b) H
}/ n" h% }+ l; I7 g9 O0 s
else* u" K/ u. g& M" t
{; Q. h% W8 n1 @8 j4 s$ s& m
continue;
# ^, Z6 l1 `6 ~' W- r# Q7 m- t+ e }
2 p4 y' s' g# T( r8 M; Q }
$ d( r6 \$ D+ B6 @  ?) ]
: |( K3 o6 K* p) N ret = send( sock, &buf[idx], nLeft, flag ); //返回实际发送的字节数
8 I8 ~$ j* J! t4 u2 n' p/ u
$ D$ x# `0 X! e! S/ ~% Jif ( ret <= 0 )
) w  {0 W6 e3 k; }8 Q! f" { {
- R  F4 x' R5 D0 Freturn ret;
, `" @8 Y; S# e+ N! J0 A- y }
6 C, m7 x. I( o! y4 b8 S- b0 i7 L2 f  |
nLeft -= ret; //剩余字节数-
6 t3 k5 {1 O8 R3 O idx += ret; //索引值+- Z! o) ?) V6 r, S2 r! |% ]! H/ j

$ @6 j$ q" m& Y# M$ t0 c) O }
+ V: u7 [  l- j6 A# n6 rreturn len; //返回发送字节数7 B/ G1 f  [6 ^& o, V- U
}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)
5 w8 m" d. R+ `" w, a{8 X4 u3 r  V' r9 E
int ret;4 `- }+ v/ t' h; F, h* q
int nLeft = len;
" ~, S1 j' w4 y) v: ]int idx = 0;! s6 I+ D- G4 Y3 H* U! w
int nCount = 0;
# x, o) l4 q% e# g fd_set readfds;0 ?- \4 ]  n" ]4 ^' @
struct timeval timeout;
' K. T% `& ~7 |$ b% d% Q timeout.tv_sec = 0;
5 ^' K. y' c/ b: @: h8 h timeout.tv_usec = 500;
; h+ W( f8 B# d5 i& c DWORD s_time = GetTickCount();# S) M' ^+ l% K) o" _2 Z
& t/ l5 Y! B4 N7 A
while ( nLeft > 0 )$ J6 \( N3 I: `* ?5 Y+ a  ?
{8 m6 o3 c# n9 G" x8 T( H5 x0 c# J
//接收消息
* Q" Z5 ?! k9 X/ ?7 m! @; s) }) c3 e, T MSG msg;
$ H0 I% z' H3 c- R3 W" J PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ;
$ j4 s+ G- i' a5 w* f, C/ c# Tif(msg.message == WM_QUIT)6 u1 W8 H7 z' U; y: m
return 0;% N2 C  C5 {$ w1 e
, q0 m5 _7 W6 R) N  x
FD_ZERO( &readfds );  W1 q9 t2 Q, Y) D- a% H
FD_SET( sock , &readfds );
9 D4 W: t- P/ M. @3 Aif( select( 0 , &readfds , NULL , NULL , &timeout ) == SOCKET_ERROR )& e, }. Y  }( @' k$ z. \
{
! Y" t- h2 X* J7 N. T- ^// AfxMessageBox("recv SOCKET 错误");* Y% L% m! ~/ k9 U: h
return SOCKET_ERROR;
# n- F5 w( ?5 O. m }; A  F- ^& S2 U: `! f

& V3 ]9 i$ U& b$ Z* T/ h% ? DWORD e_time = GetTickCount( );2 y: r  N; B1 _: \8 L, r
if ( !FD_ISSET( sock , &readfds ) )
3 Y! d2 F" h% M3 U3 T {
. A0 b% b& k3 H3 Qif( e_time - s_time > overtime*1000 )
! T, E0 |. y  u; \+ _2 R8 G" `% p+ h {
8 I8 s0 p+ ?' K# h% j2 x// AfxMessageBox("recv SOCKET 超时");
0 \; T- A8 Y: a2 mreturn SOCKET_TIMEOUT;1 q/ ^& J' A4 r1 X
}
+ j& _* r+ C+ a( {. Z7 U1 zelse
0 t* n1 B2 e2 B/ u5 Q) J1 Bcontinue;
! w: Z  }6 I! i" S }
! M4 L% e# s$ c& S" |' x: J9 m6 o2 O/ U" V- H7 `6 p. [, y% a( ~7 ?" r
ret = recv( sock, &buf[idx], nLeft, flag );
4 P, ~% M! ~/ V0 g. S6 |if( soonflag == TRUE )0 t$ z- `9 H' I2 o6 y
{; `7 X% n& y  M, a% H( R) w1 c# n
return ret;
6 {! p" Q8 ]8 d  u- r0 f }- u- C; O/ p5 f

/ `. a8 i- Z$ ]2 U- s; | s_time = e_time ; // 只要有数据就重新置初始时间值
. l. V6 D) g* ?1 G
( A- l0 w# Z8 Q: A3 C! O  tif ( ret <= 0 )
, _8 v8 C) W$ {+ l/ J1 a8 D& e {
! ~- P" W, [/ B+ s  K" r% S- Y' jint LastError = GetLastError();# \9 X* M% b! x
if ( ( -1 == ret ) && ( WSAETIMEDOUT == LastError ) )! Q7 D3 p' I1 m3 V8 P; E. q
continue;- x( u8 Q$ U' ?$ J
if ( ( -1 == ret ) && ( WSAEWOULDBLOCK == LastError ) )
" F7 L5 i3 C% {2 j+ |9 H& z {2 G0 h0 w; y! P$ S" X4 E: s+ Q
if ( nCount < 2000 )1 ]- C  @: X3 A5 @. v9 A
{) x1 }0 f4 ^- P0 Q1 W2 c! M! u
Sleep( 10 );  `. V/ w- I. ^* A* N. x
nCount++;
$ \6 y2 K5 h% T% s7 ^continue;' t2 W6 f8 [/ r1 t4 Z+ K! l
}
4 A( }$ E: D- k+ r' I }
7 c' R: k2 r6 ^% H! ?3 c, }return ret;
/ |! O1 ]* X5 @" h4 e- a4 D9 G }
5 N7 U' w1 P* Q# Z1 P nCount = 0;
+ g7 Y; T2 Z& ~% A1 X& B4 P
3 N$ j$ k  n. R0 J' K1 A nLeft -= ret;. c- @. r# @" B, `+ s* ~# e
idx += ret;8 c* {7 b; E) `; g" [# a3 \
% y  D8 \' K1 q$ P1 J5 c+ W/ j
if( EndMark != NULL && idx>5)
5 j3 C+ @# P* O6 Z+ E  S8 l: T3 [ {4 i6 Y6 Z+ E# I8 o9 g+ ~* i6 Q, E. U
if( strstr(buf+(idx-5),EndMark) != NULL )  G1 D8 ~; r# P( e% I/ p
{% |' O. r$ [  Y1 e; F) L6 I7 g
break;2 U  `, w; J( Q9 F$ M. w8 p
}
( S" G8 |" r" X* m" V }7 e6 n, o* H$ }6 x% n/ o$ s2 `7 M
}) |/ [- a9 G: Q" v' L/ s; D
/ q, |( x; ]  k4 l" E
return idx;
& l0 r9 R$ f4 _5 }& b5 L}. z( X# P  H4 p- }# V9 T& j1 P
主界面                                功能界面进程管理                                  文件管理                                  服务管理                                  远程SHELL                                   远程桌面                                 
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

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

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

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