ERROR - Process Hollowing

Iniciado por ThunderCls, 11 Agosto 2011, 01:35 AM

0 Miembros y 1 Visitante están viendo este tema.

ThunderCls

Hola gente
Veran, he estado practicando un poco con el formato PE, la cuestion es que he querido usar un codigo para dichos fines pero no logro que me funcione.
El codigo que estoy estudiando es uno usado para correr un ejecutable en el contexto de otro, lo que comunmente la mayoria conoce como RunPE  :P , el codigo compila sin problemas, el problema se da a la hora de resumir el hilo para continuar la ejecucion, por lo que sospecho que hay algun fallo cuando el exe2 se copia en la memoria del exe1, pero no se a ciencia cierta cual podria ser el fallo, pues cuando intento ejecutar, por ej, el bloc de notas en la calculadora lo hace sin problemas, el fallo lo da cuando intento con otra app. El codigo es el siguiente:

Código (cpp) [Seleccionar]
typedef DWORD (__stdcall *pNtUnmapViewOfSection)(HANDLE ProcessHandle, PVOID BaseAddress);
void RunPE(LPSTR, LPSTR);

typedef struct {
   PIMAGE_DOS_HEADER dos_header;
   PIMAGE_NT_HEADERS nt_headers;
   PIMAGE_SECTION_HEADER section_header;
   LPBYTE file_data;
} NEW_PROCESS_INFO, *PNEW_PROCESS_INFO;

void get_replacement_info(const char* full_file_path, PNEW_PROCESS_INFO new_process_info)
{
   DWORD bytes_read;

   HANDLE hFile = CreateFileA(full_file_path,
                              GENERIC_READ,
                              FILE_SHARE_READ,
                              NULL,
                              OPEN_EXISTING,
                              FILE_ATTRIBUTE_NORMAL,
                              NULL);
   //Note: High DWORD ignored, dangerous with >4GB files :-P
   DWORD file_size = GetFileSize(hFile, NULL);

   new_process_info->file_data = (LPBYTE)malloc(file_size * sizeof(LPBYTE));
   ReadFile(hFile, new_process_info->file_data, file_size, &bytes_read, 0);

   assert(bytes_read == file_size);
   new_process_info->dos_header = (PIMAGE_DOS_HEADER)(&new_process_info->file_data[0]);
   new_process_info->nt_headers = (PIMAGE_NT_HEADERS)(&new_process_info->file_data[new_process_info->dos_header->e_lfanew]);
}

void RunPE(LPSTR file, LPSTR host)
{
   NEW_PROCESS_INFO new_process_info;
   PROCESS_INFORMATION process_info;
   STARTUPINFOA startup_info;

   RtlZeroMemory(&startup_info, sizeof(STARTUPINFOA));
   pNtUnmapViewOfSection NtUnmapViewOfSection = NULL;

   CreateProcessA(NULL,
                  host,
                  NULL,
                  NULL,
                  FALSE,
                  CREATE_SUSPENDED,
                  NULL,
                  NULL,
                  &startup_info,
                  &process_info);

   get_replacement_info(file, &new_process_info);
   NtUnmapViewOfSection = (pNtUnmapViewOfSection)(GetProcAddress(GetModuleHandleA("ntdll.dll"),
                                                                                  "NtUnmapViewOfSection"));
   //Remove target memory code
   NtUnmapViewOfSection(process_info.hProcess, (PVOID)new_process_info.nt_headers->OptionalHeader.ImageBase);
   //Allocate memory in target process starting at replacements image base
   VirtualAllocEx(process_info.hProcess,
                  (PVOID)new_process_info.nt_headers->OptionalHeader.ImageBase,
                  new_process_info.nt_headers->OptionalHeader.SizeOfImage,
                  MEM_COMMIT | MEM_RESERVE,
                  PAGE_EXECUTE_READWRITE);

   //Copy in PE header of replacement process
   WriteProcessMemory(process_info.hProcess,
                      (PVOID)new_process_info.nt_headers->OptionalHeader.ImageBase,
                      &new_process_info.file_data[0],
                      new_process_info.nt_headers->OptionalHeader.SizeOfHeaders,
                      NULL);

   //Write in all sections of the replacement process
   for(int i = 0; i < new_process_info.nt_headers->FileHeader.NumberOfSections; i++)
   {
      //Get offset of section
      int section_offset = new_process_info.dos_header->e_lfanew +
                           sizeof(IMAGE_NT_HEADERS) +
                           (sizeof(IMAGE_SECTION_HEADER) * i);
      new_process_info.section_header = (PIMAGE_SECTION_HEADER)(&new_process_info.file_data[section_offset]);

      //Write in section
      WriteProcessMemory(process_info.hProcess,
                         (LPVOID)(new_process_info.nt_headers->OptionalHeader.ImageBase +
                         new_process_info.section_header->VirtualAddress),
                         &new_process_info.file_data[new_process_info.section_header->PointerToRawData],
                         new_process_info.section_header->SizeOfRawData,
                         NULL);
   }

   //Get CONTEXT of main thread of suspended process, fix up EAX to point to new entry point
   LPCONTEXT thread_context = (LPCONTEXT)LocalAlloc(LPTR, sizeof(CONTEXT));
   thread_context->ContextFlags = CONTEXT_FULL;
   GetThreadContext(process_info.hThread, thread_context);
   thread_context->Eax = new_process_info.nt_headers->OptionalHeader.ImageBase +
                         new_process_info.nt_headers->OptionalHeader.AddressOfEntryPoint;
   SetThreadContext(process_info.hThread, thread_context);

   //Resume the main thread, now holding the replacement processes code
   ResumeThread(process_info.hThread);
   free(new_process_info.file_data);
   LocalFree(thread_context);
}


