mirror of https://github.com/x64dbg/TitanEngine
Relocate the image with No ASLR
This commit is contained in:
parent
259f1e88e3
commit
e005ba44b6
|
|
@ -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)
|
static bool HollowProcessWithoutASLR(const wchar_t* szFileName, PROCESS_INFORMATION & pi)
|
||||||
{
|
{
|
||||||
bool success = false;
|
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 (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);
|
auto expectedBase = DebugModuleImageBase == ULONG_PTR(imageBase);
|
||||||
DebugModuleImageBase = ULONG_PTR(imageBase);
|
DebugModuleImageBase = ULONG_PTR(imageBase);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue