【发布时间】:2023-03-06 01:07:01
【问题描述】:
我有一个指向函数的指针 (void *),我想知道这个函数属于哪个进程。我不知道该怎么做,但我认为使用某种形式的VirtualQuery 诡计是可能的。任何帮助将不胜感激。
提前致谢,
澄清:“属于进程”是指函数所在的进程。例如:
假设内存中加载了一个可执行文件 (test.exe)。这个可执行文件包含一个名为SayHello 的函数,它位于内存中的 0xDEADBEEF。在一个完全不同的过程中,我怎么知道 0xDEADBEEF 在 test.exe 的内存空间中。
希望能解决问题。
澄清 2: 我确定您熟悉“VTable 挂钩”,即外部模块在单独的进程中更改 VTable 指针以指向不同的函数。因此,每当调用钩子成员时,它都会传递给外部模块。
为了防止这种情况(反作弊),我希望能够检查 VTable 的所有方法是否都指向它们所在的模块。
解决方案代码:
template<class T>
inline void **GetVTableArray(T *pClass, int *pSize)
{
void **ppVTable = *(void ***)pClass;
if(pSize)
{
*pSize = 0;
while(!IsBadReadPtr(ppVTable[*pSize], sizeof(UINT_PTR)))
(*pSize)++;
}
return ppVTable;
}
bool AllVTableMembersPointToCurrentModule(void *pClass)
{
DWORD dwOldProtect;
HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
MODULEENTRY32 moduleEntry;
// Take a snapshot of all modules in the specified process
hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
if(hModuleSnap == INVALID_HANDLE_VALUE)
return false;
// Set the size of the structure before using it
moduleEntry.dwSize = sizeof(MODULEENTRY32);
// Retrieve information about the first module (current process)
if(!Module32First(hModuleSnap, &moduleEntry))
{
CloseHandle(hModuleSnap);
return false;
}
// Grab the base address and size of our module (the address range where
// the VTable can validly point to)
UINT_PTR ulBaseAddress = reinterpret_cast<UINT_PTR>(moduleEntry.modBaseAddr);
UINT_PTR ulBaseSize = moduleEntry.modBaseSize;
// Get the VTable array and VTable member count
int nMethods;
void **ppVTable = GetVTableArray(pClass, &nMethods);
#ifdef VTABLE_FAKING
// Allow patching
VirtualProtect(ppVTable, nMethods * sizeof(UINT_PTR), PAGE_EXECUTE_READWRITE, &dwOldProtect);
// Now take the next module and set the first VTable pointer to point to an
// invalid address, outside of the current module's address range
Module32Next(hModuleSnap, &moduleEntry);
ppVTable[0] = moduleEntry.modBaseAddr;
#endif
// Don't allow people to overwrite VTables (can easily be bypassed, so make
// sure you check the VirtualProtect status of the VTable regularly with
// VirtualQuery)
VirtualProtect(ppVTable, nMethods * sizeof(UINT_PTR), PAGE_EXECUTE, &dwOldProtect);
// Clean up the snapshot object
CloseHandle(hModuleSnap);
// Ensure all VTable pointers are in our current module's address range
for(int i = 0; i < nMethods; ++i)
{
// Get address of the method this VTable pointer points to
UINT_PTR ulFuncAddress = reinterpret_cast<UINT_PTR>(ppVTable[i]);
// Check the address is within our current module range
if(ulFuncAddress < ulBaseAddress || ulFuncAddress > ulBaseAddress + ulBaseSize)
return false;
}
return true;
}
【问题讨论】:
-
我不确定我是否理解这个问题 - 函数在什么意义上属于进程?
-
你是如何获得那个 void* 的?
-
@Carl Norum:已编辑以清除问题。 @nos: VTable 指针