Merge pull request #3131 from ynwarcs/virtualmod_memorymodule_support
Support for MemoryModule recognition and debugging via virtualmod.
This commit is contained in:
commit
9746dee02f
|
@ -82,7 +82,7 @@ static void ReadExportDirectory(MODINFO & Info, ULONG_PTR FileMapVA)
|
|||
// Get the export directory and its size
|
||||
ULONG exportDirSize;
|
||||
auto exportDir = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData((PVOID)FileMapVA,
|
||||
FALSE,
|
||||
Info.isVirtual,
|
||||
IMAGE_DIRECTORY_ENTRY_EXPORT,
|
||||
&exportDirSize);
|
||||
if(exportDirSize == 0 || exportDir == nullptr ||
|
||||
|
@ -97,7 +97,7 @@ static void ReadExportDirectory(MODINFO & Info, ULONG_PTR FileMapVA)
|
|||
|
||||
auto rva2offset = [&Info](ULONG64 rva)
|
||||
{
|
||||
return ModRvaToOffset(0, Info.headers, rva);
|
||||
return Info.isVirtual ? rva : ModRvaToOffset(0, Info.headers, rva);
|
||||
};
|
||||
|
||||
auto addressOfFunctionsOffset = rva2offset(exportDir->AddressOfFunctions);
|
||||
|
@ -139,7 +139,7 @@ static void ReadExportDirectory(MODINFO & Info, ULONG_PTR FileMapVA)
|
|||
auto & entry = Info.exports.back();
|
||||
entry.ordinal = i + exportDir->Base;
|
||||
entry.rva = addressOfFunctions[i];
|
||||
const auto entryVa = ModRvaToOffset(FileMapVA, Info.headers, entry.rva);
|
||||
const auto entryVa = Info.isVirtual ? entry.rva : ModRvaToOffset(FileMapVA, Info.headers, entry.rva);
|
||||
entry.forwarded = entryVa >= (ULONG64)exportDir && entryVa < (ULONG64)exportDir + exportDirSize;
|
||||
if(entry.forwarded)
|
||||
{
|
||||
|
@ -227,7 +227,7 @@ static void ReadImportDirectory(MODINFO & Info, ULONG_PTR FileMapVA)
|
|||
// Get the import directory and its size
|
||||
ULONG importDirSize;
|
||||
auto importDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData((PVOID)FileMapVA,
|
||||
FALSE,
|
||||
Info.isVirtual,
|
||||
IMAGE_DIRECTORY_ENTRY_IMPORT,
|
||||
&importDirSize);
|
||||
if(importDirSize == 0 || importDescriptor == nullptr ||
|
||||
|
@ -238,7 +238,7 @@ static void ReadImportDirectory(MODINFO & Info, ULONG_PTR FileMapVA)
|
|||
const ULONG64 ordinalFlag = IMAGE64(Info.headers) ? IMAGE_ORDINAL_FLAG64 : IMAGE_ORDINAL_FLAG32;
|
||||
auto rva2offset = [&Info](ULONG64 rva)
|
||||
{
|
||||
return ModRvaToOffset(0, Info.headers, rva);
|
||||
return Info.isVirtual ? rva : ModRvaToOffset(0, Info.headers, rva);
|
||||
};
|
||||
|
||||
for(size_t moduleIndex = 0; importDescriptor->Name != 0; ++importDescriptor, ++moduleIndex)
|
||||
|
@ -325,7 +325,7 @@ static void ReadTlsCallbacks(MODINFO & Info, ULONG_PTR FileMapVA)
|
|||
// Get the TLS directory
|
||||
ULONG tlsDirSize;
|
||||
auto tlsDir = (PIMAGE_TLS_DIRECTORY)RtlImageDirectoryEntryToData((PVOID)FileMapVA,
|
||||
FALSE,
|
||||
Info.isVirtual,
|
||||
IMAGE_DIRECTORY_ENTRY_TLS,
|
||||
&tlsDirSize);
|
||||
if(tlsDir == nullptr /*|| tlsDirSize == 0*/ || // The loader completely ignores the directory size. Setting it to 0 is an anti-debug trick
|
||||
|
@ -340,7 +340,8 @@ static void ReadTlsCallbacks(MODINFO & Info, ULONG_PTR FileMapVA)
|
|||
return;
|
||||
|
||||
auto imageBase = HEADER_FIELD(Info.headers, ImageBase);
|
||||
auto tlsArrayOffset = ModRvaToOffset(0, Info.headers, tlsDir->AddressOfCallBacks - imageBase);
|
||||
auto rva = tlsDir->AddressOfCallBacks - imageBase;
|
||||
auto tlsArrayOffset = Info.isVirtual ? rva : ModRvaToOffset(0, Info.headers, rva);
|
||||
if(!tlsArrayOffset)
|
||||
return;
|
||||
|
||||
|
@ -370,7 +371,7 @@ static void ReadBaseRelocationTable(MODINFO & Info, ULONG_PTR FileMapVA)
|
|||
// Get address and size of base relocation table
|
||||
ULONG totalBytes;
|
||||
auto baseRelocBlock = (PIMAGE_BASE_RELOCATION)RtlImageDirectoryEntryToData((PVOID)FileMapVA,
|
||||
FALSE,
|
||||
Info.isVirtual,
|
||||
IMAGE_DIRECTORY_ENTRY_BASERELOC,
|
||||
&totalBytes);
|
||||
if(baseRelocBlock == nullptr || totalBytes == 0 ||
|
||||
|
@ -442,7 +443,7 @@ static void ReadDebugDirectory(MODINFO & Info, ULONG_PTR FileMapVA)
|
|||
// Get the debug directory and its size
|
||||
ULONG debugDirSize;
|
||||
auto debugDir = (PIMAGE_DEBUG_DIRECTORY)RtlImageDirectoryEntryToData((PVOID)FileMapVA,
|
||||
FALSE,
|
||||
Info.isVirtual,
|
||||
IMAGE_DIRECTORY_ENTRY_DEBUG,
|
||||
&debugDirSize);
|
||||
if(debugDirSize == 0 || debugDir == nullptr ||
|
||||
|
@ -474,12 +475,12 @@ static void ReadDebugDirectory(MODINFO & Info, ULONG_PTR FileMapVA)
|
|||
BYTE PdbFileName[1];
|
||||
};
|
||||
|
||||
const auto supported = [&Info](PIMAGE_DEBUG_DIRECTORY entry)
|
||||
const auto supported = [&Info, FileMapVA](PIMAGE_DEBUG_DIRECTORY entry)
|
||||
{
|
||||
// Check for valid RVA
|
||||
ULONG_PTR offset = 0;
|
||||
if(entry->AddressOfRawData)
|
||||
offset = (ULONG_PTR)ModRvaToOffset(0, Info.headers, entry->AddressOfRawData);
|
||||
offset = Info.isVirtual ? entry->AddressOfRawData : (ULONG_PTR)ModRvaToOffset(0, Info.headers, entry->AddressOfRawData);
|
||||
else if(entry->PointerToRawData)
|
||||
offset = entry->PointerToRawData;
|
||||
if(!offset)
|
||||
|
@ -494,7 +495,7 @@ static void ReadDebugDirectory(MODINFO & Info, ULONG_PTR FileMapVA)
|
|||
if(entry->Type == IMAGE_DEBUG_TYPE_CODEVIEW) // TODO: support other types (DBG)?
|
||||
{
|
||||
// Get the CV signature and do a final size check if it is valid
|
||||
auto signature = *(DWORD*)(Info.fileMapVA + offset);
|
||||
auto signature = *(DWORD*)(FileMapVA + offset);
|
||||
if(signature == '01BN')
|
||||
return entry->SizeOfData >= sizeof(CV_INFO_PDB20) && entry->SizeOfData < sizeof(CV_INFO_PDB20) + DOS_MAX_PATH_LENGTH;
|
||||
else if(signature == 'SDSR')
|
||||
|
@ -576,7 +577,7 @@ static void ReadDebugDirectory(MODINFO & Info, ULONG_PTR FileMapVA)
|
|||
// At this point we know the entry is a valid CV one
|
||||
ULONG_PTR offset = 0;
|
||||
if(entry->AddressOfRawData)
|
||||
offset = (ULONG_PTR)ModRvaToOffset(0, Info.headers, entry->AddressOfRawData);
|
||||
offset = Info.isVirtual ? entry->AddressOfRawData : (ULONG_PTR)ModRvaToOffset(0, Info.headers, entry->AddressOfRawData);
|
||||
else if(entry->PointerToRawData)
|
||||
offset = entry->PointerToRawData;
|
||||
auto cvData = (unsigned char*)(FileMapVA + offset);
|
||||
|
@ -667,7 +668,7 @@ static void ReadExceptionDirectory(MODINFO & Info, ULONG_PTR FileMapVA)
|
|||
// Get address and size of exception directory
|
||||
ULONG totalBytes;
|
||||
auto baseRuntimeFunctions = (PRUNTIME_FUNCTION)RtlImageDirectoryEntryToData((PVOID)FileMapVA,
|
||||
FALSE,
|
||||
Info.isVirtual,
|
||||
IMAGE_DIRECTORY_ENTRY_EXCEPTION,
|
||||
&totalBytes);
|
||||
if(baseRuntimeFunctions == nullptr || totalBytes == 0 ||
|
||||
|
@ -854,9 +855,9 @@ bool ModLoad(duint Base, duint Size, const char* FullPath, bool loadSymbols)
|
|||
}
|
||||
|
||||
// Load module data
|
||||
bool virtualModule = strstr(FullPath, "virtual:\\") == FullPath;
|
||||
info.isVirtual = strstr(FullPath, "virtual:\\") == FullPath;
|
||||
|
||||
if(!virtualModule)
|
||||
if(!info.isVirtual)
|
||||
{
|
||||
auto wszFullPath = StringUtils::Utf8ToUtf16(FullPath);
|
||||
|
||||
|
@ -879,12 +880,13 @@ bool ModLoad(duint Base, duint Size, const char* FullPath, bool loadSymbols)
|
|||
else
|
||||
{
|
||||
// This was a virtual module -> read it remotely
|
||||
Memory<unsigned char*> data(Size);
|
||||
MemRead(Base, data(), data.size());
|
||||
info.mappedData.realloc(Size);
|
||||
MemRead(Base, info.mappedData(), info.mappedData.size());
|
||||
|
||||
// Get information from the local buffer
|
||||
// TODO: this does not properly work for file offset -> rva conversions (since virtual modules are SEC_IMAGE)
|
||||
GetModuleInfo(info, (ULONG_PTR)data());
|
||||
info.loadedSize = Size;
|
||||
GetModuleInfo(info, (ULONG_PTR)info.mappedData());
|
||||
}
|
||||
|
||||
info.symbols = &EmptySymbolSource; // empty symbol source per default
|
||||
|
@ -904,7 +906,7 @@ bool ModLoad(duint Base, duint Size, const char* FullPath, bool loadSymbols)
|
|||
EXCLUSIVE_RELEASE();
|
||||
|
||||
// Put labels for virtual module exports
|
||||
if(virtualModule)
|
||||
if(info.isVirtual)
|
||||
{
|
||||
if(info.entry >= Base && info.entry < Base + Size)
|
||||
LabelSet(info.entry, "EntryPoint", false, true);
|
||||
|
|
|
@ -119,6 +119,8 @@ struct MODINFO
|
|||
ULONG_PTR fileMapVA = 0;
|
||||
|
||||
MODULEPARTY party; // Party. Currently used value: 0: User, 1: System
|
||||
bool isVirtual = false;
|
||||
Memory<unsigned char*> mappedData;
|
||||
|
||||
MODINFO()
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue