Convert Userdata to hex in Wireshark Dissector - lua

I'm coding Wireshark Dissector lua script now.
How to convert userdata to hex string?
I want to get output like this 0102030405060708000a0b0c0d0e0f10
I can convert hex string using tostring.
But it omits long data.
Output Image
How to convert userdata to hex string without omit long data?
proto = Proto("Test", "My Test Protocol")
function proto.dissector(buffer, pinfo, tree)
print(tostring(buffer()))
-- "userdata"
-- print(type(buffer()))
end
tcp_table = DissectorTable.get("tcp.port")
tcp_table:add(1234, proto)
Environment
Wireshark 3.2.1

I'm not very familiar with Wireshark, but from a quick look into the manual I get that buffer is a Tvb
and buffer() is equivalent to buffer:range() which returns a TvbRange
There is a Tvb:__tostring function which claims to
Convert the bytes of a Tvb into a string. This is primarily useful for
debugging purposes since the string will be truncated if it is too
long.
Printing a TvbRange is truncated to 24 bytes.
I'd try to get a ByteArray from your Tvb and obtain the hex string of that ByteArray using
11.8.1.14. bytearray:tohex([lowercase], [separator]) Obtain a Lua string of the bytes in a ByteArray as hex-ascii, with given separator
So your code might look something like
proto = Proto("Test", "My Test Protocol")
function proto.dissector(buffer, pinfo, tree)
print(buffer:bytes():tohex())
-- or print(buffer():bytes():tohex())
-- but I guess if you don't give a range in buffer()
-- it will be pretty much the same as buffer.
end

Related

Wireshark Lua dissector utf16 string

I am writing a custom Wireshark Lua dissector. One field in the dissector is a UTF16 string. I tried to specify this field with
msg_f = ProtoField.string("mydissector.msg", "msg", base.UNICODE)
local getMsg = buffer(13) -- starting on byte 13
subtree:add_le(m.msg_f, getMsg)
However, this only adds the first character rather than the whole string. It also raises an Expert Info warning undecoded trailing/stray characters.
What is the correct way to parse a UTF16 string?
You haven't specified the range of bytes that comprises the string. This is typically determined by either an explicit length field or by a NULL-terminator. The exact method of determining the range is dependent upon the particular protocol and field in question.
An example of each type:
If there's a length field, say of 1 byte in length that precedes the string, then you can use something like:
local str_len = buffer(13, 1):le_uint()
subtree:add_le(m.msg_len_f, buffer(13))
if str_len > 0 then
subtree:add_le(m.msg_f, buffer(14, str_len))
end
And if the string is NULL-terminated, you can use something like:
local str = buffer(13):stringz()
local str_len = str:len()
subtree:add_le(m.msg_f, buffer(13, str_len + 1))
These are just pseudo-examples, so you'll need to apply whatever method, possibly none of these, to fit your data.
Refer to the Wireshark's Lua API Reference Manual for more details, or to the Wireshark LuaAPI wiki pages.
The solution I came up with is simply:
msg_f = ProtoField.string("mydissector.msg", "msg")
local getMsg = buffer(13) -- starting on byte 13
local msg = getMsg:le_ustring()
subtree:add(msg_f, getMsg, msg)

What does "tvb(offset):string()" mean?

