⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scanmain.pas

📁 多线程端口扫描演示
💻 PAS
字号:
//------------------------------------------------------------------------------
//  端口扫描主窗体单元ScanMain.pas(仅作为教学演示使用)
//  功能:实现端口扫描主界面,调用ScanPort单元中的主机扫描类TScanHostThread,
//        实现端口扫描功能
//  作者:邓飞 2004.7.  成都理工大学--计算机工程系
//  **声明:任何个人和团体均可以使用该单元文件,但需要保留原作者姓名**
//------------------------------------------------------------------------------
unit ScanMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection,
  IdTCPClient, ComCtrls, Buttons, CheckLst, ExtCtrls, Gauges,
  IdThreadComponent, IdTCPServer, IdWinSock2, ScanPort, IdIOHandler,
  IdIOHandlerSocket, IdIOHandlerStream, IdAntiFreezeBase, IdAntiFreeze,
  Spin, ImgList, IdThreadMgr, IdThreadMgrPool;

type
  TScanMainForm = class(TForm)
    BeginIPEdit: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    EndIPEdit: TEdit;
    ScanBtn: TSpeedButton;
    StopBtn: TSpeedButton;
    Panel1: TPanel;
    ResultTreeView: TTreeView;
    PortListBox: TCheckListBox;
    Splitter1: TSplitter;
    Label3: TLabel;
    ProgressBar: TProgressBar;
    IdAntiFreeze: TIdAntiFreeze;
    Label4: TLabel;
    TimeOutEdit: TSpinEdit;
    ResultImageList: TImageList;
    IPLabel: TStaticText;
    IdThreadMgrPool1: TIdThreadMgrPool;
    procedure FormCreate(Sender: TObject);
    procedure ScanBtnClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure StopBtnClick(Sender: TObject);
  private
    { Private declarations }
    FBeginIP: TIPArray;
    FEndIP: TIPArray;
    FIPWordList: TList;
    FPortList: TList;
    FScanThread: TScanHostThread;
    FScanNext: Integer;
    FTerminated: Boolean;
  protected
    procedure Init;
    procedure ClearIPWordList;
    procedure ClearPortList;
    procedure Scan;
    procedure ShowResult;
  public
    { Public declarations }
  end;

var
  ScanMainForm: TScanMainForm;

const
  //常用扫描端口
  CommonPorts: Array[0..29] of Integer =
  (7, 9, 13, 19, 21, 22, 23, 25, 53, 79, 80, 99, 110, 111, 113, 135, 139, 143,
   161, 443, 445, 514, 515, 808, 1080, 1433, 3306, 3389, 6000, 8080);

implementation

{$R *.dfm}

//----class TScanMainForm-------------------------------------------------------
procedure TScanMainForm.FormCreate(Sender: TObject);
var
  WSA: TWSADATA;
begin
  WSAStartup(makeword(2,2), WSA);
  FIPWordList:= TList.Create;
  FPortList:= TList.Create;
  FScanThread:= nil;
  FTerminated:= True;
  Init;
end;

procedure TScanMainForm.FormDestroy(Sender: TObject);
begin
  if FScanThread <> nil then begin
    if not FScanThread.Terminated then FScanThread.Terminate;
  end;

  ClearIPWordList;
  FIPWordList.Free;

  ClearPortList;
  FPortList.Free;
  WSACleanup();
end;

procedure TScanMainForm.Init;
var
  i, j: Integer;
  Port: String;
begin
  //加入常用扫描端口
  Port:= IntToStr(CommonPorts[0])+'->';   //在端口字符串后面加上'->'便于查找
  i:=0;   j:=Low(CommonPorts);
  while (i < PortListBox.Items.Count) and (j <= High(CommonPorts)) do begin
    //查找列表框中的第i项是否包含有,CommonPorts[j]中端口形成的Port字符串
    if StrPos(PChar(PortListBox.Items[i]), PChar(Port)) <> nil then begin
      PortListBox.Checked[i]:= True;   //将该项标记为真
      //增加j准备寻找下一个常用端口
      Inc(j);
      Port:= IntToStr(CommonPorts[j])+'->';
    end;
    Inc(i);
  end;
end;

procedure TScanMainForm.ClearIPWordList;
var
  i: Integer;
  p: PDWord;
begin
  for i:=0 to FIPWordList.Count-1 do begin
    p:= FIPWordList.Items[i];
    Dispose(p);
  end;
  FIPWordList.Clear;
end;

procedure TScanMainForm.ClearPortList;
var
  i: Integer;
  p: PInteger;
begin
  for i:=0 to FPortList.Count-1 do begin
    p:= FPortList.Items[i];
    Dispose(p);
  end;
  FPortList.Clear;
end;

procedure TScanMainForm.ShowResult;
var
  i: Integer;
  PortStr: String;
  IPArray: TIPArray;
  IPStr: String;
  HostNode, PortNode: TTreeNode;
