今天在找如何在Windows上编译breakpad的答案时,看到了这个博客:https://www.cnblogs.com/cswuyg/p/3207576.html。在这个博客的代码中学到了点东西,现在就来记录一下。
talk is cheap show me the code.先上代码好了,下面的代码是我从上面的博客上精简下来的测试代码,如下
#include <Windows.h>
#include <iostream>
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI TempSetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
{
std::cout << "TempSetUnhandledExceptionFilter\n";
return NULL;
}
BOOL PreventSetUnhandledExceptionFilter()
{
HMODULE hKernel32 = LoadLibrary(L"kernel32.dll");
if (hKernel32 == NULL)
{
return FALSE;
}
void *pOrgEntry = ::GetProcAddress(hKernel32, "SetUnhandledExceptionFilter");
if (pOrgEntry == NULL)
{
return FALSE;
}
unsigned char newJump[5];
DWORD dwOrgEntryAddr = (DWORD)pOrgEntry;
dwOrgEntryAddr += 5; //跳转指令使用5字节的空间
void *pNewFunc = &TempSetUnhandledExceptionFilter;
DWORD dwNewEntryAddr = (DWORD)pNewFunc;
DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr;
newJump[0] = 0xE9; //jump
memcpy(&newJump[1], &dwRelativeAddr, sizeof(DWORD));
SIZE_T bytesWritten;
DWORD dwOldFlag, dwTempFlag;
::VirtualProtect(pOrgEntry, 5, PAGE_READWRITE, &dwOldFlag);
BOOL bRet = ::WriteProcessMemory(::GetCurrentProcess(), pOrgEntry, newJump, 5, &bytesWritten);
::VirtualProtect(pOrgEntry, 5, dwOldFlag, &dwTempFlag);
return bRet;
}
int main()
{
PreventSetUnhandledExceptionFilter();
SetUnhandledExceptionFilter(NULL);
return 0;
}
上述代码的功能很简单,在PreventSetUnhandledExceptionFilter函数中,先找到SetUnhandledExceptionFilter函数在进程中的地址+5的值,为什么要+5呢,因为这五个字节要存放汇编的跳转指令E9 地址;然后获取TempSetUnhandledExceptionFilter函数的在进程中的地址值,接着计算上面两个值的差,最后把汇编的跳转指令写入到SetUnhandledExceptionFilter函数的地址。造成的结果就是,当在main函数中执行SetUnhandledExceptionFilter时,程序会跳转到SetUnhandledExceptionFilter地址的位置开始执行,然后执行E9 地址汇编指令再跳转到TempSetUnhandledExceptionFilter函数的位置执行,这样就达到了屏蔽SetUnhandledExceptionFilter函数的目标。
从上述程序的汇编代码运行上可以更清晰地看到结果,如下所示
以上就是本博客的全文,本人限于能力,上文中难免有错误的地方,若读者发现上文的错误,请于评论区中指出,本人看到之后会立即修改的,谢谢。