Hi all,
I'm trying to learn basic shellcoding and I've run across something curious that I hope someone can explain to me. I've compiled the following code two ways: declaring the shellcode as an array and as a char*. When I declare shellcode as an array, linux detects that I am trying to execute data and I get a segfault on the first instruction. However, when I declare shellcode as a char* all of the shellcode executes and I get a "Hello world!". How does the compiler treat these two declarations differently and why does one end in shellcode that lives in memory that is unprotected? Thanks in advance.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* This declaration ends in a segfault */
//char shellcode[] =
/* This declaration ends in successful execution */
char* shellcode =
/* Shellcode prints "Hello world!" and exits */
"\xeb\x1f\x48\x31\xc0\x48\x31\xdb\x48\x31\xc9\x48\x31\xd2\xb0\x04\xb3\x01\x59\xb2\x0c\xcd\x80\x48\x31\xc0\xb0\x01\x48\x31\xdb\xcd\x80\xe8\xdc\xff\xff\xff\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64\x21";
int main()
{
void (*f)();
f = (void (*)())shellcode;
(void)(*f)();
}
The main difference between them is that the first is an array and the other one is a pointer.
A character array is a sequence of characters, just as a numeric array is a sequence of numbers.
char[] is a character array whereas char* is a pointer reference. char[] is a specific section of memory in which we can do things like indexing, whereas char* is the pointer that points to the memory location.
In C, an array of type char is used to represent a character string, the end of which is marked by a byte set to 0 (also known as a NUL character)
When you declare it as a char[]
, the memory is on the stack. When you declare it as a char*
and assign it a string literal, the memory is in the executable image itself. Linux doesn't like you executing code on the stack, but is fine with you executing memory in that part of the executable image. That is because it is trying to avoid a certain type of stack overflow attack where people can overflow the stack with some arbitrary instructions and then execute them.
You can use mprotect
on Linux to set the permissions for a region of memory or VirtualProtectEx
on Windows. That way you can explicitly set the permissions of the memory to be executable.
In your first case:
char shellcode[] =
This puts the string literal on the stack as a local array. The stack and heap memory usually does not have execute permissions (for obvious reasons of security).
In your second case:
char* shellcode =
The string lives in static memory - typically in the same region as the rest of the program binary - which is executable.
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