И снова здравствуйте!И как я и обещал сегодня я расскажу о таблице секций.Это не слишком сложно и поэтому мы можем сразу перейти к кодингу на Delphi.
Значит, что нам необходимо знать так это - то, что таблица секций находится сразу за заголовком IMAGE_NT_HEADERS.Таким образом прибавив указатель на IMAGE_NT_HEADERS к размеру NT заголовка мы получим указатель на первую секцию, а именно указатель на структуру IMAGE_SECTION_HEADER.Так ещё, что нам необходимо знать так это-то где нам взять количество секций находящихся в образе файла.Взять количество секций можно и даже нужно в структуре IMAGE_FILE_HEADER которая в ходит в состав IMAGE_NT_HEADERS.Ниже её описание:
Код:
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;// Сигнатура PE Файла имеющая вид $4550
IMAGE_FILE_HEADER FileHeader; // Структура файлового заголовка
IMAGE_OPTIONAL_HEADER32 OptionalHeader;//Дополнительный заголовок
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
И ещё несколько слов о структуре IMAGE_SECTION_HEADER. Значит в этой структуре 10 полей, но нас интересует только 5 полей, а именно: Name - в этом поле содержится имя текущей секции.VirtualAddress - адрес структуры в образе. SizeOfData - размер данных. PointerToRAWData - указатель на данные и последний но не менее важный член - это Characteristic - Аттрибуты доступа текущей секции.Суммируя всё это начинаем шкодить
Сначала создадим процедуру которая будет перечислять секции:
Код:
procedure TForm1.LoadSection(pBaseAddr: Pointer);
var
Nt: ^IMAGE_NT_HEADERS;
begin
Nt:= GetNtHdr(pBaseAddr);
if (Assigned(Nt) and (Nt^.Signature = IMAGE_NT_SIGNATURE)) then
begin
Section:= Pointer(Cardinal(Nt) + SizeOf(Nt^));//Получаем указатель на первую секцию.
CountSection:= Nt^.FileHeader.NumberOfSections;
end;
end;
Здесь мы как и раньше сначала получаем указатель на NT заголовок, потом мы проверяем его сигнатуру и если всё OK тогда мы получаем указатель на первую секцию путём сложения адреса NT заголовка и его размера. Потом получаем количество секций из файлового заголовка.Предварительно я в приватной секции обЪявил две переменные следующего вида:
Код:
private
Section: ^IMAGE_SECTION_HEADER;//Указатель на Заголовок Секций
CountSection: Integer;//Количество секций
И наконец я написал ещё одну процедуру которая выводит информацию о каждой секции:
Код:
procedure TForm1.Print_s;
var
i: Integer;
Buffer: array [0..7] of WideChar;
OutStr: String;
Item: TListItem;
begin
for i := 1 to CountSection do
begin
Item:= ListView1.Items.Add;
GetSectionName(Buffer, Section^);
OutStr:= Format('%s', [Buffer]);
Item.Caption:= OutStr;
OutStr:= Format('%x', [Section^.VirtualAddress]);
Item.SubItems.Add(OutStr);
OutStr:= Format('%x', [Section^.SizeOfRawData]);
Item.SubItems.Add(OutStr);
OutStr:= Format('%p', [Pointer(Section^.PointerToRawData)]);
Item.SubItems.Add(OutStr);
OutStr:= Format('%x', [Section^.Characteristics]);
Item.SubItems.Add(OutStr);
Section:= Pointer(Cardinal(Section) + SizeOf(IMAGE_SECTION_HEADER));
end;
end;
Вывод я решил осуществить в компонент ListView.Здесь переменная Buffer будет содержать имя текущей секции, а OutStr будет содержать форматированный текст содержащий различные значения взятые из текущего IMAGE_SECTION_HEADER. Далее в цикле перебираю значения и вывожу в компонент.И последний момент, имя секции содержится в массиве типа BYTE, но тип BYTE не совместим с символьными типами Delphi и трактуется как короткое целое.Для того, чтобы получить имя секции я написал ещё одну процедуру которая декодирует имя секции в необходимый нам вид, а именно WideChar потому как я работаю со строками UNICODE.Ниже приведена эта процедура:
Код:
procedure TForm1.GetSectionName(var Buf: array of WideChar;
var ISH: IMAGE_SECTION_HEADER);
var
ind: Integer;
begin
{Так как имя секции храниться в массиве типа BYTE, а он не совместим
с символьными типами в Delphi пришлось написать проседуру декодирующую
байты в символы. И так как мы используем кодировку символов UNICODE
приэтом нам необходимо ещё и расширить символы до UNICODE.}
for ind := 0 to 7 do
begin
Buf[ind]:= WideChar(Chr(ISH.Name[ind]));
end;
end;
Тут из комментариев должно быть всё понятно. В процедуру передаётся по ссылке массив в который мы будем помещать декодированные символы, и по ссылке передаётся структура текущей секции.Это и правда несложно
Ну вот и подошла к концу ещё одна статья. В следующей статье расскажу о таблице импорта и это будет гораздо сложнее, но как говориться да осилит дорогу идущий.И вконце концов мы осилм всё.До новых втреч!!!