this days,I'm learning how to use Lua to write WireShark plugin.But I don't know what the mean of tvb(offset):string. Why is wrong of use tostring(tvb(offset))? thank you for your answer
function weibo.dissector(tvb, pinfo, tree)
local proto_type = tvb(23, 1):uint();
if(proto_type ~= 0x06) then
return
end
local offset = get_payload_offset(tvb, proto_type)
local data = tvb(offset):string();
local i, j = string.find(data, "weibo")
if(i) then
pinfo.cols.protocol = weibo.name
local subtree = tree:add(weibo, tvb(offset+i-1))
subtree:append_text(", ptn_pos: " .. i .. "-" .. j)
end
end
tvb is a Testy Virtual Buffer.
A Tvb ("Testy Virtual Buffer") represents the packet's buffer. It is
passed as an argument to listeners and dissectors, and can be used to
extract information (via TvbRange) from the packet's data. Beware that
Tvbs are usable only by the current listener or dissector call and are
destroyed as soon as the listener/dissector returns, so references to
them are unusable once the function has returned.
A call as tvb(offset) returns a TvbRange
A range of bytes within a Tvb that is used to extract data. A TvbRange
is created from tvb:__call() or tvb:range([offset] [,length]).
Remark:
tvb is a Lua table. If you call it like tvb() the __call() metamethod is invoked.
https://wiki.wireshark.org/LuaAPI/Tvb#tvb:__call.28.29
tvb:__call()
Description
Creates a TvbRange from a subset of this Tvb. Same as tvb:range().
Cannot be directly called.
Returns
userdata : The new TvbRange
One of TvbRange's many methods is tvbrange:string()
tvbrange:string()
Description
Gets a string from the TvbRange
Returns
string : The string, containing all bytes in the TvbRange including
all zeroes (e.g., "a\000bc\000")
tostring() on the other hand is one of Lua's standard functions.
From https://www.lua.org/manual/5.3/manual.html#pdf-tostring
Receives a value of any type and converts it to a string in a
human-readable format. (For complete control of how numbers are
converted, use string.format.) If the metatable of v has a __tostring
field, then tostring calls the corresponding value with v as argument,
and uses the result of the call as its result.
As tvb implements a __tostring() tostring(tvb) would return the return value of that metamethod.
tvb:__tostring()
Description
Gets a string representation of the Tvb. Cannot be directly called.
Returns
string : The string representation

Convert first two bytes of Lua string (in bigendian format) to unsigned short number

I want to have a lua function that takes a string argument. String has N+2 bytes of data. First two bytes has length in bigendian format, and rest N bytes contain data.
Say data is "abcd" So the string is 0x00 0x04 a b c d
In Lua function this string is an input argument to me.
How can I calculate length optimal way.
So far I have tried below code
function calculate_length(s)
len = string.len(s)
if(len >= 2) then
first_byte = s:byte(1);
second_byte = s:byte(2);
//len = ((first_byte & 0xFF) << 8) or (second_byte & 0xFF)
len = second_byte
else
len = 0
end
return len
end
See the commented line (how I would have done in C).
In Lua how do I achieve the commented line.
The number of data bytes in your string s is #s-2 (assuming even a string with no data has a length of two bytes, each with a value of 0). If you really need to use those header bytes, you could compute:
len = first_byte * 256 + second_byte
When it comes to strings in Lua, a byte is a byte as this excerpt about strings from the Reference Manual makes clear:
The type string represents immutable sequences of bytes. Lua is 8-bit clean: strings can contain any 8-bit value, including embedded zeros ('\0'). Lua is also encoding-agnostic; it makes no assumptions about the contents of a string.
This is important if using the string.* library:
The string library assumes one-byte character encodings.
If the internal representation in Lua of your number is important, the following excerpt from the Lua Reference Manual may be of interest:
The type number uses two internal representations, or two subtypes, one called integer and the other called float. Lua has explicit rules about when each representation is used, but it also converts between them automatically as needed.... Therefore, the programmer may choose to mostly ignore the difference between integers and floats or to assume complete control over the representation of each number. Standard Lua uses 64-bit integers and double-precision (64-bit) floats, but you can also compile Lua so that it uses 32-bit integers and/or single-precision (32-bit) floats.
In other words, the 2 byte "unsigned short" C data type does not exist in Lua. Integers are stored using the "long long" type (8 byte signed).
Lastly, as lhf pointed out in the comments, bitwise operations were added to Lua in version 5.3, and if lhf is the lhf, he should know ;-)

Read first bytes of lrange results using Lua scripting

