Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.07.31;
Скачать: CL | DM;

Вниз

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

 
-=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.7 MB
Время: 0.04 c
4-1117798574
webpauk
2005-06-03 15:36
2005.07.31
DirectDraw, инфо о поверхности


9-1113155896
Green_Templar
2005-04-10 21:58
2005.07.31
текст


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


6-1113827513
balamutik
2005-04-18 16:31
2005.07.31
Скачивание с мэйла


14-1121120536
Profi
2005-07-12 02:22
2005.07.31
Оцените, пожалуйста!