I'm trying to modify the return address on the stack within a segment fault handler, so that it skips over the faulting instruction. However, I get a segment fault whenever I try to modify the return address, if I do not call the signal handler directly.
gdb is not great for debugging when the program does segfault, but when I do info frame
I see that, after a segfault, there is "frame level 2" as opposed to "frame level 0"? I don't know where GDB gets that information, because when I try x/12xw $ebp
or however many words, I don't see the return address to main()
...
Compiled with -m32 -z execstack -fno-stack-protector on CentOS linux
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
void segment_fault_handler(int signum)
{
char* ret = (char*)(&signum)-4;
*(ret) += 8;
}
int main()
{
int phail = 0;
signal(SIGSEGV, segment_fault_handler);
segment_fault_handler(7); //Only by using this can I skip the next instruction
phail = *( (int *) 0);
printf("Win!\n");
return 0;
}
The reason that I increase by 8 is because the phail instruction in main()
is 8 bytes:
0x080484e2 <+37>: movl $0x7,(%esp)
0x080484e9 <+44>: call 0x8048480 <segment_fault_handler>
0x080484ee <+49>: mov $0x0,%eax
0x080484f3 <+54>: mov (%eax),%eax
0x080484f5 <+56>: mov %eax,0x1c(%esp)
0x080484f9 <+60>: movl $0x80485b4,(%esp)
0x08048500 <+67>: call 0x8048350 <puts@plt>
Do I need to increase the offset a bit? Does my method of accessing the stack (which I think corresponds to EBP+4) need to change when dealing with a segment fault situation?