首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用RtlAddFunctionTable的SEH处理程序

使用RtlAddFunctionTable的SEH处理程序
EN

Stack Overflow用户
提问于 2015-02-17 04:28:47
回答 2查看 2.8K关注 0票数 1

我一直在尝试通过调用RtlAddFunctionTable在x64 windows上使用gcc设置SEH。不幸的是,API调用返回成功,但我的处理程序似乎从未被调用过。我找不到出了什么问题。我的小例子是:

代码语言:javascript
复制
EXCEPTION_DISPOSITION catchDivZero( struct _EXCEPTION_RECORD* rec
                                  , void* arg1 __attribute__((unused))
                                  , struct _CONTEXT* ctxt __attribute__((unused))
                                  , void* arg2 __attribute__((unused))
                                  )
{
    printf("Exception will be handled!\n");
    return ExceptionContinueSearch;
}

HMODULE GetCurrentModule()
{ // NB: XP+ solution!
    HMODULE hModule = NULL;
    GetModuleHandleEx(
        GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
        (LPCTSTR)GetCurrentModule,
        &hModule);

    return hModule;
}

typedef struct {
    UINT8  Version : 3;
    UINT8  Flags : 5;
    UINT8  SizeOfProlog;
    UINT8  CountOfUnwindCodes;
    UINT8  FrameRegister : 4;
    UINT8  FrameRegisterOffset : 4;
    ULONG  ExceptionHandler;
} UNWIND_INFO;

/* Hack, for bug in ld.  Will be removed soon.  */
#if defined(__GNUC__)
#define __ImageBase __MINGW_LSYMBOL(_image_base__)
#endif

/* Get the end of the text section.  */
extern char etext[] asm("etext");

/* Get the base of the module.       */
/* This symbol is defined by ld.     */
extern IMAGE_DOS_HEADER __ImageBase;

static UNWIND_INFO info[1];
static RUNTIME_FUNCTION handlers[1];

#define base (ULONG)((HINSTANCE)&__ImageBase)

int main()
{
    HANDLE hProcess = GetCurrentProcess();
    HMODULE hModule = GetCurrentModule();

    MODULEINFO mi;
    GetModuleInformation(hProcess, hModule, &mi, sizeof(mi));

    printf( "Module: 0x%.8X (0x%.8X) 0x%.8X |0x%.8X| [0x%.8X] {0x%.8X}\n\n"
          , mi.lpBaseOfDll
          , base
          , (char*)etext
          , mi.SizeOfImage
          , &catchDivZero
          , (ULONG)(&catchDivZero - base)
          );

    printf("Building UNWIND_INFO..\n");

    info[0].Version             = 1;
    info[0].Flags               = UNW_FLAG_EHANDLER;
    info[0].SizeOfProlog        = 0;
    info[0].CountOfUnwindCodes  = 0;
    info[0].FrameRegister       = 0;
    info[0].FrameRegisterOffset = 0;
    info[0].ExceptionHandler    = (ULONG)(&catchDivZero - base);

    printf("Created UNWIND_INFO at {0x%.8X}\n", info[0].ExceptionHandler);

    printf("Building SEH handlers...\n");

    handlers[0].BeginAddress = 0;
    handlers[0].EndAddress   = (ULONG)(etext - base);
    handlers[0].UnwindData   = (ULONG)((char*)info - base);

    printf("Adding SEH handlers to .pdata..\n");
    printf("Handler Unwind: 0x%.8X\n", &info);
    printf( "Handler Info:: s: 0x%.8X, e: 0x%.8X, u: 0x%.8X\n"
          , handlers[0].BeginAddress
          , handlers[0].EndAddress
          , handlers[0].UnwindData
          );

    if (RtlAddFunctionTable(handlers, 1, (DWORD64)base))
    {
        printf("Hook succeeded.\nTesting..\n");
        printf("Things to do: %i\n", 12 / 0);
    }
    else 
    {
        printf("Hook failed\n");
        DWORD result = GetLastError();
        printf("Error code: 0x%.8X\n", result);
    }
}

然而,当被调用时,我得到的输出是:

代码语言:javascript
复制
> .\a.exe
Module: 0x00400000 (0x00400000) 0x00402FF0 |0x00022000| [0x00401530] {0x00001530}

Building UNWIND_INFO..
Created UNWIND_INFO at {0x00001530}
Building SEH handlers...
Adding SEH handlers to .pdata..
Handler Unwind: 0x00407030
Handler Info:: s: 0x00000000, e: 0x00002FF0, u: 0x00007030
Hook succeeded.
Testing..

我的处理程序中的消息永远不会打印。

任何帮助/指示都将不胜感激。

EN

回答 2

Stack Overflow用户

发布于 2019-10-04 06:15:57

RtlAddFunctionTable()添加一个动态函数表;如果基地址已经有一个静态函数表(.pdata节),RtlAddFunctionTable()调用会成功,但静态函数表仍然优先。

您需要在镜像范围之外分配内存,例如使用VirtualAlloc(),并将您的代码和运行表以及展开信息放在那里。已分配内存的地址是表中所有RVA的基地址,需要传递给RtlAddFunctionTable()。

您可以尝试使用RtlLookupFunctionEntry()来查看是否找到了给定地址的函数表条目。

https://pmeerw.net/blog/programming/RtlAddFunctionTable.html上显示了RtlAddFunctionTable()实际运行的示例代码。

票数 3
EN

Stack Overflow用户

发布于 2016-06-02 01:15:54

你是不是忘了把你的处理程序注册到SetUnhandledExceptionFilter (如果你按照你的帖子所说的那样使用了SEH )或者AddVectoredExceptionHandler (如果你决定切换到VEH )?在您的代码中添加有关处理程序的信息,但不注册它。

我已经用处理程序本身的变化测试了你的样本:

代码语言:javascript
复制
LONG WINAPI catchDivZero(EXCEPTION_POINTERS * ExceptionInfo)
{
    printf("Exception will be handled!\n");
    return ExceptionContinueSearch;
}

并添加代码:

代码语言:javascript
复制
if (::AddVectoredExceptionHandler(TRUE, catchDivZero))
{
    printf("Set exception handler.\nContinuing..\n");
}
else
{
    printf("Setting exception handler failed\n");
    DWORD result = GetLastError();
    printf("Error code: 0x%.8X\n", result);

    return 1;
}

就在调用RtlAddFunctionTable之前。

现在,来自处理程序的消息被打印出来。

要删除处理程序,请使用:

代码语言:javascript
复制
::RemoveVectoredExceptionHandler(catchDivZero);

希望能有所帮助。

注意:作为一种替代方案,您可以使用SetUnhandledExceptionFilter(catchDivZero))。请记住,它是not that useful for debugging

调用此函数后,如果在未调试的进程中发生异常,并且该异常通过了未处理的异常筛选器,则该筛选器将调用lpTopLevelExceptionFilter参数指定的异常筛选器函数。

使用VEH方式,我们可以在IDE中调试处理程序函数,而使用SEH则不能(可能有解决方案,但我不知道),所以我建议使用VEH作为主要解决方案。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28549775

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档