今天在找如何在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函數的目標。
從上述程序的彙編代碼運行上可以更清晰地看到結果,如下所示
以上就是本博客的全文,本人限於能力,上文中難免有錯誤的地方,若讀者發現上文的錯誤,請於評論區中指出,本人看到之後會立即修改的,謝謝。