//===============================================================================================// // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, are permitted // provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, this list of // conditions and the following disclaimer. // // * Redistributions in binary form must reproduce the above copyright notice, this list of // conditions and the following disclaimer in the documentation and/or other materials provided // with the distribution. // // * Neither the name of Harmony Security nor the names of its contributors may be used to // endorse or promote products derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. //===============================================================================================// #include "LoadLibraryR.h" #include //===============================================================================================// DWORD Rva2Offset( DWORD dwRva, UINT_PTR uiBaseAddress, BOOL is64 ) { WORD wIndex = 0; PIMAGE_SECTION_HEADER pSectionHeader = NULL; PIMAGE_NT_HEADERS32 pNtHeaders32 = NULL; PIMAGE_NT_HEADERS64 pNtHeaders64 = NULL; if (is64) { pNtHeaders64 = (PIMAGE_NT_HEADERS64)(uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew); pSectionHeader = (PIMAGE_SECTION_HEADER)((UINT_PTR)(&pNtHeaders64->OptionalHeader) + pNtHeaders64->FileHeader.SizeOfOptionalHeader); if( dwRva < pSectionHeader[0].PointerToRawData ) return dwRva; for( wIndex=0 ; wIndex < pNtHeaders64->FileHeader.NumberOfSections ; wIndex++ ) { if( dwRva >= pSectionHeader[wIndex].VirtualAddress && dwRva < (pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].SizeOfRawData) ) return ( dwRva - pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].PointerToRawData ); } } else { pNtHeaders32 = (PIMAGE_NT_HEADERS32)(uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew); pSectionHeader = (PIMAGE_SECTION_HEADER)((UINT_PTR)(&pNtHeaders32->OptionalHeader) + pNtHeaders32->FileHeader.SizeOfOptionalHeader); if( dwRva < pSectionHeader[0].PointerToRawData ) return dwRva; for( wIndex=0 ; wIndex < pNtHeaders32->FileHeader.NumberOfSections ; wIndex++ ) { if( dwRva >= pSectionHeader[wIndex].VirtualAddress && dwRva < (pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].SizeOfRawData) ) return ( dwRva - pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].PointerToRawData ); } } return 0; } //===============================================================================================// DWORD GetReflectiveLoaderOffset( VOID * lpReflectiveDllBuffer ) { UINT_PTR uiBaseAddress = 0; UINT_PTR uiExportDir = 0; UINT_PTR uiNameArray = 0; UINT_PTR uiAddressArray = 0; UINT_PTR uiNameOrdinals = 0; DWORD dwCounter = 0; BOOL is64 = 0; uiBaseAddress = (UINT_PTR)lpReflectiveDllBuffer; // get the File Offset of the modules NT Header uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; // process a PE file based on its architecture if( ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.Magic == 0x010B ) // PE32 { is64 = FALSE; // uiNameArray = the address of the modules export directory entry uiNameArray = (UINT_PTR)&((PIMAGE_NT_HEADERS32)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; } else if( ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.Magic == 0x020B ) // PE64 { is64 = TRUE; // uiNameArray = the address of the modules export directory entry uiNameArray = (UINT_PTR)&((PIMAGE_NT_HEADERS64)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; } else { return 0; } // get the File Offset of the export directory uiExportDir = uiBaseAddress + Rva2Offset( ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress, uiBaseAddress, is64 ); // get the File Offset for the array of name pointers uiNameArray = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames, uiBaseAddress, is64 ); // get the File Offset for the array of addresses uiAddressArray = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions, uiBaseAddress, is64 ); // get the File Offset for the array of name ordinals uiNameOrdinals = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals, uiBaseAddress, is64 ); // get a counter for the number of exported functions... dwCounter = ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->NumberOfNames; // loop through all the exported functions to find the ReflectiveLoader while( dwCounter-- ) { char * cpExportedFunctionName = (char *)(uiBaseAddress + Rva2Offset( DEREF_32( uiNameArray ), uiBaseAddress, is64 )); if( strstr( cpExportedFunctionName, "ReflectiveLoader" ) != NULL ) { // get the File Offset for the array of addresses uiAddressArray = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions, uiBaseAddress, is64 ); // use the functions name ordinal as an index into the array of name pointers uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); // return the File Offset to the ReflectiveLoader() functions code... return Rva2Offset( DEREF_32( uiAddressArray ), uiBaseAddress, is64 ); } // get the next exported function name uiNameArray += sizeof(DWORD); // get the next exported function name ordinal uiNameOrdinals += sizeof(WORD); } return 0; } //===============================================================================================// // Loads a DLL image from memory via its exported ReflectiveLoader function HMODULE WINAPI LoadLibraryR( LPVOID lpBuffer, DWORD dwLength ) { HMODULE hResult = NULL; DWORD dwReflectiveLoaderOffset = 0; DWORD dwOldProtect1 = 0; DWORD dwOldProtect2 = 0; REFLECTIVELOADER pReflectiveLoader = NULL; DLLMAIN pDllMain = NULL; if( lpBuffer == NULL || dwLength == 0 ) return NULL; __try { // check if the library has a ReflectiveLoader... dwReflectiveLoaderOffset = GetReflectiveLoaderOffset( lpBuffer ); if( dwReflectiveLoaderOffset != 0 ) { pReflectiveLoader = (REFLECTIVELOADER)((UINT_PTR)lpBuffer + dwReflectiveLoaderOffset); // we must VirtualProtect the buffer to RWX so we can execute the ReflectiveLoader... // this assumes lpBuffer is the base address of the region of pages and dwLength the size of the region if( VirtualProtect( lpBuffer, dwLength, PAGE_EXECUTE_READWRITE, &dwOldProtect1 ) ) { // call the librarys ReflectiveLoader... pDllMain = (DLLMAIN)pReflectiveLoader(); if( pDllMain != NULL ) { // call the loaded librarys DllMain to get its HMODULE if( !pDllMain( NULL, DLL_QUERY_HMODULE, &hResult ) ) hResult = NULL; } // revert to the previous protection flags... VirtualProtect( lpBuffer, dwLength, dwOldProtect1, &dwOldProtect2 ); } } } __except( EXCEPTION_EXECUTE_HANDLER ) { hResult = NULL; } return hResult; } //===============================================================================================// // Loads a PE image from memory into the address space of a host process via the image's exported ReflectiveLoader function // Note: You must compile whatever you are injecting with REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR // defined in order to use the correct RDI prototypes. // Note: The hProcess handle must have these access rights: PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | // PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ // Note: If you are passing in an lpParameter value, if it is a pointer, remember it is for a different address space. // Note: This function currently cant inject accross architectures, but only to architectures which are the // same as the arch this function is compiled as, e.g. x86->x86 and x64->x64 but not x64->x86 or x86->x64. HANDLE WINAPI LoadRemoteLibraryR( HANDLE hProcess, LPVOID lpBuffer, DWORD dwLength, LPVOID lpParameter ) { BOOL bSuccess = FALSE; LPVOID lpRemoteLibraryBuffer = NULL; LPTHREAD_START_ROUTINE lpReflectiveLoader = NULL; HANDLE hThread = NULL; DWORD dwReflectiveLoaderOffset = 0; DWORD dwThreadId = 0; __try { do { if( !hProcess || !lpBuffer || !dwLength ) break; // check if the library has a ReflectiveLoader... dwReflectiveLoaderOffset = GetReflectiveLoaderOffset( lpBuffer ); if( !dwReflectiveLoaderOffset ) break; // alloc memory (RWX) in the host process for the image... lpRemoteLibraryBuffer = VirtualAllocEx( hProcess, NULL, dwLength, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); if( !lpRemoteLibraryBuffer ) break; // write the image into the host process... if( !WriteProcessMemory( hProcess, lpRemoteLibraryBuffer, lpBuffer, dwLength, NULL ) ) break; // add the offset to ReflectiveLoader() to the remote library address... lpReflectiveLoader = (LPTHREAD_START_ROUTINE)( (ULONG_PTR)lpRemoteLibraryBuffer + dwReflectiveLoaderOffset ); // create a remote thread in the host process to call the ReflectiveLoader! hThread = CreateRemoteThread( hProcess, NULL, 1024*1024, lpReflectiveLoader, lpParameter, (DWORD)NULL, &dwThreadId ); } while( 0 ); } __except( EXCEPTION_EXECUTE_HANDLER ) { hThread = NULL; } return hThread; } //===============================================================================================//