Si alguien me pudiera dar una manito aqui se lo agradeceria. Por cierto, estoy usando el BC++
Saludos
-[ "...I can only show you the door. You're the one that has to walk through it." – Morpheus (The Matrix) ]-
http://reversec0de.wordpress.com
https://github.com/ThunderCls/

Eternal Idol

Lo mejor que podes hacer es instalar el WinDbg y depurar.
La economía nunca ha sido libre: o la controla el Estado en beneficio del Pueblo o lo hacen los grandes consorcios en perjuicio de éste.
Juan Domingo Perón

Karman

Cita de: [ Thunder | CLS ] en 11 Agosto 2011, 01:35 AMel problema se da a la hora de resumir el hilo para continuar la ejecucion, por lo que sospecho que hay algun fallo cuando el exe2 se copia en la memoria del exe1, pero no se a ciencia cierta cual podria ser el fallo, pues cuando intento ejecutar, por ej, el bloc de notas en la calculadora lo hace sin problemas, el fallo lo da cuando intento con otra app.

para "ese código" tenes que asegurarte que ambos ejecutables tengan la misma imagebase, dado que el código no comprueba la imagebase del ejecutable original, en caso de no ser iguales tendrías que asegurarte que el segundo ejecutable tenga el directorio reloc's y realizar el relocado manual... acá tenes un ejemplo de como hacerlo:

Código (cpp) [Seleccionar]
#include <windows.h>
#include <stdio.h>

typedef ULONG (WINAPI *tNtUnmapViewOfSection)(HANDLE ProcessHandle, PVOID BaseAddress);
typedef ULONG (WINAPI *tNtQueryInformationProcess)(HANDLE ProcessHandle,DWORD ProcessInformationClass,
PVOID ProcessInformation,ULONG ProcessInformationLength,PULONG ReturnLength);

typedef struct{
   PIMAGE_DOS_HEADER dos_header;
   PIMAGE_NT_HEADERS nt_headers;
   PIMAGE_SECTION_HEADER section_header;
   LPBYTE file_data;
}NEW_PROCESS_INFO, *PNEW_PROCESS_INFO;

typedef struct _PEB {
  BYTE   Reserved1[2];
  BYTE   BeingDebugged;
  BYTE   Reserved2[1];
  PVOID  Reserved3[1];
  PVOID  ImageBaseAddress;
  PVOID  Ldr;
  PVOID  ProcessParameters;
  BYTE   Reserved4[104];
  PVOID  Reserved5[52];
  PVOID  PostProcessInitRoutine;
  BYTE   Reserved6[128];
  PVOID  Reserved7[1];
  ULONG  SessionId;
} PEB, *PPEB;

