Agradecimientos a The Swash y Thor por esos magníficos manuales de las secciones PE y a Pink por la ayudita prestada.
Sin mas aquí el code, esta bastante comentado:
#cs ----------------------------------------------------------------------------
AutoIt Version: 3.3.8.1
Author: Naker90
Script Function:
Añade una seccion a un ejecutable
Agradecimientos a Pink, The Swash y Thor
Esta funcion no soporta la tabla BOUND IMPORT.
#ce ----------------------------------------------------------------------------
Func AddSection($sFile, $sSectionName)
;Abrimos el archivo, obtenemos su peso, lo leemos y lo cerramos.
Local $sOpen = FileOpen($sFile, 16)
Local $sSize = FileGetSize($sFile)
Local $sRead = FileRead($sOpen)
FileClose($sOpen)
;Creamos una structura de bytes y creamos el puntero para pasarselos a las estructuras posteriores.
Local $sFileStruct = DllStructCreate('Byte[' & $sSize & ']')
DllStructSetData($sFileStruct, 1, $sRead)
Local $sPointer = DllStructGetPtr($sFileStruct)
;Creamos la primera structura IMAGE_DOS_HEADER donde se encuentra e_magic que contiene los datos "MZ" si el archivo es un ejecutable.
Local $sIMAGE_DOS_HEADER = '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'
Local $sDosStruct = DllStructCreate($sIMAGE_DOS_HEADER, $sPointer)
Local $sMZ = DllStructGetData($sDosStruct, 'e_magic')
;Si el archivo no es un ejecutable (Por que no contiene "MZ"), mostramos un error y salimos de lo contrario seguimos el codigo.
If Not $sMZ = 23117 Then
MsgBox(64, 'ERROR', 'El archivo elegido no es un archivo ejecutable')
Exit
Else
;Le sumamos al puntero el valor de PE\0x\0x que se encuentra en IMAGE_DOS_HEAEDER en el parametro e_lfanew.
$sPointer += DllStructGetData($sDosStruct, 'e_lfanew')
;Caragamos 3 nuevas estructuras .
Local $sIMAGE_NT_HEADER = 'DWORD signature;CHAR IMAGE_FILE_HEADER[20];CHAR IMAGE_OPTIONAL_HEADER[224]'
Local $sNTStruct = DllStructCreate($sIMAGE_NT_HEADER, $sPointer)
;Le pasamos de puntero el ultimo parametro de la structura de IMAGE_NT_HEADER y obtenemos el sectionalignment y el filealignment que despues nos van a hacer
;falta para calcular la nueva seccion.
Local $sIMAGE_OPTIONAL_HEADER = 'WORD magic;BYTE majorlinkerversion;BYTE minorlinkerversion;DWORD sizeofcode;DWORD sizeofinitializeddata;' & _
'DWORD sizeofuninitializeddata;DWORD addressofentrypoint;DWORD baseofcode;DWORD baseofdata;DWORD imagebase;' & _
'DWORD sectionalignment;DWORD filealignment;WORD majoroperatingsystemversion;WORD minoroperatingsystemversion;' & _
'WORD majorimageversion;WORD minorimageversion;WORD majoresubsystemversion;WORD minorsubsystemversion;' & _
'DWORD win32versionvalue;DWORD sizeofimage;DWORD sizeofheaders;DWORD checksum;WORD subsystem;WORD dllcharacteristics;' & _
'DWORD sizeofstackreserve;DWORD sizeofstackcommit;DWORD sizeofheapcommit;DWORD loaderflags;DWORD numberofrvaandsizes;' & _
'DOUBLE datadirectory[16]'
Local $sOptionalStruct = DllStructCreate($sIMAGE_OPTIONAL_HEADER, DllStructGetPtr($sNTStruct, 'IMAGE_OPTIONAL_HEADER'))
Local $sSectionAligment = DllStructGetData($sOptionalStruct, 'sectionalignment')
Local $sFileAligment = DllStructGetData($sOptionalStruct, 'filealignment')
;Le pasamos como puntero en 2º parametro de la estructura de IMAGE_NT_HEADER.
Local $sIMAGE_FILE_HEADER = 'WORD Machine;WORD NumberOfSections;DWORD TimeDateStamp;DWORD PointerToSymbolTable;DWORD NumberOfSymbols;WORD SizeOfOptionalHeader;' & _
'WORD Characteristics;'
Local $sFileHeaderStruct = DllStructCreate($sIMAGE_FILE_HEADER, DllStructGetPtr($sNTStruct, 'IMAGE_FILE_HEADER'))
;Obtenemos la direccion del la ultima seccion.
Local $sLastSection = DllStructGetData($sFileHeaderStruct, 'numberofsections') - 1
;Le sumamos al puntero el tamaño de SizeOfOptionalHeader + 24 y las secciones multiplicadas por 0x28 (0x28 por que es lo que ocupa cada seccion).
$sPointer += (24 + DllStructGetData($sFileHeaderStruct, 'SizeOfOptionalHeader'))
$sPointer += ($sLastSection * 0x28)
;Creamos una nueva estructura (IMAGE_FILE_HEADER) para sacar unos valores de la ultima seccion que nos haran falta para calcular la nueva seccion.
Local $sIMAGE_SECTION_HEADER = 'CHAR name[8];DWORD virtualsize;DWORD virtualaddress;DWORD sizeofrawdata;DWORD pointertorawdata;DWORD pointertorelocations;' & _
'DWORD pointertolinenumbers;WORD numberofrelocations;WORD numberoflinenumbers;DWORD characteristics'
Local $sLastSectionStruct = DllStructCreate($sIMAGE_SECTION_HEADER, $sPointer)
Local $sLastVirtualAddress = DllStructGetData($sLastSectionStruct, 'virtualaddress')
Local $sLastVirtualSize = DllStructGetData($sLastSectionStruct, 'virtualsize')
Local $sLastPointerToRawData = DllStructGetData($sLastSectionStruct, 'pointertorawdata')
Local $sLastSizeOfRawData = DllStructGetData($sLastSectionStruct, 'sizeofrawdata')
;Sumamos 1 al numero total de secciones para añadir nuestra seccion
Local $sNewNumberOfSection = DllStructGetData($sFileHeaderStruct, 'numberofsections') + 1
DllStructSetData($sFileHeaderStruct, 'NumberOfSections', $sNewNumberOfSection)
;Sumamos 0x28 al puntero para ubicarnos al final de la ultima seccion, donde vamos a añadir la nuestra.
$sPointer += 0x28
;Creamos la estructura para nuestra nueva seccion
Local $sNewSectionStruct = DllStructCreate($sIMAGE_SECTION_HEADER, $sPointer)
;Si el nombre de la nueva seccion supera los 8 caracteres (que serian 8 bytes) solo nos quedamos con los 8 primeros caracteres.
if StringLen($sSectionName) > 8 then
$sSectionName = StringLeft($sSectionName, 8)
EndIf
;Añadimos a nuestra nueva seccion su nombre.
DllStructSetData($sNewSectionStruct, 1, $sSectionName)
;Añadimos el valor "VirtualSize" de nuestra nueva seccion, le voy a dar 0x100 por defecto
DllStructSetData($sNewSectionStruct, 2, 0x10)
;Añadimos el VirtualAddress de nuestra secccion, esta se calcula de la siguiente manera: Sumamos el VirtualSize + VirtualAddress de la seccion anterior a la nuestra
;y lo alineamos con SectionAligment
Local $sNewVirtualAddress = $sLastVirtualAddress + $sLastVirtualSize
$sNewVirtualAddress = ($sNewVirtualAddress + $sSectionAligment) - Mod($sNewVirtualAddress, $sSectionAligment)
DllStructSetData($sNewSectionStruct, 3, $sNewVirtualAddress)
;Alineamos los datos al valor de FileAligment.
Local $sNewSizeOfRawData = (0x10 + $sFileAligment) - Mod(0x10, $sFileAligment)
DllStructSetData($sNewSectionStruct, 4, $sNewSizeOfRawData)
;El PointerToRawData lo obtenemos sumando el PonterToRawData + SizeOfRawData de la seccion anterior
Local $sNewPointerToRawData = $sLastPointerToRawData + $sLastSizeOfRawData
DllStructSetData($sNewSectionStruct, 5, $sNewPointerToRawData)
;Los proximos 4 parametros de nuestra estructura no nos interesan asi que los dejamos a 0
DllStructSetData($sNewSectionStruct, 6, 0)
DllStructSetData($sNewSectionStruct, 7, 0)
DllStructSetData($sNewSectionStruct, 8, 0)
DllStructSetData($sNewSectionStruct, 9, 0)
;Por ultimo el atributo de nuestra seccion, le asignaremos los valores de lectura y escritura (C0000000)
DllStructSetData($sNewSectionStruct, 10, 0xC0000000)
;Modificamos el SizeOfImage, El resultado lo obtenermos sumando el sizeofimage + sizeofrawdata de nuestra seccion y por ultimo lo alineamos con FileAligment
Local $sNewSizeOfImage = DllStructGetData($sOptionalStruct, 'sizeofimage') + DllStructGetData($sNewSectionStruct, 'sizeofrawdata')
$sNewSizeOfImage = ($sNewSizeOfImage + $sFileAligment) - Mod($sNewSizeOfImage, $sFileAligment)
DllStructSetData($sOptionalStruct, 'sizeofimage', $sNewSizeOfImage)
;Cremaos un nuevo archivo donde escribir los nuevos datos y le añadimos bytes al final del archivo.
Local $sNewFile = FileOpen('new.exe', 17)
FileWrite($sNewFile, DllStructGetData($sFileStruct, 1))
For $i = 0 to 210
FileWrite($sNewFile, 0)
Next
FileClose($sNewFile)
MsgBox(64, 'Listo', 'Nuevo archivo creado con las secciones modificadas!')
EndIf
EndFunc
Saludos