C/C++ 内存转储与获取DLL加载

CREATE_PROCESS_DEBUG_EVENT 创建进程的调试事件。CREATE_PROCESS_DEBUG_INFO结构体描述了该类调试事件的详细信息
OUTPUT_DEBUG_STRING_EVENT 该事件,当被调试进程调用OutputDebugString时就会引发该类调试事件,OUTPUT_DEBUG_STRING_INFO结构体描述了关于该事件的详细信息
LOAD_DLL_DEBUG_EVENT 当DLL被加载时,会调用该回调,LOAD_DLL_DEBUG_INFO结构体描述了它的详细信息,dll的路径被放在了,hfile字段,该字段默认是句柄方式存储的,需要手工转换,

实现简易调试器: 通过调试API实现建议调试器,可以加以改进,变成内存dump工具,等,也可以获取实际OEP作为查壳工具来用。

#include <stdio.h>
#include <Windows.h>
#include <Tlhelp32.h>
#include <imagehlp.h>
#pragma comment (lib, "Dbghelp")

BYTE bCC = '\xCC';

// 这是调试进程第一次被断下后执行操作
void OnException(DEBUG_EVENT *pDebug, BYTE *bCode)
{
	CONTEXT context;
	DWORD dwNum;
	BYTE bTmp;

	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pDebug->dwProcessId);
	HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, pDebug->dwThreadId);
	
	SuspendThread(hThread);
	// 读取出异常首地址
	ReadProcessMemory(hProcess, pDebug->u.Exception.ExceptionRecord.ExceptionAddress, &bTmp, sizeof(BYTE), &dwNum);

	context.ContextFlags = CONTEXT_FULL;
	GetThreadContext(hThread, &context);

	printf("EAX = %x  EIP = %x \n", context.Eax, context.Eip);
	// 将刚才的CC断点取消,也就是会写原始指令集
	WriteProcessMemory(hProcess, pDebug->u.Exception.ExceptionRecord.ExceptionAddress, bCode, sizeof(BYTE), &dwNum);
	context.Eip--;
	SetThreadContext(hThread, &context);

	printf("EAX = %x  EIP = %x \n", context.Eax, context.Eip);
	printf("入口点: %x \n", pDebug->u.CreateProcessInfo.lpBaseOfImage);

	ResumeThread(hThread);
	CloseHandle(hThread);
	CloseHandle(hProcess);
}

int main(int argc, char * argv[])
{
	STARTUPINFO si = { 0 };
	PROCESS_INFORMATION pi = { 0 };
	DEBUG_EVENT de = { 0 };

	// 创建调试进程
	BOOL bRet = CreateProcess("c://123.exe", 0, 0, 0, FALSE, DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, 0, 0, &si, &pi);

	if (bRet == FALSE)
		return bRet;
	CloseHandle(pi.hThread);
	CloseHandle(pi.hProcess);

	BYTE bCode;
	DWORD dwNum;
	int dwCC_Count = 0;

	// 开始调试循环
	while (WaitForDebugEvent(&de, INFINITE))
	{
		switch (de.dwDebugEventCode)
		{
			// 当进程创建成功后自动执行的部分
			case CREATE_PROCESS_DEBUG_EVENT:
			{
				// 获取入口地址 0x0 可以增加偏移到入口后任意位置
				DWORD dwAddr = 0x0 + (DWORD)de.u.CreateProcessInfo.lpStartAddress;
				// 暂停线程
				SuspendThread(de.u.CreateProcessInfo.hThread);
				// 读取入口地址处的字节码
				ReadProcessMemory(de.u.CreateProcessInfo.hProcess, (const void *)dwAddr, &bCode, sizeof(BYTE), &dwNum);
				// 在入口地址处写入0xCC 即写入INT 3
				WriteProcessMemory(de.u.CreateProcessInfo.hProcess, (void *)dwAddr, &bCC, sizeof(BYTE), &dwNum);
				// 恢复线程
				ResumeThread(de.u.CreateProcessInfo.hThread);
				break;
			}
			// 当进程产生异常时自动执行这里
			case EXCEPTION_DEBUG_EVENT:
			{
				switch (dwCC_Count)
				{
					// 第0次是系统断点,这里我们直接跳过
					case 0: 
						dwCC_Count++; break;
					// 第一次断点,我们让他执行下面的函数
					case 1:
						OnException(&de, &bCode); dwCC_Count++; break;
				}
			}
		}
		ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE);
	}
	system("pause");
	return 0;
}

获取DLL加载情况:

#include <stdio.h>
#include <Windows.h>
#include <tchar.h>
#include <psapi.h>

void OnDllLoaded(const LOAD_DLL_DEBUG_INFO *pDebug)
{
	printf("基址: 0x%-8X --> ", pDebug->lpBaseOfDll);

	BOOL bSuccess = FALSE;
	TCHAR pszFilename[MAX_PATH + 1];
	HANDLE hFileMap;

	// Get the file size.
	DWORD dwFileSizeHi = 0;
	DWORD dwFileSizeLo = GetFileSize(pDebug->hFile, &dwFileSizeHi);

	printf("长度: %9d --> ", dwFileSizeLo);

	if (dwFileSizeLo == 0 && dwFileSizeHi == 0)
	{
		return;
	}
	// 创建内存映射
	hFileMap = CreateFileMapping(pDebug->hFile, 0, PAGE_READONLY, 0, 1, 0);

	if (hFileMap)
	{
		void* pMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1);
		if (pMem)
		{
			if (GetMappedFileName(GetCurrentProcess(), pMem, pszFilename, MAX_PATH))
			{
				printf("路径: %s \n", pszFilename);
			}
			UnmapViewOfFile(pMem);
		}
		CloseHandle(hFileMap);
	}
}

int main(int argc, char * argv[])
{
	STARTUPINFO si = { 0 };
	PROCESS_INFORMATION pi = { 0 };
	DEBUG_EVENT debug_event = { 0 };

	// 创建调试进程
	BOOL bRet = CreateProcess("C:/Program Files/Tencent/QQ/Bin/QQ.exe", 0, 0, 0, FALSE, DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, 0, 0, &si, &pi);
	CloseHandle(pi.hThread);
	CloseHandle(pi.hProcess);

	// 开始调试循环
	while (WaitForDebugEvent(&debug_event, INFINITE))
	{
		switch (debug_event.dwDebugEventCode)
		{
			// 当DLL加载到进程时自动的执行此处代码
		case LOAD_DLL_DEBUG_EVENT:
			OnDllLoaded(&debug_event.u.LoadDll);
			break;
		}
		ContinueDebugEvent(debug_event.dwProcessId, debug_event.dwThreadId, DBG_CONTINUE);
	}
	return 0;
}

原文链接: https://www.cnblogs.com/LyShark/p/13073701.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    C/C++ 内存转储与获取DLL加载

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/198629

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月12日 下午7:54
下一篇 2023年2月12日 下午7:55

相关推荐