资源表、重定位表
// win原理Day003.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <windows.h>//1 把文件读到内存中char* ReadFileToMemory(char* pFilePath){ //1 获取文件句柄 HANDLE hFile = CreateFileA(pFilePath, GENERIC_READ | GENERIC_WRITE, FALSE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { printf("文件打开失败\n"); return 0; } //2.获取文件大小 DWORD dwFileSize = GetFileSize(hFile, NULL); //3.申请内存空间 char* pBuf = new char[dwFileSize]{}; if (!pBuf) { CloseHandle(hFile); printf("内存申请失败\n"); return 0; } //4.读取文件内容到内存空间 DWORD dwRead; ReadFile(hFile, pBuf, dwFileSize, &dwRead, NULL); //5. 返回内存地址 return pBuf;}//2 是否是PE文件bool IsPeFile(char* pBuf){ PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuf; if (pDos->e_magic != IMAGE_DOS_SIGNATURE) { printf("不是PE文件\n"); return false; } PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS) (pDos->e_lfanew + pBuf); if (pNt->Signature != IMAGE_NT_SIGNATURE) { printf("不是PE文件\n"); return false; } return true;}//RVA to FOADWORD RVAtoFOA(DWORD dwRVA, char* pBuf){ PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuf; PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + pBuf); //区段个数(文件头第二个字段) DWORD dwCount = pNt->FileHeader.NumberOfSections; //区段首地址(IMAGE_FIRST_SECTION) PIMAGE_SECTION_HEADER pSec = IMAGE_FIRST_SECTION(pNt); for (DWORD i = 0; i < dwCount; i++) { //FOA = RVA - 内存中区段首地址 + 文件中区段首地址 if (dwRVA >= pSec->VirtualAddress && dwRVA < pSec->VirtualAddress + pSec->SizeOfRawData) { return dwRVA - pSec->VirtualAddress + pSec->PointerToRawData; } //下一个区段表 pSec++; } return 0;}/*//低16位是其IDchar* arryResType[] = { "", "鼠标指针(Cursor)", "位图(Bitmap)", "图标(Icon)", "菜单(Menu)", "对话框(Dialog)", "字符串列表(String Table)", "字体目录(Font Directory)", "字体(Font)", "快捷键(Accelerators)", "非格式化资源(Unformatted)", "消息列表(Message Table)", "鼠标指针组(Croup Cursor)", "", "图标组(Group Icon)", "", "版本信息(Version Information)" };*///解析资源表void ShowResouceTable(char* pBuf){ PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuf; PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + pBuf); //找到资源表(数据目录表的第三项) DWORD dwResRVA = pNt->OptionalHeader.DataDirectory[2].VirtualAddress; //资源表在文件中的具体文件地址 DWORD dwResRoot = (DWORD)(RVAtoFOA(dwResRVA, pBuf) + pBuf); //开始解析 //第一层地址 PIMAGE_RESOURCE_DIRECTORY pRes1 = (PIMAGE_RESOURCE_DIRECTORY)dwResRoot; //第一层总个数 DWORD dwCount_1 = pRes1->NumberOfIdEntries + pRes1->NumberOfNamedEntries; //第一层资源项的起始地址 PIMAGE_RESOURCE_DIRECTORY_ENTRY pEntry1 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pRes1 + 1); for (DWORD i = 0; i < dwCount_1; i++) { //判断资源命名方式 if (pEntry1->NameIsString) { //字符串命名 PIMAGE_RESOURCE_DIR_STRING_U pName = (PIMAGE_RESOURCE_DIR_STRING_U) (pEntry1->NameOffset + dwResRoot); //资源字符是WCHAR类型 //在文件中并不是以0为结尾存储的 WCHAR * wcName = new WCHAR[pName->Length+1]{}; memcpy(wcName, pName->NameString, pName->Length * 2); printf("资源种类名称:【%S】\n", wcName); delete wcName; } else { //ID命名 //低16位是其ID char* arryResType[] = { "", "鼠标指针(Cursor)", "位图(Bitmap)", "图标(Icon)", "菜单(Menu)" , "对话框(Dialog)", "字符串列表(String Table)", "字体目录(Font Directory)", "字体(Font)", "快捷键(Accelerators)" , "非格式化资源(Unformatted)", "消息列表(Message Table)", "鼠标指针组(Croup Cursor)", "", "图标组(Group Icon)", "" , "版本信息(Version Information)" }; if (pEntry1->Id > 17) { printf("资源种类ID:【%d】\n", pEntry1->Id); } else { printf("资源种类ID:【%s】\n", arryResType[pEntry1->Id]); } } //判断是否有下一层 if (pEntry1->DataIsDirectory) { //第二层起始地址 PIMAGE_RESOURCE_DIRECTORY pRes2 = (PIMAGE_RESOURCE_DIRECTORY) (pEntry1->OffsetToDirectory + dwResRoot); //第二层资源个数 DWORD dwCount2 = pRes2->NumberOfIdEntries + pRes2->NumberOfNamedEntries; //第二层资源项的起始地址 PIMAGE_RESOURCE_DIRECTORY_ENTRY pEntry2 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pRes2 + 1); for (DWORD i2 = 0; i2 < dwCount2; i2++) { //判断资源命名方式 if (pEntry2->NameIsString) { //字符串命名 PIMAGE_RESOURCE_DIR_STRING_U pName = (PIMAGE_RESOURCE_DIR_STRING_U) (pEntry2->NameOffset + dwResRoot); //资源字符是WCHAR类型 WCHAR * wcName = new WCHAR[pName->Length + 1]{}; memcpy(wcName, pName->NameString, pName->Length * 2); printf("\t资源名称:【%S】\n", wcName); delete wcName; } else { //ID命名 printf("\t资源ID:【%d】\n", pEntry2->Id); } //判断是否有下一层 if (pEntry2->DataIsDirectory) { //第三层 PIMAGE_RESOURCE_DIRECTORY pRes3 = (PIMAGE_RESOURCE_DIRECTORY) (pEntry2->OffsetToDirectory + dwResRoot); //资源个数 DWORD dwCount3 = pRes3->NumberOfIdEntries + pRes3->NumberOfNamedEntries; PIMAGE_RESOURCE_DIRECTORY_ENTRY pEntry3 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pRes3 + 1); //资源类别(英文的或者中文的等等) //pEntry3->Name; PIMAGE_RESOURCE_DATA_ENTRY pData = (PIMAGE_RESOURCE_DATA_ENTRY)(pEntry3->OffsetToData + dwResRoot); //资源的数据大小 DWORD dwDataSize = pData->Size; //pData->OffsetToData,资源数据的RVA DWORD dwDataFOA = RVAtoFOA(pData->OffsetToData, pBuf); PBYTE pByteData = (PBYTE)(dwDataFOA + pBuf); //这里输出前10个字节 printf("\t\t"); for (int n = 0; n < 10; n++) { printf("%02X ", pByteData[n]); } printf("\n"); } //下一个资源 pEntry2++; } } //下一种资源 pEntry1++; }}//解析重定位表void ShowRelocTable(char* pBuf){ PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuf; PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + pBuf); //找到重定位表(数据目录表第六项) //解析 DWORD dwRelocRVA = pNt->OptionalHeader.DataDirectory[5].VirtualAddress; //得到重定位表在文件中的地址 PIMAGE_BASE_RELOCATION pReloc = (PIMAGE_BASE_RELOCATION) (RVAtoFOA(dwRelocRVA, pBuf) + pBuf); struct TypeOffset //重定位项结构 { WORD offset : 12; //低12位表示相对于本块记录的内存页的偏移量 WORD type : 4; //高4位表示需要修正几个字节(0:不需要修正;3:修正4个字节;0x10:修正8个字节) }; int n = 1;//重定位块个数 while (pReloc->SizeOfBlock) { printf("第%d块【0x%08X】\n", n++, pReloc->VirtualAddress); //计算重定位项的个数 DWORD dwCount = (pReloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD); //重定位项数组的首地址 TypeOffset* pOffset = (TypeOffset*)(pReloc + 1); for (int i = 0; i < dwCount; i++) { if (pOffset->type == 3) { DWORD dwDataRVA = pOffset->offset + pReloc->VirtualAddress; DWORD* pRelocData = (DWORD*)(RVAtoFOA(dwDataRVA, pBuf) + pBuf); printf("\t需要修正的数据:0x%08X\n", *pRelocData); //如果程序运行起来,修正的方式 //*pRelocData = *pRelocData - 默认加载基址 + 新的加载基址; } //下一个重定位项 pOffset++; } //下一个重定位块的地址 pReloc = (PIMAGE_BASE_RELOCATION) ((DWORD)pReloc + pReloc->SizeOfBlock); }}int _tmain(int argc, _TCHAR* argv[]){ char* pBuf = ReadFileToMemory("123.exe"); if (IsPeFile(pBuf)) { //ShowResouceTable(pBuf); ShowRelocTable(pBuf); } //释放内存 delete pBuf; return 0;}