Tag Archives: lua

Decoding Vendor Specific USB protocols with Wireshark lua plugins

Earlier this week I was doing some reverse engineering and confirmation of behaviour for a USB tool. I got wireshark to sniff the traffic, (Not going into that here, it’s relatively straightforward and documented enough on the web to get by) but as it’s a vendor specific protocol, it was just lots of bytes.

I was decoding them by hand, and then copying and pasting into a python script (I had pretty good sources of what all the bytes meant, I just had no good way of visualising the stream, which is where wireshark and this post comes in)

I have written a custom wireshark dissector before, but I wasn’t super happy with the mechanism. I have been doing some work with Lua in my dayjob, and had read that wireshark supported dissector plugins could be written in Lua now. Seemed like a better/easier/more flexible approach.

I got to work, following these (somewhat) helpful resources:

These were all generally very helpful, but there two things I wrestled with, that I didn’t feel were at all well described. From here on out, I’m going to assume that you know what’s going on, and just need help with things that are not covered in any of the earlier links.

Little Endian

You declare ProtoField’s as just uint8, uint16, uint32. This is fine and sane. But there’s a few ways of working with it when you add it to the tree.

f.f_myfield = ProtoField.uint32("myproto.myfield", "My Field", base.HEX)
-- snip --
mytree:add_le(f.f_myfield, buffer(offset, 4)

This way works very well, selecting “myfield” in the packet view correctly highlights the relevant bytes. But say you want to get the value, to add to the info column for instance, you might do this.. (if you read the api guide well enough)

local val = buffer(offset, 4):le_uint()
-- normal add, we've done the LE conversion
-- if you don't do :le_uint() above, and do a :add_le() below,
-- the info column will show the backwards endian value!
mytree:add(f.f_myfield, val)
pinfo.cols["info"]:append(string.format(" magicfield=%d", val))

At first glance, this works too. The Info Column shows the right value, the tree view shows the right value. BUT clicking on the tree view doesn’t highlight the bytes.

Here’s how to do it properly:

local val = buffer(offset, 4)
mytree:add_le()(f.f_myfield, val)
pinfo.cols["info"]:append(string.format(" magicfield=%d", val:le_uint()))

Ok, a little fiddly, but you would probably get there in the end.

Reading existing USB properties

The docs talk about doing something like:

local f_something = Field.new("tcp.port")

Except, I didn’t find anywhere that described what magic strings were available. I tried using the values available in the display filter box, like, “bEndpointAddress” but never got anywhere. One of the samples led me to this tidbit:

       local fields = { all_field_infos() }
       for ix, finfo in ipairs(fields) do
            print(string.format("ix=%d, finfo.name = %s, finfo.value=%s", ix, finfo.name, getstring(finfo)))
        end

When you click on a packet, this will dump lots to the console, and you can hopefully work out the magic values you need!

Synchronising packets

TCP streams are easy, you have sequence ids to correlate things. USB isn’t quite the same. You can see the “URB” has two frames, from host to device and device to host, which are in sync, but for the very common case of writing to an OUT endpoint, and getting a response on an IN endpoint, you don’t get any magical help.

I found a way of doing this, but it’s not ideal, and tends to mess up the display in wireshark if you click on packets in reverse order. This is because I just set a state variable in the dissector when I parsed the OUT packet, and check it when I parse the IN packet. It works, but it was less that ideal. Sometimes you need to click forwards through packets again. Sometimes the tree view would show the right values too, but the info column would be busted. Probably doing something wrong somewhere, but hard to know what.

Actually hooking it up

Finally, and the most frustrating, was how to actually hook it up! The demos, all being TCP related, just do:

the_table = DissectorTable.get("udp.port")
the_table:add(9999, my_protocol)

Ok, well and good, but how on earth do I register a USB dissector? You need to register it by the class which is sort of ok, but good luck having dissectors for multiple vendor specific classes. I didn’t see a way of adding a dissector based on the VID:PID, though I think that would be very useful.

usb_table = DissectorTable.get("usb.bulk")
-- this is the vendor specific class, which is how the usb.bulk table is arranged.
usb_table:add(0xff, my_proto)
-- this is the unknown class, which is what shows up with some usb tools?!
usb_table:add(0xffff, my_proto)

Update 2013-Jan-16One of the sigrok developers got the vid/pid matching working, in another example of a lua plugin.

This skims over a lot, but it should help.
Final working code:

I’ve totally glossed over exactly _what_ or _why_ I was decoding vendor specific usb classes. That’s a topic for another day :)

