Pull to refresh

Пишем плагин-диссектор для Wireshark – теперь на Lua

Статья написана под впечатлением от ранее опубликованной Пишем плагин-диссектор для Wireshark, в виде её продолжения.

В качестве альтернативы написанию плагинов на Си, Wireshark предлагает API для скриптовых языков – Lua и Python. К сожалению, оказалось, что в Windows-сборке Python до сих пор не поддерживается. Зато есть Lua.

Преимущества скриптового подхода:
  • Никакого шаманства с Makefile, сборками и пересборками плагина
  • Низкий порог входа – код проще для новичков и/или не знакомых с Си
  • Более компактная программа (что на данном примере практически незаметно)
Недостатки:
  • Скорость разбора протокола ниже, по сравнению с диссектором на Си
  • Плагины на Lua нельзя сделать частью дистрибутива Wireshark
Соответственно, алгоритм:
  1. Для быстрого прототипирования и отладки диссектор пишется на Lua/Python
  2. Далее, если необходимо, готовый уже прототип переписывается на Си
  3. Profit!


Напишем аналогичный плагин-диссектор для разбора протокола FOO, используя Lua. Сам протокол описан в RFC оригинальной статье, и здесь для краткости не рассматривается.

Настройка окружения


Первым делом запускаем Wireshark, и в окошке About проверяем, что сборка включает Lua:


Далее, находим файл init.lua в папке Wireshark. Убеждаемся, что расширение Lua включено:
disable_lua = false

Добавляем в конец файла путь к нашему плагину:
FOOPROTO_SCRIPT_PATH = "C:\\!my\\habr\\"
dofile(FOOPROTO_SCRIPT_PATH .. "foo_dissector.lua")

На этом подготовительная работа завершена, все просто.

Код диссектора


Я постарался сохранить авторские имена переменных и сделать вывод в Wireshark максимально похожим. Открываем foo_dissector.lua в текстовом редакторе и пишем:


p_foo = Proto("foo", "FOO Protocol")    -- Определение нового протокола

-- Текстовые отображения некоторых типов данных
packettypes = { "Ping request", "Ping acknowledgment", "Print payload" }
packetbool  = { [0] = "False",  "True" }

-- Заголовки протокола
local f_hdr_version = ProtoField.uint8("foo.hdr.version", 
                      "FOO Header Version", base.DEC, {"Version 1"})

local f_hdr_type    = ProtoField.uint8("foo.hdr.type", 
                      "FOO Header Type",    base.DEC, packettypes)

local f_hdr_flags   = ProtoField.uint8("foo.hdr.flags", "FOO Header Flags", base.HEX)

-- Битовые флаги
local f_hdr_flags_first   = ProtoField.uint8("foo.hdr.flags.first",   
                            "FOO first flag",   base.DEC, packetbool, 0x01)
local f_hdr_flags_second  = ProtoField.uint8("foo.hdr.flags.second",  
                            "FOO second flag",  base.DEC, packetbool, 0x02)
local f_hdr_flags_onemore = ProtoField.uint8("foo.hdr.flags.onemore", 
                            "FOO onemore flag", base.DEC, packetbool, 0x04)

-- Остаток заголовка и данные
local f_hdr_bool = ProtoField.bool  ("foo.hdr.bool", "FOO Header Boolean")
local f_pl_len   = ProtoField.uint32("foo.pl_len",   "FOO Payload Length")
local f_payload  = ProtoField.string("foo.payload",  "FOO Payload", base.STRING)

-- Регистрируем все поля протокола
p_foo.fields = { f_hdr_version,     f_hdr_type,         f_hdr_flags,
                 f_hdr_flags_first, f_hdr_flags_second, f_hdr_flags_onemore,
                 f_hdr_bool,        f_pl_len,           f_payload }

-- Собственно функция диссектора для протокола FOO
function p_foo.dissector(buf, pinfo, tree)
    if buf:len() == 0 then return end
    pinfo.cols.protocol = p_foo.name       -- в колонке Protocol будет название протокола 

    subtree = tree:add(p_foo, buf(0))      -- создаем поддерево

    subtree:add(f_hdr_version, buf(0,1))   -- начинаем добавлять поля
    local ver = buf(0,1):uint()

    if ver == 1 then
       local type_str = packettypes[buf(1,1):uint()]
       if type_str == nil then type_str = "Unknown" end
       pinfo.cols.info = "Type: " .. type_str   -- в колонке Info будет отображаться тип пакета

       subtree:add(f_hdr_type,  buf(1,1))

       subtree:add(f_hdr_flags,         buf(2,1))
       subtree:add(f_hdr_flags_first,   buf(2,1))
       subtree:add(f_hdr_flags_second,  buf(2,1))
       subtree:add(f_hdr_flags_onemore, buf(2,1))

       subtree:add(f_hdr_bool,  buf(3,1))
       subtree:add_le(f_pl_len, buf(4,4))     -- поле длины в Little Endian

       local pl_len = buf(4,4):le_uint()
       subtree:add(f_payload, buf(8,pl_len))  -- данные
    else
       subtree:append_text(string.format(", Unknown version of Foo protocol (0x%02x)", ver))
    end
end

-- регистрируем диссектор на UDP порт 35000
local udp_dissector_table = DissectorTable.get("udp.port")
udp_dissector_table:add(35000, p_foo)

Готово, можно запускать Wireshark.

Результат




Кстати, для отладки удобнее и быстрее использовать текстовую версию «великого рассекателя пакетов» — TShark.

Список источников


Lua Support in Wireshark
www.wireshark.org/docs/wsug_html_chunked/wsluarm.html

Devendra @ Work — Create a Wireshark dissector in Lua
delog.wordpress.com/2010/09/27/create-a-wireshark-dissector-in-lua

Stig Bjørlykke — Lua Scripting in Wireshark
ссылка на PDF: DT06_Bjorlykke_Lua Scripting in Wireshark.pdf
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.