Subversion Repositories Kolibri OS

Rev

Rev 616 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
616 bw 1
{$mode objfpc}
2
{$apptype console}
3
 
4
program exe2kos;
5
 
6
uses
7
  SysUtils, Classes, ExeTypes, KosTypes;
8
 
9
const
10
  ARGS_SIZE = 512;
11
  PATH_SIZE = 512;
12
 
13
type
14
  EExeError = class(Exception);
15
 
16
  TExeImage = class;
17
  TExeImageSection = class;
18
 
19
  TExeImageSection = class
20
  private
21
    FExeImage: TExeImage;
22
    FHeader: IMAGE_SECTION_HEADER;
23
    FName: String;
24
    procedure Read(var Buffer);
25
  public
26
    constructor Create(AExeImage: TExeImage; APosition: DWord);
27
    property Name: String read FName;
28
    property VirtualSize: DWord read FHeader.PhysicalAddress;
29
    property SectionRVA: DWord read FHeader.VirtualAddress;
30
    property PhysicalSize: DWord read FHeader.SizeOfRawData;
31
    property PhysicalOffset: DWord read FHeader.PointerToRawData;
32
    property ObjectFlags: DWord read FHeader.Characteristics;
33
  end;
34
 
35
  TExeImageSections = class
36
  private
37
    FCount: DWord;
38
    FItems: array of TExeImageSection;
39
    function GetItem(Index: DWord): TExeImageSection;
40
  public
41
    constructor Create(AExeImage: TExeImage; APosition, ACount: DWord);
42
    destructor Destroy; override;
43
    function ByName(AName: String): TExeImageSection;
44
    property Count: DWord read FCount;
45
    property Items[Index: DWord]: TExeImageSection read GetItem; default;
46
  end;
47
 
48
  TExeImage = class
49
  private
50
    FFileName: String;
51
    FFileStream: TStream;
52
    FDosHeader: IMAGE_DOS_HEADER;
53
    FNTHeader: IMAGE_NT_HEADERS;
54
    FSections: TExeImageSections;
55
    procedure Read(var Buffer; Position, Size: Longint);
56
    function GetSizeOfCode(): DWord;
57
    function GetSizeOfInitData(): DWord;
58
    function GetSizeOfUnInitData(): DWord;
59
    function GetEntryPoint(): DWord;
60
    function GetImageBase(): DWord;
61
    function GetObjectAlign(): DWord;
62
    function GetFileAlign(): DWord;
63
    function GetImageSize(): DWord;
64
    function GetHeaderSize(): DWord;
65
    function GetStackReserveSize(): DWord;
66
    function GetStackCommitSize(): DWord;
67
    function GetHeapReserveSize(): DWord;
68
    function GetHeapCommitSize(): DWord;
69
  public
70
    constructor Create(AFileName: String);
71
    destructor Destroy; override;
72
    property FileName: String read FFileName;
73
    property Sections: TExeImageSections read FSections;
74
    property SizeOfCode: DWord read GetSizeOfCode;
75
    property SizeOfInitializedData: DWord read GetSizeOfInitData;
76
    property SizeOfUninitializedData: DWord read GetSizeOfUnInitData;
77
    property EntryPoint: DWord read FNTHeader.OptionalHeader.AddressOfEntryPoint{GetEntryPoint};
78
    property ImageBase: DWord read FNTHeader.OptionalHeader.ImageBase{GetImageBase};
79
    property ObjectAlign: DWord read GetObjectAlign;
80
    property FileAlign: DWord read GetFileAlign;
81
    property ImageSize: DWord read GetImageSize;
82
    property HeaderSize: DWord read GetHeaderSize;
83
    property StackReserveSize: DWord read GetStackReserveSize;
84
    property StackCommitSize: DWord read GetStackCommitSize;
85
    property HeapReserveSize: DWord read GetHeapReserveSize;
86
    property HeapCommitSize: DWord read GetHeapCommitSize;
87
  end;
88
 
89
 
90
constructor TExeImage.Create(AFileName: String);
91
begin
92
  FFileName := AFileName;
93
  FFileStream := TFileStream.Create(FFileName, fmOpenRead);
94
 
95
  Read(FDosHeader, 0, SizeOf(FDosHeader));
96
  if not FDosHeader.e_magic = IMAGE_DOS_SIGNATURE then
97
    EExeError.Create('Unrecognized file format');
98
 
99
  Read(FNTHeader, FDosHeader.e_lfanew, SizeOf(FNTHeader));
100
  if FNTHeader.Signature <> IMAGE_NT_SIGNATURE then
101
    EExeError.Create('Not a PE (WIN32 Executable) file');
102
 
