hook技术截取服务器信息,Windows Hook技术

hook技术截取服务器信息,Windows Hook技术0x01简介有人称它为“钩子”,有人称它为“挂钩”技术。谈到钩子,很容易让人联想到在钓东西,比如鱼钩就用于钓鱼。编程技术的钩子也是在等待捕获系统中的某个消息或者动作。钩子的应用范围非常广泛,比如输入监控、API拦截、消息捕获、改变程序执行流程等方面。杀毒软件会用Hook技术钩住一些API函数,比如钩住注册表读写函数,从而防止病毒对注册表进行写入;病毒使用Hook技术有针对性的捕获键盘的输入,从而…

大家好,又见面了,我是你们的朋友全栈君。

0x01 简介

有人称它为“钩子”,有人称它为“挂钩”技术。谈到钩子,很容易让人联想到在钓东西,比如鱼钩就用于钓鱼。编程技术的钩子也是在等待捕获系统中的某个消息或者动作。钩子的应用范围非常广泛,比如输入监控、API拦截、消息捕获、改变程序执行流程等方面。杀毒软件会用Hook技术钩住一些API函数,比如钩住注册表读写函数,从而防止病毒对注册表进行写入;病毒使用Hook技术有针对性的捕获键盘的输入,从而记录用户的密码等敏感信息;文件加密系统通过Hook技术在不改变用户操作的情况下对用户的文件进行透明加密,这些都属于Hook范畴的知识。

在windows系统下,Hook技术的方法比较多,使用比较灵活,常见的Hook方法有Inline Hook,IAT Hook,Windows钩子。。。Hook技术涉及DLL相关的知识。Hook技术也涉及注入的知识,想要把完成Hook功能的DLL文件加载到目标进程空间中,就要使用注入的知识。

0x02 常见Hook技术介绍

Inline Hook

API函数都保存在操作系统提供的DLL文件中,当在程序中调用某个API函数并运行程序后,程序会隐式地将API函数所在的DLL文件加载入内存中,这样,程序就会像调用自己的函数一样调用API。Inline Hook这种方法是在程序流程中直接进行嵌入jmp指令来改变流程的。

Inline Hook流程

构造跳转指令。

在内存中找到欲Hook函数地址,并保存欲Hook位置处的前5字节。

将构造的跳转指令写入需Hook的位置处。

当被Hook位置被执行时会转到自己的流程执行。

如果要执行原来的流程,那么取消Hook,也就是还原被修改的字节。

执行原来的流程。

继续Hook住原来的位置

这就是Inline Hook的大概流程。

导入地址表钩子-IAT HOOK

导入地址表是PE文件结构中的一个表结构。在可执行文件中使用其他DLL可执行文件的代码或数据,成为导入或者输入。当PE文件需要运行时,将被系统加载至内存中,此时windows加载器会定位所有的导入的函数或者数据将定位到的内容填写至可执行文件的某个位置供其使用。这个地位是需要借助于可执行文件的导入表来完成的。导入表中存放了所使用的DLL的模块名称及导入的函数名称或函数序号。

在加壳和脱壳的研究中,导入表是非常关键的部分。加壳要尽可能地隐藏或破坏原始的导入表。脱壳一定要找到或者还原或者重建原始的导入表,如果无法还原或修过脱壳后的导入表的话,那么可执行文件仍然是无法运行的。

windows钩子函数

windows下的窗口应用程序是基于消息驱动的,但是在某种情况下需要捕获或者修改消息,从而完成一些特殊的功能。对于捕获消息而言,无法使用IAT或Inline Hook之类的方式去进行捕获,不过windows提供了专门用于处理消息的钩子函数。

windows系统提供的钩子按照挂钩范围分为局部钩子和全局钩子。局部钩子是针对一个线程的,而全局钩子这是针对这个操作系统内基于消息机制的应用程序的。全局钩子需要使用DLL文件,DLL文件里面存放了钩子函数的代码。

在操作系统中安装全局钩子以后,只要进程接收到可以发出钩子的消息后,全局钩子的DLL文件会被操作系统自动或强行加载到该进程中,由此可见,设置消息钩子也是一种可以进行DLL注入的方法。

windows下的钩子函数,主要用3个,分别是SetWindowsHookEx() 、CallNextHookEx()和UnhookWindowsHookEx()

0x03 实例

Inline Hook实例

00cb7332af76fa32106c619324b8f294.png

首先通过Process Explorer可以查看程序的父进程,可以看出,大部分普通的应用程序都是由explorer.exe进程创建的(像360、QQProtect以及一些驱动程序除外),那么知道把Explorer.exe 进程中CreateProcessW()函数Hook住,就可以针对要完成的工作做很多事情了,比如,可以记录哪个应用程序被启动,也可以对应用程序进行拦截。

