So after changing the entry point via the e_entry field I managed to execute my shellcode before returning control to the original entry point. Here's how I did it:
// write string and jump to OEP, patch address at 23 unsigned char shellcode = "\x48\x31\xc0\x48\x31\xff\x48\x31\xf6\xeb" "\x16\x5e\xb0\x01\x40\xb7\x01\xb2\x09\x0f" "\x05\x48\xb8\x41\x41\x41\x41\x41\x41\x41" "\xff\xe0\xe8\xe5\xff\xff\xff\x68\x69\x6a" "\x61\x63\x6b\x65\x64\x0a";
So as soon as I parse the ELF header I patch the shellcode:
uint64_t oep = ehdr->e_entry; memcpy(&opcode, &oep, 8);
Everything works, the shellcode executes and then execution resumes where it should. The problem is that after the target's main function finishes it segfaults(To make things simple I just made a program that prints a string).
So I used gdb and IDA to see what's going on. Just to make things clear the flow of excution is as follows:
- execution starts at the shellcode
- shellcode jumps to _start
- _start calls libc_start_main
- main executes and returns to libc_start_main
Now, after main returns IDA shows the following:
libc_start_main: ext:000000000040244B lea rax, [rsp+108h+var_98] .text:0000000000402450 mov fs:300h, rax .text:0000000000402459 mov rdx, cs:environ .text:0000000000402460 mov edi, [rsp+108h+var_FC] .text:0000000000402464 mov rsi, [rsp+108h+var_F8] .text:0000000000402469 mov rax, [rsp+108h+mainaddr] .text:000000000040246E call rax ; jump to main .text:0000000000402470 mov edi, eax .text:0000000000402472 .text:0000000000402472 loc_402472: ; CODE XREF: __libc_start_main+4AF↓j .text:0000000000402472 call exit .text:0000000000402477 ; -----------------------------------------------------------
The exit function ends up calling run_exit_handlers which appears to be the real culprit, as it faults with the following instruction:
mov rdx, [rax+18h] mov rdi, [rax+20h] mov qword ptr [rax+10h], 0 mov esi, ebp ror rdx, 11h xor rdx, fs:30h call rdx ; faults jmp loc_40823A
For some reason rdx has the value of 9, which is not allowed and hence causes the segmentation fault.
I searched for information on run_exit_handlers but didn't find anything meaningful.
So my question is: Why is this happening? All my shellcode does is write a string and jump to the OEP, it shouldn't really affect anything else.