Dynamic
Dynamic linking interface.
This module provides an interface to analyze various aspects of dynamically linked programs.
It also defines a hook that watches for changes to the link map communicated by ld.so, and exposes an event that other parts of pwndbg can tap into, but one that may have a somewhat obtuse beahvior, due to limitations in GDB. See r_debug_install_link_map_changed_hook
for more information.
DYNAMIC_SECTION_ALLOW_MULTIPLE = {elf.DT_NEEDED}
module-attribute
¶
DYNAMIC_SECTION_REQUIRED_TAGS = {elf.DT_STRTAB, elf.DT_STRSZ, elf.DT_SYMTAB, elf.DT_SYMENT}
module-attribute
¶
R_DEBUG_LINK_MAP_CHANGED_HOOK = None
module-attribute
¶
R_DEBUG_LINK_MAP_CHANGED_LISTENERS: Set[Callable[..., Any]] = set()
module-attribute
¶
CStruct
¶
Utility class for reading fields off of C structs.
Without proper debug information it cannot be guaranteed that the calculated field offsets are correct, therefore, reasonable caution should be exercised when using this class. The assumptions made are: - Padding is added between fields so that all internal members are correctly aligned, as long as the struct itself is correctly aligned. - The alignment of the struct is the same as the alignment of its most strictly aligned member. - Padding is added to the end of the struct so that sequentially laid out instances are always correctly aligned. - Stuct sizes must be greater than or equal to 1 byte.
While these assumptions do not apply in all cases, they should be good enough for the structs in ld.so and in the ELF program images.
align = alignment
class-attribute
instance-attribute
¶
converters: Dict[str, type] = {}
class-attribute
instance-attribute
¶
offsets: Dict[str, int] = {}
class-attribute
instance-attribute
¶
size = current_offset
class-attribute
instance-attribute
¶
types: Dict[str, pwndbg.dbg_mod.Type] = {}
class-attribute
instance-attribute
¶
__init__(fields)
¶
elf32_sym()
staticmethod
¶
Creates a new instance describing the Elf32_Sym srtucture.
elf64_sym()
staticmethod
¶
Creates a new instance describing the Elf64_Sym structure.
elfNN_dyn()
staticmethod
¶
Creates a new instance describing the ElfNN_Dyn structure, suitable for the architecture of the inferior.
elfNN_rel()
staticmethod
¶
Creates a new instance describing the ElfNN_Rel structure, suitable for the architecture of the inferior.
elfNN_rela()
staticmethod
¶
Creates a new instance describing the ElfNN_Rela structure, suitable for the architecture of the inferior.
has_field(name)
¶
Returns whether a field with the given name exists in this struct.
link_map()
staticmethod
¶
Creates a new instance describing the ABI-stable part of the link_map struct.
r_debug()
staticmethod
¶
Creates a new instance describing the ABI-stable part of the r_debug struct.
read(address, name)
¶
Reads the field with the given name from the struct instance located at the given address.
DynamicSegment
¶
Parser for the DYNAMIC segment present in a binary image.
address = address
instance-attribute
¶
elf_dyn = elf_dyn
instance-attribute
¶
entries = count
instance-attribute
¶
entries_by_tag: Dict[Any, Any] = sections
class-attribute
instance-attribute
¶
has_jmprel = elf.DT_JMPREL in sections and elf.DT_PLTREL in sections and elf.DT_PLTRELSZ in sections
class-attribute
instance-attribute
¶
has_rel = elf.DT_REL in sections and elf.DT_RELSZ in sections and elf.DT_RELENT in sections
class-attribute
instance-attribute
¶
has_rela = elf.DT_RELA in sections and elf.DT_RELASZ in sections and elf.DT_RELAENT in sections
class-attribute
instance-attribute
¶
jmprel_addr = 0
class-attribute
instance-attribute
¶
jmprel_elem = None
class-attribute
instance-attribute
¶
jmprel_r_info_fn = None
class-attribute
instance-attribute
¶
jmprel_r_sym = elf32_r_sym
instance-attribute
¶
jmprel_r_sym_fn = None
class-attribute
instance-attribute
¶
jmprel_r_type = elf32_r_type
instance-attribute
¶
load_bias = load_bias
instance-attribute
¶
rel_addr = 0
class-attribute
instance-attribute
¶
rel_elem = None
class-attribute
instance-attribute
¶
rel_r_info_fn = None
class-attribute
instance-attribute
¶
rel_r_sym = elf32_r_sym
instance-attribute
¶
rel_r_sym_fn = None
class-attribute
instance-attribute
¶
rel_r_type = elf32_r_type
instance-attribute
¶
rela_addr = 0
class-attribute
instance-attribute
¶
rela_elem = None
class-attribute
instance-attribute
¶
rela_r_info_fn = None
class-attribute
instance-attribute
¶
rela_r_sym = elf32_r_sym
instance-attribute
¶
rela_r_sym_fn = None
class-attribute
instance-attribute
¶
rela_r_type = elf32_r_type
instance-attribute
¶
strtab_addr = self.dyn_array_read_tag_val(elf.DT_STRTAB)
class-attribute
instance-attribute
¶
strtab_size = self.dyn_array_read_tag_val(elf.DT_STRSZ)
class-attribute
instance-attribute
¶
symtab_addr = self.dyn_array_read_tag_val(elf.DT_SYMTAB)
class-attribute
instance-attribute
¶
symtab_elem = None
class-attribute
instance-attribute
¶
__init__(address, load_bias)
¶
dyn_array_read(i, field)
¶
Reads the requested field from the entry of given index in the dynamic array.
dyn_array_read_tag_val(tag)
¶
Reads the d_un
field from the entry of given tag in the dynamic array. Must not be a tag that allows multiple entries.
jmprel_entry_count()
¶
Returns the number of JMPREL entries.
jmprel_has_addend()
¶
Returns whether the r_addend
field is available in entries of JMPREL.
jmprel_read(i, field)
¶
Reads the requested field from the entry of the given index in JMPREL.
rel_entry_count()
¶
Returns the number of REL entries.
rel_read(i, field)
¶
Reads the requested field from the entry of the given index in REL.
rela_entry_count()
¶
Returns the number of RELA entries.
rela_read(i, field)
¶
Reads the requested field from the entry of the given index in RELA.
string(i)
¶
Reads the string at index i from the string table.
symtab_read(i, field)
¶
Reads the requested field from the entry of given index in the symbol table.
LinkMapEntry
¶
An entry in the link map.
link_map = CStruct.link_map()
instance-attribute
¶
link_map_address = address
instance-attribute
¶
__init__(address)
¶
__repr__()
¶
dynamic()
¶
The pointer to the memory mapped dynamic segment of the binary image.
load_bias()
¶
The difference between the addresses in the data structures of the binary image and the actual location of the data being pointed to by them in the address space of the inferior. This number will never be negative.
Aditionally, for DYN images, such as PIE executables and shared libraries, this value is the same as the base load address of the image.
The term "load bias" comes from the ELF binary format loading procedure in the Linux Kernel.
name()
¶
The name of the binary image this entry describes.
next()
¶
The next entry in the chain, if any.
prev()
¶
The previous entry in the chain, if any.
elf32_r_sym(r_info)
¶
Returns the r_sym portion of the r_info relocation field for ELF32.
elf32_r_type(r_info)
¶
Returns the r_type portion of the r_info relocation field for ELF32.
elf64_r_sym(r_info)
¶
Returns the r_sym portion of the r_info relocation field for ELF64.
elf64_r_type(r_info)
¶
Returns the r_type portion of the r_info relocation field for ELF64.
is_dynamic()
¶
Returns whether the current inferior is dynamic.
Not all programs are dynamically linked, or even need the dynamic loader at all. Since this module is entirely reliant on at least the presence of the dynamic loader, and really only makes sense for dynamic programs, it should not be used at all with programs that don't participate in dynamic linkage, or when there is a dynamic linker, but we have no way to talk to it.
link_map()
¶
Iterator over all the entries in the link map.
link_map_head()
¶
Acquires a reference to the head entry of the link map.
r_debug_install_link_map_changed_hook()
¶
Installs the r_debug-based hook to the change event of the link map.
This function is a bit tricky, because ideally we want it to be run as soon as possible, before even the dynamic linker runs, but after both it and the main binary have been mapped into the address space of the inferior. While doing this manually would be trivial - seeing as there is a command in GDB that gives the user control at the exact place we would like -, there does not seem to be a way of easily doing this from inside Python.
Because of this, parts of the code that rely on the hook should try calling this function and firing their own listeners manually at least once.
r_debug_link_map_changed_add_listener(handler)
¶
Install a callback to be called whenever r_debug signal of there being a change in the link map link map is triggered.
Keep in mind this function may be called before the hook that calls the listeners is installed, and, until it is installed, no listener callbacks will actually be triggered. See r_debug_install_link_map_changed_hook
.
r_debug_link_map_changed_hook()
¶
Hook that gets activated whenever the link map changes.
The r_debug structure, in addition to having a refence to the head of the link map, also has, in its ABI-stable part, a reference to an address that can have a breakpoint attached to it, such that whenever the contents of the link map change, that breakpoint will be triggered1.
We take advantage of that here, by installing our own breakpoint in that location, and watching for trigger events, so that we can notify other bits of pwndbg that the contents of the link_map()
function will be different.
r_debug_link_map_changed_remove_listener(handler)
¶
Removes a listener previously installed with r_debug_link_map_changed_add_listener().