stamp_pe.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /*
  2. *******************************************************************************
  3. \file stamp_pe.c
  4. \brief Parsing of Windows PE Executables
  5. \project bee2/stamp
  6. \author (С) Sergey Agievich [agievich@{bsu.by|gmail.com}]
  7. \created 2011.10.18
  8. \version 2016.05.24
  9. \license This program is released under the GNU General Public License
  10. version 3. See Copyright Notices in bee2/info.h.
  11. *******************************************************************************
  12. */
  13. /*
  14. *******************************************************************************
  15. Разбор PE-файлов ведется по документу
  16. Microsoft Portable Executable and Common Object File Format Specification
  17. Revision 8.2 – September 21, 2010
  18. Контрольная характеристика размещается в ресурсе типа STAMP_TYPE
  19. с идентификатором STAMP_ID и представляет собой буфер памяти из STAMP_SIZE
  20. октетов.
  21. \warning Если ресурс STAMP_ID типа STAMP_TYPE задан для нескольких языков,
  22. то выбирается первый язык.
  23. *******************************************************************************
  24. */
  25. #include <windows.h>
  26. #define STAMP_TYPE 256
  27. #define STAMP_ID 1
  28. #define STAMP_SIZE 32
  29. /*
  30. *******************************************************************************
  31. Вспомогательные макросы
  32. *******************************************************************************
  33. */
  34. #define _CHECK_PTR(ptr, end)\
  35. if ((const void*)((UINT8*)(ptr) + sizeof(*(ptr))) > (end))\
  36. return (DWORD)-1;
  37. #define _CAST_PTR(T, ptr)\
  38. ((ptr) == NULL ? NULL : (T*)(ptr))
  39. #define _CAST_PTR_OFFSET(T, ptr, offset)\
  40. ((ptr) == NULL ? NULL : (T*)((UINT8*)(ptr) + (offset)))
  41. /*
  42. *******************************************************************************
  43. Разбор PE-файла
  44. Определяется смещение контрольной характеристики в образе image размера size.
  45. \return Смещение или -1 в случае ошибки.
  46. *******************************************************************************
  47. */
  48. DWORD stampFindOffset(const UINT8* image, DWORD size)
  49. {
  50. IMAGE_DOS_HEADER* pDOSHeader;
  51. IMAGE_NT_HEADERS* pNTHeader;
  52. IMAGE_FILE_HEADER* pFileHeader;
  53. IMAGE_RESOURCE_DIRECTORY* pSection;
  54. IMAGE_SECTION_HEADER* pSectionHeader;
  55. IMAGE_RESOURCE_DIRECTORY_ENTRY* pEntry;
  56. IMAGE_RESOURCE_DIRECTORY* pSubDir;
  57. IMAGE_RESOURCE_DATA_ENTRY* pData;
  58. DWORD offset;
  59. WORD pos;
  60. // окончание образа
  61. const void* image_end = image + size;
  62. if (size < STAMP_SIZE)
  63. return -1;
  64. // заголовки
  65. pDOSHeader = _CAST_PTR(IMAGE_DOS_HEADER, image);
  66. _CHECK_PTR(pDOSHeader, image_end);
  67. pNTHeader = _CAST_PTR_OFFSET(IMAGE_NT_HEADERS, pDOSHeader,
  68. pDOSHeader->e_lfanew);
  69. _CHECK_PTR(pNTHeader, image_end);
  70. pFileHeader = _CAST_PTR(IMAGE_FILE_HEADER, &pNTHeader->FileHeader);
  71. _CHECK_PTR(pFileHeader, image_end);
  72. // поиск секции ресурсов
  73. pSection = NULL;
  74. pSectionHeader = _CAST_PTR_OFFSET(IMAGE_SECTION_HEADER,
  75. &pNTHeader->OptionalHeader, pFileHeader->SizeOfOptionalHeader);
  76. pos = 0;
  77. for (; pos < pFileHeader->NumberOfSections; ++pos, ++pSectionHeader)
  78. {
  79. _CHECK_PTR(pSectionHeader, image_end);
  80. if (strcmp((char*)&pSectionHeader->Name[0], ".rsrc") == 0)
  81. {
  82. pSection = _CAST_PTR_OFFSET(IMAGE_RESOURCE_DIRECTORY, image,
  83. pSectionHeader->PointerToRawData);
  84. break;
  85. }
  86. }
  87. if (pSection == NULL)
  88. return -1;
  89. _CHECK_PTR(pSection, image_end);
  90. // поиск ресурсов типа STAMP_TYPE
  91. pEntry = _CAST_PTR_OFFSET(IMAGE_RESOURCE_DIRECTORY_ENTRY, pSection,
  92. sizeof(IMAGE_RESOURCE_DIRECTORY));
  93. pos = pSection->NumberOfNamedEntries + pSection->NumberOfIdEntries;
  94. for (; pos--; ++pEntry)
  95. {
  96. _CHECK_PTR(pEntry, image_end);
  97. if (pEntry->DataIsDirectory && pEntry->Name == STAMP_TYPE)
  98. break;
  99. }
  100. if (pos == (WORD)-1)
  101. return -1;
  102. _CHECK_PTR(pEntry, image_end);
  103. // поиск ресурса с идентификатором STAMP_ID
  104. pSubDir = _CAST_PTR_OFFSET(IMAGE_RESOURCE_DIRECTORY, pSection,
  105. pEntry->OffsetToDirectory);
  106. _CHECK_PTR(pSubDir, image_end);
  107. pEntry = _CAST_PTR_OFFSET(IMAGE_RESOURCE_DIRECTORY_ENTRY, pSubDir,
  108. sizeof(IMAGE_RESOURCE_DIRECTORY));
  109. pos = pSubDir->NumberOfNamedEntries + pSubDir->NumberOfIdEntries;
  110. for (; pos--; ++pEntry)
  111. {
  112. _CHECK_PTR(pEntry, image_end);
  113. if (pEntry->DataIsDirectory && pEntry->Name == STAMP_ID)
  114. break;
  115. }
  116. if (pos == (WORD)-1)
  117. return -1;
  118. _CHECK_PTR(pEntry, image_end);
  119. // выбираем первый язык для ресурса
  120. pSubDir = _CAST_PTR_OFFSET(IMAGE_RESOURCE_DIRECTORY, pSection,
  121. pEntry->OffsetToDirectory);
  122. _CHECK_PTR(pSubDir, image_end);
  123. if (pSubDir->NumberOfIdEntries + pSubDir->NumberOfNamedEntries == 0)
  124. return -1;
  125. pEntry = _CAST_PTR_OFFSET(IMAGE_RESOURCE_DIRECTORY_ENTRY, pSubDir,
  126. sizeof(IMAGE_RESOURCE_DIRECTORY));
  127. _CHECK_PTR(pEntry, image_end);
  128. if (pEntry->DataIsDirectory)
  129. return -1;
  130. // выбираем данные
  131. pData = _CAST_PTR_OFFSET(IMAGE_RESOURCE_DATA_ENTRY, pSection,
  132. pEntry->OffsetToData);
  133. _CHECK_PTR(pData, image_end);
  134. if (pData->Size != STAMP_SIZE)
  135. return -1;
  136. // смещение
  137. offset = pData->OffsetToData;
  138. // подправка смещения
  139. offset -= pSectionHeader->VirtualAddress;
  140. offset += pSectionHeader->PointerToRawData;
  141. if (offset >= size - 32)
  142. return -1;
  143. // все нормально
  144. return offset;
  145. }