Blog. Just Blog

Как проверить соответствие файла PE-формату без запуска

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Как проверить соответствие файла PE-формату без запуска
Как проверить соответствие файла PE-формату без запуска

На форуме EXEL@B встретилась интересная тема по проверке является ли файл корректным PE-файлом, но без его запуска. Статическая проверка по типовым полям PE-заголовка не дает гарантии корректности, так как можно просто приписать к валидному заголовку кусок мусора или испортить его содержимое. Придется как минимум проверить соответствие размера файла суммарному размеру секций, а более тщательные проверки потребуют самостоятельного разбора секций импорта и экспорта, TLS, релоков и еще много чего. Проще всего доверить подобные проверки самой системе.

Самый простой способ - использовать функцию LoadLibraryEx с двумя флагами в параметрах: LOAD_LIBRARY_AS_DATAFILE и DONT_RESOLVE_DLL_REFERENCES. Первый флаг будет подавлять системное сообщение об ошибке загрузки, если проверяемый файл вообще никак не относится к исполняемым, второй не даст выполниться DllMain при загрузке библиотеки и не будет подгружать дополнительные модули из ее таблицы импорта. Это будет гарантировать, что никакой код не получит несанкционированного управления.
  1.         invoke  LoadLibraryEx,fname,NULL,\
  2.                 LOAD_LIBRARY_AS_DATAFILE+DONT_RESOLVE_DLL_REFERENCES
  3.         or      eax,eax
  4.         ; EAX=0 - файл загрузить не удалось
  5.         ; EAX!=0 - заголовок файла соответствует PE-формату
Но, как показала практика, использовать для проверки только эту функцию недостаточно. Поэтому на форуме EXEL@B был предложен второй способ - с использованием функции WinAPI CreateFileMapping с флагом SEC_IMAGE. Такая комбинация сообщает системе, что проецируемый файл должен являться исполняемым, и, соответственно, память проекции надо подготовить соответствующим образом, с учетом заголовка и секций. Если файл не является корректным, например, повреждена структура секций или не соответствует заголовок, то CreateFileMapping вернет ошибку. На этом и основана следующая функция проверки:
  1. ;----------------------------------------------------------
  2. ; Функция проверки корректности PE-файла
  3. ;----------------------------------------------------------
  4. ; Параметры:
  5. ;    lpszFileName - указатель на путь файла
  6. ; На выходе:
  7. ;    EAX = 1 - файл корректный
  8. ;    EAX = 0 - файл не является PE-файлом
  9. ;----------------------------------------------------------
  10. proc isPE lpszFileName:DWORD
  11.         locals
  12.         result  dd ?
  13.         endl
  14.  
  15.         SEC_IMAGE = 0x01000000
  16.  
  17.         pusha
  18.         mov     [result],0
  19.         invoke  CreateFile,[lpszFileName],GENERIC_READ,FILE_SHARE_READ,\
  20.                 NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0
  21.         cmp     eax,-1
  22.         je      .loc_ret
  23.         mov     ebx,eax
  24.         invoke  CreateFileMapping,ebx,NULL,PAGE_READONLY+SEC_IMAGE,0,0,NULL
  25.         push    eax
  26.         invoke  CloseHandle,ebx
  27.         pop     ebx
  28.         or      ebx,ebx
  29.         jz      .loc_ret
  30.         invoke  MapViewOfFile,ebx,FILE_MAP_READ,0,0,0
  31.         or      eax,eax
  32.         jz      @f
  33.         invoke  UnmapViewOfFile,eax
  34.  
  35.         ; Файл соответствует PE-формату
  36.         mov     [result],1
  37. @@:
  38.         invoke  CloseHandle,ebx
  39. .loc_ret:
  40.         popa
  41.  
  42.         mov     eax,[result]
  43.         ret
  44. endp
Функция принимает единственный параметр lpszFileName - указатель на имя проверяемого файла. На выходе EAX=1 - файл соответствует PE-формату, EAX=0 - файл не является корректным PE-файлом. Осталось протестировать обе функции. Тестирование проводилось на Windows 7 x86, Windows XP и Windows 8.1 x64, приложение скомпилировано как 32-битное. Для наглядности я собрал в табличку результаты тестирования на различных файлах.

Тестовый файлLoadLibraryExФункция isPE
32-битный EXE-файлCorrectCorrect
32-битный DLL-файлCorrectCorrect
64-битный EXE-файл на 32-битной системеCorrectInvalid
64-битный DLL-файл на 32-битной системеCorrectInvalid
64-битный EXE-файл на 64-битной системеCorrectCorrect
64-битный DLL-файл на 64-битной системеCorrectCorrect
Поврежденный 32-битный EXE-файлCorrectInvalid
Поврежденный 32-битный DLL-файлCorrectInvalid
Поврежденный 64-битный EXE-файлCorrectInvalid
Поврежденный 64-битный DLL-файлCorrectInvalid
Текстовый файлInvalidInvalid

