注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

无翼风的网易博客

欢迎光临无翼风的网易博客

 
 
 

日志

 
 

我的学习笔记之二——修改导入表HOOK API(ring3_iat_exe_hook_Messagebox)v  

2010-03-24 18:57:26|  分类: 编程与电脑技术 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
IAT即Import Address Table 是PE(可以理解为EXE)的输入地址表,我们知道一个程序运行时可以要调用多个模块,或都说要调用许多API函数,但这些函数不一定都在EXE本身中,例如你调用Messagebox来显示一个对话框时,你只需要调用它,你并没有编写Messagebox的函数的实现过程,Messagebox的函数的实现过程实际上是在user32.dll这个库文件中,当这个程序运行时会在user32.dll中找到Messagebox并调用它。
那么具体的调入过程是怎样的呢?下面来谈谈其中的重要环节即:IMAGE_IMPORT_BY_NAME,那么IMAGE_IMPORT_BY_NAME结构到底是什么样子的呢:?下面是引入表图

OriginalFirstThunk IMAGE_IMPORT_BY_NAME FirstThunk
   | IMAGE_THUNK_DATA IMAGE_THUNK_DATA IMAGE_THUNK_DATA IMAGE_THUNK_DATA ... IMAGE_THUNK_DATA --->--->--->--->--->--->Function 1 Function 2 Function 3 Function 4 ... Function n <---<---<---<---<---<---IMAGE_THUNK_DATA IMAGE_THUNK_DATA IMAGE_THUNK_DATA IMAGE_THUNK_DATA ... IMAGE_THUNK_DATA 

首先不要被IMAGE_THUNK_DATA这个名字弄糊涂它仅是指向 IMAGE_IMPORT_BY_NAME 结构的RVAOriginalFirstThunk和 FirstThunk 所指向的这两个数组大小取决于PE文件从DLL中引入函数的数目。比如,如果PE文件从kernel32.dll中引入10个函数,那么IMAGE_IMPORT_DESCRIPTOR 结构的 Name1域包含指向字符串"kernel32.dll"RVA,同时每个IMAGE_THUNK_DATA 数组有10个元素。为什么我们需要两个完全相同的数组为了回答该问题,我们需要了解当PE文件被装载到内存时,PE装载器将查找IMAGE_THUNK_DATA 和 IMAGE_IMPORT_BY_NAME 这些结构数组,以此决定引入函数的地址。然后用引入函数真实地址来替代由FirstThunk指向的 IMAGE_THUNK_DATA 数组里的元素值。因此当PE文件准备执行时,上图已转换成:

OriginalFirstThunk IMAGE_IMPORT_BY_NAME FirstThunk
   | IMAGE_THUNK_DATA IMAGE_THUNK_DATA IMAGE_THUNK_DATA IMAGE_THUNK_DATA ... IMAGE_THUNK_DATA --->--->--->--->--->--->Function 1 Function 2 Function 3 Function 4 ... Function n         Address of Function 1 Address of Function 2 Address of Function 3 Address of Function 4 ... Address of Function n 
我们现在要做的是把后面的地址改成我们自己的函数地址,例如当EXE调用Messagebox时让它转入我们的函数,我们处理完后再转入真正的函数地址。
因此API HOOK和其它HOOK存在本质的区别,可以理解为API劫持,说一行道一万不如动手去实践,下面代码演示了如何HOOK本进程中的Messagebox,当本EXE调用Messagebox时会先转入到我们的函数中,请看清是怎样找到PE的引入表并修改的。
#include <stdio.h>
#include <windows.h>
#include <Dbghelp.h>
#pragma comment(lib,"Dbghelp.lib")
#pragma comment(lib,"User32.lib")
typedef int (__stdcall *OLD_MessageBox)( HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption,UINT uType );
OLD_MessageBox g_procOldMessageBox = NULL;
int __stdcall HOOK_MessageBox( HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption,UINT uType)
{
printf("%s\t%d\r\n",__FUNCTION__,__LINE__);
if (NULL != g_procOldMessageBox)
  return g_procOldMessageBox(hWnd,lpText,"不好意思,hook到了!",uType); 
else
  return MessageBox(hWnd,lpText,lpCaption,uType); ;
}

