stamp_pe.c 5.3 KB

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