882a0fe9bb9c9e86df15bf2650088693.png

aecb02ddd83f9b0a5f083c2d71ce7f0d.png

关键代码如下:

ILHook.cpp

654e24ebd6f0940edc1b84b8c4407db0.gif

#include “ILHook.h”

CILHook::CILHook()

{ // 对成员变量的初始化 m_pfnOrig = NULL; ZeroMemory(m_bOldBytes, 5); ZeroMemory(m_bNewBytes, 5);

}

CILHook::~CILHook()

{ // 取消HOOK UnHook(); m_pfnOrig = NULL; ZeroMemory(m_bOldBytes, 5); ZeroMemory(m_bNewBytes, 5);

}

/*

函数名称:Hook

函数功能:对指定模块中的函数进行挂钩

参数说明: pszModuleName:模块名称 pszFuncName: 函数名称 pfnHookFunc: 钩子函数

*/

BOOL CILHook::Hook(LPSTR pszModuleName, LPSTR pszFuncName, PROC pfnHookFunc)

{ BOOL bRet = FALSE; // 获取指定模块中函数的地址 m_pfnOrig = (PROC)GetProcAddress(GetModuleHandle(pszModuleName), pszFuncName); if ( m_pfnOrig != NULL ) { // 保存该地址处5个字节的内容 DWORD dwNum = 0; ReadProcessMemory(GetCurrentProcess(), m_pfnOrig, m_bOldBytes, 5, &dwNum); // 构造JMP指令 m_bNewBytes[0] = ‘\xe9’; // jmp Opcode // pfnHookFunc是我们HOOK后的目标地址 // m_pfnOrig是原来的地址 // 5是指令长度 *(DWORD *)(m_bNewBytes + 1) = (DWORD)pfnHookFunc – (DWORD)m_pfnOrig – 5; // 将构造好的地址写入该地址处 WriteProcessMemory(GetCurrentProcess(), m_pfnOrig, m_bNewBytes, 5, &dwNum); bRet = TRUE; } return bRet;

}

/*

函数名称:UnHook

函数功能:取消函数的挂钩

*/

VOID CILHook::UnHook()

{ if ( m_pfnOrig != 0 ) { DWORD dwNum = 0; WriteProcessMemory(GetCurrentProcess(), m_pfnOrig, m_bOldBytes, 5, &dwNum); }

}

/*

函数名称:ReHook

函数功能:重新对函数进行挂钩

*/

BOOL CILHook::ReHook()

{ BOOL bRet = FALSE; if ( m_pfnOrig != 0 ) { DWORD dwNum = 0; WriteProcessMemory(GetCurrentProcess(), m_pfnOrig, m_bNewBytes, 5, &dwNum); bRet = TRUE; } return bRet;

}

0429338f8ffc8ba131867ecb8cf2474a.gif

HookCreateProcess.cpp

0d33271e7f40c8b5c3ac9299259195f0.gif

#include “ILHook.h”

CILHook CreateProcessHook;

// 我们实现的Hook函数

BOOL

WINAPI

MyCreateProcessW( LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation )

{ BOOL bRet = FALSE; if ( MessageBoxW(NULL, lpApplicationName, lpCommandLine, MB_YESNO) == IDYES ) { CreateProcessHook.UnHook(); bRet = CreateProcessW(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation); CreateProcessHook.ReHook(); } else { MessageBox(NULL, “您启动的程序被拦截”, “提示”, MB_OK); } // CreateProcessHook.UnHook();

// // 弹出被创建进程的进程名

// MessageBoxW(NULL, lpApplicationName, lpCommandLine, MB_OK);

//

// // 创建进程

// bRet = CreateProcessW(lpApplicationName,

// lpCommandLine,

// lpProcessAttributes,

// lpThreadAttributes,

// bInheritHandles,

// dwCreationFlags,

// lpEnvironment,

// lpCurrentDirectory,

// lpStartupInfo,

// lpProcessInformation);

//

// CreateProcessHook.ReHook(); return bRet;

}

BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )

{ switch ( ul_reason_for_call ) { case DLL_PROCESS_ATTACH: { // Hook CreateProcessW()函数 CreateProcessHook.Hook(“kernel32.dll”, “CreateProcessW”, (PROC)MyCreateProcessW); break; } case DLL_PROCESS_DETACH: { CreateProcessHook.UnHook(); break; } } return TRUE;

}

235b1f94b2e8a856a093c329cb46b086.gif

钩子实例:

这里实现一个简单的键盘记录工具。

47697f46045cf5e5cac22c17f2ce1ca3.png

关键代码如下:

KeyBoradHookTest.cpp  主要来生成dll文件,在该dll文件中需要定义两个导出函数和两个全局变量。

a6cde855164f8d4f9dafe618876eabe1.gif

// KeyBoradHookTest.cpp : Defines the entry point for the DLL application.

//

#include “stdafx.h”

extern “C” __declspec(dllexport) VOID SetHookOn();

extern “C” __declspec(dllexport) VOID SetHookOff();

// 钩子句柄

HHOOK g_Hook = NULL;

// DLL模块句柄

HINSTANCE g_Inst = NULL;

BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )

{ // 保存DLL的模块句柄 g_Inst = (HINSTANCE)hModule; return TRUE;

}

// 钩子函数

LRESULT CALLBACK KeyboardProc( int code, // hook code WPARAM wParam, // virtual-key code LPARAM lParam // keystroke-message information

)

{ if ( code < 0 ) { return CallNextHookEx(g_Hook, code, wParam, lParam); } if ( code == HC_ACTION && lParam > 0 ) { char szBuf[MAXBYTE] = { 0 }; GetKeyNameText(lParam, szBuf, MAXBYTE); MessageBox(NULL, szBuf, NULL, MB_OK); } return CallNextHookEx(g_Hook, code, wParam, lParam);

}

VOID SetHookOn()

{ // 安装钩子 g_Hook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_Inst, 0);

}

VOID SetHookOff()

{ // 卸载钩子 UnhookWindowsHookEx(g_Hook);

}

9338918a8042842af6fb3ab4de0c4aa8.gif

0x04Reference

1.http://blog.csdn.net/u013761036/article/details/52268500 DLL劫持(HiJack)原理以及实现细节

没有一个系统是安全的 Know it,And hack it!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/141159.html原文链接:https://javaforall.net

(0)
上一篇 2022年5月9日 上午8:20
下一篇 2022年5月9日 上午8:20


相关推荐

  • OTA测试方法解析

    OTA测试方法解析目前 标准的 OTA 测试系统是 SISO 单输入 单输出 如主流的 2G 3G 和 WLAN 的 802 11a b g 等设备 其主要的测试指标是 TRP 总辐射功率 和 TIS 总全向灵敏度 现代无线技术如 LTE HSPA WI FI 和 WiMAX 为了提高数据传输速度 都开始采用 MIMO 多输入 多输出 技术 MIMO 技术能提高无线传输的可靠性 提高无线通信系统的频谱效率 是面向未来的关键技术 随着 MIMO 技术的不断发展和应用 需要完整而成熟的评估 MIMO 设备的辐射吞吐量的测试要求和测试方法 MIMO 技术利用

    2026年3月20日
    2
  • TOTALCMD 小计

    TOTALCMD 小计1 创建快捷方式 ctrl shift f5 管理员在 2009 年 8 月 13 日编辑了该文章文章 window bd share config common bdSns

    2026年3月18日
    1
  • navicat for mysql永久激活码最新【2022最新】「建议收藏」

    (navicat for mysql永久激活码最新)这是一篇idea技术相关文章,由全栈君为大家提供,主要知识点是关于2021JetBrains全家桶永久激活码的内容https://javaforall.net/100143.htmlIntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,上面是详细链接哦~2KLKA7BQFO-eyJsaWNlb…

    2022年4月1日
    5.0K
  • 使用 Nginx 配置jsp服务器

    使用 Nginx 配置jsp服务器br Nginx 简介 br Nginx enginex 是一个高性能的 HTTP 和反向代理服务器 也是一个 IMAP POP3 SMTP 代理服务器 Nginx 是由 IgorSysoev 为俄罗斯访问量第二的 Rambler ru 站点开发的 它已经在该站点运行超过两年半了 Igor 将源代码以类 BSD 许可证的形式发布 尽管还是测试版 但是 Nginx 已经因为它的稳定性 丰富的功能集 示例配置文件和低系统资源的消耗而闻名了 br 根据最新一

    2026年3月18日
    1
  • setsockopt()使用方法(參数具体说明)

    setsockopt()使用方法(參数具体说明)

    2021年11月28日
    54
  • shell脚本基本语法详解

    shell脚本基本语法详解编写shell脚本的时候,最前面要加上一行:#!/bin/bash,因为linux里面不仅仅只有bash一个解析器,还有其它的,它们之间的语法会有一些不同,所以最好加上这一句话,告诉系统要用这个解析器。一.shell变量shell变量和一些编程语言不同,一般shell的变量赋值的时候不用带“$”,而使用或者输出的时候要带“$”。加减乘除的时候要加两层小括号。括号外面要有一个“$”,括号里面的变量可以

    2022年7月26日
    6

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号