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

Вниз

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

 
-=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.68 MB
Время: 0.052 c
9-1113506736
Fords
2005-04-14 23:25
2005.07.31
Физика GLScene


9-1113670911
Степан
2005-04-16 21:01
2005.07.31
Что такое Z-буфер, и для чего он нужен??


14-1120534822
Starcom
2005-07-05 07:40
2005.07.31
Присоеденительные файлы!


14-1120650056
vecna
2005-07-06 15:40
2005.07.31
У нас олимпиады не будет...


1-1121065795
Курдль
2005-07-11 11:09
2005.07.31
Про отображение BLOB типа jpeg в DBImage





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский