Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "WinAPI";
Текущий архив: 2005.07.31;
Скачать: [xml.tar.bz2];

Вниз

Определить тип приложения   Найти похожие ветки 

 
-=GaLaN=-   (2005-05-27 01:03) [0]

У меня есть путь к файлу exe. Как можно определить тип приложения - консольное ли оно, DOS, Win32?


 
Defunct ©   (2005-05-27 01:09) [1]

http://www.rsdn.ru/article/baseserv/peloader.xml

в этой статье можно найти краткое описание заголока PE файлов, а также список литературы, который вам не помешает.


 
Просто Джо ©   (2005-05-27 01:09) [2]

Во-первых, оно не обязано вообще быть приложением.
Во-вторых, определить, является ли оно DOS-приложением тоже нельзя.
В-третьих, приложения Win32 - это и консольные приложения, в том числе.
Ну, а если уверен, что оно точно является Win32-приложением, тогда можно попытаться прочитать PE-заголовок файла и из него определить тип приложения, там для этого предусмотрено поле. Короче говоря, ищи по ключевым словам "структура PE-заголовка".


 
Defunct ©   (2005-05-27 01:13) [3]

Просто Джо ©   (27.05.05 01:09) [2]

> Во-вторых, определить, является ли оно DOS-приложением тоже нельзя.

Можно - необходимые и достаточные условия:
1. Отсутствие MS-DOS заголовка EXE файла. (COM-формат)
2. Отсутствие Win32 заголовка.

> В-третьих, приложения Win32 - это и консольные приложения, в том числе.

Тоже можно определить по заголовку, но не помню как.


 
Просто Джо ©   (2005-05-27 01:19) [4]

[3] Defunct ©   (27.05.05 01:13)
> Можно - необходимые и достаточные условия:
> 1. Отсутствие MS-DOS заголовка EXE файла. (COM-формат)
> 2. Отсутствие Win32 заголовка.

Да, я неудачно выразился. Не заметил, что уточняется "EXE", увидел только ключевое слово "приложение".

> > В-третьих, приложения Win32 - это и консольные приложения,
> в том числе.
Это мое замечание к тому, что автор противопоставляет консольные и Win32-приложения. В то время как консольные - это разновидность Win32-приложений.

К автору: не стоит забывать, что в файле "екзе" может также находится 16-битное приложение, приложение для OS/2 и мало ли что еще.


 
KilkennyCat ©   (2005-05-27 01:25) [5]

И не стоит также забывать, что расширения еxe, com, bat - являются лишь информативными о запускаемости. Все остальное - согласно заголовкам, поэтому [3] Defunct ©   (27.05.05 01:13) - верно.


 
-=GaLaN=-   (2005-05-27 01:35) [6]

Спасибо за ответы, попробую немного точнее дать задачу. Есть путь к файлу exe. Нужно определить, что во-первых, это приложение, а вторых, это приложение, работающее в текстовом режиме. Не важно, DOS или Win32 Console.
Я попробую почитать статью по вышеприведённой ссылке и разобрать в ней, но неужели нет каких-нибудь WinAPI функций? Ведь command.com и cmd.exe как-то определяют это...


 
GuAV ©   (2005-05-27 01:48) [7]

-=GaLaN=-   (27.05.05 1:35) [6]
Не важно, DOS или Win32 Console.

DOS приложение, работающее в текстовом режиме не отличается никакими заголовками от DOS приложения, работающего в графическом режиме. Изначально дос-приложение запускается в текстовом режиме, но оно может перейти в графический.


 
Просто Джо ©   (2005-05-27 01:53) [8]


> [7] GuAV ©   (27.05.05 01:48)
> Изначально дос-приложение запускается в текстовом
> режиме

Ну уж нет, не обязательно. Оно запускается в том режиме, какой установлен на момент запуска.


 
Defunct ©   (2005-05-27 02:11) [9]

> Нужно определить, что во-первых, это приложение, а вторых, это приложение, работающее в текстовом режиме.

Можно определить наличие переключения в графический режим (в DOS приложении). Для этого придется "прошерстить" весь exe/com файл и искать последовательность команд

такую:
mov  ax, zzyy;  // где yy больше 3, а zz = 0
int  10h

вот как будет это выглядеть в hex:
xx xx xx xx B8 YY 00 CD 10 xx xx
на месте xx, любые числа.

или такую:
mov  ah, 0  
mov  al, yy     // где yy больше 3
...
int  10h

вот как будет это выглядеть в hex:
xx xx xx xx B4 00 B0 YY xx .... xx CD 10 xx xx

ps: чаще используется первая последовательность.


 
-=GaLaN=-   (2005-05-27 02:15) [10]

2Defunct:
Но, согласись, отсутствие данных последовательностей вовсе не означает, что это консольное приложение? Оно вполне может оказаться обычным графическим Win32 или WinNT приложением...


 
Просто Джо ©   (2005-05-27 02:16) [11]

Угу, или такую:
xor ah,ah


 
Просто Джо ©   (2005-05-27 02:18) [12]


> [10] -=GaLaN=-   (27.05.05 02:15)

А зачем это нужно, если не секрет?


 
Defunct ©   (2005-05-27 02:22) [13]

-=GaLaN=-   (27.05.05 02:15) [10]

> Но, согласись, отсутствие данных последовательностей вовсе не означает, что это консольное приложение?
Конечно.

Наличие данных последовательностей может быть информативным только в DOS приложениях которые переключают видеорежим, не более того. В Win32 приложении такой код будет просто неработоспособен.

Т.е. вначале нужно точно знать, что приложение - DOS. Затем, если интересует в каком режиме работает именно это DOS приложение, ищем эти последовательности. (плюс может быть ложное срабатывание, например, в программе размещены данные, которые совпадают с указанными последовательностями команд).


 
Просто Джо ©   (2005-05-27 02:24) [14]

