注册通行证 用户名 密码
  • 文章投稿
  • 博客
  • 论坛
  • 设为首页
  • 加入收藏
jztop.com网络技术
  • 首页
  • | iT新闻
  • | 操作系统
  • | 组网建网
  • | 网络安全
  • | 程序开发
  • | 办公一族
  • | 工具软件
  • | 网页制作
  • | 多媒体制作
  • | 网吧技术
  • | 服务器
  • | 专题教程
Vista | 软件评测 | 系统备份 | 优化 | 进程 | 聊天 | 病毒 | Linux | 黑客 | 防火墙 | 数据库 | Web开发 | Java | Word | 游戏 | 32位开发 | 移动开发
当前位置:首页 > 程序开发 > 32位开发 > C/C++ 内容正文:Windows下的函数hook技术

Windows下的函数hook技术

发布时间:2006-05-05 19:02:56 来源:csdn 网友评论 0 条

都是很成熟的东西了,这几天看了看,总结一下而已。
讨论了Windows下hook函数的几种方法。提供了一个hook TextOutA的完整例子。通过CreateRemoteThread的方法把hook dll注入到一个普通的应用程序中。Hooking Imported Functions by name调用imported functions'时的步骤/实现
在程序中调用从其它模块引入的函数的方法和普通的函数调用有所不同。对于普通的函数调用,直接使用
call address来调用即可,但是对于
imported functions
,在编译的时候
compiler/link
并不知道实际的函数实现会被加载到那个地址,函数实现在那个地址在运行的时候才会确定。对于
imported functions
,首先是
call
引入表中的一个函数,在运行时再初始化引入表,使用
jmp
跳转到真实的函数实现。


引入表:
The PE file IMAGE_IMPORT_DESCRIPTORstructure, which holds all the information about functions imported from a specific DLL, has pointers to two arrays in the executable. These arrays are called import address tables (IATs), or sometimes thunk data arrays. The first pointer references the real IAT, which the program loader fixes up when the executable is loaded. The second pointer references the original IAT, which is untouched by the loader and lists the imported functions.


实现原理

  • 找到
    PE
    文件的
    Image_Import_Descriptor
    结构
  • 找到
    Original LAT
    和
    Real LAT.
  • 通过要
    hook
    的函数的名字在
    Original LAT
    找到要
    hook
    的
    imported function
    在数组中的
    index.
  • 保存并修改
    Real LAT
    在相应
    index
    的
    function address

(refer to John Robbins, BugsLayerUtil.dll)

Hooking Imported Functions by ordinal

原理和
Hook Imported functions by name
一样,只是是通过要
hook
的函数的
ordinal
在
original LAT
中找到
index.

Hooking a function in this dll

当一个
DLL
是通过
LoadLibrary
载入的时候,我们无法通过
hook imported function
的方法的
hook
它中的
function
。有两种可能的办法处理这种情况:
第一种方法,遍历进程空间,发现
call
指定函数的地方替换为
call hookFunction.
太麻烦,而且不安全。


