Текущий архив: 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.68 MB
Время: 0.059 c