Хм. А если это ДОС-приложение работает в графическом режиме, иногда переключаясь в текстовый, - то как его, простите, называть? Пример: Автокад версии 10.
Не туда копаете, товарищи :)


 
KilkennyCat ©   (2005-05-27 02:27) [15]


> Не туда копаете, товарищи :)


Угу. надо OCR экрана делать.


 
Просто Джо ©   (2005-05-27 02:28) [16]


>  [15] KilkennyCat ©   (27.05.05 02:27)

Да, ИИ в задаче мощный, это вам не плюшки со стола таскать (ц)
:)


 
Defunct ©   (2005-05-27 02:29) [17]

Просто Джо ©   (27.05.05 02:24) [14]

Ну и пусть себе переключается в текстовый. Код для переключения в графический режим все равно в нем будет.


 
Просто Джо ©   (2005-05-27 02:30) [18]


>  [17] Defunct ©   (27.05.05 02:29)
> Ну и пусть себе переключается в текстовый. Код для переключения
> в графический режим все равно в нем будет.


Какой? Может он напрямую с драйвером VESA общается с особыми изысками?


 
Defunct ©   (2005-05-27 02:31) [19]

Просто Джо ©   (27.05.05 02:30) [18]

Режимы VESA включаются такой же самой последовательностью кода.


 
Просто Джо ©   (2005-05-27 02:31) [20]

Или руки у программиста воот такой кривизны и у него там
xor ah,ah
push val
pop al
int 10h


 
Просто Джо ©   (2005-05-27 02:33) [21]


>  [19] Defunct ©   (27.05.05 02:31)
> Просто Джо ©   (27.05.05 02:30) [18]
>
> Режимы VESA включаются такой же самой последовательностью
> кода.

Я вот не уверен. Насколько помню, веза-драйвер висит на своем прерывании и допускает вызовы напрямую этого прерывания. Не помню, если честно. Да и кодв может быть столько вариантов, что все и не предусмотришь.


 
Defunct ©   (2005-05-27 02:34) [22]

Просто Джо ©   (27.05.05 02:31) [20]

:))
нельзя же думать только о плохом.
реализовать вначале 2 последовательности, при ошибке распознавания внести маску из приложения в определении которого программа ошиблась.


 
Просто Джо ©   (2005-05-27 02:34) [23]

Я автору не зря вопрос задал: зачем это надо. Тут от задачи нужно отталкиваться, имхо.


 
Defunct ©   (2005-05-27 02:36) [24]

Просто Джо ©   (27.05.05 02:33) [21]

А я в этом уверен (VESA драйвер "висит" на int 10h), просто довелось проработать с VESA.


 
-=GaLaN=-   (2005-05-27 02:38) [25]

Народ! Немного не в ту сторону беседа ушла. :) Честно говоря, если DOS приложение будет переключаться в графический режим - это не важно. Главное - определить, что это DOS-приложение. Т.е. по сути, мне надо решить задачу от противного - определить, что это приложение, но НЕ графическое Win32\16.

У меня есть уже несколько домыслов. Определить, что это приложение легко. Файл должен начинаться с 4D 5A. Если дальше НЕ идёт 50, то это, наверное, DOS. Если идёт, то это уже Win32 приложение, но опять же - не понятно, консольное или графическое. :(
Возможно, я не прав и что-то упустил...

2Просто Джо:
Не секрет. У меня программа должна запускать приложение. Я хочу определить, что это консольное приложение, чтобы запустить его не просто, а, например, через cmd.exe /k или иной обработчик.


 
Просто Джо ©   (2005-05-27 02:39) [26]

[24] Defunct ©   (27.05.05 02:36)

В-общем, пока автор пусть поспит, а мы все возможные сигнатуры тут ему напишем :)) А он проснется - и окажется, что ему стандартный вывод нужно было перехватить :)


 
Просто Джо ©   (2005-05-27 02:40) [27]


>  [26] Просто Джо ©   (27.05.05 02:39)

А поутру она проснулась :)) Опоздал.


 
-=GaLaN=-   (2005-05-27 02:41) [28]

Кстати, сама винда, когда жмякаешь Enter на файле, ведь определяет, надо ли звать command.com и cmd.exe или пускать приложение так...


 
Defunct ©   (2005-05-27 02:41) [29]

-=GaLaN=-   (27.05.05 02:38) [25]

> Если дальше НЕ идёт 50, то это, наверное, DOS.

Так дело не пойдет :)
Берите открывайте справочик, смотрите что обозначает каждое поле заголовка EXE файла, потом аналогичную процедуру для PE-заголовка и ваша задача решена.


 
Просто Джо ©   (2005-05-27 02:43) [30]


> Я хочу определить, что это консольное приложение, чтобы
> запустить его не просто, а, например, через cmd.exe /k или
> иной обработчик.

А разве другое нельзя запустить "через" cmd.exe /K ?


 
Просто Джо ©   (2005-05-27 02:44) [31]

Тебе ж дали ссылку на описание PE-заголовка, чего ты мучаешься?


 
-=GaLaN=-   (2005-05-27 02:48) [32]