第二种方法,改写要
hook
的函数
FuncA
。比较好的方法

  1. 实现
    HookFuncA
    ,最后的实现垫入
    n
    个
    nop.
  2. 找到要
    hook
    的函数
    FuncA
    的绝对地址,改写前
    5
  3. 把
    FuncA
    的前
    5
    个字节拷贝到
    hookFuncA
    的后面,在加上一条指令jmp funcA+5.
    ----Code of HookDLL.dll, 可以通过CreateRemoteThread的方法把hook dll注入到一个普通的应用程序中。
    // HookDLL.cpp : Defines the entry point for the DLL application.
    //
    #include "stdafx.h"
    #include "HookDLL.h"
    #include "Log.h"
    //forward declare.
    LRESULT WINAPI InstallTextoutHook();
    LRESULT WINAPI UninstallTextoutHook();
    BOOL APIENTRY DllMain( HANDLE hModule,
    DWORD ul_reason_for_call,
    LPVOID lpReserved
    )
    {
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    if (InstallTextoutHook())
    {
    WriteLog("Install hook success./n");
    }else
    {
    WriteLog("Intall hook failed./n");
    }
    break;
    case DLL_THREAD_ATTACH:
    break;
    case DLL_THREAD_DETACH:
    break;
    case DLL_PROCESS_DETACH:
    if (UninstallTextoutHook())
    {
    WriteLog("Uninstall hook success./n");
    }else
    {
    WriteLog("Unintall hook failed./n");
    }
    break;
    }
    return TRUE;
    }
    #define DWORD_PTR DWORD*
    #define __LOCAL_SIZE 40h
    #define NAKED_PROLOG() /
    DWORD_PTR dwRet ; /
    DWORD_PTR dwESI ; /
    { /
    __asm PUSH EBP /* Set up the standard frame.*//
    __asm MOV EBP , ESP /
    __asm SUB ESP , __LOCAL_SIZE /* Save room for the local *//
    /* variables. *//
    __asm MOV EAX , EBP /* EBP has the stack coming *//
    /* into the fn. in it. *//
    __asm ADD EAX , 4 /* Account for PUSH EBP *//
    __asm MOV EAX , [EAX] /* Get return address. *//
    __asm MOV [dwRet] , EAX /* Save return address. *//
    __asm MOV [dwESI] , ESI /* Save ESI so chkesp in dbg *//
    /* builds works. *//
    }// The common epilog part that can be shared between the stdcall and
    // cdecl hook functions.
    #define EPILOG_COMMON() /
    { /
    __asm MOV ESI , [dwESI] /* Restore ESI. *//
    __asm ADD ESP , __LOCAL_SIZE /* Take away local var space *//
    __asm MOV ESP, EBP /* Restore standard frame. *//
    __asm POP EBP /
    }
    #define COPY_CODE_LENGTH 5
    BYTE g_abOriCode[COPY_CODE_LENGTH];
    BYTE g_abJmpCode[COPY_CODE_LENGTH];
    PROC g_oriTextout;
    BOOL g_blHooked = FALSE;
    LRESULT WINAPI InstallTextoutHook()
    {
    if (g_blHooked)
    return TRUE;
    //Get TextOutA's address.
    HMODULE hGdi32 = ::LoadLibrary(_T("Gdi32.dll"));
    g_oriTextout = GetProcAddress(hGdi32, _T("TextOutA"));
    if (NULL == g_oriTextout)
    return FALSE;
    //Get the hook'a address.
    HMODULE hModule = GetModuleHandle(_T("HookDLL.dll"));
    if (NULL == hModule)
    return FALSE;
    DWORD dwHookAddr = NULL;
    __asm
    {
    mov esi, offset HookLabel;
    mov edi, 0x10000000;//0x10000000 is the dll's base address.
    sub esi, edi;
    add esi, hModule;
    mov [dwHookAddr], esi;
    }
    //Get the NOP's address.
    DWORD dwNOPAddr = NULL;
    __asm
    {
    mov esi, offset NOPLabel;
    mov edi, 0x10000000;//0x10000000 is the dll's base address.
    sub esi, edi;
    add esi, hModule;
    mov [dwNOPAddr], esi;
    }
    //Save the first 5 byte of TextOutA to g_abOriCode
    __asm
    {
    mov esi, g_oriTextout;
    lea edi, g_abOriCode;
    cld;
    movsd;
    movsb;
    }
    //Generate the jmp Hook function.
    g_abJmpCode[0] = 0xe9;
    __asm
    {
    mov eax, dwHookAddr;
    mov ebx, g_oriTextout;
    add ebx, 5;
    sub eax, ebx;
    mov dword ptr[g_abJmpCode+1], eax;
    }
    //Write the jump instruction to the textoutA.
    DWORD dwProcessId = GetCurrentProcessId();
    HANDLE hProcess = OpenProcess (PROCESS_ALL_ACCESS,
    FALSE, dwProcessId);
    if (NULL == hProcess)
    return FALSE;
    DWORD dwOldFlag;
    VirtualProtectEx(hProcess, g_oriTextout, 5, PAGE_READWRITE, &dwOldFlag);
    WriteProcessMemory(hProcess, g_oriTextout, g_abJmpCode, sizeof(g_abJmpCode), NULL);
    VirtualProtectEx(hProcess, g_oriTextout, 5, dwOldFlag, NULL);
    //Write g_abOriTextout to the end of Hook function(NOP addr), then write the jmp instruction.
    VirtualProtectEx(hProcess, (LPVOID)dwNOPAddr, 10, PAGE_READWRITE, &dwOldFlag);
    WriteProcessMemory(hProcess, (LPVOID)dwNOPAddr, g_abOriCode, sizeof(g_abOriCode), NULL);
    //Generate the jmp TextoutA + 5
    __asm
    {
    mov eax, g_oriTextout;
    mov ebx, dwNOPAddr;
    add ebx, 5;
    sub eax, ebx;
    mov dword ptr[g_abJmpCode+1], eax;
    }
    WriteProcessMemory(hProcess, (LPVOID)(dwNOPAddr+5), g_abJmpCode, sizeof(g_abJmpCode), NULL);
    VirtualProtectEx(hProcess, (LPVOID)dwNOPAddr, 10, dwOldFlag, NULL);
    g_blHooked = TRUE;
    if(TRUE)
    return TRUE;
    HookLabel:
    NAKED_PROLOG ( ) ;
    int nx, ny;
    LPCSTR lp;
    lp = NULL;
    _asm
    {
    mov esi, ebp;
    add esi, 0Ch;
    lea edi, nx;
    movsd;
    lea edi, ny;
    movsd;

    lea edi, lp;
    movsd;
    }
    WriteLog_F("Try to ouput /"%s/" at (%d,%d)/n", lp, nx, ny);
    // Do the common epilog.
    EPILOG_COMMON ( ) ;
    NOPLabel:
    _asm NOP
    _asm NOP
    _asm NOP
    _asm NOP
    _asm NOP
    _asm NOP
    _asm NOP
    _asm NOP
    _asm NOP
    _asm NOP
    _asm NOP
    }
    LRESULT WINAPI UninstallTextoutHook()
    {
    if (!g_blHooked)
    return FALSE;
    //Restore the first 5 bytes code of TextOutA
    DWORD dwProcessId = GetCurrentProcessId();
    HANDLE hProcess = OpenProcess (PROCESS_ALL_ACCESS,
    FALSE, dwProcessId);
    if (NULL == hProcess)
    return FALSE;
    DWORD dwOldFlag;
    VirtualProtectEx(hProcess, g_oriTextout, 5, PAGE_READWRITE, &dwOldFlag);
    WriteProcessMemory(hProcess, g_oriTextout, g_abOriCode, sizeof(g_abOriCode), NULL);
    VirtualProtectEx(hProcess, g_oriTextout, 5, dwOldFlag, NULL);
    g_blHooked = FALSE;
    return TRUE;
    }