typedef struct _PROCESS_BASIC_INFORMATION {
  PVOID Reserved1;
  PPEB PebBaseAddress;
  PVOID Reserved2[2];
  ULONG_PTR UniqueProcessId;
  PVOID Reserved3;
} PROCESS_BASIC_INFORMATION;

BOOL get_replacement_info(const char* full_file_path, PNEW_PROCESS_INFO new_process_info){
  DWORD bytes_read;
  HANDLE hFile=CreateFileA(full_file_path,GENERIC_READ,FILE_SHARE_READ,NULL,
    OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
  if(hFile==INVALID_HANDLE_VALUE)
  return FALSE;
  DWORD file_size=GetFileSize(hFile,NULL);
  new_process_info->file_data=(LPBYTE)malloc(file_size*sizeof(LPBYTE));
  if(ReadFile(hFile,new_process_info->file_data,file_size,&bytes_read,0)){
    new_process_info->dos_header = (PIMAGE_DOS_HEADER)(&new_process_info->file_data[0]);
    new_process_info->nt_headers = (PIMAGE_NT_HEADERS)(&new_process_info->file_data[new_process_info->dos_header->e_lfanew]);
    return TRUE;
  }
  free(new_process_info->file_data);
  CloseHandle(hFile);
  return FALSE;
}

BOOL RunPE(LPSTR file, LPSTR host){
  NEW_PROCESS_INFO new_process_info;
  HMODULE hNtdll=GetModuleHandleA("ntdll.dll");
  tNtUnmapViewOfSection NtUnmapViewOfSection=(tNtUnmapViewOfSection)
  (GetProcAddress(hNtdll,"NtUnmapViewOfSection"));
  tNtQueryInformationProcess NtQueryInformationProcess=(tNtQueryInformationProcess)
  (GetProcAddress(hNtdll,"NtQueryInformationProcess"));
  if(!NtUnmapViewOfSection||!NtQueryInformationProcess)
    return FALSE;
  if(get_replacement_info(file,&new_process_info)){
    PROCESS_INFORMATION process_info;STARTUPINFOA startup_info;
    RtlZeroMemory(&startup_info,sizeof(STARTUPINFOA));
    if(CreateProcessA(NULL,host,NULL,NULL,FALSE,CREATE_SUSPENDED,NULL,NULL,&startup_info,&process_info)){
      //Get client base address
      PEB Peb;PROCESS_BASIC_INFORMATION pbi;/*ProcessBasicInformation*/
      NtQueryInformationProcess(process_info.hProcess,0,&pbi,sizeof(pbi),NULL);
      ReadProcessMemory(process_info.hProcess,(LPCVOID)pbi.PebBaseAddress,&Peb,sizeof(Peb),NULL);
      //Reloc new process
      if(new_process_info.nt_headers->OptionalHeader.ImageBase!=(DWORD)Peb.ImageBaseAddress){
        DWORD Delta=((DWORD)Peb.ImageBaseAddress-new_process_info.nt_headers->OptionalHeader.ImageBase);
        if(new_process_info.nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress){
          PIMAGE_BASE_RELOCATION pIBR=NULL;
          DWORD pRVAIBR=(DWORD)new_process_info.nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
          for(int i=0;i<new_process_info.nt_headers->FileHeader.NumberOfSections;i++){
            PIMAGE_SECTION_HEADER pimage_section_header=(PIMAGE_SECTION_HEADER)(
              (LPBYTE)&new_process_info.nt_headers->OptionalHeader+new_process_info.nt_headers->FileHeader.SizeOfOptionalHeader+
              (i*sizeof(IMAGE_SECTION_HEADER))
            );
            if((pRVAIBR>=pimage_section_header->VirtualAddress)&&(pRVAIBR<=(pimage_section_header->VirtualAddress+pimage_section_header->SizeOfRawData))){
              PIMAGE_SECTION_HEADER section=(PIMAGE_SECTION_HEADER)pimage_section_header;
              pIBR=(PIMAGE_BASE_RELOCATION)(pRVAIBR+section->PointerToRawData-section->VirtualAddress+new_process_info.file_data);
              break;
            }
          }
          PBYTE dest=NULL;
          for(;pIBR->VirtualAddress>0;){
            DWORD pRVAIBR=(DWORD)pIBR->VirtualAddress;
            for(int i=0;i<new_process_info.nt_headers->FileHeader.NumberOfSections;i++){
              PIMAGE_SECTION_HEADER pimage_section_header=(PIMAGE_SECTION_HEADER)(
                (LPBYTE)&new_process_info.nt_headers->OptionalHeader+new_process_info.nt_headers->FileHeader.SizeOfOptionalHeader+
                (i*sizeof(IMAGE_SECTION_HEADER))
              );
              if((pRVAIBR>=pimage_section_header->VirtualAddress)&&(pRVAIBR<=(pimage_section_header->VirtualAddress+pimage_section_header->SizeOfRawData))){
                PIMAGE_SECTION_HEADER section=(PIMAGE_SECTION_HEADER)pimage_section_header;
                dest=(PBYTE)(pRVAIBR+section->PointerToRawData-section->VirtualAddress+new_process_info.file_data);
                break;
              }
            }
            if(dest){
              PWORD relInfo=(PWORD)((PBYTE)pIBR+IMAGE_SIZEOF_BASE_RELOCATION);
              for(DWORD i=0;i<((pIBR->SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION)/2);i++,relInfo++){
                if((*relInfo>>12)==IMAGE_REL_BASED_HIGHLOW){
                  PDWORD pAddress=(LPDWORD)(dest+(*relInfo&0xfff));
                  *pAddress+=Delta;
                }
              }
            }
            pIBR=(PIMAGE_BASE_RELOCATION)(((DWORD)pIBR)+pIBR->SizeOfBlock);
          }
        }else{
          puts("no reloc table");
          TerminateProcess(process_info.hProcess,0);
          return FALSE;
        }
        new_process_info.nt_headers->OptionalHeader.ImageBase=(DWORD)Peb.ImageBaseAddress;
      }
      //Remove target memory code
      NtUnmapViewOfSection(process_info.hProcess,(PVOID)new_process_info.nt_headers->OptionalHeader.ImageBase);
      //Allocate memory in target process starting at replacements image base
      VirtualAllocEx(process_info.hProcess,(PVOID)new_process_info.nt_headers->OptionalHeader.ImageBase,
        new_process_info.nt_headers->OptionalHeader.SizeOfImage,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);
      //Copy in PE header of replacement process
      WriteProcessMemory(process_info.hProcess,(PVOID)new_process_info.nt_headers->OptionalHeader.ImageBase,
        &new_process_info.file_data[0],new_process_info.nt_headers->OptionalHeader.SizeOfHeaders,NULL);
      //Write in all sections of the replacement process
      for(int i=0;i<new_process_info.nt_headers->FileHeader.NumberOfSections;i++){
        //Get offset of section
        int section_offset=new_process_info.dos_header->e_lfanew+sizeof(IMAGE_NT_HEADERS)+(sizeof(IMAGE_SECTION_HEADER)*i);
        new_process_info.section_header=(PIMAGE_SECTION_HEADER)(&new_process_info.file_data[section_offset]);
        //Write in section
        WriteProcessMemory(process_info.hProcess,(LPVOID)((DWORD_PTR)new_process_info.nt_headers->OptionalHeader.ImageBase+
          new_process_info.section_header->VirtualAddress),&new_process_info.file_data[new_process_info.section_header->PointerToRawData],
          new_process_info.section_header->SizeOfRawData,NULL);
      }
      //Get CONTEXT of main thread of suspended process, fix up EAX to point to new entry point
      CONTEXT thread_context;
      thread_context.ContextFlags=CONTEXT_FULL;
      GetThreadContext(process_info.hThread,&thread_context);
      thread_context.Eax=new_process_info.nt_headers->OptionalHeader.ImageBase+new_process_info.nt_headers->OptionalHeader.AddressOfEntryPoint;
      SetThreadContext(process_info.hThread,&thread_context);
      //Resume the main thread, now holding the replacement processes code
      ResumeThread(process_info.hThread);
      free(new_process_info.file_data);
      return TRUE;
    }else
      puts("createprocess fail!");
  }else
    puts("get_replacement_info fail!");
  return FALSE;
}

int main(void){
  RunPE("C:\\WINDOWS\\explorer.exe","C:\\CodeBlocks\\Examples\\MyApp.exe");
  system("pause");
  return 0;
}


S2