I'm want to read and filter data from a list in redis. I want to inspect the first 4 bytes (an int32) of data in a blob to compare to an int32 I will pass in as an ARG.
I have a script started, but how can I check the first 4 bytes?
local updates = redis.call('LRANGE', KEYS[1], 0, -1)
local ret = {}
for i=1,#updates do
-- read int32 header
-- if header > ARGV[1]
ret[#ret+1] = updates[i]
end
return ret
Also, I see there is a limited set of libraries: http://redis.io/commands/EVAL#available-libraries
EDIT: Some more poking around and I'm running into issues due to how LUA stores numbers - ARGV[1] is a 8 byte string, and cannot be safely be converted into a 64 bit number. I think this is due to LUA storing everything as doubles, which only have 52 bits of precision.
EDIT: I'm accepting the answer below, but changing the question to int32. The int64 part of the problem I put into another question: Comparing signed 64 bit number using 32 bit bitwise operations in Lua
The Redis Lua interpreter loads struct library, so try
if struct.unpack("I8",updates) > ARGV[1] then

Reassemble PDUs in lua wireshark dissector

In a system I have a custom protocol and I would like to implement a Wireshark dissector so that I can use Wireshark to analyze the communication.
Objects are sent over the protocol, let us call them "Messages". Each message can be large, maybe up to 100 MB, they can also be very small for example 50 byte.
Each Message is split up in chunks of around 1 kB and tagged with a sequence number and a guid message id and those can be used at the other end to reassemble the messages.
So far I have successfully made a dissector that will individually log all chunks to Wireshark but I want to take this further and also log all messages (chunks assembled into messages) in Wireshark. Can this be done and how? Is it maybe possible to implement a dissector on top of the dissector I have developed below?
If it is possible to implement a dissector on top of the one below, how can I make sure it will only analyze myproto PDUs? The dissector below triggers on a specific tcp port, but that is not going to work for the second phase dissector...
myproto_proto = Proto("myproto", "My Protocol")
function myproto_proto.dissector(buffer, pinfo, tree)
pinfo.cols.protocol = "myproto"
local message_length = buffer(0, 4):le_uint()+4
if message_length>pinfo.len then
pinfo.desegment_len = message_length
pinfo.desegment_offset = 0
return;
end
local subtree = tree:add(myproto_proto, buffer(), "My Protocol Data")
local packet = subtree:add(buffer(0, message_length), "Chunk")
packet:add(buffer(0, 4), "Packet length: " .. buffer(0, 4):le_uint())
packet:add(buffer(32, 16), "Message ID")
packet:add(buffer(48, 4), "Block ID: " .. buffer(48, 4):le_uint())
packet:add(buffer(52, 4), "Max Block ID: " .. buffer(52, 4):le_uint())
packet:add(buffer(68, message_length-68-20), "Data")
pinfo.desegment_len = 0
pinfo.desegment_offset = message_length
return
end
tcp_table = DissectorTable.get("tcp.port")
tcp_table:add(1234, myproto_proto)
Let's say you have created a second dissector msgproto. Since you don't seem to have any multiplexing between chunks and messages, you don't need to setup a dissector table. Instead, at the end of myproto_proto.dissector you do a
msgproto.dissector:call(buffer(68, message_length-68-20):tvb, pinfo, tree)
This will pass all the chunk data to your msgproto . In the message protocol dissector you can use the chunk protocol's fields and of course the tvb that will contain just the data of one chunk. You will now need to piece together the chunks to one gloriously huge tvb. Make the msgprotohave state:
local stateMap = {}
function msgproto.init()
stateMap = {}
end
Convert your the tvb into a ByteArray and store into the stateMap together with the arrays from the other calls to your dissector. When you have assembled all your data into one array, let's call it oarr, make a tvb out of it:
local otvb = ByteArray.tvb(oarr, "message data")
-- starting from 0, need to pass a tvb range, not a tvb.
stree:add(msgproto.fields.payload, otvb(0))
supposed you have payload field of type Protofield.bytes. This code will make a new data pane called "message data" appear next to your regular "Frame" pane at the bottom of your Wireshark window.
I'm not sure how well Wireshark will like your ultra large buffers. Apart from that, I'm quite convinced that the approach outlined above will work. I have not used the described techniques in this exact order, but I have used all the described techniques, for example to make a new byte pane filled with data deflated in pure Lua.

Resources