I'm trying to inject some compiled code into an elf executable. The strategy is to write some bytes at the end of the 'code' segment. The reason why I chose that segment is because I need my payload to be executed too. I'd like to extend the segment by the required amount, when the padding between segments is too small, so that it can host my payload. objcopy
can do that just fine with objcopy <exec> --update-section <name>=<file>
.
My host will be section .fini
, and the section after that one is .rodata
. After executing objcopy, the code segment's file size and memory image size are the correct amount. Section and segment offsets are also patched when they need to be. And the code is present at the expected offset (confirmed by objdump
).
My problem is that none of the segments' virtual addresses were patched, which causes the code segment to overlap on the next section/segment, which results in a segfault during _dl_start
because the code is considered to be in a read-only segment.
Below are some snippets from the output generated by readelf
.
before objcopy:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[16] .fini PROGBITS 00000000000a3e84 000a3e84
0000000000000009 0000000000000000 AX 0 0 4
[17] .rodata PROGBITS 00000000000a4000 000a4000
000000000003b488 0000000000000000 A 0 0 32
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000063000 0x0000000000063000 0x0000000000063000
0x0000000000040e8d 0x0000000000040e8d R E 0x1000
LOAD 0x00000000000a4000 0x00000000000a4000 0x00000000000a4000
0x0000000000043ccc 0x0000000000043ccc R 0x1000
and after:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[16] .fini PROGBITS 00000000000a3e84 000a3e84
00000000000002bd 0000000000000000 AX 0 0 4
[17] .rodata PROGBITS 00000000000a4000 000a5000
000000000003b488 0000000000000000 A 0 0 32
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000063000 0x0000000000063000 0x0000000000063000
0x0000000000041141 0x0000000000041141 R E 0x1000
LOAD 0x00000000000a5000 0x00000000000a4000 0x00000000000a4000
0x0000000000043ccc 0x0000000000043ccc R 0x1000
my system: Linux 6.1.0-13-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.55-1 (2023-09-29) x86_64 GNU/Linux
Does anybody know how to further patch the binary to make it functional while still having a valid elf in the end?
This isn't going to work -- you have a linked binary, which means the linker has "baked" data addresses into code.
You wish to move data to a different address, but that requires updating all of the "baked in" addresses, and the info (relocations) needed to perform such an update has already been discarded.
What you need to do is add a new executable segment (sections don't matter at runtime), and put your payload into that new segment.