Stack overflow case analysis under Linux-gdb debug Drills

Source: Internet
Author: User

Summary:
This article mainly demonstrates the stack overflow under the Linux platform, first the overflow attack according to the theory to the example code, the result is the overflow attack, but it is different from the idea, then uses the GDB debugging tool to carry on the thorough analysis to the occurrence accident.

Platform for testing:
1. Ubuntu 9;   GCC 4.4.1; Gdb 7.0-ubuntu
2. The Ubuntu system is installed on virtual box 3.2.8 VMS;

The sample code is as follows:

#include <string.h>void overflow (char* Arg) {char buf[12];strcpy (buf, arg);} int main (int argc, char *argv[]) {if (argc > 1) overflow (argv[1]); return 0;}

If you compile in a general way:
Gcc–o StackOverflow stackoverflow.c
The Linux system detects the stack overflow in the program and terminates the program as shown in:

There is no way to let the system does not detect the stack overflow, where you can compile, disable stack protection, the specific command is as follows:
Gcc–fno-stack-protector–o StackOverflow stackoverflow.c
Then debug StackOverflow with GDB,

The output here is quite different from what is envisaged, as the function stack in the scenario is as follows:

The previous 12 bytes are populated with buf, then the next 4 bytes are filled with EBP, the last 4 bytes are filled with the RET address, so it is supposed that the EIP here should be 0x65656565, then why is this 0x61616161, just the value of AAAA?

According to the results of single step debugging, it is found that the EIP becomes 0x61616161 after the main function exits, and the EIP becomes 0x65656565 when the overflow exits.

Why does overflow return to the main function after exiting? Possible cause: The input string does not overwrite the RET address, but the string unexpectedly overwrites the return address of main.

But for coverage, why does the value of the overlay not take the value of E, but rather the value of a? Do you know that a is at the beginning of the string? This is really a strange thing to do.

1. Let's take a step-by-step debug approach to the problem, and first look at the GCC compiled disassembly code:
The command to use:
Set Disassembly-flavor Intel//sets the assembly to Intel style;
Disassemble main//disassembly main function;

Main function:

1. Push EBP2. MVO EBP, Esp3. and ESP, 0xfffffff04. Sub ESP, 0x105. CMP DWORD PTR [ebp+0x8], 0x16. Jle  0x804841d <main+31>7. mov eax, DWORD ptr [ebp+0xc]8. add eax, 0x49. mov eax, DWORD ptr [EAX]10. mov DWORD PT R [ESP], eax11. Call 0x80483e4 <overflow>12. mov eax, 0x013. Leave14. Ret

And then look at overflow's disassembly code, command: Disassemble overflow
Overflow function:

1. Push EBP2. mov ebp, esp3. Sub ESP, 0x284. MOV  eax, DWORD ptr[ebp+0x8]5. mov  DWORD ptr[esp+0x4], eax6. Lea  eax, [ebp-0x14]7. mov  DWORD  PTR [ ESP], eax8. Call  0x804831c <[email protected]>9 leave10. ret


We step through the above instructions, focusing on the changes in ESP values. The general diagram follows, followed by an analysis of each of these steps:

After the MAIN.1 is completed, the value of the ESP is changed to: ESP = 0xbffff438 after the command p $ESP
After main.3, the value of ESP becomes 0xbffff430, which is estimated to be used for alignment;
After main.4, the value of ESP is 0xbffff420;
Main.7-10, where the first address of the argv[] arg[1] string is taken out, and placed in the ESP, the value of ESP is 0xbffff420;

After executing overflow.1, the value of ESP changes to: 0xbffff41c, which holds the address of the next statement of Main,
by command: x $ESP you can see the address returned by overflow:
0xbffff41c 0x0804841d
After overflow.1 executes, the value of ESP becomes 0xbffff418 and is used to hold the value of EBP;
After overflow.3 executes, the value of ESP becomes 0xbffff3f0,
After Overflow.5-7 executes, place the address of the string at the 3f0+0x4 address, and then place the temporary string, also known as the BUF's first address [ebp-0x14], at the 3f0 address (current ESP point);

After we have finished overflow.8, we look at the beginning of the BUF and find that we have actually finished assigning the content, and the command is as follows:
X address;

