Текущий архив: 2005.07.31;
Скачать: CL | DM;
ВнизОпределить тип приложения Найти похожие ветки
← →
-=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 вся ветка
Текущий архив: 2005.07.31;
Скачать: CL | DM;
Память: 0.74 MB
Время: 0.042 c