Create a Wireshark dissector in Lua


You have a custom protocol over TCP and would like to give your users the ability to visualize it in Wireshark? This post is for you. To create your dissector I recommend Wireshark’s Lua API and the embedded Lua interpreter. It is the easiest way to prototype dissectors, which for performance reasons may later be rewritten in C. At the time of writing I am still using Wireshark 1.2.1, but you might consider using the latest version.

Let us begin with some sample code.

Protocol dissector script in Lua

We use a chained dissector, it adds functionality to dissect packets of an existing protocol, such as packets destined to a particular tcp port. It receives only the payload part of the original protocol packet as the input buffer in the dissector function.

-- create myproto protocol and its fields
p_myproto = Proto ("myproto","My Protocol")
local f_command = ProtoField.uint16("myproto.command", "Command", base.HEX)
local f_data = ProtoField.string("myproto.data", "Data", FT_STRING)

p_myproto.fields = {f_command}

-- myproto dissector function
function p_myproto.dissector (buf, pkt, root)
  -- validate packet length is adequate, otherwise quit
  if buf:len() == 0 then return end
  pkt.cols.protocol = p_myproto.name

  -- create subtree for myproto
  subtree = root:add(p_myproto, buf(0))
  -- add protocol fields to subtree
  subtree:add(f_command, buf(0,2)):append_text(" [Command text]")

  -- description of payload
  subtree:append_text(", Command details here or in the tree below")
end

-- Initialization routine
function p_myproto.init()
end

-- register a chained dissector for port 8002
local tcp_dissector_table = DissectorTable.get("tcp.port")
dissector = tcp_dissector_table:get_dissector(8002)
  -- you can call dissector from function p_myproto.dissector above
  -- so that the previous dissector gets called
tcp_dissector_table:add(8002, p_myproto)

Running the Lua script in Wireshark

Here are the steps required to get the above code running. If your Wireshark version is 1.4 or better, skip step 3.

  1. Edit and save the lua script above to any folder (e.g. c:\myproto) and call the file myproto.lua
  2. Open init.lua in the Wireshark installation directory for editing. You will need Admin privileges on Windows Vista and 7.
  3. Comment out the following line in init.lua (single line comments begin with --):
    disable_lua = true; do return end;
  4. Add the following lines to init.lua (at the very end):
    MYPROTO_SCRIPT_PATH="C:\\myproto\\"
    dofile(MYPROTO_SCRIPT_PATH.."myproto.lua")
  5. Change MYPROTO_SCRIPT_PATH to point to the folder where you saved the script in step 1
  6. Run Wireshark
  7. Load a capture file that has the packets of your custom protocol or start a live capture

Here’s a figure that shows the protocol dissector in action.

