• 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;
    }
    
  • 相关阅读:
    sql server 2008数据复制方法
    排错技能:任务管理器中追踪某w3wp.exe是哪个IIS站点的application pool
    SplendidCRM中给来自EditView中的listbox控件设置选中值或数据源
    jQuery String Functions
    [转]jquery getJSON 数据联动(采用序列化和反序列化获取数据) .
    [转]javascript eval函数解析json数据时为什加上圆括号eval("("+data+")")
    深入理解C语言
    Qt回忆录之配置开发环境
    360电话面试
    浅谈C++设计模式之单例模式
  • 原文地址:https://www.cnblogs.com/LyShark/p/13073701.html
Copyright © 2020-2023  润新知