SCAN
Portas abertas
Quantos de vocês trancam a porta de suas casas ao anoitecer, ou até mesmo à luz do dia? Acredito que a maioria. Com o forte avanço da Internet em todo o planeta nos deparamos com o mesmo problema em nossos computadores: portas abertas.
Neste artigo iremos desenvolver um aplicativo para scannear e apresentar as portas que estão abertas num determinado servidor.
Para facilitar a compreensão de todos, estou apresentando um exemplo muito simples, onde o usuário informa o Nome do Servidor (ou endereço IP), e o intervalo de portas a serem scanneadas.
Os leitores com conhecimentos mais avançados ou know-how em Threads irão me crucificar por falta das benditas. Acontece que o principal objetivo deste exemplo é demonstrar o uso do componente TCPClient, e não do uso de Threads. Isso iria complicar um pouco a compreensão dos nossos amigos leitores.
Aos amigos que se encaixam neste perfil, minhas sinceras desculpas. Bem, continuando, agora vem a parte boa: mão-na-massa. Vamos iniciar um novo projeto no Delphi (grave a unit como un_scan.pas e o projeto como pscan.drp) e inserir os objetos que seguem:
Objeto |
Propriedade |
Valor |
TPanel |
Align |
AlTop |
Caption |
| |
Name |
PnTopo |
Com o foco no objeto pnTopo insira os seguintes objetos:
Objeto |
Propriedade |
Valor |
TLabel |
Caption |
HOST |
Left |
16 | |
Top |
14 |
Objeto |
Propriedade |
Valor |
TLabel |
Caption |
Porta Inicial |
Left |
16 | |
Top |
43 |
Objeto |
Propriedade |
Valor |
TLabel |
Caption |
Porta Final |
Left |
232 | |
Top |
43 |
Agora vamos inserir os objetos de controle e interatividade com o usuário. Mantenha o foco no objeto pnTopo e insira os seguintes objetos:
Objeto |
Propriedade |
Valor |
TEdit |
Name |
Nome do Servidor |
Left |
104 | |
Top |
10 | |
Width |
290 |
Objeto |
Propriedade |
Valor |
TSpinEdit |
Name |
Inicio |
Left |
104 | |
Top |
40 |
Objeto |
Propriedade |
Valor |
TSpinEdit |
Name |
Fim |
Left |
320 | |
Top |
40 |
Neste ponto vamos inserir o botão para iniciar o processo de scanner de portas.
Objeto |
Propriedade |
Valor |
TButton |
Name |
BtScan |
Caption |
Scan | |
Left |
416 | |
Top |
8 |
Com isso concluímos a primeira etapa do projeto. Prosseguindo, vamos criar o módulo de saída das informações.
Agora com o foco no formulário e não mais no objeto pnTopo, insira um objeto do tipo Tpanel alterando as seguintes propriedades:
Objeto |
Propriedade |
Valor |
TPanel |
Name |
PnDados |
Align |
AlCliente |
Vamos inserir os objetos deste painel, como segue:
Objeto |
Propriedade |
Valor |
TButton |
Name |
ListadePortas |
Height |
180 | |
Left |
16 | |
Top |
76 | |
Width |
500 |
Dentro deste mesmo painel pnDados, insira outro objeto do tipo TPanel alterando as propriedades que seguem:
Objeto |
Propriedade |
Valor |
TPanel |
Name |
PnProgresso |
Caption |
| |
Height |
65 | |
Left |
16 | |
Top |
8 | |
Width |
500 |
Com o foco no objeto pnProgresso insira os seguintes objetos:
Objeto |
Propriedade |
Valor |
TButton |
Name |
BtParar |
Caption |
Parar | |
Left |
400 | |
Top |
32 |
Objeto |
Propriedade |
Valor |
TProgressBar |
Name |
ProgressBar1 |
Width |
470 | |
Left |
16 | |
Top |
8 |
Objeto |
Propriedade |
Valor |
TLabel |
Caption |
Scaneando Porta... |
Left |
16 | |
Top |
36 |
Objeto |
Propriedade |
Valor |
TLabel |
Caption |
0 |
Left |
112 | |
Top |
36 |
Ufa !!! E para concluir a “enorme” lista de objetos, insira um do tipo TTCPClient que se encontra na seção Internet.
Objeto |
Propriedade |
Valor |
TTCPClient |
Name |
TCPClient1 |
Codificando o Projeto
Finalmente vamos codificar o nosso projeto. Crie uma variável global pertencente a nossa classe Form1 com o nome Parar, do tipo Integer; veja:
var
Form1: TForm1;
parar:integer; // variavel auxiliar
implementation
A variável Parar será utilizada para finalizar o processo de Scanner das Portas. Neste ponto é que poderíamos criar uma Thread, mas não vamos complicar.
Só para aliviar um pouco a forte tensão, vamos dar uma olhadinha na interface do nosso projeto:
Figura 1. Projeto Port Scanner
Vamos codificar o botão btScan, responsável pelo núcleo do nosso projeto. No evento onClick do objeto btScan, insira o código que segue (para facilitar, numerei as linhas de programação, de forma que possamos analisar melhor o código).
001 procedure TForm1.BtScanClick(Sender: TObject);
002 var i:integer;
003 begin
004 try
005 ListadePortas.Clear; // Limpa a Lista de Portas
006
007 parar:=0; // 0 = continua, 1 = conclui
008
009 // Definições da barra de progresso
010
011 ProgressBar1.Max:=Fim.Value;
012 ProgressBar1.Min:=Inicio.Value;
013
014 PainelProgresso.Visible:=True;
015 TcpClient1.RemoteHost := NomeServidor.Text;
016
017 for i := Inicio.Value to Fim.Value do
018 begin
019 if parar=1 then break; // finaliza o laço
020
021 ProgressBar1.Position:=i;
022 porta.Caption:=inttostr(i);
023
024 Application.ProcessMessages;
025 TcpClient1.RemotePort := inttostr(i);
026 TcpClient1.Active:=true;
027
028 if TcpClient1.Connect then
029 ListadePortas.Lines.Add('Porta ['+ inttostr(i) +'] aberta');
030
031 TcpClient1.Disconnect; // disconeta porta
032
033 end; //for loop
034 except
035 on E:Exception do begin
036 ListadePortas.Lines.Add('Erro: ' + E.Message);
037 end; // end on do begin
038 end; // end on do begin
039
040 ListadePortas.Lines.Add('Scaneamento das portas finalizado !');
041
042 PainelProgresso.Visible:=False;
043 end
Detalhamento do Código
A linha 002 declara uma variável “ i “ que irá auxiliar no laço de contagem das portas.
var i:integer;
Na linha 004 iniciamos uma proteção de erros da aplicação.
try
A linha 005 limpa o conteúdo do objeto ListaPortas.
ListadePortas.Clear
Na linha 007 inicializamos a variável parar com o valor 0, de forma que o sistema continue scanneando as portas até o limite solicitado pelo usuário, ou através do pressionamento da tecla Parar, fazendo com que a variável receba o valor 1
parar:=0;
As linhas 011 e 012 configuram o objeto ProgressBar1 de maneira que o mesmo fique compatível com as informações porta inicial e final. Com isso temos um progresso adequado.
ProgressBar1.Max:=Fim.Value;
ProgressBar1.Min:=Inicio.Value;
A linha 014 torna visível o objeto PainelProgresso.
PainelProgresso.Visible:=True;
A linha 015 configura o servidor remoto do objeto TcpClient1.
TcpClient1.RemoteHost := NomeServidor.Text;
A linha 017 inicia um loop baseado nas informações Porta Inicial e Final.
for i := Inicio.Value to Fim.Value do
Já na linha 019 nossa aplicação verifica se existe a obrigação de paralisar o loop. Esta informação vem do botão btParar.
if parar=1 then break;
A linha 021 posiciona a barra de progresso em relação ao andamento do loop.
ProgressBar1.Position:=i;
Na linha 022 apenas mostramos ao usuário através do objeto Porta, qual porta está sendo scanneada no momento
porta.Caption:=inttostr(i);
A linha 024 solicita ao Windows que processe as informações da aplicação, de maneira que a mesma não tenha o efeito congelamento.
Application.ProcessMessages;
A linha 025 configura a porta que deve ser scanneada, a 026 tenta ativar, e a 028 verifica se houve sucesso na ativação, e em caso afirmativo, a linha 029 adiciona no objeto ListadePortas a informação que a Porta está aberta.
TcpClient1.RemotePort := inttostr(i);
TcpClient1.Active:=true;
if TcpClient1.Connect then
ListadePortas.Lines.Add('Porta ['+ inttostr(i) + '] aberta');
A linha 031 disconecta a porta independente do seu estado (aberta ou fechada).
TcpClient1.Disconnect;
A linha 032 finaliza o loop. As linhas 033, 034 e 035 tratam qualquer exceção ocorrida no bloco protegido (try...except...end).
end; //for loop
except
0 on E:Exception do begin
ListadePortas.Lines.Add('Erro: ' + E.Message);
end; // end on do begin
end; //try block
Concluindo esta rotina, a linha 039 apresenta uma mensagem indicando o fim do scanneamento das portas, e a 041 torna o objeto PainelProgresso invisível.
ListadePortas.Lines.Add('Scaneamento das portas finalizado !');
PainelProgresso.Visible:=False;
Para concluir o nosso projeto, devemos codificar o botão btParar com o seguinte código (no evento OnClick):
Parar:=1;
Amigos, agora é só executar aplicativo, informar o nome do servidor (caso seu próprio equipamento, digite localhost, no campo Nome do Servidor), e o intervalo de portas a serem scanneadas.
Importante
Embora seja possível, não recomendo o uso deste aplicativo para scanear portas de servidores não-autorizados. Normalmente utilizamos este tipo de arquivo para vigiar nosso "quintal" e não o do vizinho.