学逆向论坛

找回密码
立即注册

只需一步,快速开始

发新帖

2万

积分

41

好友

1157

主题

[转载图文] 萌新逆向学习笔记

发表于 2020-9-4 12:20:44 | 查看: 3955| 回复: 1
前言  在上一篇文章中介绍了以模拟调试器的方式来对特定的API地址进行钩取。而这次本篇文章介绍的是修改IAT来同样达到钩取API的目的,这也是一种“劫持”API的方法。
  本文为个人学习《逆向工程核心原理》书籍的学习笔记,如果想深入学习逆向工程,推荐去观摩一下该本书籍。因为它实在是十分的易懂。
原理  当程序调用函数的时候,它会使用函数所在模块名称进行一个查表操作。这个表就是俗称的IID(IMAGE_IMPORT_DESCRIPTOR)。表上记载着程序调用目标函数的地址又称为IAT。待查询到目标函数地址后,程序才会真正的通过这个函数地址来进行函数调用:

萌新逆向学习笔记

萌新逆向学习笔记
  而我们只要修改IID中记录的对应的函数地址IAT,使它指向我们自己定义的另一个MessageBoxA,这样函数查表返回的地址就不是原来程序中定义的地址,而是我们修改后指向自己定义函数的地址了,这就完成了一次IAT“劫持”。

萌新逆向学习笔记

萌新逆向学习笔记
实现思路  整体思路:将修改函数地址的实现,以及新函数的实现写在一个DLL里,再编写一个注入器,将该DLL注入到目标程序中。DLL注入成功后便会修改IAT函数地址,达到IAT钩取的目的。
  细节思路:主要是如何找到该程序的IID里对应的IAT。我们可以先使用getModuleHandle(NULL)函数找到当前被注入程序的基址pfile,该基址即是指向当前PE文件DOS头的起始地址。通过DOS头结构体的e_lfanew属性,获取到NT头的虚拟内存空间的偏移量RVA,将该值加上基址pfile即可得到NT头的虚拟内存地址。而最后通过相关的属性操作,就可以从NT头中获取对应的IAT地址。
实践获取IID:
void findIID() {  // 找到IID所在的内存地址
  //获取当前被注入DLL的程序模块基址
  pfile = (PBYTE)GetModuleHandle(NULL);
  //转换成DOS头
  PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)pfile;
  //通过DOS头的e_lfanew找到NT头
  PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)(pfile + dosHeader->e_lfanew);
  //NT头中的可选NT头里的DataDirectory数组,记载着IID的虚拟内存偏移地址
  IMAGE_DATA_DIRECTORY IATSection = (IMAGE_DATA_DIRECTORY)(ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]);
  //加上基址,获取到IID虚拟内存地址
  currentIID = PIMAGE_IMPORT_DESCRIPTOR(pfile + IATSection.VirtualAddress);
  }
  

修改IAT
LPCSTR dialogDLL = "user32.dll";  void hookIAT() {
  // 修改IAT
  while (currentIID)
  {
  //去IID中的Name字段,其为IAT对应的模块名称虚拟内存地址偏移量,如MessageBoxA是在系统函数user32.dll中
  DWORD RVAName = currentIID->Name;
  char* VAName = (char*)(pfile + RVAName);
  //对比是否为user32.dll
  if (strcmp(VAName, dialogDLL))
  {
  // 符合条件,取出IAT列表
  DWORD RVAIAT = currentIID->FirstThunk;
  PIMAGE_THUNK_DATA pthunk = (PIMAGE_THUNK_DATA)(pfile + RVAIAT);
  //循环IAT函数地址列表,找到MessageBoxA函数地址
  while (pthunk->u1.Function)
  {
  DWORD funAddress = pthunk->u1.Function;
  if (funAddress == (DWORD)oriAddress)
  {
  //修改IAT
  DWORD oldProtect = NULL;
  VirtualProtect((LPVOID)&pthunk->u1.Function, 4, PAGE_EXECUTE_READWRITE, &oldProtect);
  pthunk->u1.Function = (DWORD)hookMessageBox;
  VirtualProtect((LPVOID)&pthunk->u1.Function, 4, oldProtect, &oldProtect);
  break;
  }
  pthunk++;
  }
  return;
  }
  currentIID++;
  }
  }
  

结果  例中使用的依旧是上篇文章中编写的可怜的弹窗程序:

萌新逆向学习笔记

萌新逆向学习笔记

萌新逆向学习笔记

萌新逆向学习笔记
结论  IAT钩取具有一定的局限性,我们只能钩取IAT中存在的函数,而不能无中生有。而我们定义的函数签名也必须符合钩取的原函数前的签名;如参数类型,函数返回等须相同。
  总的来说IAT钩取还是比较简单快速的,其难点是寻找IAT的过程。倘若我们对PE文件结构毫无所知,不能理解DOS头,NT头等重要结构,想必就要多费一些心思了吧。
源码及例子  https://share.weiyun.com/iCyzPWuM
  《0day安全 软件漏洞分析技术(第二版)》第三次再版印刷预售开始!


温馨提示:
1.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
2.回复帖子不仅是对作者的认可,还可以获得学币奖励,请尊重他人的劳动成果,拒绝做伸手党!
3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【投诉建议】板块发帖举报。
论坛交流群:672619046

    发表于 2020-9-6 05:12:13
    非常不错啊,感谢楼主无私的共享精神!

    小黑屋|手机版|站务邮箱|学逆向论坛 ( 粤ICP备2021023307号 )|网站地图

    GMT+8, 2024-4-25 14:23 , Processed in 0.129654 second(s), 47 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表