2Просто Джо:
Ага, дали, вот цитата оттуда:
"Я не буду подробно описывать форматы заголовков – большая часть из них описана в Windows.pas". Ни ничего там практически нет для моей задачи. :(
А другое запустить через cmd.exe /k нельзя - консольное окно будет болтаться на экране, это не дело.


 
Defunct ©   (2005-05-27 02:51) [33]

> -=GaLaN=-

Если определять по вашему:
цифра 50 наверное DOS вы так долго будете определять. Вот если открыть спрвочник там четко написано.
MS-DOS заголовок exe-шника:

0000  word  Signature               "4D5A"
0002  word  Bytes on last page
0004  word  Pages in File
0006  word  Relocations
0008  word  Paragraphs in header
000A  word  Minimum memory
000C  word  Maximum memory
000E  dword SS:SP
0012  word  Checksum
0014  dword CS:IP (entrypoint)
0016  word  Relocation table address
0018  word  Overlay number
...

за MS-DOS заголовком располагается Win32 заголовок. Как отличить DOS от Win32 написал в [3]


 
Просто Джо ©   (2005-05-27 02:55) [34]

[32] -=GaLaN=-   (27.05.05 02:48)
Ну, тогда запускай все через WinExec.
Нужные определения ПЕ-заголовка есть в Windows.pas, в том чиле и константы, определяющие режим приложения (subsystem values): например IMAGE_SUBSYSTEM_WINDOWS_GUI. Если есть не все, что нужно, погугли, в сетке не раз встречал расширенное описание формата.


 
-=GaLaN=-   (2005-05-27 02:56) [35]

2Defunc:
Да, это я уже нашёл. И был прав, кстати, говоря, что если третий байт НЕ 50, то это DOS. :) Вопрос остался лишь в том, как из Win32 приложений отличить консольные...


 
Просто Джо ©   (2005-05-27 02:56) [36]


> Вопрос остался лишь в том, как из Win32 приложений отличить
> консольные...

См [34], константы Subsystem Values.


 
-=GaLaN=-   (2005-05-27 02:57) [37]

2Просто Джо:
Константы-то есть, кстати, нужная мне называется IMAGE_SUBSYSTEM_WINDOWS_CUI, однако больше в этом файле они нигде не используются...


 
Defunct ©   (2005-05-27 02:59) [38]

-=GaLaN=-   (27.05.05 02:56) [35]

Не может быть!!
Вы видимо смотрите только по одному dos exe-шнику.

Открыл у себя первый попавшийся DOS exe-шник, третий байт равен С0h

Да и разве не видно из приведенного в [33] заголовка, 3-й и 4-й байты показывают сколько байт занимает последняя страница exe файла.


 
Просто Джо ©   (2005-05-27 03:00) [39]


> однако больше в этом файле они нигде не используются...

а нужно?? Эти константы ты должен сравнивать со значением, полученным тобой из файла.
Но там может быть вообще что угодно, хотя бы и IMAGE_SUBSYSTEM_UNKNOWN. А консоль приложение само создаст с удовольствием после запуска. Поэтому лично мне и не ясен весь этот цирк. Уж извини.


 
-=GaLaN=-   (2005-05-27 03:05) [40]

2Defunct:
Я сказал НЕ 50, значит DOS. Внимательнее, пожалуйста. ;)

2Просто Джо:
Каким значением, полученным из файла? Каким образом полученным? Вы о чём вообще? :)
А цирк прост. Консоль-то приложение создаст. Но "ping www.ru" умрёт после того, как отработает. И если я сам хочу указать интерпретатор для обработки консольных приложений?


 
Defunct ©   (2005-05-27 03:06) [41]

-=GaLaN=-   (27.05.05 03:05) [40]

пардон прочитал "НЕ" как "he" ;)


 
Defunct ©   (2005-05-27 03:09) [42]

Так или иначе не достаточно только 3-го байта для определяния DOS/WIN, потому что это младший байт количества байт последней страницы. Вполне может быть DOS приложение у которого 3-й и 4-й байты равны соответственно 50h и 00h


 
Просто Джо ©   (2005-05-27 03:12) [43]


>  [40] -=GaLaN=-   (27.05.05 03:05)
> Каким значением, полученным из файла? Каким образом полученным?
> Вы о чём вообще? :)

См. статью по ссылке. Узнаешь из нее, как прочитать ПЕ-заголовок (дополнительные он же расширенный). Далее, в поле Subsystem: Word; находится значение. Оно-то тебе и нужно. Там и будет одна из тех констант, на которые я указал.


 
Просто Джо ©   (2005-05-27 03:15) [44]

Вот СКОПИРОВАЛ описание нужной тебе структуры из той статьи:

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" умрёт после того, как отработает

Ты о чем?


 
-=GaLaN=-   (2005-05-27 03:22) [45]

2Defunct:
Да, вы правы, это я упустил...

2Просто Джо:
Так, это уже интересно. Сейчас попробую. Однако, как быть, если этого _опционального_ хидера не будет?


 
Defunct ©   (2005-05-27 03:32) [46]

-=GaLaN=-   (27.05.05 03:22) [45]

> Однако, как быть, если этого _опционального_ хидера не будет?

Тогда это DOS приложение :)
Что же еще непонятного?


 
-=GaLaN=-   (2005-05-27 03:36) [47]

2Defunct:
Ой ли... В качестве примера могу привести файл из дистрибутива WinXP: System32\sysedit.exe, имеющий тип New Executable (NE) (Windows 3.1). Графическое приложение Windows без опционального заголовка.

2Просто Джо:
Запустите "ping ww.ru" из-под Win+R. Вы поймёте, о чём я...


 
Defunct ©   (2005-05-27 03:44) [48]

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 все графические)


 
Просто Джо ©   (2005-05-27 04:59) [49]

