gdb addresses: 0x565561f5 instead of 0x41414141 - c

I want to try a buffer overflow on a c program. I compiled it like this gcc -fno-stack-protector -m32 buggy_program.c with gcc. If i run this program in gdb and i overflow the buffer, it should said 0x41414141, because i sent A's. But its saying 0x565561f5. Sorry for my bad english. Can somebody help me?
This is the source code:
#include <stdio.h>
int main(int argc, char **argv)
{
char buffer[64];
printf("Type in something: ");
gets(buffer);
}
Starting program: /root/Downloads/a.out
Type in something: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Program received signal SIGSEGV, Segmentation fault.
0x565561f5 in main ()
I want to see this:
Starting program: /root/Downloads/a.out
Type in something: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in main ()

Looking at the address at which the process segfaulted shows the relevant line in the disassembled code:
gdb a.out <<EOF
set logging on
r < inp
disassemble main
x/i $eip
p/x $esp
Produces the following output:
(gdb) Starting program: .../a.out < in
Program received signal SIGSEGV, Segmentation fault.
0x08048482 in main (argc=, argv=) at tmp.c:10 10 }
(gdb) Dump of assembler code for function main:
0x08048436 <+0>: lea 0x4(%esp),%ecx
0x0804843a <+4>: and $0xfffffff0,%esp
0x0804843d <+7>: pushl -0x4(%ecx)
0x08048440 <+10>: push %ebp
0x08048441 <+11>: mov %esp,%ebp
0x08048443 <+13>: push %ebx
0x08048444 <+14>: push %ecx
0x08048445 <+15>: sub $0x40,%esp
0x08048448 <+18>: call
0x8048370 <__x86.get_pc_thunk.bx>
0x0804844d <+23>: add $0x1bb3,%ebx
0x08048453 <+29>: sub $0xc,%esp
0x08048456 <+32>: lea -0x1af0(%ebx),%eax
0x0804845c <+38>: push %eax
0x0804845d <+39>: call 0x8048300
0x08048462 <+44>: add $0x10,%esp
0x08048465 <+47>: sub $0xc,%esp
0x08048468 <+50>: lea -0x48(%ebp),%eax
0x0804846b <+53>: push %eax
0x0804846c <+54>: call 0x8048310
0x08048471 <+59>: add $0x10,%esp
0x08048474 <+62>: mov $0x0,%eax
0x08048479 <+67>: lea -0x8(%ebp),%esp
0x0804847c <+70>: pop %ecx
0x0804847d <+71>: pop %ebx
0x0804847e <+72>: pop %ebp
0x0804847f <+73>: lea -0x4(%ecx),%esp
=> 0x08048482 <+76>: ret
End of assembler dump.
(gdb) => 0x8048482 : ret
(gdb) $1 = 0x4141413d
(gdb) quit
The failing statement is the ret at the end of main. The program fails, when ret attempts to load the return-address from the top of the stack. The produced executable stores the old value of esp on the stack, before aligning to word-boundaries. When main is completed, the program attempts to restore the esp from the stack and afterwards read the return-address. However the whole top of the stack is compromised, thus rendering the new value of the stack-pointer garbage ($1 = 0x4141413d). When ret is executed, it attempts to read a word from address 0x4141413d, which isn't allocated and produces as segfault.
Notes
The above disassembly was produced from the code in the question using the following compiler-options:
-m32 -fno-stack-protector -g -O0

So guys, i found a solution:
Just compile it with gcc 3.3.4
gcc -m32 buggy_program.c

Modern operating systems use address-space-layout-randomization ASLR to make this stuff not work quite so easily.
I remember the controversy when it was first started. ASLR was kind of a bad idea for 32 bit processes due to the number of other constraints it imposed on the system and dubious security benefit. On the other hand, it works great on 64 bit processes and almost everybody uses it now.
You don't know where the code is. You don't know where the heap is. You don't know where the stack is. Writing exploits is hard now.
Also, you tried to use 32 bit shellcode and documentation on a 64 bit process.
On reading the updated question: Your code is compiled with frame pointers (which is the default). This is causing the ret instruction itself to fault because esp is trashed. ASLR appears to still be in play most likely it doesn't really matter.

