C/C++ 定位文件 .text 区段地址

举报
微软技术分享 发表于 2022/12/24 19:44:11 2022/12/24
【摘要】 首先声明.text区段的起始地址是需要计算的,无论是哪个结构体里都不会直接提供某个区段的直接地址(虚拟内存地址),我就是因为想偷懒所以翻了好久的结构体成员列表,结果头都翻炸了还是没找到。计算过程:1.先看 IMAGE_DOS_HEADER STRUCT 这个结构体,它有一个成员 e_lfanew 指向了 NT 头。(我这里的e_lfanew = 0x100,需要根据实际情况来动态获取)2.再...

首先声明.text区段的起始地址是需要计算的,无论是哪个结构体里都不会直接提供某个区段的直接地址(虚拟内存地址),我就是因为想偷懒所以翻了好久的结构体成员列表,结果头都翻炸了还是没找到。

计算过程:

1.先看 IMAGE_DOS_HEADER STRUCT 这个结构体,它有一个成员 e_lfanew 指向了 NT 头。(我这里的e_lfanew = 0x100,需要根据实际情况来动态获取)

image.png

2.再看 _IMAGE_NT_HEADERS 结构体,FileHeader 成员是文件头结构体对象,所以再加 0x4

image.png

3.同理来到 _IMAGE_FILE_HEADER 结构体,SizeOfOptionalHeader 成员为可选头的大小,所以在加 0x14,最后因为可选头大小为 0xE0,所以总体的偏移就是:0x100+0x4+0x14+0xE0 = 0x1F8 = 504

image.png

但这仅仅是偏移,如果我们想得到真实的虚拟内存地址,还需要得到模块地址,用模块地址+偏移才能得到 .text 区段的入口地址。那么问题来了,怎么得到模块地址呢?

下面放上代码:

HMODULE GetProcessModuleHandle(DWORD pid, CONST TCHAR* moduleName) {	// 根据 PID 、模块名(需要写后缀,如:".dll"),获取模块入口地址。
	MODULEENTRY32 moduleEntry;
	HANDLE handle = NULL;
	handle = ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid); //  获取进程快照中包含在th32ProcessID中指定的进程的所有的模块。
	if (!handle) {
		CloseHandle(handle);
		return NULL;
	}
	ZeroMemory(&moduleEntry, sizeof(MODULEENTRY32));
	moduleEntry.dwSize = sizeof(MODULEENTRY32);
	if (!Module32First(handle, &moduleEntry)) {
		CloseHandle(handle);
		return NULL;
	}
	do {
		if (_tcscmp(moduleEntry.szModule, moduleName) == 0) { return moduleEntry.hModule; }
	} while (Module32Next(handle, &moduleEntry));
	CloseHandle(handle);
	return 0;
}

int main(){
	HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);  // 进程快照句柄
	PROCESSENTRY32 process = { sizeof(PROCESSENTRY32) };	// 存放进程快照的结构体

	//  遍历进程
	while (Process32Next(hProcessSnap, &process)) {
		// 找到进程
		string s_szExeFile = process.szExeFile; // char* 转 string
		if (s_szExeFile == "HEX2ASCII.exe") {
			HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process.th32ProcessID); // 进程句柄
			
			// 打印模块地址
			cout << "HEX2ASCII.exe PE头地址:" << GetProcessModuleHandle(process.th32ProcessID, "HEX2ASCII.exe") << endl;
			
			// 把模块地址转换成 int ,方便后面的计算
			int peAddress = (int)GetProcessModuleHandle(process.th32ProcessID, "HEX2ASCII.exe");
			cout << ".text 区段起始地址:" << hex << peAddress + 504 << endl;
			
			// 读取 .text 区段的前 4 个字节,验证地址是否正确
			DWORD szBuffer; // 内存数组暂存
			ReadProcessMemory(hProcess, (LPVOID)(peAddress + 504), &szBuffer, 4, NULL);
			cout << ".text 前4个字节::" << hex << szBuffer << endl;
		}
	}
}

image.png

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。