木马隐藏端口的一种方法.htm
来自「关于win2000核心编程的文章」· HTM 代码 · 共 166 行
HTM
166 行
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0059)http://jiurl.cosoft.org.cn/jiurl/document/NoPort/NoPort.htm -->
<HTML><HEAD><TITLE>Jiurl255</TITLE>
<META content="text/html; charset=gb2312" http-equiv=Content-Type>
<STYLE type=text/css>.title {
FONT-FAMILY: "黑体", Arial, sans-serif; FONT-SIZE: 21px; FONT-WEIGHT: bold; LINE-HEIGHT: 48px; TEXT-DECORATION: none
}
.author {
FONT-FAMILY: "宋体"; FONT-SIZE: 12px; LINE-HEIGHT: 16px
}
.content {
FONT-SIZE: 14px; LINE-HEIGHT: 20px
}
</STYLE>
<META content="MSHTML 5.00.2614.3500" name=GENERATOR></HEAD>
<BODY bgColor=#f7f7f7 topMargin=5>
<DIV align=center>
<CENTER>
<TABLE border=0 cellPadding=0 cellSpacing=0 height=29 width="96%">
<TBODY>
<TR>
<TD class=title height=41 width="100%">
<P align=center><FONT face=宋体>木马隐藏端口的一种方法</FONT></P></TD></TR></CENTER>
<TR>
<TD class=author height=9 width="100%">
<P align=center>作者: <A href="mailto:jiurl@mail.china.com">JIURL</A>
</P></TD></TR>
<TR>
<TD class=author height=6 width="100%">
<P
align=center>
主页: <A href="http://jiurl.yeah.net/">http://jiurl.yeah.net/</A> </P></TD></TR>
<TR>
<TD class=author height=2 width="100%">
<P align=center> 日期: 2003-1-13
</P></TD></TR></TBODY></TABLE></DIV>
<DIV align=center>
<CENTER>
<TABLE border=0 cellPadding=0 cellSpacing=0 height=1 width="96%">
<TBODY>
<TR>
<TD height=1 width="100%">
<HR color=#396da5 SIZE=3>
</TD></TR></TBODY></TABLE></CENTER></DIV>
<DIV align=center>
<TABLE border=0 cellPadding=0 cellSpacing=0 class=content height=6390
width="96%">
<TBODY>
<TR>
<TD height=376 vAlign=top width="131%">
<P>
这是一种很特殊的方法,使用它通讯没有端口,而且由于它的特殊性,也许会带来一些其他的优点。但这种方法也有一个比较大的缺点。<BR>
它,也许该起个名字,比如叫Jiurl255。它不使用tcp协议,也不使用udp协议,也不使用icmp协议。它使用什么协议,就像乱起的那个名字一样,它使用255协议。
<P><BR><IMG border=0 height=240 src="木马隐藏端口的一种方法.files/IPHEADER.gif"
width=546>
<P>上面这幅图,是一个没有IP选项的IP头。其中有个字段为8位协议,一个字节长,系统就是通过这个字节中的值来区别上层协议是什么,通过这个字节的值来决定应该把数据交给谁来处理。TCP是十进制6,UDP是十进制17。就是说这个值是6的话就交给tcp处理,是17的话就交给udp处理。那么如果这个值是一个没有人处理的值会怎么样呢?比如222,255(8bit,最大255)。我觉得255漂亮些,就拿255说吧,其他没人用的值都是一样的。那么会怎么样呢?我猜测可以收到的,后来做了些小试验,说明我是对的。(我曾夜观天象,发现你有学计算机的命)。这个东西和tcp,udp没什么关系,自然也就不会有tcp,udp的端口号了。
<P>好了,有兴趣的先试一试吧,使用Jiurl255做一次简单通讯的<A
href="http://jiurl.cosoft.org.cn/jiurl/document/NoPort/rclient.exe">客户端程序下载</A>,<A
href="http://jiurl.cosoft.org.cn/jiurl/document/NoPort/rserver.exe">服务器端程序下载</A>。<BR>服务器端叫rserver,客户端叫rclient。<BR>rserver
首先 theSocket = socket(AF_INET, SOCK_RAW,
255);建立一个使用Jiurl255的原始套接字,然后绑定本地地址,最后阻塞在recvfrom,等待着发往255协议的数据。收到之后,会将收到数据打印出来。<BR>rclient
首先 获得服务器的IP地址,然后 theSocket = socket(AF_INET, SOCK_RAW,
255);建立一个使用Jiurl255的原始套接字,然后让你从键盘输入些数据 就 sendto 用协议255向服务器端发送输入的数据。
<P>第一个试验,进行一次收发,就可以发现,确实是可以利用没人用的协议号发送和接收数据。大概是这样的,系统收到ip包以后看该协议号有没有进程要接受,如果有的话,就发给那个进程。
<P>第二个试验,运行一个rclient,运行两个rserver,发一次数据。可以发现,两个rserver都收到了rclient发的数据。说明系统会把收到的数据发给每个要接受这个协议号上数据的进程。
<P>另一个试验,server端创建套接字时,指定协议号为200,client端创建套接字,填充ip头时,都指定协议号为255,结果server端就收不到client端发送的数据了。
<P>当时试验后的笔记:"<BR>server端收数据<BR>client端发数据<BR>server端创建套接字时,指定协议号为255,<BR>client端创建套接字,填充ip头时,都指定协议号为255,<BR>结果server端收到了client端发送的数据。<BR><BR>server端创建套接字时,指定协议号为200,<BR>client端创建套接字,填充ip头时,都指定协议号为255,<BR>结果server端就收不到client端发送的数据了。<BR><BR>多个server端,都使用协议号255,<BR>client端也向255协议发数据,<BR>多个server端,都收到了数据。<BR>"
<P>还有就是,如果程序既发又收的,并且是发往本机的,那么程序会收到自己发出的内容。没说清楚好像,比如吧,一个程序,发255的数据之后,就接收255上的数据,他把数据发往本机,那么它就会收到数据。
<P><B>rclient:</B>
<P>#include <winsock2.h><BR>#include <windows.h><BR>#include
<stdio.h><BR>#include <ws2tcpip.h> <BR>#include
<conio.h><BR><BR>#pragma
comment(lib,"ws2_32.lib")<BR><BR><BR>typedef struct ip_hdr
//定义IP首部<BR>{<BR>unsigned char h_verlen; //4位首部长度,4位IP版本号<BR>unsigned char
tos; //8位服务类型TOS<BR>unsigned short total_len; //16位总长度(字节)<BR>unsigned
short ident; //16位标识<BR>unsigned short frag_and_flags; //3位标志位<BR>unsigned
char ttl; //8位生存时间 TTL<BR>unsigned char proto; //8位协议 (TCP, UDP
或其他)<BR>unsigned short checksum; //16位IP首部校验和<BR>unsigned int sourceIP;
//32位源IP地址<BR>unsigned int destIP; //32位目的IP地址<BR>}IP_HEADER,
*PIP_HEADER;<BR><BR><BR>USHORT CheckSum(USHORT *buffer, int
size);<BR><BR>void RawClient( char *szServer );<BR><BR><BR>void
main()<BR>{<BR>WSADATA wsaData;<BR><BR>char
ServerAddr[256];<BR><BR>printf("Server Addr :
");<BR>scanf("%s",ServerAddr);<BR>printf("\n");<BR><BR>WSAStartup(0x0202,
&wsaData);<BR><BR>RawClient(ServerAddr);<BR><BR>WSACleanup();<BR>}<BR><BR>/////////////////////////////////////////////////<BR>USHORT
CheckSum(USHORT *buffer, int size)<BR>{<BR>unsigned long
cksum=0;<BR><BR>while (size > 1)<BR>{<BR>cksum += *buffer++;<BR>size -=
sizeof(USHORT); <BR>}<BR>if (size)<BR>{<BR>cksum +=
*(UCHAR*)buffer; <BR>}<BR>cksum = (cksum >> 16) + (cksum &
0xffff);<BR>cksum += (cksum >>16); <BR><BR>return
(USHORT)(~cksum); <BR>}<BR><BR>//////////////////////////////////////////////////////////<BR>void
RawClient( char *szServer )<BR>{<BR>LPHOSTENT
lpHostEntry;<BR><BR>lpHostEntry = gethostbyname(szServer);<BR>if
(lpHostEntry == NULL)<BR>{<BR>printf("gethostbyname()
error\n");<BR>return;<BR>}<BR><BR>SOCKET theSocket;<BR><BR>theSocket =
socket(AF_INET, SOCK_RAW, 255);<BR>if (theSocket ==
INVALID_SOCKET)<BR>{<BR>printf("socket()
error\n");<BR>return;<BR>}<BR><BR>int nRet;<BR>BOOL
optval;<BR><BR>optval=TRUE;<BR>nRet = setsockopt(theSocket, IPPROTO_IP,
IP_HDRINCL, (char*)&optval, sizeof(optval));<BR>if (SOCKET_ERROR ==
nRet)<BR>{<BR>printf("SetSockOpt Error!%d\n",
WSAGetLastError());<BR>return;<BR>}<BR><BR>SOCKADDR_IN
saServer;<BR><BR>saServer.sin_family = AF_INET;<BR>saServer.sin_addr =
*((LPIN_ADDR)*lpHostEntry->h_addr_list); // Let WinSock assign
address<BR>saServer.sin_port = 0; // Use port passed from user<BR><BR>char
szBuf[1024];<BR><BR>//////////////////////////////////////////////////////////////////<BR>memset(szBuf,
0, sizeof(szBuf));<BR><BR>int IpHdrLen=0;<BR>int
DataLen=0;<BR><BR>IP_HEADER *pIpHdr=NULL;<BR>char*
pData=NULL;<BR><BR>IpHdrLen=sizeof(IP_HEADER);<BR><BR>pIpHdr=(IP_HEADER*)szBuf;<BR><BR>pIpHdr->h_verlen=(4<<4)|
(sizeof(IP_HEADER) / sizeof(unsigned
long));<BR>pIpHdr->tos=0;<BR>pIpHdr->proto=255;<BR>pIpHdr->ttl=128;<BR>pIpHdr->ident=0;<BR>pIpHdr->checksum=0;<BR>pIpHdr->frag_and_flags=0;<BR>pIpHdr->sourceIP=inet_addr("1.1.1.1");<BR>pIpHdr->destIP=(unsigned
int)saServer.sin_addr.s_addr;<BR><BR>pData=(szBuf+IpHdrLen);<BR>printf("Type
a String
:");<BR>scanf("%s",pData);<BR>DataLen=strlen(pData);<BR><BR>pIpHdr->total_len=IpHdrLen+DataLen;<BR><BR>//////////////////////////////////////////////////////////////////<BR>nRet
= sendto(theSocket, // Socket<BR>szBuf, // Data
buffer<BR>IpHdrLen+DataLen, // Length of data<BR>0, //
Flags<BR>(LPSOCKADDR)&saServer, // Server address<BR>sizeof(struct
sockaddr)); // Length of
address<BR>if(nRet!=SOCKET_ERROR)<BR>{<BR>printf("Client send:
%s\n",pData);<BR>}<BR><BR>getch();<BR>closesocket(theSocket);<BR>return;<BR>}<BR>
<P><B>rserver:</B>
<P>#include <winsock2.h><BR>#include <windows.h><BR>#include
<stdio.h><BR>#include <ws2tcpip.h> <BR>#include
<conio.h><BR><BR>#pragma comment(lib,"ws2_32.lib")<BR><BR>void
RawServer();<BR><BR>void main()<BR>{<BR>WSADATA
wsaData;<BR><BR>WSAStartup(0x0202,
&wsaData);<BR><BR>RawServer();<BR><BR>WSACleanup();<BR>}<BR><BR>//////////////////////////////////////////////////////////<BR>void
RawServer()<BR>{<BR>int nRet;<BR>SOCKET theSocket;<BR><BR>theSocket =
socket(AF_INET, SOCK_RAW, 255);<BR>if (theSocket ==
INVALID_SOCKET)<BR>{<BR>printf("socket()
error\n");<BR>return;<BR>}<BR><BR>SOCKADDR_IN
saServer;<BR><BR>saServer.sin_family =
AF_INET;<BR>saServer.sin_addr.s_addr = INADDR_ANY; // Let WinSock assign
address<BR>saServer.sin_port = 0; // Use port passed from user<BR><BR>nRet
= bind(theSocket, // Socket descriptor<BR>(LPSOCKADDR)&saServer, //
Address to bind to<BR>sizeof(struct sockaddr) // Size of
address<BR>);<BR>if (nRet == SOCKET_ERROR)<BR>{<BR>printf("bind()
error\n");<BR>closesocket(theSocket);<BR>return;<BR>}<BR><BR>///////////////////////////////////////////////////<BR>int
nLen;<BR>nLen = sizeof(SOCKADDR);<BR>char szBuf[1024];<BR><BR>nRet =
gethostname(szBuf, sizeof(szBuf));<BR>if (nRet ==
SOCKET_ERROR)<BR>{<BR>printf("gethostname()
error\n");<BR>closesocket(theSocket);<BR>return;<BR>}<BR><BR>LPHOSTENT
lpHostEntry;<BR>lpHostEntry = gethostbyname(szBuf);<BR><BR>printf("Server
named %s addr %s \n\n",<BR>szBuf,
inet_ntoa(*(LPIN_ADDR)lpHostEntry->h_addr));<BR>///////////////////////////////////////////////////<BR><BR>SOCKADDR_IN
saClient;<BR><BR>memset(szBuf, 0, sizeof(szBuf));<BR><BR>nRet =
recvfrom(theSocket, // Bound socket<BR>szBuf, // Receive
buffer<BR>sizeof(szBuf), // Size of buffer in bytes<BR>0, //
Flags<BR>(struct sockaddr*)&saClient, // Buffer to receive client
address <BR>&nLen); // Length of client address
buffer<BR>if(nRet!=SOCKET_ERROR)<BR>{<BR>printf("Server recv:
%s\n",szBuf+20);<BR>}<BR>else<BR>{<BR>printf("recv error:
%d\n",WSAGetLastError());<BR>closesocket(theSocket);<BR>return;<BR>}<BR><BR>getch();<BR>closesocket(theSocket);<BR>return;<BR>}<BR>
<P>使用Jiurl255进行数据传输明显是没有tcp和udp的端口的,这样也就不会被 netstat -an
之类的命令看到。这和利用icmp传输数据很象,但是我觉得Jiurl255比用icmp传数据要来的好一些。它还有个比较大的缺点就是,由于直接使用的是ip,所以传输的数据是有可能丢失的,这是我观察后写的笔记:"使用ip,ip头字段中的上层协议填255,这是一个还没有人用的协议号。然后在网络中两个主机上分别运行c,s程序,c发送ip255报文,内容hello
n,共发50个,每秒发一个。s收ip255报文,确实收到,一次测试中,50个报文,收到了49个,也确实存在ip报丢失的情况。两个方向上都试了,是可行的。"<BR>因此用此方法隐藏端口是要多费不少力气的,我自己写的一个程序中,传送文件使用了一些简单的等待ack,超时重发的机制保证数据不会丢失和发生错误,传送命令,没有保证不会丢失。有时间的话,准备写个保证不丢失,不错误的收发函数。传送文件用的那些机制,参考了使用udp协议进行文件可靠传输的tftp协议。
<P><B>终</B>
<P><A
href="http://jiurl.cosoft.org.cn/jiurl/document/NoPort/rclient.exe">编译好的客户端程序下载</A>
<A
href="http://jiurl.cosoft.org.cn/jiurl/document/NoPort/rserver.exe">编译好的服务器端程序下载</A>
<A
href="http://jiurl.cosoft.org.cn/jiurl/document/NoPort/JiurlNoPortShow.zip">源程序下载</A>
</P></TD></TR></TBODY></TABLE></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?