Ох, бессонница... Раз уж все-равно не сплю, накорябал тут кусок кода. Определяет 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. Зачем я это сделал? Скукота... :((( Извращенное ночное воображение.


 
Просто Джо ©   (2005-05-27 05:00) [50]

Кстати, хороший пример раздувания кода :)


 
Просто Джо ©   (2005-05-27 05:04) [51]

Блин, во избежание выхода за пределы массива в случае, если в поле subsystem находится ерунда, перепеши метод GetSubsystemName так:


function TPEImageHeader.GetSubsystemName: string;
begin
 if FSubSystem in [0..8] then
   Result := SubSystemNames[FSubSystem]
 else
   Result := "Ambiguous"
end;


 
Defunct ©   (2005-05-27 05:11) [52]

> Извращенное ночное воображение.

Дык, воображение только ночью и работает. ;)
Днем жара, шум, свет, телефон, болтовня и прочее отвлекает.

Хороший пример получился, пригодится
Спасибо Джо ;>


 
VMcL ©   (2005-05-27 08:06) [53]

>>Просто Джо ©   (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;


 
Digitman ©   (2005-05-27 08:49) [54]

а стоит ли городить огород с исследованием заголовка для определения, является ли файл исполняемым файлом ДОС ? не проще ли сделать это одной-единственной строкой, поручив системе самой определить это ?

win32check(loadlibraryex("C:\Utilites\arj.exe", 0, DONT_RESOLVE_DLL_REFERENCES) <> 0);


 
Просто Джо ©   (2005-05-27 08:51) [55]


>  [54] Digitman ©   (27.05.05 08:49)

Нет, тут человек определяет консольное приложение или нет.


 
wal ©   (2005-05-27 09:56) [56]

Хочу добавить насчет MZ-заголовка. В старые добрые времена, при царе Горохе, переименовал я файл .com в .exe. И ничего, ОС схавала и не подавилась. Программа нормально работала. А в .com, как известно, никаких заголовков нет. Незнаю, как в таком случае современные ОС себя вести будут, если так же, то однозначно определить, что .exe файл - это НЕ приложение без анализа кода, наверное, невозможно.

С уважением


 
Игорь Шевченко ©   (2005-05-27 10:07) [57]


> Как можно определить тип приложения - консольное ли оно,
> DOS, Win32?


GetBinaryType


 
Просто Джо ©   (2005-05-27 10:14) [58]


>  [57] Игорь Шевченко ©   (27.05.05 10:07)

Снимаю шляпу, которой нет (но все же).


 
Просто Джо ©   (2005-05-27 10:18) [59]

А все-таки, функцией GetBinaryType не определишь - консольное оно или нет, все равно придется в хэдэрах ковыряться.


 
Игорь Шевченко ©   (2005-05-27 10:40) [60]

Просто Джо ©   (27.05.05 10:18) [59]

type
 THSBinaryType = (hsbtError, hsbtWin32, hsbtWin16, hsbtDos16, hsbtCom,
   hsbtVxd, hsbtW3, hsBtUnknown);

function HSGetBinaryType (const FileName: string): THSBinaryType;
type
 PIMAGE_DOS_HEADER = ^IMAGE_DOS_HEADER;
 PIMAGE_NT_HEADERS = PImageNtHeaders;
var
 Mapper: THSFileMapper;
 DosHeader: PIMAGE_DOS_HEADER;
 FileHeader: PIMAGE_NT_HEADERS;
begin
 Result := hsbtError;
 Mapper := THSFileMapper.Create (FileName);
 try
   if (Mapper.Map[0] <> "M") or (Mapper.Map[1] <> "Z") then begin
     if UpperCase(ExtractFileExt(FileName)) = ".COM" then
       Result := hsbtCom;
     Exit;
   end else if Mapper.FileSize >= SizeOf(IMAGE_DOS_HEADER) then begin
     DosHeader := PIMAGE_DOS_HEADER(Mapper.Map);
     if (DosHeader^._lfanew > $40) { Matt Pietrek } and
        (DWORD(DosHeader^._lfanew) < Mapper.FileSize - SizeOf(WORD)) then begin
       FileHeader := PIMAGE_NT_HEADERS(DWORD(DosHeader) +
                                       DWORD(DosHeader^._lfanew));
       if FileHeader^.Signature = IMAGE_NT_SIGNATURE then
         Result := hsbtWin32
       else if WORD(FileHeader^.Signature) = IMAGE_OS2_SIGNATURE then
         Result := hsbtWin16
       else if WORD(FileHeader^.Signature) = IMAGE_VXD_SIGNATURE then
         Result := hsbtVxd
       else if WORD(FileHeader^.Signature) = IMAGE_W3_SIGNATURE then
         Result := hsbtW3
       else
         Result := hsbtUnknown;
     end else
       Result := hsbtDos16;
   end;
 finally
   Mapper.Free;
 end;
end;


 
Игорь Шевченко ©   (2005-05-27 10:43) [61]

Просто Джо ©   (27.05.05 10:18) [59]

{
  Модуль: HSPEImage

  Описание: Класс для образа 32-битного исполняемого файла Windows

  Автор: Игорь Шевченко

  Дата создания: 23.02.2003

  История изменений:
  03.04.2003 Добавлен метод получения имени импортируемой функции по адресу
             в таблице импорта.
             Добавлен метод получения импортируемых функций.
  04.04.2003 Добавлено описание для структур .Net. При описании использовалась
             статья Павла Румянцева в RSDN Magazine №2 2003.
}
unit HSPEImage;

interface
uses
 Windows, HSDosImage, HSFileMapper, Classes, SysUtils, HSImageUtils,
 HSObjectList;

type
 PDwordArray = ^TDwordArray;
 TDwordArray = array[0..8191] of DWORD;
 USHORT = Word;

 PIMAGE_NT_HEADERS = PImageNtHeaders;
 PIMAGE_DATA_DIRECTORY = ^IMAGE_DATA_DIRECTORY;

 PIMAGE_IMPORT_DESCRIPTOR = ^IMAGE_IMPORT_DESCRIPTOR;
 IMAGE_IMPORT_DESCRIPTOR = packed record
   Characteristics: Cardinal;  // 0 for terminating null import descriptor
                                // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
   TimeDateStamp: Cardinal;    // 0 if not bound,
                                // -1 if bound, and real date\time stamp
                                //     in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
                                // O.W. date/time stamp of DLL bound to (Old BIND)

   ForwarderChain: Cardinal;   // -1 if no forwarders
   Name: Cardinal;
   FirstThunk: Cardinal;       // RVA to IAT (if bound this IAT has actual addresses)
 end;

 IMAGE_IMPORT_BY_NAME = packed record
   Hint: WORD;
   Name: Char;
 end;
 PIMAGE_IMPORT_BY_NAME = ^IMAGE_IMPORT_BY_NAME;

 TDelayLoadImportTableItem = packed record
   Flags: LongInt;
   DllName: Cardinal;
   Handle: Cardinal; //RVA to DATA segment
   EpAddresses: Cardinal; //Array of entry point addresses for this library
   ImportNameTable: Cardinal; //RVA of Module name table
   Reserved2: Cardinal; //Don"t know
   Reserved3: Cardinal; //Don"t know
   Reserved4: Cardinal; //Don"t know
 end;
 PDelayLoadImportTableItem = ^TDelayLoadImportTableItem;

 TDelayLoadImportTableItemArray = array [0..1024] of TDelayLoadImportTableItem;
 PDelayLoadImportTableItemArray = ^TDelayLoadImportTableItemArray;

 PDelayLoadEntryItem = PIMAGE_IMPORT_BY_NAME;

 IMAGE_COR20_HEADER = packed record
   //Информация о версии
   cb: ULONG;
   MajorRuntimeVersion: USHORT;
   MinorRuntimeVersion: USHORT;
   //Таблицы метаданных, флаги и информация о точке входа
   MetaData: IMAGE_DATA_DIRECTORY;
   Flags: ULONG;
   EntryPointToken: ULONG;
   Resources: IMAGE_DATA_DIRECTORY;
   StrongNameSignature: IMAGE_DATA_DIRECTORY;
   CodeManagerTable: IMAGE_DATA_DIRECTORY;
   VTableFixups: IMAGE_DATA_DIRECTORY;
   ExportAddressTableJumps: IMAGE_DATA_DIRECTORY;
   // Информация о прекомпилированном образе файла (только для внутреннего
   //  использования)
   ManagedNativeHeader: IMAGE_DATA_DIRECTORY;
 end;
 PIMAGE_COR20_HEADER = ^IMAGE_COR20_HEADER;

 // метадата .Net
 STORAGESIGNATURE = packed record
   lSignature: ULONG; // "Магическая" сигнатура ($424A5342)
   iMajorVer: USHORT; // Старшая часть версии файла
   iMinorVer: USHORT; // Младшая часть версии файла
   iExtraData: ULONG;  // Смещение следующей структуры с информацией
   iVersionString: ULONG; // длина строки с названием версии
   pVersion: array[0..0] of Char; //строка, содержащая название версии,
                   // длина определяется полем iVersionString
 end;
 PSTORAGESIGNATURE = ^STORAGESIGNATURE;

 STORAGEHEADER = packed record
   fFlags: BYTE; // Флаги STGHDR_
   Pad: BYTE;
   iStreams: USHORT; // Число стримов
 end;
 PSTORAGEHEADER = ^STORAGEHEADER;

 STORAGESTREAM = packed record
   iOffset: ULONG;
   iSize: ULONG;
   rcName: array[0..0] of Char;
 end;
 PSTORAGESTREAM = ^STORAGESTREAM;

 TPEImage = class(TDosImage)
 private
   FMapper: THSFileMapper;
   FModuleReferences: TStrings;
   FImportLibraries: TStringList;
   FNtHeaders: PIMAGE_NT_HEADERS;
   FSections: TList;
   FImports: TStringList;
   FDelayImports: TStringList;
   function GetSection(I: Integer): PImageSectionHeader;
   procedure LoadSections (Mapper: THSFileMapper);
   procedure LoadModuleReferences (Mapper: THSFileMapper);
   function GetImportedNameFromIATEntry (IATEntryRVA: DWORD;
     FullInfo: Boolean = false): string;
   function GetSubSystem: THSSubSystem;
   function GetImports: TStrings;
   procedure LoadImports;
   procedure LoadDelayImports;
   function GetDelayImports: TStrings;
 protected
   procedure Load (Mapper: THSFileMapper); override;
 public
   constructor Create (const FileName: string); override;
   destructor Destroy; override;
   function EpCode: PByteArray; override;
   function RawAddress (VirtualAddress: Cardinal): Cardinal;
   function GetFullImportedFunctionName(const DllName: string;
     IATEntryRVA: DWORD): string;
   function GetImportedFunctionName(const DllName: string;
     IATEntryRVA: DWORD): string;
   function FindSection (VirtualAddress: Cardinal): PImageSectionHeader;
   property Mapper: THSFileMapper read FMapper;
   property ModuleReferences: TStrings read FModuleReferences;
   property ImportLibraries: TStringList read FImportLibraries;
   property NtHeaders: PIMAGE_NT_HEADERS read FNtHeaders;
   property SectionList: TList read FSections;
   property Sections[I: Integer]: PImageSectionHeader read GetSection;
   property Subsystem: THSSubSystem read GetSubSystem;
   property Imports: TStrings read GetImports;
   property DelayImports: TStrings read GetDelayImports;
 end;

{ Не вошедшие в Windows.pas константы из Platform SDK }
const
 IMAGE_FILE_LARGE_ADDRESS_AWARE = $0020;

 IMAGE_SUBSYSTEM_NATIVE_WINDOWS = 8;   // image is a native Win9x driver.
 IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 9;   // Image runs in the Windows CE subsystem.
 IMAGE_SUBSYSTEM_EFI_APPLICATION = 10;
 IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER = 11;
 IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER = 12;
 IMAGE_SUBSYSTEM_EFI_ROM = 13;
 IMAGE_SUBSYSTEM_XBOX = 14;

 IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = $0200;    // Image understands
                                                   // isolation and doesn"t
                                                   // want it
 IMAGE_DLLCHARACTERISTICS_NO_SEH = $0400;     // Image does not use SEH.
                                              // No SE handler may reside
                                              // in this image
 IMAGE_DLLCHARACTERISTICS_NO_BIND = $0800;     // Do not bind this image.
 IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = $2000;     // Driver uses WDM model
 IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = $8000;

 IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT  = 13;   // Delay Load Import Descriptors
 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14;   // COM Runtime descriptor



 
Игорь Шевченко ©   (2005-05-27 10:44) [62]

Просто Джо ©   (27.05.05 10:18) [59]


implementation

{ TPEImage }

constructor TPEImage.Create(const FileName: string);
begin
 inherited Create(FileName);
 FSections := TList.Create;
 FModuleReferences := TStringList.Create;
 FImportLibraries := TStringList.Create;
 with FImportLibraries do begin
   Sorted := true;
   Duplicates := dupIgnore;
 end;
 FMapper := THSFileMapper.Create (FileName);
 Load (FMapper);
end;

destructor TPEImage.Destroy;
begin
 FMapper.Free;
 FImportLibraries.Free;
 FModuleReferences.Free;
 FSections.Free;
 FImports.Free;
 FDelayImports.Free;
 inherited;
end;

function TPEImage.EpCode: PByteArray;
var
 EpAddr: DWORD;
begin
 EpAddr := RawAddress(NtHeaders^.OptionalHeader.AddressOfEntryPoint);
 if EpAddr <> 0 then
   Result := PByteArray(FMapper.Map + EpAddr)
 else
   Result := nil;
end;

function TPEImage.FindSection(
 VirtualAddress: Cardinal): PImageSectionHeader;
var
 I: Integer;
begin
 Result := nil;
 for I := 0 to Pred(FSections.Count) do
   if (Sections[I].VirtualAddress <= VirtualAddress) and
      (VirtualAddress < Sections[I].VirtualAddress +
       Sections[I].SizeOfRawData) then begin
     Result := Sections[I];
     Break;
   end;
end;

function TPEImage.GetDelayImports: TStrings;
begin
 if not Assigned(FDelayImports) then begin
   FDelayImports := TStringList.Create;
   FDelayImports.Sorted := true;
   FDelayImports.Duplicates := dupIgnore;
   LoadDelayImports;
 end;
 Result := FDelayImports;
end;

function TPEImage.GetFullImportedFunctionName(const DllName: string;
 IATEntryRVA: DWORD): string;
begin
 if (IATEntryRVA and $80000000) <> 0 then
   Result := Format("%s.%d", [ChangeFileExt(DllName, ""),
     (IATEntryRVA and $7FFFFFFF)])
 else
   Result := Format("%s.%s", [ChangeFileExt(DllName, ""),
     GetImportedNameFromIATEntry(IATEntryRVA, true)]);
end;

function TPEImage.GetImportedFunctionName(const DllName: string;
 IATEntryRVA: DWORD): string;
begin
 if (IATEntryRVA and $80000000) <> 0 then
   Result := Format("%s.%d", [ChangeFileExt(DllName, ""),
     (IATEntryRVA and $7FFFFFFF)])
 else
   Result := Format("%s.%s", [ChangeFileExt(DllName, ""),
     GetImportedNameFromIATEntry(IATEntryRVA)]);
end;

function TPEImage.GetImportedNameFromIATEntry(IATEntryRVA: DWORD;
 FullInfo: Boolean): string;
var
 RawOffset: DWORD;
begin
 RawOffset := RawAddress (IATEntryRVA);
 Result := StrPas(RawData + RawOffset + SizeOf(Word));
 if FullInfo then
   Result := Format("%s (Hint=%.4x)", [Result,
     PIMAGE_IMPORT_BY_NAME(RawData + RawOffset)^.Hint]);
end;

function TPEImage.GetImports: TStrings;
begin
 if not Assigned(FImports) then begin
   FImports := TStringList.Create;
   FImports.Sorted := true;
   FImports.Duplicates := dupIgnore;
   LoadImports;
 end;
 Result := FImports;
end;

function TPEImage.GetSection(I: Integer): PImageSectionHeader;
begin
 Result := PImageSectionHeader(FSections[I]);
end;

function TPEImage.GetSubSystem: THSSubSystem;
begin
 with NtHeaders.OptionalHeader.DataDirectory[
     IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR] do
   if (VirtualAddress <> 0) and (Size <> 0) then
     Result := hsssDotNet
   else
     case NtHeaders^.OptionalHeader.Subsystem of
     IMAGE_SUBSYSTEM_WINDOWS_GUI:
       Result := hsssGUI32;
     IMAGE_SUBSYSTEM_WINDOWS_CUI:
       Result := hsssCon32;
     IMAGE_SUBSYSTEM_NATIVE:
       Result := hsssNative;
     else
       Result := hsssUnknown;
     end;
end;



 
Игорь Шевченко ©   (2005-05-27 10:46) [63]

Просто Джо ©   (27.05.05 10:18) [59]

procedure TPEImage.Load(Mapper: THSFileMapper);
begin
 inherited;
 FNtHeaders := PIMAGE_NT_HEADERS(Mapper.Map + DosHeader^._lfanew);
 LoadSections (Mapper);
 LoadModuleReferences (Mapper);
end;

procedure TPEImage.LoadDelayImports;
var
 RawOffset: Integer;
 ImportDescriptor: PDelayLoadImportTableItem;
 DllName: string;
 PFunctionsAddress: PDWORD;
 ImportAddress: DWORD;
begin
 with NtHeaders^.OptionalHeader.DataDirectory[
     IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT] do begin
   if (VirtualAddress = 0) or (Size = 0) then
     Exit;
   RawOffset := RawAddress(VirtualAddress);
 end;
 ImportDescriptor := PDelayLoadImportTableItem(RawData + RawOffset);
 while ImportDescriptor^.DllName <> 0 do begin
   if ImportDescriptor^.Flags = 1 then begin
     RawOffset := RawAddress(ImportDescriptor^.DllName);
     if RawOffset <> 0 then
       DllName := UpperCase(StrPas(RawData + RawOffset));
     RawOffset := RawAddress(ImportDescriptor^.ImportNameTable);
     PFunctionsAddress := PDWORD(RawData + RawOffset);
     while PFunctionsAddress^ <> 0 do begin
       ImportAddress := PFunctionsAddress^;
       FDelayImports.Add(GetImportedFunctionName(DllName, ImportAddress));
       Inc(PFunctionsAddress);
     end;
   end;
   Inc(ImportDescriptor);
 end;
end;

procedure TPEImage.LoadImports;
var
 RawOffset: Integer;
 ImportDescriptor: PIMAGE_IMPORT_DESCRIPTOR;
 DllName: string;
 PFunctionsAddress: PDWORD;
 ImportAddress: DWORD;
begin
 with NtHeaders^.OptionalHeader.DataDirectory[
     IMAGE_DIRECTORY_ENTRY_IMPORT] do begin
   if (VirtualAddress = 0) or (Size = 0) then
     Exit;
   RawOffset := RawAddress(VirtualAddress);
 end;
 ImportDescriptor := PIMAGE_IMPORT_DESCRIPTOR(RawData + RawOffset);
 while ImportDescriptor^.Name <> 0 do begin
   RawOffset := RawAddress(ImportDescriptor^.Name);
   if RawOffset <> 0 then
     DllName := UpperCase(StrPas(RawData + RawOffset));
   if ImportDescriptor^.Characteristics = 0 then
     RawOffset := RawAddress(ImportDescriptor^.FirstThunk)
   else
     RawOffset := RawAddress(ImportDescriptor^.Characteristics);
   PFunctionsAddress := PDWORD(RawData + RawOffset);
   while PFunctionsAddress^ <> 0 do begin
     ImportAddress := PFunctionsAddress^;
     FImports.Add(GetImportedFunctionName(DllName, ImportAddress));
     Inc(PFunctionsAddress);
   end;
   Inc(ImportDescriptor);
 end;
end;

procedure TPEImage.LoadModuleReferences(Mapper: THSFileMapper);
var
 IAddr: DWORD;
 PImport: PIMAGE_IMPORT_DESCRIPTOR;
 PModName: PChar;
begin
 with NtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] do
   if Size <> 0 then begin
     IAddr := RawAddress(VirtualAddress);
     PImport := PIMAGE_IMPORT_DESCRIPTOR(Mapper.Map + IAddr);
     while PImport^.Name <> 0 do begin
       PModName := Mapper.Map + RawAddress(PImport^.Name);
       FModuleReferences.Add(PModName);
       FImportLibraries.Add(UpperCase(PModName));
       Inc(PImport);
     end;
   end;
end;

procedure TPEImage.LoadSections(Mapper: THSFileMapper);
var
 PSection: PImageSectionHeader;
 I: Integer;
begin
 PSection := PImageSectionHeader(DWORD(@(NtHeaders^.OptionalHeader)) +
       NtHeaders^.FileHeader.SizeOfOptionalHeader);
 for I:=1 to NtHeaders^.FileHeader.NumberOfSections do begin
   FSections.Add (PSection);
   Inc(PSection);
 end;
end;

function TPEImage.RawAddress(VirtualAddress: Cardinal): Cardinal;
var
 I: Integer;
 Position: Cardinal;
begin
 Result := 0;
 for I := 0 to Pred(FSections.Count) do
   if (Sections[I].VirtualAddress <= VirtualAddress) and
      (VirtualAddress < Sections[I].VirtualAddress +
       Sections[I].SizeOfRawData) then begin
     Position := VirtualAddress - Sections[I].VirtualAddress;
     Result := Sections[I].PointerToRawData + Position;
     Break;
   end;
end;

end.


Кусок программы, анализирующей исполняемые файлы.


 
Просто Джо ©   (2005-05-27 10:59) [64]

Игорь Шевченко ©  
Спасибо, проделанная работа действительно впечатляет. Думаю, что автору топика это подойдет в самый раз. Да и я себе в заначку положу, на досуге поковыряюсь :)


 
Digitman ©   (2005-05-27 11:11) [65]


