在Win 7上是否可以设置单步陷阱? [英] Is set single step trap available on win 7?

查看:103
本文介绍了在Win 7上是否可以设置单步陷阱?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在做一个所谓的"seh钩".实际上,它会更改内存区域的权限并在访问它时捕获异常,因此可以挂接该函数.

它使用如下所示的单步陷阱:

info->ContextRecord->EFlags |= 0x100;

将保护恢复到PAGE_NOACCESS.

该应用在win xp上运行良好,但在win 7上却没有例外.在win 7上它被冻结了.我非常怀疑这是因为设置了单步陷阱",但我不确定. >

解决方案

简短答案:

是的,单步标记是x86体系结构的一部分,并且仍通过处理器上下文的eflags组件在Windows 7中实现.

我已经成功下载了您的项目,并且在关闭UAC的情况下在Windows 8上进行了任何修改都可以正常工作.因此它也可以在Windows 7上运行.启动VEH Hooking Test.exe时,它将显示两个消息框,每显示一个消息框后,我就会获得MessageBoxA控制台输出,因此该钩子起作用了.也许尝试在Windows 7上以管理员身份启动程序?


长答案:

SEH代表结构化异常处理,但是您所描述的听起来更像是VEH-矢量化异常处理.

VEH挂钩是一种非常慢的挂钩方法,因此它不能真正用于性能至关重要的挂钩,例如图形挂钩,例如您的挂钩每秒击中多次.通常用于一次钩子. VEH挂钩的目的是真正隐身.没有用别人的代码写的内存,您也不必使用调试寄存器.


以下是我如何使用c ++来实现它.

首先,您必须注册向量异常处理程序.这是该过程的全局异常处理程序.此处理程序将捕获所有未处理的异常并将落入操作系统的所有抛出异常.

PVOID pExHandler = AddVectoredExceptionHandler(1, VectoredHandler);

在此之后,您应该设置HOOK_LOCATION(要挂接的地址)所在页面的内存保护.我正在使用的新保护是PAGE_EXECUTE_READ|PAGE_GUARD.受保护的页面将导致访问异常,并在此之后自动删除保护.任何人都不会处理此异常,因此它将落入我们的矢量处理程序.引发异常后,可以再次访问该页面. (请参见创建防护页)

只能在页面中保护内存(通常为0x1000字节长).这就是为什么我们不仅可以保护钩子位置而且拥有巨大的性能开销的原因.

DWORD orgProt;
VirtualProtect(HOOK_LOCATION, 1, PAGE_EXECUTE_READ|PAGE_GUARD, &orgProt);

现在是我们的异常处理程序.看起来像这样:

LONG CALLBACK VectoredHandler(PEXCEPTION_POINTERS exc)
{
    if (exc->ExceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION)
    {
        // guard page exeption occured. guard page protection is gone now

        if (HOOK_LOCATION == reinterpret_cast<long*>(exc->ContextRecord->Eip)) {
            // hook location was hit! call any hook callbacks here
        } else {
            // hook was not hit and has to be refreshed. set single-step flag
            exc->ContextRecord->EFlags |= 0x100;
        }

        return EXCEPTION_CONTINUE_EXECUTION;
    }

    if (exc->ExceptionRecord->ExceptionCode == STATUS_SINGLE_STEP)
    {
        // single-step exeption occured. single-step flag is cleared now

        // set guard page protection
        DWORD oldProt;
        VirtualProtect(HOOK_LOCATION, 1, PAGE_EXECUTE_READ|PAGE_GUARD, &oldProt);

        return EXCEPTION_CONTINUE_EXECUTION;
    }

    return EXCEPTION_CONTINUE_SEARCH;
}

如果代码运行到受保护的内存页面中,它将抛出保护页面冲突.我们检查是否在挂钩位置.如果一切正常,我们可以调用钩子回调.如果我们不在正确的位置,则需要以某种方式重新保护代码,但是如果现在执行此操作,则无法前进,并且总是在同一位置获得异常并死锁应用程序.因此,我们将处理器设置为单步标记.

现在,当接收到单步异常时,因为我们前进了一条指令,所以我们可以再次设置防护保护.这样我们就可以始终保护目标页面,而不会错过任何钩子命中.

代价是在目标页面中执行的每条指令有两个例外和一个页面保护.不要尝试在附加调试器的情况下执行此操作.会发疯的.