After executing the leave instruction, it is found that the value of ESP changes to: 0xbffff41c, exactly pointing to the address of main, and then after the RET instruction is executed, the ESP becomes 0xbffff420; then the program jumps back to the main function;

After executing the leave instruction in the main function, the value of ESP should be 43c to the return address of main after assuming the leave instruction executes, but when we do, the value of ESP changes to 0xbffff404, where the content is exactly 0x61616161. That is, the value of AAAA; the first four characters of the parameters used in this test are just aaaa;

To this point, we understand the crux of the problem:
When the leave directive is called in the main function, the value of ESP is not adjusted to fit in place. It should point to 43c (the previous address is ignored), but here it points to the 404?
So why does it have to be such a situation? This is supposed to be the compiler's job, why is the compiler not responsible?

The strange thing is:
Does not occur when the stack overflow, that is, we enter the string length of not more than 12 o'clock, the leave instruction in main executes, the program can return to the 43c position, the smooth exit;
The problem here is very strange: the stack overflow occurs in the overflow, the program can be returned from overflow to main, and then main leave instructions are not normal, if there is no stack overflow in overflow, the program also returned to the main function smoothly, Then the leave instruction of main will work normally.

The crux of the problem lies in figuring out the leave directive itself, and guessing that it may rely on certain registers or rely on specific storage units for recovery purposes.

First see if you can stepi into leave; The answer is leave is a single instruction, not a processing function;
So let's try to find something out of the register and find out what's actually going on in contrast to the operation in Vistual Studio,
The leave directive should be equivalent to:
Mov ESP, EBP
Pop EBP

The previous focus is on ESP, which, according to the equivalent above, should follow the changes in the EBP register. So the next thing to do is 1. First verify that the equivalent of the above is established, 2. Keep an eye on the changes in EBP in the course of execution.

For the verification of issue 1, we stole a lazy, direct Baidu, found that it is indeed in line with our conjecture, the leave instruction is mainly to restore the storage value before ESP and EBP. (After the passing of the test, and indeed the main do the corresponding operation.) )

So we go back to question 2, mainly looking at when entering overflow and exiting overflow, as well as entering main and exiting main, the register EBP value changes.

Under the overflow version, we look at the value of the EBP before and after call strcpy, as shown, we find that the value of EBP is 418 (omitted) in the pre-and post-process of calling the strcpy function, meaning that the value of the EBP before and after the call to the strcpy function is normal.

Then the subsequent execution of the leave instruction, according to the normal version (after the normal version of the verification), then ESP = 418, and then after the pop Ebp, the value of ESP to 41c, and the value of EBP should be restored to 438;

After the actual execution, the ESP changes as expected, but the value of EBP does not follow the expected change; then the problem is only possible in the pop EBP statement, and there is only one reason: the contents of the address in the stack of the EBP store have been modified, This means that the value at the 418 address is modified to 400 during the function call and should be 438.

That may occur only in overflow function calls, which can happen. According to the above analysis, we can prove this in the stack overflow version by looking at 418 values before and after the strcpy call. Sure enough, the following illustration shows the problem:

After executing the strcpy function, look at the last line of the countdown, the content of 0xbffff418 is modified to 0xbffff400; As a comparison, let's look at non-overflow versions:

You can see that the EBP value of the last line has not been modified, so no error occurs.

It is now possible to determine that the value of EBP has been modified in the overflow strcpy call, causing problems when the main function exits. The question below is: How did strcpy change the EBP value? The solution of this problem to go deep into the strcpy assembly code inside, can get the answer, this article does not discuss, has the interest can further study.

Conclusion and inspiration:
1. Although the function can return smoothly depending on the return address on the stack, this example also allows us to see whether the value of the EBP is modified indirectly, or the purpose of controlling the return address, except that the modification of the EBP value will not affect the return of the current function, but will affect the return of the previous function;

2. Although the compilation under the Linux is not familiar, but it is easy to read the code under the Visual Studio, it is easily readable through the compilation of Linux, thus, it can be learned from the value of reference, and the premise lies in the depth of some technology;

3. In the process of finding a problem, the use of contrasting methods, such as the comparison of the above-mentioned code version of BSD, can be implemented as envisaged; Let me confirm that the above code is indeed problematic; Thus, the value of comparison can be realized;

Stack overflow case analysis under Linux-gdb debug Drills

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.