读书人

lt;lt;Windows核心编程gt;gt;上的IAT HOOK有异

发布时间: 2013-04-21 21:18:07 作者: rapoo

<<Windows核心编程>>上的IAT HOOK有错误
<<Windows核心编程>>堪称经典,但一本书从头到尾没点错误是不可能的.
一下是原书中的一段代码:

void ReplaceIATEntryInOneMod(PCSTR pszCalleeModName,
PROC pfnCurrent, PROC pfnNew, HMODULE hmodCaller)
{
ULONG ulSize;
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)
ImageDirectoryEntryToData(hmodCaller, TRUE,
IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize);

if(pImportDesc == NULL)
return; // This module has no import section.

//Find the import descriptor containing references
//to callee's functions.
for(; pImportDesc->Name; pImportDesc++)
{
PSTR pszModName = (PSTR)
((PBYTE) hmodCaller + pImportDesc->Name);
if(lstrcmpiA(pszModName, pszCalleeModName) == 0)
break;
}

if(pImportDesc->Name == 0)
// This module doesn't import any functions from this callee.
return;

//Get caller's import address table (IAT)
//for the callee's functions.
PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)
((PBYTE) hmodCaller + pImportDesc->FirstThunk);

//Replace current function address with new function address.
for(; pThunk->u1.Function; pThunk++)
{

// Get the address of the function address.
PROC* ppfn = (PROC*) &pThunk->u1.Function;

// Is this the function we're looking for?
BOOL fFound = (*ppfn == pfnCurrent);

// See the sample code for some tricky Windows 98
// stuff that goes here.

if(fFound)
{
//The addresses match; change the import section address.
WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew,
sizeof(pfnNew), NULL);
return; // We did it; get out.
}
}

//If we get to here, the function
//is not in the caller's import section.
}

这段程序有3个错误.
1.一个模块的输入节可能存在多个Name相同的pImportDesc,此程序只在第一个找到的pImportDesc中查找想要的函数,而真正要替换的函数可能就被忽略了.
有些dll的导入库,没有包含所有的函数,如果想要用一些未公开函数,就需要自己写导入库,就会出现此情况.


2.一个函数可能有多个名字,比如LockResource与SetHandleCount就指向同一个函数,你到底要替换哪一个?
函数的参数中指定pfnCurrent不如指定函数名更明确.
3.WriteProcessMemory需要在OpenProcess时指定相应PROCESS_VM_WRITE权限.而GetCurrentProcess获得的本进程句柄似乎无此权限.
还是用VirtualProtect吧,但这样就不是线程安全的了.所幸一般不会有多个线程同时修改输入节.
4.无返回值.这不能算是错误,但返回一个值表示成功失败还是有用处的吧.返回原先的函数更有用,这样要卸除HOOK也容易.
我重写了一下这个函数,欢迎拍砖.

PROC ReplaceIATEntry(HMODULE hmodCaller, PCSTR pszCalleeModName, PCSTR pszFunctionName, PROC pfnNew) 
{
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = PIMAGE_IMPORT_DESCRIPTOR(DWORD(hmodCaller)+PIMAGE_NT_HEADERS((DWORD(hmodCaller)+PIMAGE_DOS_HEADER(hmodCaller)->e_lfanew))->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

if(pImportDesc)
{
for(; pImportDesc->Name; pImportDesc++)
{
if(lstrcmpiA(PSTR(DWORD(hmodCaller)+pImportDesc->Name), pszCalleeModName) == 0)
{
PIMAGE_THUNK_DATA pOriginalThunk = PIMAGE_THUNK_DATA(DWORD(hmodCaller)+pImportDesc->OriginalFirstThunk);
PIMAGE_THUNK_DATA pThunk = PIMAGE_THUNK_DATA(DWORD(hmodCaller)+pImportDesc->FirstThunk);

for(int f = 0; pThunk[f].u1.Function; f++)
{
PIMAGE_IMPORT_BY_NAME fName = PIMAGE_IMPORT_BY_NAME(DWORD(hmodCaller)+DWORD(pOriginalThunk[f].u1.AddressOfData));
if (lstrcmpA((PSTR)fName->Name, pszFunctionName) == 0)
{
PROC r = (PROC)pThunk[f].u1.Function;
DWORD op;
VirtualProtect(&pThunk[f], 4, PAGE_READWRITE, &op);
pThunk[f].u1.Function = (PDWORD)pfnNew;
VirtualProtect(&pThunk[f], 4, op, &op);
return r;
}
}
}


}
}
return 0;
}



[解决办法]
是要注入进去然后拦截么?
[解决办法]
这种查找IAT的方法不太好。
我当时用的LoadImage.确实DLL已经加载后再查找自己想hook的API。
[解决办法]
find name比较. 很局限的.我也是用了他的. 改了下 . 比较地址 而不是funname.

读书人网 >VC/MFC

热点推荐