About these ads
Posted in Lua, Wireshark
29 comments on “Create a Wireshark dissector in Lua
  1. ravi@ingram.in says:

    Hello, I am using ubuntu 11.10

    I followed your method along with if 0 and running_superuser then
    local disabled_lib = {}
    to make Lua work its still throwing out dofile disabled error.

    i am using 1.6.2 version

  2. Hello,
    I am trying to isolate a custom protocol that comes in the data part of udp using Lua scripts in Wireshark. How can i recognize these with flag values of the custom headers that come sequncially after udp headers in udp’s data.
    Any Idea where there is a proper list of comands pertaining to wireshark-lua script writing.
    A big Thanx in Advance.

    I am using latest wireshark version.

    Edwin Abraham

    • Devendra says:

      Writing a dissector for UDP is very much like writing a dissector for TCP. You can register to dissect UDP packets with a particular port as follows

      local udp_dissector_table = DissectorTable.get("udp.port")
      dissector = udp_dissector_table:get_dissector(8002)
        -- you can call dissector from function p_myproto.dissector above
        -- so that the previous dissector gets called
      udp_dissector_table:add(8002, p_myproto)
      

      For help on Wireshark’s LUA API please refer to http://www.wireshark.org/docs/wsug_html_chunked/wsluarm.html. For Lua related information see the manual at http://www.lua.org/manual/5.1/manual.html.

      • Okay suppose I did this. How does Wireshark know that this is my custom protocol. Like where is the filter option there? Lets say I can check that this is my custom protocol with a flag. Anyway of getting the data part of udp and then compare it?
        and is there a way to tell wireshark to look at all my udp ports not just a specific one?

      • Devendra says:

        Q. Okay suppose I did this. How does Wireshark know that this is my custom protocol.

        A. You create a new Proto object, that is how it knows.

        Q. Like where is the filter option there? Lets say I can check that this is my custom protocol with a flag.

        A. You specify the fields by setting the fields property of your Proto object. You can add fields dynamically from the dissector function of your Proto object by using the root parameter. Wireshark cannot filter based on those fields though. You don’t need any additional flags, you can filter packets based on the procotol name to begin with.

        Q. Anyway of getting the data part of udp and then compare it?

        A. You can use the buf object, a parameter of the dissector function, to get the data and do whatever you want with it.

        Q. …and is there a way to tell wireshark to look at all my udp ports not just a specific one?

        A. You can register your protocol dissector against as many ports as you wish. Just repeat the following several times with different port numbers

        dissector = udp_dissector_table:get_dissector(8002)
        udp_dissector_table:add(8002, p_myproto)
        
  3. Thanx for the info firstly. One last question.

    The protocol I have to recognize is a udp packet where the data part of udp will act as headers for the rest of the data in the packet. Its a completely new packet and only way to Identify whether the udp that comes is of that custom protocol is a field that is 12th (unsigned long) from the udp headers. Now I defined all the names of the headers with uint32. But it still doesn’t understand that its myproto. I feel its because I haven’t asked it to recognize that. Now the only way it will recognize is by comparing the 12th uint32 data with some value.

    I understood the part of the udp ports , the protocol creation, but from the udp packet how will it know its my packet. For that what do I do? You said with the name of the protocol. But from where the packet?

    • Devendra says:

      You can do that with something like the following in the dissector function

      if buf(11):uint() == val then
      
        -- dissect
      
      else
        -- call the previous dissector and quit
        dissector:call(buf, pkt, root)
        return
      end
      
  4. That should fix the problem. Thanx a bunch.

  5. [...] If you are not familiar with writing dissectors for Wireshark in Lua I recommend reading this post on that topic [...]

  6. toi_la_toi says:

    Hello!
    Thanks you for yours tutor. I have a problem with my dissector, and i need yours help. After running LUA script, I want to count total packets that appear in myproto. So, i dont know how to do :|. Can u help me,pls?.
    Sorry my english is not good
    Thank

    • Devendra says:

      Hello! The dissector function is called once for each packet. You can maintain a global counter (defined outside the function) and increment it each time the dissector function is called, e.g.

      local count = 0
      ...
      function p_myproto.dissector (buf, pkt, root)
      ...
        count = count + 1
      ...
      end
      
  7. Santosh says:

    Hi,
    I see the following error thrown while the Wireshark GUI loads:
    Lua: Error during loading:
    C:\Program Files\Wireshark\myproto.lua:1: unexpected symbol near ‘{‘

    I have copied the script as is and placed “myproto.lua” in folder where “init.lua” is located (c:\Program Files\Wireshark )and added

    dofile(“myproto.lua”) at the end .

    Request to please help solve the issue

    • Devendra says:

      Hi Santosh. The code as posted should work. Check that you didn’t add any extra characters into the script by mistake. Please tell more about your environment – OS version, Wireshark version etc.

      • Santosh says:

        Devendra,
        Thanks I actually posted it on a rtf file that had extra charecters appended before the actual script. I used notepad and its fine now and working.

        Thanks for the post as it is tailor made for my use.

        Wanted to know are there ways to convert the hex data in the payload and display it as a decimal value when we expand the subtree for the custom protocol.

        Ex. Subtree lists “Squence Number: 3886″ , for the value 0f2e in the payload.

        I use wireshark version 1.8.0 on Windows XP

        Thanks.

      • Devendra says:

        Hi Santosh. The buf parameter of the dissector function is of type Tvb. You can obtain a TvbRange by doing something like buf(offset, 2). TvbRange has methods that return integer and other values. For your case you can use something like buf(offset, 2):uint(). Remember to change offset to the position in the buffer you want to read your value from. If the byte order of the data is little endian you can use le_uint. Follow the Wireshark Lua API link above for further details.

  8. Santosh says:

    Thanks Devendra.
    I was able to get my requirement of the previous post however, facing the issue while adding new protocol fields.

    only buf(x,x) ; where x=0,1,2,3,4 are accepted

    i.e, for Ex.If I attempt subtree:add(f_command, buf(4,5)) or subtree:add(f_command, buf(5,5)),

    It fails with error thrown as, [Dissector bug, protocol KODRTPOTCP: proto.c:1115: failed assertion "DISSECTOR_ASSERT_NOT_REACHED"].

    Can you please let me know what could be the problem.

    Thanks.

    • Devendra says:

      You are most certainly exceeding the bounds of the buffer. You should create a TvbRange like buf(offset, length). The second parameter is the length of the field, not the end index/offset.

      • Santosh says:

        So we can confirm the Bounds of the buffer is been configured to read till 16bits? Is this a default value?

      • Devendra says:

        It is intelligent enough to determine that the range has just 2 bytes (16 bits) and create an integer value from that. I hope that answers your question. If not, I don’t understand your question.

  9. Santosh says:

    Yes it’s obvious. Missed it. Thanks.

    Also,
    I plan to use control structure (if/else) and depending upon the value of payload data decoded, append text to the subtree, but I am facing issue in the same.

    i.e,
    local f_cmd = ProtoField.uint32(“Koproto.cmd”, “Version”,base.DEC)

    The above command displays the Version in subtree (as 2) correctly but when I use it in if/else statement, it’s not able to resolve, i.e

    if f_cmd == 2 then
    subtree:add(f_cmd, buf(1,1)):append_text(” Version is 2″)
    else
    subtree:add(f_cmd, buf(1,1)):append_text(” Version is not 2″)
    end.

    This Is failing.

    Unfortunately cannot print the value of “f_cmd” to verify what it holds actually.

    Can you please let me know what could be the issue?

    Thanks.

    • Devendra says:

      f_cmd is like a template, not the actual field. You can read the value directly from buf as TvbRange and using one of its methods, then use that value in the if statement.

  10. Santosh says:

    Hi,
    Thanks for your reply.
    I face following error when I tried working with bitstring:

    Lua: Error during loading:
    error loading module ‘bitstring’ from file ‘C:\Program Files\Wireshark\bitstring.dll':
    %1 is not a valid Win32 application.

    Can I know what could be the reason for the same?

    Followed following steps:
    1. Copy ‘bitstring.dll’ to your wireshark directory. This file provides ‘bitstring’ library for Lua.
    2. Copy ‘coap.lua’ to somewhere in your wireshark directory. For example, /plugins/coap/coap.lua.
    3. Open ‘init.lua’ in your wireshark root directory. Comment the line ‘disable_lua = true’ or change it to ‘disable_lua = false’.
    4. Add ‘dofile(“/plugins/coap/coap.lua”)’ at the end of the file(init.lua)

  11. GK says:

    Hi Devendra,
    I want to check total length of the buffer (Valid number of bytes to decode). How can I do it?

  12. [...] you are not familiar with writing dissectors for Wireshark in Lua I recommend reading this post [...]

  13. […] function still needs. If you are not familiar with writing dissectors for Wireshark in Lua, read this post […]

  14. david says:

    I made a slight change to associate the dissector with port 80 because I have a test pcap with that traffic. At the bottom of the page in the screenshot shows a filterable field called myproto.command that links to 0x ebff. When I run this script it parses out the bytes but my bytes (2 bytes from traffic) show up as text. If this data is text then I cannot filter or use tshark command. Can you shed some light on this matter? I have tried a lot of different things and cannot get it to work:( Also, I am evaluating the lua script directly in wireshark via the evaluate option and then I refresh my test pcap.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 62 other followers

%d bloggers like this: