elf.lua: decode program headers
This commit is contained in:
parent
233a69e859
commit
52411d0a2e
195
plugins/elf.lua
195
plugins/elf.lua
|
@ -20,6 +20,82 @@ local detect = function (c)
|
||||||
return c:read (4) == "\x7FELF"
|
return c:read (4) == "\x7FELF"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local ph_type_table = {
|
||||||
|
[0] = "unused segment",
|
||||||
|
[1] = "loadable segment",
|
||||||
|
[2] = "dynamic linking information",
|
||||||
|
[3] = "interpreter pathname",
|
||||||
|
[4] = "auxiliary information",
|
||||||
|
[5] = "reserved",
|
||||||
|
[6] = "the program header table itself",
|
||||||
|
[7] = "the thread-local storage template"
|
||||||
|
}
|
||||||
|
|
||||||
|
local xform_ph_flags = function (u32)
|
||||||
|
local info = {}
|
||||||
|
if u32 & 4 ~= 0 then table.insert (info, "read") end
|
||||||
|
if u32 & 2 ~= 0 then table.insert (info, "write") end
|
||||||
|
if u32 & 1 ~= 0 then table.insert (info, "execute") end
|
||||||
|
|
||||||
|
local junk = u32 & ~7
|
||||||
|
if junk ~= 0 then
|
||||||
|
table.insert (info, ("unknown: %#x"):format (junk))
|
||||||
|
end
|
||||||
|
|
||||||
|
if #info == 0 then return 0 end
|
||||||
|
|
||||||
|
local result = info[1]
|
||||||
|
for i = 2, #info do result = result .. ", " .. info[i] end
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
local decode_ph = function (elf, c)
|
||||||
|
local ph = {}
|
||||||
|
ph.type = c:u32 ("type: %s", function (u32)
|
||||||
|
-- TODO: there are more known weird values and ranges
|
||||||
|
name = ph_type_table[u32]
|
||||||
|
if name then return name end
|
||||||
|
return "unknown: %#x", u32
|
||||||
|
end)
|
||||||
|
if elf.class == 2 then ph.flags = c:u32 ("flags: %s", xform_ph_flags) end
|
||||||
|
ph.offset = elf.uwide (c, "offset in file: %#x")
|
||||||
|
ph.vaddr = elf.uwide (c, "virtual address: %#x")
|
||||||
|
ph.paddr = elf.uwide (c, "physical address: %#x")
|
||||||
|
ph.filesz = elf.uwide (c, "size in file: %d")
|
||||||
|
ph.memsz = elf.uwide (c, "sise in memory: %d")
|
||||||
|
if elf.class == 1 then ph.flags = c:u32 ("flags: %s", xform_ph_flags) end
|
||||||
|
ph.align = elf.uwide (c, "alignment: %d")
|
||||||
|
end
|
||||||
|
|
||||||
|
local decode_sh = function (elf, c)
|
||||||
|
-- TODO
|
||||||
|
end
|
||||||
|
|
||||||
|
local abi_table = {
|
||||||
|
[0] = "UNIX System V ABI",
|
||||||
|
[1] = "HP-UX operating system",
|
||||||
|
[2] = "NetBSD",
|
||||||
|
[3] = "GNU/Linux",
|
||||||
|
[4] = "GNU/Hurd",
|
||||||
|
[6] = "Solaris",
|
||||||
|
[7] = "AIX",
|
||||||
|
[8] = "IRIX",
|
||||||
|
[9] = "FreeBSD",
|
||||||
|
[10] = "TRU64 UNIX",
|
||||||
|
[11] = "Novell Modesto",
|
||||||
|
[12] = "OpenBSD",
|
||||||
|
[13] = "OpenVMS",
|
||||||
|
[14] = "Hewlett-Packard Non-Stop Kernel",
|
||||||
|
[15] = "AROS",
|
||||||
|
[16] = "FenixOS",
|
||||||
|
[17] = "Nuxi CloudABI",
|
||||||
|
[64] = "Bare-metal TMS320C6000",
|
||||||
|
[64] = "AMD HSA runtime",
|
||||||
|
[65] = "Linux TMS320C6000",
|
||||||
|
[97] = "ARM",
|
||||||
|
[255] = "Standalone (embedded) application"
|
||||||
|
}
|
||||||
|
|
||||||
local type_table = {
|
local type_table = {
|
||||||
[0] = "no file type",
|
[0] = "no file type",
|
||||||
[1] = "relocatable file",
|
[1] = "relocatable file",
|
||||||
|
@ -210,74 +286,20 @@ local machine_table = {
|
||||||
[247] = "Linux kernel bpf virtual machine"
|
[247] = "Linux kernel bpf virtual machine"
|
||||||
}
|
}
|
||||||
|
|
||||||
local decode32 = function (c)
|
|
||||||
-- TODO: like the 64-bit version, maybe try to merge the code somehow
|
|
||||||
end
|
|
||||||
|
|
||||||
local decode64 = function (c)
|
|
||||||
local type = c:u16 ("type of file: %s", function (u16)
|
|
||||||
name = type_table[u16]
|
|
||||||
if name then return name end
|
|
||||||
return "unknown: %d", u16
|
|
||||||
end)
|
|
||||||
local machine = c:u16 ("required architecture: %s", function (u16)
|
|
||||||
name = machine_table[u16]
|
|
||||||
if name then return name end
|
|
||||||
return "unknown: %d", u16
|
|
||||||
end)
|
|
||||||
local version = c:u32 ("version: %d")
|
|
||||||
local entry = c:u64 ("program entry address: %#x")
|
|
||||||
local ph_offset = c:u64 ("program header table offset: %#x")
|
|
||||||
local sh_offset = c:u64 ("section header table offset: %#x")
|
|
||||||
local flags = c:u32 ("processor-specific flags: %#x")
|
|
||||||
local eh_size = c:u16 ("ELF header size: %d")
|
|
||||||
local ph_entry_size = c:u16 ("program header size: %d")
|
|
||||||
local ph_number = c:u16 ("program header count: %d")
|
|
||||||
local sh_entry_size = c:u16 ("section header size: %d")
|
|
||||||
local sh_number = c:u16 ("section header count: %d")
|
|
||||||
local sh_string_index = c:u16 ("section header index for strings: %d")
|
|
||||||
|
|
||||||
-- TODO: decode all sections as well, see man 5 elf,
|
|
||||||
-- /usr/include/elf.h and /usr/include/llvm/Support/ELF.h
|
|
||||||
end
|
|
||||||
|
|
||||||
local abi_table = {
|
|
||||||
[0] = "UNIX System V ABI",
|
|
||||||
[1] = "HP-UX operating system",
|
|
||||||
[2] = "NetBSD",
|
|
||||||
[3] = "GNU/Linux",
|
|
||||||
[4] = "GNU/Hurd",
|
|
||||||
[6] = "Solaris",
|
|
||||||
[7] = "AIX",
|
|
||||||
[8] = "IRIX",
|
|
||||||
[9] = "FreeBSD",
|
|
||||||
[10] = "TRU64 UNIX",
|
|
||||||
[11] = "Novell Modesto",
|
|
||||||
[12] = "OpenBSD",
|
|
||||||
[13] = "OpenVMS",
|
|
||||||
[14] = "Hewlett-Packard Non-Stop Kernel",
|
|
||||||
[15] = "AROS",
|
|
||||||
[16] = "FenixOS",
|
|
||||||
[17] = "Nuxi CloudABI",
|
|
||||||
[64] = "Bare-metal TMS320C6000",
|
|
||||||
[64] = "AMD HSA runtime",
|
|
||||||
[65] = "Linux TMS320C6000",
|
|
||||||
[97] = "ARM",
|
|
||||||
[255] = "Standalone (embedded) application"
|
|
||||||
}
|
|
||||||
|
|
||||||
local decode = function (c)
|
local decode = function (c)
|
||||||
|
assert (c.position == 1)
|
||||||
if not detect (c ()) then error ("not an ELF file") end
|
if not detect (c ()) then error ("not an ELF file") end
|
||||||
|
|
||||||
local p = c.position, c:read (4)
|
local p = c.position, c:read (4)
|
||||||
c (p, p + 3):mark ("ELF magic")
|
c (p, p + 3):mark ("ELF magic")
|
||||||
|
|
||||||
local class = c:u8 ("ELF class: %s", function (u8)
|
local elf = {}
|
||||||
|
elf.class = c:u8 ("ELF class: %s", function (u8)
|
||||||
if u8 == 1 then return "32-bit" end
|
if u8 == 1 then return "32-bit" end
|
||||||
if u8 == 2 then return "64-bit" end
|
if u8 == 2 then return "64-bit" end
|
||||||
return "invalid: %d", u8
|
return "invalid: %d", u8
|
||||||
end)
|
end)
|
||||||
local data = c:u8 ("ELF data: %s", function (u8)
|
elf.data = c:u8 ("ELF data: %s", function (u8)
|
||||||
if u8 == 1 then
|
if u8 == 1 then
|
||||||
c.endianity = "le"
|
c.endianity = "le"
|
||||||
return "little-endian"
|
return "little-endian"
|
||||||
|
@ -288,22 +310,65 @@ local decode = function (c)
|
||||||
end
|
end
|
||||||
return "invalid: %d", u8
|
return "invalid: %d", u8
|
||||||
end)
|
end)
|
||||||
local version = c:u8 ("ELF version: %d")
|
elf.version = c:u8 ("ELF version: %d")
|
||||||
local abi = c:u8 ("OS ABI: %s", function (u8)
|
elf.abi = c:u8 ("OS ABI: %s", function (u8)
|
||||||
name = abi_table[u8]
|
name = abi_table[u8]
|
||||||
if name then return name end
|
if name then return name end
|
||||||
return "unknown: %d", u8
|
return "unknown: %d", u8
|
||||||
end)
|
end)
|
||||||
local abi_version = c:u8 ("OS ABI version: %d")
|
elf.abi_version = c:u8 ("OS ABI version: %d")
|
||||||
|
|
||||||
-- The padding is reserved, no big sense in marking it
|
-- The padding is reserved, no big sense in marking it
|
||||||
local padding = c:read (7)
|
local padding = c:read (7)
|
||||||
|
|
||||||
-- We cannot decode anything further as we don't know how
|
-- We cannot decode anything further if we don't know endianity
|
||||||
if data ~= 1 and data ~= 2 then return end
|
if elf.data ~= 1 and elf.data ~= 2 then return end
|
||||||
|
|
||||||
if class == 1 then decode32 (c) end
|
-- And the same applies to the class
|
||||||
if class == 2 then decode64 (c) end
|
if elf.class == 1 then elf.uwide = c.u32
|
||||||
|
elseif elf.class == 2 then elf.uwide = c.u64
|
||||||
|
else return end
|
||||||
|
|
||||||
|
elf.type = c:u16 ("type of file: %s", function (u16)
|
||||||
|
name = type_table[u16]
|
||||||
|
if name then return name end
|
||||||
|
return "unknown: %d", u16
|
||||||
|
end)
|
||||||
|
elf.machine = c:u16 ("required architecture: %s", function (u16)
|
||||||
|
name = machine_table[u16]
|
||||||
|
if name then return name end
|
||||||
|
return "unknown: %d", u16
|
||||||
|
end)
|
||||||
|
elf.version = c:u32 ("version: %d")
|
||||||
|
elf.entry = elf.uwide (c, "program entry address: %#x")
|
||||||
|
elf.ph_offset = elf.uwide (c, "program header table offset: %#x")
|
||||||
|
elf.sh_offset = elf.uwide (c, "section header table offset: %#x")
|
||||||
|
elf.flags = c:u32 ("processor-specific flags: %#x")
|
||||||
|
elf.eh_size = c:u16 ("ELF header size: %d")
|
||||||
|
c (1, elf.eh_size):mark ("ELF header")
|
||||||
|
|
||||||
|
elf.ph_entry_size = c:u16 ("program header size: %d")
|
||||||
|
elf.ph_number = c:u16 ("program header count: %d")
|
||||||
|
elf.sh_entry_size = c:u16 ("section header size: %d")
|
||||||
|
elf.sh_number = c:u16 ("section header count: %d")
|
||||||
|
elf.sh_string_index = c:u16 ("section header index for strings: %d")
|
||||||
|
|
||||||
|
-- TODO: decode all headers as well, see man 5 elf,
|
||||||
|
-- /usr/include/elf.h and /usr/include/llvm/Support/ELF.h
|
||||||
|
for i = 1, elf.ph_number do
|
||||||
|
local start = elf.ph_offset + (i - 1) * elf.ph_entry_size
|
||||||
|
local ph = c (1 + start, start + elf.ph_entry_size)
|
||||||
|
ph:mark ("ELF program header %d", i - 1)
|
||||||
|
decode_ph (elf, ph)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO: we will need to decode "sh_string_index" first to get names
|
||||||
|
for i = 1, elf.sh_number do
|
||||||
|
local start = elf.sh_offset + (i - 1) * elf.sh_entry_size
|
||||||
|
local sh = c (1 + start, start + elf.sh_entry_size)
|
||||||
|
sh:mark ("ELF section header %d", i - 1)
|
||||||
|
decode_sh (elf, sh)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
hex.register { type="elf", detect=detect, decode=decode }
|
hex.register { type="elf", detect=detect, decode=decode }
|
||||||
|
|
Loading…
Reference in New Issue