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
|
// Get the export directory and its size
|
||||||
ULONG exportDirSize;
|
ULONG exportDirSize;
|
||||||
auto exportDir = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData((PVOID)FileMapVA,
|
auto exportDir = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData((PVOID)FileMapVA,
|
||||||
FALSE,
|
Info.isVirtual,
|
||||||
IMAGE_DIRECTORY_ENTRY_EXPORT,
|
IMAGE_DIRECTORY_ENTRY_EXPORT,
|
||||||
&exportDirSize);
|
&exportDirSize);
|
||||||
if(exportDirSize == 0 || exportDir == nullptr ||
|
if(exportDirSize == 0 || exportDir == nullptr ||
|
||||||
|
@ -97,7 +97,7 @@ static void ReadExportDirectory(MODINFO & Info, ULONG_PTR FileMapVA)
|
||||||
|
|
||||||
auto rva2offset = [&Info](ULONG64 rva)
|
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);
|
auto addressOfFunctionsOffset = rva2offset(exportDir->AddressOfFunctions);
|
||||||
|
@ -139,7 +139,7 @@ static void ReadExportDirectory(MODINFO & Info, ULONG_PTR FileMapVA)
|
||||||
auto & entry = Info.exports.back();
|
auto & entry = Info.exports.back();
|
||||||
entry.ordinal = i + exportDir->Base;
|
entry.ordinal = i + exportDir->Base;
|
||||||
entry.rva = addressOfFunctions[i];
|
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;
|
entry.forwarded = entryVa >= (ULONG64)exportDir && entryVa < (ULONG64)exportDir + exportDirSize;
|
||||||
if(entry.forwarded)
|
if(entry.forwarded)
|
||||||
{
|
{
|
||||||
|
@ -227,7 +227,7 @@ static void ReadImportDirectory(MODINFO & Info, ULONG_PTR FileMapVA)
|
||||||
// Get the import directory and its size
|
// Get the import directory and its size
|
||||||
ULONG importDirSize;
|
ULONG importDirSize;
|
||||||
auto importDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData((PVOID)FileMapVA,
|
auto importDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData((PVOID)FileMapVA,
|
||||||
FALSE,
|
Info.isVirtual,
|
||||||
IMAGE_DIRECTORY_ENTRY_IMPORT,
|
IMAGE_DIRECTORY_ENTRY_IMPORT,
|
||||||
&importDirSize);
|
&importDirSize);
|
||||||
if(importDirSize == 0 || importDescriptor == nullptr ||
|
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;
|
const ULONG64 ordinalFlag = IMAGE64(Info.headers) ? IMAGE_ORDINAL_FLAG64 : IMAGE_ORDINAL_FLAG32;
|
||||||
auto rva2offset = [&Info](ULONG64 rva)
|
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)
|
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
|
// Get the TLS directory
|
||||||
ULONG tlsDirSize;
|
ULONG tlsDirSize;
|
||||||
auto tlsDir = (PIMAGE_TLS_DIRECTORY)RtlImageDirectoryEntryToData((PVOID)FileMapVA,
|
auto tlsDir = (PIMAGE_TLS_DIRECTORY)RtlImageDirectoryEntryToData((PVOID)FileMapVA,
|
||||||
FALSE,
|
Info.isVirtual,
|
||||||
IMAGE_DIRECTORY_ENTRY_TLS,
|
IMAGE_DIRECTORY_ENTRY_TLS,
|
||||||
&tlsDirSize);
|
&tlsDirSize);
|
||||||
if(tlsDir == nullptr /*|| tlsDirSize == 0*/ || // The loader completely ignores the directory size. Setting it to 0 is an anti-debug trick
|
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;
|
return;
|
||||||
|
|
||||||
auto imageBase = HEADER_FIELD(Info.headers, ImageBase);
|
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)
|
if(!tlsArrayOffset)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -370,7 +371,7 @@ static void ReadBaseRelocationTable(MODINFO & Info, ULONG_PTR FileMapVA)
|
||||||
// Get address and size of base relocation table
|
// Get address and size of base relocation table
|
||||||
ULONG totalBytes;
|
ULONG totalBytes;
|
||||||
auto baseRelocBlock = (PIMAGE_BASE_RELOCATION)RtlImageDirectoryEntryToData((PVOID)FileMapVA,
|
auto baseRelocBlock = (PIMAGE_BASE_RELOCATION)RtlImageDirectoryEntryToData((PVOID)FileMapVA,
|
||||||
FALSE,
|
Info.isVirtual,
|
||||||
IMAGE_DIRECTORY_ENTRY_BASERELOC,
|
IMAGE_DIRECTORY_ENTRY_BASERELOC,
|
||||||
&totalBytes);
|
&totalBytes);
|
||||||
if(baseRelocBlock == nullptr || totalBytes == 0 ||
|
if(baseRelocBlock == nullptr || totalBytes == 0 ||
|
||||||
|
@ -442,7 +443,7 @@ static void ReadDebugDirectory(MODINFO & Info, ULONG_PTR FileMapVA)
|
||||||
// Get the debug directory and its size
|
// Get the debug directory and its size
|
||||||
ULONG debugDirSize;
|
ULONG debugDirSize;
|
||||||
auto debugDir = (PIMAGE_DEBUG_DIRECTORY)RtlImageDirectoryEntryToData((PVOID)FileMapVA,
|
auto debugDir = (PIMAGE_DEBUG_DIRECTORY)RtlImageDirectoryEntryToData((PVOID)FileMapVA,
|
||||||
FALSE,
|
Info.isVirtual,
|
||||||
IMAGE_DIRECTORY_ENTRY_DEBUG,
|
IMAGE_DIRECTORY_ENTRY_DEBUG,
|
||||||
&debugDirSize);
|
&debugDirSize);
|
||||||
if(debugDirSize == 0 || debugDir == nullptr ||
|
if(debugDirSize == 0 || debugDir == nullptr ||
|
||||||
|
@ -474,12 +475,12 @@ static void ReadDebugDirectory(MODINFO & Info, ULONG_PTR FileMapVA)
|
||||||
BYTE PdbFileName[1];
|
BYTE PdbFileName[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto supported = [&Info](PIMAGE_DEBUG_DIRECTORY entry)
|
const auto supported = [&Info, FileMapVA](PIMAGE_DEBUG_DIRECTORY entry)
|
||||||
{
|
{
|
||||||
// Check for valid RVA
|
// Check for valid RVA
|
||||||
ULONG_PTR offset = 0;
|
ULONG_PTR offset = 0;
|
||||||
if(entry->AddressOfRawData)
|
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)
|
else if(entry->PointerToRawData)
|
||||||
offset = entry->PointerToRawData;
|
offset = entry->PointerToRawData;
|
||||||
if(!offset)
|
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)?
|
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
|
// 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')
|
if(signature == '01BN')
|
||||||
return entry->SizeOfData >= sizeof(CV_INFO_PDB20) && entry->SizeOfData < sizeof(CV_INFO_PDB20) + DOS_MAX_PATH_LENGTH;
|
return entry->SizeOfData >= sizeof(CV_INFO_PDB20) && entry->SizeOfData < sizeof(CV_INFO_PDB20) + DOS_MAX_PATH_LENGTH;
|
||||||
else if(signature == 'SDSR')
|
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
|
// At this point we know the entry is a valid CV one
|
||||||
ULONG_PTR offset = 0;
|
ULONG_PTR offset = 0;
|
||||||
if(entry->AddressOfRawData)
|
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)
|
else if(entry->PointerToRawData)
|
||||||
offset = entry->PointerToRawData;
|
offset = entry->PointerToRawData;
|
||||||
auto cvData = (unsigned char*)(FileMapVA + offset);
|
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
|
// Get address and size of exception directory
|
||||||
ULONG totalBytes;
|
ULONG totalBytes;
|
||||||
auto baseRuntimeFunctions = (PRUNTIME_FUNCTION)RtlImageDirectoryEntryToData((PVOID)FileMapVA,
|
auto baseRuntimeFunctions = (PRUNTIME_FUNCTION)RtlImageDirectoryEntryToData((PVOID)FileMapVA,
|
||||||
FALSE,
|
Info.isVirtual,
|
||||||
IMAGE_DIRECTORY_ENTRY_EXCEPTION,
|
IMAGE_DIRECTORY_ENTRY_EXCEPTION,
|
||||||
&totalBytes);
|
&totalBytes);
|
||||||
if(baseRuntimeFunctions == nullptr || totalBytes == 0 ||
|
if(baseRuntimeFunctions == nullptr || totalBytes == 0 ||
|
||||||
|
@ -854,9 +855,9 @@ bool ModLoad(duint Base, duint Size, const char* FullPath, bool loadSymbols)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load module data
|
// 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);
|
auto wszFullPath = StringUtils::Utf8ToUtf16(FullPath);
|
||||||
|
|
||||||
|
@ -879,12 +880,13 @@ bool ModLoad(duint Base, duint Size, const char* FullPath, bool loadSymbols)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// This was a virtual module -> read it remotely
|
// This was a virtual module -> read it remotely
|
||||||
Memory<unsigned char*> data(Size);
|
info.mappedData.realloc(Size);
|
||||||
MemRead(Base, data(), data.size());
|
MemRead(Base, info.mappedData(), info.mappedData.size());
|
||||||
|
|
||||||
// Get information from the local buffer
|
// Get information from the local buffer
|
||||||
// TODO: this does not properly work for file offset -> rva conversions (since virtual modules are SEC_IMAGE)
|
// 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
|
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();
|
EXCLUSIVE_RELEASE();
|
||||||
|
|
||||||
// Put labels for virtual module exports
|
// Put labels for virtual module exports
|
||||||
if(virtualModule)
|
if(info.isVirtual)
|
||||||
{
|
{
|
||||||
if(info.entry >= Base && info.entry < Base + Size)
|
if(info.entry >= Base && info.entry < Base + Size)
|
||||||
LabelSet(info.entry, "EntryPoint", false, true);
|
LabelSet(info.entry, "EntryPoint", false, true);
|
||||||
|
|
|
@ -119,6 +119,8 @@ struct MODINFO
|
||||||
ULONG_PTR fileMapVA = 0;
|
ULONG_PTR fileMapVA = 0;
|
||||||
|
|
||||||
MODULEPARTY party; // Party. Currently used value: 0: User, 1: System
|
MODULEPARTY party; // Party. Currently used value: 0: User, 1: System
|
||||||
|
bool isVirtual = false;
|
||||||
|
Memory<unsigned char*> mappedData;
|
||||||
|
|
||||||
MODINFO()
|
MODINFO()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue