发现功能,第2部分(Finding Functions, Part 2)
继续上次说的,现在我们有了签名和function的基址。在windows上,dll几乎总是不变,你可以确定的是server.dll 总是被加载在0×22000000。但在linux上则并非如此。无论哪种方式,这都是一个糟糕的设计(但它有助于程序更稳定)。
所以我们需要在内存中找到dll,幸运的是这不是太难,windows和linux都有内置的API来寻找任何给定地址的基地址。这些函数分别是
VirtualQuery()
和
dladdr()
我们知道一个总是存在于GameDll的地址么?当然!这将是GameDll的工厂: 服务器插件的gameServerFactory和 Metamod:Source插件的 SMAPI->serverFactory(false)。让我们假设我们有这个地址
void *pDllAddr
// First, we need to get the base address of the DLL in memory.
bool GetDllMemInfo(void *pAddr, unsigned char **pBaseAddr, size_t *memLength)
{
#ifdef WIN32
MEMORY_BASIC_INFORMATION mem;
if (!VirtualQuery(pAddr, &mem, sizeof(mem)))
return false;
if (*pBaseAddr)
*pBaseAddr = (unsigned char *)mem.AllocationBase;
IMAGE_DOS_HEADERS *dos = (IMAGE_DOS_HEADERS *)(mem.AllocationBase);
IMAGE_NT_HEADERS *pe = (unsigned long)dos + (unsigned long)dos->e_lfanew;
if (pe->Signature != IMAGE_NT_SIGNATURE)
return false;
if (memLength)
*memLength = (size_t)(pe->OptionalHeader.SizeOfImage);
return true;
#else
Dl_info info;
struct stat buf;
if (!dladdr(pAddr, &info))
return false;
if (!info.dli_fbase || !info.dli_fname)
return false;
if (stat(info.dli_fname, &buf) != 0)
return false;
if (pBaseAddr)
*pBaseAddr = (unsigned char *)info.dli_fbase;
if (memLength)
*memLength = buf.st_size;
return true;
#endif
}
unsigned char *base;
size_t len;
bool success = GetDllMemInfo(pDllAddr, &base, &len);
这段代码相当简单。 在Windows中,我们使用VirtualQuery()和PE头的基地址。 基地址和PE头给我们我们需要的信息。 在Linux中,解析ELF文件可没有像windows中那么简单。 我们依靠共享对象文件名的文件大小。
明天,最简单的部分:扫描内存和使用你的函数!
相关文章
发现功能,第3部分(Finding Functions, Part 3)
原文
Finding Functions, Part 2
Picking up where we left off, we now have the signature and imagebase address of the function. On Windows, the ImageBase of a DLL is almost always obeyed, and you can be assured that server.dll will always be loaded at 0×22000000. However, on Linux, this is not the case. And either way, assuming this is a bad design (not to say these ‘hacks’ are good design, but it helps make things more stable).
So, we need to find the DLL in memory. Luckily this isn’t too hard. Both Window and Linux come with native API for finding the base address of any given address. Respectively, these function calls are
VirtualQuery()
and
dladdr()
. Do we know of an address that will always exist in the GameDLL? Of course! This would be the GameDLL’s factory: gameServerFactory for server plugins and g_SMAPI->serverFactory(false) for Metamod:Source plugins. Let’s pretend we have this address in
void *pDllAddr
. First, we need to get the base address of the DLL in memory.
bool GetDllMemInfo(void *pAddr, unsigned char **pBaseAddr, size_t *memLength)
{
#ifdef WIN32
MEMORY_BASIC_INFORMATION mem;
if (!VirtualQuery(pAddr, &mem, sizeof(mem)))
return false;
if (*pBaseAddr)
*pBaseAddr = (unsigned char *)mem.AllocationBase;
IMAGE_DOS_HEADERS *dos = (IMAGE_DOS_HEADERS *)(mem.AllocationBase);
IMAGE_NT_HEADERS *pe = (unsigned long)dos + (unsigned long)dos->e_lfanew;
if (pe->Signature != IMAGE_NT_SIGNATURE)
return false;
if (memLength)
*memLength = (size_t)(pe->OptionalHeader.SizeOfImage);
return true;
#else
Dl_info info;
struct stat buf;
if (!dladdr(pAddr, &info))
return false;
if (!info.dli_fbase || !info.dli_fname)
return false;
if (stat(info.dli_fname, &buf) != 0)
return false;
if (pBaseAddr)
*pBaseAddr = (unsigned char *)info.dli_fbase;
if (memLength)
*memLength = buf.st_size;
return true;
#endif
}
unsigned char *base;
size_t len;
bool success = GetDllMemInfo(pDllAddr, &base, &len);
This code is pretty straight forward. For Windows, we use VirtualQuery() and cast the base address to PE headers. That base address and the PE headers give us the information we need. In Linux, there is nothing easy to parse ELF files like there is in Windows. We rely on getting the file size of the shared object filename.
Tomorrow, the easiest part: Scanning memory and using your function!

浙公网安备 33010602011771号