Windows API Hooking 学习

简介: Windows API Hooking 学习

实验去Hook以及UnhookMessageBoxA,来了解WindowsAPI的Hooking技术,当然也可以尝试实验任意函数

API hooking 是一种让我们监测和修改API调用的技术,Windows API hooking也是AV/EDR用来确定代码是否恶意的技术之一。

本文参照链接:https://resources.infosecinstitute.com/topic/api-hooking/的实验去理解

实验:

编写一个C++程序,整体的工作方式如下:

  1. Get memory address of the MessageBoxA function
  2. Read the first 6 bytes of the MessageBoxA - (will need these bytes for unhooking the function)
  3. Create a HookedMessageBox function (that will be executed when the original MessageBoxA is called)
  4. Get memory address of the HookedMessageBox
  5. Patch / redirect MessageBoxA to HookedMessageBox
  6. Call MessageBoxACode gets redirected to HookedMessageBox
  7. HookedMessageBox executes its code, prints the supplied arguments, unhooks theMessageBoxA and transfers the code control to the actual MessageBoxA

调试学习:

代码放入VS设为x86(代码下面提供),下好断点

首先弹一个正常消息框,然后往下走,

messageBoxAddress = GetProcAddress(library, "MessageBoxA");获取MessageBoxA的地址 ,可以在反汇编窗口看到。(7518EEA0处)

前六个字节为8b ff 55 8b ec 83,然后下一句

ReadProcessMemory(GetCurrentProcess(), messageBoxAddress, messageBoxOriginalBytes, 6, &bytesRead);

把它存到messageBoxOriginalBytes,相当于保存原来的正常MessageBoxA的内存地址,为了我们待会实验unhook用。

创建一个patch,相当于去hookMessageBoxA

// create a patch "push <address of new MessageBoxA); ret"
  void* hookedMessageBoxAddress = &HookedMessageBox;
  char patch[6] = { 0 };
  memcpy_s(patch, 1, "\x68", 1);
  memcpy_s(patch + 1, 4, &hookedMessageBoxAddress, 4);
  memcpy_s(patch + 5, 1, "\xC3", 1);
    WriteProcessMemory(GetCurrentProcess(), (LPVOID)messageBoxAddress, patch, sizeof(patch), &bytesWritten);

还记得我们的messageBoxAddress变量是存的原MessageBoxA函数的地址

经过如上代码,调用WriteProcessMemory,将前六位换为了68 00 10 D6 00 C3再写入messageBoxAddress

这里代码很清晰,前一位后一位对应两个指令,中间的void* hookedMessageBoxAddress = &HookedMessageBox;HookedMessageBox的地址

查看地址,可以看到,指令相当于:

// push HookedMessageBox memory address onto the stack
push HookedMessageBox
// jump to HookedMessageBox
ret

我们这里为 push 0D6100h,可以验证一下:

HookedMessageBoxfunction

然后最后的一个MessageBoxA(NULL, "hi", "hi", MB_OK);是我们hooking完之后执行的,那么执行后会进入HookedMessageBox,因为已经修改了内存中前六字节的值。通过WriteProcessMemory

可以看到首先是定义好的去输出MessageBoxA的参数,然后下一步就是Unhook了,把我们之前最开始存到messageBoxOriginalBytes的原地址换回到messageBoxAddress,如下图 查看地址时已经变为原地址8b ff 55 8b ec 83,成功unhook

最后调用MessageBoxA

Code

#include "pch.h"
#include <iostream>
#include <Windows.h>
FARPROC messageBoxAddress = NULL;
SIZE_T bytesWritten = 0;
char messageBoxOriginalBytes[6] = {};
int __stdcall HookedMessageBox(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) {
  // print intercepted values from the MessageBoxA function
  std::cout << "Ohai from the hooked function\n";
  std::cout << "Text: " << (LPCSTR)lpText << "\nCaption: " << (LPCSTR)lpCaption << std::endl;
  // unpatch MessageBoxA
  WriteProcessMemory(GetCurrentProcess(), (LPVOID)messageBoxAddress, messageBoxOriginalBytes, sizeof(messageBoxOriginalBytes), &bytesWritten);
  // call the original MessageBoxA
  return MessageBoxA(NULL, lpText, lpCaption, uType);
}
int main()
{
  // show messagebox before hooking
  MessageBoxA(NULL, "hi", "hi", MB_OK);
  HINSTANCE library = LoadLibraryA("user32.dll");
  SIZE_T bytesRead = 0;
  // get address of the MessageBox function in memory
  messageBoxAddress = GetProcAddress(library, "MessageBoxA");
  // save the first 6 bytes of the original MessageBoxA function - will need for unhooking
  ReadProcessMemory(GetCurrentProcess(), messageBoxAddress, messageBoxOriginalBytes, 6, &bytesRead);
  // create a patch "push <address of new MessageBoxA); ret"
  void *hookedMessageBoxAddress = &HookedMessageBox;
  char patch[6] = { 0 };
  memcpy_s(patch, 1, "\x68", 1);
  memcpy_s(patch + 1, 4, &hookedMessageBoxAddress, 4);
  memcpy_s(patch + 5, 1, "\xC3", 1);
  // patch the MessageBoxA
  WriteProcessMemory(GetCurrentProcess(), (LPVOID)messageBoxAddress, patch, sizeof(patch), &bytesWritten);
  // show messagebox after hooking
  MessageBoxA(NULL, "hi", "hi", MB_OK);
  return 0;
}

总结

整个过程去Hook,MessageBoxA这个API,了解了怎么样去Hook Windows API的流程,以及原理。简单来说也可以理解为一种劫持。我们首先要做的是:获取要劫持函数的地址,然后我们在自己组装一个数据结构,数据结构的内容是 执行汇编:把新函数地址拷到寄存器里,然后再jmp到新函数地址位置执行新函数,然后我们把自己组装这个数据结构拷贝到之前获取的需要劫持的函数地址指向的内存的位置,这样当我们再次调用该函数的时候,程序走到函数地址处发现是执行我们刚刚写好的汇编命令,直接jmp到了我们自己定义的函数地址的位置,也就相当于直接运行了我们自己写好的函数地址

,许多AV/EDR也是这样去Hook敏感的API的,这样的话,我们可以用windbg去调试AV程序是怎么注入到我们的程序中检测我们的API调用的,然后找到API的原地址去修改。

二进制小白,哪里写的有问题还请斧正!

相关文章
|
7月前
|
存储 缓存 网络协议
dpdk课程学习之练习笔记二(arp, udp协议api测试)
dpdk课程学习之练习笔记二(arp, udp协议api测试)
186 0
|
2月前
|
开发框架 .NET API
Windows Forms应用程序中集成一个ASP.NET API服务
Windows Forms应用程序中集成一个ASP.NET API服务
98 9
|
3月前
|
网络协议 API Windows
MASM32编程调用 API函数RtlIpv6AddressToString,windows 10 容易,Windows 7 折腾
MASM32编程调用 API函数RtlIpv6AddressToString,windows 10 容易,Windows 7 折腾
|
7月前
|
Kubernetes 安全 API
Kubernetes学习-集群搭建篇(三) Node配置完善和API概述
Kubernetes学习-集群搭建篇(三) Node配置完善和API概述
Kubernetes学习-集群搭建篇(三) Node配置完善和API概述
|
5月前
|
存储 API Go
学习gin-vue-admin之创建api和swagger
学习gin-vue-admin之创建api和swagger
|
5月前
|
JavaScript 前端开发 Java
|
7月前
|
SQL 关系型数据库 MySQL
Trinitycore学习之windows上用cmake生成vs项目并尝试在windows上启动服务
Trinitycore学习之windows上用cmake生成vs项目并尝试在windows上启动服务
130 0
|
6月前
|
Windows
逆向学习Windows篇:通过编写函数处理菜单消息
逆向学习Windows篇:通过编写函数处理菜单消息
40 0
|
6月前
|
安全 API C++
逆向学习Windows篇:C++中多线程的使用和回调函数的实现
逆向学习Windows篇:C++中多线程的使用和回调函数的实现
208 0
|
6月前
|
安全 API Windows
逆向学习Windows篇:文件操作详解
逆向学习Windows篇:文件操作详解
37 0