Inline HOOK

news2024/11/25 4:49:42

一、Inline HOOK介绍

1、内联钩子简介

Inline hook(内联钩子)是一种在程序运行时修改函数执行流程的技术。它通过修改函数的原始代码,将目标函数的执行路径重定向到自定义的代码段,从而实现对目标函数的拦截和修改。

内联钩子通常用于函数的动态修改和函数的跟踪,常见的应用场景包括代码注入、API挂钩、调试、性能分析等。它可以用于实现函数的监控、跟踪参数、修改返回值、修改参数等操作。

内联钩子的实现方式通常有以下几个步骤:

  1. 定位目标函数的地址:通过函数名或者导入表等方式找到目标函数在内存中的地址。
  2. 修改目标函数的内存权限:将目标函数的内存权限修改为可写可执行,以便后续修改函数的指令。
  3. 备份目标函数的原始指令:将目标函数的原始指令备份到自定义的缓冲区中。
  4. 修改目标函数的指令:将目标函数的指令修改为跳转到自定义代码的指令,以实现拦截和修改。
  5. 编写自定义代码:编写自定义的代码,实现对目标函数的拦截和修改逻辑。
  6. 执行自定义代码:将自定义的代码插入到目标函数的执行流程中,使其被调用时执行自定义逻辑。
  7. 恢复目标函数的原始指令:在自定义代码执行完毕后,恢复目标函数的原始指令,以确保目标函数的正常执行。

2、为什么要引入inline hook?

我们上一节介绍的IAT HOOK当中有一个很大的问题就是我们只能hook掉存在于IAT表当中的函数,如果我们想hook的函数不在IAT表当中IAT hook就无能为力了,为了弥补这一缺陷,我们引出了inline hook。

在这里我们浅谈一下hook的本质,就是在执行函数A之前,让他去执行我们的代码B,然后再回过来去执行A,达到暗度陈仓的目的。或者进一步,就是把call dword ptr ds:[addr]里的addr替换为我们自定义函数的地址。

!!Attention!!:

这里还有个小bug就是这里的call的地址,并不一定就是真正的函数的地址,比如在debug版的程序当中你call的函数地址他不一定就是真正的函数入口点,而是call到一个jmp指令的位置,然后通过jmp指令跳转到真正的函数入口点的位置。为了防止函数地址发生变更,我们使用GetProcAddress函数来获取MessageBoxA开始的准确地址。

 

至于这样做有什么好处?

》主要是便于编译器去调试,有时候重新编译的时候,函数地址可能会发生变动,就需要修改每一个函数的地址,比较麻烦,为了省事,就统一使用jmp跳转,这样函数地址变动的时候,只需要修改jmp后面的地址就可以了!

3、Inline hook的主要用途

Inline hook(内联钩子)在软件开发和系统调试中有广泛的用途。以下是一些常见的用途:

  1. 动态函数拦截与修改:通过内联钩子可以拦截目标函数的调用,修改函数的输入参数或返回值,实现对函数行为的定制化控制。这可以用于实现调试器、破解软件保护机制、API挂钩等功能。

  2. API监控和追踪:通过内联钩子可以监控和记录系统中特定API函数的调用信息,用于分析程序行为、检测恶意行为、收集性能统计数据等。这对于系统调试、性能分析和安全监控非常有用。

  3. 代码注入和修改:内联钩子可以用于将自定义的代码注入到目标进程的执行流程中,实现对程序的动态修改和扩展。这在软件插件、热修复、代码破解等方面有应用。

  4. 反调试和反破解:内联钩子可以用于对抗调试器和破解工具,通过拦截和修改关键函数的调用,使得调试器无法正确运行或破解工具无法识别关键逻辑。这用于软件保护和反破解技术。

  5. 动态代码分析和跟踪:通过内联钩子可以在程序执行过程中动态跟踪代码执行路径、记录函数调用顺序、分析运行时行为等。这对于调试、优化和逆向工程非常有帮助。

二、编程前准备工作

1、如何在vs调试dll文件

打断点之后,会自动启动目标进程,然后等待dll被加载进来

 

将dll文件注入到目标进程

 

然后发现dll已经进入断点了

2、我们直接在MessageBoxA的函数体里面填写JMP不会破坏源代码导致出错吗?

》先给答案:不会。分析如下:

call MessageBoxA会把下一条指令mov eax,dword ptr [y]所在的地址压栈,然后不管是执行我们的自定义函数的ret指令,还是原来的MessageBoxA最后的ret指令,都会返回到指令mov eax,dword ptr [y]去执行,从而达到了顺序执行,不破坏原exe的目的。

三、思路分析

1、首先初始化钩子:获取要hook的函数的地址空间的起始位置,在函数空间的这块内存里面存放的就是指令的硬编码,我们需要把原指令存放在oldCode[5]里面,然后把新指令(也就是跳转到哪个地址去执行)放到newCode[5]里面即可。

2、安装钩子:把函数地址原来的指令修改为新指令,具体来说就是E9到我们自定义的函数地址去执行。

3、进程执行结束之后卸载钩子,也就是把hook的函数地址的指令给他还原回去。

