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:
parent
77a0fb4402
commit
1f561b54f3
@ -49,6 +49,7 @@ MemoryUtils g_MemUtils;
|
||||
|
||||
MemoryUtils::MemoryUtils()
|
||||
{
|
||||
m_InfoMap.init();
|
||||
#ifdef PLATFORM_APPLE
|
||||
|
||||
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)
|
||||
{
|
||||
DynLibInfo lib;
|
||||
bool found;
|
||||
char *ptr, *end;
|
||||
const DynLibInfo* lib = nullptr;
|
||||
|
||||
memset(&lib, 0, sizeof(DynLibInfo));
|
||||
|
||||
if (!GetLibraryInfo(libPtr, lib))
|
||||
if ((lib = GetLibraryInfo(libPtr)) == nullptr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ptr = reinterpret_cast<char *>(lib.baseAddress);
|
||||
end = ptr + lib.memorySize - len;
|
||||
// Search in the original unaltered state of the binary.
|
||||
char *start = lib->originalCopy.get();
|
||||
char *ptr = start;
|
||||
char *end = ptr + lib->memorySize - len;
|
||||
|
||||
bool found;
|
||||
while (ptr < end)
|
||||
{
|
||||
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)
|
||||
return ptr;
|
||||
return reinterpret_cast<char *>(lib->baseAddress) + (ptr - start);
|
||||
|
||||
ptr++;
|
||||
}
|
||||
@ -116,6 +117,8 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
|
||||
{
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
|
||||
/* Add this this library into the cache */
|
||||
GetLibraryInfo(handle);
|
||||
return GetProcAddress((HMODULE)handle, symbol);
|
||||
|
||||
#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 (table == NULL)
|
||||
{
|
||||
@ -326,6 +332,9 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Add this this library into the cache */
|
||||
GetLibraryInfo((void *)dlbase);
|
||||
|
||||
/* See if we already have a symbol table for this library */
|
||||
for (size_t i = 0; i < m_SymTables.size(); i++)
|
||||
{
|
||||
@ -429,15 +438,17 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
||||
const DynLibInfo *MemoryUtils::GetLibraryInfo(const void *libPtr)
|
||||
{
|
||||
uintptr_t baseAddr;
|
||||
|
||||
if (libPtr == NULL)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DynLibInfo lib;
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
|
||||
#ifdef PLATFORM_X86
|
||||
@ -456,7 +467,7 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
||||
|
||||
if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION)))
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
baseAddr = reinterpret_cast<uintptr_t>(info.AllocationBase);
|
||||
@ -470,19 +481,19 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
||||
/* Check PE magic and signature */
|
||||
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 */
|
||||
if (file->Machine != PE_FILE_MACHINE)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* For our purposes, this must be a dynamic library */
|
||||
if ((file->Characteristics & IMAGE_FILE_DLL) == 0)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Finally, we can do this */
|
||||
@ -509,12 +520,12 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
||||
|
||||
if (!dladdr(libPtr, &info))
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!info.dli_fbase || !info.dli_fname)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* This is for our insane sanity checks :o */
|
||||
@ -524,31 +535,31 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
||||
/* Check ELF magic */
|
||||
if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Check ELF version */
|
||||
if (file->e_ident[EI_VERSION] != EV_CURRENT)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Check ELF endianness */
|
||||
if (file->e_ident[EI_DATA] != ELFDATA2LSB)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Check ELF architecture */
|
||||
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 */
|
||||
if (file->e_type != ET_DYN)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
phdrCount = file->e_phnum;
|
||||
@ -598,12 +609,12 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
||||
|
||||
if (!dladdr(libPtr, &info))
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!info.dli_fbase || !info.dli_fname)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* This is for our insane sanity checks :o */
|
||||
@ -613,19 +624,19 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
||||
/* Check Mach-O magic */
|
||||
if (file->magic != MACH_MAGIC)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Check architecture */
|
||||
if (file->cputype != MACH_CPU_TYPE || file->cpusubtype != MACH_CPU_SUBTYPE)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* For our purposes, this must be a dynamic library */
|
||||
if (file->filetype != MH_DYLIB)
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
cmd_count = file->ncmds;
|
||||
@ -646,5 +657,17 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -32,6 +32,8 @@
|
||||
|
||||
#include "common_logic.h"
|
||||
#include <IMemoryUtils.h>
|
||||
#include <am-hashmap.h>
|
||||
#include <memory>
|
||||
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
||||
#include <sh_vector.h>
|
||||
#include "sm_symtable.h"
|
||||
@ -49,6 +51,7 @@ struct DynLibInfo
|
||||
{
|
||||
void *baseAddress;
|
||||
size_t memorySize;
|
||||
std::unique_ptr<char[]> originalCopy;
|
||||
};
|
||||
|
||||
#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 *ResolveSymbol(void *handle, const char *symbol);
|
||||
public:
|
||||
bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib);
|
||||
const DynLibInfo *GetLibraryInfo(const void *libPtr);
|
||||
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
|
||||
private:
|
||||
CVector<LibSymbolTable *> m_SymTables;
|
||||
@ -83,6 +86,8 @@ private:
|
||||
SInt32 m_OSXMinor;
|
||||
#endif
|
||||
#endif
|
||||
typedef ke::HashMap<void *, DynLibInfo, ke::PointerPolicy<void> > LibraryInfoMap;
|
||||
LibraryInfoMap m_InfoMap;
|
||||
};
|
||||
|
||||
extern MemoryUtils g_MemUtils;
|
||||
|
Loading…
Reference in New Issue
Block a user