• 学习windows 应用层 inline hook 原理总结


    inline hook 实际上就是指 通过改变目标函数头部的代码来使改变后的代码跳转到我们自己设置的一个函数里,产生hook。

    今天就拿MessageBoxA这个api函数来做实验。功能就是当程序调用MessageBoxA 时,我们打印出MessageBoxA的参数

    大概代码结构应该是这样

    typedef int (WINAPI
        *MessageBox_type) (
        __in_opt HWND hWnd,
        __in_opt LPCSTR lpText,
        __in_opt LPCSTR lpCaption,
        __in UINT uType) ;
    
    MessageBox_type RealMessageBox;
    
    //我们自己的MessageBox,每调用MessageBox都要跳到myMessageBox来处理
    int WINAPI
        myMessageBox(
        __in_opt HWND hWnd,
        __in_opt LPCSTR lpText,
        __in_opt LPCSTR lpCaption,
        __in UINT uType)
    {
        //下面打印MessageBox参数
        printf("hwnd:%8X lpText:%s lpCaption:%s,uType:%8X",hWnd,lpText,lpCaption,uType); 
        return RealMessageBox(hWnd,lpText,lpCaption,uType); //现在开始调用真正的MessageBox
    }
    
    VOID HookMessageBoxA()
    {
    
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        HookMessageBoxA();  //hook操作
        ::MessageBoxA(NULL,"hook test","tip",MB_OK); //执行api MessageBox
        return 0;
    }

    我们先看看汇编是怎样调用MessageBoxA的

    MessageBox流程

    首先看到,MessageBoxA里面

    mov edi,edi
    mov ebp
    mov ebp,esp
    刚好是5个字节,5个字节可以做一个远jmp

    直接汇编改成我们自己的jmp

    改后结果如下

    image

    单步执行发现hook成功。但程序崩溃。原因主要是由于

    我们破坏了真正的MessageBox使们想要调用真正的MessageBox时也会调用失败了,所以我们要调用真正的MessageBox时要加上头部被我们换掉的部分,我们要内联汇编,里面不能含有编译器自动添加的代码,所以在myMessageBox头部要加上 _declspec(naked)

    vs2010的debug版本每执行一个函数都要 cmp esi,esp 来验证堆栈的。所以还要加一句push esi 和pop esi

    //我们自己的MessageBox,每调用MessageBox都要跳到myMessageBox来处理
    _declspec(naked)  void WINAPI
        myMessageBox(
        __in_opt HWND hWnd,
        __in_opt LPCSTR lpText,
        __in_opt LPCSTR lpCaption,
        __in UINT uType)
    {
            __asm
        {
            PUSH ebp
            mov ebp,esp
    
            /*
            vs2010 debug 编译后的代码由于要cmp esi esp来比较堆栈。
            所以这里在调用非__asm函数前push一下esi
            */
            push esi
        }
        //下面打印MessageBox参数
        printf("hwnd:%8X lpText:%s lpCaption:%s,uType:%8X",hWnd,lpText,lpCaption,uType); 
    
        __asm
        {
            /*
            vs2010 debug 编译后的代码由于要cmp esi esp来比较堆栈。
            所以这里在调用非__asm函数前push一下esi
            */
            pop esi
    
            mov ebx,RealMessageBox
            add ebx,5
            jmp ebx
        }
    }

    下面说一下用代码来写MessageBoxA着呢5个字节

    首先要懂得 JMP指令转换公式推导  不懂的话 看 http://www.cnblogs.com/zhangdongsheng/archive/2012/12/06/2804234.html

    先声明一个JMP结构体。注意前面加 #pragma pack(1)来避免内存对齐的一些规则

    #pragma pack(1)
    typedef struct _JMPCODE
    {
        BYTE jmp;
        DWORD addr;
    }JMPCODE,*PJMPCODE;

    接下来写hook函数

    VOID HookMessageBoxA()
    {
        JMPCODE jcode;
        jcode.jmp = 0xe9;//jmp
        jcode.addr = (DWORD)myMessageBox - (DWORD)RealMessageBox - 5; 
    
        RealMessageBox = MessageBoxA;
        ::WriteProcessMemory(GetCurrentProcess(),MessageBoxA,&jcode,sizeof(JMPCODE),NULL);
    }

    现在测试成功。

    image

    完整源代码如下:

    // hook_blog_writer.cpp : 定义控制台应用程序的入口点。
    //
    
    #include "stdafx.h"
    #include <windows.h>
    #include <stdio.h>
    
    typedef int (WINAPI
        *MessageBox_type) (
        __in_opt HWND hWnd,
        __in_opt LPCSTR lpText,
        __in_opt LPCSTR lpCaption,
        __in UINT uType) ;
    
    MessageBox_type RealMessageBox = MessageBoxA;
    
    //我们自己的MessageBox,每调用MessageBox都要跳到myMessageBox来处理
    _declspec(naked)  void WINAPI
        myMessageBox(
        __in_opt HWND hWnd,
        __in_opt LPCSTR lpText,
        __in_opt LPCSTR lpCaption,
        __in UINT uType)
    {
            __asm
        {
            PUSH ebp
            mov ebp,esp
    
            /*
            vs2010 debug 编译后的代码由于要cmp esi esp来比较堆栈。
            所以这里在调用非__asm函数前push一下esi
            */
            push esi
        }
        //下面打印MessageBox参数
        printf("hwnd:%8X lpText:%s lpCaption:%s,uType:%8X",hWnd,lpText,lpCaption,uType); 
    
        __asm
        {
            /*
            vs2010 debug 编译后的代码由于要cmp esi esp来比较堆栈。
            所以这里在调用非__asm函数前push一下esi
            */
            pop esi
    
            mov ebx,RealMessageBox
            add ebx,5
            jmp ebx
        }
    }
    
    
    #pragma pack(1)
    typedef struct _JMPCODE
    {
        BYTE jmp;
        DWORD addr;
    }JMPCODE,*PJMPCODE;
    
    VOID HookMessageBoxA()
    {
        JMPCODE jcode;
        jcode.jmp = 0xe9;//jmp
        jcode.addr = (DWORD)myMessageBox - (DWORD)RealMessageBox - 5; 
    
        RealMessageBox = MessageBoxA;
        ::WriteProcessMemory(GetCurrentProcess(),MessageBoxA,&jcode,sizeof(JMPCODE),NULL);
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        HookMessageBoxA();  //hook操作
        ::MessageBoxA(NULL,"hook test","tip",MB_OK); //执行api MessageBox
        return 0;
    }
    本人新博客网址为:http://www.hizds.com
    本博客注有“转”字样的为转载文章,其余为本人原创文章,转载请务必注明出处或保存此段。c++/lua/windows逆向交流群:69148232
  • 相关阅读:
    Linux中批量添加文件和修改文件小笔记
    scp 命令快速使用讲解
    使用Apache Spark 对 mysql 调优 查询速度提升10倍以上
    阿里云CentOS-7.2安装mysql
    yum安装网络配置图形界面
    忘记了root密码,如何进入系统?
    Linux学习之竿头直上
    Linux命令之初出茅庐
    Linux学习之要点必备
    阿里云CentOS7.2服务器的安装
  • 原文地址:https://www.cnblogs.com/zhangdongsheng/p/3007154.html
Copyright © 2020-2023  润新知