Skip to content

Commit

Permalink
Cache copy of library on first symbol/signature lookup (#1642)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
peace-maker committed Nov 18, 2021
1 parent 9cb693d commit 1c30b88
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 29 deletions.
79 changes: 51 additions & 28 deletions core/logic/MemoryUtils.cpp
Expand Up @@ -49,6 +49,7 @@ MemoryUtils g_MemUtils;

MemoryUtils::MemoryUtils()
{
m_InfoMap.init();
#ifdef PLATFORM_APPLE

task_dyld_info_data_t dyld_info;
Expand Down Expand Up @@ -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;

memset(&lib, 0, sizeof(DynLibInfo));
const DynLibInfo* lib = nullptr;

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;
Expand All @@ -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++;
}
Expand All @@ -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
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -325,6 +331,9 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
/* Uh oh, we couldn't find a matching handle */
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++)
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand All @@ -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 */
Expand All @@ -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 */
Expand All @@ -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;
Expand Down Expand Up @@ -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 */
Expand All @@ -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;
Expand All @@ -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;
}
7 changes: 6 additions & 1 deletion core/logic/MemoryUtils.h
Expand Up @@ -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"
Expand All @@ -49,6 +51,7 @@ struct DynLibInfo
{
void *baseAddress;
size_t memorySize;
std::unique_ptr<char[]> originalCopy;
};

#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
Expand All @@ -73,7 +76,7 @@ class MemoryUtils :
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;
Expand All @@ -83,6 +86,8 @@ class MemoryUtils :
SInt32 m_OSXMinor;
#endif
#endif
typedef ke::HashMap<void *, DynLibInfo, ke::PointerPolicy<void> > LibraryInfoMap;
LibraryInfoMap m_InfoMap;
};

extern MemoryUtils g_MemUtils;
Expand Down

0 comments on commit 1c30b88

Please sign in to comment.