Segundo a Wikipédia, Wireshark (anteriormente conhecido como Ethereal) é um programa que analisa o tráfego de rede, e o organiza por protocolos. As funcionalidades do Wireshark são parecidas com o tcpdump mas com uma interface GUI, com mais informação e com a possibilidade da utilização de dissectors.
O Wireshark permite o uso da linguagem de programação Lua para criação de novos dissectors. Esta funcionalidade é interessante quando se tem um protocolo privado e gostaria de facilitar a visualização dos dados trafegados com a utilização do Wireshark.
Como criar um dissector novo?
Vamos criar um dissector atrelado a porta UDP 50000 como exemplo. Para isso, vamos adicionar um novo dissector para trabalhar em cima de um protocolo já existente, no caso UDP, com os pacotes destinados a porta 50000. O Wireshark só repassa ao dissector uma parte do buffer. No nosso caso, somente será repassado ao dissector o conteúdo do buffer destinado a porta 50000.
Código do dissector
Conteúdo do arquivo novoProtocolo.lua:
-- Vamos criar um novo dissector e seus campos
p_novoProtocolo = Proto ("novoProtocolo", "Novo Protocolo")
local f_campo1 = ProtoField.uint16("p_novoProtocolo.campo1", "Campo1", base.HEX)
local f_campo2 = ProtoField.string("p_novoProtocolo.campo2", "Campo2", base.HEX)
p_novoProtocolo.fields = {f_campo1, f_campo2}
-- Função principal do dissector novoProtocolo
function p_novoProtocolo.dissector (buf, pkt, root)
-- É importante validar o tamanho do pacote recebido.
if buf:len() <= 0 then
return
end
-- Atribuição do nome que sera exibido na coluna "Protocol"
pkt.cols.protocol = p_novoProtocolo.name
-- Criação da subtree para o novoProtocolo
subtree = root:add(p_novoProtocolo, buf(0))
-- Adicionar os campos do novo protocolo ao subtree
subtree:add(f_campo1, buf(0,2)):append_text(" [Detalhes do Campo 1]")
subtree:add(f_campo1, buf(2,2)):append_text(" [Detalhes do Campo 2]")
-- Descrição do payload
subtree:append_text(", Alguns detalhes a mais.")
end
-- Rotina de inicialização.
function p_novoProtocolo.init()
end
-- Registrar um dissector atrelado a porta UDP 50000
local udp_dissector_table = DissectorTable.get("udp.port")
dissector = udp_dissector_table:get_dissector(50000)
udp_dissector_table:add(50000, p_novoProtocolo)
Rodando seu script Lua no Wireshark
Ainda é preciso algumas etapas antes de conseguir rodar o código acima. Se você tiver a versão 1.4 ou melhor, pule a etapa 3.
- Salve o script lua acima em qualquer pasta. (ex. C:\NovoProtocolo) e chame o arquivo de novoProtocolo.lua
- Abra o arquivo ini.lua, que se encontra no diretorio de instalação do Wireshark, para edição. Você precisará de privilégios de administrador no Windows Vista e 7.
- Comente a seguinte linha no arquivo init.lua (Para comentar uma linha basta usar — no inicio da linha):
disable_lua = true; do return end;
- Adicione o seguinte código abaixo no arquivo init.lua (no final dele):
NOVOPROTOCOLO_SCRIPT_PATH="C:\\NovoProtocolo\\" dofile(NOVOPROTOCOLO_SCRIPT_PATH.."novoProtocolo.lua")
Vide imagem abaixo da tela do Wireshark utilizando o Novo Protocolo.
Para validar o código demonstrado acima, é só baixar o pcap aqui.
Organização dos Dissectors
Entretanto é importante pensar na organização do código. Lua nos deixa bastante livre para decidirmos como organizar o código fonte. Você pode dividir seu código em quantos arquivos forem necessários e também coloca-los para serem carregados na ordem que você desejar. É possível carregar todos os arquivos na inicialização do Wireshark, ao colocar o código abaixo no final do arquivo init.lua no diretório aonde o Wireshark foi instalado.
PATH="C:\\NovoProtocolo\\" dofile(PATH.."arquivo1.lua") dofile(PATH.."arquivo2.lua") dofile(PATH.."arquivo3.lua") dofile(PATH.."arquivoN.lua")
Porem também é possível carregar seu código somente quando necessário, como no código exemplo abaixo:
if true then
dofile("C:\\NovoProtocolo\\arquivoN.lua")
end
Trabalhando com bitfields
A API Lua que o Wireshark usa não possui uma forma simples de se trabalhar com bitfield,porque eles só aceitam campos do tipo inteiro com máscara.
O wireshark 1.4.2 e anteriores tem um bug na API Lua. Eles só suportam bitfields (campos int com máscara), quando adicionado a um Proto definindo os campos do protocolo, assim como no exemplo abaixo:
-- criando novoproto e seus campos
p_novo = Proto ("novoproto","Novo Protocolo")
local f_bitfield = ProtoField.uint8("novoproto.bitfield", "Comando", base.HEX,
{[0]="Pacote Normal", [1]="Último Pacote"}, 0x40)
p_novo.fields = {f_bitfield}
Isso torna-se complicado caso você tenha um protocolo grande com vários bitfields, você terá que adicionar todos eles no inicio. Então coloco aqui uma função feita por Devendra Tewari que auxilia na exibição de bitfields.
-- Add a bit field to the dissection tree
-- buf - a tvb
-- subtree - dissection tree to which field will be added
-- offset - offset of the field within the tvb
-- size - number of octets containing the bitfield
-- bitfieldstart - start index of the bitfield, the highest bit is at 0
-- bitfieldlen - length of the bitfield to add
-- name - name of the field
-- valuestring - table containing description of bitfield value, can be nil
-- desc - description of the bit field
-- format - display format of the bitfield value, can be nil
function bitfield_add(buf, subtree, offset, size, bitfieldstart, bitfieldlen,
name, valuestring, desc, format)
local val = buf(offset, size):bitfield(bitfieldstart, bitfieldlen)
local binary=""
local i = bitfieldlen - 1
local intval = val
repeat
local result = intval % 2^i
if result ~= intval then
binary = binary.."1"
else
binary = binary.."0"
end
intval = result
i = i - 1
until (i < 0)
local dotted = string.rep(".", bitfieldstart)..binary
..string.rep(".", size*8-bitfieldstart-bitfieldlen)
local chunked = ""
for i = 0, size do
chunked = chunked..string.sub(dotted, 8*i+1, 8*i+4)
.." "..string.sub(dotted, 8*i+5, 8*i+8).." "
end
desc = chunked.." = "..desc
if format ~= nil then
desc = desc..": "..string.format(format, val)
end
if valuestring ~= nil then
if valuestring[val] ~= nil then
desc = desc.." ["..valuestring[val].."]"
end
end
subtree:add(ProtoField.uint8(name), buf(offset, size), desc)
end
Sua única limitação é que o Wireshark irá destacar todos os octetos que contêm o bitfield, se você ativar Bit View no painel mais abaixo (terceiro), o Wireshark não irá destacar somente os bits referentes ao campo de bits.
Como colorir seu protocolo no Wireshark
O Wireshark tem uma funcionalidade bem interessante e útil quando precisamos analisar grandes logs capturados. Ele nos permite configurar filtros para cada protocolo e assim colorir cada ocasião que aquele protocolo aparecer. Como pode ser visto na imagem abaixo:
- Para fazer isso basta ir no menu View/Coloring Rules…
- Clique no botão de criar novo, irá abrir uma nova janela.
- No primeiro campo dê um nome ao filtro que será criado.
- No segundo campo informe o nome do protocolo que será filtrado.
- Logo abaixo escolha as cores e dê ok.
- Posicione o seu novo filtro acima da camada onde seu protocolo roda. Por exemplo: Se o seu protocolo roda em cima de TCP, então coloque seu filtro logo acima do filtro de TCP.

home
blog de design do c.e.s.a.r.