四、改写上节案例

我们书接上回,坤坤在进行篮球表演🏀,台下的ikuns尖叫声太大,影响了居民休息,我们采取把ikuns替换成小黑子的方式来起到消音效果,但是其实不妨换一个思路,我们直接把坤坤大变活人,替换成小鬼哥哥,下面的观众可能会考虑到远古毒兽泰裤剌的致命毒性而纷纷有序离场,从而也可以达到控制噪声的效果!

五、完整代码:

以下是dll文件的完整内容:

#include "pch.h"

//我们这次hook的是MessageBoxA

DWORD g_oldFuncAddr = 0;
BYTE g_oldCode[5] = { 0 };
BYTE g_newCode[5] = { 0xE9 };

BOOL initHook();
bool installHook();
bool unistallHook();

int WINAPI MyMessageBoxA(
    HWND   hWnd,
    LPCSTR lpText,
    LPCSTR lpCaption,
    UINT   uType
)
{
    unistallHook();
    int result = MessageBoxA(hWnd, "本活动由小鬼哥哥赞助", "太裤剌!", MB_OK);
    installHook();
    return result;
}

BOOL initHook() {

    //获取需要hook的函数MessageBoxA的地址
    HMODULE hDll = LoadLibraryA("user32.dll");
    g_oldFuncAddr =(DWORD)GetProcAddress(hDll, "MessageBoxA");
    if (g_oldFuncAddr > 0) {
        MessageBoxA(0, "找到了MessageBoxA函数", "标题", MB_OK);
    }

    //保留原汇编代码
    memcpy(g_oldCode, (char*)g_oldFuncAddr, 5);

    //保存新汇编代码
    DWORD offset = (DWORD)MyMessageBoxA - g_oldFuncAddr - 5;
    memcpy(&g_newCode[1], &offset, 4);
    
    return true;
}

bool installHook() {

    DWORD oldProtect = 0;
    VirtualProtect((char*)g_oldFuncAddr, 5, PAGE_EXECUTE_READWRITE, &oldProtect);
    memcpy((char*)g_oldFuncAddr, g_newCode, 5);
    VirtualProtect((char*)g_oldFuncAddr, 5, oldProtect, &oldProtect);
    return true;
}

bool unistallHook() {
    DWORD oldProtect = 0;
    VirtualProtect((char*)g_oldFuncAddr, 5, PAGE_EXECUTE_READWRITE, &oldProtect);
    memcpy((char*)g_oldFuncAddr, g_oldCode, 5);
    VirtualProtect((char*)g_oldFuncAddr, 5, oldProtect, &oldProtect);

    return true;
}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH: {
        initHook();
        bool bret=installHook();
        if (bret) {
            MessageBoxW(0, L"钩子安装成功!", L"标题", MB_OK);
        }
        break;
    }
    case DLL_THREAD_ATTACH:
        break;
    case DLL_THREAD_DETACH:
        break;
    case DLL_PROCESS_DETACH: {
        bool bret=unistallHook();
        if (bret) {
            MessageBoxW(0, L"钩子卸载成功", L"标题", MB_OK);
        }
        break;
    }
    }
    return TRUE;
}

六、运行结果

hook之前:

hook之后: 

 

今天的学习就到此结束啦!同时Windows API的学习也要告一段落了,后面我们会进入shellcode以及汇编、反汇编的学习,喜欢的话多多支持一下吧!🧡🧡🧡

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/579083.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Flume学习笔记

1 简介 (1) Apache Flume是一个分布式、可信任的数据采集、日志收集弹性系统(框架),用于高效收集、汇聚和移动大规模日志信息从多种不同的数据源到一个集中的数据存储中心(HDFS、Hbase或者本地文件系统) (2) 可信任是指保证消息有效的处理和传递: 如果…

聊聊Go语言的控制语句

在高级编程语言中,控制流语句(control-flow statement)是一类用于控制程序执行流程的语句,以下简称为控制语句。它们可以根据条件或循环执行相应的代码块,或者跳转到指定位置执行代码。 常见的控制语句包括: 条件语句:…

【特征选择】基于二进制粒子群算法的特征选择方法(GRNN广义回归神经网络分类)【Matlab代码#32】

文章目录 【可更换其他算法,获取资源请见文章第6节:资源获取】1. 特征选择问题2. 二进制粒子群算法3. 广义回归神经网络(GRNN)分类4. 部分代码展示5. 仿真结果展示6. 资源获取 【可更换其他算法,获取资源请见文章第6节…

2023年Github学生包认证,提取JetBrains全家桶,认证Copilot 等多种权益

