I'm not really getting how this code does what it does:
char shellcode[] = "\xbb\x00\x00\x00\x00"
"\xb8\x01\x00\x00\x00"
"\xcd\x80";
int main()
{
int *ret;
ret = (int *)&ret + 2;
(*ret) = (int)shellcode;
}
Okay, I know:
int *ret;
sets a pointer of int. and:
ret = (int *)&ret + 2;
sets the address of ret and 2 bytes (I think.)
But I don't get what this means:
(int *)&ret
I know what &ret
means but not what (int *)&ret
means.
Also, how does it execute the shellcode by assigning the value of shellcode
to ret
?
UPDATE: What is the difference between:
(int *)&ret + 2
and:
&ret + 2
It is called "shellcode" because it typically starts a command shell from which the attacker can control the compromised machine, but any piece of code that performs a similar task can be called shellcode.
In relation to a vulnerability, it's a set of instructions used as a payload. In most cases, the shellcode is written in assembly language. In most situations, a command shell or a Meterpreter shell will be supplied after the target computer has completed the set of instructions.
Shellcodes are typically written in assembly language, in order to gain full control on the layout of code and data in stack and heap memory, to make the shellcode more compact, to obfuscate the code, and to perform low-level operations on data representation (Deckard 2005; Foster 2005; Anley et al.
Linux/x86 - execve(/bin/sh) Shellcode (20 bytes)
The 'string' shellcode
contains some machine code of some sort.
The int *ret;
defines a variable ret
which is a pointer to an int
.
The assignment ret = (int *)&ret + 2;
makes ret
point to a location the size of two int
from its own actual location (or address); this is an address in the stack, presumably where the return address of the function (main()
) is stored on the stack.
The assignment *ret = (int)shellcode;
assigns the address of the shell code to the return address. Therefore, when the main()
function exits, the return address is the shell code, which does whatever it does instead of exiting the program normally.
The casts cover up a multitude of sins. The code makes a large number of non-portable assumptions which are probably justified on the target environment but not necessarily anywhere else.
What's the difference between:
&ret+2
and(int *)&ret + 2
?
Type, mainly; this is one of the multitude of sins mentioned previously. &ret
has the type int **
(pointer to pointer to int
) instead of int *
which is the type of ret
itself. Since sizeof(int *) == sizeof(int **)
on all actual machines, the cast merely quells a complaint from the compiler (about assigning the wrong type of pointer to ret
) without changing the numerical result.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With