I wrote some code that does the following:

  1. Searches for and finds an offset in a binary file to add code (looks for a sequence of 00s I can overwrite).

  2. Then, I change the entrypoint of the ELF to the above address.

  3. Then, I write my code to the address and jmp back to the original entrypoint.

So, what happens is when the binary starts it will execute code at the address I changed the entrypoint to, I can see my code in gdb but any kind of instruction other than nop will trigger a segfault.

Can ayone help me understand why this happen?

For the record, in the binary I am using, the place where I write my code is a place where I found a bunch of 00s. It is in the .eh_frame section.

I added the executable flag to the section in case that was the cause, but it did not help.

I am trying to add code to a "hello world" program written in C. An offset in the following section is located as a place to write code to:

Before any modifications the binary has the following:

Section: [17] .eh_frame
Addr: 00000000004005d0 Offset: 0005d0 Size: 0000f4 Flags: A
Entry point address:               0x400400

After my code runs:

Section: [17] .eh_frame
Addr: 00000000004005d0 Offset: 0005d0 Size: 0000f4 Flags: A**WX**
Entry point address:               **0x4006b6**

Inside GDB:

 Breakpoint 1, 0x00000000004006b6 in ?? ()
(gdb) x/10i $rip
=> 0x4006b6:    nop
   0x4006b7:    nop
   0x4006b8:    nop
   0x4006b9:    add    0x1,%ebx

When I hit the add 0x1, %ebx the program segfaults. ** I've also tried a add 0x1, %rbx.


I am pretty sure I found the issue.

When writing my assembly code I was using GCC and then using the eXamine command to get the bytes for each instruction but I was doing something like this:

__asm__("movl 0x00, %rax") (trying to access 0x00 location..)

Instead of __asm__("movl $0x00, %rax") (moving a 0 constant into register as I wanted).

So, I am an idiot but at least I realized it myself ;))

thanks all who looked and helped.

  • 1
    I'm voting to close this question as off-topic because it's about a very minor typo with GDB and no relevance to reverse engineering nor Radare/Linux/C. – Evan Carroll Dec 12 '18 at 3:19

The .eh_frame section is not a code section. Therefore, it is not an executable section and the memory allocated for it is non-executable memory. You can read it, but the CPU won't execute it.

One solution is to change the permissions for that section in the ELF header (in the sections listing). Another would be to find another code cave (that's how regions you can add code to are often called) in an executable section. You could also create your own section if you can't find an appropriate code cave.

P.S. An area full of nulls is not necessarily an area you can edit, those null bytes might still be used or parsed or whatever.

  • The section is has write/execute/alloc bits set. Initially it has just the alloc bit set but even when I set Write and Executable bits the code segfaults on any instruction other than nop, even simple add instructions. – joe Apr 21 '17 at 23:44
  • I don't think the answer correct, for an executable binary, something like code section doesn't have much sense. The ELF loader simply doesn't care about sections, it is interested in segments instead. – Ta Thanh Dinh May 2 '17 at 8:39

.eh_header is probably not executable but editing the section table won't help. You need to edit the segment (Program header) corresponding to this section. you can find out the segment using e.g. readelf -a:

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000000040 0x0000000000000040
                 0x0000000000000230 0x0000000000000230  R E    8
  INTERP         0x0000000000000270 0x0000000000000270 0x0000000000000270
                 0x000000000000001c 0x000000000000001c  R      1
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000020a28 0x0000000000020a28  R E    200000
  LOAD           0x0000000000020ab8 0x0000000000220ab8 0x0000000000220ab8
                 0x0000000000002e10 0x0000000000a53d58  RW     200000
  DYNAMIC        0x0000000000020c30 0x0000000000220c30 0x0000000000220c30
                 0x0000000000000250 0x0000000000000250  RW     8
  NOTE           0x000000000000028c 0x000000000000028c 0x000000000000028c
                 0x0000000000000020 0x0000000000000020  R      4
  TLS            0x0000000000020ab8 0x0000000000220ab8 0x0000000000220ab8
                 0x0000000000000000 0x0000000000000040  R      8
  GNU_EH_FRAME   0x000000000001c3d0 0x000000000001c3d0 0x000000000001c3d0
                 0x0000000000000ae4 0x0000000000000ae4  R      4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     10
  GNU_RELRO      0x0000000000020ab8 0x0000000000220ab8 0x0000000000220ab8
                 0x0000000000000548 0x0000000000000548  R      1
Section to Segment mapping:
Segment Sections...
01     .interp 
02     .interp .note.ABI-tag .hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .init .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame .gcc_except_table 
03     .preinit_array .init_array .fini_array .jcr .data.rel.ro .dynamic .got .data .bss 
04     .dynamic 
05     .note.ABI-tag 
06     .tbss 
07     .eh_frame_hdr 
09     .preinit_array .init_array .fini_array .jcr .data.rel.ro .dynamic .got 

in this example, .eh_frame is actually already in the executable segment (first LOAD entry, R-E), but if you patch e.g. .data.rel.ro, you'd need to edit the entry #3 (second LOAD entry, RW-).

Note that the OS loader only uses LOAD program headers to map the file, so editing other entries (e.g. GNU_EH_FRAME) is not necessary even if they cover the section you're interested in.

  • So if .eh_frame is in an executable segment already any idea why it segfaults when it hits my code and does even simple add instructions? I can follow in gdb and see the add instruction but it wont execute the instruction, it just segfaults. – joe Apr 21 '17 at 23:51

Your Answer

