Cache copy of library on first symbol/signature lookup (#1642)

Always perform signature searches on an unaltered copy of the binary. This avoids signature mismatches if the same function is detoured twice and thus the first bytes of the function were replaced by the detour.
This commit is contained in:
peace-maker 2021-11-18 17:55:32 +01:00 committed by Your Name
parent 77a0fb4402
commit 1f561b54f3
2 changed files with 57 additions and 29 deletions

View File

@ -49,6 +49,7 @@ MemoryUtils g_MemUtils;
MemoryUtils::MemoryUtils() MemoryUtils::MemoryUtils()
{ {
m_InfoMap.init();
#ifdef PLATFORM_APPLE #ifdef PLATFORM_APPLE
task_dyld_info_data_t dyld_info; task_dyld_info_data_t dyld_info;
@ -77,20 +78,19 @@ void MemoryUtils::OnSourceModAllInitialized()
void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t len) void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t len)
{ {
DynLibInfo lib; const DynLibInfo* lib = nullptr;
bool found;
char *ptr, *end;
memset(&lib, 0, sizeof(DynLibInfo)); if ((lib = GetLibraryInfo(libPtr)) == nullptr)
if (!GetLibraryInfo(libPtr, lib))
{ {
return NULL; return NULL;
} }
ptr = reinterpret_cast<char *>(lib.baseAddress); // Search in the original unaltered state of the binary.
end = ptr + lib.memorySize - len; char *start = lib->originalCopy.get();
char *ptr = start;
char *end = ptr + lib->memorySize - len;
bool found;
while (ptr < end) while (ptr < end)
{ {
found = true; found = true;
@ -103,8 +103,9 @@ void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t l
} }
} }
// Translate the found offset into the actual live binary memory space.
if (found) if (found)
return ptr; return reinterpret_cast<char *>(lib->baseAddress) + (ptr - start);
ptr++; ptr++;
} }
@ -116,6 +117,8 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
{ {
#ifdef PLATFORM_WINDOWS #ifdef PLATFORM_WINDOWS
/* Add this this library into the cache */
GetLibraryInfo(handle);
return GetProcAddress((HMODULE)handle, symbol); return GetProcAddress((HMODULE)handle, symbol);
#elif defined PLATFORM_LINUX #elif defined PLATFORM_LINUX
@ -162,6 +165,9 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
} }
} }
/* Add this this library into the cache */
GetLibraryInfo((void *)dlmap->l_addr);
/* If we don't have a symbol table for this library, then create one */ /* If we don't have a symbol table for this library, then create one */
if (table == NULL) if (table == NULL)
{ {
@ -326,6 +332,9 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
return NULL; return NULL;
} }
/* Add this this library into the cache */
GetLibraryInfo((void *)dlbase);
/* See if we already have a symbol table for this library */ /* See if we already have a symbol table for this library */
for (size_t i = 0; i < m_SymTables.size(); i++) for (size_t i = 0; i < m_SymTables.size(); i++)
{ {
@ -429,15 +438,17 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
#endif #endif
} }
bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib) const DynLibInfo *MemoryUtils::GetLibraryInfo(const void *libPtr)
{ {
uintptr_t baseAddr; uintptr_t baseAddr;
if (libPtr == NULL) if (libPtr == NULL)
{ {
return false; return nullptr;
} }
DynLibInfo lib;
#ifdef PLATFORM_WINDOWS #ifdef PLATFORM_WINDOWS
#ifdef PLATFORM_X86 #ifdef PLATFORM_X86
@ -456,7 +467,7 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION))) if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION)))
{ {
return false; return nullptr;
} }
baseAddr = reinterpret_cast<uintptr_t>(info.AllocationBase); baseAddr = reinterpret_cast<uintptr_t>(info.AllocationBase);
@ -470,19 +481,19 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
/* Check PE magic and signature */ /* Check PE magic and signature */
if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != PE_NT_OPTIONAL_HDR_MAGIC) if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != PE_NT_OPTIONAL_HDR_MAGIC)
{ {
return false; return nullptr;
} }
/* Check architecture */ /* Check architecture */
if (file->Machine != PE_FILE_MACHINE) if (file->Machine != PE_FILE_MACHINE)
{ {
return false; return nullptr;
} }
/* For our purposes, this must be a dynamic library */ /* For our purposes, this must be a dynamic library */
if ((file->Characteristics & IMAGE_FILE_DLL) == 0) if ((file->Characteristics & IMAGE_FILE_DLL) == 0)
{ {
return false; return nullptr;
} }
/* Finally, we can do this */ /* Finally, we can do this */
@ -509,12 +520,12 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
if (!dladdr(libPtr, &info)) if (!dladdr(libPtr, &info))
{ {
return false; return nullptr;
} }
if (!info.dli_fbase || !info.dli_fname) if (!info.dli_fbase || !info.dli_fname)
{ {
return false; return nullptr;
} }
/* This is for our insane sanity checks :o */ /* This is for our insane sanity checks :o */
@ -524,31 +535,31 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
/* Check ELF magic */ /* Check ELF magic */
if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0) if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0)
{ {
return false; return nullptr;
} }
/* Check ELF version */ /* Check ELF version */
if (file->e_ident[EI_VERSION] != EV_CURRENT) if (file->e_ident[EI_VERSION] != EV_CURRENT)
{ {
return false; return nullptr;
} }
/* Check ELF endianness */ /* Check ELF endianness */
if (file->e_ident[EI_DATA] != ELFDATA2LSB) if (file->e_ident[EI_DATA] != ELFDATA2LSB)
{ {
return false; return nullptr;
} }
/* Check ELF architecture */ /* Check ELF architecture */
if (file->e_ident[EI_CLASS] != ELF_CLASS || file->e_machine != ELF_MACHINE) if (file->e_ident[EI_CLASS] != ELF_CLASS || file->e_machine != ELF_MACHINE)
{ {
return false; return nullptr;
} }
/* For our purposes, this must be a dynamic library/shared object */ /* For our purposes, this must be a dynamic library/shared object */
if (file->e_type != ET_DYN) if (file->e_type != ET_DYN)
{ {
return false; return nullptr;
} }
phdrCount = file->e_phnum; phdrCount = file->e_phnum;
@ -598,12 +609,12 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
if (!dladdr(libPtr, &info)) if (!dladdr(libPtr, &info))
{ {
return false; return nullptr;
} }
if (!info.dli_fbase || !info.dli_fname) if (!info.dli_fbase || !info.dli_fname)
{ {
return false; return nullptr;
} }
/* This is for our insane sanity checks :o */ /* This is for our insane sanity checks :o */
@ -613,19 +624,19 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
/* Check Mach-O magic */ /* Check Mach-O magic */
if (file->magic != MACH_MAGIC) if (file->magic != MACH_MAGIC)
{ {
return false; return nullptr;
} }
/* Check architecture */ /* Check architecture */
if (file->cputype != MACH_CPU_TYPE || file->cpusubtype != MACH_CPU_SUBTYPE) if (file->cputype != MACH_CPU_TYPE || file->cpusubtype != MACH_CPU_SUBTYPE)
{ {
return false; return nullptr;
} }
/* For our purposes, this must be a dynamic library */ /* For our purposes, this must be a dynamic library */
if (file->filetype != MH_DYLIB) if (file->filetype != MH_DYLIB)
{ {
return false; return nullptr;
} }
cmd_count = file->ncmds; cmd_count = file->ncmds;
@ -646,5 +657,17 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
lib.baseAddress = reinterpret_cast<void *>(baseAddr); lib.baseAddress = reinterpret_cast<void *>(baseAddr);
return true; LibraryInfoMap::Insert i = m_InfoMap.findForAdd(lib.baseAddress);
if (i.found())
{
// We already loaded this binary before.
return &i->value;
}
// Keep a copy of the binary in its initial unpatched state for lookup.
lib.originalCopy = std::make_unique<char[]>(lib.memorySize);
memcpy(lib.originalCopy.get(), lib.baseAddress, lib.memorySize);
m_InfoMap.add(i, lib.baseAddress, std::move(lib));
return &i->value;
} }