Поврежденными я назвал изначально корректные исполняемые файлы, от которых я просто отрезал приличный кусок. То есть заголовок остался прежним, а вот внутренняя структура секций была нарушена. При попытке запустить поврежденный файл система выдаст ошибку. Тем не менее, функция LoadLibraryEx бодренько загружает такие файлы в память и возвращает корректный хэндл. Конечно, дальнейшая работа с этим файлом очень сомнительна, например, при попытке загрузить из него какие-нибудь ресурсы, вы почти со стопроцентной вероятностью получите ошибку. Результат "Invalid" LoadLibraryEx дает только на файлах, которые к исполняемым не имеют вообще никакого отношения.

В то же время, если попытаться проверить корректность 64-битного исполняемого файла на 32-битной системе при помощи функции isPE, она вернет результат "Invalid". Своя правда в этом тоже есть, тем самым функция сообщает, что проверяемый файл не может быть запущен в имеющемся окружении, хотя имеет абсолютно корректную внутреннюю структуру. Поэтому результаты функции isPE можно расценивать как ответ на вопрос "может ли проверяемый файл вообще запуститься на этом компьютере?".

В приложении пример программы с исходным текстом, которая проверяет соответствие файла "test.exe" PE-формату с помощью функций LoadLibraryEx и isPE.

Пример программы с исходным текстом (FASM)Пример программы с исходным текстом (FASM)

Is.Valid.PE.File.Demo.zip (2,046 bytes)


Поделиться ссылкой ВКонтакте Поделиться ссылкой на Facebook Поделиться ссылкой на LiveJournal Поделиться ссылкой в Мой Круг Добавить в Мой мир Добавить на ЛиРу (Liveinternet) Добавить в закладки Memori Добавить в закладки Google
Просмотров: 2139 | Комментариев: 7

Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
Nobody4all (10.04.2017 в 01:20):
Ну так очевидно, что LoadLibraryEx не сможет ответить является ли исполняемый файл правильным. Ведь она служит для проецирования библы в память. А dll не совсем исполняемый файл )) вообще LLE тебе что угодно с проецирует. Вместо предложенной функции, правильней было бы назвать что правильность проверяет именно функция CreateFileMapping с флагом SEC_IMAGE. Результаты теста верны, по другому быть и не может
user (01.12.2015 в 23:35):
Цитатаписать типа: handle=func(0,"string",@const)

- Это удобно, но имеет свою цену. Часто она неоправданно высока.
Да и дело привычки
ManHunter (01.12.2015 в 23:06):
Конечно стоит.
brute (01.12.2015 в 22:13):
стоит ли проверять "MapViewOfFile" или сие уже излишне и достаточно остановиться на "CreateFileMapping"?
п.с. как только хватает терпения писать на fasm'e? Я бы давно уже макросами все параметны в функции засунул, чтобы писать типа: handle=func(0,"string",@const)
user (30.11.2015 в 17:33):
А вообще было бы неплохо иметь реальный загрузчик PE-файлов, что-то типа отладочной его версии, где любая ошибка при загрузке PE сопровождалась бы выдачей исчерпывающей информации об ошибке и о её месте в файле..
У кого-то ведь такая вещь имеется, 100%.
ManHunter (30.11.2015 в 17:16):
Я остановлюсь на мысли, что корректность файла является достаточной, если система способна правильно разместить его в памяти и подготовить к запуску (или к загрузке данных, в случае, например, dll с ресурсами).
user (30.11.2015 в 17:05):
К сожалению, определения самого факта незагружаемости файла бывает недостаточно. Такой подход можно применять в утилитах, чтобы проверить, верно ли выполнена манипуляция с файлом и в случае ошибки откатиться к сохранённому варианту.
Вообще, это очень мутная тема. Такая утилита, как PEVerify (HIEW) во многих случаях не имеет претензий к файлу, но тем не менее он не загружается.
Вот кто мог бы прояснить эти все вопросы, так это микрософт - но они не горят стремлением это делать. Больше того, их фирменная HDR.EXE бывало висла при проверке некорректного PE-файла..

--добавлено--
Хм. Уже HIEW 8.44 есть..

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2017
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.06 сек. / MySQL: 2 (0.0034 сек.) / Память: 4.5 Mb
Наверх