zoukankan      html  css  js  c++  java
  • 在两种情景下获得指定进程基地址的方法

    情景一

    最近在写一个简单调试器的时候,需要在CreateProcess()创建调试进程后获得程序的基地址。
    一开始我是在CreateProcess()前,利用内存映射文件来加载指定可执行文件,然后从文件的NT文件头中读取程序的加载基地址。但是我忽略了有可能程序发生基址随机化,这样的话就获得的基地址就不准确了。

    解决方法

    可以在CreateProcess()创建进程前利用内存映射文件读NT文件头中的入口地址的RVA(入口地址随基地址变化,但是入口地址的RVA是不变的)。然后在CreateProcess()创建调试进程后,获取调试进程的进程环境块(CONTEXT),context . eax即为其程序的入口地址。然后减去入口地址的RVA即为真正的基地址。

    	HANDLE	hFile;				//文件句柄
    	HANDLE	hMapFile;			//内存映射文件对象句柄
    	LPVOID	lpMapFile;			//内存映射文件指针
    
    
    	hFile = CreateFile(ExeName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    	hMapFile = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
    	lpMapFile = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
    	IMAGE_DOS_HEADER* lpDosMZ = (IMAGE_DOS_HEADER*)lpMapFile;
    	IMAGE_NT_HEADERS* lpNT = (IMAGE_NT_HEADERS*)lpMapFile;
    	lpNT = (IMAGE_NT_HEADERS*)((BYTE*)lpNT + lpDosMZ->e_lfanew);
    	
    	dwEntryPointRVA = lpNT->OptionalHeader.AddressOfEntryPoint;				//获得入口地址的RVA
    
    	UnmapViewOfFile(lpMapFile);		//撤销映射
    	CloseHandle(hMapFile);			//关闭内存映射对象句柄
    	CloseHandle(hFile);				//关闭文件
    
    	
    
    
    	//创建被调试程序进程
    	CreateProcess(
    		ExeName,
    		NULL,
    		NULL,
    		NULL,
    		FALSE, // 不可继承
    		DEBUG_ONLY_THIS_PROCESS | DEBUG_PROCESS, // 调试模式启动			(DEBUG_ONLY_THIS_PROCESS标志表示其不能调试进程如果被调试的话,此新进程不会成为其调试进程的调试对象)
    		NULL,
    		NULL,
    		&si,
    		&pi);
    
    		
    	//获取入口地址
    	stContext.ContextFlags = CONTEXT_ALL;
    	GetThreadContext(pi.hThread, &stContext);
    	dwEntryPoint = stContext.Eax;
    
    	//获取基地址
    	hInstance = dwEntryPoint - dwEntryPointRVA;
    

    情景二

    如果要调试一个已运行的进程需要对其进行附加,附加之后需要获得其基地址。(进一步获得其入口地址)

    解决方法

    可以先创建一个进程快照,获得指定进程的PID之后。在建立一个基于这个进程的模块快照,然后获得此进程第一个模块的基地址,此基地址即为这个进程的基地址。然后在通过基地址调用ReadProcessMemory()读取NT头获得入口地址RVA,在与基地址相加即为此进程的入口地址。

    	//dwData是指定进程的PID,通过创建进程快照获得
    	
    	//进程模块快照,(获得已运行进程基地址)
    	hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwData);
    	Module32First(hModuleSnap, &me32);
    	dwInstance = (DWORD)me32.modBaseAddr;			//进程基地址
    	CloseHandle(hModuleSnap);
    
    
    	//获取入口地址RVA
    
    	DWORD lpNT;			//指向NT头
    	ReadProcessMemory(hIsDebuggedProcess, (LPVOID)(dwInstance + 0x3c), &lpNT, 4, NULL);
    	lpNT = lpNT + dwInstance;
    	ReadProcessMemory(hIsDebuggedProcess, (LPVOID)(lpNT + 0x28), &dwEntryPointRVA, 4, NULL);
    
    
    	//获取入口地址
    	dwEntryPoint = dwInstance + dwEntryPointRVA;
    
  • 相关阅读:
    # 机器学习算法总结-第七天(线性回归)
    # 机器学习算法总结-第六天(Adaboost算法)
    # 机器学习算法总结-第五天(降维算法PCA/SVD)
    #再谈 CVE-2017-10271回显POC构造
    # 机器学习算法总结-第四天(SKlearn/数据处理and特征工程)
    # 机器学习算法总结-第三天(支持向量机)
    # 机器学习算法总结-第二天(朴素贝叶斯、逻辑回归)
    # 机器学习算法总结-第一天(KNN、决策树)
    # weblogic CVE-2019-2615/2618(任意文件读取,任意文件上传)
    # CVE-2019-2725二次反序列化EventData Gadget POC/JdbcRowSetImpl POC构造
  • 原文地址:https://www.cnblogs.com/revercc/p/13287072.html
Copyright © 2011-2022 走看看