forked from KolibriOS/kolibrios
5780544c0f
git-svn-id: svn://kolibrios.org@763 a494cfbc-eb01-0410-851d-a64ba20cac60
346 lines
9.4 KiB
ObjectPascal
346 lines
9.4 KiB
ObjectPascal
{$mode objfpc}
|
||
{$apptype console}
|
||
|
||
program exe2kos;
|
||
|
||
uses
|
||
SysUtils, Classes, ExeTypes, KosTypes;
|
||
|
||
const
|
||
ARGS_SIZE = 512;
|
||
PATH_SIZE = 512;
|
||
|
||
type
|
||
EExeError = class(Exception);
|
||
|
||
TExeImage = class;
|
||
TExeImageSection = class;
|
||
|
||
TExeImageSection = class
|
||
private
|
||
FExeImage: TExeImage;
|
||
FHeader: IMAGE_SECTION_HEADER;
|
||
FName: String;
|
||
procedure Read(var Buffer);
|
||
public
|
||
constructor Create(AExeImage: TExeImage; APosition: DWord);
|
||
property Name: String read FName;
|
||
property VirtualSize: DWord read FHeader.PhysicalAddress;
|
||
property SectionRVA: DWord read FHeader.VirtualAddress;
|
||
property PhysicalSize: DWord read FHeader.SizeOfRawData;
|
||
property PhysicalOffset: DWord read FHeader.PointerToRawData;
|
||
property ObjectFlags: DWord read FHeader.Characteristics;
|
||
end;
|
||
|
||
TExeImageSections = class
|
||
private
|
||
FCount: DWord;
|
||
FItems: array of TExeImageSection;
|
||
function GetItem(Index: DWord): TExeImageSection;
|
||
public
|
||
constructor Create(AExeImage: TExeImage; APosition, ACount: DWord);
|
||
destructor Destroy; override;
|
||
function ByName(AName: String): TExeImageSection;
|
||
property Count: DWord read FCount;
|
||
property Items[Index: DWord]: TExeImageSection read GetItem; default;
|
||
end;
|
||
|
||
TExeImage = class
|
||
private
|
||
FFileName: String;
|
||
FFileStream: TStream;
|
||
FDosHeader: IMAGE_DOS_HEADER;
|
||
FNTHeader: IMAGE_NT_HEADERS;
|
||
FSections: TExeImageSections;
|
||
procedure Read(var Buffer; Position, Size: Longint);
|
||
function GetSizeOfCode(): DWord;
|
||
function GetSizeOfInitData(): DWord;
|
||
function GetSizeOfUnInitData(): DWord;
|
||
function GetEntryPoint(): DWord;
|
||
function GetImageBase(): DWord;
|
||
function GetObjectAlign(): DWord;
|
||
function GetFileAlign(): DWord;
|
||
function GetImageSize(): DWord;
|
||
function GetHeaderSize(): DWord;
|
||
function GetStackReserveSize(): DWord;
|
||
function GetStackCommitSize(): DWord;
|
||
function GetHeapReserveSize(): DWord;
|
||
function GetHeapCommitSize(): DWord;
|
||
public
|
||
constructor Create(AFileName: String);
|
||
destructor Destroy; override;
|
||
property FileName: String read FFileName;
|
||
property Sections: TExeImageSections read FSections;
|
||
property SizeOfCode: DWord read GetSizeOfCode;
|
||
property SizeOfInitializedData: DWord read GetSizeOfInitData;
|
||
property SizeOfUninitializedData: DWord read GetSizeOfUnInitData;
|
||
property EntryPoint: DWord read FNTHeader.OptionalHeader.AddressOfEntryPoint{GetEntryPoint};
|
||
property ImageBase: DWord read FNTHeader.OptionalHeader.ImageBase{GetImageBase};
|
||
property ObjectAlign: DWord read GetObjectAlign;
|
||
property FileAlign: DWord read GetFileAlign;
|
||
property ImageSize: DWord read GetImageSize;
|
||
property HeaderSize: DWord read GetHeaderSize;
|
||
property StackReserveSize: DWord read GetStackReserveSize;
|
||
property StackCommitSize: DWord read GetStackCommitSize;
|
||
property HeapReserveSize: DWord read GetHeapReserveSize;
|
||
property HeapCommitSize: DWord read GetHeapCommitSize;
|
||
end;
|
||
|
||
|
||
constructor TExeImage.Create(AFileName: String);
|
||
begin
|
||
FFileName := AFileName;
|
||
FFileStream := TFileStream.Create(FFileName, fmOpenRead);
|
||
|
||
Read(FDosHeader, 0, SizeOf(FDosHeader));
|
||
if not FDosHeader.e_magic = IMAGE_DOS_SIGNATURE then
|
||
EExeError.Create('Unrecognized file format');
|
||
|
||
Read(FNTHeader, FDosHeader.e_lfanew, SizeOf(FNTHeader));
|
||
if FNTHeader.Signature <> IMAGE_NT_SIGNATURE then
|
||
EExeError.Create('Not a PE (WIN32 Executable) file');
|
||
|
||
FSections := TExeImageSections.Create(Self,
|
||
FDosHeader.e_lfanew + SizeOf(FNTHeader), FNTHeader.FileHeader.NumberOfSections);
|
||
end;
|
||
|
||
destructor TExeImage.Destroy;
|
||
begin
|
||
FSections.Free;
|
||
FFileStream.Free;
|
||
end;
|
||
|
||
procedure TExeImage.Read(var Buffer; Position, Size: Longint);
|
||
begin
|
||
FFileStream.Position := Position;
|
||
if FFileStream.Read(Buffer, Size) <> Size then
|
||
EExeError.Create('Damaged or unrecognized file');
|
||
end;
|
||
|
||
function TExeImage.GetSizeOfCode(): DWord;
|
||
begin
|
||
Result := FNTHeader.OptionalHeader.SizeOfCode;
|
||
end;
|
||
|
||
function TExeImage.GetSizeOfInitData(): DWord;
|
||
begin
|
||
Result := FNTHeader.OptionalHeader.SizeOfInitializedData;
|
||
end;
|
||
|
||
function TExeImage.GetSizeOfUnInitData(): DWord;
|
||
begin
|
||
Result := FNTHeader.OptionalHeader.SizeOfUninitializedData;
|
||
end;
|
||
|
||
function TExeImage.GetEntryPoint(): DWord;
|
||
begin
|
||
Result := FNTHeader.OptionalHeader.AddressOfEntryPoint;
|
||
end;
|
||
|
||
function TExeImage.GetImageBase(): DWord;
|
||
begin
|
||
Result := FNTHeader.OptionalHeader.ImageBase;
|
||
end;
|
||
|
||
function TExeImage.GetObjectAlign(): DWord;
|
||
begin
|
||
Result := FNTHeader.OptionalHeader.SectionAlignment;
|
||
end;
|
||
|
||
function TExeImage.GetFileAlign(): DWord;
|
||
begin
|
||
Result := FNTHeader.OptionalHeader.FileAlignment;
|
||
end;
|
||
|
||
function TExeImage.GetImageSize(): DWord;
|
||
begin
|
||
Result := FNTHeader.OptionalHeader.SizeOfImage;
|
||
end;
|
||
|
||
function TExeImage.GetHeaderSize(): DWord;
|
||
begin
|
||
Result := FNTHeader.OptionalHeader.SizeOfHeaders;
|
||
end;
|
||
|
||
function TExeImage.GetStackReserveSize(): DWord;
|
||
begin
|
||
Result := FNTHeader.OptionalHeader.SizeOfStackReserve;
|
||
end;
|
||
|
||
function TExeImage.GetStackCommitSize(): DWord;
|
||
begin
|
||
Result := FNTHeader.OptionalHeader.SizeOfStackCommit;
|
||
end;
|
||
|
||
function TExeImage.GetHeapReserveSize(): DWord;
|
||
begin
|
||
Result := FNTHeader.OptionalHeader.SizeOfHeapReserve;
|
||
end;
|
||
|
||
function TExeImage.GetHeapCommitSize(): DWord;
|
||
begin
|
||
Result := FNTHeader.OptionalHeader.SizeOfHeapCommit;
|
||
end;
|
||
|
||
|
||
constructor TExeImageSections.Create(AExeImage: TExeImage; APosition, ACount: DWord);
|
||
var
|
||
i: Integer;
|
||
begin
|
||
FCount := ACount;
|
||
SetLength(FItems, ACount);
|
||
for i := 0 to ACount - 1 do
|
||
begin
|
||
FItems[i] := TExeImageSection.Create(AExeImage, APosition);
|
||
Inc(APosition, SizeOf(IMAGE_SECTION_HEADER));
|
||
end;
|
||
end;
|
||
|
||
destructor TExeImageSections.Destroy;
|
||
var
|
||
i: Integer;
|
||
begin
|
||
for i := 0 to Length(FItems) - 1 do FItems[i].Free;
|
||
SetLength(FItems, 0);
|
||
end;
|
||
|
||
function TExeImageSections.GetItem(Index: DWord): TExeImageSection;
|
||
begin
|
||
Result := FItems[Index];
|
||
end;
|
||
|
||
function TExeImageSections.ByName(AName: String): TExeImageSection;
|
||
var
|
||
i: Integer;
|
||
begin
|
||
for i := 0 to Length(FItems) - 1 do
|
||
if FItems[i].Name = AName then
|
||
begin
|
||
Result := FItems[i];
|
||
Exit;
|
||
end;
|
||
Result := nil;
|
||
end;
|
||
|
||
|
||
|
||
constructor TExeImageSection.Create(AExeImage: TExeImage; APosition: DWord);
|
||
begin
|
||
FExeImage := AExeImage;
|
||
FExeImage.Read(FHeader, APosition, SizeOf(FHeader));
|
||
FName := FHeader.Name;
|
||
end;
|
||
|
||
procedure TExeImageSection.Read(var Buffer);
|
||
begin
|
||
FExeImage.Read(Buffer, PhysicalOffset, PhysicalSize);
|
||
end;
|
||
|
||
|
||
procedure WriteHead(s: String);
|
||
var
|
||
i: Integer;
|
||
begin
|
||
WriteLn;
|
||
WriteLn(s);
|
||
for i:=1 to Length(s) do Write('-');
|
||
WriteLn;
|
||
end;
|
||
|
||
procedure Convert(InputFile, OutputFile: String);
|
||
var
|
||
ExeImage: TExeImage;
|
||
KosHeader: TKosHeader;
|
||
FileStream: TStream;
|
||
ImageBase, ImageSize, Size: DWord;
|
||
Buffer: Pointer;
|
||
i: Integer;
|
||
begin
|
||
ExeImage := TExeImage.Create(InputFile);
|
||
|
||
{$ifdef debug}
|
||
WriteHead('NT Header');
|
||
WriteLn(Format('Size of Code: %d', [ExeImage.SizeOfCode]));
|
||
WriteLn(Format('Size of Init Data: %d', [ExeImage.SizeOfInitializedData]));
|
||
WriteLn(Format('Size of UnInit Data: %d', [ExeImage.SizeOfUninitializedData]));
|
||
WriteLn(Format('Entry Point: 0x%x', [ExeImage.EntryPoint]));
|
||
WriteLn(Format('Image Base: 0x%x', [ExeImage.ImageBase]));
|
||
WriteLn(Format('Object Align: %d; File Align: %d', [ExeImage.ObjectAlign, ExeImage.FileAlign]));
|
||
WriteLn(Format('Image Size: %d; Header Size: %d', [ExeImage.ImageSize, ExeImage.HeaderSize]));
|
||
WriteLn(Format('Stack Reserve Size: %d; Stack Commit Size: %d', [ExeImage.StackReserveSize, ExeImage.StackCommitSize]));
|
||
WriteLn(Format('Heap Reserve Size: %d; Heap Comit Size: %d', [ExeImage.HeapReserveSize, ExeImage.HeapCommitSize]));
|
||
{$endif}
|
||
|
||
ImageBase := ExeImage.ImageBase;
|
||
ImageSize := 0;
|
||
|
||
{ <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> }
|
||
FileStream := TFileStream.Create(OutputFile, fmCreate);
|
||
for i:=0 to ExeImage.Sections.Count-1 do
|
||
with ExeImage.Sections[i] do
|
||
begin
|
||
|
||
{$ifdef debug}
|
||
WriteHead(Format('Section %s (0x%x)', [Name, ObjectFlags]));
|
||
WriteLn(Format('Section RVA/Size: 0x%x / %d', [SectionRVA, VirtualSize]));
|
||
WriteLn(Format('Physical Offset/Size: 0x%x / %d', [PhysicalOffset, PhysicalSize]));
|
||
{$endif}
|
||
|
||
Size := ImageBase + SectionRVA;
|
||
FileStream.Position := Size;
|
||
Inc(Size, VirtualSize);
|
||
if Size > ImageSize then ImageSize := Size;
|
||
|
||
if PhysicalSize > 0 then
|
||
begin
|
||
GetMem(Buffer, PhysicalSize);
|
||
Read(Buffer^);
|
||
FileStream.Write(Buffer^, PhysicalSize);
|
||
FreeMem(Buffer);
|
||
end;
|
||
end;
|
||
|
||
FillByte(KosHeader, SizeOf(KosHeader), 0);
|
||
with KosHeader do
|
||
begin
|
||
sign := KOS_SIGN;
|
||
version := 1;
|
||
start := ImageBase + ExeImage.EntryPoint;
|
||
size := FileStream.Size;
|
||
args := ImageSize;
|
||
path := args + ARGS_SIZE;
|
||
stack := path + PATH_SIZE + ExeImage.StackReserveSize;
|
||
memory := stack;
|
||
end;
|
||
FileStream.Position := 0;
|
||
FileStream.Write(KosHeader, SizeOf(KosHeader));
|
||
FileStream.Free();
|
||
end;
|
||
|
||
|
||
var
|
||
InputFile, OutputFile: String;
|
||
begin
|
||
if ParamCount < 1 then
|
||
begin
|
||
WriteLn(Format('%s <exe input file> [kos output file]', [ExtractFileName(ParamStr(0))]));
|
||
Exit;
|
||
end;
|
||
|
||
InputFile := ParamStr(1);
|
||
if ParamCount <2 then
|
||
OutputFile := ChangeFileExt(InputFile, '') else
|
||
OutputFile := ParamStr(2);
|
||
|
||
if InputFile = OutputFile then
|
||
WriteLn(Format('Cannot convert the file "%s" onto itself.', [InputFile])) else
|
||
|
||
if not FileExists(InputFile) then
|
||
WriteLn(Format('Input the file "%s", not found.', [InputFile])) else
|
||
|
||
begin
|
||
WriteLn(Format('Converting "%s" to "%s"...', [InputFile, OutputFile]));
|
||
Convert(InputFile, OutputFile);
|
||
end;
|
||
end.
|