个字节为
jmp hookFuncA(
假定前
5
个字节为
n
个完整的指令
)
相关文章
  • 超级DIY 自己做Windows XP精美登录界面
  • Windows XP/2003系统服务备份与保护
  • 使用Windows系统提供的IP控件
  • Windows Socket1.1 程序设计
  • Windows Sockets API实现网络异步通讯
【评论】【收藏本文】【打印】【关闭】
上一篇文章:基于VC++的OpenGL编程讲座之曲线和曲面
下一篇文章:MFC中几个有用的字符串操作函数
讨论区
查看
已有 0 位对此新闻感兴趣的网友发表了看法
匿名发表
注册通行证 登陆
图文阅读推荐
推荐阅讯
  • C++箴言:使用对象管理资源
  • C++箴言:理解inline化的介入和排除
  • VC下揭开“特洛伊木马”的隐藏面纱
  • C++箴言:避免返回对象内部构件的句柄
  • C/C++语言void及void指针深层探索
  • Visual C++6.0 API函数操作技巧集
  • c++类的多重继承与虚拟继承
  • Windows Sockets 示例列表
  • c++中函数重载的相关知识
  • C++/CLI中实现singleton模式
阅读排行
  • 1.Borland 发布C++ Builder 2006 RAD 环境
  • 2.C/C++程序员应聘常见面试题深入剖析
  • 3.Visual C++常用数据类型转换详解
  • 4.C++中的 static 关键字
  • 5.利用VC++实现局域网实时视频传输
  • 6.浅谈C/C++内存泄漏及其检测工具
  • 7.英国投票否决C++/CLI 微软强攻ISO标准受挫
  • 8.VC++下用MSComm控件实现串口通讯
  • 9.伪随机数生成及在VC++中的实现
  • 10.VC++编程实现对波形数据的频谱分析
专题教程
  • 大话G游 专题:手机病毒揭密
  • ARP攻击防范与解决方案 路由故障处理手册
  • Picasa中文版_Picasa教程 专题:清除流氓软件
  • Firefox专题 seo搜索引擎优化专区
  • 重装Windows必知的事情 装机之必备软件大行动
病毒专杀栏
  • 杀毒软件反被病毒杀 连"救命"都不能喊
  • 金山ARP防火墙
  • 还原卡神话破灭“机器狗”病毒来势汹汹
  • cctv经济半小时:你的手机现在安全吗?
  • 新挂马方式开始流行 ARP挂马称雄局域网
  • 木马和病毒清除的通用解法
  • IP地址不再冲突 查找ARP攻击者元凶
  • 教你几招识别和防御Web网页木马
  • 分析:封杀BT只是暂时的止痛药
  • QQ爆危险漏洞,“QQ游戏邀请大盗”邀请你玩病
关于我们 | 诚聘英才 | 联系我们 | 版权声明 | 网站大事 | 网站地图 | 意见建议
CopyRight 2005-2007 Jztop.Com 版权所有 未经许可 请勿转载