> wal ©   (27.05.05 09:56) [56]



> wal ©   (27.05.05 09:56) [56]



> В старые добрые времена


нынешние времена злые пошли .. "шаг влево, шаг вправо - попытка к побегу, расстрел на месте" )

иду я, к примеру, в папку c:\winnt\system32 и рассматриваю в лупу известный edit.com ... вижу там "MZ" - значит, явно не com-формат ... но системе это по барабану - на мое требование запуска задачи система тут же стартует экземпляр виртуальной ДОС-машины, а та уже сама разбирается, как его, этот исп.файл, запустить - по EXE- или СОМ-соглашениям...

логика здесь, очевидно, такова :

- система, обнаружив что файл имеет одно из расширений - ЕХЕ или СОМ, шарит по заголовкам

- обнаружив в корректных заголовках все признаки того, что файл есть образ исполняемого Win32-модуля, система делает попытку старта соответствующего Win32-процесса

- обнаружив корректный ДОС-заголовок, но не обнаружив признаков образа исполняемого Win32-модуля, либо не обнаружив вообще никаких заголовков, система подразумевает что дан.файл является образом ДОС16-модуля и стартует новый процесс вирт. ДОС-машины, которая уже собственно и пытается исполнить код ДОС-задачи

- если файл в реальности не содержит ДОС16-образ  (например, в файле некая абракадабра, внешне похожая на СОМ-файл, но при выполнении кода которого как правило возникнет искл.ситуация), вирт.машина сообщает об этом, и после подтверждения юзера система немедля снимает процесс вирт.машины с выполнения


 
wal ©   (2005-05-27 11:56) [66]


