initial commit
This commit is contained in:
+256
@@ -0,0 +1,256 @@
|
||||
// reflective_loader.c
|
||||
// v0.14.2 (c) Alexander 'xaitax' Hagenah
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
|
||||
#include <windows.h>
|
||||
#include "reflective_loader.h"
|
||||
|
||||
#pragma intrinsic(_ReturnAddress)
|
||||
#pragma intrinsic(_rotr)
|
||||
|
||||
static DWORD ror_dword_loader(DWORD d)
|
||||
{
|
||||
return _rotr(d, HASH_KEY);
|
||||
}
|
||||
|
||||
static DWORD hash_string_loader(char *c)
|
||||
{
|
||||
DWORD h = 0;
|
||||
do
|
||||
{
|
||||
h = ror_dword_loader(h);
|
||||
h += *c;
|
||||
} while (*++c);
|
||||
return h;
|
||||
}
|
||||
|
||||
__declspec(noinline) ULONG_PTR GetIp(VOID)
|
||||
{
|
||||
return (ULONG_PTR)_ReturnAddress();
|
||||
}
|
||||
|
||||
DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(LPVOID lpLoaderParameter)
|
||||
{
|
||||
LOADLIBRARYA_FN fnLoadLibraryA = NULL;
|
||||
GETPROCADDRESS_FN fnGetProcAddress = NULL;
|
||||
VIRTUALALLOC_FN fnVirtualAlloc = NULL;
|
||||
NTFLUSHINSTRUCTIONCACHE_FN fnNtFlushInstructionCache = NULL;
|
||||
|
||||
ULONG_PTR uiDllBase;
|
||||
ULONG_PTR uiPeb;
|
||||
ULONG_PTR uiKernel32Base = 0;
|
||||
ULONG_PTR uiNtdllBase = 0;
|
||||
|
||||
PIMAGE_NT_HEADERS pNtHeaders_current;
|
||||
PIMAGE_DOS_HEADER pDosHeader_current;
|
||||
|
||||
uiDllBase = GetIp();
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
pDosHeader_current = (PIMAGE_DOS_HEADER)uiDllBase;
|
||||
if (pDosHeader_current->e_magic == IMAGE_DOS_SIGNATURE)
|
||||
{
|
||||
pNtHeaders_current = (PIMAGE_NT_HEADERS)(uiDllBase + pDosHeader_current->e_lfanew);
|
||||
if (pNtHeaders_current->Signature == IMAGE_NT_SIGNATURE)
|
||||
break;
|
||||
}
|
||||
uiDllBase--;
|
||||
}
|
||||
|
||||
#if defined(_M_X64)
|
||||
uiPeb = __readgsqword(0x60);
|
||||
#elif defined(_M_ARM64)
|
||||
uiPeb = __readx18qword(0x60);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
PPEB_LDR_DATA_LDR pLdr = ((PPEB_LDR)uiPeb)->Ldr;
|
||||
PLIST_ENTRY pModuleList = &(pLdr->InMemoryOrderModuleList);
|
||||
PLIST_ENTRY pCurrentEntry = pModuleList->Flink;
|
||||
|
||||
while (pCurrentEntry != pModuleList && (!uiKernel32Base || !uiNtdllBase))
|
||||
{
|
||||
PLDR_DATA_TABLE_ENTRY_LDR pEntry = (PLDR_DATA_TABLE_ENTRY_LDR)CONTAINING_RECORD(pCurrentEntry, LDR_DATA_TABLE_ENTRY_LDR, InMemoryOrderLinks);
|
||||
if (pEntry->BaseDllName.Length > 0 && pEntry->BaseDllName.Buffer != NULL)
|
||||
{
|
||||
DWORD dwModuleHash = 0;
|
||||
USHORT usCounter = pEntry->BaseDllName.Length;
|
||||
BYTE *pNameByte = (BYTE *)pEntry->BaseDllName.Buffer;
|
||||
|
||||
do
|
||||
{
|
||||
dwModuleHash = ror_dword_loader(dwModuleHash);
|
||||
if (*pNameByte >= 'a' && *pNameByte <= 'z')
|
||||
{
|
||||
dwModuleHash += (*pNameByte - 0x20);
|
||||
}
|
||||
else
|
||||
{
|
||||
dwModuleHash += *pNameByte;
|
||||
}
|
||||
pNameByte++;
|
||||
} while (--usCounter);
|
||||
|
||||
if (dwModuleHash == KERNEL32DLL_HASH)
|
||||
{
|
||||
uiKernel32Base = (ULONG_PTR)pEntry->DllBase;
|
||||
}
|
||||
else if (dwModuleHash == NTDLLDLL_HASH)
|
||||
{
|
||||
uiNtdllBase = (ULONG_PTR)pEntry->DllBase;
|
||||
}
|
||||
}
|
||||
pCurrentEntry = pCurrentEntry->Flink;
|
||||
}
|
||||
|
||||
if (!uiKernel32Base || !uiNtdllBase)
|
||||
return 0;
|
||||
|
||||
PIMAGE_DOS_HEADER pDosKernel32 = (PIMAGE_DOS_HEADER)uiKernel32Base;
|
||||
PIMAGE_NT_HEADERS pNtKernel32 = (PIMAGE_NT_HEADERS)(uiKernel32Base + pDosKernel32->e_lfanew);
|
||||
ULONG_PTR uiExportDirK32 = uiKernel32Base + pNtKernel32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
||||
PIMAGE_EXPORT_DIRECTORY pExportDirK32 = (PIMAGE_EXPORT_DIRECTORY)uiExportDirK32;
|
||||
|
||||
ULONG_PTR uiAddressOfNamesK32 = uiKernel32Base + pExportDirK32->AddressOfNames;
|
||||
ULONG_PTR uiAddressOfFunctionsK32 = uiKernel32Base + pExportDirK32->AddressOfFunctions;
|
||||
ULONG_PTR uiAddressOfNameOrdinalsK32 = uiKernel32Base + pExportDirK32->AddressOfNameOrdinals;
|
||||
|
||||
for (DWORD i = 0; i < pExportDirK32->NumberOfNames; i++)
|
||||
{
|
||||
char *sName = (char *)(uiKernel32Base + ((DWORD *)uiAddressOfNamesK32)[i]);
|
||||
DWORD dwHashVal = hash_string_loader(sName);
|
||||
if (dwHashVal == LOADLIBRARYA_HASH)
|
||||
fnLoadLibraryA = (LOADLIBRARYA_FN)(uiKernel32Base + ((DWORD *)uiAddressOfFunctionsK32)[((WORD *)uiAddressOfNameOrdinalsK32)[i]]);
|
||||
else if (dwHashVal == GETPROCADDRESS_HASH)
|
||||
fnGetProcAddress = (GETPROCADDRESS_FN)(uiKernel32Base + ((DWORD *)uiAddressOfFunctionsK32)[((WORD *)uiAddressOfNameOrdinalsK32)[i]]);
|
||||
else if (dwHashVal == VIRTUALALLOC_HASH)
|
||||
fnVirtualAlloc = (VIRTUALALLOC_FN)(uiKernel32Base + ((DWORD *)uiAddressOfFunctionsK32)[((WORD *)uiAddressOfNameOrdinalsK32)[i]]);
|
||||
|
||||
if (fnLoadLibraryA && fnGetProcAddress && fnVirtualAlloc)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!fnLoadLibraryA || !fnGetProcAddress || !fnVirtualAlloc)
|
||||
return 0;
|
||||
|
||||
PIMAGE_DOS_HEADER pDosNtdll = (PIMAGE_DOS_HEADER)uiNtdllBase;
|
||||
PIMAGE_NT_HEADERS pNtNtdll = (PIMAGE_NT_HEADERS)(uiNtdllBase + pDosNtdll->e_lfanew);
|
||||
ULONG_PTR uiExportDirNtdll = uiNtdllBase + pNtNtdll->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
||||
PIMAGE_EXPORT_DIRECTORY pExportDirNtdll = (PIMAGE_EXPORT_DIRECTORY)uiExportDirNtdll;
|
||||
|
||||
ULONG_PTR uiAddressOfNamesNtdll = uiNtdllBase + pExportDirNtdll->AddressOfNames;
|
||||
ULONG_PTR uiAddressOfFunctionsNtdll = uiNtdllBase + pExportDirNtdll->AddressOfFunctions;
|
||||
ULONG_PTR uiAddressOfNameOrdinalsNtdll = uiNtdllBase + pExportDirNtdll->AddressOfNameOrdinals;
|
||||
|
||||
for (DWORD i = 0; i < pExportDirNtdll->NumberOfNames; i++)
|
||||
{
|
||||
char *sName = (char *)(uiNtdllBase + ((DWORD *)uiAddressOfNamesNtdll)[i]);
|
||||
if (hash_string_loader(sName) == NTFLUSHINSTRUCTIONCACHE_HASH)
|
||||
{
|
||||
fnNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE_FN)(uiNtdllBase + ((DWORD *)uiAddressOfFunctionsNtdll)[((WORD *)uiAddressOfNameOrdinalsNtdll)[i]]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fnNtFlushInstructionCache)
|
||||
return 0;
|
||||
|
||||
PIMAGE_NT_HEADERS pOldNtHeaders = pNtHeaders_current;
|
||||
ULONG_PTR uiNewImageBase = (ULONG_PTR)fnVirtualAlloc(NULL, pOldNtHeaders->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
if (!uiNewImageBase)
|
||||
return 0;
|
||||
|
||||
PBYTE pSourceBytes = (PBYTE)uiDllBase;
|
||||
PBYTE pDestinationBytes = (PBYTE)uiNewImageBase;
|
||||
DWORD dwBytesToCopy = pOldNtHeaders->OptionalHeader.SizeOfHeaders;
|
||||
|
||||
while (dwBytesToCopy--)
|
||||
{
|
||||
*pDestinationBytes++ = *pSourceBytes++;
|
||||
}
|
||||
|
||||
PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)&pOldNtHeaders->OptionalHeader + pOldNtHeaders->FileHeader.SizeOfOptionalHeader);
|
||||
for (WORD i = 0; i < pOldNtHeaders->FileHeader.NumberOfSections; i++)
|
||||
{
|
||||
pSourceBytes = (PBYTE)(uiDllBase + pSectionHeader[i].PointerToRawData);
|
||||
pDestinationBytes = (PBYTE)(uiNewImageBase + pSectionHeader[i].VirtualAddress);
|
||||
dwBytesToCopy = pSectionHeader[i].SizeOfRawData;
|
||||
|
||||
while (dwBytesToCopy--)
|
||||
{
|
||||
*pDestinationBytes++ = *pSourceBytes++;
|
||||
}
|
||||
}
|
||||
|
||||
ULONG_PTR uiDelta = uiNewImageBase - pOldNtHeaders->OptionalHeader.ImageBase;
|
||||
PIMAGE_DATA_DIRECTORY pRelocationData = &pOldNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
|
||||
|
||||
if (pRelocationData->Size > 0 && uiDelta != 0)
|
||||
{
|
||||
PIMAGE_BASE_RELOCATION pRelocBlock = (PIMAGE_BASE_RELOCATION)(uiNewImageBase + pRelocationData->VirtualAddress);
|
||||
while (pRelocBlock->VirtualAddress)
|
||||
{
|
||||
DWORD dwEntryCount = (pRelocBlock->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
|
||||
PIMAGE_RELOC_ENTRY pRelocEntry = (PIMAGE_RELOC_ENTRY)((ULONG_PTR)pRelocBlock + sizeof(IMAGE_BASE_RELOCATION));
|
||||
for (DWORD k = 0; k < dwEntryCount; k++)
|
||||
{
|
||||
#if defined(_M_X64) || defined(_M_ARM64)
|
||||
if (pRelocEntry[k].type == IMAGE_REL_BASED_DIR64)
|
||||
{
|
||||
*(ULONG_PTR *)(uiNewImageBase + pRelocBlock->VirtualAddress + pRelocEntry[k].offset) += uiDelta;
|
||||
}
|
||||
#else
|
||||
if (pRelocEntry[k].type == IMAGE_REL_BASED_HIGHLOW)
|
||||
{
|
||||
*(DWORD *)(uiNewImageBase + pRelocBlock->VirtualAddress + pRelocEntry[k].offset) += (DWORD)uiDelta;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
pRelocBlock = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)pRelocBlock + pRelocBlock->SizeOfBlock);
|
||||
}
|
||||
}
|
||||
|
||||
PIMAGE_DATA_DIRECTORY pImportData = &pOldNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
|
||||
if (pImportData->Size > 0)
|
||||
{
|
||||
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)(uiNewImageBase + pImportData->VirtualAddress);
|
||||
while (pImportDesc->Name)
|
||||
{
|
||||
char *sModuleName = (char *)(uiNewImageBase + pImportDesc->Name);
|
||||
HINSTANCE hModule = fnLoadLibraryA(sModuleName);
|
||||
if (hModule)
|
||||
{
|
||||
PIMAGE_THUNK_DATA pOriginalFirstThunk = (PIMAGE_THUNK_DATA)(uiNewImageBase + pImportDesc->OriginalFirstThunk);
|
||||
PIMAGE_THUNK_DATA pFirstThunk = (PIMAGE_THUNK_DATA)(uiNewImageBase + pImportDesc->FirstThunk);
|
||||
if (!pOriginalFirstThunk)
|
||||
pOriginalFirstThunk = pFirstThunk;
|
||||
|
||||
while (pOriginalFirstThunk->u1.AddressOfData)
|
||||
{
|
||||
FARPROC pfnImportedFunc;
|
||||
if (IMAGE_SNAP_BY_ORDINAL(pOriginalFirstThunk->u1.Ordinal))
|
||||
{
|
||||
pfnImportedFunc = fnGetProcAddress(hModule, (LPCSTR)(pOriginalFirstThunk->u1.Ordinal & 0xFFFF));
|
||||
}
|
||||
else
|
||||
{
|
||||
PIMAGE_IMPORT_BY_NAME pImportByName = (PIMAGE_IMPORT_BY_NAME)(uiNewImageBase + pOriginalFirstThunk->u1.AddressOfData);
|
||||
pfnImportedFunc = fnGetProcAddress(hModule, pImportByName->Name);
|
||||
}
|
||||
pFirstThunk->u1.Function = (ULONG_PTR)pfnImportedFunc;
|
||||
pOriginalFirstThunk++;
|
||||
pFirstThunk++;
|
||||
}
|
||||
}
|
||||
pImportDesc++;
|
||||
}
|
||||
}
|
||||
|
||||
DLLMAIN_FN fnDllEntry = (DLLMAIN_FN)(uiNewImageBase + pOldNtHeaders->OptionalHeader.AddressOfEntryPoint);
|
||||
fnNtFlushInstructionCache((HANDLE)-1, NULL, 0);
|
||||
fnDllEntry((HINSTANCE)uiNewImageBase, DLL_PROCESS_ATTACH, lpLoaderParameter);
|
||||
|
||||
return uiNewImageBase;
|
||||
}
|
||||
Reference in New Issue
Block a user