As pointed out by others, this statement suffers from undefined behavior:
*(&x+5) += 7;
Memory address &x+5
is outside the bounds of variable x
. Writing to that address is a very bad idea.
OP’s code sample exploits certain C compiler implementation details.
Probably educational; it can be used to demonstrate how hackers can exploit missing bounds checks to change the designed behavior of a program.
It is interesting enough to investigate the actual behavior of this program.
I will assume the program has been compiled by GCC with default settings on a 64-bit Linux distro on Intel x64 processor architecture (i.e. little endian).
Pointers are 64 bits (8 bytes), int
is 32 bits (4 bytes).
Variable x
is located on the stack. During execution of k()
, the stack looks like this:
+--------+----------------------------------------------------+ TOP OF STACK
| rsp+0 | unused; 16-byte alignment filler | <--- rsp
+--------+----------------------------------------------------+
| rsp+4 | x | <--- &x
+--------+----------------------------------------------------+
| rsp+8 | reserved; least significant 32 bits of stack guard |
+--------+----------------------------------------------------+
| rsp+12 | reserved; most significant 32 bits of stack guard |
+--------+----------------------------------------------------+
| rsp+16 | least significant 32 bits of saved base pointer | <--- rbp
+--------+----------------------------------------------------+
| rsp+20 | most significant 32 bits of saved base pointer |
+--------+----------------------------------------------------+
| rsp+24 | least significant 32 bits of return address of k() | <--- &x+5
+--------+----------------------------------------------------+
| rsp+28 | most significant 32 bits of return address of k() |
+--------+----------------------------------------------------+
| rsp+32 | start of stack frame of main() |
+--------+----------------------------------------------------+
&x+5
is a memory address that is 20 bytes away from &x
(because sizeof(int)
is 4).
That happens to be the location of the return address of k()
.
*(&x+5) += 7
will increase the return address by 7.
That will have its effect when returning from k()
to main()
.
Here is objdump
output of main()
:
void main(void)
{
45: 55 push rbp
46: 48 89 e5 mov rbp,rsp
49: 48 83 ec 10 sub rsp,0x10
int y = 1;
4d: c7 45 fc 01 00 00 00 mov DWORD PTR [rbp-0x4],0x1
y = 13;
54: c7 45 fc 0d 00 00 00 mov DWORD PTR [rbp-0x4],0xd
k();
5b: e8 00 00 00 00 call 60 <main+0x1b>
y = 2;
60: c7 45 fc 02 00 00 00 mov DWORD PTR [rbp-0x4],0x2
printf("y = %d\n", y);
67: 8b 45 fc mov eax,DWORD PTR [rbp-0x4]
6a: 89 c6 mov esi,eax
6c: 48 8d 3d 00 00 00 00 lea rdi,[rip+0x0] # 73 <main+0x2e>
73: b8 00 00 00 00 mov eax,0x0
78: e8 00 00 00 00 call 7d <main+0x38>
}
7d: 90 nop
7e: c9 leave
7f: c3 ret
The program is supposed to return from k()
at offset 60
(the start of y = 2
), but instead, it will return at offset 67
(the start of printf("y = %d\n", y)
).
In other words, after returning from k()
, the program will skip y = 2
and continue from printf("y = %d\n", y)
, printing y = 1
.
solved C’s strange pointer arithmetics [closed]