summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Wu <peter@lekensteyn.nl>2018-12-17 18:46:19 +0100
committerPeter Wu <peter@lekensteyn.nl>2018-12-17 18:46:19 +0100
commit09e6c5a5d19919ec167a11cef74473026ef15318 (patch)
tree7b769f5f363a63f5fa8bb7e345b43a7d31c3c3b7
parent4388526d2c91d3e4ea98b5040cb0d386a1d7e3e5 (diff)
downloadwireshark-notes-09e6c5a5d19919ec167a11cef74473026ef15318.tar.gz
file-ar: ar and COFF dissector for Wireshark
Created in order to compare libgcrypt-20.dll.a as created by MinGW versus libgcrypt-20.lib as created by MSVC. Based on file-zip.lua.
-rw-r--r--lua/file-ar.lua523
1 files changed, 523 insertions, 0 deletions
diff --git a/lua/file-ar.lua b/lua/file-ar.lua
new file mode 100644
index 0000000..172492d
--- /dev/null
+++ b/lua/file-ar.lua
@@ -0,0 +1,523 @@
+--
+-- ar (Unix) dissector
+-- Author: Peter Wu <peter@lekensteyn.nl>
+--
+-- Information about the file format:
+-- https://en.wikipedia.org/wiki/Ar_(Unix)#File_format_details
+-- https://docs.microsoft.com/en-us/windows/desktop/Debug/pe-format#archive-library-file-format
+--
+
+local machine_types = {
+ [0x0000] = "Unknown",
+ [0x014c] = "i386",
+ [0x8664] = "x64",
+}
+local import_types = {
+ [0] = "IMPORT_CODE",
+ [1] = "IMPORT_DATA",
+ [2] = "IMPORT_CONST",
+}
+local import_name_types = {
+ [0] = "IMPORT_ORDINAL",
+ [1] = "IMPORT_NAME",
+ [2] = "IMPORT_NAME_NOPREFIX",
+ [3] = "IMPORT_NAME_UNDECORATE",
+}
+local reloc_types_x64 = {
+ [0x0000] = "IMAGE_REL_AMD64_ABSOLUTE",
+ [0x0001] = "IMAGE_REL_AMD64_ADDR64",
+ [0x0002] = "IMAGE_REL_AMD64_ADDR32",
+ [0x0003] = "IMAGE_REL_AMD64_ADDR32NB",
+ [0x0004] = "IMAGE_REL_AMD64_REL32",
+ [0x0005] = "IMAGE_REL_AMD64_REL32_1",
+ [0x0006] = "IMAGE_REL_AMD64_REL32_2",
+ [0x0007] = "IMAGE_REL_AMD64_REL32_3",
+ [0x0008] = "IMAGE_REL_AMD64_REL32_4",
+ [0x0009] = "IMAGE_REL_AMD64_REL32_5",
+ [0x000A] = "IMAGE_REL_AMD64_SECTION",
+ [0x000B] = "IMAGE_REL_AMD64_SECREL",
+ [0x000C] = "IMAGE_REL_AMD64_SECREL7",
+ [0x000D] = "IMAGE_REL_AMD64_TOKEN",
+ [0x000E] = "IMAGE_REL_AMD64_SREL32",
+ [0x000F] = "IMAGE_REL_AMD64_PAIR",
+ [0x0010] = "IMAGE_REL_AMD64_SSPAN32",
+}
+
+local proto_ar = Proto.new("ar_archive", "ar Archive")
+-- More are defined at https://docs.microsoft.com/en-us/windows/desktop/Debug/pe-format#machine-types
+local hf = {
+ header = ProtoField.none("ar.header", "Archive Header"),
+ magic = ProtoField.string("ar.magic", "Magic"),
+ entry = ProtoField.none("ar.entry", "File entry"),
+ file_id = ProtoField.string("ar.file_id", "File identifier"),
+ file_mtime = ProtoField.absolute_time("ar.file_mtime", "File modification timestamp", base.UTC),
+ owner_id = ProtoField.string("ar.owner_id", "Owner ID"),
+ group_id = ProtoField.string("ar.group_id", "Group ID"),
+ file_mode = ProtoField.string("ar.file_mode", "File mode"),
+ file_size = ProtoField.string("ar.file_size", "File size"),
+ end_chars = ProtoField.string("ar.end_chars", "End of header"),
+ file_data = ProtoField.bytes("ar.file_data", "File data"),
+ padding = ProtoField.bytes("ar.padding", "Padding"),
+ l1_number_of_symbols = ProtoField.uint32("ar.l1.number_of_symbols", "Number of Symbols"),
+ l1_file_offset = ProtoField.uint32("ar.l1.file_offset", "File offset", base.HEX_DEC),
+ l1_symbol_name = ProtoField.stringz("ar.l1.symbol_name", "Symbol Name"),
+ l2_number_of_members = ProtoField.uint32("ar.l2.number_of_members", "Number of Members"),
+ l2_number_of_symbols = ProtoField.uint32("ar.l2.number_of_symbols", "Number of Symbols"),
+ l2_file_offset = ProtoField.uint32("ar.l2.file_offset", "File offset", base.HEX_DEC, nil, nil, "File offset to archive member headers"),
+ l2_index = ProtoField.uint32("ar.l2.index", "Index", base.DEC, nil, nil, "Index into offsets array"),
+ l2_symbol_name = ProtoField.stringz("ar.l2.symbol_name", "Symbol Name"),
+ ln_member_name = ProtoField.stringz("ar.ln.member_name", "Member Name"),
+ import_header = ProtoField.none("ar.import_header", "Import Header"),
+ imp_sig1 = ProtoField.none("ar.imp.sig1", "Import Header Sig1"),
+ imp_sig2 = ProtoField.none("ar.imp.sig1", "Import Header Sig2"),
+ imp_version = ProtoField.uint16("ar.imp.version", "Structure Version"),
+ imp_machine = ProtoField.uint16("ar.imp.machine", "Machine Type", base.HEX, machine_types),
+ imp_timedate = ProtoField.absolute_time("ar.imp.timedate", "Creation Datetime", base.UTC),
+ imp_size = ProtoField.uint32("ar.imp.size", "Size"),
+ imp_hint = ProtoField.uint16("ar.imp.hint", "Ordinal/Hint"),
+ imp_type = ProtoField.uint16("ar.imp.type", "Import Type", base.DEC, import_types, 0x0003),
+ imp_name_type = ProtoField.uint16("ar.imp.name_type", "Import Name Type", base.DEC, import_name_types, 0x000c),
+ imp_symbol_name = ProtoField.stringz("ar.imp.symbol_name", "Symbol Name"),
+ imp_dll = ProtoField.stringz("ar.imp.dll", "DLL"),
+ coff_file_header = ProtoField.none("ar.coff.file_header", "COFF File Header"),
+ coff_machine = ProtoField.uint16("ar.coff.machine", "Machine Type", base.HEX, machine_types),
+ coff_number_of_sections = ProtoField.uint16("ar.coff.number_of_sections", "Number of sections"),
+ coff_timedate = ProtoField.absolute_time("ar.coff.timedate", "Creation Datetime", base.UTC),
+ coff_symbol_table_ptr = ProtoField.uint32("ar.coff.symbol_table_ptr", "PointerToSymbolTable", base.HEX_DEC),
+ coff_number_of_symbols = ProtoField.uint32("ar.coff.number_of_symbols", "Number of symbols"),
+ coff_opt_header_size = ProtoField.uint16("ar.coff.opt_header_size", "Optional Header Size"),
+ coff_characteristics = ProtoField.uint16("ar.coff.characteristics", "Characteristics", base.HEX),
+ coff_section = ProtoField.none("ar.coff.section", "Section"),
+ coff_sect_name = ProtoField.stringz("ar.coff.sect.name", "Section Name"),
+ coff_sect_virtual_size = ProtoField.uint32("ar.coff.sect.virtual_size", "Virtual Size"),
+ coff_sect_virtual_addr = ProtoField.uint32("ar.coff.sect.virtual_addr", "Virtual Address"),
+ coff_sect_size = ProtoField.uint32("ar.coff.sect.size", "Raw Data Size"),
+ coff_sect_raw_data_ptr = ProtoField.uint32("ar.coff.sect.raw_data_ptr", "PointerToRawData", base.HEX_DEC),
+ coff_sect_relocs_ptr = ProtoField.uint32("ar.coff.sect.relocs_ptr", "PointerToRelocations", base.HEX_DEC),
+ coff_sect_linenums_ptr = ProtoField.uint32("ar.coff.sect.linenums_ptr", "PointerToLinenumbers", base.HEX_DEC),
+ coff_sect_number_of_relocs = ProtoField.uint16("ar.coff.sect.number_of_relocs", "Number of relocations"),
+ coff_sect_number_of_linenums = ProtoField.uint16("ar.coff.sect.number_of_linenums", "Number of line numbers"),
+ coff_sect_characteristics = ProtoField.uint32("ar.coff.sect.characteristics", "Characteristics", base.HEX),
+ coff_sect_data = ProtoField.bytes("ar.coff.sect.data", "Section Data"),
+ coff_reloc = ProtoField.none("ar.coff.reloc", "COFF Relocation"),
+ coff_reloc_virtual_addr = ProtoField.uint32("ar.coff.virtual_addr", "Virtual Address", base.HEX_DEC),
+ coff_reloc_symbol_table_index = ProtoField.uint32("ar.coff.symbol_table_index", "Symbol Table Index", base.HEX_DEC),
+ coff_reloc_type = ProtoField.uint16("ar.coff.type", "Relocation Type", base.HEX),
+ coff_reloc_type_x64 = ProtoField.uint16("ar.coff.type.x64", "Relocation Type", base.HEX, reloc_types_x64),
+ coff_sym = ProtoField.none("ar.coff.sym", "COFF Symbol Table Entry"),
+ coff_sym_shortname = ProtoField.string("ar.coff.sym.shortname", "Symbol Name"),
+ coff_sym_name = ProtoField.stringz("ar.coff.sym.name", "Symbol Name"),
+ coff_sym_name_zeroes = ProtoField.none("ar.coff.sym.name.zeroes", "Zeroes"),
+ coff_sym_name_offset = ProtoField.uint32("ar.coff.sym.name.offset", "Offset"),
+ coff_sym_value = ProtoField.uint32("ar.coff.sym.value", "Value", base.HEX_DEC),
+ coff_sym_section_number = ProtoField.uint16("ar.coff.sym.section_number", "Section Number"),
+ coff_sym_type = ProtoField.uint16("ar.coff.sym.type", "Type", base.HEX, {[0] = "not a function", [0x20] = "function"}),
+ coff_sym_storage_class = ProtoField.uint8("ar.coff.sym.storage_class", "Storage Class"),
+ coff_sym_number_of_aux_symbols = ProtoField.uint8("ar.coff.sym.number_of_aux_symbols", "Number of auxilliary symbols"),
+
+ -- XXX expert info?
+ unprocessed = ProtoField.bytes("ar.unprocessed", "Unprocessed Data"),
+}
+proto_ar.fields = hf
+
+local function dissect_coff_first_linker_member(tvb, offset, file_size, tree, symbols_map)
+ local number_of_symbols = tvb(offset, 4):uint()
+ tree:add(hf.l1_number_of_symbols, tvb(offset, 4))
+ offset = offset + 4
+ local strings_offset = offset + 4 * number_of_symbols
+ for i = 0, number_of_symbols - 1 do
+ local str0len = tvb(strings_offset):strsize()
+ local str_tvb = tvb(strings_offset, str0len)
+ local subtree = tree:add(hf.l1_symbol_name, str_tvb)
+ local fileoff_tvb = tvb(offset + 4 * i, 4)
+ subtree:add(hf.l1_file_offset, fileoff_tvb)
+ strings_offset = strings_offset + str0len
+
+ local file_offset = fileoff_tvb:uint()
+ local symbols_list = symbols_map[file_offset]
+ if not symbols_list then
+ symbols_list = {}
+ symbols_map[file_offset] = symbols_list
+ end
+ table.insert(symbols_list, str_tvb:stringz())
+ end
+end
+
+local function dissect_coff_second_linker_member(tvb, offset, file_size, tree, symbols_map)
+ local number_of_members = tvb(offset, 4):le_uint()
+ tree:add_le(hf.l2_number_of_members, tvb(offset, 4))
+ offset = offset + 4
+
+ local file_offset = offset
+ offset = offset + 4 * number_of_members
+
+ local number_of_symbols = tvb(offset, 4):le_uint()
+ tree:add_le(hf.l2_number_of_symbols, tvb(offset, 4))
+ offset = offset + 4
+
+ local strings_offset = offset + 2 * number_of_symbols
+ for i = 0, number_of_symbols - 1 do
+ local str0len = tvb(strings_offset):strsize()
+ local str_tvb = tvb(strings_offset, str0len)
+ local subtree = tree:add(hf.l2_symbol_name, str_tvb)
+ local index_tvb = tvb(offset + 2 * i, 2)
+ subtree:add_le(hf.l2_index, index_tvb)
+ local fileoff_tvb = tvb(file_offset + 4 * (index_tvb:le_uint() - 1), 4)
+ subtree:add_le(hf.l2_file_offset, fileoff_tvb)
+ strings_offset = strings_offset + str0len
+
+ local file_offset = fileoff_tvb:le_uint()
+ local symbols_list = symbols_map[file_offset]
+ if not symbols_list then
+ symbols_list = {}
+ symbols_map[file_offset] = symbols_list
+ end
+ table.insert(symbols_list, str_tvb:stringz())
+ end
+end
+
+local function dissect_coff_longnames_member(tvb, offset, file_size, tree, member_names_map)
+ local offset_begin = offset
+ local offset_end = offset + file_size
+ while offset < offset_end do
+ local namelen = tvb(offset):strsize()
+ local name_tvb = tvb(offset, namelen)
+ tree:add(hf.ln_member_name, name_tvb)
+ member_names_map[offset - offset_begin] = name_tvb:stringz()
+ offset = offset + namelen
+ end
+end
+
+local function dissect_coff_import_header(tvb, offset, file_size, tree)
+ local offset_begin = offset
+ local subtree = tree:add(hf.import_header, tvb(offset, 20))
+ subtree:add_le(hf.imp_sig1, tvb(offset, 2))
+ subtree:add_le(hf.imp_sig2, tvb(offset + 2, 2))
+ subtree:add_le(hf.imp_version, tvb(offset + 4, 2))
+ subtree:add_le(hf.imp_machine, tvb(offset + 6, 2))
+ subtree:add_le(hf.imp_timedate, tvb(offset + 8, 4))
+ subtree:add_le(hf.imp_size, tvb(offset + 12, 4))
+ local hint_tvb = tvb(offset + 16, 2)
+ subtree:add_le(hf.imp_hint, hint_tvb)
+ local typeval = tvb(offset + 18, 2):le_uint()
+ subtree:add_le(hf.imp_type, tvb(offset + 18, 2))
+ subtree:add_le(hf.imp_name_type, tvb(offset + 18, 2))
+ offset = offset + 20
+ local type_str = import_types[bit32.band(typeval, 3)]
+ local name_type_str = import_name_types[bit32.band(bit32.rshift(typeval, 2), 7)]
+ local symbol0len = tvb(offset):strsize()
+ local symbol0tvb = tvb(offset, symbol0len)
+ subtree:add(hf.imp_symbol_name, symbol0tvb)
+ offset = offset + symbol0len
+ local dll0len = tvb(offset):strsize()
+ local dll0tvb = tvb(offset, dll0len)
+ subtree:add(hf.imp_dll, dll0tvb)
+ offset = offset + dll0len
+ subtree:set_text(string.format("Import: %s from %s (%s %s hint=%d)",
+ symbol0tvb:stringz(), dll0tvb:stringz(),
+ type_str or "UnkType", name_type_str or "UnkNameType",
+ hint_tvb:le_uint()))
+ --tree:append_text(string.format(" - %s", symbol0tvb:stringz()))
+ tree:append_text(string.format(" hint=%d", hint_tvb:le_uint()))
+ subtree:set_len(offset - offset_begin)
+ return offset
+end
+
+local function dissect_coff_reloc(tvb, offset, tree, hf_reloc_type, type_map)
+ local subtree = tree:add(hf.coff_reloc, tvb(offset, 10))
+ local va_tvb = tvb(offset, 4)
+ subtree:add_le(hf.coff_reloc_virtual_addr, va_tvb)
+ local symidx_tvb = tvb(offset + 4, 4)
+ subtree:add_le(hf.coff_reloc_symbol_table_index, symidx_tvb)
+ local type_tvb = tvb(offset + 8, 2)
+ subtree:add_le(hf_reloc_type, type_tvb)
+ local reloc_type = type_tvb:le_uint()
+ if type_map then
+ reloc_type = type_map[reloc_type]
+ end
+ subtree:append_text(string.format(" va=0x%08x %d %s",
+ va_tvb:le_uint(), symidx_tvb:le_uint(), reloc_type))
+end
+
+local function dissect_coff_section(tvb, offset, tree, machine, section_number, coff_start)
+ local subtree = tree:add(hf.coff_section, tvb(offset, 40))
+ local name = tvb:raw(offset, 8)
+ subtree:add_le(hf.coff_sect_name, tvb(offset, 8))
+ subtree:append_text(string.format(" %d: %s", section_number, name))
+ subtree:add_le(hf.coff_sect_virtual_size, tvb(offset + 8, 4))
+ subtree:add_le(hf.coff_sect_virtual_addr, tvb(offset + 12, 4))
+ local data_size = tvb(offset + 16, 4):le_uint()
+ subtree:add_le(hf.coff_sect_size, tvb(offset + 16, 4))
+ local data_ptr = coff_start + tvb(offset + 20, 4):le_uint()
+ subtree:add_le(hf.coff_sect_raw_data_ptr, tvb(offset + 20, 4))
+ local reloc_ptr = coff_start + tvb(offset + 24, 4):le_uint()
+ subtree:add_le(hf.coff_sect_relocs_ptr, tvb(offset + 24, 4))
+ subtree:add_le(hf.coff_sect_linenums_ptr, tvb(offset + 28, 4))
+ local number_of_relocs = tvb(offset + 32, 2):le_uint()
+ subtree:add_le(hf.coff_sect_number_of_relocs, tvb(offset + 32, 2))
+ subtree:add_le(hf.coff_sect_number_of_linenums, tvb(offset + 34, 2))
+ subtree:add_le(hf.coff_sect_characteristics, tvb(offset + 36, 4))
+ offset = offset + 40
+ subtree:add(hf.coff_sect_data, tvb(data_ptr, data_size))
+ if relocs_ptr ~= coff_start and number_of_relocs ~= 0 then
+ local hf_reloc_type, type_map
+ if machine == 0x8664 then
+ hf_reloc_type = hf.coff_reloc_type_x64
+ type_map = reloc_types_x64
+ else
+ hf_reloc_type = hf.coff_reloc_type
+ end
+ subtree:append_text(string.format(" (relocs=%d)", number_of_relocs))
+ for i = 0, number_of_relocs - 1 do
+ dissect_coff_reloc(tvb, reloc_ptr + 10 * i, subtree, hf_reloc_type, type_map)
+ end
+ end
+ return offset
+end
+
+local function dissect_coff_symbol_name(tvb, offset, tree, strings_offset)
+ if tvb(offset, 4):le_uint() ~= 0 then
+ tree:add_le(hf.coff_sym_shortname, tvb(offset, 8))
+ tree:append_text(string.format(": %s", tvb:raw(offset, 8):gsub("\0+$", "")))
+ else
+ local name_offset_tvb = tvb(offset + 4, 4)
+ local name_tvb = tvb(strings_offset + name_offset_tvb:le_uint())
+ local nametree = tree:add(hf.coff_sym_name, name_tvb)
+ nametree:add_le(hf.coff_sym_name_zeroes, tvb(offset, 4))
+ nametree:add_le(hf.coff_sym_name_offset, name_offset_tvb)
+ tree:append_text(string.format(": %s", name_tvb:stringz()))
+ end
+end
+
+local function dissect_coff_symbol_record(tvb, offset, tree, symbol_index, string_table_ptr)
+ local subtree = tree:add(hf.coff_sym, tvb(offset, 18))
+ subtree:append_text(string.format(" %d", symbol_index))
+ dissect_coff_symbol_name(tvb, offset, subtree, string_table_ptr)
+ subtree:add_le(hf.coff_sym_value, tvb(offset + 8, 4))
+ subtree:add_le(hf.coff_sym_section_number, tvb(offset + 12, 2))
+ subtree:add_le(hf.coff_sym_type, tvb(offset + 14, 2))
+ subtree:add_le(hf.coff_sym_storage_class, tvb(offset + 16, 1))
+ subtree:add_le(hf.coff_sym_number_of_aux_symbols, tvb(offset + 17, 1))
+end
+
+local function dissect_coff_file_header(tvb, offset, file_size, tree)
+ local coff_start = offset
+ local subtree = tree:add(hf.coff_file_header, tvb(offset, 20))
+ local machine = tvb(offset, 2):le_uint()
+ subtree:add_le(hf.coff_machine, tvb(offset, 2))
+ local number_of_sections = tvb(offset + 2, 2):le_uint()
+ subtree:add_le(hf.coff_number_of_sections , tvb(offset + 2, 2))
+ subtree:add_le(hf.coff_timedate, tvb(offset + 4, 4))
+ local symbol_table_ptr = coff_start + tvb(offset + 8, 4):le_uint()
+ subtree:add_le(hf.coff_symbol_table_ptr, tvb(offset + 8, 4))
+ local number_of_symbols = tvb(offset + 12, 4):le_uint()
+ subtree:add_le(hf.coff_number_of_symbols, tvb(offset + 12, 4))
+ subtree:add_le(hf.coff_opt_header_size, tvb(offset + 16, 2))
+ subtree:add_le(hf.coff_characteristics, tvb(offset + 18, 2))
+ offset = offset + 20
+ for i = 1, number_of_sections do
+ offset = dissect_coff_section(tvb, offset, tree, machine, i, coff_start)
+ end
+ if symbol_table_ptr ~= coff_start and number_of_symbols ~= 0 then
+ local string_table_ptr = symbol_table_ptr + 18 * number_of_symbols
+ for i = 0, number_of_symbols - 1 do
+ local symbol_record_offset = symbol_table_ptr + 18 * i
+ dissect_coff_symbol_record(tvb, symbol_record_offset, tree, i, string_table_ptr)
+ end
+ end
+ -- XXX this assumes that all data is covered by the sections.
+ return offset + file_size
+end
+
+local function dissect_coff_archive_member(tvb, offset, file_size, tree)
+ local offset_end = offset + file_size
+ if tvb(offset, 4):le_uint() == 0xffff0000 then
+ offset = dissect_coff_import_header(tvb, offset, file_size, tree)
+ else
+ offset = dissect_coff_file_header(tvb, offset, file_size, tree)
+ end
+ if offset < offset_end then
+ tree:add(hf.unprocessed, tvb(offset, offset_end - offset))
+ end
+end
+
+
+local function get_coff_type(file_id, member_number)
+ if member_number == 1 and file_id == "/" then
+ -- The archive member is one of the two linker members.
+ -- Both of the linker members have this name.
+ return "First Linker Member", dissect_coff_first_linker_member
+ elseif member_number == 2 and file_id == "/" then
+ return "Second Linker Member", dissect_coff_second_linker_member
+ elseif member_number == 3 and file_id == "//" then
+ -- The archive member is the longnames member, which consists of a
+ -- series of null-terminated ASCII strings. The longnames member is the
+ -- third archive member and must always be present even if the contents
+ -- are empty.
+ return "Longnames Member", dissect_coff_longnames_member
+ elseif member_number >= 4 and string.match(file_id, "^/%d+$") then
+ -- The name of the archive member is located at offset n within the
+ -- longnames member. The number n is the decimal representation of the
+ -- offset. For example: "/26" indicates that the name of the archive
+ -- member is located 26 bytes beyond the beginning of the longnames
+ -- member contents.
+ local label = string.format("OBJ File %d Contents", member_number - 3)
+ return label, dissect_coff_archive_member
+ else
+ -- XXX is this correct? This seems true for MinGW .dll.a files.
+ local label = string.format("OBJ %d", member_number - 2)
+ return label, dissect_coff_archive_member
+ end
+end
+
+local function dissect_one(tvb, offset, pinfo, tree, member_number, symbols_map, member_names_map)
+ -- File header (based on the Wikipedia article):
+ -- 0 16 File identifier ASCII
+ -- 16 12 File modification timestamp Decimal
+ -- 28 6 Owner ID Decimal
+ -- 34 6 Group ID Decimal
+ -- 40 8 File mode Octal
+ -- 48 10 File size in bytes Decimal
+ -- 58 2 Ending characters 0x60 0x0A
+ local subtree = tree:add(hf.entry, tvb(offset, 60))
+ local htree = subtree:add(hf.header, tvb(offset, 60))
+ local file_id = tvb:raw(offset, 16):gsub(" +$", "")
+ htree:append_text(string.format(": id=%s", file_id))
+ local entry_label, data_dissector = get_coff_type(file_id, member_number)
+ if entry_label then
+ subtree:set_text(entry_label)
+ if data_dissector == dissect_coff_archive_member then
+ local member_name = member_names_map[tonumber(file_id:sub(2))]
+ if member_name then
+ subtree:append_text(string.format(" (%s)", member_name))
+ end
+ end
+ else
+ subtree:append_text(string.format(": %s", file_id))
+ end
+ local sym = symbols_map[offset]
+ if sym then
+ local syms = table.concat(sym, ", ")
+ subtree:append_text(string.format(" for %s", syms))
+ end
+ htree:add(hf.file_id, tvb(offset, 16))
+ htree:add(hf.file_mtime, tvb(offset + 16, 12), NSTime(tvb:raw(offset + 16, 12)))
+ htree:add(hf.owner_id, tvb(offset + 28, 6))
+ htree:add(hf.group_id, tvb(offset + 34, 6))
+ htree:add(hf.file_mode, tvb(offset + 40, 8))
+ local file_size = tonumber(tvb:raw(offset + 48, 10))
+ htree:add(hf.file_size, tvb(offset + 48, 10))
+ htree:append_text(string.format(" filesize=%d", file_size))
+ htree:add(hf.end_chars, tvb(offset + 58, 2))
+ htree:add(hf.file_data, tvb(offset + 60, file_size))
+ if data_dissector == dissect_coff_first_linker_member or data_dissector == dissect_coff_second_linker_member then
+ data_dissector(tvb, offset + 60, file_size, subtree, symbols_map)
+ elseif data_dissector == dissect_coff_longnames_member then
+ data_dissector(tvb, offset + 60, file_size, subtree, member_names_map)
+ elseif data_dissector then
+ data_dissector(tvb, offset + 60, file_size, subtree)
+ end
+ offset = offset + 60 + file_size
+ local padlen = 0
+ if file_size % 2 == 1 then
+ htree:add(hf.padding, tvb(offset, 1))
+ offset = offset + 1
+ end
+ subtree:set_len(60 + file_size + padlen)
+ return offset
+end
+
+function proto_ar.dissector(tvb, pinfo, tree)
+ -- Magic 8 bytes followed by multiple file header + data
+ pinfo.cols.protocol = "ar"
+ --pinfo.cols.info = ""
+ tree:add(hf.magic, tvb(0, 8))
+ local next_offset = 8
+ local member_number = 1
+ local symbols_map = {}
+ local member_names_map = {}
+ while next_offset and next_offset < tvb:len() do
+ next_offset = dissect_one(tvb, next_offset, pinfo, tree, member_number, symbols_map, member_names_map)
+ member_number = member_number + 1
+ end
+ return next_offset
+end
+
+local function ar_heur(tvb, pinfo, tree)
+ if tvb:len() < 8 or tvb:raw(0, 8) ~= "!<arch>\n" then
+ return false
+ end
+
+ proto_ar.dissector(tvb, pinfo, tree)
+ return true
+end
+
+-- Register MIME types in case an ar file appears over HTTP.
+DissectorTable.get("media_type"):add("application/x-archive", proto_ar)
+
+-- Ensure that files can directly be opened (after any FileHandler has accepted
+-- it, see below).
+proto_ar:register_heuristic("wtap_file", ar_heur)
+
+
+--
+-- File handler (for directly interpreting opening a Zip file in Wireshark)
+-- Actually, all it does is recognizing a Zip file and passing one packet to the
+-- MIME dissector.
+--
+
+local ar_fh = FileHandler.new("ar", "ar", ".LIB and .a archive file reader", "rms")
+
+-- Check if file is really a ar file (return true if it is)
+function ar_fh.read_open(file, cinfo)
+ if file:read(8) ~= "!<arch>\n" then
+ return false
+ end
+
+ -- Find end of file and rewind.
+ local endpos, err = file:seek("end")
+ if not endpos then error("Error while finding end! " .. err) end
+ local ok, err = file:seek("set", 0)
+ if not ok then error("Non-seekable file! " .. err) end
+
+ cinfo.encap = wtap_encaps.MIME
+ cinfo.private_table = {
+ endpos = endpos,
+ }
+
+ return true
+end
+
+-- Read next packet (returns begin offset or false on error)
+local function ar_fh_read(file, cinfo, finfo)
+ local p = cinfo.private_table
+ local curpos = file:seek("cur")
+
+ -- Fal on EOF
+ if curpos >= p.endpos then return false end
+
+ finfo.original_length = p.endpos - curpos
+ finfo.captured_length = p.endpos - curpos
+
+ if not finfo:read_data(file, finfo.captured_length) then
+ -- Partial read?
+ print("Hmm, partial read, curpos=" .. curpos .. ", len: " .. finfo.captured_length)
+ return false
+ end
+
+ return curpos
+end
+ar_fh.read = ar_fh_read
+
+-- Reads packet at offset (returns true on success and false on failure)
+function ar_fh.seek_read(file, cinfo, finfo, offset)
+ file:seek("set", offset)
+ -- Return a boolean since WS < 2.4 has an undocumented "feature" where
+ -- strings (including numbers) are treated as data.
+ return ar_fh_read(file, cinfo, finfo) ~= false
+end
+
+-- Hints for when to invoke this dissector.
+ar_fh.extensions = "lib;a"
+
+register_filehandler(ar_fh)