1

我一直在尝试通过调用RtlAddFunctionTable. 不幸的是,API 调用返回成功,但我的处理程序似乎从未被调用过。而且我不知道出了什么问题。我的小例子是:

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);
    }
}

但是,当调用我得到的输出是:

> .\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..

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

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

4

2 回答 2

3

RtlAddFunctionTable() 添加动态函数表;如果基地址已经存在静态函数表(.pdata 部分),则 RtlAddFunctionTable() 调用成功,但静态函数表仍然优先。

您需要在图像范围之外分配内存,例如使用 VirtualAlloc(),并在此处保存您的代码和运行时表和展开信息。分配的内存地址是表中所有 RVA 的基地址,需要传递给 RtlAddFunctionTable()。

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

显示 RtlAddFunctionTable() 的示例代码位于https://pmeerw.net/blog/programming/RtlAddFunctionTable.html

于 2019-10-03T22:15:57.120 回答
0

您是否忘记使用调用注册您的处理程序SetUnhandledExceptionFilter(如果您使用帖子中所述的 SEH)或AddVectoredExceptionHandler(如果您决定切换到VEH)?在您的代码中,您添加有关处理程序的信息,但不注册它。

我已经通过更改处理程序本身测试了您的样本:

LONG WINAPI catchDivZero(EXCEPTION_POINTERS * ExceptionInfo)
{
    printf("Exception will be handled!\n");
    return ExceptionContinueSearch;
}

并添加代码:

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.

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

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

::RemoveVectoredExceptionHandler(catchDivZero);

希望能帮助到你。

注意:作为替代方案,您可以使用SetUnhandledExceptionFilter(catchDivZero)). 请记住,它对调试没有那么有用

调用该函数后,如果一个未被调试的进程 发生异常,并且该异常进入未处理异常过滤器,该过滤器将调用lpTopLevelExceptionFilter参数指定的异常过滤器函数。

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

于 2016-06-01T17:15:54.333 回答