lengshizai 2024-02-27 20:02 采纳率: 31.7%
浏览 2
已结题

学习汇编hook保护遇到的问题

由于不知道该插入哪一个板块,就随便插入一个了,不影响观看即可
问题:学习汇编hook过程中自己的hook影响到堆栈导致程序崩溃
请求指出问题 并知道相应的解决办法 并作出解释帮助学习
备注已表明要hook 的点

另请求讲解 涉及到多余 5字节 的那一部分字节的处理办法。

0063B39E   | 8B16              | mov     edx, dword ptr [esi]                |
0063B3A0   | 51                | push    ecx                                 |
0063B3A1   | 8B4C24 0C         | mov     ecx, dword ptr [esp+C]              |//假定这里是我需要hook的点   但是下方是一个push 改变堆栈了
0063B3A5   | 51                | push    ecx                                 |
0063B3A6   | 50                | push    eax                                 |
0063B3A7   | 8BCE              | mov     ecx, esi                            |
0063B3A9   | FF92 4C100000     | call    dword ptr [edx+104C]                | 
0063B3AF   | 5F                | pop     edi                                 |

下面是hook的相关代码:

__declspec(naked) void 跳转提示HOOK成功() 
{
    _asm 
    {    
        pushad
    }

    printf("11111\n");

    _asm 
    {
        popad
        mov     ecx, dword ptr[esp + 0xC]
        push ecx
        retn        
    }

}
void HOOK测试()
{
  
        //这里是要hook地址处的原代码:
    //0063B3A1 | 8B4C24 0C   | mov     ecx, dword ptr[esp + C] |
    //0063B3A5 | 51             | push    ecx |



    DWORD Hook地址 = 0x0063B3A1;


    DWORD Hook子程序指针 = (DWORD)跳转call;
    DWORD 跳转值 = Hook子程序指针 - Hook地址 - 5;

    DWORD old = 0;//存放原来的属性
    VirtualProtect((PVOID)0x0063B3A1, 32, PAGE_EXECUTE_READWRITE, &old);
    //修改内存

    *(BYTE*)Hook地址 = 0xE8;
    *(DWORD*)(Hook地址 + 0x1) = 跳转值;

    VirtualProtect((PVOID)Hook地址, 32, old, &old);//恢复页面属性



}
void UnHOOK测试()
{

    DWORD Hook地址 = 0x0063B3A1;

    DWORD old = 0;//存放原来的属性
    VirtualProtect((PVOID)Hook地址, 32, PAGE_EXECUTE_READWRITE, &old);
    *(BYTE*)Hook地址 = 0x8B;
    *(DWORD*)(Hook地址 + 0x1) = 0x510C244C;


    VirtualProtect((PVOID)Hook地址, 32, old, &old);//恢复页面属性

}

下方是hook后 代码的变化;

0063B39A   | 8B4C24 10         | mov     ecx, dword ptr [esp+10]             |
0063B39E   | 8B16              | mov     edx, dword ptr [esi]                |
0063B3A0   | 51                | push    ecx                                 |
0063B3A1   | E8 0A6DFD6E       | call    commondll.6F6120B0                  |//自己的hook跳转函数
0063B3A6   | 50                | push    eax                                 |
0063B3A7   | 8BCE              | mov     ecx, esi                            |
0063B3A9   | FF92 4C100000     | call    dword ptr [edx+104C]                | 
0063B3AF   | 5F                | pop     edi                                 |

下方是hook跳转函数内部

6F6120B0   | 60                | pushad                                      |
6F6120B1   | 68 8453616F       | push    commondll.6F615384                  | 6F615384:"11111\n"
6F6120B6   | E8 25000000       | call    6F6120E0                            |
6F6120BB   | 83C4 04           | add     esp, 4                              |
6F6120BE   | 61                | popad                                       |
6F6120BF   | 8B4C24 0C         | mov     ecx, dword ptr [esp+C]              |
6F6120C3   | 51                | push    ecx                                 |
6F6120C4   | C3                | ret                                         |


我hook之后发现 一旦相关运行涉及到我的hook程序即崩溃,请协助查找 并讲解原因
并提出解决办法加以解释。
想要达成的目的:hook 目标地址 ,加入一个打印提示 :“111111”即提示hook成功。
目前的情况是可以打印出11111 但是随机程序崩溃

  • 写回答

4条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-02-27 20:03
    关注

    引自免费微信小程序:皆我百晓生

    在你提供的汇编代码片段中,你试图Hook的指令是在将ecx的值压入堆栈(push ecx)之前读取它的一个偏移量。而在你的Hook函数实现中,你替换了一条跳转指令(E8),并期望在Hook子程序执行完毕后恢复原始流程。但是,你的Hook子程序没有正确处理堆栈平衡,这是导致程序崩溃的主要原因。

    问题分析:

    1. 在Hook子程序中,你首先保存了所有寄存器(pushad),然后打印信息。
    2. 打印之后,你恢复了所有的寄存器(popad),这会恢复ecx的值,但此时堆栈深度与原始代码不匹配,因为原始代码在这之后还有一个push ecx操作。
    3. 你尝试手动推送ECX到堆栈以模拟原始行为,但由于pushadpopad的影响,堆栈可能已经不对齐,所以这个操作可能导致堆栈混乱。

    解决办法:

    为了正确地进行Hook,并在不影响堆栈平衡的情况下插入你的提示消息,你需要确保Hook子程序能够模拟原始函数的行为,即:

    • 保存原始函数需要的所有寄存器内容
    • 执行你的hook操作(如打印消息)
    • 恢复堆栈到调用前的状态
    • 跳转回原始函数的下一条指令

    下面是一个修改后的Hook子程序示例:

    __declspec(naked) void 跳转提示HOOK成功() 
    {
        _asm 
        {    
            push ebp
            mov ebp, esp
            sub esp, 4 // 为局部变量预留空间(如果需要)
    
            // 保存原始堆栈上的ecx
            push ecx
            
            // 执行你的hook操作
            push offset promptMsg ;// promptMsg是你要打印的消息字符串
            call printf
            add esp, 4 // 清理printf参数占用的堆栈空间
    
            // 恢复ecx到堆栈上
            pop ecx
            
            // 恢复堆栈指针到原始位置
            leave
            retn        
        }
    
        const char* promptMsg = "11111\n";
    }
    

    同时,请注意,在实际Hook过程中,除了修改第一条指令为跳转指令外,还需要计算好跳转地址,并确保跳转后能准确返回到原函数的下一条指令。另外,使用VirtualProtect进行内存保护时,要确保Hook前后页面属性的一致性。

    这样修改后,你的Hook子程序就能在不破坏堆栈平衡的前提下插入所需的操作,并且在完成后能顺利回到原函数继续执行。

    评论 编辑记录

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 2月27日
  • 修改了问题 2月27日
  • 修改了问题 2月27日
  • 创建了问题 2月27日

悬赏问题

  • ¥15 软件工程用例图的建立(相关搜索:软件工程用例图|画图)
  • ¥15 如何在arcgis中导出拓扑关系表
  • ¥15 处理数据集文本挖掘代码
  • ¥15 matlab2017
  • ¥15 在vxWorks下TCP/IP编程,总是connect()报错,连接服务器失败: errno = 0x41
  • ¥15 AnolisOs7.9如何安装 Qt_5.14.2的运行库
  • ¥20 求:怎么实现qt与pcie通信
  • ¥50 前后端数据顺序不一致问题,如何解决?(相关搜索:数据结构)
  • ¥15 基于蒙特卡罗法的中介效应点估计代码
  • ¥15 罗技G293和UE5.3