Skip to content

Commit 2af253f

Browse files
author
vdisasmdev
committed
* Handle malformed number of data directories.
1 parent 0207b45 commit 2af253f

File tree

2 files changed

+73
-44
lines changed

2 files changed

+73
-44
lines changed

PE.DataDirectories.pas

Lines changed: 65 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,15 @@ TDataDirectories = class
2525

2626
procedure Clear;
2727

28+
procedure NullInvalid(const Msg: TMsgMgr);
29+
2830
// Load array of TImageDataDirectory (va,size) from stream.
29-
procedure LoadDirectoriesFromStream(Stream: TStream; const Msg: TMsgMgr;
30-
DeclaredCount: integer);
31+
procedure LoadDirectoriesFromStream(
32+
Stream: TStream;
33+
const Msg: TMsgMgr;
34+
DeclaredCount: uint32; // # of rva and sizes
35+
MaxBytes: uint16
36+
);
3137

3238
// Save array of TImageDataDirectory (va,size) to stream.
3339
// Return saved size.
@@ -190,14 +196,46 @@ function TDataDirectories.GetName(Index: integer): string;
190196
Result := '';
191197
end;
192198

199+
procedure TDataDirectories.NullInvalid(const Msg: TMsgMgr);
200+
var
201+
i: integer;
202+
needToNullDir: boolean;
203+
begin
204+
// Check RVAs.
205+
for i := 0 to self.Count - 1 do
206+
begin
207+
// Empty dir is ok.
208+
if FItems[i].IsEmpty then
209+
continue;
210+
211+
needToNullDir := False;
212+
213+
if (FItems[i].Size = 0) and (FItems[i].RVA <> 0) then
214+
begin
215+
Msg.Write(SCategoryDataDirecory, 'Directory # %d has size = 0.', [i]);
216+
needToNullDir := true;
217+
end
218+
else if not TPEImage(FPE).RVAExists(FItems[i].RVA) then
219+
begin
220+
Msg.Write(SCategoryDataDirecory, 'Directory # %d RVA is not in image.', [i]);
221+
needToNullDir := true;
222+
end;
223+
224+
if needToNullDir and (PO_NULL_INVALID_DIRECTORY in TPEImage(FPE).Options) then
225+
begin
226+
FItems[i] := NULL_IMAGE_DATA_DIRECTORY;
227+
Msg.Write(SCategoryDataDirecory, 'Directory # %d nulled.', [i]);
228+
end;
229+
end;
230+
end;
231+
193232
procedure TDataDirectories.LoadDirectoriesFromStream;
194233
var
195-
CountToEOF: integer; // Count from StartOfs to EOF.
234+
MaxCountPossible: integer;
196235
CountToRead: integer;
197-
SizeToEOF: uint64;
236+
SizeToFileEnd: uint64;
198237
Size: uint32;
199-
i: integer;
200-
needToNullDir: boolean;
238+
MaxSizePossible: uint16;
201239
begin
202240
Clear;
203241

@@ -207,26 +245,35 @@ procedure TDataDirectories.LoadDirectoriesFromStream;
207245
exit;
208246
end;
209247

210-
SizeToEOF := (Stream.Size - Stream.Position);
248+
SizeToFileEnd := (Stream.Size - Stream.Position);
211249

212-
CountToEOF := SizeToEOF div SizeOf(TImageDataDirectory);
250+
// Max size available for dirs.
251+
if SizeToFileEnd > MaxBytes then
252+
MaxSizePossible := MaxBytes
253+
else
254+
MaxSizePossible := SizeToFileEnd;
213255

214-
// File can have part of dword stored. It must be extended with zeros.
215-
if (SizeToEOF mod SizeOf(TImageDataDirectory)) <> 0 then
216-
inc(CountToEOF);
256+
MaxCountPossible := MaxSizePossible div SizeOf(TImageDataDirectory);
217257

218-
CountToRead := DeclaredCount;
258+
// File can have part of dword stored. It must be extended with zeros.
259+
if (MaxSizePossible mod SizeOf(TImageDataDirectory)) <> 0 then
260+
inc(MaxCountPossible);
219261