Here’s some pictures though

How it looks before you write a plugin.

How it looks before you write a plugin.

With the plugin, note that the info column isn't always showing the proper values.  No idea why.  wireshark's weird

With the plugin, note that the info column isn’t always showing the proper values. No idea why. wireshark’s weird

PS: How about that title! linkbait to the max! keywords to the rescue! (or at least, the ones I had tried searching for)

Eclipse 4.2, Lua and execution environments

One of the things that made me want to go and try eclipse again was this advertised Lua Development Toolkit, the LDT. (aka Koneki, have I mentioned how much I hate eclipse’s acronym+codename soup?) Apparently I could develop Lua scripts in eclipse, with syntax highlighting, debugging, documentation and all that good stuff.

So, I made a simple script. I didn’t get any help/luadoc. I did get syntax highlight, but I get that in vim too. Oh, and there’s no “run” configuration. Umm, that’s kinda important. I didn’t set up an “execution environment” because well, I just wanted to use the system lua. Seems that you actually must set up an execution environment so that it knows how to run things and do the luadoc. Except, it’s just some magical zip file. Which is not provided by default and has no documentation on what it should contain.

So yeah, good fucking luck actually using this advertised feature of the Lua Development Toolkit. Another excellent fucking release from eclipse. I try to like eclipse, I try to use it, but for fucks sake.

Local development for LuCI

So, you’ve got some LuCi modules packaged up, and you can build them via the OpenWRT build root, and you can install them with opkg, and you can edit the final files in /usr/lib/lua/luci/{controller,views,etc} and the changes take effect immediately, but you don’t like working on the target router. You don’t get to use the editors you want, it’s hard to integrate into your version control to see what you’ve been doing. You’ve seen this page about a “local development environment”, but it didn’t help as much as you had hoped?

Here’s a few things that worked for me, based on lots of advice and snippets from jow_laptop and some experimentation.

First, I’m assuming you’ve got luci trunk checked out, and I’m going to refer to that directory as [LUCI_DIR]. I’m assuming that your working luci package, which has the OpenWRT opkg Makefile, and a luasrc and htdocs directory are in [YOUR_PKG].

Now, the opkg Makefile that does a great job of building your package normally isn’t going to cut it for running inside luci. Make a new directory in [LUCI_DIR]/applications/your_name and add a Makefile with the following contents

include ../../build/config.mk
include ../../build/module.mk

That’s it. Now, you need the luasrc/htdocs etc directories from your project. This is a touch tedious…

  1. [LUCI_DIR]/applications/your_name$ ln -s [YOUR_PKG]/luasrc
  2. [LUCI_DIR]/applications/your_name$ ln -s [YOUR_PKG]/htdocs

At this point, [LUCI_DIR]$ make runuhttpd will churn away, and copy things all over the place, and you should have your package working locally.

I had problems where controllers were simply not detected, with the page’s “entry” links simply returning a 404 “No page is registered at blah/wop” As best I can tell, this was a problem in the fast indexer, and editing [LUCI_DIR]/libs/web/dispatcher.lua, in the createindex function, to use the plain indexing instead of the fast indexing meant that all my controllers showed up properly. The controllers were all working perfectly on the target mind you.

So, with this, I don’t have to fiddle around with sshfs, and I can easily use things like git diff to see what I’ve actually done recently. However, because of the way make runuhttpd works, by copying all the files first into a dist directory, then copying that into the [LUCI_DIR]/host/ tree, you have to continually stop and start the server after any changes. A project for another day….