对于实际的实现,您可能需要同步对象来摆脱钩子,而不会导致程序崩溃和更好的钩子管理.

我真的很喜欢这种聪明的机制,希望有人对此有所了解.

I was doing with a so called 'seh hooking'. Actually it changes permission of region of memory and catches the exception when it gets accessed, so it can hook the function.

It uses the single step trap which looks like:

info->ContextRecord->EFlags |= 0x100;

to resume the protection to PAGE_NOACCESS.

The app run well on win xp but not as excepted on win 7. It just got frozen on win 7. I highly doubt it is because of the 'set single step trap' thing, but I am not sure.

Click here to the direct download link of the source package

解决方案

Short answer:

Yes the single step flag is part of the x86 achitecture and also still implemented in windows 7 via the eflags component of the processor context.

I have managed to download your project and everything works fine without modifications on Windows 8 with UAC turned off. So it should work on Windows 7, too. When starting VEH Hooking Test.exe it displays two message boxes, after each one I get MessageBoxA console output, so the hook worked. Maybe try starting the program as admin on Windows 7?


Long answer:

SEH stands for structured exception handling, but what you are describing sounds more like VEH - vectored exception handling.

VEH hooking is a hooking method that is really damn slow, so it can't really be used in performance critical hooks, like graphics hook for example where your hooks hits multiple times per second. It is usually used for one time hooks. The purpose of VEH hooking is to be really stealthy. There is no memory written in someone elses code and you don't have to use debug registers.


The following is how I would implement it using c++.

First you have to register a vectored exceptionhandler. This is a global exception handler for the process. Every thrown exception that were unhandled and would fall through to the operating system will be caught by this handler.

PVOID pExHandler = AddVectoredExceptionHandler(1, VectoredHandler);

After this you should set the memory protection of the page where your HOOK_LOCATION (the address to hook) is in. The new protection I'm using is PAGE_EXECUTE_READ|PAGE_GUARD. A guarded page will cause an exception on access and will remove the guard protection after that automaticly. This exception will not be handled by anyone, so it will fall through to our vectored handler. After the exception is thrown, the page is accessible again. (see Creating Guard Pages)

Memory can only be protected in pages (usually 0x1000 bytes long). This is why we can't only protect the hook location and have the massive performance overhead.

DWORD orgProt;
VirtualProtect(HOOK_LOCATION, 1, PAGE_EXECUTE_READ|PAGE_GUARD, &orgProt);

Now for our exception handler. This is how it could look like:

LONG CALLBACK VectoredHandler(PEXCEPTION_POINTERS exc)
{
    if (exc->ExceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION)
    {
        // guard page exeption occured. guard page protection is gone now

        if (HOOK_LOCATION == reinterpret_cast<long*>(exc->ContextRecord->Eip)) {
            // hook location was hit! call any hook callbacks here
        } else {
            // hook was not hit and has to be refreshed. set single-step flag
            exc->ContextRecord->EFlags |= 0x100;
        }

        return EXCEPTION_CONTINUE_EXECUTION;
    }

    if (exc->ExceptionRecord->ExceptionCode == STATUS_SINGLE_STEP)
    {
        // single-step exeption occured. single-step flag is cleared now

        // set guard page protection
        DWORD oldProt;
        VirtualProtect(HOOK_LOCATION, 1, PAGE_EXECUTE_READ|PAGE_GUARD, &oldProt);

        return EXCEPTION_CONTINUE_EXECUTION;
    }

    return EXCEPTION_CONTINUE_SEARCH;
}

If code runs into the protected memory page, it will throw the guard page violation. We check if we were at the hook location. If we are everything is fine and we can call the hook callback. If we are not at the correct location we somehow need to reprotect the code, but if we would do it now, we could not advance and always get an exception on the same location and deadlock the application. So we set the processor single step flag.

Now when recieving the single step exception, we can set the guard protection again, because we advanced by one instruction. This is how we can always have the target page protected and not miss any hook hits.

The cost is two exceptions and one page protection per instruction that gets executed in the target page. Don't try to do this with a debugger attached. It will go crazy.

For an actual implementation you may need synchronisation objects to get rid of the hook without crashing the program and better hook managing.

I really like this clever mechanism and hope some people learned a bit about it.

这篇关于在Win 7上是否可以设置单步陷阱?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