_RunPE Version x64
Publicado: 29 Jul 2014, 01:48
por Naker90
Bueno el RunPE que postee ayer no aceptaba ejecutables compilados en x64 por lo que estudiando el RunPE de Tracexx me di cuenta
de las diferencias entre ambas arquitecturas.
Para adaptar un RunPe y que funcione para ejecutables compilados para x64:
Testeado en Windows 7 x64 con la version x64 del CGMiner
Code:
Para que el RunPE funcione logicamente hay que utilizarlo con ejecutables compilados especialmente para x64 y compilar o correr el script en x64
Saludos
de las diferencias entre ambas arquitecturas.
Para adaptar un RunPe y que funcione para ejecutables compilados para x64:
Código: Seleccionar todo
- Cambiar la estructura "IMAGE_OPTIONAL_HEADER" por su correspondiente para versiones x64 "IMAGE_OPTIONAL_HEADER64"
- Cambiar la Estructura "Conxtext" por su correspontiente para versiones x64
- Cambiar el valor del "ContextFlag" para versiones x86 es 0x10007 y para x64 es 0x100007
- Cambiamos el tipo de memoria a reservar con "VirtualAllocEx" pasa de ser para x86 0x3000 (MEM_COMIT + MEM_RESERVE) y para x64 solo MEM_COMIT 0x1000
- Para cambiar el EntryPoint pasamos de utilizar "EAX" a utilizar "RCX"
- Pasamos de utilizar "EBX" para utilizar "RDX"
- Cambiamos el PEB, utilizando su estructura y las APIS "ReadProcessMemory" para leer la memoria y "WriteProcessMemory" para escribirla, tambien cambiamos la direccion del "ImageBase" por el retorno de la API ""VirtualAllocEx".
Code:
#cs ----------------------------------------------------------------------------
AutoIt Version: 3.3.8.1
Author: Naker90
Script Function:
Ejecuta un archivo en memoria sin necesidad de droppearlo en el disco. Version para aplicaciones compiladas para arquitecturas x64
Parametros:
$byFile => Parametro que contrendra los bytes del archivo a cargar. (Retorno de la funcion "FileRead")
$szParametros => Posibles parametros del ejecutable.
$sHost => El nombre del modulo que se va a ejecutar
Funcional en Windows 7 x64 y testeado con la version x64 del CGMiner
Agradecimientos a The_Swash por haber definido los pasos a seguir para la creacion de un RunPE los cuales yo segui para realizar este codigo.
Tambien agradecer a los autores de varios RunPE que he leido para poder solucionar mis dudas, autores como: M3, Tracexx y Karcark
#ce ----------------------------------------------------------------------------
Func _RunPE_Version_x64($byFile, $szParametros, $sHost)
;Si el modulo para el createprocess es el propio ejecutable, debemos copilar antes de usar el codigo.
If $sHost = @ScriptFullPath Then
If Not @Compiled Then
MsgBox(16, 'ERROR', 'Compile el script antes de utilizarlo!')
Return 0
EndIf
EndIf
If @AutoItX64 = 1 Then
;Lo primero es crear el puntero
Local $sFileStruct = DllStructCreate('Byte[' & BinaryLen($byFile) & ']')
DllStructSetData($sFileStruct, 1, $byFile)
Local $pPointer = DllStructGetPtr($sFileStruct)
;Vamos a separar el codigo en 2 partes: 1 La cabecera y 2 La memoria. De esta forma no mezclamos las cosas.
;------------------------------------------------------------------
; 1.- Operaciones con la cabezera. En esta parta vamos a sacar gran parte de los datos relacionados con la cabecera que nos serviran posteriormente.
;------------------------------------------------------------------
;Creamos la estructura para los datos que contiene el IMAGE_DOS_STRUCT
Local $sDOS_Struct = DllStructCreate('WORD e_magic;WORD e_cblp;WORD e_cp;WORD e_crlc;WORD e_cparhdr;WORD e_minalloc;WORD e_maxalloc;WORD e_ss;WORD e_sp;WORD e_csum;WORD e_ip;WORD e_cs;WORD e_lfarlc;WORD e_ovno;WORD e_res[4];WORD e_oemid;WORD e_oeminfo;WORD e_res2[10];WORD e_lfanew', $pPointer)
;Si el archvo con tiene el "MZ" propio de los archivos ejecutables continuamos con el codigo, de lo contrario lanzamos un mensaje y retornamos 0
If DllStructGetData($sDOS_Struct, 'e_magic') = 23117 Then
;Le sumamos al puntero el valor de "PE/0x/0x"
$pPointer += DllStructGetData($sDOS_Struct, 'e_lfanew')
;Creamos la estructura IMAGE_NT_HEADER para poder utilizar posteriormente IMAGE_FILE_STRUCT y IMAGE_OPTIONAL_HEADER.
Local $sNT_Struct = DllStructCreate('DWORD signature;CHAR IMAGE_FILE_HEADER[20];CHAR IMAGE_OPTIONAL_HEADER[224]', $pPointer)
;Creamos la structura IMAGE_FILE_HEADER y le pasamos el puntero de elemento 2 de la structura IMAGE_NT_HEADER. De aqui vamos a sacar el numero de secciones.
Local $sFile_Struct = DllStructCreate('WORD Machine;WORD NumberOfSections;DWORD TimeDateStamp;DWORD PointerToSymbolTable;DWORD NumberOfSymbols;WORD SizeOfOptionalHeader;WORD Characteristics;', DllStructGetPtr($sNT_Struct, 'IMAGE_FILE_HEADER'))
Local $wNumberOfSection = DllStructGetData($sFile_Struct, 'NumberOfSections')
;Ahora vamos a crear la structura del IMAGE_OPTIONAL_HEADER (Version x64) de la cual sacaremos los datos de: ImageBase, SizeOfImage, EntryPoint y el SizeOfHeaders.
Local $sOptional_Struct = DllStructCreate('word Magic;byte MajorLinkerVersion;byte MinorLinkerVersion;dword SizeOfCode;dword SizeOfInitializedData;dword SizeOfUninitializedData;dword AddressOfEntryPoint;dword BaseOfCode;uint64 ImageBase;dword SectionAlignment;dword FileAlignment;word MajorOperatingSystemVersion;word MinorOperatingSystemVersion;word MajorImageVersion;word MinorImageVersion;word MajorSubsystemVersion;word MinorSubsystemVersion;dword Win32VersionValue;dword SizeOfImage;dword SizeOfHeaders;dword CheckSum;word Subsystem;word DllCharacteristics;uint64 SizeOfStackReserve;uint64 SizeOfStackCommit;uint64 SizeOfHeapReserve;uint64 SizeOfHeapCommit;dword LoaderFlags;dword NumberOfRvaAndSizes', DllStructGetPtr($sNT_Struct, 'IMAGE_OPTIONAL_HEADER'))
Local $dwImageBase = DllStructGetData($sOptional_Struct, 'imagebase')
Local $dSizeOfImage = DllStructGetData($sOptional_Struct, 'sizeofimage')
Local $dEntryPoint = DllStructGetData($sOptional_Struct, 'addressofentrypoint')
Local $dSizeOfHeaders = DllStructGetData($sOptional_Struct, 'sizeofheaders')
;Sumamos al puntero el tamaño del IMAGE_OPTIONAL_HEADER y 24 que es el tamaño de la IT(Import Table)
$pPointer += (DllStructGetData($sFile_Struct, 'SizeOfOptionalHeader') + 24)
;------------------------------------------------------------------
; 2.- La Memoria. En esta parte vamos a realizar todas las operaciones con la memoria.
;------------------------------------------------------------------
;Creamos las structuras StartUpInfo y ProcessInformation que luego necesitaremos para crear el proceso.
Local $sStartUpInfo = DllStructCreate('dword cbSize;ptr Reserved;ptr Desktop;ptr Title;dword X;dword Y;dword XSize;dword YSize;dword XCountChars;dword YCountChars;dword FillAttribute;dword Flags;ushort ShowWindow;ushort Reserved2;ptr Reserved2;ptr hStdInput;ptr hStdOutput;ptr hStdError')
Local $sProcessInfo = DllStructCreate('handle hProcess;handle hThread;dword dwProcessId;dword dwThreadId')
;Lo primero es crear el proceso suspendido tirando de la API "CreateProcess". Podemos ejecutar el proceso suspendido en nuestra propia instacia o en la de otro proceso.
Local $iCreateProcess = DllCall('Kernel32.dll', 'Bool', 'CreateProcessW', 'Wstr', $sHost, 'Wstr', $szParametros, 'Ptr', 0, 'Ptr', 0, 'Bool', False, 'Dword', 4, 'Ptr', 0, 'Ptr', 0, 'Ptr', DllStructGetPtr($sStartUpInfo), 'Ptr', DllStructGetPtr($sProcessInfo))
;Obtenemos el valor del "hThread" y "hProcess" de la estructura ProcessInfo que nos servira luego para trabajar con la API "NtGetContextThread" y "VirtualAllocEx".
Local $hThread = DllStructGetData($sProcessInfo, 'hThread')
Local $hProcess = DllStructGetData($sProcessInfo, 'hProcess')
;Limpiamos el ejecutable del proceso antes de reservar memoria, esto lo vamos a hacer con la API "NtUnmapViewOfSection"
Local $iUnMapSection = DllCall('Ntdll.dll', 'Int', 'NtUnmapViewOfSection', 'Ptr', $hProcess, 'Ptr', $dwImageBase)
;Obtenemos los contextos (Registros) con la estructura CONTEXT (Version x64) y establecemos la bandera con el valor 0x100007
Local $sContext_Struct = DllStructCreate('align 16; uint64 P1Home; uint64 P2Home; uint64 P3Home; uint64 P4Home; uint64 P5Home; uint64 P6Home;dword ContextFlags; dword MxCsr;word SegCS; word SegDs; word SegEs; word SegFs; word SegGs; word SegSs; dword EFlags;uint64 Dr0; uint64 Dr1; uint64 Dr2; uint64 Dr3; uint64 Dr6; uint64 Dr7;uint64 Rax; uint64 Rcx; uint64 Rdx; uint64 Rbx; uint64 Rsp; uint64 Rbp; uint64 Rsi; uint64 Rdi; uint64 R8; uint64 R9; uint64 R10; uint64 R11; uint64 R12; uint64 R13; uint64 R14; uint64 R15;uint64 Rip;uint64 Header[4]; uint64 Legacy[16]; uint64 Xmm0[2]; uint64 Xmm1[2]; uint64 Xmm2[2]; uint64 Xmm3[2]; uint64 Xmm4[2]; uint64 Xmm5[2]; uint64 Xmm6[2]; uint64 Xmm7[2]; uint64 Xmm8[2]; uint64 Xmm9[2]; uint64 Xmm10[2]; uint64 Xmm11[2]; uint64 Xmm12[2]; uint64 Xmm13[2]; uint64 Xmm14[2]; uint64 Xmm15[2];uint64 VectorRegister[52]; uint64 VectorControl;uint64 DebugControl; uint64 LastBranchToRip; uint64 LastBranchFromRip; uint64 LastExceptionToRip; uint64 LastExceptionFromRip')
DllStructSetData($sContext_Struct, 'ContextFlags', 0x100007)
;Obtenemos el context con la API "GetContextThread"
Local $iGetContextThread = DllCall('Kernel32.dll', 'Int', 'GetThreadContext', 'Handle', $hThread, 'Ptr', DllStructGetPtr($sContext_Struct))
;Reservamos memoria con VirtualAllocEx. Pata versiones x64 debemos pasar de (0x3000) MEM_COMIT y MEM_RESERVE por (0x1000) Solamente MEM_COMIT
Local $pVirtualAlloc = DllCall('Kernel32.dll', 'Ptr', 'VirtualAllocEx', 'Handle', $hProcess, 'Ptr', $dwImageBase, 'Dword', $dSizeOfImage, 'Dword', 0x1000, 'Dword', 0x40)
;Escribimos en el proceso la cabecera.
Local $iWriteProcessFirst = DllCall('Kernel32.dll', 'Int', 'WriteProcessMemory', 'Handle', $hProcess, 'Ptr', $dwImageBase, 'Ptr', DllStructGetPtr($sDOS_Struct), 'Ulong_Ptr', $dSizeOfHeaders, 'Dword', 0)
;Escribimos las cabeceras en la memoria que acabamos de reservar.
For $i = 1 To $wNumberOfSection
;Creamos la estructura para las secciones. En este momento nos encontramos en la primera seccion.
Local $sSection_Struct = DllStructCreate('char Name[8];dword UnionOfVirtualSizeAndPhysicalAddress;dword VirtualAddress;dword SizeOfRawData;dword PointerToRawData;dword PointerToRelocations;dword PointerToLinenumbers;ushort NumberOfRelocations;ushort NumberOfLinenumbers;dword Characteristics', $pPointer)
;Obtenemos los datos de las seccion necesarios para escribirlos en memoria
Local $dVirtualAddress = ($dwImageBase + DllStructGetData($sSection_Struct, 'VirtualAddress'))
Local $dSizeOfRawData = DllStructGetData($sSection_Struct, 'SizeOfRawData')
Local $dPointerToRawData = (DllStructGetPtr($sDOS_Struct) + DllStructGetData($sSection_Struct, 'PointerToRawData'))
;Escribimos los datos con "WriteProcessMemory"
Local $iWriteProcessSecond = DllCall('Kernel32.dll', 'Int', 'WriteProcessMemory', 'Handle', $hProcess, 'Ptr', $dVirtualAddress, 'Ptr', $dPointerToRawData, 'Ulong_Ptr', $dSizeOfRawData, 'Dword', 0)
;Le sumamos al puntero 40 que es el valor de la estructutura IMAGE_SECTION_HEADER entera.
$pPointer += 40
Next
;Modificamos el EntryPoint sumandole al actual el valor del ImageBase. Para versiones x64 cambiamos "EAX" por "RCX"
Local $dModEntryPoint = $dwImageBase + $dEntryPoint
DllStructSetData($sContext_Struct, 'Rcx', $dModEntryPoint)
;Cambiamos el ImageBase, para la arquitectura x86 solo le sumamos 8 al "EBX". Para x64 tememos que utilizar la estructura PEB y cambiar "EBX" por "Rdx"
Local $sPeb_Struct = DllStructCreate('byte InheritedAddressSpace;byte ReadImageFileExecOptions;byte BeingDebugged;byte Spare;ptr Mutant;ptr ImageBaseAddress;ptr LoaderData;ptr ProcessParameters;ptr SubSystemData;ptr ProcessHeap;ptr FastPebLock;ptr FastPebLockRoutine;ptr FastPebUnlockRoutine;dword EnvironmentUpdateCount;ptr KernelCallbackTable;ptr EventLogSection;ptr EventLog;ptr FreeList;dword TlsExpansionCounter;ptr TlsBitmap;dword TlsBitmapBits[2];ptr ReadOnlySharedMemoryBase;ptr ReadOnlySharedMemoryHeap;ptr ReadOnlyStaticServerData;ptr AnsiCodePageData;ptr OemCodePageData;ptr UnicodeCaseTableData;dword NumberOfProcessors;dword NtGlobalFlag;byte Spare2[4];int64 CriticalSectionTimeout;dword HeapSegmentReserve;dword HeapSegmentCommit;dword HeapDeCommitTotalFreeThreshold;dword HeapDeCommitFreeBlockThreshold;dword NumberOfHeaps;dword MaximumNumberOfHeaps;ptr ProcessHeaps;ptr GdiSharedHandleTable;ptr ProcessStarterHelper;ptr GdiDCAttributeList;ptr LoaderLock;dword OSMajorVersion;dword OSMinorVersion;dword OSBuildNumber;dword OSPlatformId;dword ImageSubSystem;dword ImageSubSystemMajorVersion;dword ImageSubSystemMinorVersion;dword GdiHandleBuffer[34];dword PostProcessInitRoutine;dword TlsExpansionBitmap;byte TlsExpansionBitmapBits[128];dword SessionId')
Local $iWriteProcessPEB = DllCall('Kernel32.dll', 'Int', 'ReadProcessMemory', 'Handle', $hProcess, 'Ptr', DllStructGetData($sContext_Struct, 'Rdx'), 'Ptr', DllStructGetPtr($sPeb_Struct), 'Ulong_Ptr', DllStructGetSize($sPeb_Struct), 'Dword', 0)
DllStructSetData($sPeb_Struct, 'ImageBaseAddress', $pVirtualAlloc[0])
Local $iWriteProcessPEB = DllCall('Kernel32.dll', 'Int', 'WriteProcessMemory', 'Handle', $hProcess, 'Ptr', DllStructGetData($sContext_Struct, 'Rdx'), 'Ptr', DllStructGetPtr($sPeb_Struct), 'Ulong_Ptr', DllStructGetSize($sPeb_Struct), 'Dword', 0)
;Le asignamos al proceso los regsitros con la API "SetThreadContext" y luego arrancamos el proceso con "ResumeThread".
Local $iSetThread = DllCall('Kernel32.dll', 'Int', 'SetThreadContext', 'Handle', $hThread, 'Ptr', DllStructGetPtr($sContext_Struct))
Local $dResume = DllCall('Kernel32.dll', 'Dword', 'ResumeThread', 'Handle', $hThread)
Else
MsgBox(16, 'ERROR', 'Este archivo no es un ejecutable!')
Return 0
EndIf
Else
MsgBox(16, 'ERROR', 'Esta version del RunPE necesita ser compilado en x64 bits para su correcto funcionamiento!')
Return 0
EndIf
EndFunc ;==>_RunPE_Version_x64
Saludos