IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 使用函数钩子实现打印throw异常时的调用栈 -> 正文阅读

[C++知识库]使用函数钩子实现打印throw异常时的调用栈

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

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-11 21:57:07  更:2022-03-11 21:57:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 4:35:58-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码