Skip to content

Commit f5dd902

Browse files
committed
Улучшена обработка RVA и импортов в PE-файлах
Добавлена защита от бесконечного цикла при обработке импортов, безопасное вычисление RVA с проверкой переполнения. Усилена проверка корректности PE-файла (минимальный размер, отсутствие исключения при отсутствии файла). В RvaToFileOffset добавлена проверка на диапазон SizeOfRawData. В ReadDataFromRVA добавлена проверка размера и уточнено сообщение об ошибке. В PEResources исправлен расчет RVA для записей ресурсов.
1 parent cb09269 commit f5dd902

3 files changed

Lines changed: 28 additions & 9 deletions

File tree

MathCore/PE/ImportedFunctions.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,14 @@ private List<ImportedFunction> LoadImportedFunctions(PEFile pefFile, IMAGE_IMPOR
8686
var lookupTableRVA = descriptor.OriginalFirstThunk;
8787

8888
uint index = 0;
89-
while (true)
89+
const uint max_imports = 10000; // Защита от бесконечного цикла
90+
while (index < max_imports)
9091
{
91-
var lookupData = pefFile.ReadDataFromRVA(lookupTableRVA + index * sizeof(uint), sizeof(uint));
92+
// Безопасное вычисление RVA с проверкой переполнения
93+
var offset_bytes = checked((uint)(index * sizeof(uint)));
94+
var entry_rva = checked(lookupTableRVA + offset_bytes);
95+
96+
var lookupData = pefFile.ReadDataFromRVA(entry_rva, sizeof(uint));
9297
var lookupValue = BitConverter.ToUInt32(lookupData, 0);
9398

9499
if (lookupValue == 0)

MathCore/PE/PEFile.cs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@ public bool IsPE
2222
{
2323
get
2424
{
25-
if (!Exists) throw new FileNotFoundException("Файл не найден", _File.FullName);
25+
if (!Exists) return false;
2626

27-
if (_File.Length < 128) return false;
27+
// DOS заголовок минимум 64 байта, NT заголовок требует еще данных
28+
if (_File.Length < 512) return false;
2829

2930
try
3031
{
@@ -62,10 +63,18 @@ public long RvaToFileOffset(uint RVA)
6263

6364
foreach (var section in header.Sections)
6465
{
66+
// RVA находится в диапазоне виртуального адреса раздела
6567
if (RVA >= section.VirtualAddress && RVA < section.VirtualAddress + section.VirtualSize)
6668
{
67-
var offset = RVA - section.VirtualAddress + section.PointerToRawData;
68-
return offset;
69+
// Но смещение файла должно быть в пределах реального размера раздела в файле
70+
var offset_in_section = RVA - section.VirtualAddress;
71+
if (offset_in_section < section.SizeOfRawData)
72+
{
73+
var offset = offset_in_section + section.PointerToRawData;
74+
return offset;
75+
}
76+
// RVA в диапазоне виртуального размера, но вне реального файла
77+
return -1;
6978
}
7079
}
7180

@@ -98,6 +107,9 @@ public uint FileOffsetToRva(long FileOffset)
98107
/// <returns>Прочитанные данные</returns>
99108
public byte[] ReadDataFromRVA(uint RVA, int Size)
100109
{
110+
if (Size <= 0)
111+
throw new ArgumentException("Размер должен быть положительным", nameof(Size));
112+
101113
var offset = RvaToFileOffset(RVA);
102114
if (offset < 0)
103115
throw new InvalidOperationException($"RVA 0x{RVA:X8} находится вне разделов файла");
@@ -109,7 +121,7 @@ public byte[] ReadDataFromRVA(uint RVA, int Size)
109121
var read = file.Read(data, 0, Size);
110122

111123
if (read != Size)
112-
throw new InvalidOperationException($"Не удалось прочитать полный объём данных из RVA 0x{RVA:X8}");
124+
throw new InvalidOperationException($"Не удалось прочитать полный объём данных из RVA 0x{RVA:X8}: прочитано {read} байт вместо {Size}");
113125

114126
return data;
115127
}

MathCore/PE/PEResources.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,13 @@ private IMAGE_RESOURCE_DIRECTORY_ENTRY[] ReadDirectoryEntries(IMAGE_RESOURCE_DIR
128128
{
129129
// Первые NumberOfNamedEntries - это именованные записи, потом идут записи с ID
130130
var entrySize = Marshal.SizeOf<IMAGE_RESOURCE_DIRECTORY_ENTRY>();
131-
var offset = BaseRVA + (uint)Marshal.SizeOf<IMAGE_RESOURCE_DIRECTORY>();
131+
var directory_size = Marshal.SizeOf<IMAGE_RESOURCE_DIRECTORY>();
132132

133133
for (int i = 0; i < totalEntries; i++)
134134
{
135-
var data = _PEFile.ReadDataFromRVA(offset + (uint)(i * entrySize), entrySize);
135+
// Вычисляем RVA каждой записи (BaseRVA + размер директории + смещение записи)
136+
var entry_rva = BaseRVA + (uint)directory_size + (uint)(i * entrySize);
137+
var data = _PEFile.ReadDataFromRVA(entry_rva, entrySize);
136138
var gch = GCHandle.Alloc(data, GCHandleType.Pinned);
137139
try
138140
{

0 commit comments

Comments
 (0)