103
  FSections := TExeImageSections.Create(Self,
104
    FDosHeader.e_lfanew + SizeOf(FNTHeader), FNTHeader.FileHeader.NumberOfSections);
105
end;
106
 
107
destructor TExeImage.Destroy;
108
begin
109
  FSections.Free;
110
  FFileStream.Free;
111
end;
112
 
113
procedure TExeImage.Read(var Buffer; Position, Size: Longint);
114
begin
115
  FFileStream.Position := Position;
116
  if FFileStream.Read(Buffer, Size) <> Size then
117
    EExeError.Create('Damaged or unrecognized file');
118
end;
119
 
120
function TExeImage.GetSizeOfCode(): DWord;
121
begin
122
  Result := FNTHeader.OptionalHeader.SizeOfCode;
123
end;
124
 
125
function TExeImage.GetSizeOfInitData(): DWord;
126
begin
127
  Result := FNTHeader.OptionalHeader.SizeOfInitializedData;
128
end;
129
 
130
function TExeImage.GetSizeOfUnInitData(): DWord;
131
begin
132
  Result := FNTHeader.OptionalHeader.SizeOfUninitializedData;
133
end;
134
 
135
function TExeImage.GetEntryPoint(): DWord;
136
begin
137
  Result := FNTHeader.OptionalHeader.AddressOfEntryPoint;
138
end;
139
 
140
function TExeImage.GetImageBase(): DWord;
141
begin
142
  Result := FNTHeader.OptionalHeader.ImageBase;
143
end;
144
 
145
function TExeImage.GetObjectAlign(): DWord;
146
begin
147
  Result := FNTHeader.OptionalHeader.SectionAlignment;
148
end;
149
 
150
function TExeImage.GetFileAlign(): DWord;
151
begin
152
  Result := FNTHeader.OptionalHeader.FileAlignment;
153
end;
154
 
155
function TExeImage.GetImageSize(): DWord;
156
begin
157
  Result := FNTHeader.OptionalHeader.SizeOfImage;
158
end;
159
 
160
function TExeImage.GetHeaderSize(): DWord;
161
begin
162
  Result := FNTHeader.OptionalHeader.SizeOfHeaders;
163
end;
164
 
165
function TExeImage.GetStackReserveSize(): DWord;
166
begin
167
  Result := FNTHeader.OptionalHeader.SizeOfStackReserve;
168
end;
169
 
170
function TExeImage.GetStackCommitSize(): DWord;
171
begin
172
  Result := FNTHeader.OptionalHeader.SizeOfStackCommit;
173
end;
174
 
175
function TExeImage.GetHeapReserveSize(): DWord;
176
begin
177
  Result := FNTHeader.OptionalHeader.SizeOfHeapReserve;
178
end;
179
 
180
function TExeImage.GetHeapCommitSize(): DWord;
181
begin
182
  Result := FNTHeader.OptionalHeader.SizeOfHeapCommit;
183
end;
184
 
185
 
186
constructor TExeImageSections.Create(AExeImage: TExeImage; APosition, ACount: DWord);
187
var
188
  i: Integer;
189
begin
190
  FCount := ACount;
191
  SetLength(FItems, ACount);
192
  for i := 0 to ACount - 1 do
193
  begin
194
    FItems[i] := TExeImageSection.Create(AExeImage, APosition);
195
    Inc(APosition, SizeOf(IMAGE_SECTION_HEADER));
196
  end;
197
end;
198
 
199
destructor TExeImageSections.Destroy;
200
var
201
  i: Integer;
202
begin
203
  for i := 0 to Length(FItems) - 1 do FItems[i].Free;
204
  SetLength(FItems, 0);
205
end;
206
 
207
function TExeImageSections.GetItem(Index: DWord): TExeImageSection;
208
begin
209
  Result := FItems[Index];
210
end;
211
 
212
function TExeImageSections.ByName(AName: String): TExeImageSection;
213
var
214
  i: Integer;
215
begin
216
  for i := 0 to Length(FItems) - 1 do
217
  if FItems[i].Name = AName then
218
  begin
219
    Result := FItems[i];
220
    Exit;
221
  end;
222
  Result := nil;
223
end;
224
 
225
 
226
 
227
constructor TExeImageSection.Create(AExeImage: TExeImage; APosition: DWord);
228
begin
229
  FExeImage := AExeImage;
230
  FExeImage.Read(FHeader, APosition, SizeOf(FHeader));
231
  FName := FHeader.Name;
232
end;
233
 
234
procedure TExeImageSection.Read(var Buffer);
235
begin
236
  FExeImage.Read(Buffer, PhysicalOffset, PhysicalSize);
237
end;
238
 
239
 
240
procedure WriteHead(s: String);
241
var
242
  i: Integer;
243
begin
244
  WriteLn;
