16,548
社区成员




void ReplaceIATEntryInOneMod(PCSTR pszCalleeModName,PROC pfnCurrent, PROC pfnNew, HMODULE hmodCaller)
{
ULONG ulSize;
/*ReplaceIATEntryInOneMod函数要做的第一件事情是找出hmodCaller模块的输入节,方法是调用ImageDirectoryEntryToData函数,
给它传递IMAGE_DIRECTORY_ENTRY_IMPORT。如果该函数返回NULL,DataBase.exe模块就没有输入节,并且不进行任何操作。*/
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)
ImageDirectoryEntryToData(hmodCaller, TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize);
if(pImportDesc == NULL)
return;
/*如果DataBase.exe有一个输入节,那么ImageDirectoryEntryToData就返回该输入节的地址,该地址是一个类型为PIMAGE_IMPORT_DESCRIPTOR的指针。现在 我们必须查看该模块的输入节,找出包含我们想要修改的输入函数的DLL。for循环负责扫描DLL模块的名字。注意,模块的输入节中的所有字符串都是用ANSI(决不能用Unicode)编写。这就是为什么要显式调用lstrcmpiA而不是lstrcmpi宏的原因。*/
for(; pImportDesc->Name; pImportDesc++)
{
PSTR pszModName = (PSTR)((PBYTE) hmodCaller + pImportDesc->Name);
if(lstrcmpiA(pszModName, pszCalleeModName) == 0)
break;
}
if(pImportDesc->Name == 0)
return;
/*如果该循环终止运行,但是没有找到对“Kernel32.dll”中的任何符号的引用,那么该函数就返回,并且仍然无所事事。*/
/*如果模块的输入节确实引用了“Kernel32.dll”中的符号,那么将得到包含输入符号信息的IMAGE_THUNK_DATA结构的数组的地址。然后,重复引用来自“Kernel32.dll”的所有输入符号,寻找与符号的当前地址相匹配的地址。*/
PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)((PBYTE)hmodCaller + pImportDesc->FirstThunk);
for(; pThunk->u1.Function; pThunk++)
{
PROC* ppfn = (PROC*) &pThunk->u1.Function;
// Is this the function we're looking for?
BOOL fFound = (*ppfn == pfnCurrent);
/*如果找到了一个匹配的地址,便调用WriteProcessMemory函数,以便改变替换函数的地址。使用WriteProcessMemory函数,而不是InterlockedExchangePointer函数是因为WriteProcessMemory能够改变字节,而不管这些字节拥有什么页面保护属性。*/
if(fFound)
{
WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew, sizeof(pfnNew), NULL);
return;
}
}
}