![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Определить тип приложения [D7, Win95/98, WinME, NT4, Win2k, WinXP]
-=GaLaN=- © (2005-05-27 01:03:00)У меня есть путь к файлу exe. Как можно определить тип приложения - консольное ли оно, DOS, Win32?
Просто Джо (2005-05-27 10:14:00) [21]
> [57] Игорь Шевченко © (27.05.05 10:07)
Снимаю шляпу, которой нет (но все же).
Игорь Шевченко (2005-05-27 10:07:00) [22]
> Как можно определить тип приложения - консольное ли оно,
> DOS, Win32?
GetBinaryType
wal (2005-05-27 09:56:00) [23]Хочу добавить насчет MZ-заголовка. В старые добрые времена, при царе Горохе, переименовал я файл .com в .exe. И ничего, ОС схавала и не подавилась. Программа нормально работала. А в .com, как известно, никаких заголовков нет. Незнаю, как в таком случае современные ОС себя вести будут, если так же, то однозначно определить, что .exe файл - это НЕ приложение без анализа кода, наверное, невозможно.
С уважением
Просто Джо (2005-05-27 08:51:00) [24]
> [54] Digitman © (27.05.05 08:49)
Нет, тут человек определяет консольное приложение или нет.
Digitman (2005-05-27 08:49:00) [25]а стоит ли городить огород с исследованием заголовка для определения, является ли файл исполняемым файлом ДОС ? не проще ли сделать это одной-единственной строкой, поручив системе самой определить это ?
win32check(loadlibraryex('C:\Utilites\arj.exe', 0, DONT_RESOLVE_DLL_REFERENCES) <> 0);
VMcL (2005-05-27 08:06:00) [26]>> Просто Джо © (27.05.05 05:04) [51]
Тогда уж так:
function TPEImageHeader.GetSubsystemName: String;
begin
if (FSubSystem >= Low(SubSystemNames)) and (FSubSystem <= High(SubSystemNames)) then
Result := SubSystemNames[FSubSystem]
else
Result := 'Ambiguous';
end;
Defunct (2005-05-27 05:11:00) [27]> Извращенное ночное воображение.
Дык, воображение только ночью и работает. ;)
Днем жара, шум, свет, телефон, болтовня и прочее отвлекает.
Хороший пример получился, пригодится
Спасибо Джо ;>
Просто Джо (2005-05-27 05:04:00) [28]Блин, во избежание выхода за пределы массива в случае, если в поле subsystem находится ерунда, перепеши метод GetSubsystemName так:
function TPEImageHeader.GetSubsystemName: string;
begin
if FSubSystem in [0..8] then
Result := SubSystemNames[FSubSystem]
else
Result := 'Ambiguous'
end;
Просто Джо (2005-05-27 05:00:00) [29]Кстати, хороший пример раздувания кода :)
Просто Джо (2005-05-27 04:59:00) [30]Ох, бессонница... Раз уж все-равно не сплю, накорябал тут кусок кода. Определяет subsystem у исполнимого PE-файла. Особо скрупулезных проверок не делал, просто пример.
unit ExeImages;
interface
uses Windows, SysUtils, Classes;
type
ENotPEFile = class (Exception);
ENoOptionalHeader = class (Exception);
IImageHeader = interface
['{19A8FD78-D997-4645-9667-47AB841DCD0C}']
function GetSubsystem: Word;
function GetSubsystemName: string;
property Subsystem: Word read GetSubsystem;
property SubsystemName: string read GetSubsystemName;
end;
TPEImageHeader = class (TInterfacedObject, IImageHeader)
private
FFileName: string;
FStream: TFileStream;
FSubSystem: Word;
function GetPEOffset: Integer;
procedure ReadHeaders;
procedure OpenFile;
procedure CloseFile;
public
function GetSubsystem: Word;
function GetSubsystemName: string;
constructor Create (AFileName: string); reintroduce;
end;
implementation
const
fmOpenRead = 0;
SubSystemNames: array [0..8] of string =
(
'Unknown',
'Native',
'Windows GUI',
'Windows character mode',
'4',
'OS/2 character mode',
'6',
'POSIX character mode',
'8 subsystem'
);
{ TPEImageHeader }
procedure TPEImageHeader.CloseFile;
begin
FStream.Free;
end;
constructor TPEImageHeader.Create;
begin
inherited Create;
FFileName := AFileName;
ReadHeaders;
end;
function TPEImageHeader.GetPEOffset: Integer;
var
DOSHDR: TImageDosHeader;
begin
FStream.Read(DOSHDR,SizeOf(DOSHDR));
Result := DOSHDR._lfanew
end;
function TPEImageHeader.GetSubsystem: Word;
begin
Result := FSubSystem
end;
procedure TPEImageHeader.ReadHeaders;
var
PEOffset: Integer;
ImgHdr: _IMAGE_NT_HEADERS;
begin
OpenFile;
try
PEOffset := GetPEOffset;
if PEOffset <> 0 then
begin
FStream.Seek (PEOffset,soFromBeginning);
FStream.Read(ImgHdr,SizeOf(ImgHdr));
if ImgHdr.FileHeader.SizeOfOptionalHeader <> 0 then
begin
FSubSystem := ImgHdr.OptionalHeader.Subsystem;
end
else
raise ENoOptionalHeader.Create('No optional PE header');
end
else
raise ENotPEFile.Create('No PE header detected');
finally
CloseFile;
end;
end;
procedure TPEImageHeader.OpenFile;
begin
FStream := TFileStream.Create(FFileName,fmOpenRead);
end;
function TPEImageHeader.GetSubsystemName: string;
begin
Result := SubSystemNames[FSubSystem]
end;
end.
Использование:
procedure TForm1.Button1Click(Sender: TObject);
var
Img: IImageHeader;
begin
try
Img := TPEImageHeader.Create('C:\Program Files\Far\Far.exe');
ShowMessage(Img.SubsystemName);
except
on E: Exception do
MessageDlg ('Error: ' + E.Message, mtWarning,[MBOK],-1);
end;
end;
Как видишь, обернул все это дело в класс-наследник TInterfacedObject, посему, можешь не заботиться об своевременном освобождении ресурсов и всяких там вызовахFree. Зачем я это сделал? Скукота... :((( Извращенное ночное воображение.
Defunct (2005-05-27 03:44:00) [31]Defunct © (27.05.05 03:32) [46]
Смайлик не там поставил.
должно было быть так:
Тогда это DOS приложение
Что же еще непонятного? :)
-=GaLaN=- (27.05.05 03:36) [47]
хм.. но этот файл же не win32.
поищите еще особенности заголовка для приложений win3.1
итого имеем:
1. если есть опциональный заголовок, тогда анализируем subsystem.
2. если нет, тогда остается отличить DOS от Win3.1 (Win3.1 все графические)
-=GaLaN=- (2005-05-27 03:36:00) [32]2Defunct:
Ой ли... В качестве примера могу привести файл из дистрибутива WinXP: System32\sysedit.exe, имеющий тип New Executable (NE) (Windows 3.1). Графическое приложение Windows без опционального заголовка.
2Просто Джо:
Запустите "ping ww.ru" из-под Win+R. Вы поймёте, о чём я...
Defunct (2005-05-27 03:32:00) [33]-=GaLaN=- (27.05.05 03:22) [45]
> Однако, как быть, если этого _опционального_ хидера не будет?
Тогда это DOS приложение :)
Что же еще непонятного?
-=GaLaN=- (2005-05-27 03:22:00) [34]2Defunct:
Да, вы правы, это я упустил...
2Просто Джо:
Так, это уже интересно. Сейчас попробую. Однако, как быть, если этого _опционального_ хидера не будет?
Просто Джо (2005-05-27 03:15:00) [35]Вот СКОПИРОВАЛ описание нужной тебе структуры из той статьи:
Type
_IMAGE_OPTIONAL_HEADER = packed record //(C++: IMAGE_OPTIONAL_HEADER)
Magic: Word; //Сигнатура:
// 010B для 32-битного PE,
// 020B для 64-битного,
// 0107 для ROM (???)
MajorLinkerVersion: Byte;
MinorLinkerVersion: Byte; //Понятно без слов
SizeOfCode: DWORD; //Суммарный виртуальный размер всех секций, содержащих код
SizeOfInitializedData: DWORD; //То же для инициализированных данных
SizeOfUninitializedData: DWORD; // и для неинициализированных
AddressOfEntryPoint: DWORD; //Виртуальный адрес точки входа в PE-файл (для DLL это адрес
// DllMain, - процедуры, обрабатывающей сообщения о загрузке/выгрузке данной DLL в
// какой-либо процесс). 0, если точки входа нет.
BaseOfCode: DWORD; // Виртуальный адрес секции с кодом. Что содержит это поле, если секций
//несколько, мне точно не известно – но это и не представляет интереса
BaseOfData: DWORD; //То же для данных
ImageBase: DWORD; //Предпочтительный базовый адрес загрузки. Внутри DLL все абсолютные (т.е.
// не в виде смещения от ссылающейся инструкции, а в виде адреса) ссылки на содержащиеся
// в ней объекты формируются в предположении, что DLL загружается в память именно с
// этого базового адреса. Если это не так, ссылки нужно корректировать при помощи
// информации из секции перемещений (Relocation), см. раздел о коррекции ссылок
SectionAlignment: DWORD; //Все виртуальные адреса секций кратны этому числу
FileAlignment: DWORD; //Для любой секции данные, помещаемые в нее, находятся в исходном
// файле по смещению, кратному этому числу
MajorOperatingSystemVersion: Word;
MinorOperatingSystemVersion: Word; //Тоже, вроде бы, понятно
MajorImageVersion: Word;
MinorImageVersion: Word;
MajorSubsystemVersion: Word;
MinorSubsystemVersion: Word;
Win32VersionValue: DWORD; //Зарезервировано. Есть мысль, что сюда положат версию
// Win32-эмулятора для Win64-систем
SizeOfImage: DWORD; //Размер области памяти, необходимый для размещения образа PE-файла
//Равен виртуальному адресу, начиная с которого могла бы располагаться
// секция, идущая в памяти сразу за последней существующей секцией (т.е.
// вирт. адрес конца последней секции, дополненной до границы секции с
// учетом SectionAlignment)
SizeOfHeaders: DWORD; //Размер области заголовков. Областью заголовков считается все
// пространство исходного файла до списка секций
CheckSum: DWORD; //Возможно, род цифровой подписи или вид CRC, но обычно это поле равно 0
Subsystem: Word; //Для исполнимых файлов – требуемая для работы подсистема
DllCharacteristics: Word; //Свойства DLL. Значения 1,2,4 и 8 зарезервированы;
// 2000hex означает WDM-драйвер
SizeOfStackReserve: DWORD; // *
SizeOfStackCommit: DWORD; // * Эти 4 полей управляют действиями,
SizeOfHeapReserve: DWORD; // * выполняемыми при загрузке EXE-файла
SizeOfHeapCommit: DWORD; // *
LoaderFlags: DWORD; //Рудимент, более не используется
NumberOfRvaAndSizes: DWORD; // Количество элементов в каталоге DataDirectory
//Далее следует массив из NumberOfRvaAndSizes элементов, ссылающиеся на важные структуры данных,
// такие как: секция импорта, секция экспорта, секция ресурсов и т.п.
//Лучше для доступа к этим структурам применять именно DataDirectory, а не искать нужную
// секцию путем перебора всех секций, т.к. в одной секции могут (теоретически) находиться
// сразу несколько управляющих структур (напр., и таблицы импорта, и экспорта)
DataDirectory: packed array[0..IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1] of TImageDataDirectory;
end;
Жирным выделено нужное поле.
> Но "ping www.ru" умрёт после того, как отработает
Ты о чем?
Просто Джо (2005-05-27 03:12:00) [36]
> [40] -=GaLaN=- (27.05.05 03:05)
> Каким значением, полученным из файла? Каким образом полученным?
> Вы о чём вообще? :)
См. статью по ссылке. Узнаешь из нее, как прочитать ПЕ-заголовок (дополнительные он же расширенный). Далее, в поле Subsystem: Word; находится значение. Оно-то тебе и нужно. Там и будет одна из тех констант, на которые я указал.
Defunct (2005-05-27 03:09:00) [37]Так или иначе не достаточно только 3-го байта для определяния DOS/WIN, потому что это младший байт количества байт последней страницы. Вполне может быть DOS приложение у которого 3-й и 4-й байты равны соответственно 50h и 00h
Defunct (2005-05-27 03:06:00) [38]-=GaLaN=- (27.05.05 03:05) [40]
пардон прочитал "НЕ" как "he" ;)
-=GaLaN=- (2005-05-27 03:05:00) [39]2Defunct:
Я сказал НЕ 50, значит DOS. Внимательнее, пожалуйста. ;)
2Просто Джо:
Каким значением, полученным из файла? Каким образом полученным? Вы о чём вообще? :)
А цирк прост. Консоль-то приложение создаст. Но "ping www.ru" умрёт после того, как отработает. И если я сам хочу указать интерпретатор для обработки консольных приложений?
Просто Джо (2005-05-27 03:00:00) [40]
> однако больше в этом файле они нигде не используются...
а нужно?? Эти константы ты должен сравнивать со значением, полученным тобой из файла.
Но там может быть вообще что угодно, хотя бы и IMAGE_SUBSYSTEM_UNKNOWN. А консоль приложение само создаст с удовольствием после запуска. Поэтому лично мне и не ясен весь этот цирк. Уж извини.