Skip to content

Add DT_NEEDED dependency injection#49

Merged
xoofx merged 4 commits into
xoofx:masterfrom
ProjectSynchro:dt-needed-injection
Jul 23, 2026
Merged

Add DT_NEEDED dependency injection#49
xoofx merged 4 commits into
xoofx:masterfrom
ProjectSynchro:dt-needed-injection

Conversation

@ProjectSynchro

Copy link
Copy Markdown
Contributor

Builds on #48. This PR is stacked on it, so the diff to look at is just the injection commits on top.

Adds ElfFile.AddNeededLibrary(name), which injects a DT_NEEDED dependency into an existing dynamically-linked image so the loader loads that library at startup. It's essentially patchelf --add-needed as an in-process .NET API.

What's new

ElfFile.AddNeededLibrary(string libraryName). It's address-preserving: no existing section changes byte offset, so existing symbols, relocations and code stay valid. The mechanism is the same idea patchelf uses:

  • Grows .dynstr with the new name and adds a DT_NEEDED entry.
  • Relocates the .dynamic and .dynstr sections to end-of-file, backfilling the space they vacated with equal-size padding so every other section keeps its offset.
  • Maps the relocated region with a new PT_LOAD built from a spare PT_NOTE program header, so the program-header table doesn't grow.
  • Repoints PT_DYNAMIC, DT_STRTAB/DT_STRSZ, and the _DYNAMIC symbol at the new location.

Because the sections move (not just the segment), section and segment stay consistent:
Both readelf -d and a LibObjectFile re-read see the injected dependency. You can use that to check whether a binary is already patched, so re-running the injection is a no-op.

Trade-offs / limits (documented and enforced with diagnostics)

  • Requires a PT_NOTE to repurpose and a PT_DYNAMIC (a dynamically-linked image). If either is
    missing it throws rather than producing a broken file.
  • The repurposed PT_NOTE's contents (e.g. the build-id note) drop from the load image.
  • The original .dynamic/.dynstr bytes stay in the file as padding. This is the same trade-off patchelf makes.

Tests

  • In-process: injecting into a real shared object repurposes a PT_NOTE into a PT_LOAD, moves PT_DYNAMIC, and resolving DT_NEEDED the way the loader does (PT_DYNAMIC -> DT_STRTAB) shows existing dependencies preserved and the injected one resolvable, and the section view agrees with it. Plus rejection of a non-dynamic file.
  • Verified in the docker test image: a patched executable and a dlopen'd shared object both load and run with the injected library's constructor firing, and eu-elflint seem happy versus the original binary.

ProjectSynchro and others added 4 commits July 23, 2026 14:12
There was no way to add a dependency to an existing dynamically-linked
image. Growing .dynamic and .dynstr in place is not viable: it would
shift every later section's file offset while its virtual address stays
fixed, breaking the loader's vaddr-to-offset mapping and every stored
address reference.

Adds ElfFile.AddNeededLibrary, which never changes an existing section's
byte offset. It relocates the .dynamic and .dynstr sections to
end-of-file (backfilling their old offsets with equal-size padding so no
other section moves), maps them with a PT_LOAD built from a spare
PT_NOTE program header, and repoints PT_DYNAMIC, DT_STRTAB/DT_STRSZ and
the _DYNAMIC symbol at the new location. Section and segment stay
consistent, so a re-read sees the injected dependency.
Covers ElfFile.AddNeededLibrary in-process: injecting into a real shared
object repurposes a PT_NOTE into a PT_LOAD and moves PT_DYNAMIC, and
resolving DT_NEEDED the way the loader does (PT_DYNAMIC to the dynamic
array, then DT_STRTAB) shows the existing dependencies preserved and the
injected one resolvable, with the section view agreeing. Also checks
that a non-dynamic object file is rejected.
Adds ElfFile.AddNeededLibrary to the ELF feature list.
@xoofx
xoofx merged commit 6261b5d into xoofx:master Jul 23, 2026
1 check failed
@xoofx

xoofx commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants