用ASP.Net写追捕(上)

Posted on 2005-07-10 10:42  flourish  阅读(148)  评论(0)    收藏  举报
作者:http://www.aspcn.com 飞刀

程序是在.Net Framework Beta 1上调试的。现在新出来的Beta 2中是不能通过的。请大家自行修改。

前言:
ASP.Net已经出来一年了,虽然现在它还仅是个Beta产品,但是它所提供的功大功能以及SoftWare编程思想已经被越来越多的人所肯定(呵呵,没有想到微软的产品除了被骂以外还有能得到表扬的东东,这在微软的历史上是罕见的)。But飞刀我痛心地看到不少朋友,仍满足于ASP简单功能,甚至有人大声"疾呼":"不要学习ASP.Net,他和ASP差不多"。看到这些,飞刀便觉得非常有必要写一些文章来介绍ASP.Net的强大功能了。

正文:

冯志宏先生的追捕,相信大家都用过吧,我在这里也就不详细说明了。飞刀今天主要讲的是如何使用ASP.Net写一个与追捕同样功能的网页,我们就暂时将其命名为"WEB追捕"吧。
我们先对将要编写的ASP.Net程序有个感性认识,如图1,它所示的是用"WEB追捕"收集到的mail.sina.com.cn的主机信息。"WEB追捕"已经探测到这个主机的IP为202.106.187.150,来至"北京新浪网",操作系统是Unix,HTTP服务器是Apache,存在SMTP服务等,怎么样,和追捕差不多吧。
看到这些动心没有?真的动心了吗,那就马上拿出编辑器跟随飞刀一起来编写这个程序。

编写代码之前,我们需要给页面一个显示的框架,为了表现为追捕的WEB模拟程序,我们将模仿真正追捕的显示格式(大家在图1中可以看到显示格式)。

图1

图2

图3

<form runat="server">
<table border=1 >
<
tr>
<td width="70%">
<table >
<
tr><td><asp:TextBox id="IPHost" Width="200" runat="Server" /></td></tr>
<
tr><td><asp:Label id="OppFrom" ForeColor="White" runat="Server" /></td></tr>
<
tr><td>对方主机情况:</td></tr>
<
tr><td><br></td></tr>
<
tr><td>对方操作系统:<asp:Label Font-Size=9pt ForeColor="White" id="OppSystem" runat="Server" /></td></tr>
<
tr><td>HTTP服务:<asp:Label Font-Size=9pt ForeColor="White" id="OppHTTP" runat="Server" /></td></tr>
<
tr><td>FTP服务:<asp:Label Font-Size=9pt ForeColor="White" id="OppFTP" runat="Server" /></td></tr>
<
tr><td>Telnet服务:<asp:Label Font-Size=9pt ForeColor="White" id="OppTelnet" runat="Server" /></td></tr>
<
tr><td>Smtp服务:<asp:Label Font-Size=9pt ForeColor="White" id="OppSmtp" runat="Server" /></td></tr>
<
tr><td>POP3服务:<asp:Label Font-Size=9pt ForeColor="White" id="OppPOP3" runat="Server" /></td></tr>
<
tr><td>DNS服务:<asp:Label Font-Size=9pt ForeColor="White" id="OppDNS" runat="Server" /></td></tr>
</table>
</td>
<td width="30%">
<table>
<
tr><td><asp:Button id="btnHute" Type="submit" Text="追捕" OnClick="Hute_Click" runat="Server" /></td></tr>
<
tr><td><br></td></tr>
<
tr><td><asp:CheckBox id="chkMachine" Font-Size=9pt Text="检查对方机器" runat="Server" /></td></tr>
<
tr><td><asp:CheckBox id="chkHute" Font-Size=9pt Text="智能追捕" runat="Server" Checked /></td></tr>
</table>
</td>
</
tr>
</form>


为了体现ASP.Net的软件编程思想,飞刀这里全部使用Web 控件。
接下来,我们就需要来编写程序的真正代码了(摒住呼吸,激动人心的时刻就要来了)。

程序前面是在例行公事,列出所用的程序语言、联结Assembly以及导入所需的Namespace:

