Tesla.Angela 发表于 2010-11-3 13:12:04

[转载]CreateRemoteThreadEx

// Sample code that shows how to call CreateRemoteThread with
// multiple parameters.
//
// Coded by. Defsanguje
#include <stdio.h>
#include <windows.h>

using namespace std;

////////////////////////////////////////////////////////////////////////////////
// "Extended" version of CreateRemoteThread. Supports multiple parameters and //
// handles parameter passing.                                                 //
////////////////////////////////////////////////////////////////////////////////
// Parameters:                                                                //
//                                                                            //
// - __in HANDLE hProcess                                                   //
//   A handle to the process in which the thread is to be created             //
// - __in LPSECURITY_ATTRIBUTES lpThreadAttributes                            //
//   A pointer to a SECURITY_ATTRIBUTES structure that specifies a security   //
//   descriptor for the new thread. If lpThreadAttributes is NULL, the thread //
//   gets a default security descriptor.                                    //
// - __in SIZE_T dwStackSize                                                //
//   The initial size of the stack, in bytes. The system rounds this value to //
//   the nearest page. If this parameter is 0 (zero), the new thread uses the //
//   default size for the executable.                                       //
// - __in LPTHREAD_START_ROUTINE lpStartAddress                               //
//   A pointer to the application-defined function of type                  //
//   LPTHREAD_START_ROUTINE to be executed by the thread and represents the   //
//   starting address of the thread in the remote process. The function must//
//   exist in the remote process.                                             //
// - __in DWORD dwCreationFlags                                             //
//   The flags that control the creation of the thread.                     //
//   (0, CREATE_SUSPENDED, STACK_SIZE_PARAM_IS_A_RESERVATION)               //
// - __out LPDWORD lpThreadId                                                 //
//   A pointer to a variable that receives the thread identifier. Can be NULL //
// - __in LPSTR szFormat                                                      //
//   Similar to format in printf/scanf. Specifies types of arguments.         //
//   There's three different specifiers for szFormat:                         //
//   %x/%u/%d - DWORD, 4 bytes, value passed directly to the thread         //
//   %d- Write num bytes from argument to remote process, pass pointer //
//            - to the data for the thread(ex. %10d)                        //
//   %s       - Write ASCII string to remote process, pass pointer to the   //
//            string for the thread                                       //
////////////////////////////////////////////////////////////////////////////////
// Remarks:                                                                   //
//                                                                            //
// Threads that exits using TerminateThread(), ExitThread() or similar doesn't//
// free memory that's allocated for "callgate"                              //
////////////////////////////////////////////////////////////////////////////////
HANDLE
CreateRemoteThreadEx(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes,
                     SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
                     DWORD dwCreationFlags, LPDWORD lpThreadId,
                     LPSTR szFormat, ...)
{
    char *lpCallGate,
         *lpData,
         *lpCode,
         *lpArg;
    va_list vlParameters;
    BYTE i, j;
    DWORD dwDataSize,
          dwCallSize,
          dwWritten,
          dwAmount = 0; // amount of parameters

    char CallGateShellcode[] = "\xE8\x1D\x00\x00\x00" // CALL $+0x1D
                           /*/*/
                        /*|*/"\x50"               // PUSH EAX
                        /*|*/"\x68\x58\x58\xC3\x90" // PUSH 90C35858 (code for POP EAX\nPOP EAX\nRETN)"
                        /*|*/"\x68\x00\x40\x00\x00" // PUSH MEM_RELEASE
                        /*|*/"\x6A\x01"             // PUSH 1
                        /*|*/"\x68\x00\x00\x00\x00" // PUSH 00000000 (-> PUSH lpCallGate)
                        /*|*/"\x54"               // PUSH ESP
                        /*|*/"\x83\x04\x24\x0C"   // ADD DWORD , 0x0C
                        /*|*/"\x68\x00\x00\x00\x00" // PUSH 00000000 (-> PUSH VirtualFree)
                        /*|*/"\xC3"               // RETN
                           /*\*/
                               "\x68\x00\x00\x00\x00" // PUSH 00000000 (-> PUSH lpStartAddress)
                               "\xC3"               // RETN
                               ;
   
    // Calculate the size of our callgate. Depends on
    // amount of parameters.
   
    if(szFormat)
    {
      // Count %'s
      for(i = 0; szFormat != '\0'; i++)
            if(szFormat == '%')
                dwAmount++;
   
      // Calculate size of data (%s, %d)
      i = 0;
      dwDataSize = 0;
      va_start(vlParameters, dwAmount);
      while(szFormat != '\0')
      {
            if(szFormat != '%')
                return NULL;
            i++;
         
            switch(szFormat)
            {
                case 'd':
                case 'u':
                case 'x':
                  va_arg(vlParameters, DWORD);
                  break;
                case 's':
                  dwDataSize += lstrlen(va_arg(vlParameters, char*)) + 1;
                  break;
                default: // number?
                  // Conversion from string to integer
                  for(j = 0; szFormat >= '0' && szFormat <= '9'; i++)
                        j = j * 10 + szFormat - '0';
                  if(!j || szFormat != 'd') return 0; // Converting failed
               
                  va_arg(vlParameters, char*);
                  dwDataSize += j;
                  break;
            }
            i++;
      }
      va_end(vlParameters);
    } // if(szFormat)
   
    dwCallSize = dwAmount * (4+1)             // Size ofPUSH instructions
               + dwDataSize               // %s, %d
               + sizeof(CallGateShellcode);
   
    // Allocate memory for callgate constructing (local process)
    char* lpShellcodeBuffer = (char*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCallSize);
    if(!lpShellcodeBuffer)
      return NULL;
   
    // Allocate memory from remote process
    lpCallGate = (char*)VirtualAllocEx(hProcess, NULL, dwCallSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if(!lpCallGate)
    {
      HeapFree(GetProcessHeap(), 0, lpShellcodeBuffer);
      return NULL;
    }
   
    // Construct it. Copy data/strings to beginning of the buffer,
    // code to the end.
    va_start(vlParameters, dwAmount);
    lpData = lpShellcodeBuffer;
    lpCode = lpShellcodeBuffer + dwDataSize + dwAmount * (1+4);
    i = 0;
    if(szFormat)
    {
      while(szFormat != '\0')
      {
            i++; // %
            switch(szFormat)
            {
                case 'd':
                case 'u':
                case 'x':
                  lpCode -= 5; // due to calling conventions
                  (*lpCode)         = 0x68; // PUSH
                  *(DWORD*)(lpCode+1) = (DWORD)va_arg(vlParameters, DWORD);
                  break;
                case 's':
                  lpArg = va_arg(vlParameters, char*);
                  j = lstrlen(lpArg) + 1;
                  break;
                default:
                  // Conversion from string to integer
                  lpArg = va_arg(vlParameters, char*);
                  for(j = 0; szFormat >= '0' && szFormat <= '9'; i++)
                        j = j * 10 + szFormat - '0';
                  break;
            }
            if(szFormat == 's' || szFormat == 'd')
            {
                lpCode -= 5;
                (*lpCode)         = 0x68;
                *(DWORD*)(lpCode+1) = (DWORD)(lpCallGate + (lpData-lpShellcodeBuffer));
            
                while(j)
                {
                  (*lpData) = *lpArg;
                  lpData++, lpArg++;
                  j--;
                }
            }
            i++; // xsd
      }
      va_end(vlParameters);
    } // if(szFormat)
   
    // Copy the shellcode
    // (it's responsible to push arguments to stack, virtualfree itself, call the thread)
    lpCode = lpShellcodeBuffer + dwDataSize + dwAmount * (1+4);
    *(DWORD*)(CallGateShellcode + 19) = (DWORD)lpCallGate;
    *(DWORD*)(CallGateShellcode + 35) = (DWORD)lpStartAddress;
    *(DWORD*)(CallGateShellcode + 29) = (DWORD)GetProcAddress(GetModuleHandle("kernel32.dll"), "VirtualFree");
    for(i = 0; i < sizeof(CallGateShellcode); i++, lpCode++)
       (*lpCode) = CallGateShellcode;
   
    // Write the shellcode to remote process and call it
    WriteProcessMemory(hProcess, lpCallGate, lpShellcodeBuffer, dwCallSize, &dwWritten);   
    HeapFree(GetProcessHeap(), 0, lpShellcodeBuffer);
   
    if(!dwWritten)
      return NULL;
    return CreateRemoteThread(hProcess, lpThreadAttributes, dwStackSize,
                              (LPTHREAD_START_ROUTINE)(lpCallGate + dwDataSize), 0,
                              dwCreationFlags, lpThreadId);
}

int main(int argc, char *argv[])
{
    char szWnd;
    HANDLE hProcess = NULL, hThr = NULL;
    HWND hWnd = NULL;
    DWORD dwPID = 0, dwExitCode;
    printf("Boring CreateRemoteThreadEx() demo\n");
   
    do
    {
      printf("Give window (not process) name\n");
         
      // whitespaces also
      scanf("%255[^\t\n]", szWnd);
      while(getchar() != (int)'\n');
         
      GetWindowThreadProcessId(FindWindow(NULL, szWnd), &dwPID);
      if(dwPID)
      {
            hProcess =
            OpenProcess(
                        PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION
                        | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
                        FALSE,
                        dwPID
                        );
      } else printf ("FindWindow(); failed\n");
    } while(!hProcess);
   
    hThr = CreateRemoteThreadEx(hProcess, NULL, 0,
                              (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("user32.dll"), "MessageBoxA"),
                              0, NULL,
                              "%x%s%8d%x",
                              NULL, "Hello world", "Caption", MB_ICONEXCLAMATION | MB_YESNOCANCEL);
    /*hThr = CreateRemoteThreadEx(hProcess, NULL, 0,
                              (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("kernel32.dll"), "GetTickCount"),
                              0, NULL,
                              NULL); // "");*/
   
    CloseHandle(hProcess);
   
    if(hThr)
    {
      printf("Created remote thread succesfully!\n"
               "Waiting for thread exit code...\n");
      WaitForSingleObject(hThr, INFINITE);
      GetExitCodeThread(hThr, &dwExitCode);
      CloseHandle(hThr);
      printf("Thread exited with code: %d\n", dwExitCode);
    } else printf("Remote thread creation failed!");
   
    system("PAUSE");
    return EXIT_SUCCESS;
}

Tesla.Angela 发表于 2010-11-3 13:14:50

原始出处:http://www.rohitab.com/discuss/t ... reateremotethreadex;/
页: [1]
查看完整版本: [转载]CreateRemoteThreadEx