首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > VC/MFC >

<<Windows核心编程>>上的IAT HOOK有异常

2013-04-21 
Windows核心编程上的IAT HOOK有错误Windows核心编程堪称经典,但一本书从头到尾没点错误是不可能的

<<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.

热点排行