int replace_IAT(const char *pDllName,const char *pApiName,bool bReplace)
{
HANDLE hProcess = ::GetModuleHandle (NULL);
DWORD dwSize = 0;
PIMAGE_IMPORT_DESCRIPTOR pImageImport = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(hProcess,TRUE,
   IMAGE_DIRECTORY_ENTRY_IMPORT,&dwSize);
if (NULL == pImageImport)
  return 1;
PIMAGE_IMPORT_BY_NAME pImageImportByName = NULL;
PIMAGE_THUNK_DATA   pImageThunkOriginal = NULL;
PIMAGE_THUNK_DATA   pImageThunkReal  = NULL;
while (pImageImport->Name)
{
  if (0 == strcmpi((char*)((PBYTE)hProcess+pImageImport->Name),pDllName))
   {
   break;
   }
  ++pImageImport;
}
if (! pImageImport->Name)
  return 2;
pImageThunkOriginal = (PIMAGE_THUNK_DATA)((PBYTE)hProcess+pImageImport->OriginalFirstThunk   );
pImageThunkReal = (PIMAGE_THUNK_DATA)((PBYTE)hProcess+pImageImport->FirstThunk    );
while (pImageThunkOriginal->u1.Function)
{
  if ((pImageThunkOriginal->u1 .Ordinal & IMAGE_ORDINAL_FLAG) != IMAGE_ORDINAL_FLAG)
   {
    pImageImportByName = (PIMAGE_IMPORT_BY_NAME)((PBYTE)hProcess+pImageThunkOriginal->u1 .AddressOfData );
   if (0 == strcmpi(pApiName,(char*)pImageImportByName->Name))
    {
     MEMORY_BASIC_INFORMATION mbi_thunk;
     VirtualQuery(pImageThunkReal, &mbi_thunk, sizeof(MEMORY_BASIC_INFORMATION)); 
     VirtualProtect(mbi_thunk.BaseAddress,mbi_thunk.RegionSize, PAGE_READWRITE, &mbi_thunk.Protect); 
    if (true == bReplace)
     {
      g_procOldMessageBox =(OLD_MessageBox) pImageThunkReal->u1.Function; 
      pImageThunkReal->u1.Function = (DWORD)HOOK_MessageBox;
     }
    else
      pImageThunkReal->u1.Function = (DWORD)g_procOldMessageBox;
     DWORD dwOldProtect; 
     VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, mbi_thunk.Protect, &dwOldProtect); 
    break;
    }
   }
  ++pImageThunkOriginal;
  ++pImageThunkReal;
}
return 0;
}
int main()
{
replace_IAT("User32.dll","MessageBoxA",true);
MessageBox(NULL,"EnumIAT User32.dll MessageBoxA true;","没有Hook",MB_OK);
replace_IAT("User32.dll","MessageBoxA",false);
MessageBox(NULL,"EnumIAT User32.dll MessageBoxA false;","没有Hook",MB_OK);
return getchar();
}

上面的代码修改一下随可用于全局HOOK,但我不看好IAT HOOK,虽然WINDOWS核心编程看好这种做法。因为现在主流操作系统是XP和WINDOWS2003,都是数据执行保护(也可能某个补丁前没有这个功能),它们会保护多数进程在内在中不被修改,所以IAT全局HOOK会被系统拦截从而失败,但也同时发现它能保护进程却不保护模块,因此用INLINE HOOK可能会更可行些。但IAT的原理和思想仍值得进一步学习。
版权所有,如需引用请注明作者和出处
  评论这张
 
阅读(228)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018