资源表、重定位表

  1. // win原理Day003.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "stdafx.h"
  4. #include <windows.h>
  5. //1 把文件读到内存中
  6. char* ReadFileToMemory(char* pFilePath)
  7. {
  8. //1 获取文件句柄
  9. HANDLE hFile = CreateFileA(pFilePath,
  10. GENERIC_READ | GENERIC_WRITE,
  11. FALSE,
  12. NULL,
  13. OPEN_EXISTING,
  14. FILE_ATTRIBUTE_NORMAL,
  15. NULL);
  16. if (hFile == INVALID_HANDLE_VALUE)
  17. {
  18. printf("文件打开失败\n");
  19. return 0;
  20. }
  21. //2.获取文件大小
  22. DWORD dwFileSize = GetFileSize(hFile, NULL);
  23. //3.申请内存空间
  24. char* pBuf = new char[dwFileSize]{};
  25. if (!pBuf)
  26. {
  27. CloseHandle(hFile);
  28. printf("内存申请失败\n");
  29. return 0;
  30. }
  31. //4.读取文件内容到内存空间
  32. DWORD dwRead;
  33. ReadFile(hFile, pBuf, dwFileSize, &dwRead, NULL);
  34. //5. 返回内存地址
  35. return pBuf;
  36. }
  37. //2 是否是PE文件
  38. bool IsPeFile(char* pBuf)
  39. {
  40. PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuf;
  41. if (pDos->e_magic != IMAGE_DOS_SIGNATURE)
  42. {
  43. printf("不是PE文件\n");
  44. return false;
  45. }
  46. PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)
  47. (pDos->e_lfanew + pBuf);
  48. if (pNt->Signature != IMAGE_NT_SIGNATURE)
  49. {
  50. printf("不是PE文件\n");
  51. return false;
  52. }
  53. return true;
  54. }
  55. //RVA to FOA
  56. DWORD RVAtoFOA(DWORD dwRVA, char* pBuf)
  57. {
  58. PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuf;
  59. PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + pBuf);
  60. //区段个数(文件头第二个字段)
  61. DWORD dwCount = pNt->FileHeader.NumberOfSections;
  62. //区段首地址(IMAGE_FIRST_SECTION)
  63. PIMAGE_SECTION_HEADER pSec = IMAGE_FIRST_SECTION(pNt);
  64. for (DWORD i = 0; i < dwCount; i++)
  65. {
  66. //FOA = RVA - 内存中区段首地址 + 文件中区段首地址
  67. if (dwRVA >= pSec->VirtualAddress &&
  68. dwRVA < pSec->VirtualAddress + pSec->SizeOfRawData)
  69. {
  70. return dwRVA - pSec->VirtualAddress + pSec->PointerToRawData;
  71. }
  72. //下一个区段表
  73. pSec++;
  74. }
  75. return 0;
  76. }
  77. /*
  78. //低16位是其ID
  79. char* arryResType[] = { "", "鼠标指针(Cursor)", "位图(Bitmap)", "图标(Icon)", "菜单(Menu)"
  80. , "对话框(Dialog)", "字符串列表(String Table)", "字体目录(Font Directory)", "字体(Font)", "快捷键(Accelerators)"
  81. , "非格式化资源(Unformatted)", "消息列表(Message Table)", "鼠标指针组(Croup Cursor)", "", "图标组(Group Icon)", ""
  82. , "版本信息(Version Information)" };
  83. */
  84. //解析资源表
  85. void ShowResouceTable(char* pBuf)
  86. {
  87. PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuf;
  88. PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + pBuf);
  89. //找到资源表(数据目录表的第三项)
  90. DWORD dwResRVA = pNt->OptionalHeader.DataDirectory[2].VirtualAddress;
  91. //资源表在文件中的具体文件地址
  92. DWORD dwResRoot = (DWORD)(RVAtoFOA(dwResRVA, pBuf) + pBuf);
  93. //开始解析
  94. //第一层地址
  95. PIMAGE_RESOURCE_DIRECTORY pRes1 = (PIMAGE_RESOURCE_DIRECTORY)dwResRoot;
  96. //第一层总个数
  97. DWORD dwCount_1 = pRes1->NumberOfIdEntries + pRes1->NumberOfNamedEntries;
  98. //第一层资源项的起始地址
  99. PIMAGE_RESOURCE_DIRECTORY_ENTRY pEntry1 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pRes1 + 1);
  100. for (DWORD i = 0; i < dwCount_1; i++)
  101. {
  102. //判断资源命名方式
  103. if (pEntry1->NameIsString)
  104. {
  105. //字符串命名
  106. PIMAGE_RESOURCE_DIR_STRING_U pName =
  107. (PIMAGE_RESOURCE_DIR_STRING_U)
  108. (pEntry1->NameOffset + dwResRoot);
  109. //资源字符是WCHAR类型
  110. //在文件中并不是以0为结尾存储的
  111. WCHAR * wcName = new WCHAR[pName->Length+1]{};
  112. memcpy(wcName, pName->NameString, pName->Length * 2);
  113. printf("资源种类名称:【%S】\n", wcName);
  114. delete wcName;
  115. }
  116. else
  117. {
  118. //ID命名
  119. //低16位是其ID
  120. char* arryResType[] = { "", "鼠标指针(Cursor)", "位图(Bitmap)", "图标(Icon)", "菜单(Menu)"
  121. , "对话框(Dialog)", "字符串列表(String Table)", "字体目录(Font Directory)", "字体(Font)", "快捷键(Accelerators)"
  122. , "非格式化资源(Unformatted)", "消息列表(Message Table)", "鼠标指针组(Croup Cursor)", "", "图标组(Group Icon)", ""
  123. , "版本信息(Version Information)" };
  124. if (pEntry1->Id > 17)
  125. {
  126. printf("资源种类ID:【%d】\n", pEntry1->Id);
  127. }
  128. else
  129. {
  130. printf("资源种类ID:【%s】\n", arryResType[pEntry1->Id]);
  131. }
  132. }
  133. //判断是否有下一层
  134. if (pEntry1->DataIsDirectory)
  135. {
  136. //第二层起始地址
  137. PIMAGE_RESOURCE_DIRECTORY pRes2 =
  138. (PIMAGE_RESOURCE_DIRECTORY)
  139. (pEntry1->OffsetToDirectory + dwResRoot);
  140. //第二层资源个数
  141. DWORD dwCount2 = pRes2->NumberOfIdEntries + pRes2->NumberOfNamedEntries;
  142. //第二层资源项的起始地址
  143. PIMAGE_RESOURCE_DIRECTORY_ENTRY pEntry2 =
  144. (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pRes2 + 1);
  145. for (DWORD i2 = 0; i2 < dwCount2; i2++)
  146. {
  147. //判断资源命名方式
  148. if (pEntry2->NameIsString)
  149. {
  150. //字符串命名
  151. PIMAGE_RESOURCE_DIR_STRING_U pName =
  152. (PIMAGE_RESOURCE_DIR_STRING_U)
  153. (pEntry2->NameOffset + dwResRoot);
  154. //资源字符是WCHAR类型
  155. WCHAR * wcName = new WCHAR[pName->Length + 1]{};
  156. memcpy(wcName, pName->NameString, pName->Length * 2);
  157. printf("\t资源名称:【%S】\n", wcName);
  158. delete wcName;
  159. }
  160. else
  161. {
  162. //ID命名
  163. printf("\t资源ID:【%d】\n", pEntry2->Id);
  164. }
  165. //判断是否有下一层
  166. if (pEntry2->DataIsDirectory)
  167. {
  168. //第三层
  169. PIMAGE_RESOURCE_DIRECTORY pRes3 =
  170. (PIMAGE_RESOURCE_DIRECTORY)
  171. (pEntry2->OffsetToDirectory + dwResRoot);
  172. //资源个数
  173. DWORD dwCount3 = pRes3->NumberOfIdEntries + pRes3->NumberOfNamedEntries;
  174. PIMAGE_RESOURCE_DIRECTORY_ENTRY pEntry3 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pRes3 + 1);
  175. //资源类别(英文的或者中文的等等)
  176. //pEntry3->Name;
  177. PIMAGE_RESOURCE_DATA_ENTRY pData = (PIMAGE_RESOURCE_DATA_ENTRY)(pEntry3->OffsetToData + dwResRoot);
  178. //资源的数据大小
  179. DWORD dwDataSize = pData->Size;
  180. //pData->OffsetToData,资源数据的RVA
  181. DWORD dwDataFOA = RVAtoFOA(pData->OffsetToData, pBuf);
  182. PBYTE pByteData = (PBYTE)(dwDataFOA + pBuf);
  183. //这里输出前10个字节
  184. printf("\t\t");
  185. for (int n = 0; n < 10; n++)
  186. {
  187. printf("%02X ", pByteData[n]);
  188. }
  189. printf("\n");
  190. }
  191. //下一个资源
  192. pEntry2++;
  193. }
  194. }
  195. //下一种资源
  196. pEntry1++;
  197. }
  198. }
  199. //解析重定位表
  200. void ShowRelocTable(char* pBuf)
  201. {
  202. PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuf;
  203. PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + pBuf);
  204. //找到重定位表(数据目录表第六项)
  205. //解析
  206. DWORD dwRelocRVA = pNt->OptionalHeader.DataDirectory[5].VirtualAddress;
  207. //得到重定位表在文件中的地址
  208. PIMAGE_BASE_RELOCATION pReloc =
  209. (PIMAGE_BASE_RELOCATION)
  210. (RVAtoFOA(dwRelocRVA, pBuf) + pBuf);
  211. struct TypeOffset //重定位项结构
  212. {
  213. WORD offset : 12; //低12位表示相对于本块记录的内存页的偏移量
  214. WORD type : 4; //高4位表示需要修正几个字节(0:不需要修正;3:修正4个字节;0x10:修正8个字节)
  215. };
  216. int n = 1;//重定位块个数
  217. while (pReloc->SizeOfBlock)
  218. {
  219. printf("第%d块【0x%08X】\n", n++, pReloc->VirtualAddress);
  220. //计算重定位项的个数
  221. DWORD dwCount = (pReloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
  222. //重定位项数组的首地址
  223. TypeOffset* pOffset = (TypeOffset*)(pReloc + 1);
  224. for (int i = 0; i < dwCount; i++)
  225. {
  226. if (pOffset->type == 3)
  227. {
  228. DWORD dwDataRVA = pOffset->offset + pReloc->VirtualAddress;
  229. DWORD* pRelocData = (DWORD*)(RVAtoFOA(dwDataRVA, pBuf) + pBuf);
  230. printf("\t需要修正的数据:0x%08X\n", *pRelocData);
  231. //如果程序运行起来,修正的方式
  232. //*pRelocData = *pRelocData - 默认加载基址 + 新的加载基址;
  233. }
  234. //下一个重定位项
  235. pOffset++;
  236. }
  237. //下一个重定位块的地址
  238. pReloc = (PIMAGE_BASE_RELOCATION)
  239. ((DWORD)pReloc + pReloc->SizeOfBlock);
  240. }
  241. }
  242. int _tmain(int argc, _TCHAR* argv[])
  243. {
  244. char* pBuf = ReadFileToMemory("123.exe");
  245. if (IsPeFile(pBuf))
  246. {
  247. //ShowResouceTable(pBuf);
  248. ShowRelocTable(pBuf);
  249. }
  250. //释放内存
  251. delete pBuf;
  252. return 0;
  253. }