Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Определить тип приложения [D7, Win95/98, WinME, NT4, Win2k, WinXP]


Страницы:   1 2 3 4

-=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. А консоль приложение само создаст с удовольствием после запуска. Поэтому лично мне и не ясен весь этот цирк. Уж извини.


Страницы:   1 2 3 4

Наверх

Титульная страница Поиск, карта сайта Написать письмо