220262
if DeclaredCount <> TYPICAL_NUMBER_OF_DIRECTORIES then
221-
Msg.Write(SCategoryDataDirecory, 'Non-usual count of directories (%d).', [DeclaredCount]);
263+
Msg.Write(SCategoryDataDirecory, 'Non-usual count of directories declared (0x%x).', [DeclaredCount]);
222264

223-
if DeclaredCount > CountToEOF then
265+
if DeclaredCount > MaxCountPossible then
224266
begin
225-
CountToRead := CountToEOF;
267+
CountToRead := MaxCountPossible;
226268

227269
Msg.Write(SCategoryDataDirecory,
228-
'Declared count of directories is greater than file can contain (%d > %d).',
229-
[DeclaredCount, CountToEOF]);
270+
'Declared count of directories is greater than file can contain (0x%x > 0x%x).',
271+
[DeclaredCount, MaxCountPossible]);
272+
Msg.Write(SCategoryDataDirecory, 'Fall back to 0x%x.', [MaxCountPossible]);
273+
end
274+
else
275+
begin
276+
CountToRead := DeclaredCount;
230277
end;
231278

232279
// Read data directories.
@@ -243,32 +290,7 @@ procedure TDataDirectories.LoadDirectoriesFromStream;
243290
// Set final count.
244291
self.Count := CountToRead;
245292

246-
// Check RVAs.
247-
for i := 0 to self.Count - 1 do
248-
begin
249-
// Empty dir is ok.
250-
if FItems[i].IsEmpty then
251-
continue;
252-
253-
needToNullDir := False;
254-
255-
if (FItems[i].Size = 0) and (FItems[i].RVA <> 0) then
256-
begin
257-
Msg.Write(SCategoryDataDirecory, 'Directory # %d has size = 0.', [i]);
258-
needToNullDir := true;
259-
end
260-
else if not TPEImage(FPE).RVAExists(FItems[i].RVA) then
261-
begin
262-
Msg.Write(SCategoryDataDirecory, 'Directory # %d RVA is not in image.', [i]);
263-
needToNullDir := true;
264-
end;
265-
266-
if needToNullDir and (PO_NULL_INVALID_DIRECTORY in TPEImage(FPE).Options) then
267-
begin
268-
FItems[i] := NULL_IMAGE_DATA_DIRECTORY;
269-
Msg.Write(SCategoryDataDirecory, 'Directory # %d nulled.', [i]);
270-
end;
271-
end;
293+
NullInvalid(Msg);
272294
end;
273295

274296
function TDataDirectories.SaveToStream(Index: integer; Stream: TStream): boolean;

PE.Image.pas

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1594,6 +1594,11 @@ function TPEImage.LoadFromStream(AStream: TStream; AParseStages: TParserFlags;
15941594

15951595
// Safe read optional header.
15961596
OptHdrSizeRead := FOptionalHeader.ReadFromStream(AStream, FImageBitSize, -1);
1597+
1598+
// Can't read more bytes then available.
1599+
if OptHdrSizeRead > FFileHeader.SizeOfOptionalHeader then
1600+
raise Exception.Create('Read size of opt. header > FileHeader.SizeOfOptionalHeader');
1601+
15971602
DataDirOfs := AStream.Position;
15981603

15991604
// Load Section Headers.
@@ -1608,8 +1613,10 @@ function TPEImage.LoadFromStream(AStream: TStream; AParseStages: TParserFlags;
16081613
if OptHdrSizeRead <> 0 then
16091614
begin
16101615
AStream.Position := DataDirOfs;
1616+
16111617
FDataDirectories.LoadDirectoriesFromStream(AStream, Msg,
1612-
FOptionalHeader.NumberOfRvaAndSizes // declared count
1618+
FOptionalHeader.NumberOfRvaAndSizes, // declared count
1619+
FFileHeader.SizeOfOptionalHeader - OptHdrSizeRead // bytes left in optional header
16131620
);
16141621
end;
16151622

0 commit comments

Comments
 (0)