245
  WriteLn(s);
246
  for i:=1 to Length(s) do Write('-');
247
  WriteLn;
248
end;
249
 
250
procedure Convert(InputFile, OutputFile: String);
251
var
252
  ExeImage: TExeImage;
253
  KosHeader: TKosHeader;
254
  FileStream: TStream;
255
  ImageBase, ImageSize, Size: DWord;
256
  Buffer: Pointer;
257
  i: Integer;
258
begin
259
  ExeImage := TExeImage.Create(InputFile);
763 bw 260
 
261
{$ifdef debug}
616 bw 262
  WriteHead('NT Header');
263
  WriteLn(Format('Size of Code: %d', [ExeImage.SizeOfCode]));
264
  WriteLn(Format('Size of Init Data: %d', [ExeImage.SizeOfInitializedData]));
265
  WriteLn(Format('Size of UnInit Data: %d', [ExeImage.SizeOfUninitializedData]));
266
  WriteLn(Format('Entry Point: 0x%x', [ExeImage.EntryPoint]));
267
  WriteLn(Format('Image Base: 0x%x', [ExeImage.ImageBase]));
268
  WriteLn(Format('Object Align: %d; File Align: %d', [ExeImage.ObjectAlign, ExeImage.FileAlign]));
269
  WriteLn(Format('Image Size: %d; Header Size: %d', [ExeImage.ImageSize, ExeImage.HeaderSize]));
270
  WriteLn(Format('Stack Reserve Size: %d; Stack Commit Size: %d', [ExeImage.StackReserveSize, ExeImage.StackCommitSize]));
271
  WriteLn(Format('Heap Reserve Size: %d; Heap Comit Size: %d', [ExeImage.HeapReserveSize, ExeImage.HeapCommitSize]));
763 bw 272
{$endif}
616 bw 273
 
274
  ImageBase := ExeImage.ImageBase;
275
  ImageSize := 0;
276
 
277
  { запись секций }
278
  FileStream := TFileStream.Create(OutputFile, fmCreate);
279
  for i:=0 to ExeImage.Sections.Count-1 do
280
  with ExeImage.Sections[i] do
281
  begin
763 bw 282
 
283
{$ifdef debug}
616 bw 284
    WriteHead(Format('Section %s (0x%x)', [Name, ObjectFlags]));
285
    WriteLn(Format('Section RVA/Size: 0x%x / %d', [SectionRVA, VirtualSize]));
286
    WriteLn(Format('Physical Offset/Size: 0x%x / %d', [PhysicalOffset, PhysicalSize]));
763 bw 287
{$endif}
616 bw 288
 
289
    Size := ImageBase + SectionRVA;
290
    FileStream.Position := Size;
291
    Inc(Size, VirtualSize);
292
    if Size > ImageSize then ImageSize := Size;
293
 
294
    if PhysicalSize > 0 then
295
    begin
296
      GetMem(Buffer, PhysicalSize);
297
      Read(Buffer^);
298
      FileStream.Write(Buffer^, PhysicalSize);
299
      FreeMem(Buffer);
300
    end;
301
  end;
302
 
303
  FillByte(KosHeader, SizeOf(KosHeader), 0);
304
  with KosHeader do
305
  begin
306
    sign    := KOS_SIGN;
307
    version := 1;
308
    start   := ImageBase + ExeImage.EntryPoint;
309
    size    := FileStream.Size;
310
    args    := ImageSize;
311
    path    := args + ARGS_SIZE;
312
    stack   := path + PATH_SIZE + ExeImage.StackReserveSize;
313
    memory  := stack;
314
  end;
315
  FileStream.Position := 0;
316
  FileStream.Write(KosHeader, SizeOf(KosHeader));
317
  FileStream.Free();
318
end;
319
 
320
 
321
var
322
  InputFile, OutputFile: String;
323
begin
324
  if ParamCount < 1 then
325
  begin
326
    WriteLn(Format('%s  [kos output file]', [ExtractFileName(ParamStr(0))]));
327
    Exit;
328
  end;
329
 
330
  InputFile := ParamStr(1);
331
  if ParamCount <2 then
332
    OutputFile := ChangeFileExt(InputFile, '') else
333
    OutputFile := ParamStr(2);
334
 
335
  if InputFile = OutputFile then
336
    WriteLn(Format('Cannot convert the file "%s" onto itself.', [InputFile])) else
337
 
338
  if not FileExists(InputFile) then
339
    WriteLn(Format('Input the file "%s", not found.', [InputFile])) else
340
 
341
  begin
342
    WriteLn(Format('Converting "%s" to "%s"...', [InputFile, OutputFile]));
343
    Convert(InputFile, OutputFile);
344
  end;
345
end.