Stack overflow is mainly done by overwriting the function return address eip stored in the stack, and then writing the shellcode address at EIP.
There are many protections against stack overflow
1 Use stack protection
Such as the -fstack-protector GS switch on windows on linux.
The way this is handled is.
Save a specific DATA in the high position of the stack when entering the function
[buffer][DATA][ebp][eip]
low position high position
execute code
When exiting, the DATA is taken out and compared with the original.
If you want to overwrite the EIP at the high position, the DATA data in the stack will also be modified.
If DATA is modified, it means overflow. At this point, the exit command is executed.
(Simple is to save a data, if this data is guessed. It is still possible to bypass this detection by padding
So there is an enhanced version. It is to use esp and this value for xor. Because esp may be different every time. So it is not easy to guess.
)
This method can indeed be well protected from stack overflow.
2 ASLR load address randomization
Address Space Layout Randomization
Because the former needs to write a fixed address into EIP (if it is to jump to other modules. It is required that other modules must be loaded with fixed addresses. If it is to execute the code in the stack. The starting address of the stack must be fixed)
This causes inconvenience.
Therefore, the technology of ret2reg needs to be used. It mainly refers to checking whether there are any registers related to the stack address.
For example, when executing, find out whether there is a code called call reg jmp reg (this address should be fixed (such as the code of a module)) such as call esp call eax and the like.
And this reg points to the address in the stack. Write this fixed address code to eip. So it jumps back to the stack according to the form of call or jmp (even if the stack address is not fixed)
3 Data Execution Prevention
For example, the data in the stack is not executable. For example, Windows has DEP enabled.
In this way, the shellcode cannot be executed even if it is placed on the stack.
By returning to the system function.
For example, execute system("/bin/bash").
In this way, only strings such as /bin/bash are found in bin. Or write a custom string.
Sometimes the address of the system may end in 0. For example, 0x7fffff00. When 00 is encountered, it will not be copied.
In this case, you need to use plt or got.
what is plt and got
#include <stdio.h> void showmsg(char *szMsg) { printf("%s\n", szMsg); } int main(int argc, char **argv) { char szMsg[] = "Hello, world!"; showmsg(szMsg); return 0; }
The call to printf is changed by the compiler to puts@plt, located at 0×08048350, which is a PLT (Procedure Linkage Table) entry, scroll up to see the code at this address:
void showmsg(char *szMsg) { 8048434: 55 push %ebp 8048435: 89 e5 mov %esp,%ebp 8048437: 83 ec 18 sub $0x18,%esp printf("%s\n", szMsg); 804843a: 8b 45 08 mov 0x8(%ebp),%eax 804843d: 89 04 24 mov %eax,(%esp) 8048440: e8 0b ff ff ff call 8048350 <puts@plt> } 8048445: c9 leave 8048446: c3 ret 08048350 <puts@plt>: 8048350: ff 25 04 a0 04 08 jmp *0x804a004 8048356: 68 08 00 00 00 push $0x8 804835b: e9 d0 ff ff ff jmp 8048330 <_init+0x38> a.out: file format elf32-i386 DYNAMIC RELOCATION RECORDS OFFSET TYPE VALUE 08049ff0 R_386_GLOB_DAT __gmon_start__ 0804a000 R_386_JUMP_SLOT __stack_chk_fail 0804a004 R_386_JUMP_SLOT puts 0804a008 R_386_JUMP_SLOT __gmon_start__ 0804a00c R_386_JUMP_SLOT __libc_start_main
So you need to use strcpy to copy the addresses one by one.
For details, see http://blog.csdn.net/linyt/article/details/47429823
pop pop ret will pop the value of push when strcpy's first plt runs to repair got for the first time. Subsequent
strcpy will copy the trailing 0.