<% @ Page Language="C#" %>
<% @ Assembly Name="
System.Net" %>
<% @ Import Namespace="System" %>
<% @ Import Namespace="
System.Data" %>
<% @ Import Namespace="
System.Data.SQL" %>
<% @ Import Namespace="
System.Net" %>
<% @ Import Namespace="
System.Net.Sockets" %>
<% @ Import Namespace="
System.IO" %>
<% @ Import Namespace="
System.Text" %>

这些都是ASP.Net基础的东东,我不想在这里多费口舌,如果读者不太明白为什么要引用这些Namespace,请您去我们的站点http://www.aspcn.com查看系列教程《亲密接触ASP.Net》。

我们首先利用Page_Load事件来初始化所有Label控件:

public void Page_Load(Object src,EventArgs e)
{
OppSystem.Text = "待命中...";
OppHTTP.Text = "待命中...";
OppFTP.Text = "待命中...";
OppDNS.Text = "待命中...";
OppTelnet.Text = "待命中...";
OppSmtp.Text = "待命中...";
OppPOP3.Text = "待命中...";

OppFrom.Text = "测试中...";

//如果是非POST请求,则在
OppFrom控件中显示本机信息
if(!Page.IsPostBack)
{
string
LocalHost = DNS.GetHostName();
IPAddress LocalIP = DNS.Resolve(LocalHost);
OppFrom.Text = LocalHost+",就是你啊";
IPHost.Text = LocalIP.ToString();
}
}


这段程序中,需要注意一下的就是:
string LocalHost = DNS.GetHostName();
IPAddress LocalIP = DNS.Resolve(LocalHost);
这两行代码,它们的作用是取得本地主机名和本地IP。

接下来我们便要对后面显示的语句进行初始化:

public string strCome = "查不出";
public string
strHTTP = "没有HTTP服务";
public string
strFTP = "没有FTP服务";
public string
strDNS = "没有DNS服务";
public string
strTelnet = "没有Telnet服务";
public string strPOP3 = "没有POP3服务";
public string
strSMTP = "没有STMP服务";
public string
strSystem = "检测不出";

在定义的WEB控件的语句中可以看到,名为btnHute的Button控件,将会触发OnClick事件运行Hute_Click事件处理。Hute_Click是整个程序的核心,在这个事件处理中程序将完成所有"追捕"任务。

public void Hute_Click(Object src,EventArgs e)
{
string
strIPHost = IPHost.Text;

//检查地址的有效性,这个也可以用验证控件完成
if(-1==
strIPHost.IndexOf("."))
{
OppFrom.Text = "地址无效";
return;
}

//转换为
IPAddress实例
IPAddress OppIP = DNS.Resolve(strIPHost);
IPHost.Text = OppIP.ToString();
if(chkHute.Checked == true)
{
OppFrom.Text = GetIPFrom(OppIP.ToString());
}

//检测机器
if(chkMachine.Checked == true)
{
//初始化信息
OppSystem.Text = "测试中...";
OppHTTP.Text = "测试中...";
OppFTP.Text = "测试中...";
OppDNS.Text = "测试中...";
OppTelnet.Text = "测试中...";
OppSmtp.Text = "测试中...";
OppPOP3.Text = "测试中...";


//检查服务
DetectService(OppIP);
//检查特定的端口
DetectPort(OppIP);

//最后显示结果
OppSystem.Text = strSystem;
OppHTTP.Text = strHTTP;
OppFTP.Text = strFTP;
OppDNS.Text = strDNS;
OppTelnet.Text = strTelnet;
OppSmtp.Text = strSMTP;
OppPOP3.Text = strPOP3;

}
}

当名为chkMechine的CheckBox控件被选中后,程序将会检查目标主机,依照次序我们首先探测对方主机拥有哪些服务,程序中我们通过另外一个名为DetectService的函数来完成这个任务。
我们知道,服务器提供某项网络服务时,必须打开特定的端口来监听信息,而许多常用的服务,他们的端口通常是固定的(当然也可以人为的改动),比如端口21表示FTP服务,23表示Telnet服务,25表示SMTP服务等等。在一般情况下,只需要探测这些端口是否打开,就能判断目标主机哪些服务。
连接目标主机,通常是通过Socket完成的,这里使用System.Net.Sockets命名空间中提供的TCPClient类。
因为需要重复多次连接目标主机的不同的端口,所以我们还是写一个可以重复利用的函数来完成:

public string TcpConnect(IPAddress OppIp,int Port)
{
TCPClient tcp = new TCPClient();
StreamReader sr ;
if(0==
tcp.Connect(OppIp,Port))
{
//通过
StreamReader读取流中信息
sr = new StreamReader(tcp.GetStream(),Encoding.Default);
return
sr.ReadLine();
}
else
{
return "None";
}
tcp.Close();
}

在这个函数中,不仅试图连接目标主机的不同端口,而且还能读取连接成功后返回信息的首行信息。通过在这个首行信息中包含着该服务的版本类型。

设定好此函数后,在DetectService函数中引用它就是很容易的事情喽:

string TestFTP = TcpConnect(OppIP,21);
string
TestTelnet = TcpConnect(OppIP,23);
string
TestDNS = TcpConnect(OppIP,43);
string TestPOP3 = TcpConnect(OppIP,110);
string
TestSMTP = TcpConnect(OppIP,25);

if(TestFTP!="None") strFTP = TestFTP;
if(TestTelnet!="None") strTelnet = TestTelnet;
if(TestDNS!="None") strDNS = TestDNS;
if(TestPOP3!="None") strPOP3 = TestPOP3;
if(TestSMTP!="None") strSMTP = TestSMTP;

这里分别探测21、23、43、110、25端口来判断是否存在FTP、Telnet、DNS、POP3、SMTP等服务以及它们的版本信息。
当然飞刀也不会忘记HTTP这一重要网络服务,只是获取它的信息相对复杂一些:

//打开联结实例
TCPClient tcp = new TCPClient();

//开始测试HTTP服务

if(0==tcp.Connect(OppIP,80))
{
int OppHTTPStart;
int OppHTTPEnd;
string
strHTTPx;
string
sendmsg="POST /index.htm HTTP/1.1\r\n";
sendmsg += "Connection: Keep-Alive\r\n\r\n";

Stream
sm = tcp.GetStream();
//写入流,模拟POST请求
sm.Write(Encoding.Default.GetBytes(sendmsg.ToCharArray()),0,sendmsg.Length);
StreamReader sr = new StreamReader(tcp.GetStream(), Encoding.Default);

while (-1 !=
sr.Peek())
{
strHTTPx = sr.ReadLine();
OppHTTPStart = strHTTPx.IndexOf("Server");
//当发现返回数据流中包含有"Server"信息时,返回信息并退出
if(OppHTTPStart!= -1 )
{
strHTTP = strHTTPx;
break;
}
}
tcp.Close();
}


探测完服务器所提供的服务,接下来需要确认主机的类型。
首先检查对HTTP服务探测所获得的数据中是否存在主机的类型信息,然后再根据经验进一步通过HTTP服务器类型判断主机类型,最后是检测一些特定的端口判断主机类型。

//检查一些特定的端口,来确定主机的类型
public void
DetectPort(IPAddress OppIP)
{
//首先判断是
strHTTP中是否有信息
if(strHTTP.IndexOf("Microsoft")!=-1)
{
strSystem = "Windows";
if(strHTTP.IndexOf("IIS")!=-1)
{
strSystem = "Window NT /2000";
if(strHTTP.IndexOf("5.0")!=-1)
{
strSystem = "Windows 2000";
}
else
{
strSystem = "Windows NT";
}
}
}
else
if(strHTTP.IndexOf("Apache")!=-1)
{
strSystem = "Unix/Linux";
if(strHTTP.IndexOf("Unix")!=-1)
{
strSystem = "Unix";
}
}
else
{
if(TcpConnect(OppIP,139)!="None")
{
strSystem = "Win98/Me";
}
else if(TcpConnect(OppIP,1433)!="None")
{
strSystem = "Windows NT / 2000";
}
else
{
strSystem = "Windows/Linux/Unix";
}
}
}


这一步,主要是根据飞刀我的经验来确定探测内容,并不能保证一定完全正确。如果您对系统了解更深,那么您能写出更精确的探测方法。

对主机的探测程序已经写完,这时我们想想追捕的主要用途是什么,呵呵,是根据IP或域名来判断用户(或主机)的来源地。如果程序缺少这一环节,那么这不是一个追捕程序,顶多一个探测器而已,所以这个功能是必不可少。
下面就要接触本程序的核心代码了。

博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3