View File

@ -32,6 +32,8 @@
#include "common_logic.h" #include "common_logic.h"
#include <IMemoryUtils.h> #include <IMemoryUtils.h>
#include <am-hashmap.h>
#include <memory>
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE #if defined PLATFORM_LINUX || defined PLATFORM_APPLE
#include <sh_vector.h> #include <sh_vector.h>
#include "sm_symtable.h" #include "sm_symtable.h"
@ -49,6 +51,7 @@ struct DynLibInfo
{ {
void *baseAddress; void *baseAddress;
size_t memorySize; size_t memorySize;
std::unique_ptr<char[]> originalCopy;
}; };
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE #if defined PLATFORM_LINUX || defined PLATFORM_APPLE
@ -73,7 +76,7 @@ public: // IMemoryUtils
void *FindPattern(const void *libPtr, const char *pattern, size_t len); void *FindPattern(const void *libPtr, const char *pattern, size_t len);
void *ResolveSymbol(void *handle, const char *symbol); void *ResolveSymbol(void *handle, const char *symbol);
public: public:
bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib); const DynLibInfo *GetLibraryInfo(const void *libPtr);
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE #if defined PLATFORM_LINUX || defined PLATFORM_APPLE
private: private:
CVector<LibSymbolTable *> m_SymTables; CVector<LibSymbolTable *> m_SymTables;
@ -83,6 +86,8 @@ private:
SInt32 m_OSXMinor; SInt32 m_OSXMinor;
#endif #endif
#endif #endif
typedef ke::HashMap<void *, DynLibInfo, ke::PointerPolicy<void> > LibraryInfoMap;
LibraryInfoMap m_InfoMap;
}; };
extern MemoryUtils g_MemUtils; extern MemoryUtils g_MemUtils;