As one of the best network packet capture tools in the world, Wireshark allows you to obtain specific data packets so you can analyze them both offline and in real time. Think of the app as a way to closely examine the data flowing through your network, allowing you to detect problems and irregularities.
You can use dissectors if you want to analyze a specific part of the data in a packet. As the name implies, this process “dissects” the code, allowing you to remove certain aspects that need your attention. This tutorial explains how to create and use dissectors in Wireshark using the Lua programming language.
Before you begin: What you need to know about dissectors
Although dissectors offer a quick way to analyze parts of a data packet in Wireshark, they must follow some protocols to work effectively. These protocols include the following:
- Each dissector you create must be registered to handle a particular type of payload for a different protocol. To complete this registration, you must assign a “Proto” object to your dissector, which you will see below.
- When you call a dissector through Wireshark, you receive three things from the application:
- TVB Object: A TVB buffer of the data packet.
- TreeItem object: The root of a tree that represents a single node in a data tree.
- Pinfo object: A packet information record.
- You can only call a dissector if its data packet matches the DissectorTable you set in your “Proto” object.
- You can work around this requirement by forcing the use of a dissector using the “Decode As” function. But even then, you can only force the dissector if the DissectorTable you set up for your “Proto” object is of the correct type.
Setting up your dissector using LUA
As Wireshark is written and uses the C programming language, most dissectors are similarly written in C. However, you may want to use Lua. This programming language is simpler than C and therefore more accessible to newcomers to programming or those who simply want to create a dissector using a lighter language.
Although your code will be simpler, the dissector you get when using Lua is typically slower than the one you would create using C. However, these are the steps to follow if you want to create a Wireshark dissector using Lua.
Step 1: Configure Lua in Wireshark
You’ll need to configure Lua if you haven’t used it before in Wireshark:
- Click “Help,” followed by “About Wireshark.”

- Click “Folders.”

- Choose one of the following options to create an active Lua script:
- Global Lua Plugins
- Lua Personal Plugins
- Staff
Once activated, your script will be ready every time you start Wireshark. Every time you make a change to that script, you must restart Wireshark to register the change or press “Ctrl + Shift + L” to reload all your Lua scripts and activate the changes.
Step 2: The basic steps to create your dissector
If you are already familiar with Lua, you can follow these steps to create your own dissector script that will work in Wireshark:
- Declare the protocol for your dissector, which requires that you set a long name to use in the protocol tree and a short name to serve as the name of the dissector’s display filter.
- Create the following three fields, with their appropriate types:
- Question: Shows the type of question.
- Response: Shows the type of response.
- Message Type: Demonstrates whether your package requests a question or an answer.
- Register your fields so Wireshark knows how to display them. Without registered fields, you will receive a “Lua Error” message, which will usually tell you that your Tree Element ProtoField is invalid.
- Create a dissection function that includes the Pinfo mentioned above (which contains data about your package) and the TreeItem (which creates the tree that you will add to a subtree). You should also create a “buffer” that sits on top of your TCP.
- Specify both the protocol and port for which Wireshark should use the dissector. For example, you can set the protocol to “TCP” and the port number you want to use.
Step 3: Add your dissector to Wireshark
Right now your dissector is like a light bulb without electricity. It exists, but it’s of no use to you until you can run some energy through it. In other words, your dissector is not added to Wireshark yet, so you have to add it manually to make it work by following these steps:
- Click “Help” and go to the “About Wireshark” menu.

- Select the “Folder” tab to find a list of paths for your Lua file.

- Choose “Personal Lua Plugins”. Create a directory if necessary.

- Copy and paste the Lua file you created into the “Personal Lua Plugins” directory. Reload Wireshark to turn on the dissector.
It’s a good idea to run a test on your new dissector by opening some of the packets you’ve captured. Wireshark should send a message showing the long name you chose for your dissector, along with information about the type of message (question or answer) and the result of its verification.
Some sample code
If you haven’t created a dissector before (or are new to Lua), wireshark offers a handy example dissector for you to try:
local p_multi = Proto("multi", "MultiProto");
local vs_protos = {
[2] = "mtp2",
[3] = "mtp3",
[4] = "alcap",
[5] = "h248",
[6] = "ranap",
[7] = "rnsap",
[8] = "nbap"
}
local f_proto = ProtoField.uint8("multi.protocol", "Protocol", base.DEC, vs_protos)
local f_dir = ProtoField.uint8("multi.direction", "Direction", base.DEC, { [1] = "incoming", [0] = "outgoing"})
local f_text = ProtoField.string("multi.text", "Text")
p_multi.fields = { f_proto, f_dir, f_text }
local data_dis = Dissector.get("data")
local protos = {
[2] = Dissector.get("mtp2"),
[3] = Dissector.get("mtp3"),
[4] = Dissector.get("alcap"),
[5] = Dissector.get("h248"),
[6] = Dissector.get("ranap"),
[7] = Dissector.get("rnsap"),
[8] = Dissector.get("nbap"),
[9] = Dissector.get("rrc"),
[10] = DissectorTable.get("sctp.ppi"):get_dissector(3), -- m3ua
[11] = DissectorTable.get("ip.proto"):get_dissector(132), -- sctp
}
function p_multi.dissector(buf, pkt, tree)
local subtree = tree:add(p_multi, buf(0,2))
subtree:add(f_proto, buf(0,1))
subtree:add(f_dir, buf(1,1))
local proto_id = buf(0,1):uint()
local dissector = protos[proto_id]
if dissector ~= nil then
-- Dissector was found, invoke subdissector with a new Tvb,
-- created from the current buffer (skipping first two bytes).
dissector:call(buf(2):tvb(), pkt, tree)
elseif proto_id < 2 then
subtree:add(f_text, buf(2))
-- pkt.cols.info:set(buf(2, buf:len() - 3):string())
else
-- fallback dissector that just shows the raw data.
data_dis:call(buf(2):tvb(), pkt, tree)
end
end
local wtap_encap_table = DissectorTable.get("wtap_encap")
local udp_encap_table = DissectorTable.get("udp.port")
wtap_encap_table:add(wtap.USER15, p_multi)
wtap_encap_table:add(wtap.USER12, p_multi)
udp_encap_table:add(7555, p_multi)
Postdissectors and chained dissectors
You may want to delve a little deeper into using your dissector once you master creating it in Lua. Wireshark offers two additional types of dissectors (postdissectors and chained dissectors) that offer more functionality.
A postdissector is much like a final check of all the dissectors you’ve run for a package. You register it to be notified once Wireshark has called all the other dissectors you want to use, and you can use it to filter the “Protocol” and “Information” columns. This feature is especially useful if you want to filter multiple packets in a session where there has been a long interval between data sets and you cannot remember each of them inpidually.
Dissector chaining serves a similar function (at least in terms of filtering through previously used dissectors) by giving you access to data from a single dissector. The key advantage here is that the chained dissector doesn’t have to check each packet again, giving you a result without forcing you to wait for the original dissector to run again.
Dissect in Lua
Since Wireshark already offers the ability to create dissectors in C (its natural language), you may not see the need to also create them in Lua. Still, those not comfortable with C, as well as those already proficient in Lua, may find that Lua’s lightweight scripts make it easy to create their dissectors. Of course, you have to compensate for a longer load time when you run the process compared to C-based dissectors, but it’s useful to have the option anyway.