> [65] Digitman ©   (27.05.05 11:11)

Дак я об том и говорю, что однозначно определить только по расширению и заголовку программа это или нет без анализа кода невозможно. Так что времена хоть и "злые", но ничего существенно неизменилось. Только не виснет вся система, а вирт. машина ошибку выдает.

С уважением.


 
Defunct ©   (2005-05-27 13:21) [67]

wal ©   (27.05.05 11:56) [66]

Как раз по расширению и заголовку тип файла определяется однозначно. Иначе бы Windows и гроша ломаного не стоила.

Анализом кода только антивирусы занимаются.


 
wal ©   (2005-05-27 14:03) [68]


> [67] Defunct ©   (27.05.05 13:21)

1. Возьми в C:\WINNT\system32\ файл command.com
2. Скопируй его куда-нибудь.
3. Запусти и убедись, что работает
4. Переименуй его в command.exe
5. Запусти и убедись, что работает
6. Посмотри на его "изнутри" и убедись, что никаких MZ- и тем более PE-заголовка там нет.
7. А теперь на основании расширения (.exe) и заголовка (которого нет) определи однозначно, что это исполняемый файл.

С уважением.


 
Eraser ©   (2005-05-27 14:39) [69]

wal ©   (27.05.05 14:03) [68]

Если заголовка нету, это com файл. Чаще всего в таких файлах первая команда - безусловный переход.


 
Eraser ©   (2005-05-27 14:40) [70]

