1
0
Fork 0

Implement MODINFO::getProcAddress

This resolves forwards as well as API sets
This commit is contained in:
Duncan Ogilvie 2023-01-24 13:40:56 +01:00
parent d80847caae
commit e246545aae
2 changed files with 96 additions and 3 deletions

View File

@ -11,6 +11,7 @@
#include <shlwapi.h>
#include "console.h"
#include "debugger.h"
#include "value.h"
#include <memory>
#include "LLVMDemangle/LLVMDemangle.h"
@ -839,9 +840,9 @@ bool ModLoad(duint Base, duint Size, const char* FullPath, bool loadSymbols)
info.fileMapVA = 0;
// Determine whether the module is located in system
wchar_t sysdir[MAX_PATH];
GetEnvironmentVariableW(L"windir", sysdir, _countof(sysdir));
String Utf8Sysdir = StringUtils::Utf16ToUtf8(sysdir);
wchar_t szWindowsDir[MAX_PATH];
GetWindowsDirectoryW(szWindowsDir, _countof(szWindowsDir));
String Utf8Sysdir = StringUtils::Utf16ToUtf8(szWindowsDir);
Utf8Sysdir.append("\\");
if(_memicmp(Utf8Sysdir.c_str(), FullPath, Utf8Sysdir.size()) == 0)
{
@ -1356,6 +1357,97 @@ const MODEXPORT* MODINFO::findExport(duint rva) const
return nullptr;
}
static bool resolveApiSetForward(const String & originatingDll, String & forwardDll, String & forwardExport)
{
wchar_t szApiSetDllPath[MAX_PATH] = L"";
if(!GetSystemDirectoryW(szApiSetDllPath, _countof(szApiSetDllPath)))
return {};
wcsncat_s(szApiSetDllPath, L"\\downlevel\\", _TRUNCATE);
wcsncat_s(szApiSetDllPath, StringUtils::Utf8ToUtf16(forwardDll).c_str(), _TRUNCATE);
wcsncat_s(szApiSetDllPath, L".dll", _TRUNCATE);
auto ticks = GetTickCount();
// Load the physical module from disk
MODINFO info = {};
if(!StaticFileLoadW(szApiSetDllPath, UE_ACCESS_READ, false, &info.fileHandle, &info.loadedSize, &info.fileMap, &info.fileMapVA))
return false;
GetModuleInfo(info, info.fileMapVA);
NameIndex found;
if(!NameIndex::findByName(info.exportsByName, forwardExport, found, true))
return false;
const auto & foundExport = info.exports[found.index];
if(!foundExport.forwarded)
{
dputs("assertion failure, api set not forwarded");
return false;
}
const auto & forwardName = foundExport.forwardName;
auto dotIdx = forwardName.find('.');
if(dotIdx == String::npos)
return false;
forwardDll = forwardName.substr(0, dotIdx);
forwardExport = forwardName.substr(dotIdx + 1);
// Some DLLs have extra mappings: https://www.geoffchappell.com/studies/windows/win32/apisetschema/history/sets61.htm
// This is a heuristic to resolve correctly without having to implement proper APISetMap support
if(forwardDll == originatingDll)
{
// The only supported exceptional mapping is kernel32 -> kernelbase
if(_stricmp(forwardDll.c_str(), "kernel32") != 0)
return false;
forwardDll = "kernelbase";
}
return !forwardExport.empty();
}
duint MODINFO::getProcAddress(const String & exportName, int maxForwardDepth) const
{
NameIndex found;
if(!NameIndex::findByName(exportsByName, exportName, found, false))
return 0;
const auto exportInfo = &exports[found.index];
if(maxForwardDepth > 0 && exportInfo->forwarded)
{
const auto & forwardName = exportInfo->forwardName;
auto dotIdx = forwardName.find('.');
if(dotIdx == String::npos)
return 0;
auto forwardExport = forwardName.substr(dotIdx + 1);
if(forwardExport.empty())
return 0;
auto forwardDll = forwardName.substr(0, dotIdx);
auto forwardBase = ModBaseFromName(forwardDll.c_str());
if(forwardBase == 0 && _strnicmp(forwardDll.c_str(), "api-", 4) == 0 || _strnicmp(forwardDll.c_str(), "ext-", 4) == 0)
{
if(!resolveApiSetForward(name, forwardDll, forwardExport))
return 0;
forwardBase = ModBaseFromName(forwardDll.c_str());
}
auto forwardModule = ModInfoFromAddr(forwardBase);
if(forwardModule == nullptr)
return 0;
if(forwardExport[0] == '#')
{
duint ordinal = 0;
if(!convertNumber(forwardExport.c_str() + 1, ordinal, 0) || ordinal > 0xFFFF)
return 0;
auto exportIndex = ordinal - forwardModule->exportOrdinalBase;
if(exportIndex >= forwardModule->exports.size())
return 0;
return forwardModule->base + forwardModule->exports[exportIndex].rva;
}
return forwardModule->getProcAddress(forwardExport, maxForwardDepth - 1);
}
return base + exportInfo->rva;
}
void MODIMPORT::convertToGuiSymbol(duint base, SYMBOLINFO* info) const
{
info->addr = base + iatRva;

View File

@ -138,6 +138,7 @@ struct MODINFO
void unloadSymbols();
void unmapFile();
const MODEXPORT* findExport(duint rva) const;
duint getProcAddress(const String & name, int maxForwardDepth = 10) const;
};
ULONG64 ModRvaToOffset(ULONG64 base, PIMAGE_NT_HEADERS ntHeaders, ULONG64 rva);