Как проверить соответствие файла PE-формату без запуска
Как проверить соответствие файла PE-формату без запуска
На форуме EXEL@B встретилась интересная тема по проверке является ли файл корректным PE-файлом, но без его запуска. Статическая проверка по типовым полям PE-заголовка не дает гарантии корректности, так как можно просто приписать к валидному заголовку кусок мусора или испортить его содержимое. Придется как минимум проверить соответствие размера файла суммарному размеру секций, а более тщательные проверки потребуют самостоятельного разбора секций импорта и экспорта, TLS, релоков и еще много чего. Проще всего доверить подобные проверки самой системе.
Самый простой способ - использовать функцию LoadLibraryEx с двумя флагами в параметрах: LOAD_LIBRARY_AS_DATAFILE и DONT_RESOLVE_DLL_REFERENCES. Первый флаг будет подавлять системное сообщение об ошибке загрузки, если проверяемый файл вообще никак не относится к исполняемым, второй не даст выполниться DllMain при загрузке библиотеки и не будет подгружать дополнительные модули из ее таблицы импорта. Это будет гарантировать, что никакой код не получит несанкционированного управления.
Code (Assembler) : Убрать нумерацию
- invoke LoadLibraryEx,fname,NULL,\
- LOAD_LIBRARY_AS_DATAFILE+DONT_RESOLVE_DLL_REFERENCES
- or eax,eax
- ; EAX=0 - файл загрузить не удалось
- ; EAX!=0 - заголовок файла соответствует PE-формату
Code (Assembler) : Убрать нумерацию
- ;----------------------------------------------------------
- ; Функция проверки корректности PE-файла
- ;----------------------------------------------------------
- ; Параметры:
- ; lpszFileName - указатель на путь файла
- ; На выходе:
- ; EAX = 1 - файл корректный
- ; EAX = 0 - файл не является PE-файлом
- ;----------------------------------------------------------
- proc isPE lpszFileName:DWORD
- locals
- result dd ?
- endl
- SEC_IMAGE = 0x01000000
- pusha
- mov [result],0
- invoke CreateFile,[lpszFileName],GENERIC_READ,FILE_SHARE_READ,\
- NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0
- cmp eax,-1
- je .loc_ret
- mov ebx,eax
- invoke CreateFileMapping,ebx,NULL,PAGE_READONLY+SEC_IMAGE,0,0,NULL
- push eax
- invoke CloseHandle,ebx
- pop ebx
- or ebx,ebx
- jz .loc_ret
- invoke MapViewOfFile,ebx,FILE_MAP_READ,0,0,0
- or eax,eax
- jz @f
- invoke UnmapViewOfFile,eax
- ; Файл соответствует PE-формату
- mov [result],1
- @@:
- invoke CloseHandle,ebx
- .loc_ret:
- popa
- mov eax,[result]
- ret
- endp
Тестовый файл | LoadLibraryEx | Функция isPE |
---|---|---|
32-битный EXE-файл | Correct | Correct |
32-битный DLL-файл | Correct | Correct |
64-битный EXE-файл на 32-битной системе | Correct | Invalid |
64-битный DLL-файл на 32-битной системе | Correct | Invalid |
64-битный EXE-файл на 64-битной системе | Correct | Correct |
64-битный DLL-файл на 64-битной системе | Correct | Correct |
Поврежденный 32-битный EXE-файл | Correct | Invalid |
Поврежденный 32-битный DLL-файл | Correct | Invalid |
Поврежденный 64-битный EXE-файл | Correct | Invalid |
Поврежденный 64-битный DLL-файл | Correct | Invalid |
Текстовый файл | Invalid | Invalid |
Поврежденными я назвал изначально корректные исполняемые файлы, от которых я просто отрезал приличный кусок. То есть заголовок остался прежним, а вот внутренняя структура секций была нарушена. При попытке запустить поврежденный файл система выдаст ошибку. Тем не менее, функция LoadLibraryEx бодренько загружает такие файлы в память и возвращает корректный хэндл. Конечно, дальнейшая работа с этим файлом очень сомнительна, например, при попытке загрузить из него какие-нибудь ресурсы, вы почти со стопроцентной вероятностью получите ошибку. Результат "Invalid" LoadLibraryEx дает только на файлах, которые к исполняемым не имеют вообще никакого отношения.
В то же время, если попытаться проверить корректность 64-битного исполняемого файла на 32-битной системе при помощи функции isPE, она вернет результат "Invalid". Своя правда в этом тоже есть, тем самым функция сообщает, что проверяемый файл не может быть запущен в имеющемся окружении, хотя имеет абсолютно корректную внутреннюю структуру. Поэтому результаты функции isPE можно расценивать как ответ на вопрос "может ли проверяемый файл вообще запуститься на этом компьютере?".
В приложении пример программы с исходным текстом, которая проверяет соответствие файла "test.exe" PE-формату с помощью функций LoadLibraryEx и isPE.
Просмотров: 4135 | Комментариев: 7
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
Nobody4all
(10.04.2017 в 01:20):
Ну так очевидно, что LoadLibraryEx не сможет ответить является ли исполняемый файл правильным. Ведь она служит для проецирования библы в память. А dll не совсем исполняемый файл )) вообще LLE тебе что угодно с проецирует. Вместо предложенной функции, правильней было бы назвать что правильность проверяет именно функция CreateFileMapping с флагом SEC_IMAGE. Результаты теста верны, по другому быть и не может
user
(01.12.2015 в 23:35):
- Это удобно, но имеет свою цену. Часто она неоправданно высока.
Да и дело привычки
ManHunter
(01.12.2015 в 23:06):
Конечно стоит.
brute
(01.12.2015 в 22:13):
стоит ли проверять "MapViewOfFile" или сие уже излишне и достаточно остановиться на "CreateFileMapping"?
п.с. как только хватает терпения писать на fasm'e? Я бы давно уже макросами все параметны в функции засунул, чтобы писать типа: handle=func(0,"string",@const)
п.с. как только хватает терпения писать на fasm'e? Я бы давно уже макросами все параметны в функции засунул, чтобы писать типа: handle=func(0,"string",@const)
user
(30.11.2015 в 17:33):
А вообще было бы неплохо иметь реальный загрузчик PE-файлов, что-то типа отладочной его версии, где любая ошибка при загрузке PE сопровождалась бы выдачей исчерпывающей информации об ошибке и о её месте в файле..
У кого-то ведь такая вещь имеется, 100%.
У кого-то ведь такая вещь имеется, 100%.
ManHunter
(30.11.2015 в 17:16):
Я остановлюсь на мысли, что корректность файла является достаточной, если система способна правильно разместить его в памяти и подготовить к запуску (или к загрузке данных, в случае, например, dll с ресурсами).
user
(30.11.2015 в 17:05):
К сожалению, определения самого факта незагружаемости файла бывает недостаточно. Такой подход можно применять в утилитах, чтобы проверить, верно ли выполнена манипуляция с файлом и в случае ошибки откатиться к сохранённому варианту.
Вообще, это очень мутная тема. Такая утилита, как PEVerify (HIEW) во многих случаях не имеет претензий к файлу, но тем не менее он не загружается.
Вот кто мог бы прояснить эти все вопросы, так это микрософт - но они не горят стремлением это делать. Больше того, их фирменная HDR.EXE бывало висла при проверке некорректного PE-файла..
--добавлено--
Хм. Уже HIEW 8.44 есть..
Вообще, это очень мутная тема. Такая утилита, как PEVerify (HIEW) во многих случаях не имеет претензий к файлу, но тем не менее он не загружается.
Вот кто мог бы прояснить эти все вопросы, так это микрософт - но они не горят стремлением это делать. Больше того, их фирменная HDR.EXE бывало висла при проверке некорректного PE-файла..
--добавлено--
Хм. Уже HIEW 8.44 есть..
Добавить комментарий
Заполните форму для добавления комментария