Игорь Шевченко ©

Мда - весч впчатляет. Респект.


 
wal ©   (2005-05-27 14:53) [71]


> [69] Eraser ©   (27.05.05 14:39)
> Если заголовка нету, это com файл.

Или бессмысленный набор байтов.

> Чаще всего в таких файлах первая команда - безусловный переход.

Во первых не всегда, а во вторых это и есть анализ кода, о котором я говорил ;)

С уважением.


 
Eraser ©   (2005-05-27 14:56) [72]

wal ©   (27.05.05 14:53) [71]

Ну тогда единственный способ узнать тип файла - отослать его по почте в M$ дождаться их ответа.


 
-=GaLaN=-   (2005-05-27 15:30) [73]

2Просто Джо:
Спасибо, работает неплохо на графических и консольных Win32, но... на DOS-приложениях функция скопытивается и выдаёт либо Unknown, либо Ambigous - и при том, что опциональный заголовок отсутствует, функция считает, будто он есть.

А Игорь Шевченко респект! У меня только маааленький вопросик - а где взять HSDosImage? Не компилит за отсутствием HSDosImage.dcu. :(

2All:
Честно говоря, нет смысла забирать com файлы. Пользователи моей программы будут сами себе злобные буратины, если начнут переименовывать всякие com в exe. Если консольность, графичность или dos"ность приложения не подтвердится, то его просто CreateProcess"ну - пускай система сама разбирается что к чему...


 
Defunct ©   (2005-05-27 15:47) [74]

wal ©   (27.05.05 14:03) [68]

ну и что с того?
По расширению (COM/EXE) определяется, что надо запустить загрузчик PE файла.
Далее,
Загрузчик открыл файл, нашел там "MZ" и начал подготавливать этот файл к запуску как EXE (а не как ком, хоть файл и с расширением COM).

Вот лучше проведите другой эксперимент, частично затрите заголовок EXE файла и попробуйте его запустить.


 
Игорь Шевченко ©   (2005-05-27 15:47) [75]

-=GaLaN=-   (27.05.05 15:30) [73]

Я вообще-то в посте написал, что это "кусок программы". И не рассчитывал на то, что кто-то компилировать мой код. Там еще нескольких юниов не хватает. Надо кодом обычно рекомендуется думать, смотреть, как реализованы те или иные идеи, применять эту реализацию к своему коду.


 
Defunct ©   (2005-05-27 15:53) [76]

-=GaLaN=-   (27.05.05 15:30) [73]

Вам забесплатно дали функцию [60] и описание констант и структур данных к ней - [61].

Остальные модули Игорь не считает нужным выкладывать на всеобщее обозрение, их там требуется ни много, ни мало все с тэгом HS. На то есть его право.


 
Оля   (2005-06-06 02:26) [77]

Удалено модератором


 
Digitman ©   (2005-06-06 08:16) [78]


> пытаюсь открыть с помощью других программ


каких ?



Страницы: 1 2 вся ветка

Форум: "WinAPI";
Текущий архив: 2005.07.31;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.74 MB
Время: 0.046 c
3-1119572382
akhmadey
2005-06-24 04:19
2005.07.31
Как сохранить изменеия в таблице, используя UpdateSQL?


6-1111846159
Алексей
2005-03-26 17:09
2005.07.31
подключиться к FTP-серверу?


14-1121078518
cspr
2005-07-11 14:41
2005.07.31
Политическая карта мира


14-1120785225
Миллиадр
2005-07-08 05:13
2005.07.31
Как называются числа больше миллиарда ?


3-1118923708
evg00
2005-06-16 16:08
2005.07.31
Проблема с запросом





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский