|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#1
|
|||
|
|||
Статья - PE Sniffer на Delphi - Часть вторая: Таблица секций
И снова здравствуйте!И как я и обещал сегодня я расскажу о таблице секций.Это не слишком сложно и поэтому мы можем сразу перейти к кодингу на 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; Тут из комментариев должно быть всё понятно. В процедуру передаётся по ссылке массив в который мы будем помещать декодированные символы, и по ссылке передаётся структура текущей секции.Это и правда несложно Ну вот и подошла к концу ещё одна статья. В следующей статье расскажу о таблице импорта и это будет гораздо сложнее, но как говориться да осилит дорогу идущий.И вконце концов мы осилм всё.До новых втреч!!! |