#include <Windows.h>
#include <winnt.h>
#include <Dbghelp.h>
#include <excpt.h>
#include <ehdata.h>
#include <exception>
#include <iostream>
#include <thread>
#pragma comment(lib, "Dbghelp.lib")
__declspec(noreturn) extern "C" void __stdcall
#if !defined(_M_ARM) || defined(_M_ARM_NT)
_JCxxThrowException(
#else
_JCxxThrowException(
#endif
void* pExceptionObject, // The object thrown
ThrowInfo * pThrowInfo // Everything we need to know about it
)
{
//EHTRACE_ENTER_FMT1("Throwing object @ 0x%p", pExceptionObject);
static const EHExceptionRecord ExceptionTemplate = { // A generic exception record
EH_EXCEPTION_NUMBER, // Exception number
EXCEPTION_NONCONTINUABLE, // Exception flags (we don't do resume)
NULL, // Additional record (none)
NULL, // Address of exception (OS fills in)
EH_EXCEPTION_PARAMETERS, // Number of parameters
{
EH_MAGIC_NUMBER1, // Our version control magic number
NULL, // pExceptionObject
NULL,
#if _EH_RELATIVE_OFFSETS
NULL // Image base of thrown object
#endif
} // pThrowInfo
};
EHExceptionRecord ThisException = ExceptionTemplate; // This exception
ThrowInfo* pTI = (ThrowInfo*)pThrowInfo;
ThisException.params.pExceptionObject = pExceptionObject;
ThisException.params.pThrowInfo = pTI;
#if _EH_RELATIVE_OFFSETS
PVOID ThrowImageBase = RtlPcToFileHeader((PVOID)pTI, &ThrowImageBase);
ThisException.params.pThrowImageBase = ThrowImageBase;
#endif
if (pTI != NULL)
{
if (THROW_ISPURE(*pTI))
{
ThisException.params.magicNumber = EH_PURE_MAGIC_NUMBER1;
}
#if _EH_RELATIVE_OFFSETS
else if (ThrowImageBase == NULL)
{
ThisException.params.magicNumber = EH_PURE_MAGIC_NUMBER1;
}
#endif
}
#if defined(_M_X64) && defined(_NTSUBSET_)
RtlRaiseException((PEXCEPTION_RECORD)&ThisException);
#else
RaiseException(ThisException.ExceptionCode,
ThisException.ExceptionFlags,
ThisException.NumberParameters,
(PULONG_PTR)&ThisException.params);
#endif
}
void getSelfContext()
{
DWORD id = ::GetCurrentThreadId();
static bool b = false;
HANDLE h = OpenThread(
THREAD_ALL_ACCESS,
TRUE,
id
); //获得真实句柄
std::thread _th([=] {
::SuspendThread(h);
CONTEXT ctx = { 0 };
::GetThreadContext(h, &ctx);
MINIDUMP_EXCEPTION_INFORMATION eInfo;
EXCEPTION_POINTERS excpInfo;
excpInfo.ExceptionRecord = NULL;
excpInfo.ContextRecord = &ctx;
eInfo.ThreadId = GetCurrentThreadId();
eInfo.ExceptionPointers = &excpInfo;
eInfo.ClientPointers = FALSE;
HANDLE hFile = CreateFile(L"MiniDump.dmp", GENERIC_READ | GENERIC_WRITE,
0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
::MiniDumpWriteDump(
GetCurrentProcess(),
GetCurrentProcessId(),
hFile,
MiniDumpNormal,
&eInfo,
NULL,
NULL);
::CloseHandle(hFile);
::ResumeThread(h);
b = true;
});
_th.detach();
while (!b)
::Sleep(200);
}
void XX()
{
std::cout << "inside it" << std::endl;
std::exception exp("what is the matter?");
throw exp;
}
bool JmpHook(unsigned char* func, unsigned char* dst)
{
char original_bytes[16] = { 0 };
DWORD old_protection;
if (0 == VirtualProtect(func, 1024, PAGE_EXECUTE_READWRITE, &old_protection))
return false;
memcpy(original_bytes, dst, sizeof(void*) == 4 ? 5 : 14);
#if defined(_M_X64) || defined(__amd64__) // x86_64
func[0] = 0xFF; // absolute jmp
func[1] = 0x25; // absolute jmp
*(uint32_t*)(func + 2) = 0;
*(uint64_t*)(func + 6) = (uint64_t)dst;
#else
*(unsigned char*)func = (char)0xE9; //relative jmp near instruction
*(uint32_t*)((unsigned char*)func + 1) = (unsigned char*)dst - (unsigned char*)func - 5;
#endif
#if defined(_WIN32)
if (!VirtualProtect(func, 1024, old_protection, &old_protection))
{
memcpy(func, original_bytes, sizeof(void*) == 4 ? 5 : 14);
return false;
}
#endif
return true;
}
VOID WINAPI CXXThrowExcept(void* a, void* b)
{
getSelfContext();
std::exception* e = dynamic_cast<std::exception*>((std::exception*)a); //正确
if (e)
std::cout << e->what() << std::endl;
_JCxxThrowException(a, (ThrowInfo*)b);
}
int main()
{
#ifdef _DEBUG
auto hRun = GetModuleHandleA("vcruntime140d.dll");
#else
auto hRun= GetModuleHandleA("vcruntime140.dll");
#endif
if (nullptr == hRun)
{
std::cout << "couldn't find Kernel32.dll" << std::endl;
return EXIT_FAILURE;
}
auto addr = GetProcAddress(hRun, "_CxxThrowException");
JmpHook((unsigned char*)addr, (unsigned char*)CXXThrowExcept);
try
{
XX();
}
catch(std::exception& e)
{
std::cout << e.what() << std::endl;
}
return 0;
}
|