Rewrite the logic for processing module sections in the memory map
Closes #2920
This commit is contained in:
parent
701fb40159
commit
e36f8b7402
|
|
@ -111,73 +111,136 @@ static void ProcessFileSections(std::vector<MEMPAGE> & pageVector)
|
|||
if(pageVector.empty())
|
||||
return;
|
||||
const auto pagecount = (int)pageVector.size();
|
||||
char curMod[MAX_MODULE_SIZE] = "";
|
||||
// NOTE: this iteration is backwards
|
||||
for(int i = pagecount - 1; i > -1; i--)
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
return;
|
||||
|
||||
auto & currentPage = pageVector.at(i);
|
||||
if(!currentPage.info[0] || (scmp(curMod, currentPage.info) && !bListAllPages)) //there is a module
|
||||
continue; //skip non-modules
|
||||
strcpy_s(curMod, pageVector.at(i).info);
|
||||
auto modBase = ModBaseFromName(currentPage.info);
|
||||
if(!modBase)
|
||||
continue;
|
||||
auto base = duint(currentPage.mbi.AllocationBase);
|
||||
std::vector<MODSECTIONINFO> sections;
|
||||
if(!ModSectionsFromAddr(base, §ions))
|
||||
continue;
|
||||
int SectionNumber = (int)sections.size();
|
||||
if(!SectionNumber) //no sections = skip
|
||||
continue;
|
||||
if(!bListAllPages) //normal view
|
||||
{
|
||||
// coherence check, rest of code assumes whole module resides in one region
|
||||
// in other cases module information cannot be trusted
|
||||
if(base != modBase || currentPage.mbi.RegionSize != ROUND_TO_PAGES(ModSizeFromAddr(modBase)))
|
||||
continue;
|
||||
|
||||
MEMPAGE newPage;
|
||||
//remove the current module page (page = size of module at this point) and insert the module sections
|
||||
pageVector.erase(pageVector.begin() + i); //remove the SizeOfImage page
|
||||
for(int j = SectionNumber - 1; j > -1; j--)
|
||||
{
|
||||
const auto & currentSection = sections.at(j);
|
||||
memset(&newPage, 0, sizeof(MEMPAGE));
|
||||
VirtualQueryEx(fdProcessInfo->hProcess, (LPCVOID)currentSection.addr, &newPage.mbi, sizeof(MEMORY_BASIC_INFORMATION));
|
||||
duint SectionSize = currentSection.size;
|
||||
if(SectionSize % PAGE_SIZE) //unaligned page size
|
||||
SectionSize += PAGE_SIZE - (SectionSize % PAGE_SIZE); //fix this
|
||||
if(SectionSize)
|
||||
newPage.mbi.RegionSize = SectionSize;
|
||||
sprintf_s(newPage.info, " \"%s\"", currentSection.name);
|
||||
pageVector.insert(pageVector.begin() + i, newPage);
|
||||
}
|
||||
//insert the module itself (the module header)
|
||||
memset(&newPage, 0, sizeof(MEMPAGE));
|
||||
VirtualQueryEx(fdProcessInfo->hProcess, (LPCVOID)base, &newPage.mbi, sizeof(MEMORY_BASIC_INFORMATION));
|
||||
strcpy_s(newPage.info, curMod);
|
||||
newPage.mbi.RegionSize = sections.front().addr - base;
|
||||
pageVector.insert(pageVector.begin() + i, newPage);
|
||||
}
|
||||
else //list all pages
|
||||
// Retrieve module info
|
||||
std::vector<MODSECTIONINFO> sections;
|
||||
duint sectionAlignment = 0;
|
||||
duint modSize = 0;
|
||||
duint sizeOfImage = 0;
|
||||
{
|
||||
duint start = (duint)currentPage.mbi.BaseAddress;
|
||||
duint end = start + currentPage.mbi.RegionSize;
|
||||
duint infoOffset = 0;
|
||||
// display module name in first region (useful if PE header and first section have same protection)
|
||||
if(start == modBase)
|
||||
SHARED_ACQUIRE(LockModules);
|
||||
auto modInfo = ModInfoFromAddr(modBase);
|
||||
sections = modInfo->sections;
|
||||
sectionAlignment = modInfo->headers->OptionalHeader.SectionAlignment;
|
||||
modSize = modInfo->size;
|
||||
sizeOfImage = ROUND_TO_PAGES(modInfo->headers->OptionalHeader.SizeOfImage);
|
||||
}
|
||||
|
||||
// Nothing to do if the module doesn't have sections
|
||||
if(sections.empty())
|
||||
continue;
|
||||
|
||||
// It looks like a section alignment of 0x10000 becomes PAGE_SIZE in reality
|
||||
// The rest of the space is mapped as RESERVED
|
||||
sectionAlignment = min(sectionAlignment, PAGE_SIZE);
|
||||
|
||||
auto sectionAlign = [sectionAlignment](duint value)
|
||||
{
|
||||
return (value + (sectionAlignment - 1)) & ~(sectionAlignment - 1);
|
||||
};
|
||||
|
||||
// Align the sections
|
||||
for(size_t j = 0; j < sections.size(); j++)
|
||||
{
|
||||
auto & section = sections[j];
|
||||
section.addr = sectionAlign(section.addr);
|
||||
section.size = sectionAlign(section.size);
|
||||
|
||||
// Extend the last section to SizeOfImage under the right circumstances
|
||||
if(j + 1 == sections.size() && sectionAlignment < PAGE_SIZE)
|
||||
{
|
||||
auto totalSize = section.addr + section.size;
|
||||
totalSize -= modBase;
|
||||
if(sizeOfImage > totalSize)
|
||||
section.size += sizeOfImage - totalSize;
|
||||
}
|
||||
}
|
||||
|
||||
auto pageBase = duint(currentPage.mbi.BaseAddress);
|
||||
auto pageSize = currentPage.mbi.RegionSize;
|
||||
|
||||
// Section view
|
||||
if(!bListAllPages)
|
||||
{
|
||||
std::vector<MEMPAGE> newPages;
|
||||
newPages.reserve(sections.size() + 1);
|
||||
|
||||
// Insert a page for the header if this is the header page
|
||||
if(pageBase == modBase)
|
||||
{
|
||||
MEMPAGE headerPage = {};
|
||||
VirtualQueryEx(fdProcessInfo->hProcess, (LPCVOID)modBase, &headerPage.mbi, sizeof(MEMORY_BASIC_INFORMATION));
|
||||
headerPage.mbi.RegionSize = min(sections.front().addr - modBase, pageSize);
|
||||
strcpy_s(headerPage.info, currentPage.info);
|
||||
newPages.push_back(headerPage);
|
||||
}
|
||||
|
||||
// Insert pages for the sections
|
||||
for(const auto & section : sections)
|
||||
{
|
||||
// Only insert the sections that are within the current page
|
||||
if(section.addr >= pageBase && section.addr + section.size <= pageBase + currentPage.mbi.RegionSize)
|
||||
{
|
||||
MEMPAGE sectionPage = {};
|
||||
VirtualQueryEx(fdProcessInfo->hProcess, (LPCVOID)section.addr, §ionPage.mbi, sizeof(MEMORY_BASIC_INFORMATION));
|
||||
sectionPage.mbi.BaseAddress = (PVOID)section.addr;
|
||||
sectionPage.mbi.RegionSize = section.size;
|
||||
sprintf_s(sectionPage.info, " \"%s\"", section.name);
|
||||
newPages.push_back(sectionPage);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the total size matches the new fake pages
|
||||
size_t totalSize = 0;
|
||||
for(const auto & page : newPages)
|
||||
totalSize += page.mbi.RegionSize;
|
||||
|
||||
// Replace the single module page with the sections
|
||||
// newPages should never be empty, but try to avoid data loss if it is
|
||||
if(!newPages.empty() && totalSize == pageSize)
|
||||
{
|
||||
pageVector.erase(pageVector.begin() + i); // remove the SizeOfImage page
|
||||
pageVector.insert(pageVector.begin() + i, newPages.begin(), newPages.end());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Report an error to make it easier to debug
|
||||
auto summary = StringUtils::sprintf("Error replacing page: %p[%p]\n", pageBase, pageSize);
|
||||
summary += "Sections:\n";
|
||||
for(const auto & section : sections)
|
||||
summary += StringUtils::sprintf(" \"%s\": %p[%p]\n", section.name, section.addr, section.size);
|
||||
summary += "New pages:\n";
|
||||
for(const auto & page : newPages)
|
||||
summary += StringUtils::sprintf(" \"%s\": %p[%p]\n", page.info, page.mbi.BaseAddress, page.mbi.RegionSize);
|
||||
summary += "Please report an issue!";
|
||||
GuiAddLogMessage(summary.c_str());
|
||||
strncat_s(currentPage.info, " (error, see log)", _TRUNCATE);
|
||||
}
|
||||
}
|
||||
// List all pages
|
||||
else
|
||||
{
|
||||
size_t infoOffset = 0;
|
||||
// Display module name in first region (useful if PE header and first section have same protection)
|
||||
if(pageBase == modBase)
|
||||
infoOffset = strlen(currentPage.info);
|
||||
for(duint j = 0; (j < (duint)SectionNumber) && (infoOffset + IMAGE_SIZEOF_SHORT_NAME < sizeof(currentPage.info)); j++)
|
||||
for(size_t j = 0; j < sections.size() && infoOffset + 1 < _countof(currentPage.info); j++)
|
||||
{
|
||||
const auto & currentSection = sections.at(j);
|
||||
duint secStart = currentSection.addr;
|
||||
duint SectionSize = currentSection.size;
|
||||
if(SectionSize % PAGE_SIZE) //unaligned page size
|
||||
SectionSize += PAGE_SIZE - (SectionSize % PAGE_SIZE); //fix this
|
||||
duint secEnd = secStart + SectionSize;
|
||||
if(start < secEnd && end > secStart) //the section and memory overlap
|
||||
duint sectionStart = currentSection.addr;
|
||||
duint sectionEnd = sectionStart + currentSection.size;
|
||||
// Check if the section and page overlap
|
||||
if(pageBase < sectionEnd && pageBase + pageSize > sectionStart)
|
||||
{
|
||||
if(infoOffset)
|
||||
infoOffset += _snprintf_s(currentPage.info + infoOffset, sizeof(currentPage.info) - infoOffset, _TRUNCATE, ",");
|
||||
|
|
|
|||
Loading…
Reference in New Issue