GDB cannot access memory ... why does it matter where it returns in mapped and executable memory?

I have the following short program that sets the return address on the stack to some value so that when it returns it will go to that address:

(gdb) disas main
Dump of assembler code for function main:
   0x000000000040051c <+0>:     push   rbp
   0x000000000040051d <+1>:     mov    rbp,rsp
   0x0000000000400520 <+4>:     mov    DWORD PTR [rbp-0x14],edi
   0x0000000000400523 <+7>:     mov    QWORD PTR [rbp-0x20],rsi
   0x0000000000400527 <+11>:    lea    rax,[rbp-0x1]
   0x000000000040052b <+15>:    add    rax,0x9
   0x000000000040052f <+19>:    mov    QWORD PTR [rax],0x400520
   0x0000000000400536 <+26>:    mov    eax,0x0
   0x000000000040053b <+31>:    pop    rbp
   0x000000000040053c <+32>:    ret    
End of assembler dump.

      

Why does it matter which address I entered in [rax]? (0x400520 in this example, i.e. main + 4)

When I try different addresses it may succeed or fail with the error: "Unable to access memory at address 0x8", here (with main + 4) it fails:

(gdb) b *0x000000000040053c
Breakpoint 1 at 0x40053c
(gdb) run 
Breakpoint 1, 0x000000000040053c in main ()
=> 0x000000000040053c <main+32>:        c3      ret    
(gdb) x/a $rsp
0x7fffffffdd18: 0x400520 <main+4>
(gdb) si
Cannot access memory at address 0x8
(gdb) x/i $rip
=> 0x400520 <main+4>:   mov    DWORD PTR [rbp-0x14],edi

      

What is the problem? The address it returns is displayed, readable, and executed. "si" only executes one command, so it only executes the ret instruction.

I can also see that the address the rip was set to contains a valid instruction to execute.

It might seem interesting to note that manually setting $ rip to the same address doesn't seem to cause problems (for example, just set $ rip = 0x400520 and then si).

Where does this attempt to access address 0x8 come from? Why such access at all and where does "0x8" come from? ret only pops off the stack into rip. Surely there is something obvious that I'm missing here?

If I go back to different addresses for example. main + 0 or main + 32, it works, but most of the others seem to fail.

The C program is simple (+9 magic just gotten with gdb, to see how much I need it might need to tweak another system):

#include <stdio.h>
#include <stdint.h>

int main(int argc, char **argv)
{
        char stack; 

        *((uint64_t *) (&stack + 9)) = 0x0000000000400520;

        return 0;
}

      

I am using GNU gdb (Gentoo 7.6.2 p1) 7.6.2, but I also noticed an issue with GNU gdb (GDB) 7.5-4.0.61. I am using gcc (Gentoo 4.7.3-r1 p1.4, pie-0.5.5) 4.7.3.

+3
c assembly linux gdb


source to share


No one has answered this question yet

Check out similar questions:

12
Go to next "instruction" using gdb
8
Where is the load barrier for an intermittent application?
4
Resident buffer overflow on 64-bit?
0
Stack contents after function call
0
Simple x86 Loop Assembly - Using PTR
0
No epb / eip registers in gdb "info frame"
0
assembly for a stack frame of variable size (about stack for a local variable)
0
x86_64 ABI: disassembly problem
0
Memory Allocation and Addressing in an Assembly
-1
My stack frames are different than before



All Articles
Loading...
X
Show
Funny
Dev
Pics