Relocate the image with No ASLR

This commit is contained in:
Duncan Ogilvie 2022-09-11 15:52:18 +02:00
parent 259f1e88e3
commit e005ba44b6
1 changed files with 112 additions and 1 deletions

View File

@ -43,6 +43,115 @@ __declspec(dllexport) void* TITCALL InitDebug(char* szFileName, char* szCommandL
}
}
static bool ProcessRelocations(char* imageCopy, ULONG_PTR imageSize, ULONG_PTR newImageBase, ULONG_PTR & oldImageBase)
{
auto pnth = RtlImageNtHeader(imageCopy);
if(pnth == nullptr)
return false;
// Put the new base in the header
oldImageBase = pnth->OptionalHeader.ImageBase;
pnth->OptionalHeader.ImageBase = newImageBase;
// Nothing to do if relocations are stripped
if(pnth->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
return true;
// Nothing to do if there are no relocations
const auto & relocDir = pnth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
if(relocDir.Size == 0 || relocDir.VirtualAddress == 0)
return true;
// Process the relocations
auto delta = newImageBase - oldImageBase;
auto relocationItr = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)imageCopy + relocDir.VirtualAddress);
auto relocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)relocationItr + relocDir.Size);
while(relocationItr < relocationEnd && relocationItr->SizeOfBlock > 0)
{
auto count = (relocationItr->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT);
auto address = (ULONG_PTR)imageCopy + relocationItr->VirtualAddress;
auto typeOffset = (PUSHORT)(relocationItr + 1);
relocationItr = LdrProcessRelocationBlock(address, (ULONG)count, typeOffset, delta);
if(relocationItr == nullptr)
return false;
}
return true;
}
static bool RelocateImage(HANDLE hProcess, PVOID imageBase, SIZE_T imageSize)
{
constexpr auto pageSize = 0x1000;
std::vector<bool> writeback(imageSize / pageSize);
// allocate a local copy of the mapped image
auto imageCopy = (char*)VirtualAlloc(0, imageSize, MEM_COMMIT, PAGE_READWRITE);
if(imageCopy == nullptr)
return false;
// read all the pages
for(size_t i = 0; i < writeback.size(); i++)
{
auto offset = i * pageSize;
SIZE_T read = 0;
if(NT_SUCCESS(NtReadVirtualMemory(hProcess, (char*)imageBase + offset, imageCopy + offset, pageSize, &read)))
writeback[i] = true;
}
// perform the actual relocations
ULONG_PTR oldImageBase = 0;
auto success = ProcessRelocations(imageCopy, imageSize, (ULONG_PTR)imageBase, oldImageBase);
// write back the pages
auto memWrite = [hProcess](PVOID ptr, LPCVOID data, SIZE_T size)
{
// Make the page writable
ULONG oldProtect = 0;
if(NT_SUCCESS(NtProtectVirtualMemory(hProcess, &ptr, &size, PAGE_READWRITE, &oldProtect)))
{
// Write the memory
SIZE_T written = 0;
if(NT_SUCCESS(NtWriteVirtualMemory(hProcess, ptr, data, size, &written)))
{
// Restore the old protection
return NT_SUCCESS(NtProtectVirtualMemory(hProcess, &ptr, &size, oldProtect, &oldProtect));
}
}
return false;
};
for(size_t i = 0; i < writeback.size(); i++)
{
if(writeback[i])
{
auto offset = pageSize * i;
if(!memWrite((char*)imageBase + offset, imageCopy + offset, pageSize))
success = false;
}
}
// Create a copy of the header at the original image base
// The kernel uses it in ZwCreateThread to get the stack size for example
if(success)
{
success = false;
auto oldPage = (LPVOID)oldImageBase;
if(VirtualAllocEx(hProcess, oldPage, pageSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE))
{
if(memWrite(oldPage, imageCopy, pageSize))
{
DWORD oldProtect = 0;
if(VirtualProtectEx(hProcess, oldPage, pageSize, PAGE_READONLY, &oldProtect))
success = true;
}
}
}
// Free the copy of the image
VirtualFree(imageCopy, imageSize, MEM_DECOMMIT);
return success;
}
static bool HollowProcessWithoutASLR(const wchar_t* szFileName, PROCESS_INFORMATION & pi)
{
bool success = false;
@ -92,7 +201,9 @@ static bool HollowProcessWithoutASLR(const wchar_t* szFileName, PROCESS_INFORMAT
}
if (status == STATUS_SUCCESS || status == STATUS_IMAGE_NOT_AT_BASE)
{
if (WriteProcessMemory(pi.hProcess, (char*)pebRegister + offsetof(PEB, ImageBaseAddress), &imageBase, sizeof(PVOID), nullptr))
auto pebOk = WriteProcessMemory(pi.hProcess, (char*)pebRegister + offsetof(PEB, ImageBaseAddress), &imageBase, sizeof(PVOID), nullptr);
auto relocatedOk = RelocateImage(pi.hProcess, imageBase, viewSize);
if (pebOk && relocatedOk)
{
auto expectedBase = DebugModuleImageBase == ULONG_PTR(imageBase);
DebugModuleImageBase = ULONG_PTR(imageBase);