您的位置:首页 > 其它

编写简单代理程序

2010-02-27 01:34 99 查看
编写简单代理程序
masepu(本文已发于黑客防线,转载注明出处)

我们在使用各类网络程序时常常会接触到代理程序,如果是做网络攻击或木马控制时常称这类程序为跳板程序。我觉得跳板和代理的概念很相似,都是为运行在不同主机上的网络程序提供数据中转服务的,可以说代理和跳板程序就是网络信息的中转站,只是这类中转程序在不同的应用领域中所使用的不同称谓。它的作用主要是突破自身IP访问限制和隐藏真实的IP地址。比如在远程控制软件的使用过程中,经常会遇到被控端主机无法回连或是连接速度太慢的问题,又或是为了隐藏被控端IP地址,需要以一个中转主机作为连接跳板来防止控制端主机暴露。这些功能都可以通过简单的跳板代理予以实现。程序的结构示意如图1所示:

图1 结构示意图
在没有使用代理的情况下,客户端直接连接到服务端的指定端口,并与其建立起连接。在使用代理的情况下,客户端首先连接到代理跳板主机的指定端口,同代理服务器建立起连接,同时代理服务器会主动连接服务端的指定端口,并与之建立起连接。这样,客户端发往代理服务器的数据都会被原封不动的转发到服务端,而服务端返回的数据也会被代理服务器原封不动的转发到客户端。这样,对于客户端和服务端来说,就像直接连接通信一样,代理服务器作为它们之间的中间人,只需简单的把从一个socket获得的数据发送到另一个socket当中,这样就实现了一个端口转发的简单代理程序。
在VC++6.0下,开始编写这个简单的代理程序。首先是要和服务端程序一样,监听服务端口,等待客户端程序连接。当有客户端连接进入时,代理程序接受该连接并返回新的socket,此socket就是代理服务器与客户端的通信接口,我们称为socket A,同时再创建一个与服务器监听端口的连接,并返回连接socket,为了表述方便,我们这里称之为socket B 。之后监听端口继续监听,等待其它客户端程序的连接。而已经连接的socket A和socket B会被传递给一个新开的线程,此线程专门负责程序与该客户端的通信。该线程不断地监视着socket A和socket B,一旦某个socket接收到数据就会向另外一个socket发送出去,代理程序就这样不断地转发数据,实现了简单的代理功能。代理程序在为多台客户端连接提供代理的情况下,其连接示意图如图2所示:

图2 多客户端连接示意图
以下代码是代理程序监听,当有新连接就接受并创建与服务端连接和开启新线程处理的代码:
SocketListen=socket(AF_INET,SOCK_STREAM,0);
if(SocketListen<=0)
{
return;
}
struct sockaddr_in srvaddr;
srvaddr.sin_port=htons(ClientPort);
srvaddr.sin_family=AF_INET;
srvaddr.sin_addr.s_addr=htonl(INADDR_ANY);
setsockopt(SocketListen,SOL_SOCKET,SO_REUSEADDR, (char*)&on,sizeof(on));
bind(SocketListen,(struct sockaddr *)&srvaddr,sizeof(struct sockaddr))
if(listen(SocketListen,8)<0)
{
return;
}
while(1)
{
SocketClient=accept(SocketListen,(struct sockaddr *)&remote,&size);
SocketServer=socket(AF_INET,SOCK_STREAM,0);
ConnectHost(SocketServer,ServerHost,ServerPort);
sock.fd1 = SocketClient;
sock.fd2 = SocketServer;
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ClientThread, (LPVOID)&sock, 0, &dwThreadID);
Sleep(1000);
}
新线程负责监测socket,当socket有数据收到时会通过另一socket发送出去,以下是新线程的处理函数代码(其中省略部分代码):
while(1)
{……
result=select(maxfd,&readfd,&writefd,NULL,×et);
if(FD_ISSET(fd1, &readfd))
{
if(totalread1<MAXSIZE)
{
read1=recv(fd1, read_in1, MAXSIZE-totalread1, 0);
memcpy(send_out1+totalread1,read_in1,read1);
totalread1+=read1;
memset(read_in1,0,MAXSIZE);
}
}
if(FD_ISSET(fd2, &writefd))
{
while(totalread1>0)
{
send1=send(fd2, send_out1+sendcount1, totalread1, 0);
sendcount1+=send1;
totalread1-=send1;
}
}
if(FD_ISSET(fd2, &readfd))
{
if(totalread2<MAXSIZE)
{
read2=recv(fd2,read_in2,MAXSIZE-totalread2, 0);
}
if(FD_ISSET(fd1, &writefd))
{
while(totalread2>0)
{
send2=send(fd1, send_out2+sendcount2, totalread2, 0);
if(send2==0)break;
if((send2<0) && (errno!=EINTR))
{
break;
}
if((send2<0) && (errno==ENOSPC)) break;
sendcount2+=send2;
totalread2-=send2;
}
if(err2==1) break;
if((totalread2>0) && (sendcount2 > 0))
{
memcpy(send_out2, send_out2+sendcount2, totalread2);
memset(send_out2+totalread2, 0, MAXSIZE-totalread2);
}
else
memset(send_out2,0,MAXSIZE);
}
Sleep(5);
}
程序编写完成后就可以使用了。这里我下载了黑防上的“上兴远程控制软件”,来测试效果。配置一个上兴被控端,地址和端口都指定为代理软件所在的主机地址和监听的端口。然后在跳板主机上运行我们写好的代理程序,指定监听端口、要连接的上兴控制端地址和端口。打开上兴控制端程序,运行上兴被控端,我们即可看到主机上线了,多台主机效果一样好,使用远控的各类功能,一切正常。如图3所示:

图3 正常上线
这个简单的代理程序编写完成了。利用端口转发实现了跳板代理的功能。程序可以继续加上登录认证等功能。我开始没有采用非阻塞socket编写,而是使用阻塞socket和多线程结合来实现端口数据转发,虽然效果是一样的,但是在看了其他人写的类似程序后还是觉得利用select函数来实现非阻塞socket方式更加高效和简便。祝大家节日快乐。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: