4.1 应用层Hook挂钩原理分析

应用层,hook,挂钩,原理,分析 · 浏览次数 : 237

小编点评

**Hook技术原理** Hook技术是一种计算机安全编程技术,其基本原理是在程序执行期间进行拦截、修改、增强现有函数功能。当程序执行到指定事件时,例如点击按钮或打开文件,则会调用自定义的回调函数。这些回调函数可以执行任何想要执行的功能,例如显示消息、修改窗口大小等。 **实现Hook思路** 1. **获取目标模块的基址:** 使用 `GetModuleHandle` 获取系统调用库 (user32.dll) 的基址。 2. **获取目标函数的地址:** 使用 `GetProcAddress` 获取 `MessageBoxA` 函数的地址。 3. **修改函数属性:** 使用 `VirtualProtect` 设置内存属性以只读可写模式。 4. **计算目标函数跳转地址:** 计算出需要跳转的地址,该地址是目标函数的地址加上 0x45。 5. **替换函数开头部分:** 使用 `__asm` 汇编代码将函数开头部分替换为跳转指令。 6. **恢复内存属性:** 使用 `VirtualProtect` 将内存属性恢复到原始状态。 7. **执行自定义功能:** 在回调函数中执行用户设置的任何功能。 8. **返回原函数地址:** 使用 `jmp` 指令跳转回原函数的返回地址。 **示例代码** ```c++ #include // 定义回调函数 void callback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {} // 获取窗口句柄 HWND hwnd = FindWindow(NULL, L"Your Window Title", NULL, NULL); // 设置回调函数 SetWindowMessageCallback(hwnd, callback, NULL, 0); // 执行回调函数 // ... ``` **总结** Hook技术是一种强大的安全技术,可以被用于实现多种功能,例如显示消息、修改窗口大小等。但是,使用 hook 技术也需要注意安全性,需要谨慎选择回调函数,并确保回调函数不会导致内存泄漏或其他安全风险。

正文

InlineHook 是一种计算机安全编程技术,其原理是在计算机程序执行期间进行拦截、修改、增强现有函数功能。它使用钩子函数(也可以称为回调函数)来截获程序执行的各种事件,并在事件发生前或后进行自定义处理,从而控制或增强程序行为。Hook技术常被用于系统加速、功能增强、等领域。本章将重点讲解Hook是如何实现的,并手动封装实现自己的Hook挂钩模板。

首先我们来探索一下Hook技术是如何实现的,如下图所示是一个简单的弹窗程序,当读者点击测试弹窗按钮时则会弹出一个MessageBox提示窗口,本次实现目标很简单,通过向目标内注入一个DLL库,实现Hook挂钩住MessageBox弹窗,从而实现去除弹窗的目的;

我们先来看看如何实现Hook思路;

  • 1.调用GetModuleHandle函数来获取到user32.dll模块的基址
  • 2.调用GetProcAddress函数获取到MessageBoxA弹窗的基址
  • 3.调用VirtualProtect来修改MessageBoxA前5个字节内存属性
  • 4.计算Dest - MsgBox - 5重定位跳转地址,并写入JMP跳转指令
  • 5.计算Dest + Offset + 5 = MsgBox +5得到需要跳转回RET的位置
  • 6.最后调用VirtualProtect来将内存属性修改为原始状态

我们载入带有MessageBoxA弹窗的程序,然后在x64dbg上按下Ctrl+G输入MessageBoxA找到我们需要Hook的位置(或者说替换),如下图所示为了完成弹窗转向功能,只需要在函数开头写入jmp无条件跳转指令即可,在32位系统中JMP指令默认占用5个字节,前三条指令恰好5个字节,为了能够保持堆栈平衡,我们需要记下前三条指令,并在自己的中转函数中对其进行补齐。

此外,我们还需要计算出程序的返回地址,使用0x76600BE5 - 0x76600BA0 = 0x45从而得出返回地址就是基址加上0x45,这里的返回地址其实就是返回到原MessageBoxA弹窗的RET 0x10的位置76600BE6,从这里可以看出屏蔽弹窗的原理就是通过中转函数跳过了原始弹窗函数的执行。

由于开头位置被替换为了我们自己的Transfer()函数,当程序中弹窗被调用时默认会路由到我们自己的函数内,首先执行补齐原函数的替换部分,并执行自定义功能区中的增加内容,当执行结束后则通过jmp ebx的方式跳转回原函数的ret 0x10的位置处,从而实现增加功能的目的。这里读者需要注意__declspec(naked)的意思是不添加任何的汇编修饰,当使用了此修饰符时则编译器会只编译我们自己的汇编指令,并不会增加默认的函数开场或离场原语。

__declspec(naked) void Transfer()
{
  __asm{
    mov edi, edi
    push ebp
    mov ebp, esp
    // 自定义功能区
    mov ebx, jump     // 取出跳转地址
    jmp ebx           // 无条件转向
  }
}

通过应用上述案例中的知识点我们能很容易的实现对弹窗的替换功能,以下代码中实现了对MessageBoxA弹窗的屏蔽功能,也就是通过跳过弹窗实现流程实现的一种劫持方法,读者可自行编译这段DLL程序,但需要注意一点,读者在编译DLL时应该关闭DLL的DEP以及ASLR模式,否则会出现无法定位的问题。

#include <Windows.h>
#include <stdio.h>

DWORD jump = 0;

// 不添加任何的汇编修饰
__declspec(naked) void Transfer()
{
    __asm
    {
        mov edi, edi
        push ebp
        mov ebp, esp
        mov ebx, jump     // 取出跳转地址
        jmp ebx           // 无条件转向
    }
}

// DLL程序入口地址
bool APIENTRY DllMain(HANDLE handle, DWORD dword, LPVOID lpvoid)
{
    // 取进程内模块基址
    HMODULE hwnd = GetModuleHandle(TEXT("user32.dll"));
    DWORD base = (DWORD)GetProcAddress(hwnd, "MessageBoxA");
    DWORD oldProtect = 0;

    // 将内存设置为可读可写可执行状态,并将原属性保存在oldProtect方便恢复
    if (VirtualProtect((LPVOID)base, 5, PAGE_EXECUTE_READWRITE, &oldProtect))
    {
        DWORD value = (DWORD)Transfer - base - 5;    // 计算出需要Hook的地址
        jump = base + 0x45;                          // 计算出返回地址

        // 替换头部汇编代码
        __asm
        {
            mov eax, base
            mov byte ptr[eax], 0xe9        // e9 = jmp 指令机器码
            inc eax                        // 递增指针
            mov ebx, value                 // 需要跳转到的地址
            mov dword ptr[eax], ebx
        }

        // 恢复内存的原始属性
        VirtualProtect((LPVOID)base, 5, oldProtect, &oldProtect);
    }
    return true;
}

读者可通过注入软件将hook.dll动态链接库注入到进程内,此时我们可以再次观察0x76600BA0位置处的代码片段,读者应该能看到已经被JMP替换,如下图所示;

继续跟进则读者能看到,在跳转指令的下方则是我们自己补齐的汇编指令,此处由于没有做任何事就被返回了,这就导致当读者再次点击弹窗时,弹窗失效;

当我们需要替换程序标题时同样可是使用该方式实现,一般来说程序设置标题会调用SetWindowTextA函数,我们可以拦截这个函数,并传入自定义的窗口名称,从而实现修改指定窗口的标题的目的,代码只是在上面代码的基础上稍微改一下就能实现效果,只要程序使用了该函数设置标题,则可以实现替换的目的;

#include <Windows.h>
#include <stdio.h>

DWORD jump = 0;

// 汇编中转函数
__declspec(naked) bool _stdcall Transfer(HWND hwnd, LPCSTR lpString)
{
    __asm
    {
        mov edi, edi
        push ebp
        mov ebp, esp
        mov ebx, jump
        jmp ebx
    }
}

// 自己的设置窗体标题函数
bool __stdcall MySetWindowTextA(HWND hwnd, LPCSTR lpString)
{
    char * lpText = "LyShark 修改版";
    return Transfer(hwnd, lpText);
}

// DLL程序入口地址
bool APIENTRY DllMain(HANDLE handle, DWORD dword, LPVOID lpvoid)
{
    HMODULE hwnd = GetModuleHandle(TEXT("user32.dll"));
    DWORD base = (DWORD)GetProcAddress(hwnd, "SetWindowTextA");
    DWORD oldProtect = 0;

    if (VirtualProtect((LPVOID)base, 5, PAGE_EXECUTE_READWRITE, &oldProtect))
    {
        DWORD value = (DWORD)MySetWindowTextA - base - 5;
        jump = base + 5;
        __asm
        {
            mov eax, base
            mov byte ptr[eax], 0xe9
            inc eax
            mov ebx, value
            mov dword ptr[eax], ebx
        }
        VirtualProtect((LPVOID)base, 5, oldProtect, &oldProtect);
    }
    return true;
}

本文作者: 王瑞
本文链接: https://www.lyshark.com/post/f695c6c3.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

与4.1 应用层Hook挂钩原理分析相似的内容:

4.1 应用层Hook挂钩原理分析

InlineHook 是一种计算机安全编程技术,其原理是在计算机程序执行期间进行拦截、修改、增强现有函数功能。它使用钩子函数(也可以称为回调函数)来截获程序执行的各种事件,并在事件发生前或后进行自定义处理,从而控制或增强程序行为。Hook技术常被用于系统加速、功能增强、等领域。本章将重点讲解Hook是如何实现的,并手动封装实现自己的Hook挂钩模板。首先我们来探索一下Hook技术是如何实现的,如下

4.3 IAT Hook 挂钩技术

IAT(Import Address Table)Hook是一种针对Windows操作系统的API Hooking 技术,用于修改应用程序对动态链接库(DLL)中导入函数的调用。IAT是一个数据结构,其中包含了应用程序在运行时使用的导入函数的地址。IAT Hook的原理是通过修改IAT中的函数指针,将原本要调用的函数指向另一个自定义的函数。这样,在应用程序执行时,当调用被钩子的函数时,实际上会执行

4.4 EAT Hook 挂钩技术

EAT(Export Address Table)用于修改动态链接库(DLL)中导出函数的调用。与`IAT Hook`不同,EAT Hook是在DLL自身中进行钩子操作,而不是修改应用程序的导入表。它的原理是通过修改DLL的导出函数地址,将原本要导出的函数指向另一个自定义的函数。这样,在应用程序调用DLL的导出函数时,实际上会执行自定义的函数。与IAT不同是EAT存放的不是函数地址,而是导出函数地

Nginx负载配置

目录Nginx 负载均衡笔记1. 概述1.1 Nginx 简介1.2 负载均衡概述2. 四层负载均衡(传输层)2.1 工作原理2.2 特点2.3 优缺点优点缺点2.4 示例场景3. 七层负载均衡(应用层)3.1 工作原理3.2 特点3.3 优缺点优点缺点3.4 示例场景4. Nginx 调度算法4.

4.7 x64dbg 应用层的钩子扫描

所谓的应用层钩子(Application-level hooks)是一种编程技术,它允许应用程序通过在特定事件发生时执行特定代码来自定义或扩展其行为。这些事件可以是用户交互,系统事件,或者其他应用程序内部的事件。应用层钩子是在应用程序中添加自定义代码的一种灵活的方式。它们可以用于许多不同的用途,如安全审计、性能监视、访问控制和行为修改等。应用层钩子通常在应用程序的运行时被调用,可以执行一些预定义的

聊聊GLM-4-9B开源模型的微调loss计算

概述 Github官方地址:GLM-4 网上已经有很多关于微调的文章,介绍各种方式下的使用,这里不会赘述。我个人比较关心的是微调时的loss计算逻辑,这点在很多的文章都不会有相关的描述,因为大多数人都是关心如何使用之类的应用层,而不是其具体的底层逻辑,当然咱也说不清太底层的计算。 可了解其它loss

[转帖]长篇图解 etcd 核心应用场景及编码实战

https://xie.infoq.cn/article/3329de088beb60f5803855895 一、白话 etcd 与 zookeeper 二、etcd 的 4 个核心机制 三、Leader 选举与客户端交互 四、etcd 的应用场景 4.1. kubernetes 大脑 4.2. 服

关于19c RU补丁报错问题的分析处理

本文演示关于19c RU补丁常见报错问题的分析处理: 1.查看补丁应用失败的原因 2.问题解决后可继续应用补丁 3.发现DB的RU补丁未更新 4.opatchauto应用DB补丁报错解决 1.查看补丁应用失败的原因 补丁应用失败有详细日志记录原因; 故意使用oracle用户解压补丁,然后测试是否可以

4.8 C++ Boost 应用JSON解析库

property_tree 是 Boost 库中的一个头文件库,用于处理和解析基于 XML、Json 或者 INFO 格式的数据。 property_tree 可以提供一个轻量级的、灵活的、基于二叉数的通用容器,可以处理包括简单值(如 int、float)和复杂数据结构(如结构体和嵌套容器)在内的各种数据类型。它可以解析数据文件到内存中,然后通过迭代器访问它们。在 Boost 库中,propert

【Azure 容器应用】在中国区Azure上创建的容器服务默认应用域名不全

问题描述 在中国区Azure上,创建Container App服务,发现默认的应用程序URL只有前半段,并不是一个完整的域名。这是什么情况呢? 正常的Container App的URL格式为:...azureconta