什么是GIthub学生包 1 Github学生包简而言之是可以白嫖100美刀的微软Azure(每年),200美刀的DigitalOcean金额(一年有效期)总计300刀可用来购买云服务器。 2 一年免费的.tech .me .live三种顶级域名(可以分…

Kubernetes 云原生 Gateway 网关

一、云原生定义 CNCF 对云原生的定义中提到了几个关键的点: 1、强调应用环境的动态性,像公有云、私有云、混合云等新型的动态环境已成为大多数应用的首选; 2、强调在跨多云部署应用时具备非云平台绑定的属性; 3、还强调了弹性扩展…

Python系列模块之标准库shutil详解

感谢点赞和关注 ,每天进步一点点!加油! 目录 一、shutil介绍 二 、使用详解 2.1 复制函数 2.1.1 shutil.copy 2.1.2 shutil.copy2 2.1.3 shutil.copyfile 2.1.4 shutil.copytree 2.2 移动文件 2.2.1 shutil.move 2.3 删除文件 2.3…

Vue-后台管理项目001---侧边栏

从浏览器上可以看出,他的返回值是promise(pending),所以我们可以用async,await来简化这个操作 await只能用在被async修饰的方法中,需要把仅挨着await的方法修饰成async 需要把仅挨着await的方法修饰成异步的async现在可以将这个da…

1-1 统计数字问题

题目: 我的答案: 一、信息 二、分析 1.如何选择数据结构? 2.如何选择算法有很多思路? 3.如何用文件实现输入输出? 三、思考 疑问1 我选择了一开始数组选择使用数组是一个不错的选择,尤其在这个问题中…

【网络协议详解】——DHCP系统协议(学习笔记)

目录 🕒 1. DHCP概述🕒 2. 工作过程🕒 3. DHCP的报文格式🕒 4. DHCP中继代理🕒 5. 实验:DHCP配置 🕒 1. DHCP概述 动态主机配置协议DHCP(Dynamic Host Configuration Protocol&…

TA-lib第三方库安装问题

因为学习的需要,用到Talib库做写指标分析,但是百度了好久,说是去要某某网站下载对应版本的文件进行本地安装,但是把…404 Not found 然后通过查找,Ta-lib库的安装已经迁移到这里了 https://github.com/TA-Lib/ta-lib-p…

【SpringBoot教程】SpringBoot+MybatisPlus数据库连接测试 用户收货信息接口开发

⛪ 专栏地址 系列教程更新中 🚀 文章介绍: SpringBootMybatisPlus组合可以大大加快开发效率,紧接上一篇文章的内容,这篇文章进行数据库的连接与查询测试,并配置日志输出调试 🚀 源码获取: 项目中的资料可以通过文章底部…

数据安全治理科技系统能力-数据安全复合治理框架和模型解读(3)

数据治理,数据安全治理行业在发展,在实践,所以很多东西是实践出来的,哪有什么神仙理论指导,即使有也是一家之说,但为了提高企业投产比,必要的认知是必须的,落地数据安全治理科技水平差异直接决定产品和项目是否可持续性,当前和未来更需要专业和有效创新。数据安全治理…

《数据库》期末考试复习手写笔记-第11章 并发控制(锁)【10分】

目录 知识点:封锁活锁死锁可串行化调度 考题1:可串行化调度 考题2:调度正确判断&共享锁写锁 考题3: 事务调度死锁 知识点:封锁活锁死锁可串行化调度 考题1:可串行化调度 考题2:调度正确判…

杨立昆:科学之路读书笔记2

杨立昆:科学之路读书笔记2 人工智能的低谷人工智能无所不能吗?谁将从AI人工智能革命中获益结语 一起学AI系列博客:目录索引 人工智能的低谷 上回分享了读书缘由,杨立昆的背景及其对人工智能的研究看法,这回分享他如何…

15.Kafka系列之事务原理及实践

我们先来回顾下6.Kafka系列之设计思想(四)-消息传递语义中的一些内容 1. 消息传递保证 At most once:最多一次。消息可能会丢失,但永远不会重新传递At least once:至少一次。消息永远不会丢失,但可能会重新传递Exactly once&…

rust 初识基础: 变量、数据类型、函数、所有权、枚举

了解到 rust 和 WebAssembly 的结合使用,可以构建前端应用,而且性能也比较好。初步学习使用 rust 是预编译静态类型语言。 安装 rust 官网下载 rust-CN , 大致了解下为什么选择:高性能、可靠性、生产力。 打开控制台啊,执行安装…

【Servlet】

目录 🎂1. 第一个 Servlet 程序:使用 Servlet 写 hello world 🥞1.1 创建项目 🍳1.2 引入依赖 🎃1.3 创建目录 🍘1.4 开始写代码 🌍1.5 打包代码 🍤1.6 部署 👑1…

如何在华为OD机试中获得满分?Java实现【获取最大软件版本号】一文详解!

✅创作者:陈书予 🎉个人主页:陈书予的个人主页 🍁陈书予的个人社区,欢迎你的加入: 陈书予的社区 🌟专栏地址: Java华为OD机试真题(2022&2023) 文章目录 1. 题目描述2. 输入描述3. 输出描述…

使用kotlin用回溯法解决电话号码的字母组合问题

17. 电话号码的字母组合 难度中等 2474 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。 示例 1: 输入&#…

23种设计模式中之中介者模式(Mediator Pattern)

前言:大家好,我是小威,24届毕业生,在一家满意的公司实习。本篇文章将23种设计模式中的迭代器模式,此篇文章为一天学习一个设计模式系列文章,后面会分享其他模式知识。 如果文章有什么需要改进的地方还请大佬…