Hi all,
Hoping somebody can provide some comments re ELF files in memory.
My ultimate question is: How can I find the .bss section of an ELF
file in memory?
But I have a more specific one. Consider the following output from a
Volatility plugin I wrote which aims to parse the segments:
Volatility Foundation Volatility Framework 2.6
# First we grab the proc_maps which are mapped to the process of
interest (in this case, Xorg)...
# This mimics the linux_proc_maps plugin
Parsing proc maps...
/usr/lib/xorg/Xorg r-x start=0x55d4ddda4000 end=0x55d4ddfe0000 length=0x23c000
/usr/lib/xorg/Xorg r-- start=0x55d4de1e0000 end=0x55d4de1e2000 length=0x2000
/usr/lib/xorg/Xorg rw- start=0x55d4de1e2000 end=0x55d4de1ef000 length=0xd000
# Not listing anonymous maps for now.
# The we parse the ELF header which is at the start of the first
proc_map shown above
Parsing elf_ehdr...
Container({'e_flags': 0, 'e_shoff': 2401000, 'e_phoff': 64,
'e_shnum':
30, 'e_entry': 270368, 'e_version': 'EV_CURRENT',
'e_machine':
'EM_X86_64', 'e_phnum': 9, 'e_shentsize': 64, 'e_ident':
Container({'EI_DATA': 'ELFDATA2LSB', 'EI_OSABI':
'ELFOSABI_SYSV',
'EI_VERSION': 'EV_CURRENT', 'EI_CLASS': 'ELFCLASS64',
'EI_ABIVERSION':
0, 'EI_MAG': [127, 69, 76, 70]}), 'e_type': 'ET_DYN',
'e_phentsize':
56, 'e_shstrndx': 29, 'e_ehsize': 64})
# This looks sane, so let's go to e_phoff (64) and read the program header
Parsing segments...
0x55d4ddda4040 Segment<p_memsz=0x1f8, p_flags=0x5, p_offset=0x40,
p_type=PT_PHDR, p_align=0x8, p_paddr=0x40, p_filesz=0x1f8,
p_vaddr=0x40>
0x55d4ddda4078 Segment<p_memsz=0x1c, p_flags=0x4, p_offset=0x238,
p_type=PT_INTERP, p_align=0x1, p_paddr=0x238, p_filesz=0x1c,
p_vaddr=0x238>
0x55d4ddda40b0 Segment<p_memsz=0x23bdd4, p_flags=0x5, p_offset=0x0,
p_type=PT_LOAD, p_align=0x200000, p_paddr=0x0, p_filesz=0x23bdd4,
p_vaddr=0x0>
0x55d4ddda40e8 Segment<p_memsz=0x1f8f0, p_flags=0x6,
p_offset=0x23c408, p_type=PT_LOAD, p_align=0x200000, p_paddr=0x43c408,
p_filesz=0xdd98, p_vaddr=0x43c408>
0x55d4ddda4120 Segment<p_memsz=0x2e0, p_flags=0x6, p_offset=0x23dc78,
p_type=PT_DYNAMIC, p_align=0x8, p_paddr=0x43dc78, p_filesz=0x2e0,
p_vaddr=0x43dc78>
0x55d4ddda4158 Segment<p_memsz=0x44, p_flags=0x4, p_offset=0x254,
p_type=PT_NOTE, p_align=0x4, p_paddr=0x254, p_filesz=0x44,
p_vaddr=0x254>
0x55d4ddda4190 Segment<p_memsz=0x9904, p_flags=0x4, p_offset=0x1f2b50,
p_type=PT_GNU_EH_FRAME, p_align=0x4, p_paddr=0x1f2b50,
p_filesz=0x9904, p_vaddr=0x1f2b50>
0x55d4ddda41c8 Segment<p_memsz=0x0, p_flags=0x6, p_offset=0x0,
p_type=PT_GNU_STACK, p_align=0x10, p_paddr=0x0, p_filesz=0x0,
p_vaddr=0x0>
0x55d4ddda4200 Segment<p_memsz=0x1bf8, p_flags=0x4, p_offset=0x23c408,
p_type=PT_GNU_RELRO, p_align=0x1, p_paddr=0x43c408, p_filesz=0x1bf8,
p_vaddr=0x43c408>
# These segments look sane, and in fact the values match what I see
from `readelf --segments` against the Xorg binary on disk.
# I ignore the first PT_LOAD segment because the p_flags and p_vaddr
tell me the .bss isn't going to be in there. (As does the output from
`readelf --segments`)
# And I try to read the data pointed to by the p_vaddr of the second PT_LOAD
Testing PT_LOAD at 0x55d4ddda40e8.
# Let's re-print the segment to remind ourselves:
0x55d4ddda40e8 Segment<p_memsz=0x1f8f0, p_flags=0x6,
p_offset=0x23c408, p_type=PT_LOAD, p_align=0x200000, p_paddr=0x43c408,
p_filesz=0xdd98, p_vaddr=0x43c408>
# So starting at the base address (0x55d4ddda4000) + p_vaddr
(0x43c408) =0x55d4de1e0408, I should be able to read p_memsz (0x1f8f0)
bytes, right?
# Wrong... I can only read 0xebf7 (60,407) bytes before volatility
reports an error
Failed to read offset 0xebf8==60408
Notably, the starting offset, 0x55d4de1e0408, is in:
/usr/lib/xorg/Xorg r-- start=0x55d4de1e0000 end=0x55d4de1e2000 length=0x2000
but of course is bigger than the size of the proc_map.
I really do appreciate any comments you might have as to where my
understanding is lacking!
Adam