begin
  DecodeIPDWordToArray(PDWord(FIPWordList.Items[FScanNext])^, IPArray);
  DecodeIPArrayToStr(IPArray, IPStr);
  HostNode:= ResultTreeView.Items.Add(nil, IPStr);
  HostNode.ImageIndex:= 0;

  for i:=0 to FPortList.Count-1 do begin
    if FScanThread.PortStates[i] then begin
      PortStr:= IntToStr(PInteger(FPortList.Items[i])^);
      PortNode:= ResultTreeView.Items.AddChild(HostNode, PortStr);
      PortNode.ImageIndex:= 1;
      PortNode.SelectedIndex:= 1;
    end;
  end;
end;

procedure TScanMainForm.Scan;
var
  IPArray: TIPArray;
  IPStr: String;
begin
  FScanThread:= nil;  FTerminated:= False;  FScanNext:= 0;  //设置初始化参数

  while FScanNext < FIPWordList.Count do begin  //循环条件(存在需要扫描的主机)
    IdAntiFreeze.Process;                       //防止界面冻结
    Sleep(125);                                 //睡眠125毫秒后再进行检查工作,这样可以避免连续循环让CPU满负荷工作
    //(1)检查用户是否终止扫描线程
    if FTerminated then begin                   //用户终止线程
      FScanThread.FreeOnTerminate:= True;       //将线程设为自动删除模式
      FScanThread.Terminate;                    //终止线程,当线程终止后会自行删除资源
      FScanThread:= nil;                        //将FScanThread设为nil,便于条件检查
      Break;
    end;
    //(2)检查线程是否已经完成主机的扫描工作
    if (FScanThread <> nil) and FScanThread.Terminated then begin   //已经完成
      //(2.1)向界面中添加节点
      ShowResult;
      //(2.2)增加扫描计数器释放已经完成的线程
      Inc(FScanNext);
      FScanThread.Free;
      FScanThread:= nil;
    end;
    //(3)检查上一次线程是否已经执行结束,是否需要为下一次任务分配新的线程资源
    if (FScanThread = nil) and (FScanNext < FIPWordList.Count) then begin
      //创建线程,设置扫描参数,执行线程
      FScanThread:= TScanHostThread.Create;
      FScanThread.SetHostIP(PDword(FIPWordList.Items[FScanNext])^);
      DecodeIPDWordToArray(PDword(FIPWordList.Items[FScanNext])^, IPArray);
      DecodeIPArrayToStr(IPArray, IPStr);
      IPLabel.Caption:= IPStr;
      FScanThread.SetPortList(FPortList);
      FScanThread.OutTime:= TimeOutEdit.Value;
      FScanThread.ProgressBar:= ProgressBar;
      FScanThread.Resume;
    end;
  end;

  FTerminated:= True;   FScanNext:= 0;    //扫描结束设置终止参数
end;

procedure TScanMainForm.ScanBtnClick(Sender: TObject);
var
  i, j: Integer;
  PPort: PInteger;
  PortStr: String;
  BeginIPWord, EndIPWord: DWord;
  PIPWord: PDWord;
begin
  //(1)设置界面元素
  ScanBtn.Enabled:= False;
  StopBtn.Enabled:= True;
  ResultTreeView.Items.Clear;
  //(2)建立需要扫描的端口列表
  ClearPortList;  //清空原来的端口列表
  SetLength(PortStr, 8);
  for i:=0 to PortListBox.Count-1 do begin
    if PortListBox.Checked[i] then begin    //如果该项被选中
      //将'-'前的端口数字保存到PortStr中(因为每一项的字串都是:端口->的形式)
      ZeroMemory(PChar(PortStr), 9);  //先将PortStr清空
      for j:=1 to StrLen(PChar(PortListBox.Items[i])) do begin //复制'-'前的数字部分
        if PortListBox.Items[i][j] = '-' then Break;
        PortStr[j]:= PortListBox.Items[i][j];
      end;
      New(PPort);
      PPort^:= StrToInt(Trim(PortStr));
      FPortList.Add(PPort); //加入新的端口
    end;
  end;
  //(3)建立需要扫描的主机列表
  //将用户填入的IP字符串转换成DWord类型的数字
  DecodeIPStrToArray(BeginIPEdit.Text, FBeginIP);
  DecodeIPStrToArray(EndIPEdit.Text, FEndIP);
  DecodeIPArrayToDWord(FBeginIP, BeginIPWord);
  DecodeIPArrayToDWord(FEndIP, EndIPWord);
  ClearIPWordList;  //清空原来的主机列表
  for i:=0 to EndIPWord-BeginIPWord do begin  //通过在起始IP和终止IP间递增得到全部的主机IP
    New(PIPWord);
    PIPWord^:= BeginIPWord+DWord(i);
    FIPWordList.Add(PIPWord);
  end;
  //(4)执行扫描
  Scan;
  //(5)恢复界面元素
  IPLabel.Caption:= '扫描完毕';
  ProgressBar.Position:= 0;
  ScanBtn.Enabled:= True;
  StopBtn.Enabled:= False;
end;

procedure TScanMainForm.StopBtnClick(Sender: TObject);
begin
  FTerminated:= True;   //将终止变量置为True,结束当前扫描线程
end;

end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -