#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")
typedef void(__stdcall* PFNPREPARE_FOR_THROW)(void* ExceptionInfo);
typedef struct WinRTExceptionInfo
{
void* description;
void* restrictedErrorString;
void* restrictedErrorReference;
void* capabilitySid;
long hr;
void* restrictedInfo;
ThrowInfo* throwInfo;
unsigned int size;
PFNPREPARE_FOR_THROW PrepareThrow;
} WINRTEXCEPTIONINFO;
namespace foundation
{
static void getExceptContext(bool);
void ReportExcept(unsigned long code, PEXCEPTION_POINTERS excpInfo)
{
getExceptContext(true);
}
#if 0
__declspec(noreturn) extern "C" void __stdcall
jCxxThrowException(
void* pExceptionObject, // The object thrown
ThrowInfo * pThrowInfo // Everything we need to know about it
)
{
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
ThisException.params.magicNumber = EH_MAGIC_NUMBER1;
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
}
#else
//平台工具集V142 【vs2019】!!!
extern "C" __declspec(noreturn) void __stdcall jCxxThrowException(
void* pExceptionObject, // The object thrown
void* pThrowInfo // Everything we need to know about it
) {
//EHTRACE_FMT1("Throwing object @ 0x%p", pExceptionObject);
auto pTI = reinterpret_cast<ThrowInfo*>(pThrowInfo);
ULONG_PTR magicNumber = EH_MAGIC_NUMBER1;
if (pTI && (pTI->attributes & TI_IsWinRT)) {
// The pointer to the ExceptionInfo structure is stored sizeof(void*) in front of each WinRT Exception Info.
WINRTEXCEPTIONINFO** ppWei = *static_cast<WINRTEXCEPTIONINFO***>(pExceptionObject);
--ppWei;
const auto pWei = *ppWei;
pTI = pWei->throwInfo;
pWei->PrepareThrow(ppWei);
}
#if _EH_RELATIVE_TYPEINFO
void* throwImageBase = RtlPcToFileHeader(const_cast<void*>(static_cast<const void*>(pTI)), &throwImageBase);
#endif // _EH_RELATIVE_TYPEINFO
// If the throw info indicates this throw is from a pure region,
// set the magic number to the Pure one, so only a pure-region
// catch will see it.
//
// Also use the Pure magic number on Win64 if we were unable to
// determine an image base, since that was the old way to determine
// a pure throw, before the TI_IsPure bit was added to the FuncInfo
// attributes field.
if (pTI && ((pTI->attributes & TI_IsPure)
#if _EH_RELATIVE_TYPEINFO
|| !throwImageBase
#endif // _EH_RELATIVE_TYPEINFO
)) {
magicNumber = EH_PURE_MAGIC_NUMBER1;
}
// Build the parameters for the EHExceptionRecord:
const ULONG_PTR parameters[] = {
magicNumber,
reinterpret_cast<ULONG_PTR>(pExceptionObject),
reinterpret_cast<ULONG_PTR>(pTI),
#if _EH_RELATIVE_TYPEINFO
reinterpret_cast<ULONG_PTR>(throwImageBase),
#endif // _EH_RELATIVE_TYPEINFO
};
// Hand it off to the OS:
RaiseException(EH_EXCEPTION_NUMBER, EXCEPTION_NONCONTINUABLE, _countof(parameters), parameters);
}
#endif
void getSelfContext()
{
DWORD id = ::GetCurrentThreadId();
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);
});
_th.join();
}
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 vcruntime140.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;
}