Related

Inserting gdb breakpoints fail

I'm learning about buffer overflow in c.
For that purpose, I'm following this simple example.
I have the following gcc version:
$ gcc --version
gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
And this simple c file:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]){
char buf[256];
strcpy(buf, argv[1]);
printf("%s,", buf);
return 0;
}
I then compile this file with $ gcc buf.c -o buf.
I then open in gdb by $ gdb ./buf
I call disas and get the result assembly:
(gdb) disas main
Dump of assembler code for function main:
0x0000000000001189 <+0>: endbr64
0x000000000000118d <+4>: push %rbp
0x000000000000118e <+5>: mov %rsp,%rbp
0x0000000000001191 <+8>: sub $0x120,%rsp
0x0000000000001198 <+15>: mov %edi,-0x114(%rbp)
0x000000000000119e <+21>: mov %rsi,-0x120(%rbp)
0x00000000000011a5 <+28>: mov %fs:0x28,%rax
0x00000000000011ae <+37>: mov %rax,-0x8(%rbp)
0x00000000000011b2 <+41>: xor %eax,%eax
0x00000000000011b4 <+43>: mov -0x120(%rbp),%rax
0x00000000000011bb <+50>: add $0x8,%rax
0x00000000000011bf <+54>: mov (%rax),%rdx
0x00000000000011c2 <+57>: lea -0x110(%rbp),%rax
0x00000000000011c9 <+64>: mov %rdx,%rsi
0x00000000000011cc <+67>: mov %rax,%rdi
0x00000000000011cf <+70>: callq 0x1070 <strcpy#plt>
--Type <RET> for more, q to quit, c to continue without paging--
0x00000000000011d4 <+75>: lea -0x110(%rbp),%rax
0x00000000000011db <+82>: mov %rax,%rsi
0x00000000000011de <+85>: lea 0xe1f(%rip),%rdi # 0x2004
0x00000000000011e5 <+92>: mov $0x0,%eax
0x00000000000011ea <+97>: callq 0x1090 <printf#plt>
0x00000000000011ef <+102>: mov $0x0,%eax
0x00000000000011f4 <+107>: mov -0x8(%rbp),%rcx
0x00000000000011f8 <+111>: xor %fs:0x28,%rcx
0x0000000000001201 <+120>: je 0x1208 <main+127>
0x0000000000001203 <+122>: callq 0x1080 <__stack_chk_fail#plt>
0x0000000000001208 <+127>: leaveq
0x0000000000001209 <+128>: retq
End of assembler dump.
With some really low memory adresses.
I then want to see what happens if I input a big string of A's into the program, I therefore place a breakpoint at 0x00000000000011db
I then run it:
(gdb) run $(python3 -c "print('A'*256)"
Starting program: /home/ask/Notes/ctf/bufoverflow/code/buf $(python3 -c "print('A'*256)"
/bin/bash: -c: line 0: unexpected EOF while looking for matching `)'
/bin/bash: -c: line 1: syntax error: unexpected end of file
During startup program exited with code 1.
(gdb) run $(python3 -c "print('A'*256)")
Starting program: /home/ask/Notes/ctf/bufoverflow/code/buf $(python3 -c "print('A'*256)")
Warning:
Cannot insert breakpoint 1.
Cannot access memory at address 0x11db
Ok, so something with the memory adresses is a bit funky.
I google the issue and find this post where I find that this is because Position-Independent Executable (PIE) was probably enabled, and the memory adresses would be changed when the program is actually run.
I can confirm this by running disas after running the program, and seeing that the memory adresses are in a lot higher ranges.
This all makes sense, but it makes me wonder, iif the adresses change every time I run it, then how can I then place a breakpoint at a memory adress before the program runs?
iif the adresses change every time I run it, then how can I then place a breakpoint at a memory adress before the program runs?
This happens because GDB by default disables address randomization (to make debugging easier).
If you re-enable ASLR with (gdb) set disable-randomization off, then you wouldn't be able to set the breakpoint on an address.
You would still be able to set breakpoint on e.g. main -- in that case GDB will wait until the executable has been relocated, and will set the breakpoint on the actual runtime instruction (the address will change on every run).

How do i bypass a return adress overwrite not redirecting control flow?

Let me illustrate the problem here
This is main
(gdb) disass main
Dump of assembler code for function main:
0x000000000040057c <+0>: push rbp
0x000000000040057d <+1>: mov rbp,rsp
0x0000000000400580 <+4>: sub rsp,0x40
0x0000000000400584 <+8>: mov DWORD PTR [rbp-0x34],edi
0x0000000000400587 <+11>: mov QWORD PTR [rbp-0x40],rsi
0x000000000040058b <+15>: mov rax,QWORD PTR [rbp-0x40]
0x000000000040058f <+19>: add rax,0x8
0x0000000000400593 <+23>: mov rdx,QWORD PTR [rax]
0x0000000000400596 <+26>: lea rax,[rbp-0x30]
0x000000000040059a <+30>: mov rsi,rdx
0x000000000040059d <+33>: mov rdi,rax
0x00000000004005a0 <+36>: call 0x400430 <strcpy#plt>
0x00000000004005a5 <+41>: mov eax,0x0
0x00000000004005aa <+46>: call 0x400566 <function>
0x00000000004005af <+51>: mov eax,0x0
0x00000000004005b4 <+56>: leave
0x00000000004005b5 <+57>: ret
End of assembler dump.
(gdb) list
#include <stdio.h>
#include <string.h>
void function(){
printf("test");
}
int main(int argc, char* argv[]) {
char a[34];
strcpy(a , argv[1]);
function();
return 0;
}
It was compiled using the following:
gcc -g -o exploitable0 vulnerable_program0.c -fno-stack-protector -z execstack
The attacker is obviously tempted to overrun the buffer specified by the array 'a'.
Let's examine more in depth what the stack looks like when i run the exploit
(gdb) run $(perl -e 'print "\xeb\x15\x59\x31\xc0\xb0\x04\x31\xdb\xff\xc3\x31\xd2\xb2\x0f\xcd\x80\xb0\x01\xff\xcb\xcd\x80\xe8\xe6\xff\xff\xff\x48\x65\x6c\x6c\x6f\x2c\x1f\x77\x6f\x72\x6c\x64\x21\x21\x21\x21\x21\x21\x21\x21\x66\x05\x40\x00\x00\x00\x00\x00"')
Starting program: /home/twister17/Documents/hacking/exploitable0 $(perl -e 'print "\xeb\x15\x59\x31\xc0\xb0\x04\x31\xdb\xff\xc3\x31\xd2\xb2\x0f\xcd\x80\xb0\x01\xff\xcb\xcd\x80\xe8\xe6\xff\xff\xff\x48\x65\x6c\x6c\x6f\x2c\x1f\x77\x6f\x72\x6c\x64\x21\x21\x21\x21\x21\x21\x21\x21\x66\x05\x40\x00\x00\x00\x00\x00"')
Breakpoint 1, main (argc=2, argv=0x7fffffffdcf8) at vulnerable_program0.c:9
9 function();
(gdb) i r rbp
rbp 0x7fffffffdc10 0x7fffffffdc10
(gdb) i r rsp
rsp 0x7fffffffdbd0 0x7fffffffdbd0
(gdb) x/18xw $rsp
0x7fffffffdbd0: 0xffffdcf8 0x00007fff 0x0040060d 0x00000002
0x7fffffffdbe0: 0x315915eb 0x3104b0c0 0x31c3ffdb 0xcd0fb2d2
0x7fffffffdbf0: 0xff01b080 0xe880cdcb 0xffffffe6 0x6c6c6548
0x7fffffffdc00: 0x771f2c6f 0x646c726f 0x21212121 0x21212121
0x7fffffffdc10: 0x00400566 0x00000000
(gdb)
the affected buffer starts at 0x7fffffffdbe0 and ends at 0x7fffffffdc10.
The shellcode injects smoothtly , to make things simpler i overwrite the return address with that of the function.
That is, I actually used 0x400566 as the return address, so if everything runs smoothly it would just call the function and print "test". You can clearly see from the assembly dump that is the address of the function "function"
expected output: "testtest".
actual output: test ( the program calls the function already).
I think you're having troubles with the StackGuard protection from GCC that prevents buffer overflows.
Try compiling your code with the
-fno-stack-protector
flag in order to disable the protection for your program.
Assuming you're running it on Linux, if you want to disable kernel based protection, which is called Address Space Randomization, you can run :
sysctl -w kernel.randomize_va_space=0

buffer overflow - unable to overwrite return address

Trying a buffer overflow to overwrite return address on stack for the following program. I want to call accept on both case of strcmp()
void accept()
{
printf ("\nAccess Granted!\n");
return;
}
void deny()
{
printf ("\nAccess Denied!\n");
return;
}
int main()
{
char pwd[16]={0};
printf ("Enter Password: ");
gets (pwd);
if(strcmp(pwd, "pwd1"))
deny ();
else
accept ();
return 0;
}
While disassembling the main, it's understood 20 bytes are allocated for variables as in 0x080484fb <+14>: sub $0x14,%esp
Dump of assembler code for function main:
0x080484ed <+0>: lea 0x4(%esp),%ecx
0x080484f1 <+4>: and $0xfffffff0,%esp
0x080484f4 <+7>: pushl -0x4(%ecx)
0x080484f7 <+10>: push %ebp
0x080484f8 <+11>: mov %esp,%ebp
0x080484fa <+13>: push %ecx
0x080484fb <+14>: sub $0x14,%esp
0x080484fe <+17>: movl $0x0,-0x18(%ebp)
0x08048505 <+24>: movl $0x0,-0x14(%ebp)
0x0804850c <+31>: movl $0x0,-0x10(%ebp)
0x08048513 <+38>: movl $0x0,-0xc(%ebp)
0x0804851a <+45>: sub $0xc,%esp
0x0804851d <+48>: push $0x8048611
0x08048522 <+53>: call 0x8048370 <printf#plt>
0x08048527 <+58>: add $0x10,%esp
0x0804852a <+61>: sub $0xc,%esp
0x0804852d <+64>: lea -0x18(%ebp),%eax
0x08048530 <+67>: push %eax
0x08048531 <+68>: call 0x8048380 <gets#plt>
0x08048536 <+73>: add $0x10,%esp
0x08048539 <+76>: sub $0x8,%esp
0x0804853c <+79>: push $0x8048622
0x08048541 <+84>: lea -0x18(%ebp),%eax
0x08048544 <+87>: push %eax
0x08048545 <+88>: call 0x8048360 <strcmp#plt>
0x0804854a <+93>: add $0x10,%esp
0x0804854d <+96>: test %eax,%eax
0x0804854f <+98>: je 0x8048558 <main+107>
0x08048551 <+100>: call 0x80484d4 <deny>
0x08048556 <+105>: jmp 0x804855d <main+112>
0x08048558 <+107>: call 0x80484bb <accept>
0x0804855d <+112>: mov $0x0,%eax
0x08048562 <+117>: mov -0x4(%ebp),%ecx
0x08048565 <+120>: leave
0x08048566 <+121>: lea -0x4(%ecx),%esp
0x08048569 <+124>: ret
When I try to fuzz with input string AAAAA... I found the overwrite on buffer is partial
Backtrace stopped: Cannot access memory at address 0x41413d
(gdb) R
The program being debugged has been started already.
Start it from the beginning? (y or n) Y
Starting program: BufferOverflow.x
\Enter Password: AAAAAAAAAAAAAAAAAAAAAAAA
Access Denied!
Program received signal SIGSEGV, Segmentation fault.
0x08048569 in main ()
(gdb) BT
#0 0x08048569 in main ()
Backtrace stopped: Cannot access memory at address 0x4141413d
(gdb) R
The program being debugged has been started already.
Start it from the beginning? (y or n) Y
Starting program: BufferOverflow.x
Enter Password: AAAAAAAAAAAAAAAAAAAAAAAAA
Access Denied!
Program received signal SIGSEGV, Segmentation fault.
0x08048569 in main ()
(gdb) BT
#0 0x08048569 in main ()
Backtrace stopped: Cannot access memory at address 0x4141413d
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: BufferOverflow.x
Enter Password: AAAAAAAAAAAAAAAAAAAAAAAAAA
Access Denied!
Program received signal SIGSEGV, Segmentation fault.
0x08048569 in main ()
(gdb) bt
#0 0x08048569 in main ()
Backtrace stopped: Cannot access memory at address 0x4141413d
If you observe closely, the return address is not overflowed completely, but partially as 0x4141413d, if note the address ends with 3d always, even for 100 As - the return address same 0x4141413d
I disabled before starting
cat /proc/sys/kernel/randomize_va_space
0
And compiled as:
gcc BufferOverflow.c -o BufferOverflow.x -m32 -fno-stack-protector
Am using gcc
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
Any help in identifying why the buffer is not overflown properly would be appreciated.
Thanks
Because a buffer overflow causes undefined behavior, it's hard to say what is causing this without looking through the internals of the gets() function. It's quite possible that some pointer inside gets() is being manipulated and causing this corruption.
Note also that "?" is commonly used to represent unprintable characters in ASCII. This could be related to the behavior you're seeing, though I couldn't find any documentation describing such behavior with gets()
Just had the same question, and eventually found the answer here. In short, you need to wrap the vulnerable calls in another function, and call that function in main().

Overflow buffer in C on x86_64 to call function

Hello i have such code
#include <stdio.h>
#define SECRET "1234567890AZXCVBNFRT"
int checksecret(){
char buf[32];
gets(buf);
if(strcmp(SECRET,buf)==0) return 1;
else return 0;
}
void outsecret(){
printf("%s\n",SECRET);
}
int main(int argc, char** argv){
if (checksecret()){
outsecret();
};
}
disass of outsecret
(gdb) disassemble outsecret
Dump of assembler code for function outsecret:
0x00000000004005f4 <+0>: push %rbp
0x00000000004005f5 <+1>: mov %rsp,%rbp
0x00000000004005f8 <+4>: mov $0x4006b4,%edi
0x00000000004005fd <+9>: callq 0x400480 <puts#plt>
0x0000000000400602 <+14>: pop %rbp
0x0000000000400603 <+15>: retq
I have an assumption that i don't know SECRET, so i try to run my program with such string python -c 'print "A" * 32 + "\x40\x05\xf4"[::-1]'. But it fails with segmentation fault. What i am doing wrong? Thank you for any help.
PS
I want to call function outsecret by overwriting return code in checksecret
You have to remember that all strings have an extra character that terminates the string, so if you input 32 characters then gets will write 33 characters to the buffer. Writing beyond the limits of an array leads to undefined behavior which often leads to crashes.
The gets function have no bounds-checking, and is very dangerous to use. It has been deprecated since long, and in the latest C11 standard it has even been removed.
$ python -c 'print "A" * 32 + "\x40\x05\xf4"[::1]'
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA#
$ perl -le 'print length("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA#")'
33
Your input string is too long for buffer size of 32 characters (extra one is needed for '\0' terminating null character). You are victim to buffer or array overflow (sometimes also called as array overrun).
Note that gets() is deprecated in C99 and eventually it has been dropped in C11 Standard for security reasons.
I want to call function outsecret by overwriting return code in
checksecret
Beware, you are about to leave relatively safe regions of C Standard. This means that behaviour is relative to compiler, compiler's versions, optimization settings, ABI and so on (maybe inclucing current phase of moon).
As of x86 calling conventions integer return value is stored directly in %eax register (that's assuming that you have x86 or x86-64 CPU). Stack-likely-located array buf is handled by %rbp offsets within current stack frame. Let's consult with gdb disassemble command:
$ gcc -O0 test.c
$ gdb -q a.out
(gdb) b checksecret
(gdb) r
Breakpoint 1, 0x0000000000400631 in checksecret ()
(gdb) disas
Dump of assembler code for function checksecret:
0x000000000040062d <+0>: push %rbp
0x000000000040062e <+1>: mov %rsp,%rbp
=> 0x0000000000400631 <+4>: sub $0x30,%rsp
0x0000000000400635 <+8>: mov %fs:0x28,%rax
0x000000000040063e <+17>: mov %rax,-0x8(%rbp)
0x0000000000400642 <+21>: xor %eax,%eax
0x0000000000400644 <+23>: lea -0x30(%rbp),%rax
0x0000000000400648 <+27>: mov %rax,%rdi
0x000000000040064b <+30>: callq 0x400530 <gets#plt>
0x0000000000400650 <+35>: lea -0x30(%rbp),%rax
0x0000000000400654 <+39>: mov %rax,%rsi
0x0000000000400657 <+42>: mov $0x400744,%edi
0x000000000040065c <+47>: callq 0x400510 <strcmp#plt>
0x0000000000400661 <+52>: test %eax,%eax
0x0000000000400663 <+54>: jne 0x40066c <checksecret+63>
0x0000000000400665 <+56>: mov $0x1,%eax
0x000000000040066a <+61>: jmp 0x400671 <checksecret+68>
0x000000000040066c <+63>: mov $0x0,%eax
0x0000000000400671 <+68>: mov -0x8(%rbp),%rdx
0x0000000000400675 <+72>: xor %fs:0x28,%rdx
0x000000000040067e <+81>: je 0x400685 <checksecret+88>
0x0000000000400680 <+83>: callq 0x4004f0 <__stack_chk_fail#plt>
0x0000000000400685 <+88>: leaveq
0x0000000000400686 <+89>: retq
There is no way overwrite %eax directly from C code, but what you could do is to overwrite selective fragment of code section. In your case what you want is to replace:
0x000000000040066c <+63>: mov $0x0,%eax
with
0x000000000040066c <+63>: mov $0x1,%eax
It's easy to accomplish by gdb itself:
(gdb) x/2bx 0x40066c
0x40066c <checksecret+63>: 0xb8 0x00
set {unsigned char}0x40066d = 1
Now let's confirm it:
(gdb) x/i 0x40066c
0x40066c <checksecret+63>: mov $0x1,%eax
From that point checksecret() is returning 1 even if SECRET does not match. However It wouldn't be so easy to do it by buf itself, as you need to know (guess somehow?) correct offset of particular code section instruction.
Above answers are pretty clear and corret way to exploit buffer overflow vulnerability. But there is a different way to do same thing without exploit vulnerability.
mince#rootlab tmp $ gcc test.c -o test
mince#rootlab tmp $ strings test
/lib64/ld-linux-x86-64.so.2
libc.so.6
gets
puts
__stack_chk_fail
strcmp
__libc_start_main
__gmon_start__
GLIBC_2.4
GLIBC_2.2.5
UH-X
UH-X
[]A\A]A^A_
1234567890AZXCVBNFRT
;*3$
Please look at last 2 row. You will see your secret key in there.

My overflow code does not work

The code below is from the well-known article Smashing The Stack For Fun And Profit.
void function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
int *ret;
ret = buffer1 + 12;
(*ret)+=8;
}
void main() {
int x;
x=0;
function(1,2,3);
x=1;
printf("%d\n",x);
}
I think I must explain my target of this code.
The stack model is below. The number below the word is the number of bytes of the variable in the stack. So, if I want to rewrite RET to skip the statement I want, I calculate the offset from buffer1 to RET is 8+4=12. Since the architecture is x86 Linux.
buffer2 buffer1 BSP RET a b c
(12) (8) (4) (4) (4) (4) (4)
I want to skip the statement x=1; and let printf() output 0 on the screen.
I compile the code with:
gcc stack2.c -g
and run it in gdb:
gdb ./a.out
gdb gives me the result like this:
Program received signal SIGSEGV, Segmentation fault.
main () at stack2.c:17
17 x = 1;
I think Linux uses some mechanism to protect against stack overflow. Maybe Linux stores the RET address in another place and compares the RET address in the stack before functions return.
And what is the detail about the mechanism? How should I rewrite the code to make the program output 0?
OK,the disassemble code is below.It comes form the output of gdb since I think is more easy to read for you.And anybody can tell me how to paste a long code sequence?Copy and paste one by one makes me too tired...
Dump of assembler code for function main:
0x08048402 <+0>: push %ebp
0x08048403 <+1>: mov %esp,%ebp
0x08048405 <+3>: sub $0x10,%esp
0x08048408 <+6>: movl $0x0,-0x4(%ebp)
0x0804840f <+13>: movl $0x3,0x8(%esp)
0x08048417 <+21>: movl $0x2,0x4(%esp)
0x0804841f <+29>: movl $0x1,(%esp)
0x08048426 <+36>: call 0x80483e4 <function>
0x0804842b <+41>: movl $0x1,-0x4(%ebp)
0x08048432 <+48>: mov $0x8048520,%eax
0x08048437 <+53>: mov -0x4(%ebp),%edx
0x0804843a <+56>: mov %edx,0x4(%esp)
0x0804843e <+60>: mov %eax,(%esp)
0x08048441 <+63>: call 0x804831c <printf#plt>
0x08048446 <+68>: mov $0x0,%eax
0x0804844b <+73>: leave
0x0804844c <+74>: ret
Dump of assembler code for function function:
0x080483e4 <+0>: push %ebp
0x080483e5 <+1>: mov %esp,%ebp
0x080483e7 <+3>: sub $0x14,%esp
0x080483ea <+6>: lea -0x9(%ebp),%eax
0x080483ed <+9>: add $0x3,%eax
0x080483f0 <+12>: mov %eax,-0x4(%ebp)
0x080483f3 <+15>: mov -0x4(%ebp),%eax
0x080483f6 <+18>: mov (%eax),%eax
0x080483f8 <+20>: lea 0x8(%eax),%edx
0x080483fb <+23>: mov -0x4(%ebp),%eax
0x080483fe <+26>: mov %edx,(%eax)
0x08048400 <+28>: leave
0x08048401 <+29>: ret
I check the assemble code and find some mistake about my program,and I have rewrite (*ret)+=8 to (*ret)+=7,since 0x08048432 <+48>minus0x0804842b <+41> is 7.
Because that article is from 1996 and the assumptions are incorrect.
Refer to "Smashing The Modern Stack For Fun And Profit"
http://www.ethicalhacker.net/content/view/122/24/
From the above link:
However, the GNU C Compiler (gcc) has evolved since 1998, and as a result, many people are left wondering why they can't get the examples to work for them, or if they do get the code to work, why they had to make the changes that they did.
The function function overwrites some place of the stack outside of its own, which is this case is the stack of main. What it overwrites I don't know, but it causes the segmentation fault you see. It might be some protection employed by the operating system, but it might as well be the generated code just does something wrong when wrong value is at that position on the stack.
This is a really good example of what may happen when you write outside of your allocated memory. It might crash directly, it might crash somewhere completely different, or if might not crash at all but instead just do some calculation wrong.
Try ret = buffer1 + 3;
Explanation: ret is an integer pointer; incrementing it by 1 adds 4 bytes to the address on 32bit machines.

Resources